zames_pro 2.82.50 → 2.82.52
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/CHANGELOG.md +32 -0
- package/README.md +159 -26
- package/SECURITY.md +50 -0
- package/dist/agent-loop.js +24 -4
- package/dist/answer-parse.js +1 -1
- package/dist/attach-refs.js +22 -6
- package/dist/browser-chats.js +1 -1
- package/dist/browser-dom.js +1 -1
- package/dist/browser-pure.js +1 -1
- package/dist/browser.js +1 -1
- package/dist/changelog.js +1 -1
- package/dist/checkpoint.js +1 -1
- package/dist/cli-args.js +1 -1
- package/dist/config-command.js +1 -1
- package/dist/config-commands.js +1 -1
- package/dist/config.js +34 -6
- package/dist/context.js +19 -3
- package/dist/extraTools.js +7 -0
- package/dist/i18n/deepseek.js +3 -3
- package/dist/i18n.js +1 -1
- package/dist/index.js +3 -3
- package/dist/input/layout.js +1 -1
- package/dist/input/suggest.js +1 -1
- package/dist/input.js +1 -1
- package/dist/mcp.js +8 -2
- package/dist/path-token.js +1 -1
- package/dist/subagent.js +5 -12
- package/dist/tools.js +9 -0
- package/dist/tui/InputLine.js +8 -4
- package/dist/tui/StatusBar.js +1 -1
- package/dist/tui/log-window.js +9 -10
- package/dist/web.js +16 -6
- package/llms-full.txt +679 -0
- package/llms.txt +102 -0
- package/package.json +84 -23
package/dist/context.js
CHANGED
|
@@ -186,9 +186,25 @@ function clipIf(name, content, budget, fromTail = false) {
|
|
|
186
186
|
// MEMORY.md is APPENDED to over time, so its newest (most relevant) notes
|
|
187
187
|
// live at the TAIL — a head clip would drop exactly those. Keep the tail
|
|
188
188
|
// for memory files, the head for AGENTS.md (whose top is the summary).
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
189
|
+
//
|
|
190
|
+
// The cut is in UTF-16 units, so it can land BETWEEN the halves of a
|
|
191
|
+
// surrogate PAIR (an emoji / astral CJK char): the head would then end with
|
|
192
|
+
// a lone HIGH half and the tail would START with a lone LOW half. Both reach
|
|
193
|
+
// the model through the system prompt as broken code points (the same rule
|
|
194
|
+
// as truncateToolResult / capReport / cutHookText). Step one unit back for
|
|
195
|
+
// the head, one unit forward for the tail, so the pair is dropped whole.
|
|
196
|
+
if (!fromTail) {
|
|
197
|
+
let end = keep;
|
|
198
|
+
const last = cleaned.charCodeAt(end - 1);
|
|
199
|
+
if (last >= 0xd800 && last <= 0xdbff)
|
|
200
|
+
end--;
|
|
201
|
+
return cleaned.slice(0, end) + NL + NL + marker;
|
|
202
|
+
}
|
|
203
|
+
let start = cleaned.length - keep;
|
|
204
|
+
const first = cleaned.charCodeAt(start);
|
|
205
|
+
if (first >= 0xdc00 && first <= 0xdfff)
|
|
206
|
+
start++;
|
|
207
|
+
let slice = cleaned.slice(start);
|
|
192
208
|
// Cut at a NOTE boundary, not mid-note: start the kept tail at the next line
|
|
193
209
|
// that begins a bullet or a heading, so a half-sentence note is not left.
|
|
194
210
|
const m = slice.search(/\n(?=[-*] |#{1,6} )/);
|
package/dist/extraTools.js
CHANGED
|
@@ -226,6 +226,13 @@ export function createExtraTools(workdir, { undo, todos } = {}) {
|
|
|
226
226
|
if (v === undefined || v === null) {
|
|
227
227
|
throw new Error(`Missing required argument: ${name}. Add "${name}" to the tool call arguments and retry.`);
|
|
228
228
|
}
|
|
229
|
+
// `path`/`pattern` are strings by contract; an OBJECT used to become
|
|
230
|
+
// "[object Object]" and reach the fs layer as a literal file name.
|
|
231
|
+
if (typeof v === 'object' || typeof v === 'function') {
|
|
232
|
+
throw new Error(`Invalid required argument ${name}: expected a string, got ` +
|
|
233
|
+
JSON.stringify(v) +
|
|
234
|
+
'. Re-send the call with a plain string value.');
|
|
235
|
+
}
|
|
229
236
|
const s = String(v);
|
|
230
237
|
if (s === '' || s === 'undefined' || s === 'null') {
|
|
231
238
|
throw new Error(`Invalid required argument ${name}: ${JSON.stringify(v)}. Provide a non-empty value for "${name}" and retry.`);
|
package/dist/i18n/deepseek.js
CHANGED
|
@@ -96,9 +96,9 @@ export const deepseekMessages = {
|
|
|
96
96
|
ru: '✖ {provider} перестал отвечать, лимит повторов исчерпан. Модель не дала ответа — проверь чат вручную.',
|
|
97
97
|
en: '✖ {provider} stopped responding, retry limit exhausted. The model gave no answer — check the chat manually.',
|
|
98
98
|
},
|
|
99
|
-
'ds.
|
|
100
|
-
ru: '⏳
|
|
101
|
-
en: '⏳ The
|
|
99
|
+
'ds.text_no_tool': {
|
|
100
|
+
ru: '⏳ Модель ответила текстом без вызова инструмента ({attempt}/{max}) — прошу вызвать инструмент...',
|
|
101
|
+
en: '⏳ The model answered with plain text and no tool call ({attempt}/{max}) — asking for a tool call...',
|
|
102
102
|
},
|
|
103
103
|
'ds.not_launched': {
|
|
104
104
|
ru: '✖ Браузер не запущен.',
|
package/dist/i18n.js
CHANGED
|
@@ -37,7 +37,7 @@ export function normalizeLocale(v) {
|
|
|
37
37
|
return DEFAULT_LOCALE;
|
|
38
38
|
}
|
|
39
39
|
// String catalog. Key -> { ru, en }. If a key is missing we return the key itself.
|
|
40
|
-
// Split into section files
|
|
40
|
+
// Split into section files; merged here so callers keep importing
|
|
41
41
|
// CATALOG from a single place.
|
|
42
42
|
export const CATALOG = {
|
|
43
43
|
...commonMessages,
|
package/dist/index.js
CHANGED
|
@@ -77,7 +77,7 @@ function authMarkerExists(provider = config.provider) {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
// ---------- CLI parsing ----------
|
|
80
|
-
// The pure helpers live in src/cli-args.ts
|
|
80
|
+
// The pure helpers live in src/cli-args.ts and are bound to this process's
|
|
81
81
|
// argv ONCE here. Call sites keep using getArg/hasFlag/getPositional.
|
|
82
82
|
const { getArg, hasFlag, getPositional } = createCliArgs(process.argv.slice(2));
|
|
83
83
|
// /compact asks the OLD chat for a summary. If browser.ask() exhausts its own
|
|
@@ -1274,7 +1274,7 @@ async function main() {
|
|
|
1274
1274
|
// Write the checklist whenever the agent changes it, so a restart/resume
|
|
1275
1275
|
// brings the tasks back (they used to be in-memory only).
|
|
1276
1276
|
todoStore.onChange = () => persistTodos();
|
|
1277
|
-
// Subagents
|
|
1277
|
+
// Subagents: the `Task` tool delegates a self-contained
|
|
1278
1278
|
// sub-task to a nested agent loop in its OWN chat (context isolation — in
|
|
1279
1279
|
// zames "context" IS the chat), then restores this chat and returns only
|
|
1280
1280
|
// the report. Sequential by design (one browser, one send slot). On by
|
|
@@ -4109,7 +4109,7 @@ async function main() {
|
|
|
4109
4109
|
task: finalTaskText,
|
|
4110
4110
|
workdir: currentWorkdir,
|
|
4111
4111
|
});
|
|
4112
|
-
//
|
|
4112
|
+
// Snapshot the working tree BEFORE the task so /rewind can
|
|
4113
4113
|
// undo the whole task in one step. Best-effort: create() never throws, so
|
|
4114
4114
|
// a missing tar cannot abort the task it was meant to protect. Skipped
|
|
4115
4115
|
// while reviewing a snapshot (workdir is a throwaway copy).
|
package/dist/input/layout.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// LineEditor (src/input.ts). No terminal access, no state: given a prompt, a
|
|
3
3
|
// buffer, a cursor and a width these compute the visual rows, the cursor
|
|
4
4
|
// position, the visible width (wide chars count 2) and the status formatting.
|
|
5
|
-
// Split out
|
|
5
|
+
// Split out so the geometry can be unit-tested without driving the
|
|
6
6
|
// real editor, and so the editor class keeps only render/key handling.
|
|
7
7
|
// All control characters are assembled from codes so the file has no
|
|
8
8
|
// "raw" ESC/CR/LF in string literals (see AGENTS.md).
|
package/dist/input/suggest.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// of the LineEditor's «/» hint list (src/input.ts). No terminal access and no
|
|
3
3
|
// editor state: given the buffer text and the command list these decide which
|
|
4
4
|
// commands to show, the visible window, and the Tab completion. Split out
|
|
5
|
-
//
|
|
5
|
+
// so the fuzzy match can be unit-tested without driving the editor.
|
|
6
6
|
import { SUGGEST_PAGE, isSubsequence, visLen, } from './layout.js';
|
|
7
7
|
/**
|
|
8
8
|
* The commands matching the current buffer. Shown only when the line starts
|
package/dist/input.js
CHANGED
|
@@ -9,7 +9,7 @@ import { NL, CR, ESC, PASTE_START, PASTE_END, SUGGEST_PAGE, pasteReplacement, ex
|
|
|
9
9
|
// The pure layout/formatting helpers (visual rows, cursor position, visible
|
|
10
10
|
// width, paste markers, token formatting) live in ./input/layout.js. They are
|
|
11
11
|
// re-exported here so every existing import from './input.js' keeps working,
|
|
12
|
-
// and so tests can import them from either module
|
|
12
|
+
// and so tests can import them from either module.
|
|
13
13
|
export { PASTE_MIN_LINES, SUGGEST_PAGE, isSubsequence, countPasteLines, formatPasteMarker, pasteReplacement, expandPastes, visRows, visLen, charWidth, layoutInput, tokenStatusLevel, formatTokenStatus, formatCompactTokens, splitPasteTail, truncateToWidth, wrapToWidth, CONTEXT_LIMIT, CONTEXT_YELLOW_PCT, CONTEXT_RED_PCT, } from './input/layout.js';
|
|
14
14
|
// PURE slash-command suggestion logic (match / paging / completion), split out
|
|
15
15
|
// of the class so the fuzzy match is unit-tested without driving the editor.
|
package/dist/mcp.js
CHANGED
|
@@ -180,8 +180,14 @@ export function jsonSchemaToParams(schema) {
|
|
|
180
180
|
// descriptions and enums. The flat map alone cannot convey them, and MCP
|
|
181
181
|
// tools (browser_snapshot, browser_click, ...) rely on them heavily.
|
|
182
182
|
export function describeParamsExternally(description, schema) {
|
|
183
|
-
|
|
184
|
-
|
|
183
|
+
// A JSON Schema may spell the object type as a LIST (`type: ['object']`, a
|
|
184
|
+
// zod-derived or nullable wrapper). Rejecting anything but the exact string
|
|
185
|
+
// 'object' silently dropped the schema — field descriptions and enums — from
|
|
186
|
+
// the model-facing tool description while the flat param map still listed
|
|
187
|
+
// the fields.
|
|
188
|
+
const raw = schema?.type;
|
|
189
|
+
const isObject = raw === 'object' || (Array.isArray(raw) && raw.includes('object'));
|
|
190
|
+
if (!schema || !isObject)
|
|
185
191
|
return description;
|
|
186
192
|
try {
|
|
187
193
|
const json = JSON.stringify(schema);
|
package/dist/path-token.js
CHANGED
|
@@ -89,7 +89,7 @@ function stripRefPunct(tok) {
|
|
|
89
89
|
t = t.slice(0, -1);
|
|
90
90
|
return t;
|
|
91
91
|
}
|
|
92
|
-
// Find all `@path` references in a task text
|
|
92
|
+
// Find all `@path` references in a task text. Returns the unique paths in
|
|
93
93
|
// order of appearance. A reference is an '@' at a word boundary followed by a
|
|
94
94
|
// token that looks like a file name/path (a known extension). Implemented
|
|
95
95
|
// without regular expressions, like extractPathToken, to keep the source free
|
package/dist/subagent.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { loadHooks, runLifecycleHooks } from './hooks.js';
|
|
2
2
|
import { markInternalChat } from './sessions.js';
|
|
3
|
-
// Subagent runner
|
|
3
|
+
// Subagent runner. A `Task` tool call from the model is handled
|
|
4
4
|
// by the agent loop as a SEAM (like onAutoCompact): it calls back into the
|
|
5
5
|
// caller, which owns the whole lifecycle. This module builds that callback.
|
|
6
6
|
//
|
|
@@ -101,17 +101,10 @@ export function createSubagentRunner(opts) {
|
|
|
101
101
|
// parent chat id) returned BEFORE anything ran, and charging those
|
|
102
102
|
// attempts burned the whole budget on runs that never started.
|
|
103
103
|
used++;
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
transcript?.log('subagent_start', {
|
|
109
|
-
type: req.type,
|
|
110
|
-
description: req.description || '',
|
|
111
|
-
promptChars: String(req.prompt || '').length,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
catch { }
|
|
104
|
+
// NOTE: `subagent_start` is NOT logged here. agent-loop already writes it
|
|
105
|
+
// for the `Task` seam (with the description and the prompt), so logging it
|
|
106
|
+
// here too put a DUPLICATE event for the same run into the transcript —
|
|
107
|
+
// /export rendered every delegation twice. The seam owns the event.
|
|
115
108
|
const subTools = buildTools(req.type === 'explore');
|
|
116
109
|
const taskText = subagentPersona(req.type) + '\n\n--- SUB-TASK ---\n' + req.prompt;
|
|
117
110
|
// Save the parent's send hooks: the nested loop OVERWRITES them on
|
package/dist/tools.js
CHANGED
|
@@ -70,6 +70,15 @@ export function createTools(workdir, { undo, todos, readOnly = false, subagents
|
|
|
70
70
|
if (v === undefined || v === null) {
|
|
71
71
|
throw new Error(`Missing required argument: ${name}. Add "${name}" to the tool call arguments and retry.`);
|
|
72
72
|
}
|
|
73
|
+
// The contract says `path: string`/`command: string`; nothing used to
|
|
74
|
+
// enforce it, so an OBJECT became "[object Object]" and the file tools
|
|
75
|
+
// CREATED a file with that literal name (the same family as the old
|
|
76
|
+
// `undefined` file). A garbled tool call is exactly this shape.
|
|
77
|
+
if (typeof v === 'object' || typeof v === 'function') {
|
|
78
|
+
throw new Error(`Invalid required argument ${name}: expected a string, got ` +
|
|
79
|
+
JSON.stringify(v) +
|
|
80
|
+
'. Re-send the call with a plain string value.');
|
|
81
|
+
}
|
|
73
82
|
const s = String(v);
|
|
74
83
|
if (s === '' || s === 'undefined' || s === 'null') {
|
|
75
84
|
throw new Error(`Invalid required argument ${name}: ${JSON.stringify(v)}. Provide a non-empty value for "${name}" and retry.`);
|
package/dist/tui/InputLine.js
CHANGED
|
@@ -11,7 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
12
12
|
import { Box, Text, useInput, usePaste, useCursor, useWindowSize, useStdin, } from 'ink';
|
|
13
13
|
import { translate } from '../i18n.js';
|
|
14
|
-
import { layoutInput, SUGGEST_PAGE, } from '../input/layout.js';
|
|
14
|
+
import { inputInnerCols, layoutInput, SUGGEST_PAGE, } from '../input/layout.js';
|
|
15
15
|
import { insertText, insertPaste, insertNewline, backspace, del, moveLeft, moveRight, moveHome, moveEnd, wordLeft, wordRight, deleteWordLeft, deleteWordRight, killToLineEnd, moveVisualRows, pushUndo, undoEdit, historyUp, historyDown, searchStart, searchNext, searchAccept, searchCancel, searchInput, searchBackspace, recordHistory, afterSubmit, } from './edit.js';
|
|
16
16
|
import { dispatchKey, parseCsiU } from './keys.js';
|
|
17
17
|
import { useSyncExternalStore } from 'react';
|
|
@@ -42,9 +42,13 @@ export function InputLine(props) {
|
|
|
42
42
|
}));
|
|
43
43
|
}, [props.store]);
|
|
44
44
|
// The input lives inside a rounded box: 2 columns of border (left/right) plus
|
|
45
|
-
// 1 column of inner padding on each side
|
|
46
|
-
//
|
|
47
|
-
|
|
45
|
+
// 1 column of inner padding on each side, so the CONTENT width is `cols - 4`.
|
|
46
|
+
// Use the SHARED helper: `inputBoxRows()` — the height the full-screen layout
|
|
47
|
+
// reserves — is computed from the SAME function, and a hand-written
|
|
48
|
+
// `Math.max(4, cols - 4)` here was one independent copy that could drift from
|
|
49
|
+
// the reservation (the box then rendered more rows than were reserved and the
|
|
50
|
+
// input rows overprinted the status bar).
|
|
51
|
+
const innerCols = inputInnerCols(cols);
|
|
48
52
|
// Mirror the state into a ref so the useInput callback (a stable closure Ink
|
|
49
53
|
// calls for every key) always sees the latest values.
|
|
50
54
|
const stRef = useRef(st);
|
package/dist/tui/StatusBar.js
CHANGED
|
@@ -27,7 +27,7 @@ function stateLabel(state, locale) {
|
|
|
27
27
|
* status). Measured with the shared `visLen` so wide chars (CJK/emoji) count
|
|
28
28
|
* as 2 and the emoji's text-presentation selector (\uFE0E) as 0 — a plain
|
|
29
29
|
* `.length` counted an emoji as 1 and a CJK badge was clipped on a narrow
|
|
30
|
-
* terminal
|
|
30
|
+
* terminal. Exported so the width arithmetic is unit-tested
|
|
31
31
|
* without rendering. */
|
|
32
32
|
export function badgeTextWidth(state) {
|
|
33
33
|
let w = 0;
|
package/dist/tui/log-window.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// purpose: measuring the real Yoga layout per entry would need a ref per row
|
|
8
8
|
// and a re-render, while counting wrapped lines is exact enough for a log and
|
|
9
9
|
// costs nothing.
|
|
10
|
+
import { charWidth } from '../input/layout.js';
|
|
10
11
|
/** Visible width of a line without ANSI escapes (wide chars count 2). */
|
|
11
12
|
function visWidth(s) {
|
|
12
13
|
let w = 0;
|
|
@@ -43,16 +44,14 @@ function visWidth(s) {
|
|
|
43
44
|
continue;
|
|
44
45
|
}
|
|
45
46
|
const cp = s.codePointAt(i);
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
else
|
|
55
|
-
w += 1;
|
|
47
|
+
// Use the SAME width rule as the input/status layout (charWidth in
|
|
48
|
+
// src/input/layout.ts). The old table here counted EVERYTHING up to
|
|
49
|
+
// U+9FFF as two cells, so a line of box arrows (`→`, U+2192), the
|
|
50
|
+
// hourglass `⧗` (U+29D7) or Cyrillic/Greek letters over-estimated its
|
|
51
|
+
// rows; at a narrow width that reserves an extra row per entry and the
|
|
52
|
+
// pane believes it is full, stopping the scroll early. Sharing ONE table
|
|
53
|
+
// keeps the viewport and the rest of the TUI from disagreeing.
|
|
54
|
+
w += charWidth(cp);
|
|
56
55
|
i += cp > 0xffff ? 2 : 1;
|
|
57
56
|
}
|
|
58
57
|
return w;
|
package/dist/web.js
CHANGED
|
@@ -654,22 +654,32 @@ export function parseDuckDuckGoResults(body, limit) {
|
|
|
654
654
|
// single regex made the snippet group OPTIONAL with an unbounded gap, so a
|
|
655
655
|
// result without a snippet picked up the FOLLOWING result's snippet (wrong
|
|
656
656
|
// text under a URL). A row scan ties every snippet to its own result.
|
|
657
|
-
|
|
657
|
+
// A result anchor is `<a … class="… result__a|result__snippet …" …>`. The
|
|
658
|
+
// attribute VALUES may be single-quoted (HTML allows both, and a page served
|
|
659
|
+
// through a proxy does), so each quote style is accepted rather than only
|
|
660
|
+
// `class="…"`. Rejecting them made a valid page parse to zero results and
|
|
661
|
+
// WebSearch answer "the output format may have changed".
|
|
662
|
+
const anchorRe = /<a[^>]*class=(?:"([^"]*)"|'([^']*)')[^>]*>([\s\S]*?)<\/a>/gi;
|
|
658
663
|
const hrefOf = (tag) => {
|
|
659
|
-
const m = tag.match(/href="([^"]*)"/i);
|
|
660
|
-
return m ? m[1] : '';
|
|
664
|
+
const m = tag.match(/href=(?:"([^"]*)"|'([^']*)')/i);
|
|
665
|
+
return m ? (m[1] ?? m[2] ?? '') : '';
|
|
661
666
|
};
|
|
662
667
|
let cur = null;
|
|
663
668
|
let m;
|
|
664
669
|
while ((m = anchorRe.exec(body))) {
|
|
665
|
-
const
|
|
670
|
+
const classes = m[1] ?? m[2] ?? '';
|
|
671
|
+
const kindMatch = /result__(a|snippet)/i.exec(classes);
|
|
672
|
+
if (!kindMatch)
|
|
673
|
+
continue;
|
|
674
|
+
const kind = kindMatch[1].toLowerCase();
|
|
675
|
+
const text = m[3] || '';
|
|
666
676
|
if (kind === 'a') {
|
|
667
677
|
if (cur && cur.title && /^https?:\/\//i.test(cur.url)) {
|
|
668
678
|
results.push(cur);
|
|
669
679
|
if (results.length >= limit)
|
|
670
680
|
return results;
|
|
671
681
|
}
|
|
672
|
-
cur = { title: htmlToText(
|
|
682
|
+
cur = { title: htmlToText(text).trim(), url: '', snippet: '' };
|
|
673
683
|
// The href lives in the OPENING tag, which m[0] starts with.
|
|
674
684
|
let href = hrefOf(m[0].slice(0, m[0].indexOf('>') + 1));
|
|
675
685
|
const uddg = href.match(/[?&]uddg=([^&]+)/);
|
|
@@ -685,7 +695,7 @@ export function parseDuckDuckGoResults(body, limit) {
|
|
|
685
695
|
continue;
|
|
686
696
|
}
|
|
687
697
|
if (cur && !cur.snippet)
|
|
688
|
-
cur.snippet = htmlToText(
|
|
698
|
+
cur.snippet = htmlToText(text).trim();
|
|
689
699
|
}
|
|
690
700
|
if (cur && cur.title && /^https?:\/\//i.test(cur.url))
|
|
691
701
|
results.push(cur);
|