@nexrall/code-core 1.4.76 → 1.4.77
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/goal.d.ts +55 -0
- package/dist/agent/goal.d.ts.map +1 -0
- package/dist/agent/goal.js +120 -0
- package/dist/agent/handoffBrief.d.ts +82 -0
- package/dist/agent/handoffBrief.d.ts.map +1 -0
- package/dist/agent/handoffBrief.js +121 -0
- package/dist/agent/modelCatalogue.d.ts +23 -0
- package/dist/agent/modelCatalogue.d.ts.map +1 -1
- package/dist/agent/modelCatalogue.js +28 -0
- package/dist/agent/outputStyles.d.ts +27 -0
- package/dist/agent/outputStyles.d.ts.map +1 -0
- package/dist/agent/outputStyles.js +174 -0
- package/dist/agent/skills.d.ts.map +1 -1
- package/dist/agent/skills.js +7 -0
- package/dist/api/billingLines.d.ts +11 -0
- package/dist/api/billingLines.d.ts.map +1 -0
- package/dist/api/billingLines.js +56 -0
- package/dist/api/client.d.ts +2 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/scheduleLines.d.ts +53 -0
- package/dist/api/scheduleLines.d.ts.map +1 -0
- package/dist/api/scheduleLines.js +150 -0
- package/dist/context/contextFiles.d.ts +81 -0
- package/dist/context/contextFiles.d.ts.map +1 -0
- package/dist/context/contextFiles.js +310 -0
- package/dist/diff/collect.d.ts +25 -0
- package/dist/diff/collect.d.ts.map +1 -0
- package/dist/diff/collect.js +169 -0
- package/dist/diff/diffView.d.ts +57 -0
- package/dist/diff/diffView.d.ts.map +1 -0
- package/dist/diff/diffView.js +231 -0
- package/dist/diff/reviewQueue.d.ts +53 -0
- package/dist/diff/reviewQueue.d.ts.map +1 -0
- package/dist/diff/reviewQueue.js +349 -0
- package/dist/events/recap.d.ts +54 -0
- package/dist/events/recap.d.ts.map +1 -0
- package/dist/events/recap.js +161 -0
- package/dist/events/sessionEvents.d.ts +54 -0
- package/dist/events/sessionEvents.d.ts.map +1 -0
- package/dist/events/sessionEvents.js +324 -0
- package/dist/events/sessionStats.d.ts +89 -0
- package/dist/events/sessionStats.d.ts.map +1 -0
- package/dist/events/sessionStats.js +264 -0
- package/dist/import/claudeImport.d.ts +44 -0
- package/dist/import/claudeImport.d.ts.map +1 -0
- package/dist/import/claudeImport.js +337 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -0
- package/dist/project/projectCommands.d.ts +33 -0
- package/dist/project/projectCommands.d.ts.map +1 -0
- package/dist/project/projectCommands.js +246 -0
- package/dist/search/conversationTurns.d.ts +53 -0
- package/dist/search/conversationTurns.d.ts.map +1 -0
- package/dist/search/conversationTurns.js +170 -0
- package/dist/search/globalSearch.d.ts +144 -0
- package/dist/search/globalSearch.d.ts.map +1 -0
- package/dist/search/globalSearch.js +350 -0
- package/dist/share/sessionChannel.d.ts +136 -0
- package/dist/share/sessionChannel.d.ts.map +1 -0
- package/dist/share/sessionChannel.js +373 -0
- package/dist/share/sessionShare.d.ts +104 -0
- package/dist/share/sessionShare.d.ts.map +1 -0
- package/dist/share/sessionShare.js +336 -0
- package/dist/ui/configCmd.d.ts +48 -0
- package/dist/ui/configCmd.d.ts.map +1 -0
- package/dist/ui/configCmd.js +146 -0
- package/dist/ui/deployPanel.d.ts +91 -0
- package/dist/ui/deployPanel.d.ts.map +1 -0
- package/dist/ui/deployPanel.js +442 -0
- package/dist/ui/mergeAssistant.d.ts +120 -0
- package/dist/ui/mergeAssistant.d.ts.map +1 -0
- package/dist/ui/mergeAssistant.js +391 -0
- package/dist/ui/notify.d.ts +114 -0
- package/dist/ui/notify.d.ts.map +1 -0
- package/dist/ui/notify.js +235 -0
- package/dist/ui/promptSuggest.d.ts +56 -0
- package/dist/ui/promptSuggest.d.ts.map +1 -0
- package/dist/ui/promptSuggest.js +160 -0
- package/dist/ui/taskGraph.d.ts +44 -0
- package/dist/ui/taskGraph.d.ts.map +1 -0
- package/dist/ui/taskGraph.js +289 -0
- package/dist/util/addDir.d.ts +31 -0
- package/dist/util/addDir.d.ts.map +1 -0
- package/dist/util/addDir.js +124 -0
- package/dist/util/batch.d.ts +16 -0
- package/dist/util/batch.d.ts.map +1 -0
- package/dist/util/batch.js +92 -0
- package/dist/util/cellWidth.d.ts +12 -0
- package/dist/util/cellWidth.d.ts.map +1 -0
- package/dist/util/cellWidth.js +161 -0
- package/dist/util/duration.d.ts +8 -0
- package/dist/util/duration.d.ts.map +1 -0
- package/dist/util/duration.js +50 -0
- package/dist/util/loopJobs.d.ts +67 -0
- package/dist/util/loopJobs.d.ts.map +1 -0
- package/dist/util/loopJobs.js +169 -0
- package/dist/util/settingsFile.d.ts +14 -0
- package/dist/util/settingsFile.d.ts.map +1 -0
- package/dist/util/settingsFile.js +99 -0
- package/dist/util/toolLabel.d.ts +2 -0
- package/dist/util/toolLabel.d.ts.map +1 -0
- package/dist/util/toolLabel.js +17 -0
- package/dist/verify/failureTimeline.d.ts +100 -0
- package/dist/verify/failureTimeline.d.ts.map +1 -0
- package/dist/verify/failureTimeline.js +253 -0
- package/dist/verify/verification.d.ts +75 -0
- package/dist/verify/verification.d.ts.map +1 -0
- package/dist/verify/verification.js +315 -0
- package/package.json +5 -4
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Project commands: `/run`, `/test`, `/build`, `/lint` and `/git` (spec §85).
|
|
3
|
+
//
|
|
4
|
+
// Lives in core (moved from the CLI's projectCommands.ts, 2026-10-04) so the
|
|
5
|
+
// VS Code panel detects the same commands and runs them in its own terminal;
|
|
6
|
+
// the CLI module is a re-export shim.
|
|
7
|
+
//
|
|
8
|
+
// WHY: the everyday things you do next to an agent are "run the tests", "build it",
|
|
9
|
+
// "show me the diff" — and the only way to do them was `!npm test`, typed out in
|
|
10
|
+
// full, or asking the model (a whole turn, tokens, and an approval prompt for
|
|
11
|
+
// something YOU decided). `/test` should mean "whatever testing means in this
|
|
12
|
+
// project". That is a detection problem, and detection is what this file is: what
|
|
13
|
+
// `test` IS depends on the folder, so we read the folder instead of guessing.
|
|
14
|
+
//
|
|
15
|
+
// Kept free of chat.ts/Ink so every rule here is unit-testable (test/projectCommands.test.ts).
|
|
16
|
+
// The command that comes out is run through the SAME path as `!cmd` (permission
|
|
17
|
+
// rules, read-only gate, output limits, background, transcript) — this module only
|
|
18
|
+
// decides WHAT to run, never runs it.
|
|
19
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
20
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.packageManager = packageManager;
|
|
24
|
+
exports.detectProjectCommands = detectProjectCommands;
|
|
25
|
+
exports.resolveShortcut = resolveShortcut;
|
|
26
|
+
exports.gitCommand = gitCommand;
|
|
27
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
28
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
29
|
+
/** Lifecycle hooks: npm runs these itself, so they are noise in a "what can I run" list. */
|
|
30
|
+
const NPM_HOOKS = new Set([
|
|
31
|
+
'preinstall',
|
|
32
|
+
'install',
|
|
33
|
+
'postinstall',
|
|
34
|
+
'prepare',
|
|
35
|
+
'prepublish',
|
|
36
|
+
'prepublishOnly',
|
|
37
|
+
'prepack',
|
|
38
|
+
'postpack',
|
|
39
|
+
'preversion',
|
|
40
|
+
'postversion',
|
|
41
|
+
'dependencies',
|
|
42
|
+
'prepublishOnly',
|
|
43
|
+
]);
|
|
44
|
+
function readText(file) {
|
|
45
|
+
try {
|
|
46
|
+
return node_fs_1.default.readFileSync(file, 'utf-8');
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function isFile(file) {
|
|
53
|
+
try {
|
|
54
|
+
return node_fs_1.default.statSync(file).isFile();
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** The package manager whose scripts this project's lockfile asks for. */
|
|
61
|
+
function packageManager(workDir) {
|
|
62
|
+
const has = (f) => isFile(node_path_1.default.join(workDir, f));
|
|
63
|
+
if (has('pnpm-lock.yaml') || has('pnpm-workspace.yaml'))
|
|
64
|
+
return 'pnpm';
|
|
65
|
+
if (has('yarn.lock'))
|
|
66
|
+
return 'yarn';
|
|
67
|
+
if (has('bun.lockb') || has('bun.lock'))
|
|
68
|
+
return 'bun';
|
|
69
|
+
return 'npm';
|
|
70
|
+
}
|
|
71
|
+
/** Reads `scripts` out of a package.json-shaped file. Never throws on bad JSON. */
|
|
72
|
+
function readScripts(file, rel) {
|
|
73
|
+
const raw = readText(file);
|
|
74
|
+
if (raw === null)
|
|
75
|
+
return [];
|
|
76
|
+
let json;
|
|
77
|
+
try {
|
|
78
|
+
json = JSON.parse(raw);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
const scripts = json?.scripts;
|
|
84
|
+
if (!scripts || typeof scripts !== 'object')
|
|
85
|
+
return [];
|
|
86
|
+
const pm = packageManager(node_path_1.default.dirname(file));
|
|
87
|
+
return Object.keys(scripts)
|
|
88
|
+
.filter((n) => !NPM_HOOKS.has(n))
|
|
89
|
+
.map((n) => ({ name: n, command: `${pm} run ${n}`, source: rel }));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Make targets: column-0 `name:` rules, minus assignments (`VAR := x`, `+=`).
|
|
93
|
+
*
|
|
94
|
+
* Pattern rules (`%.o: %.c`) need no test of their own: the name is
|
|
95
|
+
* `[A-Za-z0-9][\w.-]*` and must be followed directly by `:`, so a `%` — which is not in
|
|
96
|
+
* that class — can never reach the name. A guard for it was written, proved
|
|
97
|
+
* unreachable by a mutation run, and removed rather than left looking load-bearing.
|
|
98
|
+
* Targets containing `/` are deliberately not listed: `src/foo.o: src/foo.c` would
|
|
99
|
+
* flood /run with one entry per object file.
|
|
100
|
+
*/
|
|
101
|
+
function makeTargets(file, rel) {
|
|
102
|
+
const raw = readText(file);
|
|
103
|
+
if (raw === null)
|
|
104
|
+
return [];
|
|
105
|
+
const out = [];
|
|
106
|
+
for (const line of raw.split('\n')) {
|
|
107
|
+
const m = /^([A-Za-z0-9][\w.-]*)\s*:(?!=)/.exec(line);
|
|
108
|
+
if (!m)
|
|
109
|
+
continue;
|
|
110
|
+
out.push({ name: m[1], command: `make ${m[1]}`, source: rel });
|
|
111
|
+
}
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
/** justfile recipes: column-0 `name arg:` / `name:`, minus assignments (`x := y`). */
|
|
115
|
+
function justRecipes(file, rel) {
|
|
116
|
+
const raw = readText(file);
|
|
117
|
+
if (raw === null)
|
|
118
|
+
return [];
|
|
119
|
+
const out = [];
|
|
120
|
+
for (const line of raw.split('\n')) {
|
|
121
|
+
const m = /^([A-Za-z_][\w-]*)(\s[^:]*)?\s*:(?!=)/.exec(line);
|
|
122
|
+
if (!m)
|
|
123
|
+
continue;
|
|
124
|
+
out.push({ name: m[1], command: `just ${m[1]}`, source: rel });
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
/** `deno task` entries. deno.jsonc is skipped: its comments need a real JSONC parser. */
|
|
129
|
+
function denoTasks(file, rel) {
|
|
130
|
+
const raw = readText(file);
|
|
131
|
+
if (raw === null)
|
|
132
|
+
return [];
|
|
133
|
+
let json;
|
|
134
|
+
try {
|
|
135
|
+
json = JSON.parse(raw);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
const tasks = json?.tasks;
|
|
141
|
+
if (!tasks || typeof tasks !== 'object')
|
|
142
|
+
return [];
|
|
143
|
+
return Object.keys(tasks).map((n) => ({ name: n, command: `deno task ${n}`, source: rel }));
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Every command this folder can run, in a stable order (package.json first — the most
|
|
147
|
+
* common source — then the rest alphabetically). Missing files are simply absent: a
|
|
148
|
+
* project with no package.json is not an error, it is a Cargo project.
|
|
149
|
+
*/
|
|
150
|
+
function detectProjectCommands(workDir) {
|
|
151
|
+
const out = [];
|
|
152
|
+
const at = (f) => node_path_1.default.join(workDir, f);
|
|
153
|
+
out.push(...readScripts(at('package.json'), 'package.json'));
|
|
154
|
+
const makefile = ['Makefile', 'makefile', 'GNUmakefile'].find((f) => isFile(at(f)));
|
|
155
|
+
if (makefile)
|
|
156
|
+
out.push(...makeTargets(at(makefile), makefile));
|
|
157
|
+
const justfile = ['justfile', 'Justfile'].find((f) => isFile(at(f)));
|
|
158
|
+
if (justfile)
|
|
159
|
+
out.push(...justRecipes(at(justfile), justfile));
|
|
160
|
+
if (isFile(at('deno.json')))
|
|
161
|
+
out.push(...denoTasks(at('deno.json'), 'deno.json'));
|
|
162
|
+
const composer = readText(at('composer.json'));
|
|
163
|
+
if (composer !== null) {
|
|
164
|
+
try {
|
|
165
|
+
const json = JSON.parse(composer);
|
|
166
|
+
for (const n of Object.keys(json?.scripts ?? {})) {
|
|
167
|
+
out.push({ name: n, command: `composer run ${n}`, source: 'composer.json' });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
/* a broken composer.json is not this command's problem */
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Go and Rust have one obvious command per task; no file to read beyond the manifest.
|
|
175
|
+
if (isFile(at('go.mod'))) {
|
|
176
|
+
out.push({ name: 'build', command: 'go build ./...', source: 'go.mod' }, { name: 'test', command: 'go test ./...', source: 'go.mod' }, { name: 'vet', command: 'go vet ./...', source: 'go.mod' }, { name: 'fmt', command: 'gofmt -l .', source: 'go.mod' });
|
|
177
|
+
}
|
|
178
|
+
if (isFile(at('Cargo.toml'))) {
|
|
179
|
+
out.push({ name: 'build', command: 'cargo build', source: 'Cargo.toml' }, { name: 'test', command: 'cargo test', source: 'Cargo.toml' }, { name: 'check', command: 'cargo check', source: 'Cargo.toml' }, { name: 'clippy', command: 'cargo clippy', source: 'Cargo.toml' }, { name: 'fmt', command: 'cargo fmt --check', source: 'Cargo.toml' });
|
|
180
|
+
}
|
|
181
|
+
// Python: only when the folder actually says how it is tested/linted. `pytest -q` in a
|
|
182
|
+
// project with no pytest is a wasted round trip, so evidence is required.
|
|
183
|
+
const pyproject = readText(at('pyproject.toml')) ?? '';
|
|
184
|
+
const hasPytest = isFile(at('pytest.ini')) ||
|
|
185
|
+
isFile(at('tox.ini')) ||
|
|
186
|
+
pyproject.includes('[tool.pytest') ||
|
|
187
|
+
node_fs_1.default.existsSync(at('tests'));
|
|
188
|
+
if (hasPytest)
|
|
189
|
+
out.push({ name: 'test', command: 'pytest -q', source: pyproject ? 'pyproject.toml' : 'pytest' });
|
|
190
|
+
if (pyproject.includes('[tool.ruff') || isFile(at('ruff.toml'))) {
|
|
191
|
+
out.push({ name: 'lint', command: 'ruff check .', source: 'ruff.toml' });
|
|
192
|
+
}
|
|
193
|
+
if (pyproject.includes('[tool.mypy')) {
|
|
194
|
+
out.push({ name: 'typecheck', command: 'mypy .', source: 'pyproject.toml' });
|
|
195
|
+
}
|
|
196
|
+
// An identical row twice (a Makefile that defines the same target twice, two
|
|
197
|
+
// manifests offering the same command) is always noise; the first source wins.
|
|
198
|
+
const seen = new Set();
|
|
199
|
+
return out.filter((c) => (seen.has(c.command) ? false : (seen.add(c.command), true)));
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* How well a command name answers a shortcut, lower is better, -1 means "not this one".
|
|
203
|
+
* `test:unit` and `test-unit` both answer `/test`; `e2e:test` only just.
|
|
204
|
+
*
|
|
205
|
+
* Word-based, never substring: an endsWith rule was tried and dropped, because
|
|
206
|
+
* "latest".endsWith("test") is TRUE — so `/test` in a project whose only script was
|
|
207
|
+
* `latest` would have run it and called it the test suite. `eslint` losing to that
|
|
208
|
+
* rule is the price, and `/run eslint` still works: running the wrong thing quietly
|
|
209
|
+
* is far worse than not finding a name.
|
|
210
|
+
*/
|
|
211
|
+
function tier(name, want) {
|
|
212
|
+
const n = name.toLowerCase();
|
|
213
|
+
const w = want.toLowerCase();
|
|
214
|
+
if (n === w)
|
|
215
|
+
return 0;
|
|
216
|
+
const parts = n.split(/[:._-]+/);
|
|
217
|
+
if (parts[0] === w)
|
|
218
|
+
return 1;
|
|
219
|
+
if (parts.includes(w))
|
|
220
|
+
return 2;
|
|
221
|
+
return -1;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* The commands a shortcut should run: everything in the best tier it finds, best
|
|
225
|
+
* first. More than one means the caller asks which (a repo with `test` and
|
|
226
|
+
* `test:integration` should not silently pick one — running the wrong suite and
|
|
227
|
+
* calling it "the tests" is worse than one extra keystroke).
|
|
228
|
+
*/
|
|
229
|
+
function resolveShortcut(cmds, want) {
|
|
230
|
+
const scored = cmds.map((c) => ({ c, t: tier(c.name, want) })).filter((x) => x.t >= 0);
|
|
231
|
+
if (!scored.length)
|
|
232
|
+
return [];
|
|
233
|
+
const best = Math.min(...scored.map((x) => x.t));
|
|
234
|
+
return scored.filter((x) => x.t === best).map((x) => x.c);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Runs `git` with the user's arguments: `/git` alone means `git status`, `/git log -5`
|
|
238
|
+
* means exactly that. Not a list of allowed subcommands — the read-only gate in front
|
|
239
|
+
* of this (core's isReadOnlyBash) is what decides whether it may run unprompted, so
|
|
240
|
+
* `/git commit` works in a normal session and is refused under `--readonly`.
|
|
241
|
+
*/
|
|
242
|
+
function gitCommand(arg) {
|
|
243
|
+
const a = arg.trim();
|
|
244
|
+
return a ? `git ${a}` : 'git status';
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=projectCommands.js.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type Message } from '../types';
|
|
2
|
+
/** `!cmd` transcripts are synthesised user messages; this is their prefix (moved
|
|
3
|
+
* here from commands/bangShell.ts so the synthetic-user list has one home). */
|
|
4
|
+
export declare const BANG_TRANSCRIPT_PREFIX = "I ran this command myself in the terminal:";
|
|
5
|
+
/** Lines of a turn's body shown by a jump before the rest is summarised. */
|
|
6
|
+
export declare const MAX_TURN_LINES = 80;
|
|
7
|
+
/** Tool-result lines kept inline; the rest is a count. */
|
|
8
|
+
export declare const RESULT_PREVIEW_LINES = 3;
|
|
9
|
+
/** Newest turns kept — a 400-turn session does not need all of it in memory. */
|
|
10
|
+
export declare const MAX_TURNS = 200;
|
|
11
|
+
/** Prompt length in a turn header / search label. */
|
|
12
|
+
export declare const PROMPT_CLIP = 100;
|
|
13
|
+
export interface Turn {
|
|
14
|
+
/** 1-based, in conversation order. */
|
|
15
|
+
index: number;
|
|
16
|
+
/** The user's prompt, flattened to one line. */
|
|
17
|
+
prompt: string;
|
|
18
|
+
/** Body lines, ready to print (no colour). */
|
|
19
|
+
lines: string[];
|
|
20
|
+
toolCalls: number;
|
|
21
|
+
/** Lines dropped by MAX_TURN_LINES (0 when everything fit). */
|
|
22
|
+
dropped: number;
|
|
23
|
+
}
|
|
24
|
+
export declare function flatten(s: string): string;
|
|
25
|
+
export declare function clip(s: string, max: number): string;
|
|
26
|
+
/** One display line per content block, or null for blocks that are not conversation. */
|
|
27
|
+
export declare function blockLines(m: Message, b: Message['content'][number]): string[] | null;
|
|
28
|
+
/** Did this user message start a turn, or is it agent bookkeeping? */
|
|
29
|
+
export declare function startsTurn(m: Message): boolean;
|
|
30
|
+
export declare function isSyntheticUserText(text: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Group the conversation into turns. Content before the first real prompt (the
|
|
33
|
+
* opening context block) is not a turn and is skipped.
|
|
34
|
+
*/
|
|
35
|
+
export declare function turnsFrom(messages: Message[], opts?: {
|
|
36
|
+
maxLines?: number;
|
|
37
|
+
maxTurns?: number;
|
|
38
|
+
}): Turn[];
|
|
39
|
+
/**
|
|
40
|
+
* The most recent real prompt in the conversation — the label a `/cost` turn row carries.
|
|
41
|
+
*
|
|
42
|
+
* Scans BACKWARDS so a mid-turn follow-up (folded in by the loop while the agent works) is
|
|
43
|
+
* what the row reads: that is the last thing the user actually asked for. '' when nothing
|
|
44
|
+
* has been typed yet.
|
|
45
|
+
*/
|
|
46
|
+
export declare function lastPrompt(messages: Message[], max?: number): string;
|
|
47
|
+
/**
|
|
48
|
+
* The last prompt the USER actually typed — skips the synthetic user messages (a `!cmd`
|
|
49
|
+
* transcript, a task notification, a peer message), which are turns but were not typed.
|
|
50
|
+
* The §81 handoff goal is built from this; `lastPrompt` deliberately does not skip them.
|
|
51
|
+
*/
|
|
52
|
+
export declare function lastTypedPrompt(messages: Message[], max?: number): string;
|
|
53
|
+
//# sourceMappingURL=conversationTurns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversationTurns.d.ts","sourceRoot":"","sources":["../../src/search/conversationTurns.ts"],"names":[],"mappings":"AAGA,OAAO,EAAyB,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAG/D;gFACgF;AAChF,eAAO,MAAM,sBAAsB,+CAA+C,CAAC;AAEnF,4EAA4E;AAC5E,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,0DAA0D;AAC1D,eAAO,MAAM,oBAAoB,IAAI,CAAC;AACtC,gFAAgF;AAChF,eAAO,MAAM,SAAS,MAAM,CAAC;AAC7B,qDAAqD;AACrD,eAAO,MAAM,WAAW,MAAM,CAAC;AAE/B,MAAM,WAAW,IAAI;IACnB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wFAAwF;AACxF,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,GAAG,IAAI,CAwBrF;AAUD,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAG9C;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,IAAI,EAAE,CA4C1G;AAUD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,GAAG,SAAc,GAAG,MAAM,CAQzE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,GAAG,SAAc,GAAG,MAAM,CAQ9E"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROMPT_CLIP = exports.MAX_TURNS = exports.RESULT_PREVIEW_LINES = exports.MAX_TURN_LINES = exports.BANG_TRANSCRIPT_PREFIX = void 0;
|
|
4
|
+
exports.flatten = flatten;
|
|
5
|
+
exports.clip = clip;
|
|
6
|
+
exports.blockLines = blockLines;
|
|
7
|
+
exports.startsTurn = startsTurn;
|
|
8
|
+
exports.isSyntheticUserText = isSyntheticUserText;
|
|
9
|
+
exports.turnsFrom = turnsFrom;
|
|
10
|
+
exports.lastPrompt = lastPrompt;
|
|
11
|
+
exports.lastTypedPrompt = lastTypedPrompt;
|
|
12
|
+
// Conversation → turns, the pure half (moved from the CLI's ui/transcriptView.ts,
|
|
13
|
+
// 2026-10-04) so /find searches the SAME turn shape in the VS Code panel; the
|
|
14
|
+
// CLI module re-exports everything.
|
|
15
|
+
const types_1 = require("../types");
|
|
16
|
+
const toolLabel_1 = require("../util/toolLabel");
|
|
17
|
+
/** `!cmd` transcripts are synthesised user messages; this is their prefix (moved
|
|
18
|
+
* here from commands/bangShell.ts so the synthetic-user list has one home). */
|
|
19
|
+
exports.BANG_TRANSCRIPT_PREFIX = 'I ran this command myself in the terminal:';
|
|
20
|
+
/** Lines of a turn's body shown by a jump before the rest is summarised. */
|
|
21
|
+
exports.MAX_TURN_LINES = 80;
|
|
22
|
+
/** Tool-result lines kept inline; the rest is a count. */
|
|
23
|
+
exports.RESULT_PREVIEW_LINES = 3;
|
|
24
|
+
/** Newest turns kept — a 400-turn session does not need all of it in memory. */
|
|
25
|
+
exports.MAX_TURNS = 200;
|
|
26
|
+
/** Prompt length in a turn header / search label. */
|
|
27
|
+
exports.PROMPT_CLIP = 100;
|
|
28
|
+
function flatten(s) {
|
|
29
|
+
return s.replace(/\s+/g, ' ').trim();
|
|
30
|
+
}
|
|
31
|
+
function clip(s, max) {
|
|
32
|
+
return s.length <= max ? s : s.slice(0, max - 1) + '\u2026';
|
|
33
|
+
}
|
|
34
|
+
/** One display line per content block, or null for blocks that are not conversation. */
|
|
35
|
+
function blockLines(m, b) {
|
|
36
|
+
switch (b.type) {
|
|
37
|
+
case 'text': {
|
|
38
|
+
const text = b.text.trimEnd();
|
|
39
|
+
if (!text.trim())
|
|
40
|
+
return null;
|
|
41
|
+
if (m.role === 'user')
|
|
42
|
+
return text.split('\n').map((l) => ' ' + l);
|
|
43
|
+
return text.split('\n');
|
|
44
|
+
}
|
|
45
|
+
case 'tool_use':
|
|
46
|
+
return [' \u26a1 ' + (0, toolLabel_1.toolLabel)(b.name, b.input)];
|
|
47
|
+
case 'tool_result': {
|
|
48
|
+
const body = b.content.replace(/\r/g, '').trimEnd().split('\n');
|
|
49
|
+
const kept = body.slice(0, exports.RESULT_PREVIEW_LINES).map((l) => ' \u2502 ' + clip(l, 200));
|
|
50
|
+
if (body.length > exports.RESULT_PREVIEW_LINES)
|
|
51
|
+
kept.push(` \u2514 \u2026 +${body.length - exports.RESULT_PREVIEW_LINES} line(s)`);
|
|
52
|
+
return kept;
|
|
53
|
+
}
|
|
54
|
+
case 'image':
|
|
55
|
+
return [' [image]'];
|
|
56
|
+
case 'document':
|
|
57
|
+
return [' [document]'];
|
|
58
|
+
default:
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** User turns the CLI synthesised — outputs and notices folded in dressed as
|
|
63
|
+
* user messages. None of these is "what the user asked for". */
|
|
64
|
+
const SYNTHETIC_USER_PREFIXES = [
|
|
65
|
+
'<task-notification>', // core's formatBackgroundNotifications
|
|
66
|
+
exports.BANG_TRANSCRIPT_PREFIX, // a `!cmd` transcript
|
|
67
|
+
'[Message from peer session ', // core's renderPeerMessages
|
|
68
|
+
];
|
|
69
|
+
/** Did this user message start a turn, or is it agent bookkeeping? */
|
|
70
|
+
function startsTurn(m) {
|
|
71
|
+
if (m.role !== 'user')
|
|
72
|
+
return false;
|
|
73
|
+
return m.content.some((b) => b.type === 'text' && !(0, types_1.isRuntimeContextBlock)(b));
|
|
74
|
+
}
|
|
75
|
+
function isSyntheticUserText(text) {
|
|
76
|
+
return SYNTHETIC_USER_PREFIXES.some((p) => text.startsWith(p));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Group the conversation into turns. Content before the first real prompt (the
|
|
80
|
+
* opening context block) is not a turn and is skipped.
|
|
81
|
+
*/
|
|
82
|
+
function turnsFrom(messages, opts = {}) {
|
|
83
|
+
const maxLines = opts.maxLines ?? exports.MAX_TURN_LINES;
|
|
84
|
+
const turns = [];
|
|
85
|
+
let current = null;
|
|
86
|
+
let hasPrompt = false;
|
|
87
|
+
// The block a turn's prompt came from: it is printed as `> prompt` by the header,
|
|
88
|
+
// so repeating it as the first body line would show every question twice.
|
|
89
|
+
let promptBlock = null;
|
|
90
|
+
for (const m of messages) {
|
|
91
|
+
if (startsTurn(m)) {
|
|
92
|
+
if (current)
|
|
93
|
+
turns.push(finish(current, maxLines));
|
|
94
|
+
const firstText = m.content.find((b) => b.type === 'text' && !(0, types_1.isRuntimeContextBlock)(b));
|
|
95
|
+
current = {
|
|
96
|
+
index: turns.length + 1,
|
|
97
|
+
prompt: clip(flatten(firstText?.text ?? ''), exports.PROMPT_CLIP),
|
|
98
|
+
lines: [],
|
|
99
|
+
toolCalls: 0,
|
|
100
|
+
dropped: 0,
|
|
101
|
+
};
|
|
102
|
+
promptBlock = firstText ?? null;
|
|
103
|
+
hasPrompt = true;
|
|
104
|
+
}
|
|
105
|
+
if (!hasPrompt || !current)
|
|
106
|
+
continue;
|
|
107
|
+
for (const b of m.content) {
|
|
108
|
+
if (b === promptBlock) {
|
|
109
|
+
promptBlock = null;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (b.type === 'text' && (0, types_1.isRuntimeContextBlock)(b))
|
|
113
|
+
continue; // runtime context: not conversation
|
|
114
|
+
if (b.type === 'tool_use')
|
|
115
|
+
current.toolCalls++;
|
|
116
|
+
const lines = blockLines(m, b);
|
|
117
|
+
if (lines)
|
|
118
|
+
current.lines.push(...lines);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (current)
|
|
122
|
+
turns.push(finish(current, maxLines));
|
|
123
|
+
const kept = turns.length > (opts.maxTurns ?? exports.MAX_TURNS) ? turns.slice(-(opts.maxTurns ?? exports.MAX_TURNS)) : turns;
|
|
124
|
+
kept.forEach((t, i) => {
|
|
125
|
+
t.index = i + 1;
|
|
126
|
+
});
|
|
127
|
+
return kept;
|
|
128
|
+
}
|
|
129
|
+
function finish(t, maxLines) {
|
|
130
|
+
if (t.lines.length > maxLines) {
|
|
131
|
+
t.dropped = t.lines.length - maxLines;
|
|
132
|
+
t.lines = [...t.lines.slice(0, maxLines), ` \u2514 \u2026 ${t.dropped} more line(s) in this turn`];
|
|
133
|
+
}
|
|
134
|
+
return t;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* The most recent real prompt in the conversation — the label a `/cost` turn row carries.
|
|
138
|
+
*
|
|
139
|
+
* Scans BACKWARDS so a mid-turn follow-up (folded in by the loop while the agent works) is
|
|
140
|
+
* what the row reads: that is the last thing the user actually asked for. '' when nothing
|
|
141
|
+
* has been typed yet.
|
|
142
|
+
*/
|
|
143
|
+
function lastPrompt(messages, max = exports.PROMPT_CLIP) {
|
|
144
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
145
|
+
const m = messages[i];
|
|
146
|
+
if (m.role !== 'user')
|
|
147
|
+
continue;
|
|
148
|
+
const b = m.content.find((x) => x.type === 'text' && !(0, types_1.isRuntimeContextBlock)(x));
|
|
149
|
+
if (b && b.type === 'text')
|
|
150
|
+
return clip(flatten(b.text), max);
|
|
151
|
+
}
|
|
152
|
+
return '';
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The last prompt the USER actually typed — skips the synthetic user messages (a `!cmd`
|
|
156
|
+
* transcript, a task notification, a peer message), which are turns but were not typed.
|
|
157
|
+
* The §81 handoff goal is built from this; `lastPrompt` deliberately does not skip them.
|
|
158
|
+
*/
|
|
159
|
+
function lastTypedPrompt(messages, max = exports.PROMPT_CLIP) {
|
|
160
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
161
|
+
const m = messages[i];
|
|
162
|
+
if (m.role !== 'user')
|
|
163
|
+
continue;
|
|
164
|
+
const b = m.content.find((x) => x.type === 'text' && !(0, types_1.isRuntimeContextBlock)(x));
|
|
165
|
+
if (b && b.type === 'text' && !isSyntheticUserText(b.text))
|
|
166
|
+
return clip(flatten(b.text), max);
|
|
167
|
+
}
|
|
168
|
+
return '';
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=conversationTurns.js.map
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { Turn } from './conversationTurns';
|
|
2
|
+
import type { Incident } from '../verify/failureTimeline';
|
|
3
|
+
/**
|
|
4
|
+
* Structurally minimal shapes for the two CLI-UI stores (kept local so core
|
|
5
|
+
* needs no import from the CLI; richer objects pass structurally). The CLI's
|
|
6
|
+
* ToolOutputEntry / AgentNode satisfy these unchanged.
|
|
7
|
+
*/
|
|
8
|
+
export interface ToolOutputEntry {
|
|
9
|
+
/** Monotonic id, 1-based — what `/expand <n>` refers to. */
|
|
10
|
+
id: number;
|
|
11
|
+
name: string;
|
|
12
|
+
/** One-line description of the call (the command, the path …). */
|
|
13
|
+
label: string;
|
|
14
|
+
output: string;
|
|
15
|
+
isError: boolean;
|
|
16
|
+
durationMs: number;
|
|
17
|
+
}
|
|
18
|
+
export interface AgentNode {
|
|
19
|
+
name: string;
|
|
20
|
+
label: string;
|
|
21
|
+
files: string[];
|
|
22
|
+
error?: string;
|
|
23
|
+
report?: string;
|
|
24
|
+
}
|
|
25
|
+
export type Scope = 'files' | 'conversation' | 'tools' | 'git' | 'errors' | 'agents';
|
|
26
|
+
/** Display order — §52 lists files first because that is where a code query usually lives. */
|
|
27
|
+
export declare const SCOPES: readonly Scope[];
|
|
28
|
+
export declare const SCOPE_LABEL: Record<Scope, string>;
|
|
29
|
+
/** Hits printed per scope. The counts line stays complete — only the list is capped. */
|
|
30
|
+
export declare const MAX_PER_SCOPE = 5;
|
|
31
|
+
/** A matched line kept for context, so a hit is recognisable without opening anything. */
|
|
32
|
+
export declare const DETAIL_CLIP = 96;
|
|
33
|
+
export declare const LABEL_CLIP = 72;
|
|
34
|
+
export interface Hit {
|
|
35
|
+
scope: Scope;
|
|
36
|
+
/** Stable identity inside the scope, for the "N of M" note and for ordering. */
|
|
37
|
+
key: string;
|
|
38
|
+
/** What the row shows first: a path, a command, an agent. */
|
|
39
|
+
label: string;
|
|
40
|
+
/** The matching line, when the label itself is not the match. */
|
|
41
|
+
detail?: string;
|
|
42
|
+
/** 0 = best. */
|
|
43
|
+
score: number;
|
|
44
|
+
/** 1-based position in the scope's own listing, so the row can be found again. */
|
|
45
|
+
index: number;
|
|
46
|
+
}
|
|
47
|
+
export interface Sources {
|
|
48
|
+
files?: string[];
|
|
49
|
+
turns?: Turn[];
|
|
50
|
+
tools?: ToolOutputEntry[];
|
|
51
|
+
git?: Array<{
|
|
52
|
+
path: string;
|
|
53
|
+
status?: string;
|
|
54
|
+
}>;
|
|
55
|
+
errors?: Incident[];
|
|
56
|
+
agents?: AgentNode[];
|
|
57
|
+
}
|
|
58
|
+
export interface Count {
|
|
59
|
+
scope: Scope;
|
|
60
|
+
count: number;
|
|
61
|
+
}
|
|
62
|
+
export interface Result {
|
|
63
|
+
query: string;
|
|
64
|
+
hits: Hit[];
|
|
65
|
+
counts: Count[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Shorten an ASSEMBLED line to `cols`, keeping its leading indent.
|
|
69
|
+
*
|
|
70
|
+
* `clip` flattens whitespace, which is right for a path or a matched line but destroys a row
|
|
71
|
+
* whose alignment is the point: `clip(' Files 12')` returns `Files 12`, and every column in
|
|
72
|
+
* the counts block collapses. Measured on the first run of the tests in this module.
|
|
73
|
+
*/
|
|
74
|
+
export declare function fitLine(body: string, cols: number, indent?: string): string;
|
|
75
|
+
/**
|
|
76
|
+
* Rank one text against the query. `Infinity` = no match.
|
|
77
|
+
*
|
|
78
|
+
* Substring only, case-insensitive — this is a search box for code, where a fuzzy match is
|
|
79
|
+
* noise. The ladder, weakest last:
|
|
80
|
+
*
|
|
81
|
+
* 0 the text IS the query `auth` vs `auth`
|
|
82
|
+
* 1 the text begins with the query `auth.ts` vs `auth`
|
|
83
|
+
* 2 the query begins a word `src/auth.ts`, `jwt-refresh.ts`
|
|
84
|
+
* 3 the query starts mid-word `myjwthelper.ts`, `contest/a.ts`
|
|
85
|
+
*
|
|
86
|
+
* Rung 1 exists on its own because a tie between `auth.ts` and `x/auth-mid.ts` used to be
|
|
87
|
+
* settled by whatever order the scope listed them in, which put the worse match first.
|
|
88
|
+
*/
|
|
89
|
+
export declare function scoreText(query: string, text: string): number;
|
|
90
|
+
/** Files: the path itself. */
|
|
91
|
+
export declare function searchFiles(query: string, files: string[]): Hit[];
|
|
92
|
+
/** Conversation: prompts and reply lines, via the transcript the turn navigation already builds. */
|
|
93
|
+
export declare function searchConversation(query: string, turns: Turn[]): Hit[];
|
|
94
|
+
/** Tools: the call label and the output the transcript folded away. */
|
|
95
|
+
export declare function searchTools(query: string, entries: ToolOutputEntry[]): Hit[];
|
|
96
|
+
/** Git: changed paths, with the status letter kept in front so `M`/`??` is visible. */
|
|
97
|
+
export declare function searchGit(query: string, changes: Array<{
|
|
98
|
+
path: string;
|
|
99
|
+
status?: string;
|
|
100
|
+
}>): Hit[];
|
|
101
|
+
/** Errors: the failing command, the files it touched, and the re-tests. */
|
|
102
|
+
export declare function searchErrors(query: string, incidents: Incident[]): Hit[];
|
|
103
|
+
/** Agents: type, task label and the files each one touched. */
|
|
104
|
+
export declare function searchAgents(query: string, nodes: AgentNode[]): Hit[];
|
|
105
|
+
export declare function globalSearch(query: string, sources: Sources, perScope?: number): Result;
|
|
106
|
+
export declare function filterScope(hits: Hit[], scope: Scope | null): Hit[];
|
|
107
|
+
/**
|
|
108
|
+
* The §52 counts block:
|
|
109
|
+
*
|
|
110
|
+
* > JWT
|
|
111
|
+
*
|
|
112
|
+
* Files 12
|
|
113
|
+
* Conversation 8
|
|
114
|
+
* Git 3
|
|
115
|
+
* Agents 2
|
|
116
|
+
*
|
|
117
|
+
* Labels pad to the widest, counts right-align to the widest — so the numbers line up even
|
|
118
|
+
* when "Conversation" sits next to "Files". Every line is clipped to `cols`; at narrow widths
|
|
119
|
+
* the label is what gets cut, never the count.
|
|
120
|
+
*/
|
|
121
|
+
export declare function formatCounts(result: Result, cols: number, opts?: {
|
|
122
|
+
table?: boolean;
|
|
123
|
+
}): string[];
|
|
124
|
+
/**
|
|
125
|
+
* One printed row per hit: ` 3. Git M src/app.js`, with the matched line under it when the
|
|
126
|
+
* label alone would not say why it matched.
|
|
127
|
+
*
|
|
128
|
+
* `tag` prepends the 3-letter scope — on when the rows are mixed, off inside a per-scope
|
|
129
|
+
* section where the heading already said it.
|
|
130
|
+
*/
|
|
131
|
+
export declare function formatHits(hits: Hit[], cols: number, indent?: string, tag?: boolean): string[];
|
|
132
|
+
/** `Scopes: /find <q> --files --git` — only the flags that would actually narrow this result. */
|
|
133
|
+
export declare function scopeHint(counts: Count[]): string;
|
|
134
|
+
export interface SearchArgs {
|
|
135
|
+
query: string;
|
|
136
|
+
/** null = search everything. */
|
|
137
|
+
scopes: Scope[] | null;
|
|
138
|
+
/** Flags that are not scopes — reported instead of silently becoming part of the query. */
|
|
139
|
+
bad: string[];
|
|
140
|
+
}
|
|
141
|
+
/** `/find JWT --git --tools` → query "JWT", scopes [git, tools]. `--all` clears the narrowing. */
|
|
142
|
+
export declare function parseSearchArgs(arg: string): SearchArgs;
|
|
143
|
+
export declare function searchUsage(): string;
|
|
144
|
+
//# sourceMappingURL=globalSearch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"globalSearch.d.ts","sourceRoot":"","sources":["../../src/search/globalSearch.ts"],"names":[],"mappings":"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"}
|