@cerebriline/core 4.100.274 → 4.100.277
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/prompt-templates/claude.md +7 -7
- package/assets/prompt-templates/deepseek.md +8 -8
- package/assets/prompt-templates/default.md +14 -14
- package/assets/prompt-templates/gemma.md +5 -5
- package/assets/prompt-templates/glm.md +9 -9
- package/assets/prompt-templates/kimi-k3.md +8 -8
- package/assets/prompt-templates/kimi.md +10 -10
- package/assets/prompt-templates/minimax-m3.1-flash.md +9 -8
- package/assets/prompt-templates/minimax.md +12 -10
- package/assets/prompt-templates/nemotron.md +9 -9
- package/assets/prompt-templates/qwen.md +9 -9
- package/dist/cloud/index.js +2 -2
- package/dist/document-reader-child.js +20 -20
- package/dist/extensions/browser/chrome-browser-driver.d.ts +50 -0
- package/dist/extensions/browser/chrome-render-driver.d.ts +36 -0
- package/dist/extensions/config/prompt-template-review.d.ts +1 -1
- package/dist/extensions/diagnostics/check-file-diagnostics.d.ts +99 -0
- package/dist/extensions/diagnostics/editor-diagnostics.d.ts +125 -0
- package/dist/extensions/diagnostics/render.d.ts +25 -0
- package/dist/extensions/diagnostics/types.d.ts +52 -0
- package/dist/extensions/lsp/lsp-connection.d.ts +138 -0
- package/dist/extensions/lsp/lsp-host.d.ts +134 -0
- package/dist/extensions/tools/ask-lsp.d.ts +1 -1
- package/dist/extensions/tools/browser.d.ts +1 -1
- package/dist/extensions/tools/check-file.d.ts +18 -3
- package/dist/extensions/tools/command-guard.d.ts +4 -3
- package/dist/extensions/tools/delimiter-balance.d.ts +50 -0
- package/dist/extensions/tools/edit-verification.d.ts +13 -4
- package/dist/extensions/tools/error-locations.d.ts +1 -1
- package/dist/extensions/tools/executors/awk-parser.d.ts +5 -0
- package/dist/extensions/tools/executors/awk.d.ts +14 -2
- package/dist/extensions/tools/executors/bash.d.ts +2 -0
- package/dist/extensions/tools/executors/document/formats.d.ts +4 -0
- package/dist/extensions/tools/executors/document/images.d.ts +6 -1
- package/dist/extensions/tools/executors/document/legacy.d.ts +9 -0
- package/dist/extensions/tools/executors/file-read.d.ts +15 -0
- package/dist/extensions/tools/executors/read-receipts.d.ts +10 -0
- package/dist/extensions/tools/executors/search.d.ts +2 -2
- package/dist/extensions/tools/executors/sed.d.ts +40 -0
- package/dist/extensions/tools/executors/unchanged-reads.d.ts +6 -0
- package/dist/extensions/tools/executors/web-fetch.d.ts +12 -0
- package/dist/extensions/tools/executors/whole-file.d.ts +7 -2
- package/dist/extensions/tools/helpers.d.ts +15 -1
- package/dist/extensions/tools/jev.d.ts +1 -1
- package/dist/extensions/tools/list-files.d.ts +17 -1
- package/dist/extensions/tools/media-endpoint.d.ts +16 -0
- package/dist/extensions/tools/model-tool-routing.d.ts +6 -0
- package/dist/extensions/tools/schemas.d.ts +12 -12
- package/dist/extensions/tools/task-progress.d.ts +2 -0
- package/dist/extensions/tools/team/agent-check.d.ts +15 -2
- package/dist/extensions/tools/team/agent-controls.d.ts +1 -1
- package/dist/extensions/tools/team/batch-report.d.ts +8 -0
- package/dist/extensions/tools/team/lead-agent-tools.d.ts +2 -2
- package/dist/extensions/tools/transform-image.d.ts +11 -0
- package/dist/hub/daemon/entry.js +718 -635
- package/dist/hub/index.js +703 -620
- package/dist/index.d.ts +9 -1
- package/dist/index.js +987 -874
- package/dist/remote/remote-helper-entry.js +2 -2
- package/dist/remote/remote-helper.js +2 -2
- package/dist/runtime/atomic/check-progress.d.ts +13 -0
- package/dist/runtime/atomic/file-revisions.d.ts +15 -1
- package/dist/runtime/atomic/oracle.d.ts +14 -0
- package/dist/runtime/atomic/page-check.d.ts +12 -2
- package/dist/runtime/atomic/plan-tool.d.ts +14 -2
- package/dist/runtime/atomic/protocol.d.ts +2 -0
- package/dist/runtime/atomic/restore-file-tool.d.ts +3 -3
- package/dist/runtime/atomic/snapshot.d.ts +15 -0
- package/dist/runtime/atomic/stalled-checks.d.ts +12 -4
- package/dist/runtime/atomic/transaction-controller.d.ts +10 -0
- package/dist/runtime/atomic/unparseable-change.d.ts +3 -1
- package/dist/runtime/safety/loop-detection.d.ts +15 -1
- package/dist/services/global-settings.d.ts +3 -3
- package/dist/services/retrieval/memory.d.ts +9 -0
- package/dist/services/sdd/sdd-engine.d.ts +14 -1
- package/package.json +11 -7
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { BrowserDriver } from "../tools/browser";
|
|
2
|
+
/** The extension's local-mode user agent. */
|
|
3
|
+
export declare const CHROME_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36";
|
|
4
|
+
/**
|
|
5
|
+
* Where Chrome usually is, in the order a Linux or macOS box tends to have it.
|
|
6
|
+
* Built on each call so an environment set after import is read.
|
|
7
|
+
*/
|
|
8
|
+
export declare function chromeCandidates(): string[];
|
|
9
|
+
/**
|
|
10
|
+
* The browser this machine already has. No download: a host that silently
|
|
11
|
+
* pulled 150 MB on the first tool call would be a worse surprise than a clear
|
|
12
|
+
* message saying which paths were tried.
|
|
13
|
+
*/
|
|
14
|
+
export declare function findChrome(): string | undefined;
|
|
15
|
+
export declare class MissingChromeError extends Error {
|
|
16
|
+
constructor();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* How a host hands over puppeteer: `() => import("puppeteer-core")` written in
|
|
20
|
+
* the host's own code, so its bundler sees the import and includes the module.
|
|
21
|
+
*/
|
|
22
|
+
export type PuppeteerLoader = () => Promise<unknown>;
|
|
23
|
+
/**
|
|
24
|
+
* Load puppeteer-core, or say what is missing. Kept in one place so both
|
|
25
|
+
* drivers fail the same way when a host was installed without it.
|
|
26
|
+
*/
|
|
27
|
+
export declare function loadPuppeteer(loader?: PuppeteerLoader): Promise<unknown>;
|
|
28
|
+
export interface ChromeBrowserDriverOptions {
|
|
29
|
+
headless?: boolean;
|
|
30
|
+
/** Chrome's executable. Defaults to the first of `chromeCandidates()` that exists. */
|
|
31
|
+
chromePath?: string;
|
|
32
|
+
launchTimeoutMs?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Arguments Chrome starts with. The default disables the sandbox, because
|
|
35
|
+
* a CLI is routinely run as root in a container, where Chrome's sandbox
|
|
36
|
+
* refuses to start; this browser only opens pages the model could already
|
|
37
|
+
* read off disk.
|
|
38
|
+
*/
|
|
39
|
+
args?: string[];
|
|
40
|
+
/** How to load puppeteer-core. Defaults to resolving the installed peer. */
|
|
41
|
+
loadPuppeteer?: PuppeteerLoader;
|
|
42
|
+
}
|
|
43
|
+
export declare const DEFAULT_CHROME_ARGS: string[];
|
|
44
|
+
/**
|
|
45
|
+
* A driver that launches Chrome on first use and keeps it for the session,
|
|
46
|
+
* answering every action as the extension's `BrowserSession` (local mode)
|
|
47
|
+
* does. The tool owns the lifecycle -- it builds the driver lazily and calls
|
|
48
|
+
* `closeBrowser` at the end.
|
|
49
|
+
*/
|
|
50
|
+
export declare function createChromeBrowserDriver(options?: ChromeBrowserDriverOptions): BrowserDriver;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type RenderDriver, type RenderRequest, type RenderResult } from "../tools/render-image";
|
|
2
|
+
import { type PuppeteerLoader } from "./chrome-browser-driver";
|
|
3
|
+
/**
|
|
4
|
+
* One render in a headless Chrome: the browser half of `render_image` (and of
|
|
5
|
+
* `transform_image`, which renders through the same driver).
|
|
6
|
+
*
|
|
7
|
+
* Moved here from the extension so any host can offer both tools: Chrome's
|
|
8
|
+
* path, its arguments and the Mermaid script are given, not looked up in VS
|
|
9
|
+
* Code's settings. A browser is started for the render and closed after it --
|
|
10
|
+
* a few hundred milliseconds beside a render that is rarely the tenth of a
|
|
11
|
+
* session, and a browser that is never kept is never left running.
|
|
12
|
+
*/
|
|
13
|
+
export interface RenderEnvironment {
|
|
14
|
+
executablePath: string;
|
|
15
|
+
/** `mermaid.min.js`. Absent: a diagram is refused with the reason. */
|
|
16
|
+
mermaidScriptPath?: string;
|
|
17
|
+
args?: string[];
|
|
18
|
+
/** How to load puppeteer-core. Defaults to resolving the installed peer. */
|
|
19
|
+
loadPuppeteer?: PuppeteerLoader;
|
|
20
|
+
}
|
|
21
|
+
export declare function renderWithChrome(request: RenderRequest, environment: RenderEnvironment): Promise<RenderResult>;
|
|
22
|
+
export interface ChromeRenderDriverOptions {
|
|
23
|
+
/**
|
|
24
|
+
* Chrome's executable, or how to find it per render (the extension asks
|
|
25
|
+
* its browser settings each time). Defaults to `findChrome()`.
|
|
26
|
+
*/
|
|
27
|
+
executablePath?: string | (() => string | undefined | Promise<string | undefined>);
|
|
28
|
+
/** `mermaid.min.js`; without it a Mermaid diagram is refused with the reason. */
|
|
29
|
+
mermaidScriptPath?: string | (() => string | undefined);
|
|
30
|
+
/** Chrome's arguments, or how to read them per render. Defaults to `DEFAULT_CHROME_ARGS`. */
|
|
31
|
+
args?: string[] | (() => string[] | Promise<string[]>);
|
|
32
|
+
/** How to load puppeteer-core. Defaults to resolving the installed peer. */
|
|
33
|
+
loadPuppeteer?: PuppeteerLoader;
|
|
34
|
+
}
|
|
35
|
+
/** A `RenderDriver` over `renderWithChrome`, for `render_image` and `transform_image`. */
|
|
36
|
+
export declare function createChromeRenderDriver(options?: ChromeRenderDriverOptions): RenderDriver;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type PromptTemplate } from "@cerebriline/shared";
|
|
2
2
|
import { type CompactionPromptSources } from "./prompt-template-compaction";
|
|
3
3
|
export declare const DEFAULT_REQUIRED_REWRITES: readonly ["read_files", "search_codebase", "editor", "apply_patch", "run_commands", "fetch_web_content", "check_file", "ask_lsp", "grep", "sed", "awk"];
|
|
4
|
-
export declare const PROMPT_TEMPLATE_REVIEW_INSTRUCTIONS = "You are being shown the prompt Cline gives you when it uses you as a coding agent: a system prompt and a set of tool descriptions. You are the intended reader of this text. Rewrite it into the form you would rather receive.\n\nThis is not a copy-editing task. The prompt below was written by someone reasoning about how you read, and they may have been wrong. Where a section is phrased in a way you would skim, reorder or restate it. Where a rule matters and is buried, put it where you would be when you are about to break it. Where something is repeated to no effect, cut it.\n\nFour failures are observed in practice with models in your family, and the rewrite is judged on whether it prevents them:\n\n1. Reaching for shell commands to do file work \u2014 'cat' to read, 'sed -i' or 'echo >' to write, 'grep' to search \u2014 when dedicated tools exist and are always available.\n2. Serialising independent work across turns: one read, wait, one read, wait, when all of them were known at the start.\n3. Announcing an intention instead of acting on it, or claiming a task is finished without reading back what was written.\n4. Answering a question about a symbol with a text search. Asking where something is defined, what uses it, what implements it, or what a name means, and then grepping for it and reading several files to work out which hit was the real one \u2014 when the IDE's language servers already know the answer exactly and will give it in one call. The same failure in its other form: running a compiler or a linter through the shell to find out whether one file is valid, and waiting for a whole-project build to answer a one-file question.\n\nOne thing you must get right, and which prompts written for this get wrong in both directions:\n\nA coding agent is multi-turn, and the end of a turn is never in itself the end of the work. What is final is the completion of the assigned work \u2014 the task, the work package, the milestone, the request. An end of turn may be a milestone reached, a point where you need direction, guidance or a clarification from the user, or simply an intermediate step between two things the user asked for. So:\n\n- Do not treat \"I have stopped emitting tool calls\" as \"the work is done\". It is not a signal about the work at all.\n- Do not write a rule that makes stopping feel like failure, such as \"a response without a tool call is considered complete\". A rule like that buys one more unnecessary tool call on every finished task, and it teaches the wrong thing: that continuing is always correct.\n- Keep your attention on the long horizon of the assigned work rather than on the current turn. Ending a turn to ask a question is correct when you need the answer. Ending it while work you were asked to do remains untouched, and saying nothing about that, is not.\n\nFour more things are settled by measurement rather than by opinion, and a rewrite is judged on whether it keeps them:\n\n- The checker and the run belong in the same turn. Call 'check_file' and the thing that executes the code - 'run_commands', or 'browser' for a page - together, not one or the other. Running it says *that* something is broken and where the parser gave up; the checker says *which line* to edit. Each is half the answer, and the half you skip is the half the turn gets spent guessing at.\n- A tool's report outranks your own reasoning about the same question. Where a tool has measured something - a delimiter scan naming the line to edit, a diagnostic naming a type - that is the measurement, and re-deriving it yourself is an estimate. Where the two disagree, it is the estimate that is wrong. Measured twice: a model called a delimiter scan a false positive, counted brackets by hand instead, and was wrong both times, at over 30,000 thinking tokens a turn. If you doubt a report, do not re-derive it - act on it and run the result. That costs milliseconds and settles it either way.\n- Make the planned changes one at a time, and confirm each one before starting the next. The cheap check that does not execute the code goes after every edit; the thing that runs the code is what settles whether the change was right. Six edits made together and checked once leave six things to undo and no way to tell which one was wrong - measured across ten runs, the template that said otherwise drew 13.6 'restore_file' calls per run against 0.23 for the family that did not.\n- Do not re-read a file to confirm your own edit. The edit call already reports whether it landed and what changed, and that is the confirmation. Measured on one session: 'read_files' was called 33 times, 31 of them byte-identical, returning 440,013 characters against a file of 14 KB - four times the tokens that session spent on all of its reasoning. Read again when the call failed, or when you need content you have not seen. A rule that says to read a file back after every edit is the one thing here you must not write.\n\nHard constraints:\n\n- Keep every placeholder exactly as written, including the braces: {{PLATFORM_NAME}}, {{CURRENT_DATE}}, {{IDE_NAME}}, {{CWD}}, {{CLINE_RULES}}, {{CLINE_METADATA}}, {{DEFAULT}}. They are substituted at runtime; a renamed or dropped placeholder breaks the prompt.\n- Keep the tool names exactly as written. They are the wire names of real tools.\n- Do not invent tools, parameters, or capabilities. Describe only what is described below.\n- Keep the file structure: YAML frontmatter between --- markers, then '# system', then one '# tool: <name>' section for EVERY tool listed below. Not only the ones you want to change \u2014 every one of them.\n- Covering every tool is a hard requirement. A tool with no section keeps its built-in description, and that fallback exists for exactly one situation: Cline gains a new tool and the templates have not been regenerated yet. It is not a way to skip tools you have nothing to say about. A template that covers six of thirty-one tools is not using the fallback, it is relying on it, and nothing in the file shows which twenty-five were left out.\n- '{{DEFAULT}}' expands to the tool's built-in description at runtime, and it is how you cover a tool cheaply. Where you would improve on the built-in wording, write your own and put '{{DEFAULT}}' on its own line where the built-in text should follow. Where you would not, the entire section body may be just '{{DEFAULT}}'. Either is a covered tool; an absent section is not.\n- Text you write beside '{{DEFAULT}}' is sent in addition to the built-in description, not instead of it, on every request. So write only what you add: the rule a model in your family breaks, the case it misreads, the one example that settles it. Do not restate or paraphrase what the built-in text already says; it follows anyway, and a restatement means the reader takes in the same thing twice. If you want to say everything in your own words, drop '{{DEFAULT}}' and write the whole description instead.\n- These eight tools must be written in your own words, and a section containing only '{{DEFAULT}}' is not acceptable for any of them: read_files, search_codebase, editor, apply_patch, run_commands, fetch_web_content, check_file, ask_lsp. They are the tools models in your family are observed to misuse, so they are the whole reason this template exists. For these eight, your own text \u2014 not the inherited text \u2014 has to carry the three things listed below: every value of any closed set, every argument and when to use it, and what comes back. Adding '{{DEFAULT}}' after your text is allowed and does not excuse you from any of that.\n- For 'ask_lsp', say when to reach for it, not only what it does. List at least three concrete situations as the reader actually meets them \u2014 \"about to search for a name to find where it is defined\", \"about to open a file just to read a signature\", \"about to scroll or count brackets to work out a file's structure\" \u2014 each pointing at the operation that answers it, and name 'search_codebase' as the thing those situations would otherwise go to. This is not padding: measured across a whole session against a real bug, a template that described all eight operations correctly and said only \"prefer this over search_codebase for anything about a symbol\" produced zero calls to the tool, while the model hand-rolled the same answers in the shell twenty times. It could not recognise the moment.\n- Do not copy a built-in description out word for word. That is a snapshot: it says the same thing today and stops tracking the built-in text tomorrow, so the next edit to it reaches every model except you. If you would not change the wording, write '{{DEFAULT}}' \u2014 that is what it is for.\n- Where you rule a use of a tool out, name the tool that replaces it. 'run_commands' in particular must name 'read_files', 'editor' and 'search_codebase' in your own text: \"do not use this for file operations when dedicated tools exist\" is a rule the reader has to already know the answer to in order to follow, which is the same as not writing it.\n- Two of those eight \u2014 'run_commands' and 'skills' \u2014 must keep '{{DEFAULT}}' in the section as well. Their built-in descriptions are not fixed text: 'run_commands' is composed against the shell that will actually run the commands, so PowerShell, cmd and a POSIX shell get different quoting and sequencing advice, and 'skills' appends the skills installed on that machine. Replace either outright and you freeze one machine's answer into every machine's prompt, silently. Write your own text and put '{{DEFAULT}}' on its own line where the built-in text should follow.\n- For the other tools, a section whose body is exactly '{{DEFAULT}}' is a complete and correct answer. Do not pad them. Nothing about how you read changes what 'team_finalize_outcome' should say.\n- Emit every section exactly once. Do not repeat '# system', and do not write two '# tool: <name>' headings for the same tool. Only the last copy of a repeated section survives, so a duplicate silently throws away your own work.\n- Leave the 'match:' block in the frontmatter exactly as it is. It is what routes this template to you; change it and your rewrite reaches a different model, or none.\n\nReplace a description and you inherit everything it was carrying:\n\nIf a '# tool:' section contains '{{DEFAULT}}' anywhere, the built-in description is still delivered and you are only adding emphasis on top of it. Nothing further is asked of you for that tool \u2014 unless it is one of the eight above, which are judged on your words alone.\n\nIf it does not, your text is the only thing a model will ever see about that tool, so it must not lose what the built-in description said. Specifically, and only where the built-in text below says it:\n\n1. Closed sets. Where the built-in description lists the values an argument accepts \u2014 the operations of a language-server tool, the actions of a task tool, the statuses of a run \u2014 your replacement must list all of them too. Naming four of eight hides half the tool and a model cannot guess the rest.\n2. How to address the tool. Where the built-in description names the arguments, and says which one to use when, your replacement must say the same. A tool that can be addressed three ways needs all three, and what each is for.\n3. What comes back. Where the built-in description states an output, your replacement must state one: what each entry is named by, what it holds, and what an empty or failed result means. A model that cannot map a result back onto its request spends a turn working it out, and then stops trusting the tool. Say it in words, as the built-in text does: do not name fields such as 'query', 'result' or 'success', and do not write the result as an object like '{query, result, success, error?}'. A session receives tool results as text or as JSON, chosen when it starts, so a description of one format is false in the other.\n\nNothing is required of you that the built-in text did not already provide. Reproducing what is there is always enough; improving on it is better; dropping it is the one thing that is not allowed.\n\nDo not write 'Output:' followed by nothing, or by a single word. An empty label reads as an empty result, which is worse than saying nothing at all.\n\nFor any tool outside the eight, if restating all of that is not worth it to you, do not replace its description. Write your emphasis and leave '{{DEFAULT}}' in the section, or write nothing but the marker. That is cheaper and it is always correct.\n\nReply with the complete template file and nothing else: no preamble, no explanation, no code fence.";
|
|
4
|
+
export declare const PROMPT_TEMPLATE_REVIEW_INSTRUCTIONS = "You are being shown the prompt Cline gives you when it uses you as a coding agent: a system prompt and a set of tool descriptions. You are the intended reader of this text. Rewrite it into the form you would rather receive.\n\nThis is not a copy-editing task. The prompt below was written by someone reasoning about how you read, and they may have been wrong. Where a section is phrased in a way you would skim, reorder or restate it. Where a rule matters and is buried, put it where you would be when you are about to break it. Where something is repeated to no effect, cut it.\n\nFour failures are observed in practice with models in your family, and the rewrite is judged on whether it prevents them:\n\n1. Reaching for shell commands to do file work \u2014 'cat' to read, 'sed -i' or 'echo >' to write, 'grep' to search \u2014 when dedicated tools exist and are always available.\n2. Serialising independent work across turns: one read, wait, one read, wait, when all of them were known at the start.\n3. Announcing an intention instead of acting on it, or claiming a task is finished without reading back what was written.\n4. Answering a question about a symbol with a text search. Asking where something is defined, what uses it, what implements it, or what a name means, and then grepping for it and reading several files to work out which hit was the real one \u2014 when the IDE's language servers already know the answer exactly and will give it in one call. The same failure in its other form: running a compiler or a linter through the shell to find out whether one file is valid, and waiting for a whole-project build to answer a one-file question.\n\nOne thing you must get right, and which prompts written for this get wrong in both directions:\n\nA coding agent is multi-turn, and the end of a turn is never in itself the end of the work. What is final is the completion of the assigned work \u2014 the task, the work package, the milestone, the request. An end of turn may be a milestone reached, a point where you need direction, guidance or a clarification from the user, or simply an intermediate step between two things the user asked for. So:\n\n- Do not treat \"I have stopped emitting tool calls\" as \"the work is done\". It is not a signal about the work at all.\n- Do not write a rule that makes stopping feel like failure, such as \"a response without a tool call is considered complete\". A rule like that buys one more unnecessary tool call on every finished task, and it teaches the wrong thing: that continuing is always correct.\n- Keep your attention on the long horizon of the assigned work rather than on the current turn. Ending a turn to ask a question is correct when you need the answer. Ending it while work you were asked to do remains untouched, and saying nothing about that, is not.\n\nFour more things are settled by measurement rather than by opinion, and a rewrite is judged on whether it keeps them:\n\n- The checker and the run belong in the same turn. Call 'check_file' and the thing that executes the code - 'run_commands', or 'browser' for a page - together, not one or the other. Running it says *that* something is broken and where the parser gave up; the checker says *where*: the line the parser stops on and the lines where brackets stop pairing. Each is half the answer, and the half you skip is the half the turn gets spent guessing at.\n- A tool's report outranks your own reasoning about the same question. Where a tool has measured something - a delimiter scan naming where brackets stop pairing, a diagnostic naming a type - that is the measurement, and re-deriving it yourself is an estimate. Where the two disagree, it is the estimate that is wrong. Measured twice: a model called a delimiter scan a false positive, counted brackets by hand instead, and was wrong both times, at over 30,000 thinking tokens a turn. If you doubt a report, do not re-derive it - act on it and run the result. That costs milliseconds and settles it either way.\n- Make the planned changes one at a time, and confirm each one before starting the next. The cheap check that does not execute the code goes after every edit; the thing that runs the code is what settles whether the change was right. Six edits made together and checked once leave six things to undo and no way to tell which one was wrong - measured across ten runs, the template that said otherwise drew 13.6 'restore_file' calls per run against 0.23 for the family that did not.\n- Do not re-read a file to confirm your own edit. The edit call already reports whether it landed and what changed, and that is the confirmation. Measured on one session: 'read_files' was called 33 times, 31 of them byte-identical, returning 440,013 characters against a file of 14 KB - four times the tokens that session spent on all of its reasoning. Read again when the call failed, or when you need content you have not seen. A rule that says to read a file back after every edit is the one thing here you must not write.\n\nHard constraints:\n\n- Keep every placeholder exactly as written, including the braces: {{PLATFORM_NAME}}, {{CURRENT_DATE}}, {{IDE_NAME}}, {{CWD}}, {{CLINE_RULES}}, {{CLINE_METADATA}}, {{DEFAULT}}. They are substituted at runtime; a renamed or dropped placeholder breaks the prompt.\n- Keep the tool names exactly as written. They are the wire names of real tools.\n- Do not invent tools, parameters, or capabilities. Describe only what is described below.\n- Keep the file structure: YAML frontmatter between --- markers, then '# system', then one '# tool: <name>' section for EVERY tool listed below. Not only the ones you want to change \u2014 every one of them.\n- Covering every tool is a hard requirement. A tool with no section keeps its built-in description, and that fallback exists for exactly one situation: Cline gains a new tool and the templates have not been regenerated yet. It is not a way to skip tools you have nothing to say about. A template that covers six of thirty-one tools is not using the fallback, it is relying on it, and nothing in the file shows which twenty-five were left out.\n- '{{DEFAULT}}' expands to the tool's built-in description at runtime, and it is how you cover a tool cheaply. Where you would improve on the built-in wording, write your own and put '{{DEFAULT}}' on its own line where the built-in text should follow. Where you would not, the entire section body may be just '{{DEFAULT}}'. Either is a covered tool; an absent section is not.\n- Text you write beside '{{DEFAULT}}' is sent in addition to the built-in description, not instead of it, on every request. So write only what you add: the rule a model in your family breaks, the case it misreads, the one example that settles it. Do not restate or paraphrase what the built-in text already says; it follows anyway, and a restatement means the reader takes in the same thing twice. If you want to say everything in your own words, drop '{{DEFAULT}}' and write the whole description instead.\n- These eight tools must be written in your own words, and a section containing only '{{DEFAULT}}' is not acceptable for any of them: read_files, search_codebase, editor, apply_patch, run_commands, fetch_web_content, check_file, ask_lsp. They are the tools models in your family are observed to misuse, so they are the whole reason this template exists. For these eight, your own text \u2014 not the inherited text \u2014 has to carry the three things listed below: every value of any closed set, every argument and when to use it, and what comes back. Adding '{{DEFAULT}}' after your text is allowed and does not excuse you from any of that.\n- For 'ask_lsp', say when to reach for it, not only what it does. List at least three concrete situations as the reader actually meets them \u2014 \"about to search for a name to find where it is defined\", \"about to open a file just to read a signature\", \"about to scroll or count brackets to work out a file's structure\" \u2014 each pointing at the operation that answers it, and name 'search_codebase' as the thing those situations would otherwise go to. This is not padding: measured across a whole session against a real bug, a template that described all eight operations correctly and said only \"prefer this over search_codebase for anything about a symbol\" produced zero calls to the tool, while the model hand-rolled the same answers in the shell twenty times. It could not recognise the moment.\n- Do not copy a built-in description out word for word. That is a snapshot: it says the same thing today and stops tracking the built-in text tomorrow, so the next edit to it reaches every model except you. If you would not change the wording, write '{{DEFAULT}}' \u2014 that is what it is for.\n- Where you rule a use of a tool out, name the tool that replaces it. 'run_commands' in particular must name 'read_files', 'editor' and 'search_codebase' in your own text: \"do not use this for file operations when dedicated tools exist\" is a rule the reader has to already know the answer to in order to follow, which is the same as not writing it.\n- Two of those eight \u2014 'run_commands' and 'skills' \u2014 must keep '{{DEFAULT}}' in the section as well. Their built-in descriptions are not fixed text: 'run_commands' is composed against the shell that will actually run the commands, so PowerShell, cmd and a POSIX shell get different quoting and sequencing advice, and 'skills' appends the skills installed on that machine. Replace either outright and you freeze one machine's answer into every machine's prompt, silently. Write your own text and put '{{DEFAULT}}' on its own line where the built-in text should follow.\n- For the other tools, a section whose body is exactly '{{DEFAULT}}' is a complete and correct answer. Do not pad them. Nothing about how you read changes what 'team_finalize_outcome' should say.\n- Emit every section exactly once. Do not repeat '# system', and do not write two '# tool: <name>' headings for the same tool. Only the last copy of a repeated section survives, so a duplicate silently throws away your own work.\n- Leave the 'match:' block in the frontmatter exactly as it is. It is what routes this template to you; change it and your rewrite reaches a different model, or none.\n\nReplace a description and you inherit everything it was carrying:\n\nIf a '# tool:' section contains '{{DEFAULT}}' anywhere, the built-in description is still delivered and you are only adding emphasis on top of it. Nothing further is asked of you for that tool \u2014 unless it is one of the eight above, which are judged on your words alone.\n\nIf it does not, your text is the only thing a model will ever see about that tool, so it must not lose what the built-in description said. Specifically, and only where the built-in text below says it:\n\n1. Closed sets. Where the built-in description lists the values an argument accepts \u2014 the operations of a language-server tool, the actions of a task tool, the statuses of a run \u2014 your replacement must list all of them too. Naming four of eight hides half the tool and a model cannot guess the rest.\n2. How to address the tool. Where the built-in description names the arguments, and says which one to use when, your replacement must say the same. A tool that can be addressed three ways needs all three, and what each is for.\n3. What comes back. Where the built-in description states an output, your replacement must state one: what each entry is named by, what it holds, and what an empty or failed result means. A model that cannot map a result back onto its request spends a turn working it out, and then stops trusting the tool. Say it in words, as the built-in text does: do not name fields such as 'query', 'result' or 'success', and do not write the result as an object like '{query, result, success, error?}'. A session receives tool results as text or as JSON, chosen when it starts, so a description of one format is false in the other.\n\nNothing is required of you that the built-in text did not already provide. Reproducing what is there is always enough; improving on it is better; dropping it is the one thing that is not allowed.\n\nDo not write 'Output:' followed by nothing, or by a single word. An empty label reads as an empty result, which is worse than saying nothing at all.\n\nFor any tool outside the eight, if restating all of that is not worth it to you, do not replace its description. Write your emphasis and leave '{{DEFAULT}}' in the section, or write nothing but the marker. That is cheaper and it is always correct.\n\nReply with the complete template file and nothing else: no preamble, no explanation, no code fence.";
|
|
5
5
|
export declare function buildPromptTemplateReviewPrompt(defaultTemplate: string, familyTemplate: string | undefined, familyTemplateName: string | undefined,
|
|
6
6
|
/** What this model is, so a new template can be told how to claim itself. */
|
|
7
7
|
target?: {
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type AgentTool } from "@cerebriline/shared";
|
|
2
|
+
import { type LintCommandResult } from "../tools/check-file";
|
|
3
|
+
import type { ReadDiagnostics, ReadText, TouchDocument } from "./types";
|
|
4
|
+
/**
|
|
5
|
+
* `check_file` answered from language-server diagnostics: the extension's
|
|
6
|
+
* tool, moved here so the CLI and automaticum's runner offer the same one.
|
|
7
|
+
*
|
|
8
|
+
* Core's other `check_file` (`tools/check-file.ts`) parses the file itself and
|
|
9
|
+
* answers a narrower question -- syntax and brackets, not types. A host with
|
|
10
|
+
* language servers -- VS Code's, or the ones `createLspHost` starts -- builds
|
|
11
|
+
* this one instead, and may hand the files no server covers to that one
|
|
12
|
+
* through `describeUnserved`.
|
|
13
|
+
*
|
|
14
|
+
* Everything about *reading* diagnostics -- waiting for the server to settle,
|
|
15
|
+
* dropping hint-level noise, capping and rendering a file's problems -- is the
|
|
16
|
+
* post-edit report's, imported from there. Two different answers to "what is
|
|
17
|
+
* wrong with this file" would be worse than either.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Deliberately written at the model that gets this wrong: `run_commands` is
|
|
21
|
+
* the tool it reaches for by reflex, so the alternatives it would otherwise
|
|
22
|
+
* type are named here, and so is every word a question about it uses -- a
|
|
23
|
+
* tool the model cannot name is a tool it does not have.
|
|
24
|
+
*/
|
|
25
|
+
export declare const DIAGNOSTICS_CHECK_FILE_TOOL_DESCRIPTION = "Check files for errors and warnings, using the editor's own language servers (LSP). **This is the linter.** It is also the type checker, the syntax check, and the source of the problems that would show in a Problems panel \u2014 whichever of those words the question uses, this is the tool that answers it. The results are live and follow your edits: one is current as of the moment you ask, so if it still reports a problem after an edit, the problem is still there. Restarting a language server is neither possible nor necessary from here.\n\nAsk this before running a checker yourself. For a file whose language a language server covers, it answers the same question as `tsc`, `eslint`, `biome`, `ruff`, `mypy`, `go build` or `cargo check` would \u2014 for the files you name, in milliseconds, without building the project.\n\nWhen to call it:\n- Whenever the question is about the linter, lint errors, diagnostics, problems, warnings, type errors, syntax errors or compile errors \u2014 \"how many errors is the linter reporting?\", \"is it clean now?\", \"what is still broken?\". You have no other way to know, and the report you were shown after an earlier edit does not answer it: that was true then, and you have edited since.\n- After editing a file, to confirm the edit is valid before moving on.\n- Before reporting a task finished, on every file you changed.\n- On a file you are about to change, when you want to know what was already wrong with it.\n\nPass every file you want checked in one call.\n\nRead a clean result carefully. \"No problems reported by the editor\" is conclusive only where a language server covers that file, and it does not for every language on every machine. If this reports nothing and you have reason to expect a problem, or the project has a checker the language servers do not run, run that checker with `run_commands`. Tests and builds are always `run_commands`; this tool does not run them.\n\nOutput: plain text, one section per file you named, each problem on its own line as `file:line:column` with its severity and message. A file with nothing wrong says so in one line. Problems being listed is this tool working, not failing.\n\nA parse error is reported where the parser gave up. That is where the code stopped making sense to it, which is often but not always where the mistake is: a bracket left open earlier makes it give up later. When a file's brackets do not match, a `Delimiter scan` section adds the lines where they stop pairing up and how many each line is out by, one line per place the trouble starts \u2014 read both before you edit, and work through every line listed before re-checking. A count says where brackets stop pairing, not which bracket is wrong, so read the code at those lines rather than editing them blind. The scan reads the whole file from line 1, and names each bracket by its line, its column and the text just before it: find it by that text rather than by counting columns. Do not count brackets yourself \u2014 the scan skips strings, comments and regex literals, which counting characters does not. It runs whether or not the editor reported anything, so it can appear beneath a file the editor called clean \u2014 no language server checks the script inside an `.html` file, and there this is the only report you will get.";
|
|
26
|
+
export declare const DIAGNOSTICS_CHECK_FILE_TOOL_INPUT_SCHEMA: {
|
|
27
|
+
readonly type: "object";
|
|
28
|
+
readonly properties: {
|
|
29
|
+
readonly paths: {
|
|
30
|
+
readonly type: "array";
|
|
31
|
+
readonly items: {
|
|
32
|
+
readonly type: "string";
|
|
33
|
+
};
|
|
34
|
+
readonly description: "Files to check. Absolute, or relative to the working directory. Pass all of them in one call.";
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
readonly required: readonly ["paths"];
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* A shorter settle budget than the post-edit report uses: that one runs the
|
|
41
|
+
* instant a write lands; this one usually runs against a file that has been
|
|
42
|
+
* sitting still, so the server has already had its chance.
|
|
43
|
+
*/
|
|
44
|
+
export declare const CHECK_SETTLE_BUDGET: {
|
|
45
|
+
pollMs: number;
|
|
46
|
+
timeoutMs: number;
|
|
47
|
+
};
|
|
48
|
+
/** What the editor holds for a file: the text its language server checks. */
|
|
49
|
+
export interface LoadedDocument {
|
|
50
|
+
text: string;
|
|
51
|
+
/** The user has changes to it they have not saved. */
|
|
52
|
+
dirty: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface DiagnosticsCheckFileToolOptions {
|
|
55
|
+
cwd: string;
|
|
56
|
+
readDiagnostics: ReadDiagnostics;
|
|
57
|
+
/**
|
|
58
|
+
* Hand a file to its server before reading its diagnostics: a file the
|
|
59
|
+
* server has never seen has none, and none reads as clean. For a host
|
|
60
|
+
* whose servers are its own (`LspHost.touch`).
|
|
61
|
+
*/
|
|
62
|
+
touch?: TouchDocument;
|
|
63
|
+
/**
|
|
64
|
+
* Make the editor load a file it may never have opened, and report its
|
|
65
|
+
* copy, which is compared with the disk (VS Code). Nothing returned skips
|
|
66
|
+
* the comparison.
|
|
67
|
+
*/
|
|
68
|
+
loadDocument?: (filePath: string) => Promise<LoadedDocument | undefined>;
|
|
69
|
+
/**
|
|
70
|
+
* Whether a server answers for a file. With `describeUnserved`, a file no
|
|
71
|
+
* server answers for gets that answer instead of "no problems reported".
|
|
72
|
+
*/
|
|
73
|
+
serves?: (filePath: string) => boolean;
|
|
74
|
+
/** The answer for a file no server covers -- core's syntax check, say. */
|
|
75
|
+
describeUnserved?: (absolutePath: string, displayPath: string) => Promise<string | undefined>;
|
|
76
|
+
/** The user's lint command, if they set one. */
|
|
77
|
+
resolveLintCommand?: () => string | undefined;
|
|
78
|
+
/** Runs the configured command. Injected so tests never spawn anything. */
|
|
79
|
+
runLintCommand?: (template: string, filePath: string, signal?: AbortSignal) => Promise<LintCommandResult>;
|
|
80
|
+
/**
|
|
81
|
+
* What reported paths are written relative to. Defaults to `cwd`; the
|
|
82
|
+
* extension writes them relative to the workspace root it reports.
|
|
83
|
+
*/
|
|
84
|
+
displayCwd?: () => string | Promise<string>;
|
|
85
|
+
/** Replaces the description, for a host that words it for its own setting. */
|
|
86
|
+
description?: string;
|
|
87
|
+
/** The disk, as the host reads it. Defaults to the real one. */
|
|
88
|
+
readFile?: ReadText;
|
|
89
|
+
/** Injection point for tests; defaults to a real timer. */
|
|
90
|
+
delay?: (ms: number) => Promise<void>;
|
|
91
|
+
onError?: (message: string, error: unknown) => void;
|
|
92
|
+
}
|
|
93
|
+
interface CheckFileInput {
|
|
94
|
+
paths?: unknown;
|
|
95
|
+
}
|
|
96
|
+
/** Accept the shapes a model actually sends, not only the documented one. */
|
|
97
|
+
export declare function readRequestedPaths(input: CheckFileInput | undefined): string[];
|
|
98
|
+
export declare function createDiagnosticsCheckFileTool(options: DiagnosticsCheckFileToolOptions): AgentTool;
|
|
99
|
+
export {};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { type AgentHooks } from "@cerebriline/shared";
|
|
2
|
+
import type { DiagnosticSeverityName, HostDiagnostic, HostFileDiagnostics, ReadDiagnostics, ReadText, TouchDocument } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Severities worth a turn of the model's attention.
|
|
5
|
+
*
|
|
6
|
+
* Errors and warnings are claims that something is wrong. Information and hint
|
|
7
|
+
* diagnostics are mostly editor affordances -- "convert to template literal",
|
|
8
|
+
* "this import could be type-only" -- and a model handed them will act on them,
|
|
9
|
+
* turning every edit into a style refactor nobody asked for.
|
|
10
|
+
*/
|
|
11
|
+
export declare const REPORTED_SEVERITIES: readonly DiagnosticSeverityName[];
|
|
12
|
+
/**
|
|
13
|
+
* Diagnostics reported per file. A truncated list still says "this edit broke
|
|
14
|
+
* something, look here", which is the whole job. An untruncated one can be
|
|
15
|
+
* longer than the file.
|
|
16
|
+
*/
|
|
17
|
+
export declare const MAX_DIAGNOSTICS_PER_FILE = 20;
|
|
18
|
+
/**
|
|
19
|
+
* How long to wait for the language server to catch up with the write.
|
|
20
|
+
*
|
|
21
|
+
* Diagnostics are published asynchronously and a request issued the instant an
|
|
22
|
+
* edit lands reads the state before it. The wait ends early as soon as the
|
|
23
|
+
* file's diagnostics stop changing, so the common case costs one poll interval
|
|
24
|
+
* rather than the whole budget. Small on purpose: this sits between the model
|
|
25
|
+
* and its next turn, and a slow linter must not become a slow agent.
|
|
26
|
+
*/
|
|
27
|
+
export declare const SETTLE_POLL_MS = 250;
|
|
28
|
+
export declare const SETTLE_TIMEOUT_MS = 2000;
|
|
29
|
+
export declare const sleep: (ms: number) => Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Extract the files a file-writing tool call is about.
|
|
32
|
+
*
|
|
33
|
+
* `editor` names its file directly. `apply_patch` carries a patch body whose
|
|
34
|
+
* grammar names the files in its headers, which is the only place they appear.
|
|
35
|
+
*/
|
|
36
|
+
export declare function readTargetPaths(toolName: string, input: unknown): string[];
|
|
37
|
+
/**
|
|
38
|
+
* Whether a file is one an editor diagnostic can say something useful about.
|
|
39
|
+
* A rejection list rather than an allow list: the set of things an editor
|
|
40
|
+
* lints grows with every extension installed, and a Dockerfile, a Makefile or
|
|
41
|
+
* a `.env` has no extension to allow in the first place.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isLintableFile(filePath: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* A path in the form used to compare two paths for identity.
|
|
46
|
+
*
|
|
47
|
+
* Windows filesystems are case-insensitive, and the two sides come from
|
|
48
|
+
* different places: the editor reports the path as the workspace has it, and
|
|
49
|
+
* the model types it. Measured: the workspace was `c:\Users\...` and the model
|
|
50
|
+
* asked about `C:\Users\...`, and six `check_file` calls answered "no problems"
|
|
51
|
+
* for a file `node --check` rejects. Only the case is normalized; this is a
|
|
52
|
+
* comparison key, not a canonical path.
|
|
53
|
+
*/
|
|
54
|
+
export declare function comparablePath(filePath: string): string;
|
|
55
|
+
/** Whether two paths name the same file, as this platform judges it. */
|
|
56
|
+
export declare function samePath(a: string, b: string): boolean;
|
|
57
|
+
export declare function filterToPaths(diagnostics: readonly HostFileDiagnostics[], absolutePaths: ReadonlySet<string>): HostFileDiagnostics[];
|
|
58
|
+
/** The diagnostics as the editor reports them, without a host's `pending` mark. */
|
|
59
|
+
export declare function withoutPending(files: readonly HostFileDiagnostics[]): HostFileDiagnostics[];
|
|
60
|
+
export declare function isReportableDiagnostic(diagnostic: HostDiagnostic): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Render one file's reportable diagnostics, or an empty string when there are
|
|
63
|
+
* none -- silence is the correct output for a clean edit, and the cheapest.
|
|
64
|
+
*/
|
|
65
|
+
export declare function renderFileDiagnostics(cwd: string, filePath: string, diagnostics: readonly HostDiagnostic[], readText?: ReadText): Promise<string>;
|
|
66
|
+
export declare function formatIntroducedDiagnostics(cwd: string, before: readonly HostFileDiagnostics[], after: readonly HostFileDiagnostics[]): Promise<string>;
|
|
67
|
+
/**
|
|
68
|
+
* Append a rendered block to a tool result without destroying its shape.
|
|
69
|
+
*
|
|
70
|
+
* The file-writing tools return a `ToolOperationResult`, whose `result` field is
|
|
71
|
+
* what the model reads; anything else is stringified by the transport, so the
|
|
72
|
+
* block goes where a string will survive.
|
|
73
|
+
*/
|
|
74
|
+
export declare function appendToOutput(output: unknown, block: string): unknown;
|
|
75
|
+
/**
|
|
76
|
+
* Mark a tool result as having made the file worse.
|
|
77
|
+
*
|
|
78
|
+
* The loop tracker asked "did it get anywhere?" from failure alone, which is
|
|
79
|
+
* blind to eight `editor` calls returning `success: true` while the file's
|
|
80
|
+
* diagnostics went 2 -> 20. An edit that adds problems did not get anywhere,
|
|
81
|
+
* whatever its envelope says. The flag rides on the result so the runtime can
|
|
82
|
+
* read it without this module knowing about the loop tracker.
|
|
83
|
+
*/
|
|
84
|
+
export declare function markRegressed(output: unknown): unknown;
|
|
85
|
+
/**
|
|
86
|
+
* Read the files' diagnostics once the language servers have stopped
|
|
87
|
+
* changing their mind, or once the budget runs out -- whichever comes first.
|
|
88
|
+
* A file changed after its server last reported on it is `pending`, and a
|
|
89
|
+
* pending answer is not a settled one however long it has stayed the same.
|
|
90
|
+
*/
|
|
91
|
+
export declare function readSettledDiagnostics(absolutePaths: ReadonlySet<string>, read: ReadDiagnostics, delay: (ms: number) => Promise<void>, budget?: {
|
|
92
|
+
pollMs?: number;
|
|
93
|
+
timeoutMs?: number;
|
|
94
|
+
}): Promise<HostFileDiagnostics[]>;
|
|
95
|
+
export interface EditorDiagnosticsHooksOptions {
|
|
96
|
+
cwd: string;
|
|
97
|
+
readDiagnostics: ReadDiagnostics;
|
|
98
|
+
/**
|
|
99
|
+
* For a host whose servers do not watch the disk: hand a file over before
|
|
100
|
+
* the edit (so what was already wrong with it is known, as it is for a
|
|
101
|
+
* file open in an editor) and after it, as saved. Left out, the host's
|
|
102
|
+
* diagnostics are read as they stand -- VS Code reloads the file itself.
|
|
103
|
+
*/
|
|
104
|
+
touch?: TouchDocument;
|
|
105
|
+
/** Only files this says a server answers for are watched. */
|
|
106
|
+
serves?: (filePath: string) => boolean;
|
|
107
|
+
/** Injection point for tests; defaults to a real timer. */
|
|
108
|
+
delay?: (ms: number) => Promise<void>;
|
|
109
|
+
/** One record per edit, for a host's trace: what was asked and found. */
|
|
110
|
+
trace?: (entry: Record<string, unknown>) => void;
|
|
111
|
+
/** Where a failure of this feature goes. It never fails the edit. */
|
|
112
|
+
onError?: (message: string, error: unknown) => void;
|
|
113
|
+
/**
|
|
114
|
+
* What reported paths are written relative to. Defaults to `cwd`; the
|
|
115
|
+
* extension writes them relative to the workspace root it reports.
|
|
116
|
+
*/
|
|
117
|
+
displayCwd?: () => string | Promise<string>;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Hooks that report an edit's new diagnostics back to the model.
|
|
121
|
+
*
|
|
122
|
+
* Composed with whatever hooks the host already has rather than folded into
|
|
123
|
+
* them: this is not optional in the way user-authored hook scripts are.
|
|
124
|
+
*/
|
|
125
|
+
export declare function createEditorDiagnosticsHooks(options: EditorDiagnosticsHooksOptions): AgentHooks;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { DiagnosticSeverityName, HostDiagnostic, HostFileDiagnostics, ReadText } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* How a file's diagnostics are written for a model.
|
|
4
|
+
*
|
|
5
|
+
* One renderer for every host: `check_file` and the post-edit report say the
|
|
6
|
+
* same thing about the same file whether VS Code or a language server the CLI
|
|
7
|
+
* started produced it. Moved here from the extension's
|
|
8
|
+
* `integrations/diagnostics`, which now delegates to it.
|
|
9
|
+
*/
|
|
10
|
+
/** The disk, read as text. */
|
|
11
|
+
export declare const defaultReadText: ReadText;
|
|
12
|
+
/** Two diagnostics are the same claim when every field they carry matches. */
|
|
13
|
+
export declare function sameDiagnostic(a: HostDiagnostic, b: HostDiagnostic): boolean;
|
|
14
|
+
/** The diagnostics in `after` that were not in `before`, per file. */
|
|
15
|
+
export declare function getNewDiagnostics(before: readonly HostFileDiagnostics[], after: readonly HostFileDiagnostics[]): HostFileDiagnostics[];
|
|
16
|
+
/**
|
|
17
|
+
* Every file's problems of the given severities, or an empty string when there
|
|
18
|
+
* are none. `cwd` is what the paths are written relative to.
|
|
19
|
+
*/
|
|
20
|
+
export declare function diagnosticsToProblemsString(cwd: string, diagnostics: readonly HostFileDiagnostics[], severities?: readonly DiagnosticSeverityName[]): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* One file's problems, or an empty string when the list is empty. `cwd` is
|
|
23
|
+
* what the path is written relative to.
|
|
24
|
+
*/
|
|
25
|
+
export declare function singleFileDiagnosticsToProblemsString(cwd: string, filePath: string, diagnostics: readonly HostDiagnostic[], readText?: ReadText): Promise<string>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diagnostics as an editor keeps them, in the shape every host hands over.
|
|
3
|
+
*
|
|
4
|
+
* The extension reads them from VS Code (its proto `FileDiagnostics`), the
|
|
5
|
+
* CLI and automaticum's runner from the language servers they start. The
|
|
6
|
+
* tools that read them -- `check_file`, the post-edit report -- are shared,
|
|
7
|
+
* so the shape is core's: a named severity rather than either side's number
|
|
8
|
+
* (VS Code's proto counts errors from 0, LSP from 1).
|
|
9
|
+
*/
|
|
10
|
+
export type DiagnosticSeverityName = "error" | "warning" | "information" | "hint";
|
|
11
|
+
export interface DiagnosticPosition {
|
|
12
|
+
/** 0-based, as LSP has it. */
|
|
13
|
+
line: number;
|
|
14
|
+
/** 0-based. */
|
|
15
|
+
character: number;
|
|
16
|
+
}
|
|
17
|
+
export interface HostDiagnostic {
|
|
18
|
+
message: string;
|
|
19
|
+
severity: DiagnosticSeverityName;
|
|
20
|
+
range?: {
|
|
21
|
+
start?: DiagnosticPosition;
|
|
22
|
+
end?: DiagnosticPosition;
|
|
23
|
+
};
|
|
24
|
+
/** The producer, as the editor names it: "ts", "eslint", "css". */
|
|
25
|
+
source?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface HostFileDiagnostics {
|
|
28
|
+
filePath: string;
|
|
29
|
+
diagnostics: HostDiagnostic[];
|
|
30
|
+
/**
|
|
31
|
+
* The file changed after its server last reported on it, so what is held
|
|
32
|
+
* describes an older text. A reader waiting for the server to settle keeps
|
|
33
|
+
* waiting while this is set. Hosts that cannot tell leave it out.
|
|
34
|
+
*/
|
|
35
|
+
pending?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** Reads every file's current diagnostics. */
|
|
38
|
+
export type ReadDiagnostics = () => Promise<HostFileDiagnostics[]>;
|
|
39
|
+
/**
|
|
40
|
+
* Hands a server the file as it is on disk now (`save`: as just written), so
|
|
41
|
+
* its next diagnostics are about that text. The editor does this itself; a
|
|
42
|
+
* host that starts its own servers has to. Resolves to something truthy when
|
|
43
|
+
* a server holds the file.
|
|
44
|
+
*/
|
|
45
|
+
export type TouchDocument = (filePath: string, options?: {
|
|
46
|
+
save?: boolean;
|
|
47
|
+
}) => Promise<unknown>;
|
|
48
|
+
/**
|
|
49
|
+
* A file's text, as the host reads its disk. Injected where a host wants its
|
|
50
|
+
* own view -- a sandbox, a test's fake disk -- and defaulted to the real one.
|
|
51
|
+
*/
|
|
52
|
+
export type ReadText = (filePath: string) => Promise<string>;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import type { HostDiagnostic } from "../diagnostics/types";
|
|
2
|
+
export interface LspServerSpec {
|
|
3
|
+
/** How the server is named in status and errors. Defaults to `command`. */
|
|
4
|
+
name?: string;
|
|
5
|
+
/** The executable: a name looked up on PATH, or a full path. */
|
|
6
|
+
command: string;
|
|
7
|
+
args: string[];
|
|
8
|
+
/** Languages this server answers for, as LSP language ids. */
|
|
9
|
+
languages: string[];
|
|
10
|
+
/**
|
|
11
|
+
* The file whose existence says the server is installed. Defaults to
|
|
12
|
+
* `command` (looked up on PATH when it has no directory in it). A server
|
|
13
|
+
* started as `node <script>` names its script here.
|
|
14
|
+
*/
|
|
15
|
+
probe?: string;
|
|
16
|
+
/** Added to the environment the server starts with. */
|
|
17
|
+
env?: Record<string, string>;
|
|
18
|
+
/**
|
|
19
|
+
* Server-specific `initializationOptions`.
|
|
20
|
+
*
|
|
21
|
+
* Needed because a server is not always self-sufficient:
|
|
22
|
+
* `typescript-language-server` refuses to start unless it can find a
|
|
23
|
+
* TypeScript installation, and it looks in the workspace. A workspace with
|
|
24
|
+
* no `node_modules` -- which is most of the ones a model is asked to fix --
|
|
25
|
+
* gets "Could not find a valid TypeScript installation. Exiting."
|
|
26
|
+
*/
|
|
27
|
+
initializationOptions?: Record<string, unknown> | (() => Record<string, unknown> | undefined);
|
|
28
|
+
/**
|
|
29
|
+
* The settings an editor would hold for this server: sent once with
|
|
30
|
+
* `workspace/didChangeConfiguration` and read back for every
|
|
31
|
+
* `workspace/configuration` the server asks. A section nobody set answers
|
|
32
|
+
* an empty object, never null -- see `LspConnection.setting`.
|
|
33
|
+
*/
|
|
34
|
+
settings?: Record<string, unknown>;
|
|
35
|
+
/**
|
|
36
|
+
* A diagnostic's producer as the editor names it, by what the server
|
|
37
|
+
* reports: VS Code labels what tsserver reports "ts", where the server
|
|
38
|
+
* says "typescript".
|
|
39
|
+
*/
|
|
40
|
+
sources?: Record<string, string>;
|
|
41
|
+
}
|
|
42
|
+
/** The name a spec goes by. */
|
|
43
|
+
export declare function serverName(spec: LspServerSpec): string;
|
|
44
|
+
export declare function fileUri(filePath: string): string;
|
|
45
|
+
export declare function uriToPath(uri: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* A diagnostic as the editor keeps it, from what a server sent: a position,
|
|
48
|
+
* a named severity, the message and the producer. LSP leaves the severity
|
|
49
|
+
* to the client when it is absent; VS Code treats that as an error.
|
|
50
|
+
*/
|
|
51
|
+
export declare function normalizeLspDiagnostic(raw: unknown): HostDiagnostic;
|
|
52
|
+
export interface LspConnectionOptions {
|
|
53
|
+
onError?: (message: string, error: unknown) => void;
|
|
54
|
+
/** Every `textDocument/publishDiagnostics`, the path decoded. */
|
|
55
|
+
onDiagnostics?: (filePath: string, diagnostics: HostDiagnostic[]) => void;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* One server process and the conversation with it.
|
|
59
|
+
*
|
|
60
|
+
* Requests are correlated by id. A message with a `method` is the server's,
|
|
61
|
+
* whether or not it has an id: with one it is a request and is answered, and
|
|
62
|
+
* only a message without a `method` is a response to one of ours. A server
|
|
63
|
+
* that dies takes its pending requests with it rather than leaving them
|
|
64
|
+
* hanging until the timeout.
|
|
65
|
+
*/
|
|
66
|
+
export declare class LspConnection {
|
|
67
|
+
readonly spec: LspServerSpec;
|
|
68
|
+
private readonly rootPath;
|
|
69
|
+
private child;
|
|
70
|
+
private buffer;
|
|
71
|
+
private nextId;
|
|
72
|
+
private readonly pending;
|
|
73
|
+
/** What the server holds open, by URI: the text it was last sent. */
|
|
74
|
+
private readonly documents;
|
|
75
|
+
private initializing;
|
|
76
|
+
private failure;
|
|
77
|
+
private pullRefused;
|
|
78
|
+
/** What the server said it can do, from its `initialize` answer. */
|
|
79
|
+
capabilities: Record<string, unknown>;
|
|
80
|
+
private readonly onError?;
|
|
81
|
+
private readonly onDiagnostics?;
|
|
82
|
+
constructor(spec: LspServerSpec, rootPath: string, options?: LspConnectionOptions | ((message: string, error: unknown) => void));
|
|
83
|
+
/** Whether the server has been started and is still running. */
|
|
84
|
+
get started(): boolean;
|
|
85
|
+
/** Why the server is not available, once it has failed. */
|
|
86
|
+
get failed(): Error | undefined;
|
|
87
|
+
/** Started once, on the first question, and shared by every one after it. */
|
|
88
|
+
ready(): Promise<void>;
|
|
89
|
+
private start;
|
|
90
|
+
private fail;
|
|
91
|
+
private consume;
|
|
92
|
+
private dispatch;
|
|
93
|
+
/**
|
|
94
|
+
* A request of the server's own, answered as an editor answers it.
|
|
95
|
+
*
|
|
96
|
+
* Left unanswered, some servers wait for the answer before doing anything
|
|
97
|
+
* else.
|
|
98
|
+
*/
|
|
99
|
+
private answer;
|
|
100
|
+
/**
|
|
101
|
+
* A section of the settings, as an editor answers: an object, empty for a
|
|
102
|
+
* section nobody set. Never null: the CSS validator reads properties off
|
|
103
|
+
* what it is given ("Cannot read properties of null (reading
|
|
104
|
+
* 'validProperties')"), and the HTML server validates a page's `<style>`
|
|
105
|
+
* through it, so a null aborts the whole page's validation -- and a page
|
|
106
|
+
* whose script does not parse then reports no diagnostics at all.
|
|
107
|
+
*/
|
|
108
|
+
setting(section: string | undefined): unknown;
|
|
109
|
+
private send;
|
|
110
|
+
notify(method: string, params: unknown): void;
|
|
111
|
+
request(method: string, params: unknown, timeoutMs?: number): Promise<unknown>;
|
|
112
|
+
/**
|
|
113
|
+
* Make the server hold the file as it is now.
|
|
114
|
+
*
|
|
115
|
+
* Opened the first time; after that, sent whole as a change, with the next
|
|
116
|
+
* version, when it differs from what the server holds. A second `didOpen`
|
|
117
|
+
* for a document already open is a protocol error that servers answer by
|
|
118
|
+
* ignoring it -- and then answering from the old text, which is exactly
|
|
119
|
+
* the "the model edits, then asks" case. Returns whether the server was
|
|
120
|
+
* told anything.
|
|
121
|
+
*/
|
|
122
|
+
syncDocument(filePath: string, text: string, languageId: string): boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Tell the server the file was written. Some servers check only on save:
|
|
125
|
+
* rust-analyzer's type errors come from `cargo check` on `didSave`.
|
|
126
|
+
*/
|
|
127
|
+
documentSaved(filePath: string): void;
|
|
128
|
+
/** Whether this server answers `textDocument/diagnostic` when asked. */
|
|
129
|
+
get pullsDiagnostics(): boolean;
|
|
130
|
+
/**
|
|
131
|
+
* Diagnostics asked for, from a server that answers only when asked
|
|
132
|
+
* (csharp-ls). Undefined when the server does not pull, or answered with
|
|
133
|
+
* something other than a full report.
|
|
134
|
+
*/
|
|
135
|
+
pullDiagnostics(filePath: string): Promise<HostDiagnostic[] | undefined>;
|
|
136
|
+
private label;
|
|
137
|
+
dispose(): Promise<void>;
|
|
138
|
+
}
|