Imported from kurusugawa-computer/markdown-copilot-vscode (
AGENTS.md). Install upstream withnpx skills add kurusugawa-computer/markdown-copilot-vscode. Copyright stays with the author.
Markdown Copilot — Codex Cheat Sheet
ExecPlans
When work goes beyond a small tweak (new feature flow, sizeable refactor, risky change), author an ExecPlan following .agent/PLANS.md before you touch code. Store plans under .agent/, keep scratch material inside a .gitignored subfolder there, and keep each plan fully self-contained so another agent could finish the job from the plan alone.
Design Principles
- Keep wiring anchored in
src/extension.ts; hold instances there (e.g.,ContextOutline,ContextDecorator) and pass them down instead of adding globals. - Avoid premature abstraction—do not add classes/parameters just for hypothetical reuse; match the current call graph.
- Preserve layer boundaries: features orchestrate,
llmhandles model/tool work,utilsstays general-purpose; avoid upward dependencies. - Keep side effects at the edges—prefer pure helpers and wrap VS Code/filesystem/network calls so failures surface clearly.
- Write tests around deterministic logic before wiring LLM or VS Code flows; inject dependencies explicitly (constructor args/params) instead of hidden defaults.
- Avoid unnecessary subdirectories under
src; do not add one-off folders that only holdindex.ts+ a single class without maintainer buy-in.
Repo Map
src/extension.ts: activation entry point; initializes logging/localization/configuration, instantiatesContextOutline/ContextDecorator, registers all commands/code actions/completions, and forwards editor/document/config events to decorators andCursor.src/features/: user-facing flows.markdownEditing.ts(continue/title in context),manipulateContexts.ts(summarize + start new context),filePathDiff.ts(list/apply rename/delete diffs),nameAndSave.ts(LLM-suggested filepath + save),pasteAsPrettyText.ts(rewrite clipboard in-place).src/llm/: shared LLM plumbing.index.tsdefines shared types (CopilotOptions,ToolContext, etc.).requests.tshostsChatIntent,ChatRequest, andChatRequestBuilder(parses role markers,copilot-options/copilot-tools, multimodal parts).sessions.tsstreams or batches via theaiSDK based oncopilotOptions.stream.providers.tsnormalizes copilot options/config (legacy OpenAI fields included) into backend call settings, attachesresponse_formathints, and builds OpenAI/OpenAI Responses/Azure/Google Vertex/Ollama/OpenRouter models plus provider tool factories.tools.tsimplementsToolProvider(builtin/provider/custom/VS Code LM tools, execution).src/utils/: helpers. Highlights:index.ts(EOL/range helpers, URI resolution),configuration.ts(settings + migration),context.ts(ContextOutline+ContextDecorator+resolveImport),cursor.ts(streaming insertion + progress UI),indention.ts(context-aware formatting),localization.ts,logging.ts,json.ts(deep merge),signatureParser.ts(TypeScript -> JSON Schema).src/test/: Mocha suites (extension.test.ts,llm/requests.test.ts,llm/sessions.test.ts,llm/tools.test.ts,utils/signatureParser.test.ts) running in the VS Code harness..agent/PLANS.md: ExecPlan contract; follow before creating/updating any plan.dist/,out/, packaged.vsix: generated artifacts; regenerate via scripts instead of editing directly.snippets/,media/,images/: extension assets referenced frompackage.json.tools/run_github_actions.sh: local wrapper aroundnektos/actfor replaying GitHub workflows (requires Docker +GITHUB_TOKEN).
Extension Architecture
- Activation wires logging/localization/config, constructs
ContextOutline/ContextDecorator, registers commands (continue + multimodal continue/title/summarize/name/save/diff apply/list/paste pretty/indent/outdent), code actions, and completion items. Document/selection changes update decorators and activeCursorsessions;deactivatedisposes all cursors. - Code actions and completion items surface
continueInMultimodalContextto send selections withsupportsMultimodalso image/file parts are attached to the request. ContextOutlinesegments documents by indentation and# Copilot Context:markers;ContextDecoratordims inactive ranges based onmarkdown.copilot.contextsettings usingts-debounce.Cursor(src/utils/cursor.ts) is the streaming insertion adapter: wraps edits in a mutex, batches streamed deltas until a newline, keeps a 📝 decoration, updates positions ononDidChangeTextDocument, runs work insidewithProgress, and aborts/cleans up on cancellation or errors.- Feature flows use
Cursorfor streaming insertion.markdownEditingoutdents the selection, prepends**User:**if missing, appends**Copilot:**, optionally injects context lines, and streams the session.manipulateContextsappends# Copilot Context:+ heading then streams the summary.filePathDiffemits/consumes paired- path / + pathlines and validates existence/conflicts before filesystem mutations.nameAndSaveruns JSON-mode completion to suggest{ filepath }, materializes directories, saves, and prunes empty folders on cancel.pasteAsPrettyTextdeletes any selection then streams the rewritten clipboard content.
LLM and Tooling
ChatIntentcapturesdocumentUri, user input, optional context lines, overrides (system prompt, user append,CopilotOptions,ToolProvider), andsupportsMultimodal.ChatRequestBuilder.fromIntentapplies overrides, merges context lines with role markers, parses```json|yaml copilot-options(deep merges, legacy fields honored later) andcopilot-tools(resolved viaToolProvider), and when parsing fails returns a locale-aware correction prompt while clearing options. Multimodal intents split markdown images/<img>tags: local images/audio becomeimage/fileparts viaworkspace.fs, HTTP images stay as URLs.ChatRequest.buildclones messages/options/tool context;ChatRequest.fromIntentis a convenience wrapper.ChatSessionusesai(streamTextvsgenerateTextpicked bycopilotOptions.stream) with tool sets fromToolProvider; respects abort signals andresultTextaggregates text deltas.providers.tsmerges config defaults intoCopilotOptions, maps legacy OpenAI fields (max_tokens,top_p, penalties,stop) intoCallSettings, sets OpenAI-compatibleresponse_formathints for JSON runs, prompts for API keys when missing, parses Azure deployment URLs, and instantiates models for OpenAI, OpenAI Responses (withwebSearchtool factory), Azure (withwebSearchPreviewtool factory), Google Vertex (reads service-account JSON frombackendBaseUrland exposesgoogleSearch), Ollama, or OpenRouter (adds required headers).ToolProviderresolves tool texts: builtin groups (@context,@file,@eval!,@web), singletons (fs_read_file,fs_read_dir,fs_find_files,eval_js,web_request, providerweb_search), VS Code LM tools via^prefix(filters unsafe names), or custom tools from fencedcopilot-tool-definitionTypeScript blocks parsed bysignatureParser. Custom tool execution injectscopilot-tool-parametersJSON (args, current URI/time) then runs a nestedChatSession(stream:false) expecting{ "final_answer": string }. Builtins rely onfetch,vscode.workspace.fs,resolveRootUri,resolveFragmentUri, andchardet;fs_find_filesrespects untitled docs by resolving to the workspace root.
Configuration and Localization
utils/configuration.tsmigrates legacymarkdown.copilot.openAI.*settings, exposes strongly-typed getters/setters, resolves"→ Model Name Text", and centralizes defaults consumed by LLM clients and tooling. Backend protocols now include Google Vertex; for Vertex thebackend.baseUrlvalue is a URI to the service-account JSON read viaworkspace.fs. Indent characters and inactive opacity come frommarkdown.copilot.context.*.utils/localization.tsloadspackage.nls*.jsonvia@vscode/l10n, falls back to English with a logged warning if a locale pack is missing, and exposest().
Build / Test Commands
npm install— install dependencies.npm run compile— single webpack build (desktop bundle).npm run watch— webpack watch for live rebuilds.npm run lint— eslint withtypescript-eslint.npm run compile-tests— removesout/and runstsc -p . --outDir outto prep VS Code integration tests.xvfb-run -a npm test— VS Code test harness;pretestrunscompile-tests,compile, andlint. (Headlessnpm testwithout X/DBus typically fails.)npm run test:web— builds + launches the web extension tests (headless viavscode-test-web).npm run package— production webpack bundle with hidden source maps for publishing.
Coding Conventions
- TypeScript is
strict; indentation uses tabs and strings prefer single quotes. - Avoid editing generated output (
dist/,out/, packaged.vsix); regenerate instead. - ESLint enforces
eqeqeq,prefer-const, strict naming (camelCase for values/functions, PascalCase for types), and no implicitany. - Avoid defining interfaces when only a single class implements them.
Testing Guidance
- Add suites under
src/test/using*.test.ts(or.mjswhen Node APIs are required). Tests run inside the VS Code runner; stub remote services when practical. npm run testis the default CI parity run; usenpm run watch-testsfor a TSC watch loop when iterating on suites.- Current coverage: activation/config defaults (
extension.test.ts), request construction (llm/requests.test.ts), session streaming/abort handling (llm/sessions.test.ts), tool provider behaviors including provider web search/custom tools (llm/tools.test.ts), and the TypeScript → JSON Schema parser (utils/signatureParser.test.ts). Use them as templates for deterministic logic. - Cover new commands, configuration surfaces, serialization code paths, and deterministic logic split out of LLM interactions. For LLM-heavy flows, isolate logic so it can be tested without live API calls.
PR Discipline
- Commit subjects: imperative mood, roughly ≤70 chars. Reference issues with
Fixes #123when relevant. - Summarize user-visible changes, list doc/localization updates, and attach media for UI shifts.
- Ensure
npm run lintandnpm run testsucceed before requesting review.
Key Implementation Notes
Cursorowns streaming insertion and progress UI. It serializes edits with anasync-mutex, batches deltas until a newline, decorates the cursor position, updates insertion points on text document changes, and disposes all sessions ondeactivate.ChatSessiontoggles streaming vs. batch based oncopilotOptions.stream, exposesresultText()for JSON workflows (e.g.,nameAndSave), and aborts underlying requests when canceled.ChatRequestBuilderstrips markdown role markers, merges/overrides messages (**System(Override):**), validatescopilot-options/copilot-toolsblocks (replying with a correction prompt when parse fails), merges duplicate tool declarations, and attaches multimodal parts when enabled.ContextOutline+ContextDecoratortrack the active context (indentation +# Copilot Context:markers), shade inactive ranges, and feedcollectActiveLinesfor context-aware prompts;resolveImportrecursively inlines@import "foo.md"content while deduping cycles.filePathDiff.tsexpects paired- path/+ pathlines; validates sources exist, destinations don’t conflict, and surfaces inline errors before performingworkspace.fsoperations relative to the workspace root.nameAndSave.tsruns the model in JSON mode (temperature: Number.EPSILON,response_format: 'json'), injects date/workspace variables, creates missing directories, saves the current document, and prunes newly created empty folders when the dialog is canceled.pasteAsPrettyText.tsdeletes the current selection (if any) before streaming clipboard content rewritten in the currentlanguageId, guided byinstructionsPasteAsPrettyTextMessage.ToolProviderstores tool definitions in the request-scopedToolContext; nested custom tool calls reuse the same provider instance but build their own contexts/definitions per request and can surface provider-supplied tools likeweb_searchwhen available.