zelari-code 1.2.0 → 1.4.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/README.md +67 -3
- package/dist/cli/app.js +3 -1
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/ast/engine.js +126 -0
- package/dist/cli/ast/engine.js.map +1 -0
- package/dist/cli/ast/tools.js +71 -0
- package/dist/cli/ast/tools.js.map +1 -0
- package/dist/cli/browser/driver.js +125 -0
- package/dist/cli/browser/driver.js.map +1 -0
- package/dist/cli/browser/tools.js +71 -0
- package/dist/cli/browser/tools.js.map +1 -0
- package/dist/cli/hooks/useSlashDispatch.js +33 -2
- package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
- package/dist/cli/lsp/client.js +89 -0
- package/dist/cli/lsp/client.js.map +1 -0
- package/dist/cli/lsp/manager.js +287 -0
- package/dist/cli/lsp/manager.js.map +1 -0
- package/dist/cli/lsp/protocol.js +83 -0
- package/dist/cli/lsp/protocol.js.map +1 -0
- package/dist/cli/lsp/servers.js +80 -0
- package/dist/cli/lsp/servers.js.map +1 -0
- package/dist/cli/lsp/tools.js +125 -0
- package/dist/cli/lsp/tools.js.map +1 -0
- package/dist/cli/main.bundled.js +1884 -281
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +75 -3
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/mode.js +32 -0
- package/dist/cli/mode.js.map +1 -0
- package/dist/cli/semantic/embeddings.js +71 -0
- package/dist/cli/semantic/embeddings.js.map +1 -0
- package/dist/cli/semantic/index.js +147 -0
- package/dist/cli/semantic/index.js.map +1 -0
- package/dist/cli/semantic/provider.js +29 -0
- package/dist/cli/semantic/provider.js.map +1 -0
- package/dist/cli/semantic/store.js +71 -0
- package/dist/cli/semantic/store.js.map +1 -0
- package/dist/cli/semantic/tools.js +54 -0
- package/dist/cli/semantic/tools.js.map +1 -0
- package/dist/cli/slashCommands.js +22 -1
- package/dist/cli/slashCommands.js.map +1 -1
- package/dist/cli/slashHandlers/semantic.js +37 -0
- package/dist/cli/slashHandlers/semantic.js.map +1 -0
- package/dist/cli/slashHandlers/updater.js +27 -3
- package/dist/cli/slashHandlers/updater.js.map +1 -1
- package/dist/cli/toolRegistry.js +50 -0
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/utils/doctor.js +23 -0
- package/dist/cli/utils/doctor.js.map +1 -1
- package/dist/cli/utils/prereqChecks.js +362 -0
- package/dist/cli/utils/prereqChecks.js.map +1 -0
- package/package.json +3 -3
- package/scripts/postinstall.mjs +46 -1
package/README.md
CHANGED
|
@@ -37,6 +37,30 @@
|
|
|
37
37
|
> `src/main/core/`, `src/agents/`, `src/shared/`, `src/types/` paths no longer
|
|
38
38
|
> exist. The published core package is `@zelari/core` (MIT). 9 subpath exports.
|
|
39
39
|
|
|
40
|
+
## Prerequisites
|
|
41
|
+
|
|
42
|
+
| Requirement | Version | Notes |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| **Node.js** | **≥ 20 LTS** | Earlier versions lack stable `fetch`, `AbortController.timeout`, and `node:test`. Works on 20.x and 22.x. |
|
|
45
|
+
| **npm** | **≥ 10** | Ships with Node 20 LTS; tested with npm 10 and 11. |
|
|
46
|
+
| **OS** | Linux, macOS, Windows 10/11 | Tested on Pop!_OS 24.04, macOS 15, Windows 11. Windows requires Git Bash (auto-detected). |
|
|
47
|
+
| **Disk** | ~50 MB for the CLI + `@zelari/core` | Models are not bundled — provider APIs are remote. |
|
|
48
|
+
| **Account + API key** | 1 of: xAI Grok, OpenAI-compatible, GLM/Z.AI, MiniMax, DeepSeek | OAuth Grok supported via `/login grok`. |
|
|
49
|
+
|
|
50
|
+
### Optional (for v1.3.0 advanced tools)
|
|
51
|
+
|
|
52
|
+
These are **opt-in** — the CLI runs fine without them. The agent auto-skips a tool if its dependency is missing.
|
|
53
|
+
|
|
54
|
+
| Tool group | Dependency | Used by |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `lsp_*` | Language server on PATH (e.g. `typescript-language-server`, `pyright-langserver`) + Node/Python LSP client libs | `lsp_definition`, `lsp_references`, `lsp_hover`, `lsp_symbols`, `lsp_rename` |
|
|
57
|
+
| `ast_*` | *(none)* | `ast_outline`, `ast_find_symbol` — TypeScript Compiler API, no LSP needed |
|
|
58
|
+
| `semantic_search` | Local embedding model (default `Xenova/all-MiniLM-L6-v2` via `@xenova/transformers`, downloads on first use) | `semantic_search`, `/index` |
|
|
59
|
+
| `browser_check` | Playwright (`npx playwright install chromium` once, ~150 MB) | `browser_check` |
|
|
60
|
+
| diagnostics loop | `eslint` and/or `ruff` on PATH (project-local preferred) | post-edit compile/lint feedback |
|
|
61
|
+
|
|
62
|
+
Disable any tool group: set `ZELARI_LSP=0`, `ZELARI_AST=0`, `ZELARI_SEMANTIC=0`, `ZELARI_BROWSER=0`, `ZELARI_DIAGNOSTICS=0`.
|
|
63
|
+
|
|
40
64
|
## Install
|
|
41
65
|
|
|
42
66
|
```bash
|
|
@@ -44,7 +68,23 @@ npm install -g zelari-code
|
|
|
44
68
|
zelari-code
|
|
45
69
|
```
|
|
46
70
|
|
|
47
|
-
|
|
71
|
+
**Prerequisites:**
|
|
72
|
+
- **Node.js ≥ 20** — required. Without it the agent cannot run `npm`/`tsc`/builds, so zelari-code refuses to boot.
|
|
73
|
+
- **Git** — recommended. Without it, `/diff`, `/undo` and the git sidebar are disabled. Install from <https://git-scm.com>.
|
|
74
|
+
- **Git Bash** (Windows only) — recommended. The agent's `bash` tool needs real POSIX semantics (`ls`, `which`, `$VAR`, `&&`). Ships with Git for Windows.
|
|
75
|
+
|
|
76
|
+
After install, verify your environment:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
zelari-code --doctor # checks shim, bundle, PATH, node/git/bash in the agent shell
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
> **Why `--doctor` matters on Windows:** the agent runs commands through Git
|
|
83
|
+
> Bash, which inherits a different `PATH` than the Node process. Node can be
|
|
84
|
+
> visible to PowerShell yet invisible to Git Bash (typical when Node was
|
|
85
|
+
> installed for "current user" only). `--doctor`'s `node (agent shell)` row
|
|
86
|
+
> catches this; the boot-time preflight (`runPreflight`) blocks the launch
|
|
87
|
+
> with an actionable message instead of letting the agent fail mid-task.
|
|
48
88
|
|
|
49
89
|
### `zelari-code: command not found` (Windows)
|
|
50
90
|
|
|
@@ -64,6 +104,8 @@ source ~/.bashrc
|
|
|
64
104
|
|
|
65
105
|
Verify the fix: `where zelari-code` (CMD) or `which zelari-code` (Bash) should print a path.
|
|
66
106
|
|
|
107
|
+
**Node visible to PowerShell but not to Git Bash?** This is the dual-PATH problem: Node installed for "current user" only reaches the user shell, while Git Bash inherits the system `Path`. Fix: reinstall Node with "Add to PATH for **all users**", or add `C:\Program Files\nodejs\` to the **System** `Path` (not User). Confirm with `zelari-code --doctor` — the `node (agent shell)` row must read OK.
|
|
108
|
+
|
|
67
109
|
## First Run
|
|
68
110
|
|
|
69
111
|
The first time you run `zelari-code` (or whenever your provider config
|
|
@@ -72,7 +114,7 @@ the regular TUI:
|
|
|
72
114
|
|
|
73
115
|
```
|
|
74
116
|
╭─────────────────────────────────────────────────╮
|
|
75
|
-
│ zelari-code
|
|
117
|
+
│ zelari-code v1.3.0 — first-time setup │
|
|
76
118
|
│ 1/welcome 2/provider 3/model 4/apikey 5/...│
|
|
77
119
|
│ │
|
|
78
120
|
│ Welcome! Let's get you coding in under 2 min. │
|
|
@@ -146,8 +188,12 @@ Full reference: **[docs/GUIDA.md](./docs/GUIDA.md#comandi-slash)** (all flags, e
|
|
|
146
188
|
| `/steer <text>`, `/steer --interrupt <text>` | Queue follow-up during a run |
|
|
147
189
|
| `/workspace …` | `.zelari/` artifacts + `AGENTS.MD` |
|
|
148
190
|
| `/update`, `/update --yes` | Check / install CLI updates |
|
|
191
|
+
| `/mode [agent\|council\|zelari]` | Switch dispatch mode (shift+tab fallback) |
|
|
192
|
+
| `/checkpoint [label]` | Snapshot the working tree (rollback target) |
|
|
193
|
+
| `/rollback [id\|latest]` | Restore a checkpoint (revert / restore files atomically) |
|
|
194
|
+
| `/index` | Build / refresh the semantic search index |
|
|
149
195
|
|
|
150
|
-
**TUI:** `shift+tab` cycles **agent** → **council** → **zelari** mode for free-form prompts.
|
|
196
|
+
**TUI:** `shift+tab` cycles **agent** → **council** → **zelari** mode for free-form prompts (with terminal-fallback hardening since v1.3.0). The equivalent command `/mode [agent|council|zelari]` works in any terminal.
|
|
151
197
|
|
|
152
198
|
## Headless Mode
|
|
153
199
|
|
|
@@ -185,6 +231,14 @@ Disable auto-check: `ANATHEMA_DEV=1 zelari-code`
|
|
|
185
231
|
- ⏱️ **Execution timer** — elapsed time of the in-flight turn in the status line (`⏱ 12s`), frozen as `last 34s` when the run completes
|
|
186
232
|
- 🧠 **Provider-agnostic** — OpenAI-compatible APIs (OpenAI, Together, Groq, custom), xAI Grok with OAuth refresh, GLM/Z.AI
|
|
187
233
|
- 🛠️ **Built-in tools** — filesystem (read/write/edit), shell (bash), search (grep), web fetch/search
|
|
234
|
+
- 🧠 **LSP code intelligence** (`lsp_*` tools) — go-to-definition, find references, hover type, document symbols, rename symbol via real language servers (tsserver, pyright, …)
|
|
235
|
+
- 🌲 **AST structural tools** (`ast_*` tools) — symbol outline + find-by-name via the TypeScript compiler API, no language server needed
|
|
236
|
+
- 🔎 **Semantic search** (`semantic_search` + `/index`) — concept-level code search via embeddings, local-first
|
|
237
|
+
- 🌐 **Browser verification** (`browser_check`) — headless browser with click/fill/goto/wait actions, console + network + screenshot capture for visual verification of web work
|
|
238
|
+
- 🔁 **Post-edit diagnostics loop** — after every `edit_file`/`write_file` the harness runs project lint/compile (`eslint`, `ruff`, LSP-pluggable) and surfaces the errors to the model in the same turn (opt out: `ZELARI_DIAGNOSTICS=0`)
|
|
239
|
+
- 💾 **Prompt-cache accounting** — tracks prompt-cache hit rate per provider/model and surfaces it in the status bar (`cache 73%`) so you can see when a session is amortizing its prefix
|
|
240
|
+
- 🧷 **Workspace checkpoints** — `/checkpoint [label]` + `/rollback [id|latest]` use git plumbing to snapshot the working tree (tracked + untracked) and restore it atomically; every zelari-mode mission takes one before starting
|
|
241
|
+
- 🤝 **Sub-agent delegation** (`task` tool) — delegate a focused read-only research sub-task to an isolated sub-agent with its own fresh context, max 12 tool turns, no write/bash/recursion
|
|
188
242
|
- 📚 **23 coding skills** (+ user `SKILL.md` from `.zelari/skills/`, `.claude/skills/`, …)
|
|
189
243
|
- 🔄 **Cross-provider failover** — automatic retry with provider swap on transient errors
|
|
190
244
|
- 📊 **Metrics + skill history** — fire-and-forget logging to `~/.tmp/zelari-code/`
|
|
@@ -232,6 +286,16 @@ zelari-code (CLI, proprietary)
|
|
|
232
286
|
| `ZELARI_MISSION_AUTO=1` | Auto-start Zelari missions (skip the brief confirmation) |
|
|
233
287
|
| `ZELARI_MISSION_MAX_ITER` | Max Zelari mission iterations (default 10) |
|
|
234
288
|
| `ZELARI_MODE_MAX_TOOLS_LUCIFER` | Chairman (Lucifero) tool budget in zelari-mode (default 30) |
|
|
289
|
+
| `ZELARI_DIAGNOSTICS=0` | Disable the post-edit compiler/lint diagnostics loop |
|
|
290
|
+
| `ZELARI_DIAGNOSTICS_TIMEOUT_MS` | Timeout of the diagnostics loop (default 5000) |
|
|
291
|
+
| `ZELARI_AST=0` | Disable AST structural tools (`ast_*`) |
|
|
292
|
+
| `ZELARI_SEMANTIC=0` | Disable semantic search + `/index` |
|
|
293
|
+
| `ZELARI_SEMANTIC_FILE` | Override the embeddings store path |
|
|
294
|
+
| `ZELARI_EMBED_MODEL` | Embedding model id (default `Xenova/all-MiniLM-L6-v2`) |
|
|
295
|
+
| `ZELARI_BROWSER=0` | Disable `browser_check` |
|
|
296
|
+
| `ZELARI_LSP=0` | Disable LSP tools (`lsp_*`) |
|
|
297
|
+
| `ZELARI_CHECKPOINT=0` | Disable automatic workspace checkpoints in zelari-mode |
|
|
298
|
+
| `ZELARI_TOOL_OUTPUT_LINES` | Lines of tool output shown in the TUI (default 8) |
|
|
235
299
|
|
|
236
300
|
See **[docs/GUIDA.md](./docs/GUIDA.md#variabili-dambiente)** for the full list.
|
|
237
301
|
|
package/dist/cli/app.js
CHANGED
|
@@ -28,6 +28,7 @@ import { VERSION } from './main.js';
|
|
|
28
28
|
import { useSession } from './hooks/useSession.js';
|
|
29
29
|
import { useChatTurn } from './hooks/useChatTurn.js';
|
|
30
30
|
import { useSlashDispatch } from './hooks/useSlashDispatch.js';
|
|
31
|
+
import { nextMode } from './mode.js';
|
|
31
32
|
import { useBatchedMessages } from './hooks/useBatchedMessages.js';
|
|
32
33
|
import { useTerminalSize } from './hooks/useTerminalSize.js';
|
|
33
34
|
const MODEL = process.env.OPENAI_MODEL ?? 'grok-4';
|
|
@@ -87,7 +88,7 @@ export function App() {
|
|
|
87
88
|
const { isRawModeSupported } = useStdin();
|
|
88
89
|
useInput((_input, key) => {
|
|
89
90
|
if (key.tab && key.shift) {
|
|
90
|
-
setMode(
|
|
91
|
+
setMode(nextMode);
|
|
91
92
|
}
|
|
92
93
|
}, { isActive: isRawModeSupported === true });
|
|
93
94
|
// v0.7.10: startup model discovery — refresh the /v1/models cache in the
|
|
@@ -155,6 +156,7 @@ export function App() {
|
|
|
155
156
|
dispatchCouncilPrompt: chatTurn.dispatchCouncilPrompt,
|
|
156
157
|
dispatchZelariPrompt: chatTurn.dispatchZelariPrompt,
|
|
157
158
|
mode,
|
|
159
|
+
setMode,
|
|
158
160
|
openPicker: setPicker,
|
|
159
161
|
onNewSession,
|
|
160
162
|
onExit,
|
package/dist/cli/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/cli/app.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/cli/app.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ast/engine — structural (AST) analysis for TS/JS via the TypeScript
|
|
3
|
+
* compiler API.
|
|
4
|
+
*
|
|
5
|
+
* Where LSP gives cross-file navigation, this gives precise *structural*
|
|
6
|
+
* targeting inside a file with zero server setup: an exact outline of every
|
|
7
|
+
* declaration (with line ranges + exported flag) and the ability to pull a
|
|
8
|
+
* named declaration's exact source span. The agent uses that span to make
|
|
9
|
+
* reliable, node-accurate edits through the normal (sandboxed, diagnostics-
|
|
10
|
+
* wrapped) edit path — instead of fragile whole-file string matching.
|
|
11
|
+
*
|
|
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). Everything here is
|
|
14
|
+
* best-effort: if `typescript` can't be loaded, the file can't be read, or it
|
|
15
|
+
* isn't a TS/JS file, the functions return empty/null rather than throwing.
|
|
16
|
+
*/
|
|
17
|
+
import { readFile } from 'node:fs/promises';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
const TS_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']);
|
|
20
|
+
/** True if this file's extension is one the TS compiler API can parse. */
|
|
21
|
+
export function isAstSupported(file) {
|
|
22
|
+
return TS_EXTENSIONS.has(path.extname(file).toLowerCase());
|
|
23
|
+
}
|
|
24
|
+
// Lazy, memoized TypeScript module load. Returns null if unavailable.
|
|
25
|
+
let tsPromise;
|
|
26
|
+
function loadTs() {
|
|
27
|
+
if (!tsPromise) {
|
|
28
|
+
tsPromise = import('typescript')
|
|
29
|
+
.then((m) => (m.default ?? m))
|
|
30
|
+
.catch(() => null);
|
|
31
|
+
}
|
|
32
|
+
return tsPromise;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Parse a TS/JS file into its top-level + nested declarations (with exact
|
|
36
|
+
* source text). Returns [] for unsupported files, read errors, or when the
|
|
37
|
+
* TypeScript compiler API is unavailable.
|
|
38
|
+
*/
|
|
39
|
+
export async function parseFileSymbols(file) {
|
|
40
|
+
if (!isAstSupported(file))
|
|
41
|
+
return [];
|
|
42
|
+
const ts = await loadTs();
|
|
43
|
+
if (!ts)
|
|
44
|
+
return [];
|
|
45
|
+
let text;
|
|
46
|
+
try {
|
|
47
|
+
text = await readFile(file, 'utf8');
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
let source;
|
|
53
|
+
try {
|
|
54
|
+
source = ts.createSourceFile(path.basename(file), text, ts.ScriptTarget.Latest, true);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
const out = [];
|
|
60
|
+
const lineOf = (pos) => source.getLineAndCharacterOfPosition(pos).line + 1;
|
|
61
|
+
const hasExport = (node) => {
|
|
62
|
+
const mods = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
|
|
63
|
+
return !!mods?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
|
|
64
|
+
};
|
|
65
|
+
const record = (name, kind, node, exported) => {
|
|
66
|
+
out.push({
|
|
67
|
+
name,
|
|
68
|
+
kind,
|
|
69
|
+
line: lineOf(node.getStart(source)),
|
|
70
|
+
endLine: lineOf(node.getEnd()),
|
|
71
|
+
exported,
|
|
72
|
+
text: node.getText(source),
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
const visit = (node) => {
|
|
76
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
77
|
+
record(node.name.text, 'function', node, hasExport(node));
|
|
78
|
+
}
|
|
79
|
+
else if (ts.isClassDeclaration(node) && node.name) {
|
|
80
|
+
record(node.name.text, 'class', node, hasExport(node));
|
|
81
|
+
for (const member of node.members) {
|
|
82
|
+
if (ts.isMethodDeclaration(member) && member.name && ts.isIdentifier(member.name)) {
|
|
83
|
+
record(member.name.text, 'method', member, false);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else if (ts.isInterfaceDeclaration(node)) {
|
|
88
|
+
record(node.name.text, 'interface', node, hasExport(node));
|
|
89
|
+
}
|
|
90
|
+
else if (ts.isTypeAliasDeclaration(node)) {
|
|
91
|
+
record(node.name.text, 'type', node, hasExport(node));
|
|
92
|
+
}
|
|
93
|
+
else if (ts.isEnumDeclaration(node)) {
|
|
94
|
+
record(node.name.text, 'enum', node, hasExport(node));
|
|
95
|
+
}
|
|
96
|
+
else if (ts.isVariableStatement(node)) {
|
|
97
|
+
const exported = hasExport(node);
|
|
98
|
+
for (const decl of node.declarationList.declarations) {
|
|
99
|
+
if (!ts.isIdentifier(decl.name))
|
|
100
|
+
continue;
|
|
101
|
+
const init = decl.initializer;
|
|
102
|
+
const isFn = !!init && (ts.isArrowFunction(init) || ts.isFunctionExpression(init));
|
|
103
|
+
// Attribute the whole statement's span so the exact text round-trips.
|
|
104
|
+
record(decl.name.text, isFn ? 'function' : 'variable', node, exported);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
ts.forEachChild(node, visit);
|
|
108
|
+
};
|
|
109
|
+
visit(source);
|
|
110
|
+
return out;
|
|
111
|
+
}
|
|
112
|
+
/** Outline: all declarations in a file (no source text). */
|
|
113
|
+
export async function astOutline(file) {
|
|
114
|
+
const symbols = await parseFileSymbols(file);
|
|
115
|
+
return symbols.map(({ text: _text, ...rest }) => rest);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Find a named declaration and return its exact source text + range. When
|
|
119
|
+
* several declarations share a name (overloads, a method and a function),
|
|
120
|
+
* returns the first by source order.
|
|
121
|
+
*/
|
|
122
|
+
export async function findSymbol(file, name) {
|
|
123
|
+
const symbols = await parseFileSymbols(file);
|
|
124
|
+
return symbols.find((s) => s.name === name) ?? null;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/cli/ast/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ast/tools — structural (AST) navigation tools for TS/JS.
|
|
3
|
+
*
|
|
4
|
+
* `ast_outline` gives a precise declaration outline of a file (functions,
|
|
5
|
+
* classes, methods, interfaces, types, enums, variables) with line ranges and
|
|
6
|
+
* exported flags — offline, no language server needed. `find_symbol` returns a
|
|
7
|
+
* named declaration's EXACT source span + text, so the agent can target it and
|
|
8
|
+
* edit reliably through the normal edit tools instead of fuzzy string matching.
|
|
9
|
+
*
|
|
10
|
+
* Read-only: neither tool writes. Both are best-effort (empty result when
|
|
11
|
+
* TypeScript is unavailable or the file isn't TS/JS).
|
|
12
|
+
*/
|
|
13
|
+
import { z } from 'zod';
|
|
14
|
+
import { typedOk } from '@zelari/core/harness/tools/toolTypes';
|
|
15
|
+
import { astOutline, findSymbol } from './engine.js';
|
|
16
|
+
/** Cap the returned declaration text so a huge class can't flood the context. */
|
|
17
|
+
const MAX_TEXT_CHARS = 4000;
|
|
18
|
+
export function createAstTools() {
|
|
19
|
+
const outline = {
|
|
20
|
+
name: 'ast_outline',
|
|
21
|
+
description: 'Structural outline of a TS/JS file: every declaration (function, class, ' +
|
|
22
|
+
'method, interface, type, enum, variable) with its line range and whether ' +
|
|
23
|
+
"it's exported. Faster and more precise than reading the whole file to find " +
|
|
24
|
+
'where things are. TS/JS only.',
|
|
25
|
+
permissions: ['read'],
|
|
26
|
+
inputSchema: z.object({
|
|
27
|
+
path: z.string().min(1).describe('Path to the TS/JS file to outline.'),
|
|
28
|
+
}),
|
|
29
|
+
execute: async (args) => {
|
|
30
|
+
const { path: file } = args;
|
|
31
|
+
const symbols = await astOutline(file);
|
|
32
|
+
if (symbols.length === 0) {
|
|
33
|
+
return typedOk({ symbols: [], note: 'no declarations found (or not a TS/JS file / TypeScript unavailable)' });
|
|
34
|
+
}
|
|
35
|
+
return typedOk({
|
|
36
|
+
count: symbols.length,
|
|
37
|
+
symbols: symbols.map((s) => `${s.exported ? 'export ' : ''}${s.kind} ${s.name} (lines ${s.line}-${s.endLine})`),
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
const findSymbolTool = {
|
|
42
|
+
name: 'find_symbol',
|
|
43
|
+
description: "Locate a named declaration in a TS/JS file and return its EXACT source " +
|
|
44
|
+
'text and line range. Use this to grab a function/class/method verbatim so ' +
|
|
45
|
+
'you can edit_file it reliably (node-accurate) instead of guessing the ' +
|
|
46
|
+
'surrounding text. TS/JS only.',
|
|
47
|
+
permissions: ['read'],
|
|
48
|
+
inputSchema: z.object({
|
|
49
|
+
path: z.string().min(1).describe('Path to the TS/JS file.'),
|
|
50
|
+
name: z.string().min(1).describe('The declaration name to find (function/class/method/etc).'),
|
|
51
|
+
}),
|
|
52
|
+
execute: async (args) => {
|
|
53
|
+
const { path: file, name } = args;
|
|
54
|
+
const sym = await findSymbol(file, name);
|
|
55
|
+
if (!sym) {
|
|
56
|
+
return typedOk({ found: false, note: `no declaration named "${name}" found in ${file}` });
|
|
57
|
+
}
|
|
58
|
+
const truncated = sym.text.length > MAX_TEXT_CHARS;
|
|
59
|
+
return typedOk({
|
|
60
|
+
found: true,
|
|
61
|
+
kind: sym.kind,
|
|
62
|
+
exported: sym.exported,
|
|
63
|
+
line: sym.line,
|
|
64
|
+
endLine: sym.endLine,
|
|
65
|
+
text: truncated ? `${sym.text.slice(0, MAX_TEXT_CHARS)}\n… (truncated, ${sym.text.length} chars total)` : sym.text,
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
return [outline, findSymbolTool];
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/cli/ast/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* browser/driver — drive a headless browser to verify web changes.
|
|
3
|
+
*
|
|
4
|
+
* The "visual verification loop" for web projects: after the agent edits a UI,
|
|
5
|
+
* it navigates the running app and gets back the signals an LLM can actually
|
|
6
|
+
* act on — console errors, uncaught page exceptions, failed network requests,
|
|
7
|
+
* the final title/URL, whether an expected selector is present, and a saved
|
|
8
|
+
* screenshot path. Far stronger than "the tests pass" for front-end work.
|
|
9
|
+
*
|
|
10
|
+
* Playwright is an OPTIONAL dependency, loaded via dynamic import so it is not
|
|
11
|
+
* a hard requirement of the package. When it (or a browser) isn't available,
|
|
12
|
+
* the tool degrades with a clear message. The loader is injectable, so the
|
|
13
|
+
* driver's orchestration is unit-testable with a fake browser.
|
|
14
|
+
*/
|
|
15
|
+
/** Default loader: dynamic-import playwright, or null if unavailable. */
|
|
16
|
+
export const defaultPlaywrightLoader = async () => {
|
|
17
|
+
try {
|
|
18
|
+
// Indirect specifier so TypeScript doesn't require `playwright` types at
|
|
19
|
+
// build time (it's an OPTIONAL runtime dependency). Resolved from
|
|
20
|
+
// node_modules when installed; throws (→ null) when it isn't.
|
|
21
|
+
const pkg = 'playwright';
|
|
22
|
+
const mod = (await import(pkg));
|
|
23
|
+
if (mod && mod.chromium && typeof mod.chromium.launch === 'function')
|
|
24
|
+
return mod;
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Navigate to a URL (optionally running a sequence of actions) and collect
|
|
33
|
+
* verification signals. Best-effort — never throws; a missing browser or a
|
|
34
|
+
* navigation failure is reported in the result.
|
|
35
|
+
*/
|
|
36
|
+
export async function runBrowserCheck(options, loader = defaultPlaywrightLoader) {
|
|
37
|
+
const consoleErrors = [];
|
|
38
|
+
const pageErrors = [];
|
|
39
|
+
const failedRequests = [];
|
|
40
|
+
const base = { ok: false, consoleErrors, pageErrors, failedRequests };
|
|
41
|
+
const pw = await loader();
|
|
42
|
+
if (!pw) {
|
|
43
|
+
return {
|
|
44
|
+
...base,
|
|
45
|
+
error: 'browser automation unavailable — install Playwright (`npm i -D playwright && npx playwright install chromium`) to enable browser_check',
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const timeout = options.timeoutMs ?? 15_000;
|
|
49
|
+
let browser;
|
|
50
|
+
try {
|
|
51
|
+
browser = await pw.chromium.launch({ headless: true });
|
|
52
|
+
const page = await browser.newPage();
|
|
53
|
+
page.on('console', (msg) => {
|
|
54
|
+
if (msg.type() === 'error')
|
|
55
|
+
consoleErrors.push(msg.text());
|
|
56
|
+
});
|
|
57
|
+
page.on('pageerror', (err) => pageErrors.push(err.message));
|
|
58
|
+
page.on('requestfailed', (req) => {
|
|
59
|
+
const f = req.failure();
|
|
60
|
+
failedRequests.push(`${req.url()}${f ? ` (${f.errorText})` : ''}`);
|
|
61
|
+
});
|
|
62
|
+
await page.goto(options.url, { waitUntil: 'load', timeout });
|
|
63
|
+
for (const action of options.actions ?? []) {
|
|
64
|
+
switch (action.type) {
|
|
65
|
+
case 'click':
|
|
66
|
+
await page.click(action.selector, { timeout });
|
|
67
|
+
break;
|
|
68
|
+
case 'fill':
|
|
69
|
+
await page.fill(action.selector, action.value, { timeout });
|
|
70
|
+
break;
|
|
71
|
+
case 'goto':
|
|
72
|
+
await page.goto(action.url, { waitUntil: 'load', timeout });
|
|
73
|
+
break;
|
|
74
|
+
case 'wait':
|
|
75
|
+
await page.waitForTimeout(action.ms);
|
|
76
|
+
break;
|
|
77
|
+
default:
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
let selectorFound;
|
|
82
|
+
if (options.waitForSelector) {
|
|
83
|
+
try {
|
|
84
|
+
await page.waitForSelector(options.waitForSelector, { timeout });
|
|
85
|
+
selectorFound = true;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
selectorFound = false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
let screenshotPath;
|
|
92
|
+
if (options.screenshotPath) {
|
|
93
|
+
try {
|
|
94
|
+
await page.screenshot({ path: options.screenshotPath });
|
|
95
|
+
screenshotPath = options.screenshotPath;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Screenshot is a nice-to-have; ignore failures.
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const title = await page.title().catch(() => undefined);
|
|
102
|
+
return {
|
|
103
|
+
ok: true,
|
|
104
|
+
consoleErrors,
|
|
105
|
+
pageErrors,
|
|
106
|
+
failedRequests,
|
|
107
|
+
url: page.url(),
|
|
108
|
+
...(title !== undefined ? { title } : {}),
|
|
109
|
+
...(selectorFound !== undefined ? { selectorFound } : {}),
|
|
110
|
+
...(screenshotPath ? { screenshotPath } : {}),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
return { ...base, error: err instanceof Error ? err.message : String(err) };
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
try {
|
|
118
|
+
await browser?.close();
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
/* ignore */
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../../../src/cli/browser/driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* browser/tools — the `browser_check` visual-verification tool.
|
|
3
|
+
*
|
|
4
|
+
* Lets the agent confirm a web change actually works in a real browser:
|
|
5
|
+
* navigate the running app, optionally click/fill, and get back console
|
|
6
|
+
* errors, uncaught exceptions, failed requests, the title/URL, whether an
|
|
7
|
+
* expected element appeared, and a screenshot path. Optional Playwright dep —
|
|
8
|
+
* degrades with install instructions when it's not present.
|
|
9
|
+
*/
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import os from 'node:os';
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import { typedOk } from '@zelari/core/harness/tools/toolTypes';
|
|
14
|
+
import { runBrowserCheck } from './driver.js';
|
|
15
|
+
const ActionSchema = z.discriminatedUnion('type', [
|
|
16
|
+
z.object({ type: z.literal('click'), selector: z.string().min(1) }),
|
|
17
|
+
z.object({ type: z.literal('fill'), selector: z.string().min(1), value: z.string() }),
|
|
18
|
+
z.object({ type: z.literal('wait'), ms: z.number().int().positive().max(30_000) }),
|
|
19
|
+
z.object({ type: z.literal('goto'), url: z.string().min(1) }),
|
|
20
|
+
]);
|
|
21
|
+
export function createBrowserTool(deps = {}) {
|
|
22
|
+
return {
|
|
23
|
+
name: 'browser_check',
|
|
24
|
+
description: 'Open a URL in a headless browser to VERIFY a web change: optionally run ' +
|
|
25
|
+
'click/fill/goto/wait actions, then report console errors, uncaught page ' +
|
|
26
|
+
'exceptions, failed network requests, the final title/URL, whether an ' +
|
|
27
|
+
'expected selector appeared, and a screenshot path. Use it to confirm UI ' +
|
|
28
|
+
'edits actually render and run — stronger than "tests pass" for front-end. ' +
|
|
29
|
+
'Requires Playwright (optional dependency).',
|
|
30
|
+
permissions: ['network'],
|
|
31
|
+
// A browser launch + navigation can take a while.
|
|
32
|
+
timeoutMs: 60_000,
|
|
33
|
+
inputSchema: z.object({
|
|
34
|
+
url: z.string().min(1).describe('URL to open (e.g. http://localhost:3000).'),
|
|
35
|
+
actions: z.array(ActionSchema).optional().describe('Optional sequence of interactions before checking.'),
|
|
36
|
+
waitForSelector: z.string().optional().describe('Assert this CSS selector is present after actions.'),
|
|
37
|
+
screenshot: z.boolean().optional().describe('Save a screenshot (default true).'),
|
|
38
|
+
}),
|
|
39
|
+
execute: async (args) => {
|
|
40
|
+
const a = args;
|
|
41
|
+
const dir = deps.screenshotDir ?? os.tmpdir();
|
|
42
|
+
const screenshotPath = a.screenshot === false ? undefined : path.join(dir, `zelari-browser-${Date.now()}.png`);
|
|
43
|
+
const result = await runBrowserCheck({
|
|
44
|
+
url: a.url,
|
|
45
|
+
...(a.actions ? { actions: a.actions } : {}),
|
|
46
|
+
...(a.waitForSelector ? { waitForSelector: a.waitForSelector } : {}),
|
|
47
|
+
...(screenshotPath ? { screenshotPath } : {}),
|
|
48
|
+
}, deps.loader);
|
|
49
|
+
if (!result.ok) {
|
|
50
|
+
return typedOk({ ok: false, note: result.error ?? 'browser check failed' });
|
|
51
|
+
}
|
|
52
|
+
// A clean load with no error signals is the "pass" the agent looks for.
|
|
53
|
+
const clean = result.consoleErrors.length === 0 &&
|
|
54
|
+
result.pageErrors.length === 0 &&
|
|
55
|
+
result.failedRequests.length === 0 &&
|
|
56
|
+
result.selectorFound !== false;
|
|
57
|
+
return typedOk({
|
|
58
|
+
ok: true,
|
|
59
|
+
clean,
|
|
60
|
+
title: result.title,
|
|
61
|
+
url: result.url,
|
|
62
|
+
consoleErrors: result.consoleErrors,
|
|
63
|
+
pageErrors: result.pageErrors,
|
|
64
|
+
failedRequests: result.failedRequests,
|
|
65
|
+
...(result.selectorFound !== undefined ? { selectorFound: result.selectorFound } : {}),
|
|
66
|
+
...(result.screenshotPath ? { screenshotPath: result.screenshotPath } : {}),
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/cli/browser/tools.ts"],"names":[],"mappings":"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"}
|