@ikarmic/forge-core 5.2.0 → 5.4.0
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/dist/agent/agent.js +324 -122
- package/dist/agent/cache-hints.d.ts +2 -0
- package/dist/agent/cache-hints.js +18 -3
- package/dist/agent/enhance-prompt.js +2 -1
- package/dist/agent/history-adapt.d.ts +23 -0
- package/dist/agent/history-adapt.js +114 -0
- package/dist/agent/prompts.d.ts +19 -2
- package/dist/agent/prompts.js +44 -2
- package/dist/agent/retry.d.ts +50 -0
- package/dist/agent/retry.js +192 -0
- package/dist/agent/shell-command.d.ts +23 -0
- package/dist/agent/shell-command.js +93 -0
- package/dist/agent/tool-repair.d.ts +8 -0
- package/dist/agent/tool-repair.js +16 -0
- package/dist/catalog/models-dev-snapshot.d.ts +1 -0
- package/dist/catalog/models-dev-snapshot.js +3 -0
- package/dist/catalog/models-dev.d.ts +45 -0
- package/dist/catalog/models-dev.js +155 -0
- package/dist/checkpoints/store.js +3 -1
- package/dist/context/compaction.d.ts +21 -6
- package/dist/context/compaction.js +94 -28
- package/dist/context/mask.d.ts +9 -9
- package/dist/context/mask.js +30 -1
- package/dist/format/auto-format.d.ts +22 -0
- package/dist/format/auto-format.js +39 -0
- package/dist/git/auto-commit.d.ts +4 -2
- package/dist/git/auto-commit.js +16 -5
- package/dist/github/github-tools.d.ts +1 -0
- package/dist/github/github-tools.js +9 -9
- package/dist/github/pr.d.ts +34 -0
- package/dist/github/pr.js +70 -0
- package/dist/human-text.d.ts +6 -0
- package/dist/human-text.js +37 -0
- package/dist/index.d.ts +19 -9
- package/dist/index.js +14 -6
- package/dist/journey/answers-block.d.ts +2 -4
- package/dist/lsp/diagnostics.d.ts +4 -0
- package/dist/lsp/diagnostics.js +8 -2
- package/dist/lsp/index.d.ts +1 -1
- package/dist/lsp/index.js +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/mcp/json-schema-to-zod.js +2 -4
- package/dist/mcp/mcp-client.d.ts +14 -0
- package/dist/mcp/mcp-client.js +102 -18
- package/dist/memory/session-digest.js +2 -1
- package/dist/orchestrator/specialists-registry.js +14 -1
- package/dist/orchestrator/specialists.js +3 -3
- package/dist/pricing.js +12 -0
- package/dist/semantic/embedder.d.ts +11 -0
- package/dist/semantic/embedder.js +16 -0
- package/dist/semantic/semantic-index.d.ts +39 -1
- package/dist/semantic/semantic-index.js +43 -13
- package/dist/semantic/vector-store.d.ts +2 -0
- package/dist/semantic/vector-store.js +13 -1
- package/dist/sessions/index.d.ts +2 -2
- package/dist/sessions/index.js +1 -1
- package/dist/sessions/search.js +2 -2
- package/dist/sessions/session-export.d.ts +1 -1
- package/dist/sessions/session-export.js +41 -33
- package/dist/sessions/session-store.d.ts +20 -1
- package/dist/sessions/session-store.js +7 -0
- package/dist/sessions/watch.js +4 -4
- package/dist/skills/activator.d.ts +6 -0
- package/dist/skills/activator.js +17 -0
- package/dist/skills/skill-tool.d.ts +12 -0
- package/dist/skills/skill-tool.js +28 -0
- package/dist/tools/background-process.d.ts +63 -0
- package/dist/tools/background-process.js +150 -0
- package/dist/tools/command-sandbox.d.ts +24 -0
- package/dist/tools/command-sandbox.js +73 -0
- package/dist/tools/edit-file.d.ts +8 -0
- package/dist/tools/edit-file.js +39 -16
- package/dist/tools/edit-match.d.ts +16 -0
- package/dist/tools/edit-match.js +115 -0
- package/dist/tools/fetch-url.d.ts +15 -1
- package/dist/tools/fetch-url.js +7 -47
- package/dist/tools/get-diagnostics.d.ts +14 -0
- package/dist/tools/get-diagnostics.js +44 -0
- package/dist/tools/glob-filter.d.ts +7 -0
- package/dist/tools/glob-filter.js +12 -0
- package/dist/tools/html-to-markdown.d.ts +13 -0
- package/dist/tools/html-to-markdown.js +507 -0
- package/dist/tools/index.d.ts +5 -1
- package/dist/tools/index.js +11 -1
- package/dist/tools/list-files.d.ts +1 -0
- package/dist/tools/list-files.js +17 -5
- package/dist/tools/list-symbols.js +2 -2
- package/dist/tools/network-policy.d.ts +5 -0
- package/dist/tools/network-policy.js +77 -0
- package/dist/tools/office-docs.d.ts +6 -0
- package/dist/tools/office-docs.js +393 -0
- package/dist/tools/permission-rules.js +55 -5
- package/dist/tools/read-file.d.ts +2 -0
- package/dist/tools/read-file.js +47 -10
- package/dist/tools/read-image.js +2 -2
- package/dist/tools/read-only.d.ts +1 -1
- package/dist/tools/read-only.js +4 -0
- package/dist/tools/repo-clone.d.ts +40 -0
- package/dist/tools/repo-clone.js +218 -0
- package/dist/tools/result-cap.d.ts +8 -0
- package/dist/tools/result-cap.js +44 -0
- package/dist/tools/run-command.d.ts +18 -1
- package/dist/tools/run-command.js +44 -9
- package/dist/tools/search-files.js +12 -53
- package/dist/tools/search-worker.d.ts +23 -0
- package/dist/tools/search-worker.js +86 -0
- package/dist/tools/shared.d.ts +14 -1
- package/dist/tools/shared.js +76 -4
- package/dist/tools/shell.d.ts +27 -0
- package/dist/tools/shell.js +80 -0
- package/dist/tools/sub-agent.d.ts +1 -1
- package/dist/tools/sub-agent.js +4 -1
- package/dist/tools/suggest-plan.d.ts +18 -0
- package/dist/tools/suggest-plan.js +28 -0
- package/dist/types.d.ts +132 -1
- package/dist/wakeup/wakeup-tools.d.ts +22 -0
- package/dist/wakeup/wakeup-tools.js +34 -0
- package/dist/wakeup/wakeup.d.ts +75 -0
- package/dist/wakeup/wakeup.js +151 -0
- package/dist/worktree/health.d.ts +51 -0
- package/dist/worktree/health.js +186 -0
- package/dist/worktree/index.d.ts +4 -0
- package/dist/worktree/index.js +2 -0
- package/dist/worktree/setup.d.ts +51 -0
- package/dist/worktree/setup.js +173 -0
- package/dist/worktree/worktree.d.ts +7 -0
- package/dist/worktree/worktree.js +9 -4
- package/package.json +1 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { globToRegex } from './policy.js';
|
|
2
|
+
/**
|
|
3
|
+
* A file-name filter for tools that take a glob from the model (`search_files` include, `list_files` pattern).
|
|
4
|
+
* A slash-less glob such as "*.ts" names files at any depth, as in ripgrep -g; a glob with a slash is matched
|
|
5
|
+
* against the path relative to the searched directory. Do not use `globToRegex` directly for this: it anchors a
|
|
6
|
+
* slash-less pattern to the top level on purpose, for permission rules (RB-64).
|
|
7
|
+
*/
|
|
8
|
+
export function fileGlobMatcher(glob) {
|
|
9
|
+
const re = globToRegex(glob);
|
|
10
|
+
const byPath = glob.includes('/');
|
|
11
|
+
return (rel, name) => re.test(byPath ? rel : name);
|
|
12
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML to Markdown for `fetch_url` (G19). The old converter replaced every tag with a space, so a page became one long line:
|
|
3
|
+
* no headings, no link targets, no list or code structure. This keeps what a model needs to read documentation.
|
|
4
|
+
*
|
|
5
|
+
* It is one linear scan with no parser dependency and no regex that can backtrack over the page: the input is text a stranger
|
|
6
|
+
* wrote and it runs on the host's only thread (RB-22). Output is read by a model, so it is conservative about what a page can
|
|
7
|
+
* make appear in it (RB-81): only http, https and mailto link targets, images as their description only, hidden elements dropped, and a code
|
|
8
|
+
* fence longer than any backtick run inside it, so page text cannot close the fence early.
|
|
9
|
+
*/
|
|
10
|
+
/** Decode HTML entities in one pass, so `&lt;` stays `<` instead of becoming `<`. */
|
|
11
|
+
export declare function decodeEntities(s: string): string;
|
|
12
|
+
/** Convert a page. Only the main content is kept when the page marks one and it holds real text; otherwise the whole page. */
|
|
13
|
+
export declare function htmlToMarkdown(html: string, baseUrl?: string): string;
|
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML to Markdown for `fetch_url` (G19). The old converter replaced every tag with a space, so a page became one long line:
|
|
3
|
+
* no headings, no link targets, no list or code structure. This keeps what a model needs to read documentation.
|
|
4
|
+
*
|
|
5
|
+
* It is one linear scan with no parser dependency and no regex that can backtrack over the page: the input is text a stranger
|
|
6
|
+
* wrote and it runs on the host's only thread (RB-22). Output is read by a model, so it is conservative about what a page can
|
|
7
|
+
* make appear in it (RB-81): only http, https and mailto link targets, images as their description only, hidden elements dropped, and a code
|
|
8
|
+
* fence longer than any backtick run inside it, so page text cannot close the fence early.
|
|
9
|
+
*/
|
|
10
|
+
const NAMED = {
|
|
11
|
+
amp: '&', lt: '<', gt: '>', quot: '"', apos: "'", nbsp: ' ', hellip: '…', mdash: '—', ndash: '–', lsquo: '‘', rsquo: '’',
|
|
12
|
+
ldquo: '“', rdquo: '”', copy: '©', reg: '®', trade: '™', middot: '·', bull: '•', laquo: '«', raquo: '»', times: '×',
|
|
13
|
+
larr: '←', rarr: '→', euro: '€', pound: '£', deg: '°',
|
|
14
|
+
};
|
|
15
|
+
/** Decode HTML entities in one pass, so `&lt;` stays `<` instead of becoming `<`. */
|
|
16
|
+
export function decodeEntities(s) {
|
|
17
|
+
if (!s.includes('&'))
|
|
18
|
+
return s;
|
|
19
|
+
return s.replace(/&(#[xX][0-9a-fA-F]{1,6}|#[0-9]{1,7}|[a-zA-Z]{2,8});/g, (whole, e) => {
|
|
20
|
+
if (e.charAt(0) === '#') {
|
|
21
|
+
const cp = e.charAt(1).toLowerCase() === 'x' ? parseInt(e.slice(2), 16) : parseInt(e.slice(1), 10);
|
|
22
|
+
const ok = cp === 9 || cp === 10 || cp === 13 || (cp >= 0x20 && cp <= 0x10ffff && !(cp >= 0x7f && cp <= 0x9f) && !(cp >= 0xd800 && cp <= 0xdfff));
|
|
23
|
+
return ok ? String.fromCodePoint(cp) : ' ';
|
|
24
|
+
}
|
|
25
|
+
return NAMED[e.toLowerCase()] ?? whole;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const BLOCK = new Set([
|
|
29
|
+
'p', 'div', 'section', 'article', 'header', 'main', 'aside', 'figure', 'figcaption', 'form', 'fieldset',
|
|
30
|
+
'address', 'details', 'summary', 'dl', 'dt', 'dd', 'center', 'hgroup', 'body', 'html', 'table', 'caption',
|
|
31
|
+
]);
|
|
32
|
+
const SKIPPED = new Set(['head', 'title', 'noscript', 'svg', 'template', 'iframe', 'canvas', 'object', 'nav', 'footer']);
|
|
33
|
+
const VOID = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
|
|
34
|
+
const EMPHASIS = { b: '**', strong: '**', i: '*', em: '*', del: '~~', s: '~~', strike: '~~' };
|
|
35
|
+
const CODE = new Set(['code', 'kbd', 'samp', 'tt']);
|
|
36
|
+
/** Value of an attribute in the text of one tag, or undefined. */
|
|
37
|
+
function attr(tag, name) {
|
|
38
|
+
if (!tag.toLowerCase().includes(name))
|
|
39
|
+
return undefined;
|
|
40
|
+
const m = new RegExp(`(?:^|\\s)${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s"'>]+))`, 'i').exec(tag);
|
|
41
|
+
if (!m)
|
|
42
|
+
return undefined;
|
|
43
|
+
return decodeEntities(m[1] ?? m[2] ?? m[3] ?? '');
|
|
44
|
+
}
|
|
45
|
+
function isHidden(tag) {
|
|
46
|
+
const lower = tag.toLowerCase();
|
|
47
|
+
if (lower.includes('role') && /^(?:navigation|contentinfo)$/.test(attr(tag, 'role')?.trim().toLowerCase() ?? ''))
|
|
48
|
+
return true;
|
|
49
|
+
if (!lower.includes('hidden') && !lower.includes('display'))
|
|
50
|
+
return false;
|
|
51
|
+
if (/(?:^|\s)hidden(?=[\s=/]|$)/.test(lower))
|
|
52
|
+
return true;
|
|
53
|
+
if (attr(tag, 'aria-hidden')?.trim().toLowerCase() === 'true')
|
|
54
|
+
return true;
|
|
55
|
+
const style = attr(tag, 'style')?.toLowerCase() ?? '';
|
|
56
|
+
return /display\s*:\s*none|visibility\s*:\s*hidden/.test(style);
|
|
57
|
+
}
|
|
58
|
+
/** Length of the longest run of backticks in `s` (a loop, not a spread: a page can hold hundreds of thousands of runs). */
|
|
59
|
+
function longestBacktickRun(s) {
|
|
60
|
+
let longest = 0;
|
|
61
|
+
let run = 0;
|
|
62
|
+
for (let k = 0; k < s.length; k++) {
|
|
63
|
+
run = s.charAt(k) === '`' ? run + 1 : 0;
|
|
64
|
+
if (run > longest)
|
|
65
|
+
longest = run;
|
|
66
|
+
}
|
|
67
|
+
return longest;
|
|
68
|
+
}
|
|
69
|
+
const MAX_OPEN_MARKS = 64;
|
|
70
|
+
const MAX_LIST_INDENT = 8;
|
|
71
|
+
function escapeTarget(s) {
|
|
72
|
+
return s.replace(/ /g, '%20').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/</g, '%3C').replace(/>/g, '%3E');
|
|
73
|
+
}
|
|
74
|
+
/** A link target worth showing, or undefined: only http, https and mailto; never script or data. */
|
|
75
|
+
function safeTarget(raw, base) {
|
|
76
|
+
const value = raw?.trim();
|
|
77
|
+
if (!value || value.startsWith('#'))
|
|
78
|
+
return undefined;
|
|
79
|
+
let url;
|
|
80
|
+
try {
|
|
81
|
+
url = base ? new URL(value, base) : new URL(value);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// A relative address with nothing to resolve it against stays as written; anything with a scheme we cannot read is dropped.
|
|
85
|
+
return /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(value) ? undefined : escapeTarget(value);
|
|
86
|
+
}
|
|
87
|
+
const ok = url.protocol === 'http:' || url.protocol === 'https:' || url.protocol === 'mailto:';
|
|
88
|
+
return ok ? escapeTarget(url.href) : undefined;
|
|
89
|
+
}
|
|
90
|
+
/** The index of the `>` that ends the tag starting after `from`, honouring quoted attribute values; -1 if there is none. */
|
|
91
|
+
function findTagEnd(html, from) {
|
|
92
|
+
let prevSignificant = '';
|
|
93
|
+
for (let j = from; j < html.length; j++) {
|
|
94
|
+
const c = html.charAt(j);
|
|
95
|
+
if (c === '>')
|
|
96
|
+
return j;
|
|
97
|
+
if ((c === '"' || c === "'") && prevSignificant === '=') {
|
|
98
|
+
const close = html.indexOf(c, j + 1);
|
|
99
|
+
if (close === -1)
|
|
100
|
+
return -1;
|
|
101
|
+
j = close;
|
|
102
|
+
prevSignificant = c;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (c !== ' ' && c !== '\t' && c !== '\n' && c !== '\r')
|
|
106
|
+
prevSignificant = c;
|
|
107
|
+
}
|
|
108
|
+
return -1;
|
|
109
|
+
}
|
|
110
|
+
const MIN_MAIN_CHARS = 200;
|
|
111
|
+
/** The page's main content (`<main>`, else `<article>`), or undefined: the menus and footers around it are not wanted. */
|
|
112
|
+
function contentRegion(html) {
|
|
113
|
+
const lower = html.toLowerCase();
|
|
114
|
+
for (const tag of ['main', 'article']) {
|
|
115
|
+
let start = lower.indexOf(`<${tag}`);
|
|
116
|
+
while (start !== -1 && !/[\s>/]/.test(lower.charAt(start + tag.length + 1)))
|
|
117
|
+
start = lower.indexOf(`<${tag}`, start + 1);
|
|
118
|
+
if (start === -1)
|
|
119
|
+
continue;
|
|
120
|
+
const close = lower.lastIndexOf(`</${tag}`);
|
|
121
|
+
const stop = close > start ? html.indexOf('>', close) + 1 : 0;
|
|
122
|
+
return html.slice(start, stop > 0 ? stop : html.length);
|
|
123
|
+
}
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
/** Convert a page. Only the main content is kept when the page marks one and it holds real text; otherwise the whole page. */
|
|
127
|
+
export function htmlToMarkdown(html, baseUrl) {
|
|
128
|
+
const region = contentRegion(html);
|
|
129
|
+
if (region) {
|
|
130
|
+
const inner = convert(region, baseUrl);
|
|
131
|
+
if (inner.length >= MIN_MAIN_CHARS)
|
|
132
|
+
return inner;
|
|
133
|
+
}
|
|
134
|
+
return convert(html, baseUrl);
|
|
135
|
+
}
|
|
136
|
+
function convert(html, baseUrl) {
|
|
137
|
+
const lower = html.toLowerCase();
|
|
138
|
+
const parts = [];
|
|
139
|
+
let trailingNl = 0;
|
|
140
|
+
let spaceOk = false; // may a separating space go before the next word
|
|
141
|
+
let pending = false; // whitespace was seen since the last word
|
|
142
|
+
const stack = [];
|
|
143
|
+
const lists = [];
|
|
144
|
+
let skipTag = '';
|
|
145
|
+
let skipDepth = 0;
|
|
146
|
+
let pre;
|
|
147
|
+
let tableDepth = 0;
|
|
148
|
+
let rowCells;
|
|
149
|
+
let rowsDone = 0;
|
|
150
|
+
let cell;
|
|
151
|
+
const note = (s) => {
|
|
152
|
+
let k = s.length;
|
|
153
|
+
while (k > 0 && s.charAt(k - 1) === '\n')
|
|
154
|
+
k--;
|
|
155
|
+
trailingNl = k === 0 ? trailingNl + s.length : s.length - k;
|
|
156
|
+
spaceOk = !/\s$/.test(s.slice(-1));
|
|
157
|
+
};
|
|
158
|
+
const put = (s) => {
|
|
159
|
+
if (!s)
|
|
160
|
+
return;
|
|
161
|
+
parts.push(s);
|
|
162
|
+
note(s);
|
|
163
|
+
pending = false;
|
|
164
|
+
};
|
|
165
|
+
const mark = (tag, extra = {}) => ({ tag, at: parts.length, nl: trailingNl, ok: spaceOk, ...extra });
|
|
166
|
+
/** Take back everything written since `m` and write `replacement` in its place, keeping the pending-space state. */
|
|
167
|
+
const replaceFrom = (m, replacement) => {
|
|
168
|
+
const inner = parts.splice(m.at).join('');
|
|
169
|
+
trailingNl = m.nl;
|
|
170
|
+
spaceOk = m.ok;
|
|
171
|
+
if (replacement) {
|
|
172
|
+
parts.push(replacement);
|
|
173
|
+
note(replacement);
|
|
174
|
+
}
|
|
175
|
+
return inner;
|
|
176
|
+
};
|
|
177
|
+
const block = () => {
|
|
178
|
+
if (parts.length === 0)
|
|
179
|
+
return;
|
|
180
|
+
pending = false;
|
|
181
|
+
if (trailingNl < 2)
|
|
182
|
+
put('\n'.repeat(2 - trailingNl));
|
|
183
|
+
};
|
|
184
|
+
const newline = () => {
|
|
185
|
+
if (parts.length === 0)
|
|
186
|
+
return;
|
|
187
|
+
pending = false;
|
|
188
|
+
if (trailingNl < 1)
|
|
189
|
+
put('\n');
|
|
190
|
+
};
|
|
191
|
+
const text = (raw) => {
|
|
192
|
+
if (skipDepth > 0 || !raw)
|
|
193
|
+
return;
|
|
194
|
+
if (pre) {
|
|
195
|
+
put(decodeEntities(raw).replace(/\r\n?/g, '\n').replace(/ /g, ' '));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const t = decodeEntities(raw).replace(/\s+/g, ' ');
|
|
199
|
+
if (t === ' ') {
|
|
200
|
+
if (spaceOk)
|
|
201
|
+
pending = true;
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const core = t.trim();
|
|
205
|
+
if ((t.startsWith(' ') || pending) && spaceOk)
|
|
206
|
+
put(' ');
|
|
207
|
+
put(core);
|
|
208
|
+
pending = t.endsWith(' ');
|
|
209
|
+
};
|
|
210
|
+
const wrap = (inner, marker) => {
|
|
211
|
+
const core = inner.trim();
|
|
212
|
+
if (!core)
|
|
213
|
+
return inner;
|
|
214
|
+
const lead = inner.slice(0, inner.length - inner.trimStart().length);
|
|
215
|
+
const trail = inner.slice(inner.trimEnd().length);
|
|
216
|
+
return lead + marker + core + marker + trail;
|
|
217
|
+
};
|
|
218
|
+
const closeCell = () => {
|
|
219
|
+
if (!cell || !rowCells)
|
|
220
|
+
return;
|
|
221
|
+
const raw = replaceFrom(cell, '');
|
|
222
|
+
rowCells.push(raw.replace(/\s+/g, ' ').trim().replace(/\|/g, '\\|'));
|
|
223
|
+
cell = undefined;
|
|
224
|
+
};
|
|
225
|
+
const closeRow = () => {
|
|
226
|
+
closeCell();
|
|
227
|
+
if (rowCells && rowCells.length > 0) {
|
|
228
|
+
put(`| ${rowCells.join(' | ')} |\n`);
|
|
229
|
+
if (rowsDone === 0)
|
|
230
|
+
put(`| ${rowCells.map(() => '---').join(' | ')} |\n`);
|
|
231
|
+
rowsDone++;
|
|
232
|
+
}
|
|
233
|
+
rowCells = undefined;
|
|
234
|
+
};
|
|
235
|
+
const closeInline = (tag) => {
|
|
236
|
+
let idx = -1;
|
|
237
|
+
for (let k = stack.length - 1; k >= 0; k--) {
|
|
238
|
+
if (stack[k].tag === tag) {
|
|
239
|
+
idx = k;
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (idx === -1)
|
|
244
|
+
return;
|
|
245
|
+
const m = stack[idx];
|
|
246
|
+
stack.length = idx;
|
|
247
|
+
finishMark(m);
|
|
248
|
+
};
|
|
249
|
+
const finishMark = (m) => {
|
|
250
|
+
if (m.tag === 'blockquote') {
|
|
251
|
+
const inner = replaceFrom(m, '').trim();
|
|
252
|
+
if (inner)
|
|
253
|
+
put(inner.split('\n').map((l) => (l ? `> ${l}` : '>')).join('\n'));
|
|
254
|
+
block();
|
|
255
|
+
}
|
|
256
|
+
else if (m.tag === 'a') {
|
|
257
|
+
const inner = replaceFrom(m, '');
|
|
258
|
+
const label = inner.replace(/\s+/g, ' ');
|
|
259
|
+
if (m.drop || !label.trim())
|
|
260
|
+
return;
|
|
261
|
+
parts.push(m.href ? wrapLink(label, m.href) : label);
|
|
262
|
+
note(m.href ? wrapLink(label, m.href) : label);
|
|
263
|
+
}
|
|
264
|
+
else if (m.tag === 'code') {
|
|
265
|
+
const inner = replaceFrom(m, '').replace(/\s+/g, ' ');
|
|
266
|
+
if (!inner.trim())
|
|
267
|
+
return;
|
|
268
|
+
const fence = '`'.repeat(longestBacktickRun(inner) + 1);
|
|
269
|
+
const body = inner.trim();
|
|
270
|
+
const padded = body.startsWith('`') || body.endsWith('`') ? ` ${body} ` : body;
|
|
271
|
+
const out = fence + padded + fence;
|
|
272
|
+
const wrapped = (inner.startsWith(' ') ? ' ' : '') + out + (inner.endsWith(' ') ? ' ' : '');
|
|
273
|
+
parts.push(wrapped);
|
|
274
|
+
note(wrapped);
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
const marker = EMPHASIS[m.tag];
|
|
278
|
+
const inner = replaceFrom(m, '');
|
|
279
|
+
if (!inner)
|
|
280
|
+
return;
|
|
281
|
+
const out = marker ? wrap(inner.replace(/\s+/g, ' '), marker) : inner;
|
|
282
|
+
parts.push(out);
|
|
283
|
+
note(out);
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
const wrapLink = (label, href) => {
|
|
287
|
+
const core = label.trim();
|
|
288
|
+
const lead = label.startsWith(' ') ? ' ' : '';
|
|
289
|
+
const trail = label.endsWith(' ') ? ' ' : '';
|
|
290
|
+
return `${lead}[${core}](${href})${trail}`;
|
|
291
|
+
};
|
|
292
|
+
const endPre = () => {
|
|
293
|
+
if (!pre)
|
|
294
|
+
return;
|
|
295
|
+
const raw = parts.splice(pre.at).join('');
|
|
296
|
+
const lang = pre.lang;
|
|
297
|
+
trailingNl = pre.nl;
|
|
298
|
+
spaceOk = false;
|
|
299
|
+
pre = undefined;
|
|
300
|
+
const code = raw.replace(/^\n+/, '').replace(/\s+$/, '');
|
|
301
|
+
const fence = '`'.repeat(Math.max(2, longestBacktickRun(code)) + 1);
|
|
302
|
+
block();
|
|
303
|
+
put(`${fence}${lang}\n${code}\n${fence}`);
|
|
304
|
+
block();
|
|
305
|
+
};
|
|
306
|
+
let i = 0;
|
|
307
|
+
const n = html.length;
|
|
308
|
+
while (i < n) {
|
|
309
|
+
const lt = html.indexOf('<', i);
|
|
310
|
+
if (lt === -1) {
|
|
311
|
+
text(html.slice(i));
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
if (lt > i)
|
|
315
|
+
text(html.slice(i, lt));
|
|
316
|
+
if (html.startsWith('<!--', lt)) {
|
|
317
|
+
const e = html.indexOf('-->', lt + 4);
|
|
318
|
+
i = e === -1 ? n : e + 3;
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
const first = html.charAt(lt + 1);
|
|
322
|
+
if (first === '!' || first === '?') {
|
|
323
|
+
const e = html.indexOf('>', lt);
|
|
324
|
+
i = e === -1 ? n : e + 1;
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
if (!/[a-zA-Z/]/.test(first) || (first === '/' && !/[a-zA-Z]/.test(html.charAt(lt + 2)))) {
|
|
328
|
+
text('<');
|
|
329
|
+
i = lt + 1;
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
const end = findTagEnd(html, lt + 1);
|
|
333
|
+
if (end === -1)
|
|
334
|
+
break; // a tag cut off by the end of the page: drop it rather than show its attributes
|
|
335
|
+
const rawTag = html.slice(lt + 1, end);
|
|
336
|
+
i = end + 1;
|
|
337
|
+
const closing = rawTag.charAt(0) === '/';
|
|
338
|
+
const nameMatch = /^\/?([a-zA-Z][a-zA-Z0-9:-]*)/.exec(rawTag);
|
|
339
|
+
if (!nameMatch)
|
|
340
|
+
continue;
|
|
341
|
+
const name = nameMatch[1].toLowerCase();
|
|
342
|
+
const selfClosing = rawTag.endsWith('/') || VOID.has(name);
|
|
343
|
+
// The inside of a script or style is not markup, so jump to its end tag before anything else.
|
|
344
|
+
if (!closing && (name === 'script' || name === 'style')) {
|
|
345
|
+
const e = lower.indexOf(`</${name}`, end + 1);
|
|
346
|
+
const gt = e === -1 ? -1 : html.indexOf('>', e);
|
|
347
|
+
i = gt === -1 ? n : gt + 1;
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
if (skipDepth > 0) {
|
|
351
|
+
if (name === skipTag && !selfClosing)
|
|
352
|
+
skipDepth += closing ? -1 : 1;
|
|
353
|
+
if (skipDepth === 0)
|
|
354
|
+
skipTag = '';
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
if (!closing && !selfClosing && (SKIPPED.has(name) || isHidden(rawTag))) {
|
|
358
|
+
skipTag = name;
|
|
359
|
+
skipDepth = 1;
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
if (!closing && selfClosing && isHidden(rawTag))
|
|
363
|
+
continue;
|
|
364
|
+
if (pre && name !== 'pre') {
|
|
365
|
+
if (name === 'br')
|
|
366
|
+
put('\n');
|
|
367
|
+
else if (name === 'code' && !closing && !pre.lang)
|
|
368
|
+
pre.lang = /language-([\w+#.-]+)/.exec(attr(rawTag, 'class') ?? '')?.[1] ?? '';
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
if (closing) {
|
|
372
|
+
if (name === 'pre')
|
|
373
|
+
endPre();
|
|
374
|
+
else if (/^h[1-6]$/.test(name) || BLOCK.has(name))
|
|
375
|
+
block();
|
|
376
|
+
else if (name === 'ul' || name === 'ol') {
|
|
377
|
+
lists.pop();
|
|
378
|
+
if (lists.length === 0)
|
|
379
|
+
block();
|
|
380
|
+
else
|
|
381
|
+
newline();
|
|
382
|
+
}
|
|
383
|
+
else if (name === 'li')
|
|
384
|
+
newline();
|
|
385
|
+
else if (name === 'blockquote')
|
|
386
|
+
closeInline('blockquote');
|
|
387
|
+
else if (name === 'a')
|
|
388
|
+
closeInline('a');
|
|
389
|
+
else if (CODE.has(name))
|
|
390
|
+
closeInline('code');
|
|
391
|
+
else if (EMPHASIS[name])
|
|
392
|
+
closeInline(name);
|
|
393
|
+
else if (name === 'td' || name === 'th') {
|
|
394
|
+
if (tableDepth === 1)
|
|
395
|
+
closeCell();
|
|
396
|
+
else
|
|
397
|
+
put(' ');
|
|
398
|
+
}
|
|
399
|
+
else if (name === 'tr') {
|
|
400
|
+
if (tableDepth === 1)
|
|
401
|
+
closeRow();
|
|
402
|
+
}
|
|
403
|
+
else if (name === 'table') {
|
|
404
|
+
if (tableDepth === 1)
|
|
405
|
+
closeRow();
|
|
406
|
+
tableDepth = Math.max(0, tableDepth - 1);
|
|
407
|
+
if (tableDepth === 0) {
|
|
408
|
+
rowsDone = 0;
|
|
409
|
+
block();
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
// Opening (or void) tags.
|
|
415
|
+
if (/^h[1-6]$/.test(name)) {
|
|
416
|
+
block();
|
|
417
|
+
put(`${'#'.repeat(Number(name.charAt(1)))} `);
|
|
418
|
+
}
|
|
419
|
+
else if (name === 'pre') {
|
|
420
|
+
block();
|
|
421
|
+
pre = { at: parts.length, nl: trailingNl, lang: /language-([\w+#.-]+)/.exec(attr(rawTag, 'class') ?? '')?.[1] ?? '' };
|
|
422
|
+
}
|
|
423
|
+
else if (name === 'br') {
|
|
424
|
+
if (parts.length > 0)
|
|
425
|
+
put('\n');
|
|
426
|
+
}
|
|
427
|
+
else if (name === 'hr') {
|
|
428
|
+
block();
|
|
429
|
+
put('---');
|
|
430
|
+
block();
|
|
431
|
+
}
|
|
432
|
+
else if (name === 'ul' || name === 'ol') {
|
|
433
|
+
if (lists.length === 0)
|
|
434
|
+
block();
|
|
435
|
+
else
|
|
436
|
+
newline();
|
|
437
|
+
const start = parseInt(attr(rawTag, 'start') ?? '1', 10);
|
|
438
|
+
lists.push({ ordered: name === 'ol', n: Number.isFinite(start) ? start : 1 });
|
|
439
|
+
}
|
|
440
|
+
else if (name === 'li') {
|
|
441
|
+
newline();
|
|
442
|
+
const top = lists[lists.length - 1];
|
|
443
|
+
const marker = top?.ordered ? `${top.n++}. ` : '- ';
|
|
444
|
+
put(' '.repeat(Math.min(MAX_LIST_INDENT, Math.max(0, lists.length - 1))) + marker);
|
|
445
|
+
}
|
|
446
|
+
else if (name === 'blockquote') {
|
|
447
|
+
block();
|
|
448
|
+
if (stack.length < MAX_OPEN_MARKS)
|
|
449
|
+
stack.push(mark('blockquote'));
|
|
450
|
+
}
|
|
451
|
+
else if (name === 'a') {
|
|
452
|
+
// A link with both hreflang and lang is a language switcher (Wikipedia lists hundreds): page furniture, not content.
|
|
453
|
+
const drop = attr(rawTag, 'hreflang') !== undefined && attr(rawTag, 'lang') !== undefined;
|
|
454
|
+
if (stack.length < MAX_OPEN_MARKS)
|
|
455
|
+
stack.push(mark('a', { href: safeTarget(attr(rawTag, 'href'), baseUrl), drop }));
|
|
456
|
+
}
|
|
457
|
+
else if (CODE.has(name)) {
|
|
458
|
+
if (stack.length < MAX_OPEN_MARKS)
|
|
459
|
+
stack.push(mark('code'));
|
|
460
|
+
}
|
|
461
|
+
else if (EMPHASIS[name]) {
|
|
462
|
+
if (stack.length < MAX_OPEN_MARKS)
|
|
463
|
+
stack.push(mark(name));
|
|
464
|
+
}
|
|
465
|
+
else if (name === 'img') {
|
|
466
|
+
const alt = (attr(rawTag, 'alt') ?? '').replace(/\s+/g, ' ').trim();
|
|
467
|
+
if (alt)
|
|
468
|
+
text(` ${alt} `);
|
|
469
|
+
}
|
|
470
|
+
else if (name === 'table') {
|
|
471
|
+
if (tableDepth === 0)
|
|
472
|
+
block();
|
|
473
|
+
tableDepth++;
|
|
474
|
+
}
|
|
475
|
+
else if (name === 'tr') {
|
|
476
|
+
if (tableDepth === 1) {
|
|
477
|
+
closeRow();
|
|
478
|
+
rowCells = [];
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
else if (name === 'td' || name === 'th') {
|
|
482
|
+
if (tableDepth === 1) {
|
|
483
|
+
if (!rowCells)
|
|
484
|
+
rowCells = [];
|
|
485
|
+
closeCell();
|
|
486
|
+
cell = mark('cell');
|
|
487
|
+
}
|
|
488
|
+
else
|
|
489
|
+
put(' ');
|
|
490
|
+
}
|
|
491
|
+
else if (BLOCK.has(name)) {
|
|
492
|
+
block();
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
// The page ended with things open: close them so their text is not lost or left half-marked.
|
|
496
|
+
endPre();
|
|
497
|
+
if (tableDepth > 0)
|
|
498
|
+
closeRow();
|
|
499
|
+
while (stack.length > 0)
|
|
500
|
+
finishMark(stack.pop());
|
|
501
|
+
return parts
|
|
502
|
+
.join('')
|
|
503
|
+
.replace(/^[ \t]*(?:-|\d+\.)[ \t]*$/gm, '') // a list item that ended up empty
|
|
504
|
+
.replace(/[ \t]+\n/g, '\n')
|
|
505
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
506
|
+
.trim();
|
|
507
|
+
}
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { applyPatchTool } from './apply-patch.js';
|
|
2
|
+
import { bgReadTool, bgStartTool, bgStopTool } from './background-process.js';
|
|
2
3
|
import { editFileTool } from './edit-file.js';
|
|
3
4
|
import { fetchUrlTool } from './fetch-url.js';
|
|
4
5
|
import { findReferencesTool } from './find-references.js';
|
|
5
6
|
import { findSymbolTool } from './find-symbol.js';
|
|
6
7
|
import { dependencyAuditTool } from './dependency-audit.js';
|
|
8
|
+
import { getDiagnosticsTool } from './get-diagnostics.js';
|
|
7
9
|
import { gitDiffTool } from './git-diff.js';
|
|
8
10
|
import { listFilesTool } from './list-files.js';
|
|
9
11
|
import { listSymbolsTool } from './list-symbols.js';
|
|
@@ -11,10 +13,12 @@ import { memoryForgetTool, memoryReadTool, memoryWriteTool } from './memory.js';
|
|
|
11
13
|
import { editNotebookTool } from './notebook.js';
|
|
12
14
|
import { readFileTool } from './read-file.js';
|
|
13
15
|
import { readImageTool } from './read-image.js';
|
|
16
|
+
import { repoCloneTool } from './repo-clone.js';
|
|
14
17
|
import { runCommandTool } from './run-command.js';
|
|
15
18
|
import { searchFilesTool } from './search-files.js';
|
|
16
19
|
import { askUserTool } from './ask-user.js';
|
|
17
20
|
import { subAgentTool } from './sub-agent.js';
|
|
21
|
+
import { suggestPlanTool } from './suggest-plan.js';
|
|
18
22
|
import { subAgentWaitTool } from './sub-agent-wait.js';
|
|
19
23
|
import { todoReadTool, todoWriteTool } from './todo.js';
|
|
20
24
|
import { writeFileTool } from './write-file.js';
|
|
@@ -32,7 +36,7 @@ type AnyToolDefinition = ToolDefinition<any, any>;
|
|
|
32
36
|
* intentional: the model sees this order in its tool list.
|
|
33
37
|
*/
|
|
34
38
|
export declare const BUILTIN_TOOLS: readonly AnyToolDefinition[];
|
|
35
|
-
export { applyPatchTool, askUserTool, dependencyAuditTool, editFileTool, editNotebookTool, fetchUrlTool, findReferencesTool, findSymbolTool, gitDiffTool, listFilesTool, listSymbolsTool, memoryForgetTool, memoryReadTool, memoryWriteTool, readFileTool, readImageTool, runCommandTool, searchFilesTool, subAgentTool, subAgentWaitTool, todoReadTool, todoWriteTool, writeFileTool, };
|
|
39
|
+
export { applyPatchTool, askUserTool, bgReadTool, bgStartTool, bgStopTool, dependencyAuditTool, editFileTool, editNotebookTool, fetchUrlTool, findReferencesTool, findSymbolTool, getDiagnosticsTool, gitDiffTool, listFilesTool, listSymbolsTool, memoryForgetTool, memoryReadTool, memoryWriteTool, readFileTool, readImageTool, repoCloneTool, runCommandTool, searchFilesTool, subAgentTool, subAgentWaitTool, suggestPlanTool, todoReadTool, todoWriteTool, writeFileTool, };
|
|
36
40
|
export type { ToolContext, ToolDefinition, ToolPolicy, ToolSandbox } from '../types.js';
|
|
37
41
|
export { checkPolicyViolation, globToRegex, mergeToolSandbox, normalizePathPattern, pathMatchesAny } from './policy.js';
|
|
38
42
|
export { redact, countRedactions, buildRules } from './redact.js';
|
package/dist/tools/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { applyPatchTool } from './apply-patch.js';
|
|
2
|
+
import { bgReadTool, bgStartTool, bgStopTool } from './background-process.js';
|
|
2
3
|
import { editFileTool } from './edit-file.js';
|
|
3
4
|
import { fetchUrlTool } from './fetch-url.js';
|
|
4
5
|
import { findReferencesTool } from './find-references.js';
|
|
5
6
|
import { findSymbolTool } from './find-symbol.js';
|
|
6
7
|
import { dependencyAuditTool } from './dependency-audit.js';
|
|
8
|
+
import { getDiagnosticsTool } from './get-diagnostics.js';
|
|
7
9
|
import { gitDiffTool } from './git-diff.js';
|
|
8
10
|
import { listFilesTool } from './list-files.js';
|
|
9
11
|
import { listSymbolsTool } from './list-symbols.js';
|
|
@@ -11,10 +13,12 @@ import { memoryForgetTool, memoryReadTool, memoryWriteTool } from './memory.js';
|
|
|
11
13
|
import { editNotebookTool } from './notebook.js';
|
|
12
14
|
import { readFileTool } from './read-file.js';
|
|
13
15
|
import { readImageTool } from './read-image.js';
|
|
16
|
+
import { repoCloneTool } from './repo-clone.js';
|
|
14
17
|
import { runCommandTool } from './run-command.js';
|
|
15
18
|
import { searchFilesTool } from './search-files.js';
|
|
16
19
|
import { askUserTool } from './ask-user.js';
|
|
17
20
|
import { subAgentTool } from './sub-agent.js';
|
|
21
|
+
import { suggestPlanTool } from './suggest-plan.js';
|
|
18
22
|
import { subAgentWaitTool } from './sub-agent-wait.js';
|
|
19
23
|
import { todoReadTool, todoWriteTool } from './todo.js';
|
|
20
24
|
import { writeFileTool } from './write-file.js';
|
|
@@ -34,12 +38,17 @@ export const BUILTIN_TOOLS = [
|
|
|
34
38
|
findReferencesTool,
|
|
35
39
|
gitDiffTool,
|
|
36
40
|
dependencyAuditTool,
|
|
41
|
+
getDiagnosticsTool,
|
|
37
42
|
writeFileTool,
|
|
38
43
|
editFileTool,
|
|
39
44
|
applyPatchTool,
|
|
40
45
|
editNotebookTool,
|
|
41
46
|
runCommandTool,
|
|
47
|
+
bgStartTool,
|
|
48
|
+
bgReadTool,
|
|
49
|
+
bgStopTool,
|
|
42
50
|
fetchUrlTool,
|
|
51
|
+
repoCloneTool,
|
|
43
52
|
memoryReadTool,
|
|
44
53
|
memoryWriteTool,
|
|
45
54
|
memoryForgetTool,
|
|
@@ -48,8 +57,9 @@ export const BUILTIN_TOOLS = [
|
|
|
48
57
|
todoWriteTool,
|
|
49
58
|
todoReadTool,
|
|
50
59
|
askUserTool,
|
|
60
|
+
suggestPlanTool,
|
|
51
61
|
];
|
|
52
|
-
export { applyPatchTool, askUserTool, dependencyAuditTool, editFileTool, editNotebookTool, fetchUrlTool, findReferencesTool, findSymbolTool, gitDiffTool, listFilesTool, listSymbolsTool, memoryForgetTool, memoryReadTool, memoryWriteTool, readFileTool, readImageTool, runCommandTool, searchFilesTool, subAgentTool, subAgentWaitTool, todoReadTool, todoWriteTool, writeFileTool, };
|
|
62
|
+
export { applyPatchTool, askUserTool, bgReadTool, bgStartTool, bgStopTool, dependencyAuditTool, editFileTool, editNotebookTool, fetchUrlTool, findReferencesTool, findSymbolTool, getDiagnosticsTool, gitDiffTool, listFilesTool, listSymbolsTool, memoryForgetTool, memoryReadTool, memoryWriteTool, readFileTool, readImageTool, repoCloneTool, runCommandTool, searchFilesTool, subAgentTool, subAgentWaitTool, suggestPlanTool, todoReadTool, todoWriteTool, writeFileTool, };
|
|
53
63
|
export { checkPolicyViolation, globToRegex, mergeToolSandbox, normalizePathPattern, pathMatchesAny } from './policy.js';
|
|
54
64
|
export { redact, countRedactions, buildRules } from './redact.js';
|
|
55
65
|
export { ToolResultCache, buildCacheKey, cachedExecute } from './result-cache.js';
|
|
@@ -5,6 +5,7 @@ declare const params: z.ZodObject<{
|
|
|
5
5
|
max_entries: z.ZodOptional<z.ZodNumber>;
|
|
6
6
|
include_hidden: z.ZodOptional<z.ZodBoolean>;
|
|
7
7
|
include_ignored: z.ZodOptional<z.ZodBoolean>;
|
|
8
|
+
pattern: z.ZodOptional<z.ZodString>;
|
|
8
9
|
recursive: z.ZodOptional<z.ZodBoolean>;
|
|
9
10
|
max_depth: z.ZodOptional<z.ZodNumber>;
|
|
10
11
|
}, z.core.$strip>;
|