zelari-code 1.44.0 → 1.46.1
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/cli/ast/engine.js +86 -23
- package/dist/cli/ast/engine.js.map +1 -1
- package/dist/cli/ast/engine.test.js +101 -0
- package/dist/cli/ast/engine.test.js.map +1 -0
- package/dist/cli/ast/tools.js +77 -15
- package/dist/cli/ast/tools.js.map +1 -1
- package/dist/cli/ast/tools.test.js +124 -0
- package/dist/cli/ast/tools.test.js.map +1 -0
- package/dist/cli/headless.js +37 -0
- package/dist/cli/headless.js.map +1 -1
- package/dist/cli/headless.test.js +107 -0
- package/dist/cli/headless.test.js.map +1 -0
- package/dist/cli/hooks/useChatTurn.js +2 -0
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/lsp/manager.js +10 -0
- package/dist/cli/lsp/manager.js.map +1 -1
- package/dist/cli/lsp/tools.js +37 -2
- package/dist/cli/lsp/tools.js.map +1 -1
- package/dist/cli/lsp/tools.test.js +90 -0
- package/dist/cli/lsp/tools.test.js.map +1 -0
- package/dist/cli/main.bundled.js +1082 -547
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/toolRegistry.js +22 -5
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/inspectCommand.js +346 -0
- package/dist/cli/tools/inspectCommand.js.map +1 -0
- package/dist/cli/tools/inspectCommand.test.js +311 -0
- package/dist/cli/tools/inspectCommand.test.js.map +1 -0
- package/dist/cli/tools/inspectTypecheckSafety.js +104 -0
- package/dist/cli/tools/inspectTypecheckSafety.js.map +1 -0
- package/dist/cli/tools/taskTool.js +4 -0
- package/dist/cli/tools/taskTool.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/ast/engine.js
CHANGED
|
@@ -10,9 +10,13 @@
|
|
|
10
10
|
* wrapped) edit path — instead of fragile whole-file string matching.
|
|
11
11
|
*
|
|
12
12
|
* `typescript` is loaded lazily via dynamic import and kept OUT of the CLI
|
|
13
|
-
* bundle (it's ~7MB, marked external in bundle-cli.mjs).
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* bundle (it's ~7MB, marked external in bundle-cli.mjs).
|
|
14
|
+
*
|
|
15
|
+
* Loud degradation (v0.10.0 "loud tool errors"): `parseFileSymbolsDiag` is
|
|
16
|
+
* the primary entry point and returns a DISCRIMINATED result, so an empty
|
|
17
|
+
* outcome can never be confused with an unavailable backend. The legacy
|
|
18
|
+
* `parseFileSymbols`/`astOutline`/`findSymbol` helpers remain as quiet
|
|
19
|
+
* compatibility wrappers (empty/null on any non-ok status).
|
|
16
20
|
*/
|
|
17
21
|
import { readFile } from 'node:fs/promises';
|
|
18
22
|
import path from 'node:path';
|
|
@@ -31,30 +35,76 @@ function loadTs() {
|
|
|
31
35
|
}
|
|
32
36
|
return tsPromise;
|
|
33
37
|
}
|
|
38
|
+
function errMessage(err) {
|
|
39
|
+
return err instanceof Error ? err.message : String(err);
|
|
40
|
+
}
|
|
34
41
|
/**
|
|
35
42
|
* Parse a TS/JS file into its top-level + nested declarations (with exact
|
|
36
|
-
* source text)
|
|
37
|
-
*
|
|
43
|
+
* source text), reporting WHY on every failure path.
|
|
44
|
+
*
|
|
45
|
+
* Relative paths resolve against `cwd ?? process.cwd()` (same rule as
|
|
46
|
+
* grep_content, see core builtin search.ts). Read errors distinguish ENOENT
|
|
47
|
+
* (`file-not-found`, reports the resolved absolute path) from anything else
|
|
48
|
+
* (`read-error`, propagates the message); a failing `createSourceFile`
|
|
49
|
+
* surfaces as `parse-error`.
|
|
38
50
|
*/
|
|
39
|
-
export async function
|
|
40
|
-
|
|
41
|
-
|
|
51
|
+
export async function parseFileSymbolsDiag(file, cwd) {
|
|
52
|
+
const resolvedPath = path.isAbsolute(file)
|
|
53
|
+
? file
|
|
54
|
+
: path.join(cwd ?? process.cwd(), file);
|
|
55
|
+
const extension = path.extname(resolvedPath).toLowerCase();
|
|
56
|
+
if (!TS_EXTENSIONS.has(extension)) {
|
|
57
|
+
return {
|
|
58
|
+
status: 'unsupported-extension',
|
|
59
|
+
extension: extension || '(none)',
|
|
60
|
+
resolvedPath,
|
|
61
|
+
recoverable: false,
|
|
62
|
+
recommendedFallback: 'read_file',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
42
65
|
const ts = await loadTs();
|
|
43
|
-
if (!ts)
|
|
44
|
-
return
|
|
66
|
+
if (!ts) {
|
|
67
|
+
return {
|
|
68
|
+
status: 'typescript-unavailable',
|
|
69
|
+
resolvedPath,
|
|
70
|
+
recoverable: true,
|
|
71
|
+
recommendedFallback: 'read_file',
|
|
72
|
+
};
|
|
73
|
+
}
|
|
45
74
|
let text;
|
|
46
75
|
try {
|
|
47
|
-
text = await readFile(
|
|
76
|
+
text = await readFile(resolvedPath, 'utf8');
|
|
48
77
|
}
|
|
49
|
-
catch {
|
|
50
|
-
|
|
78
|
+
catch (err) {
|
|
79
|
+
const code = err?.code;
|
|
80
|
+
if (code === 'ENOENT') {
|
|
81
|
+
return {
|
|
82
|
+
status: 'file-not-found',
|
|
83
|
+
resolvedPath,
|
|
84
|
+
recoverable: false,
|
|
85
|
+
recommendedFallback: 'grep_content',
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
status: 'read-error',
|
|
90
|
+
resolvedPath,
|
|
91
|
+
message: errMessage(err),
|
|
92
|
+
recoverable: true,
|
|
93
|
+
recommendedFallback: 'read_file',
|
|
94
|
+
};
|
|
51
95
|
}
|
|
52
96
|
let source;
|
|
53
97
|
try {
|
|
54
|
-
source = ts.createSourceFile(path.basename(
|
|
98
|
+
source = ts.createSourceFile(path.basename(resolvedPath), text, ts.ScriptTarget.Latest, true);
|
|
55
99
|
}
|
|
56
|
-
catch {
|
|
57
|
-
return
|
|
100
|
+
catch (err) {
|
|
101
|
+
return {
|
|
102
|
+
status: 'parse-error',
|
|
103
|
+
resolvedPath,
|
|
104
|
+
message: errMessage(err),
|
|
105
|
+
recoverable: false,
|
|
106
|
+
recommendedFallback: 'read_file',
|
|
107
|
+
};
|
|
58
108
|
}
|
|
59
109
|
const out = [];
|
|
60
110
|
const lineOf = (pos) => source.getLineAndCharacterOfPosition(pos).line + 1;
|
|
@@ -107,20 +157,33 @@ export async function parseFileSymbols(file) {
|
|
|
107
157
|
ts.forEachChild(node, visit);
|
|
108
158
|
};
|
|
109
159
|
visit(source);
|
|
110
|
-
return out;
|
|
160
|
+
return { status: 'ok', symbols: out };
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Compatibility wrapper over {@link parseFileSymbolsDiag}: same quiet
|
|
164
|
+
* contract as before (empty array on any non-ok status). New callers should
|
|
165
|
+
* prefer the diag version.
|
|
166
|
+
*/
|
|
167
|
+
export async function parseFileSymbols(file) {
|
|
168
|
+
const r = await parseFileSymbolsDiag(file);
|
|
169
|
+
return r.status === 'ok' ? r.symbols : [];
|
|
111
170
|
}
|
|
112
|
-
/** Outline: all declarations in a file (no source text). */
|
|
171
|
+
/** Outline: all declarations in a file (no source text). Quiet on failure. */
|
|
113
172
|
export async function astOutline(file) {
|
|
114
|
-
const
|
|
115
|
-
|
|
173
|
+
const r = await parseFileSymbolsDiag(file);
|
|
174
|
+
if (r.status !== 'ok')
|
|
175
|
+
return [];
|
|
176
|
+
return r.symbols.map(({ text: _text, ...rest }) => rest);
|
|
116
177
|
}
|
|
117
178
|
/**
|
|
118
179
|
* Find a named declaration and return its exact source text + range. When
|
|
119
180
|
* several declarations share a name (overloads, a method and a function),
|
|
120
|
-
* returns the first by source order.
|
|
181
|
+
* returns the first by source order. Quiet (null) on any non-ok status.
|
|
121
182
|
*/
|
|
122
183
|
export async function findSymbol(file, name) {
|
|
123
|
-
const
|
|
124
|
-
|
|
184
|
+
const r = await parseFileSymbolsDiag(file);
|
|
185
|
+
if (r.status !== 'ok')
|
|
186
|
+
return null;
|
|
187
|
+
return r.symbols.find((s) => s.name === name) ?? null;
|
|
125
188
|
}
|
|
126
189
|
//# sourceMappingURL=engine.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/cli/ast/engine.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/cli/ast/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S2.1/S2.3 — unit tests for the loud, discriminated parse result of
|
|
3
|
+
* ast/engine (plan: .zelari/docs/piano-loud-tool-errors-ast-diag-readonly-shell.md §2).
|
|
4
|
+
*/
|
|
5
|
+
import { mkdtemp, writeFile } from 'node:fs/promises';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { vi, describe, it, expect } from 'vitest';
|
|
9
|
+
import { parseFileSymbolsDiag, parseFileSymbols, astOutline, findSymbol, } from './engine.js';
|
|
10
|
+
const SAMPLE = [
|
|
11
|
+
'export interface Shape { kind: string }',
|
|
12
|
+
'export class Circle implements Shape {',
|
|
13
|
+
' kind = "circle";',
|
|
14
|
+
' area(): number { return 1; }',
|
|
15
|
+
'}',
|
|
16
|
+
'export const area = (r: number): number => r * r;',
|
|
17
|
+
'const hidden = 1;',
|
|
18
|
+
'',
|
|
19
|
+
].join('\n');
|
|
20
|
+
describe('parseFileSymbolsDiag', () => {
|
|
21
|
+
it('resolves relative paths against the injected cwd and parses symbols', async () => {
|
|
22
|
+
const dir = await mkdtemp(path.join(tmpdir(), 'zelari-ast-'));
|
|
23
|
+
await writeFile(path.join(dir, 'sample.ts'), SAMPLE, 'utf8');
|
|
24
|
+
const r = await parseFileSymbolsDiag('sample.ts', dir);
|
|
25
|
+
expect(r.status).toBe('ok');
|
|
26
|
+
if (r.status !== 'ok')
|
|
27
|
+
return;
|
|
28
|
+
const names = r.symbols.map((s) => s.name);
|
|
29
|
+
expect(names).toContain('Shape');
|
|
30
|
+
expect(names).toContain('Circle');
|
|
31
|
+
expect(names).toContain('area'); // arrow function → kind 'function'
|
|
32
|
+
expect(names).toContain('hidden');
|
|
33
|
+
const circle = r.symbols.find((s) => s.name === 'Circle');
|
|
34
|
+
expect(circle.exported).toBe(true);
|
|
35
|
+
expect(circle.text).toContain('area(): number');
|
|
36
|
+
});
|
|
37
|
+
it('reports file-not-found with the ABSOLUTE resolved path', async () => {
|
|
38
|
+
const dir = await mkdtemp(path.join(tmpdir(), 'zelari-ast-'));
|
|
39
|
+
const r = await parseFileSymbolsDiag('missing.ts', dir);
|
|
40
|
+
expect(r.status).toBe('file-not-found');
|
|
41
|
+
if (r.status !== 'file-not-found')
|
|
42
|
+
return;
|
|
43
|
+
expect(r.resolvedPath).toBe(path.join(dir, 'missing.ts'));
|
|
44
|
+
expect(path.isAbsolute(r.resolvedPath)).toBe(true);
|
|
45
|
+
expect(r.recoverable).toBe(false);
|
|
46
|
+
expect(r.recommendedFallback).toBe('grep_content');
|
|
47
|
+
});
|
|
48
|
+
it('reports unsupported-extension with the extension it saw', async () => {
|
|
49
|
+
const dir = await mkdtemp(path.join(tmpdir(), 'zelari-ast-'));
|
|
50
|
+
await writeFile(path.join(dir, 'script.py'), 'def f(): pass\n', 'utf8');
|
|
51
|
+
const r = await parseFileSymbolsDiag('script.py', dir);
|
|
52
|
+
expect(r.status).toBe('unsupported-extension');
|
|
53
|
+
if (r.status !== 'unsupported-extension')
|
|
54
|
+
return;
|
|
55
|
+
expect(r.extension).toBe('.py');
|
|
56
|
+
expect(r.resolvedPath).toBe(path.join(dir, 'script.py'));
|
|
57
|
+
});
|
|
58
|
+
it('reports typescript-unavailable when the compiler API cannot load', async () => {
|
|
59
|
+
const dir = await mkdtemp(path.join(tmpdir(), 'zelari-ast-'));
|
|
60
|
+
await writeFile(path.join(dir, 'sample.ts'), SAMPLE, 'utf8');
|
|
61
|
+
// Fresh module graph where the dynamic `import('typescript')` rejects.
|
|
62
|
+
vi.resetModules();
|
|
63
|
+
vi.doMock('typescript', () => {
|
|
64
|
+
throw new Error('simulated: typescript not installed');
|
|
65
|
+
});
|
|
66
|
+
try {
|
|
67
|
+
const fresh = await import('./engine.js');
|
|
68
|
+
const r = await fresh.parseFileSymbolsDiag('sample.ts', dir);
|
|
69
|
+
expect(r.status).toBe('typescript-unavailable');
|
|
70
|
+
if (r.status !== 'typescript-unavailable')
|
|
71
|
+
return;
|
|
72
|
+
expect(r.recoverable).toBe(true);
|
|
73
|
+
expect(r.recommendedFallback).toBe('read_file');
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
vi.doUnmock('typescript');
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe('quiet compatibility wrappers', () => {
|
|
81
|
+
it('parseFileSymbols: [] on non-ok, symbols on ok', async () => {
|
|
82
|
+
const dir = await mkdtemp(path.join(tmpdir(), 'zelari-ast-'));
|
|
83
|
+
const file = path.join(dir, 'sample.ts');
|
|
84
|
+
await writeFile(file, SAMPLE, 'utf8');
|
|
85
|
+
// No cwd → resolves against process.cwd(); absolute path keeps it exact.
|
|
86
|
+
expect(await parseFileSymbols(path.join(dir, 'missing.ts'))).toEqual([]);
|
|
87
|
+
expect((await parseFileSymbols(file)).length).toBeGreaterThan(0);
|
|
88
|
+
});
|
|
89
|
+
it('astOutline drops text; findSymbol round-trips exact text', async () => {
|
|
90
|
+
const dir = await mkdtemp(path.join(tmpdir(), 'zelari-ast-'));
|
|
91
|
+
const file = path.join(dir, 'sample.ts');
|
|
92
|
+
await writeFile(file, SAMPLE, 'utf8');
|
|
93
|
+
const outline = await astOutline(file);
|
|
94
|
+
expect(outline.every((s) => !('text' in s))).toBe(true);
|
|
95
|
+
const sym = await findSymbol(file, 'Circle');
|
|
96
|
+
expect(sym?.text.startsWith('export class Circle')).toBe(true);
|
|
97
|
+
expect(await findSymbol(file, 'DoesNotExist')).toBeNull();
|
|
98
|
+
expect(await findSymbol(path.join(dir, 'missing.ts'), 'X')).toBeNull();
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
//# sourceMappingURL=engine.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.test.js","sourceRoot":"","sources":["../../../src/cli/ast/engine.test.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/ast/tools.js
CHANGED
|
@@ -7,34 +7,85 @@
|
|
|
7
7
|
* named declaration's EXACT source span + text, so the agent can target it and
|
|
8
8
|
* edit reliably through the normal edit tools instead of fuzzy string matching.
|
|
9
9
|
*
|
|
10
|
-
* Read-only: neither tool writes.
|
|
11
|
-
*
|
|
10
|
+
* Read-only: neither tool writes.
|
|
11
|
+
*
|
|
12
|
+
* Loud degradation (v0.10.0 "loud tool errors"): every empty outcome carries a
|
|
13
|
+
* discriminated `status` (file-not-found / typescript-unavailable /
|
|
14
|
+
* unsupported-extension / read-error / parse-error) plus machine-readable
|
|
15
|
+
* `resolvedPath` / `recoverable` / `recommendedFallback` fields. `found: false`
|
|
16
|
+
* is only ever reported when the file was read AND parsed successfully.
|
|
12
17
|
*/
|
|
13
18
|
import { z } from 'zod';
|
|
14
19
|
import { typedOk } from '@zelari/core/harness/tools/toolTypes';
|
|
15
|
-
import {
|
|
20
|
+
import { parseFileSymbolsDiag, } from './engine.js';
|
|
16
21
|
/** Cap the returned declaration text so a huge class can't flood the context. */
|
|
17
22
|
const MAX_TEXT_CHARS = 4000;
|
|
18
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Build the loud, machine-readable payload shared by every non-ok status.
|
|
25
|
+
* `recommendedFallback` is a hint for the model — never auto-executed.
|
|
26
|
+
*/
|
|
27
|
+
function degradedPayload(r) {
|
|
28
|
+
return {
|
|
29
|
+
status: r.status,
|
|
30
|
+
resolvedPath: r.resolvedPath,
|
|
31
|
+
recoverable: r.recoverable,
|
|
32
|
+
recommendedFallback: r.recommendedFallback,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Human-facing note for each non-ok status — one cause, no "maybe" lists. */
|
|
36
|
+
function degradedNote(r) {
|
|
37
|
+
switch (r.status) {
|
|
38
|
+
case 'file-not-found':
|
|
39
|
+
return `file not found — looked at ${r.resolvedPath} (relative paths resolve against the workspace root)`;
|
|
40
|
+
case 'typescript-unavailable':
|
|
41
|
+
return 'TypeScript compiler API unavailable — the "typescript" package could not be loaded. ' +
|
|
42
|
+
'AST tools need it; disable them with ZELARI_AST=0 or fall back to read_file/grep_content.';
|
|
43
|
+
case 'unsupported-extension':
|
|
44
|
+
return `unsupported file extension "${r.extension}" — ast_outline/find_symbol only parse TS/JS files (.ts/.tsx/.js/.jsx/.mjs/.cjs)`;
|
|
45
|
+
case 'read-error':
|
|
46
|
+
return `could not read ${r.resolvedPath}: ${r.message}`;
|
|
47
|
+
case 'parse-error':
|
|
48
|
+
return `TypeScript failed to parse ${r.resolvedPath}: ${r.message}`;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Create the AST tools bound to a workspace `root` (S2.0: the root is
|
|
53
|
+
* propagated by the registry, which already has it in scope). At call time
|
|
54
|
+
* relative paths resolve against `ctx.cwd` first (aligned with grep_content),
|
|
55
|
+
* falling back to `root`.
|
|
56
|
+
*/
|
|
57
|
+
export function createAstTools(root) {
|
|
19
58
|
const outline = {
|
|
20
59
|
name: 'ast_outline',
|
|
21
60
|
description: 'Structural outline of a TS/JS file: every declaration (function, class, ' +
|
|
22
61
|
'method, interface, type, enum, variable) with its line range and whether ' +
|
|
23
62
|
"it's exported. Faster and more precise than reading the whole file to find " +
|
|
24
|
-
'where things are.
|
|
63
|
+
'where things are. Relative paths resolve against the working directory. ' +
|
|
64
|
+
'TS/JS only.',
|
|
25
65
|
permissions: ['read'],
|
|
26
66
|
inputSchema: z.object({
|
|
27
67
|
path: z.string().min(1).describe('Path to the TS/JS file to outline.'),
|
|
28
68
|
}),
|
|
29
|
-
execute: async (args) => {
|
|
69
|
+
execute: async (args, ctx) => {
|
|
30
70
|
const { path: file } = args;
|
|
31
|
-
const
|
|
32
|
-
if (
|
|
33
|
-
return typedOk({ symbols: [], note:
|
|
71
|
+
const r = await parseFileSymbolsDiag(file, ctx?.cwd ?? root);
|
|
72
|
+
if (r.status !== 'ok') {
|
|
73
|
+
return typedOk({ symbols: [], note: degradedNote(r), ...degradedPayload(r) });
|
|
74
|
+
}
|
|
75
|
+
if (r.symbols.length === 0) {
|
|
76
|
+
// Genuinely empty file (or only ambient/implicit declarations):
|
|
77
|
+
// the file WAS read and parsed, so this is a true empty — say so.
|
|
78
|
+
return typedOk({
|
|
79
|
+
status: 'ok',
|
|
80
|
+
count: 0,
|
|
81
|
+
symbols: [],
|
|
82
|
+
note: 'file parsed successfully but contains no declarations',
|
|
83
|
+
});
|
|
34
84
|
}
|
|
35
85
|
return typedOk({
|
|
36
|
-
|
|
37
|
-
|
|
86
|
+
status: 'ok',
|
|
87
|
+
count: r.symbols.length,
|
|
88
|
+
symbols: r.symbols.map((s) => `${s.exported ? 'export ' : ''}${s.kind} ${s.name} (lines ${s.line}-${s.endLine})`),
|
|
38
89
|
});
|
|
39
90
|
},
|
|
40
91
|
};
|
|
@@ -43,21 +94,32 @@ export function createAstTools() {
|
|
|
43
94
|
description: "Locate a named declaration in a TS/JS file and return its EXACT source " +
|
|
44
95
|
'text and line range. Use this to grab a function/class/method verbatim so ' +
|
|
45
96
|
'you can edit_file it reliably (node-accurate) instead of guessing the ' +
|
|
46
|
-
'surrounding text.
|
|
97
|
+
'surrounding text. Relative paths resolve against the working directory. ' +
|
|
98
|
+
'TS/JS only.',
|
|
47
99
|
permissions: ['read'],
|
|
48
100
|
inputSchema: z.object({
|
|
49
101
|
path: z.string().min(1).describe('Path to the TS/JS file.'),
|
|
50
102
|
name: z.string().min(1).describe('The declaration name to find (function/class/method/etc).'),
|
|
51
103
|
}),
|
|
52
|
-
execute: async (args) => {
|
|
104
|
+
execute: async (args, ctx) => {
|
|
53
105
|
const { path: file, name } = args;
|
|
54
|
-
const
|
|
106
|
+
const r = await parseFileSymbolsDiag(file, ctx?.cwd ?? root);
|
|
107
|
+
if (r.status !== 'ok') {
|
|
108
|
+
return typedOk({ found: false, note: degradedNote(r), ...degradedPayload(r) });
|
|
109
|
+
}
|
|
110
|
+
const sym = r.symbols.find((s) => s.name === name);
|
|
55
111
|
if (!sym) {
|
|
56
|
-
|
|
112
|
+
// File was read and parsed: a REAL not-found, safe to state.
|
|
113
|
+
return typedOk({
|
|
114
|
+
found: false,
|
|
115
|
+
status: 'ok',
|
|
116
|
+
note: `no declaration named "${name}" found in ${r.symbols.length > 0 ? `${file} (declarations present: ${[...new Set(r.symbols.map((s) => s.name))].slice(0, 12).join(', ')})` : file}`,
|
|
117
|
+
});
|
|
57
118
|
}
|
|
58
119
|
const truncated = sym.text.length > MAX_TEXT_CHARS;
|
|
59
120
|
return typedOk({
|
|
60
121
|
found: true,
|
|
122
|
+
status: 'ok',
|
|
61
123
|
kind: sym.kind,
|
|
62
124
|
exported: sym.exported,
|
|
63
125
|
line: sym.line,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/cli/ast/tools.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/cli/ast/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S2.0/S2.2/S2.3 — tool-level tests: root propagation, ctx.cwd resolution,
|
|
3
|
+
* loud degraded notes with machine fields, and "found: false only when the
|
|
4
|
+
* file was actually read and parsed".
|
|
5
|
+
*/
|
|
6
|
+
import { mkdtemp, writeFile } from 'node:fs/promises';
|
|
7
|
+
import { tmpdir } from 'node:os';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { describe, it, expect } from 'vitest';
|
|
10
|
+
import { createAstTools } from './tools.js';
|
|
11
|
+
const SAMPLE = [
|
|
12
|
+
'export interface Shape { kind: string }',
|
|
13
|
+
'export class Circle implements Shape {',
|
|
14
|
+
' kind = "circle";',
|
|
15
|
+
' area(): number { return 1; }',
|
|
16
|
+
'}',
|
|
17
|
+
'export const area = (r: number): number => r * r;',
|
|
18
|
+
'',
|
|
19
|
+
].join('\n');
|
|
20
|
+
function fakeCtx(cwd) {
|
|
21
|
+
return {
|
|
22
|
+
signal: new AbortController().signal,
|
|
23
|
+
cwd,
|
|
24
|
+
audit: () => { },
|
|
25
|
+
sessionId: 'ast-tools-test',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
async function run(tool, args, ctx) {
|
|
29
|
+
const r = await tool.execute(args, ctx);
|
|
30
|
+
if (!r.ok)
|
|
31
|
+
throw new Error(r.error);
|
|
32
|
+
return r.value;
|
|
33
|
+
}
|
|
34
|
+
function getTools(root) {
|
|
35
|
+
const tools = createAstTools(root);
|
|
36
|
+
const outline = tools.find((t) => t.name === 'ast_outline');
|
|
37
|
+
const findSym = tools.find((t) => t.name === 'find_symbol');
|
|
38
|
+
return { outline, findSym };
|
|
39
|
+
}
|
|
40
|
+
describe('ast_outline (loud degradation)', () => {
|
|
41
|
+
it('resolves a RELATIVE path against ctx.cwd', async () => {
|
|
42
|
+
const dir = await mkdtemp(path.join(tmpdir(), 'zelari-ast-'));
|
|
43
|
+
await writeFile(path.join(dir, 'sample.ts'), SAMPLE, 'utf8');
|
|
44
|
+
const { outline } = getTools('/nonexistent-root');
|
|
45
|
+
const v = await run(outline, { path: 'sample.ts' }, fakeCtx(dir));
|
|
46
|
+
expect(v.status).toBe('ok');
|
|
47
|
+
expect(v.count).toBeGreaterThan(0);
|
|
48
|
+
const symbols = v.symbols;
|
|
49
|
+
expect(symbols.some((s) => s.includes('export class Circle'))).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
it('falls back to the factory root when ctx has no cwd (S2.0)', async () => {
|
|
52
|
+
const dir = await mkdtemp(path.join(tmpdir(), 'zelari-ast-'));
|
|
53
|
+
await writeFile(path.join(dir, 'sample.ts'), SAMPLE, 'utf8');
|
|
54
|
+
const { outline } = getTools(dir);
|
|
55
|
+
const ctxNoCwd = {
|
|
56
|
+
signal: new AbortController().signal,
|
|
57
|
+
audit: () => { },
|
|
58
|
+
sessionId: 'ast-tools-test',
|
|
59
|
+
};
|
|
60
|
+
const v = await run(outline, { path: 'sample.ts' }, ctxNoCwd);
|
|
61
|
+
expect(v.status).toBe('ok');
|
|
62
|
+
expect(v.count).toBeGreaterThan(0);
|
|
63
|
+
});
|
|
64
|
+
it('file-not-found names the absolute path it looked at', async () => {
|
|
65
|
+
const dir = await mkdtemp(path.join(tmpdir(), 'zelari-ast-'));
|
|
66
|
+
const { outline } = getTools('/nonexistent-root');
|
|
67
|
+
const v = await run(outline, { path: 'missing.ts' }, fakeCtx(dir));
|
|
68
|
+
expect(v.status).toBe('file-not-found');
|
|
69
|
+
expect(v.symbols).toEqual([]);
|
|
70
|
+
expect(v.note).toContain(path.join(dir, 'missing.ts'));
|
|
71
|
+
expect(v.recoverable).toBe(false);
|
|
72
|
+
expect(v.recommendedFallback).toBe('grep_content');
|
|
73
|
+
});
|
|
74
|
+
it('unsupported-extension reports the extension in the note', async () => {
|
|
75
|
+
const dir = await mkdtemp(path.join(tmpdir(), 'zelari-ast-'));
|
|
76
|
+
await writeFile(path.join(dir, 'script.py'), 'def f(): pass\n', 'utf8');
|
|
77
|
+
const { outline } = getTools('/nonexistent-root');
|
|
78
|
+
const v = await run(outline, { path: 'script.py' }, fakeCtx(dir));
|
|
79
|
+
expect(v.status).toBe('unsupported-extension');
|
|
80
|
+
expect(v.note).toContain('.py');
|
|
81
|
+
});
|
|
82
|
+
it('an empty-but-parsed file is a TRUE empty, not a degraded note', async () => {
|
|
83
|
+
const dir = await mkdtemp(path.join(tmpdir(), 'zelari-ast-'));
|
|
84
|
+
await writeFile(path.join(dir, 'empty.ts'), '\n', 'utf8');
|
|
85
|
+
const { outline } = getTools('/nonexistent-root');
|
|
86
|
+
const v = await run(outline, { path: 'empty.ts' }, fakeCtx(dir));
|
|
87
|
+
expect(v.status).toBe('ok');
|
|
88
|
+
expect(v.symbols).toEqual([]);
|
|
89
|
+
expect(v.note).toContain('no declarations');
|
|
90
|
+
// The old conflated three-causes note must be gone.
|
|
91
|
+
expect(String(v.note)).not.toContain('TypeScript unavailable');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe('find_symbol (found:false only after a successful parse)', () => {
|
|
95
|
+
it('degraded file surfaces status, not a fake "no declaration named"', async () => {
|
|
96
|
+
const dir = await mkdtemp(path.join(tmpdir(), 'zelari-ast-'));
|
|
97
|
+
const { findSym } = getTools('/nonexistent-root');
|
|
98
|
+
const v = await run(findSym, { path: 'missing.ts', name: 'Circle' }, fakeCtx(dir));
|
|
99
|
+
expect(v.found).toBe(false);
|
|
100
|
+
expect(v.status).toBe('file-not-found');
|
|
101
|
+
expect(v.note).toContain(path.join(dir, 'missing.ts'));
|
|
102
|
+
});
|
|
103
|
+
it('symbol truly absent from a PARSED file → found:false, status ok, hint of present names', async () => {
|
|
104
|
+
const dir = await mkdtemp(path.join(tmpdir(), 'zelari-ast-'));
|
|
105
|
+
await writeFile(path.join(dir, 'sample.ts'), SAMPLE, 'utf8');
|
|
106
|
+
const { findSym } = getTools('/nonexistent-root');
|
|
107
|
+
const v = await run(findSym, { path: 'sample.ts', name: 'Sphere' }, fakeCtx(dir));
|
|
108
|
+
expect(v.found).toBe(false);
|
|
109
|
+
expect(v.status).toBe('ok');
|
|
110
|
+
expect(v.note).toContain('Sphere');
|
|
111
|
+
expect(v.note).toContain('Circle');
|
|
112
|
+
});
|
|
113
|
+
it('returns the exact declaration text for editing', async () => {
|
|
114
|
+
const dir = await mkdtemp(path.join(tmpdir(), 'zelari-ast-'));
|
|
115
|
+
await writeFile(path.join(dir, 'sample.ts'), SAMPLE, 'utf8');
|
|
116
|
+
const { findSym } = getTools('/nonexistent-root');
|
|
117
|
+
const v = await run(findSym, { path: 'sample.ts', name: 'Circle' }, fakeCtx(dir));
|
|
118
|
+
expect(v.found).toBe(true);
|
|
119
|
+
expect(v.kind).toBe('class');
|
|
120
|
+
expect(v.exported).toBe(true);
|
|
121
|
+
expect(String(v.text).startsWith('export class Circle')).toBe(true);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
//# sourceMappingURL=tools.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.test.js","sourceRoot":"","sources":["../../../src/cli/ast/tools.test.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/headless.js
CHANGED
|
@@ -27,6 +27,7 @@ object per line) or as plain text (just the assistant message text).
|
|
|
27
27
|
|
|
28
28
|
Options:
|
|
29
29
|
--task <text> Task prompt (required)
|
|
30
|
+
--task-file <path> Same as --task but read from a file (avoids Windows argv cap)
|
|
30
31
|
--output json|plain Output format (default: json)
|
|
31
32
|
--mode kraken|council|zelari Dispatch mode (default: kraken; agent=alias)
|
|
32
33
|
--council Alias for --mode council
|
|
@@ -38,6 +39,7 @@ Options:
|
|
|
38
39
|
--once Trigger mode: single cycle + lockfile (for cron/git hooks)
|
|
39
40
|
--kraken-graph <goal> Plan + execute a Kraken task graph instead of --task
|
|
40
41
|
(mutually exclusive with --task; ZELARI_KRAKEN_GRAPH=0 disables)
|
|
42
|
+
--kraken-graph-file <path> Same as --kraken-graph but read from a file
|
|
41
43
|
|
|
42
44
|
Exit codes:
|
|
43
45
|
0 completed
|
|
@@ -91,6 +93,25 @@ export function parseHeadlessFlags(argv) {
|
|
|
91
93
|
task = argv[i + 1];
|
|
92
94
|
i++;
|
|
93
95
|
}
|
|
96
|
+
else if (arg === '--task-file') {
|
|
97
|
+
// File-backed variant of --task: the desktop spills long prompts to
|
|
98
|
+
// a temp file because Windows CreateProcess caps the command line at
|
|
99
|
+
// ~32KB (os error 206) and a long first message overflows it.
|
|
100
|
+
// Unreadable/empty file leaves `task` undefined so the validation
|
|
101
|
+
// below reports "requires --task" instead of a silent empty run.
|
|
102
|
+
const next = argv[i + 1];
|
|
103
|
+
if (next) {
|
|
104
|
+
try {
|
|
105
|
+
const fromFile = readFileSync(next, 'utf-8');
|
|
106
|
+
if (fromFile.trim())
|
|
107
|
+
task = fromFile;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Missing/unreadable — validation below handles it.
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
i++;
|
|
114
|
+
}
|
|
94
115
|
else if (arg === '--council') {
|
|
95
116
|
councilFlag = true;
|
|
96
117
|
}
|
|
@@ -222,6 +243,22 @@ export function parseHeadlessFlags(argv) {
|
|
|
222
243
|
krakenGraph = argv[i + 1];
|
|
223
244
|
i++;
|
|
224
245
|
}
|
|
246
|
+
else if (arg === '--kraken-graph-file') {
|
|
247
|
+
// File-backed variant of --kraken-graph (same Windows argv cap as
|
|
248
|
+
// --task-file). Last flag wins, mirroring --task/--task-file.
|
|
249
|
+
const next = argv[i + 1];
|
|
250
|
+
if (next) {
|
|
251
|
+
try {
|
|
252
|
+
const fromFile = readFileSync(next, 'utf-8');
|
|
253
|
+
if (fromFile.trim())
|
|
254
|
+
krakenGraph = fromFile;
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
// Missing/unreadable — leave as-is.
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
i++;
|
|
261
|
+
}
|
|
225
262
|
else if (arg === '--plan-only') {
|
|
226
263
|
planOnly = true;
|
|
227
264
|
}
|