@element47/ag 4.5.4 → 4.5.6
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 +59 -11
- package/dist/cli/parser.d.ts.map +1 -1
- package/dist/cli/parser.js +8 -5
- package/dist/cli/parser.js.map +1 -1
- package/dist/cli/repl.d.ts.map +1 -1
- package/dist/cli/repl.js +137 -72
- package/dist/cli/repl.js.map +1 -1
- package/dist/core/__tests__/agent-units.test.d.ts +2 -0
- package/dist/core/__tests__/agent-units.test.d.ts.map +1 -0
- package/dist/core/__tests__/agent-units.test.js +144 -0
- package/dist/core/__tests__/agent-units.test.js.map +1 -0
- package/dist/core/__tests__/context.test.js +24 -0
- package/dist/core/__tests__/context.test.js.map +1 -1
- package/dist/core/__tests__/events.test.js +1 -1
- package/dist/core/__tests__/events.test.js.map +1 -1
- package/dist/core/__tests__/streaming.test.js +2 -1
- package/dist/core/__tests__/streaming.test.js.map +1 -1
- package/dist/core/agent.d.ts +16 -8
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +139 -406
- package/dist/core/agent.js.map +1 -1
- package/dist/core/compaction.d.ts +27 -0
- package/dist/core/compaction.d.ts.map +1 -0
- package/dist/core/compaction.js +102 -0
- package/dist/core/compaction.js.map +1 -0
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js +6 -2
- package/dist/core/context.js.map +1 -1
- package/dist/core/events.d.ts.map +1 -1
- package/dist/core/events.js +6 -1
- package/dist/core/events.js.map +1 -1
- package/dist/core/prompt.d.ts +23 -0
- package/dist/core/prompt.d.ts.map +1 -0
- package/dist/core/prompt.js +122 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/types.d.ts +5 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/utils.d.ts +11 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/core/utils.js +82 -0
- package/dist/core/utils.js.map +1 -0
- package/dist/memory/__tests__/memory.test.js +47 -2
- package/dist/memory/__tests__/memory.test.js.map +1 -1
- package/dist/memory/memory.d.ts +23 -1
- package/dist/memory/memory.d.ts.map +1 -1
- package/dist/memory/memory.js +121 -8
- package/dist/memory/memory.js.map +1 -1
- package/dist/tools/__tests__/task.test.d.ts +2 -0
- package/dist/tools/__tests__/task.test.d.ts.map +1 -0
- package/dist/tools/__tests__/task.test.js +116 -0
- package/dist/tools/__tests__/task.test.js.map +1 -0
- package/dist/tools/agent.d.ts +7 -0
- package/dist/tools/agent.d.ts.map +1 -0
- package/dist/tools/agent.js +92 -0
- package/dist/tools/agent.js.map +1 -0
- package/dist/tools/file.d.ts.map +1 -1
- package/dist/tools/file.js +9 -5
- package/dist/tools/file.js.map +1 -1
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +7 -5
- package/dist/tools/grep.js.map +1 -1
- package/dist/tools/task.d.ts +6 -0
- package/dist/tools/task.d.ts.map +1 -0
- package/dist/tools/task.js +135 -0
- package/dist/tools/task.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,12 +44,34 @@ export OPENROUTER_API_KEY=sk-or-v1-...
|
|
|
44
44
|
-k, --key <key> API key (or set OPENROUTER_API_KEY)
|
|
45
45
|
-s, --system <prompt> Custom system prompt
|
|
46
46
|
-b, --base-url <url> API base URL (default: OpenRouter; use for local LLMs)
|
|
47
|
-
-n, --max-iterations <n> Max tool-call iterations (default:
|
|
47
|
+
-n, --max-iterations <n> Max tool-call iterations (default: 200)
|
|
48
48
|
-y, --yes Auto-approve all tool calls (skip confirmation prompts)
|
|
49
49
|
--stats Show memory file paths and status
|
|
50
50
|
-h, --help Show help
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
+
## Steering
|
|
54
|
+
|
|
55
|
+
Press **Tab** while the agent is working to course-correct without aborting. This opens a `steer>` prompt with full editing support (backspace, arrow keys, paste). Output is buffered while you type.
|
|
56
|
+
|
|
57
|
+
- **Tab** — opens steer prompt, pauses output
|
|
58
|
+
- **Enter** — submits the steer message and resumes. The LLM sees it on the next turn.
|
|
59
|
+
- **Escape** — aborts everything (destructive, same as before)
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
you> build an API with auth
|
|
63
|
+
|
|
64
|
+
⠧ [bash] npm init...
|
|
65
|
+
← press Tab
|
|
66
|
+
steer> use PostgreSQL not SQLite ← type your correction
|
|
67
|
+
← press Enter
|
|
68
|
+
[steered] use PostgreSQL not SQLite
|
|
69
|
+
✓ [bash] done ← buffered output replays
|
|
70
|
+
⠧ thinking [2/200] ← LLM adjusts
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Steer messages are queued and injected before the next LLM call — current tool calls are not interrupted.
|
|
74
|
+
|
|
53
75
|
## REPL Commands
|
|
54
76
|
|
|
55
77
|
All commands follow the pattern: `/noun` to show, `/noun subcommand` to act.
|
|
@@ -92,6 +114,8 @@ All action-based tools follow the pattern: `tool(action, ...params)`.
|
|
|
92
114
|
| `git` | `status`, `init`, `branch`, `commit`, `push` | Git workflow |
|
|
93
115
|
| `grep` | `search`, `find` | Search file contents (regex), find files by glob |
|
|
94
116
|
| `web` | `fetch`, `search` | Fetch web pages, search for current info |
|
|
117
|
+
| `task` | `create`, `list`, `update`, `read`, `remove`, `clear` | Track tasks for multi-step work |
|
|
118
|
+
| `agent` | — | Spawn sub-agents for parallel work |
|
|
95
119
|
| `skill` | — | Activate a skill by name |
|
|
96
120
|
|
|
97
121
|
### Background Processes
|
|
@@ -106,6 +130,22 @@ bash(action="kill", pid=12345) → stop the process
|
|
|
106
130
|
|
|
107
131
|
Background processes are tracked by PID. Output is buffered (100KB rolling). All background processes are killed on exit.
|
|
108
132
|
|
|
133
|
+
### Sub-Agents
|
|
134
|
+
|
|
135
|
+
Spawn independent agents to work on tasks in parallel:
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
agent(prompt="Research auth best practices for Node.js")
|
|
139
|
+
agent(prompt="Set up the database schema", taskId=2)
|
|
140
|
+
agent(prompt="Write unit tests", model="anthropic/claude-haiku")
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Sub-agents get project memory, plan, skills, tools, and extensions but start with a clean context (no conversation history). When linked to a task via `taskId`, the task is auto-marked `in_progress` at start and `done` on completion. Tasks can include a `description` for richer context.
|
|
144
|
+
|
|
145
|
+
Multiple `agent()` calls in the same turn run in parallel. Use `model` to route cheap tasks to faster/cheaper models. Sub-agents run silently — only the parent shows `[agent]` start/result lines.
|
|
146
|
+
|
|
147
|
+
Sub-agents cannot spawn sub-sub-agents (depth limit = 1). Extensions loaded on sub-agents can check `agent.isSilent()` to avoid output.
|
|
148
|
+
|
|
109
149
|
## Custom Tools
|
|
110
150
|
|
|
111
151
|
Drop a `.mjs` file in a tools directory and it gets loaded at startup:
|
|
@@ -319,9 +359,10 @@ Three tiers, all plain markdown you can edit directly:
|
|
|
319
359
|
projects/
|
|
320
360
|
<id>/
|
|
321
361
|
memory.md # project: architecture, decisions
|
|
322
|
-
plans/ # timestamped plan files
|
|
362
|
+
plans/ # timestamped plan files (created on demand)
|
|
323
363
|
2026-04-13T12-31-22-add-auth.md
|
|
324
|
-
|
|
364
|
+
tasks.json # task tracking (created on demand)
|
|
365
|
+
history.jsonl # conversation history (created on demand)
|
|
325
366
|
```
|
|
326
367
|
|
|
327
368
|
All memory is injected into the system prompt on every API call (capped at ~6000 chars total to avoid context bloat). The agent reads it automatically and writes via the `memory` and `plan` tools.
|
|
@@ -455,15 +496,15 @@ Tools execute in parallel when the model returns multiple tool calls.
|
|
|
455
496
|
- A compact project file listing gives the model awareness of project structure.
|
|
456
497
|
- `tool_choice: "auto"` encourages tool use over conversational responses.
|
|
457
498
|
- Dangerous bash commands (`find ~`, `rm -rf /`, etc.) are blocked before execution.
|
|
458
|
-
- Tool results over
|
|
499
|
+
- Tool results over 32KB are smart-truncated (first 100 + last 100 lines) to preserve context.
|
|
459
500
|
- For multi-step coding tasks, the agent creates a plan before starting and updates it as it goes.
|
|
460
501
|
- For simple questions, it just answers directly.
|
|
461
|
-
- At
|
|
502
|
+
- At 200 iterations the REPL asks if you want to continue.
|
|
462
503
|
- At 90% context window usage, ag automatically summarizes older conversation messages to free space. Use `/context compact` to trigger manually. Only message history is compacted — system prompt, tools, and skills are unaffected.
|
|
463
504
|
|
|
464
505
|
## When to use something else
|
|
465
506
|
|
|
466
|
-
- **Claude Code** -- if you have a subscription and want
|
|
507
|
+
- **Claude Code** -- if you have a subscription and want MCP, git worktrees, and a polished IDE integration. ag has sub-agents, tasks, and extensions but is terminal-only.
|
|
467
508
|
- **aider** -- if your workflow is git-centric (commit-per-change, diff-based editing).
|
|
468
509
|
- **Cursor / Windsurf** -- if you want IDE integration. ag is terminal-only.
|
|
469
510
|
|
|
@@ -476,9 +517,14 @@ src/
|
|
|
476
517
|
cli.ts # entry point
|
|
477
518
|
cli/parser.ts # arg parsing + help
|
|
478
519
|
cli/repl.ts # interactive REPL (unified /noun commands)
|
|
479
|
-
core/agent.ts #
|
|
520
|
+
core/agent.ts # agent class, chat loop, tool execution, steering
|
|
521
|
+
core/utils.ts # spinner, retry, truncation, promise helpers
|
|
522
|
+
core/prompt.ts # environment detection, read-only rules, request building
|
|
523
|
+
core/compaction.ts # context compaction (summarize old messages)
|
|
480
524
|
core/config.ts # persistent config (~/.ag/config.json)
|
|
481
525
|
core/context.ts # context window usage tracking
|
|
526
|
+
core/events.ts # event system for extensions (8 lifecycle events)
|
|
527
|
+
core/extensions.ts # extension discovery and loading
|
|
482
528
|
core/skills.ts # skill discovery, parsing, loading
|
|
483
529
|
core/registry.ts # skills.sh search + GitHub install
|
|
484
530
|
core/types.ts # interfaces
|
|
@@ -488,13 +534,15 @@ src/
|
|
|
488
534
|
core/guardrails.ts # prompt injection scanning (5 threat categories)
|
|
489
535
|
core/loader.ts # custom tool loader (~/.ag/tools/, .ag/tools/)
|
|
490
536
|
core/permissions.ts # permission manager with glob pattern matching
|
|
491
|
-
memory/memory.ts #
|
|
537
|
+
memory/memory.ts # memory, plans, tasks, history
|
|
538
|
+
tools/agent.ts # sub-agent spawning (in-process, parallel)
|
|
539
|
+
tools/bash.ts # shell execution + background processes
|
|
492
540
|
tools/file.ts # file reading + directory listing
|
|
493
|
-
tools/bash.ts # shell execution (with command safeguards)
|
|
494
|
-
tools/memory.ts # memory tool
|
|
495
|
-
tools/plan.ts # plan management tool
|
|
496
541
|
tools/git.ts # git operations tool
|
|
497
542
|
tools/grep.ts # code search + file find
|
|
543
|
+
tools/memory.ts # memory tool
|
|
544
|
+
tools/plan.ts # plan management tool
|
|
545
|
+
tools/task.ts # task tracking tool
|
|
498
546
|
tools/web.ts # web fetch + search tool
|
|
499
547
|
tools/skill.ts # skill activation tool
|
|
500
548
|
```
|
package/dist/cli/parser.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/cli/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,GAAG;IAAE,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/cli/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,GAAG;IAAE,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CAqB/E;AAED,wBAAgB,QAAQ,IAAI,IAAI,CAkC/B"}
|
package/dist/cli/parser.js
CHANGED
|
@@ -11,8 +11,11 @@ export function parseArgs(args) {
|
|
|
11
11
|
options.system = args[++i];
|
|
12
12
|
else if ((arg === '--base-url' || arg === '-b') && i + 1 < args.length)
|
|
13
13
|
options.baseURL = args[++i];
|
|
14
|
-
else if ((arg === '--max-iterations' || arg === '-n') && i + 1 < args.length)
|
|
15
|
-
|
|
14
|
+
else if ((arg === '--max-iterations' || arg === '-n') && i + 1 < args.length) {
|
|
15
|
+
const n = parseInt(args[++i], 10);
|
|
16
|
+
if (!isNaN(n) && n > 0)
|
|
17
|
+
options.maxIterations = n;
|
|
18
|
+
}
|
|
16
19
|
else if (arg === '--stats')
|
|
17
20
|
options.stats = true;
|
|
18
21
|
else if (arg === '--yes' || arg === '-y')
|
|
@@ -39,7 +42,7 @@ Options:
|
|
|
39
42
|
-k, --key <key> API key (or set OPENROUTER_API_KEY)
|
|
40
43
|
-s, --system <prompt> Custom system prompt
|
|
41
44
|
-b, --base-url <url> API base URL (default: OpenRouter; use for local LLMs)
|
|
42
|
-
-n, --max-iterations <n> Max tool-call iterations (default:
|
|
45
|
+
-n, --max-iterations <n> Max tool-call iterations (default: 200)
|
|
43
46
|
-y, --yes Auto-approve all tool calls (skip confirmation prompts)
|
|
44
47
|
--stats Show memory file locations and status
|
|
45
48
|
-h, --help Show this help
|
|
@@ -55,8 +58,8 @@ REPL commands:
|
|
|
55
58
|
/exit Exit
|
|
56
59
|
|
|
57
60
|
Install:
|
|
58
|
-
npx @
|
|
59
|
-
npm install -g @
|
|
61
|
+
npx @element47/ag # Run directly
|
|
62
|
+
npm install -g @element47/ag # Install globally
|
|
60
63
|
`);
|
|
61
64
|
}
|
|
62
65
|
//# sourceMappingURL=parser.js.map
|
package/dist/cli/parser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/cli/parser.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,CAAC,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACrF,IAAI,CAAC,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACtF,IAAI,CAAC,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aAC5F,IAAI,CAAC,GAAG,KAAK,YAAY,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aAC/F,IAAI,CAAC,GAAG,KAAK,kBAAkB,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/cli/parser.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,CAAC,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACrF,IAAI,CAAC,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACtF,IAAI,CAAC,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aAC5F,IAAI,CAAC,GAAG,KAAK,YAAY,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aAC/F,IAAI,CAAC,GAAG,KAAK,kBAAkB,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAC7E,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAClC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;gBAAE,OAAO,CAAC,aAAa,GAAG,CAAC,CAAC;QACpD,CAAC;aACI,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;aAC5C,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,IAAI;YAAE,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;aACxD,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;YAAE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;aAC1D,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCb,CAAC,CAAC;AACH,CAAC"}
|
package/dist/cli/repl.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/cli/repl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,SAAS,EAAsB,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAKzC,OAAO,EAAE,iBAAiB,EAAgB,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,kBAAkB,CAAC;AAqCvE,wBAAgB,qBAAqB,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,eAAe,GAAG;IAAE,YAAY,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;CAAE,CAgBnH;AAED,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,iBAAiB,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,eAAe,GAAG;IAAE,YAAY,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;CAAE,CAiD7I;AA8GD,qBAAa,IAAI;IACf,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAY;IAC/B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAA2B;IAC9C,OAAO,CAAC,SAAS,CAAqD;gBAE1D,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,iBAAiB,EAAE,SAAS,CAAC,EAAE,UAAU,CAAC,OAAO,wBAAwB,CAAC;IAqBnG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/cli/repl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,SAAS,EAAsB,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAKzC,OAAO,EAAE,iBAAiB,EAAgB,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,kBAAkB,CAAC;AAqCvE,wBAAgB,qBAAqB,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,eAAe,GAAG;IAAE,YAAY,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;CAAE,CAgBnH;AAED,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,iBAAiB,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,eAAe,GAAG;IAAE,YAAY,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;CAAE,CAiD7I;AA8GD,qBAAa,IAAI;IACf,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAY;IAC/B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAA2B;IAC9C,OAAO,CAAC,SAAS,CAAqD;gBAE1D,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,iBAAiB,EAAE,SAAS,CAAC,EAAE,UAAU,CAAC,OAAO,wBAAwB,CAAC;IAqBnG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAkRd,aAAa;IAkZ3B,OAAO,CAAC,GAAG;CAGZ"}
|
package/dist/cli/repl.js
CHANGED
|
@@ -305,7 +305,11 @@ export class REPL {
|
|
|
305
305
|
const runAgent = async (message) => {
|
|
306
306
|
const controller = new AbortController();
|
|
307
307
|
let activeSpinnerStop = null;
|
|
308
|
-
// ──
|
|
308
|
+
// ── Steer state ──
|
|
309
|
+
let steerActive = false;
|
|
310
|
+
let steerResolve = null;
|
|
311
|
+
const chunkBuffer = [];
|
|
312
|
+
// ── Keypress handler: Escape to abort, Tab to steer ──
|
|
309
313
|
const onKeypress = (_ch, key) => {
|
|
310
314
|
if (key?.name === 'escape') {
|
|
311
315
|
// 1. Clear whatever spinner is showing
|
|
@@ -318,6 +322,37 @@ export class REPL {
|
|
|
318
322
|
// 3. Signal abort (async propagation begins)
|
|
319
323
|
controller.abort();
|
|
320
324
|
}
|
|
325
|
+
else if (key?.name === 'tab' && !steerActive) {
|
|
326
|
+
// Tab opens steer prompt — pause spinner, buffer output until resolved
|
|
327
|
+
steerActive = true;
|
|
328
|
+
clearSpinner();
|
|
329
|
+
process.stdin.removeListener('keypress', onKeypress);
|
|
330
|
+
this.rl.resume();
|
|
331
|
+
this.rl.question(` ${C.yellow}steer>${C.reset} `, (answer) => {
|
|
332
|
+
this.rl.pause();
|
|
333
|
+
if (answer.trim()) {
|
|
334
|
+
this.agent.queueSteer(answer.trim());
|
|
335
|
+
}
|
|
336
|
+
// Clear the steer prompt line, show acknowledgement
|
|
337
|
+
process.stderr.write('\x1b[A\x1b[2K');
|
|
338
|
+
if (answer.trim()) {
|
|
339
|
+
process.stderr.write(` ${C.yellow}[steered]${C.reset} ${C.dim}${answer.trim()}${C.reset}\n`);
|
|
340
|
+
}
|
|
341
|
+
// Flush buffered chunks
|
|
342
|
+
for (const buffered of chunkBuffer) {
|
|
343
|
+
renderChunk(buffered);
|
|
344
|
+
}
|
|
345
|
+
chunkBuffer.length = 0;
|
|
346
|
+
steerActive = false;
|
|
347
|
+
process.stdin.on('keypress', onKeypress);
|
|
348
|
+
process.stdin.resume();
|
|
349
|
+
// Unblock any waiting permission prompts
|
|
350
|
+
if (steerResolve) {
|
|
351
|
+
steerResolve();
|
|
352
|
+
steerResolve = null;
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
}
|
|
321
356
|
};
|
|
322
357
|
if (process.stdin.isTTY) {
|
|
323
358
|
this.rl.pause(); // Detach readline so only our keypress handler runs
|
|
@@ -342,7 +377,6 @@ export class REPL {
|
|
|
342
377
|
this.agent.setSpinnerControl({
|
|
343
378
|
pause: () => {
|
|
344
379
|
clearSpinner();
|
|
345
|
-
// Flush any in-progress text line so extension output starts on a clean line
|
|
346
380
|
if (hasText) {
|
|
347
381
|
flushLines(true);
|
|
348
382
|
process.stderr.write('\n');
|
|
@@ -351,6 +385,19 @@ export class REPL {
|
|
|
351
385
|
},
|
|
352
386
|
resume: () => { },
|
|
353
387
|
});
|
|
388
|
+
// Wrap permissions to wait for steer to finish
|
|
389
|
+
if (this.confirmCb) {
|
|
390
|
+
const originalCb = this.agent.getConfirmToolCall();
|
|
391
|
+
if (originalCb) {
|
|
392
|
+
this.agent.setConfirmToolCall(async (toolName, args, pk) => {
|
|
393
|
+
// Wait for active steer to resolve before prompting
|
|
394
|
+
while (steerActive) {
|
|
395
|
+
await new Promise(r => { steerResolve = r; });
|
|
396
|
+
}
|
|
397
|
+
return originalCb(toolName, args, pk);
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
354
401
|
const flushLines = (final) => {
|
|
355
402
|
const parts = lineBuf.split('\n');
|
|
356
403
|
lineBuf = final ? '' : (parts.pop() || '');
|
|
@@ -362,78 +409,86 @@ export class REPL {
|
|
|
362
409
|
lineBuf = '';
|
|
363
410
|
}
|
|
364
411
|
};
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
if (
|
|
380
|
-
if (hadTools)
|
|
381
|
-
process.stderr.write('\n');
|
|
382
|
-
process.stderr.write(`${C.bold}agent>${C.reset} `);
|
|
383
|
-
hasText = true;
|
|
384
|
-
}
|
|
385
|
-
lineBuf += (chunk.content || '');
|
|
386
|
-
if (lineBuf.includes('\n'))
|
|
387
|
-
flushLines(false);
|
|
388
|
-
break;
|
|
389
|
-
case 'tool_start': {
|
|
390
|
-
clearSpinner();
|
|
391
|
-
if (hasText) {
|
|
392
|
-
flushLines(true);
|
|
412
|
+
const renderChunk = (chunk) => {
|
|
413
|
+
switch (chunk.type) {
|
|
414
|
+
case 'thinking':
|
|
415
|
+
clearSpinner();
|
|
416
|
+
if (hasText) {
|
|
417
|
+
flushLines(true);
|
|
418
|
+
process.stderr.write('\n');
|
|
419
|
+
hasText = false;
|
|
420
|
+
}
|
|
421
|
+
setSpinner(startSpinner(chunk.content || 'thinking'));
|
|
422
|
+
break;
|
|
423
|
+
case 'text':
|
|
424
|
+
clearSpinner();
|
|
425
|
+
if (!hasText) {
|
|
426
|
+
if (hadTools)
|
|
393
427
|
process.stderr.write('\n');
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const cmdPreview = truncateCommand(chunk.content || '', 60);
|
|
397
|
-
setSpinner(startSpinner(`[${chunk.toolName}] ${cmdPreview}`));
|
|
398
|
-
break;
|
|
428
|
+
process.stderr.write(`${C.bold}agent>${C.reset} `);
|
|
429
|
+
hasText = true;
|
|
399
430
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
process.stderr.write(` ${icon} ${C.dim}[${endLabel}]${C.reset} ${C.dim}${preview}${(chunk.content || '').length > 150 ? '...' : ''}${C.reset}\n`);
|
|
411
|
-
break;
|
|
431
|
+
lineBuf += (chunk.content || '');
|
|
432
|
+
if (lineBuf.includes('\n'))
|
|
433
|
+
flushLines(false);
|
|
434
|
+
break;
|
|
435
|
+
case 'tool_start': {
|
|
436
|
+
clearSpinner();
|
|
437
|
+
if (hasText) {
|
|
438
|
+
flushLines(true);
|
|
439
|
+
process.stderr.write('\n');
|
|
440
|
+
hasText = false;
|
|
412
441
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
flushLines(true);
|
|
417
|
-
process.stderr.write('\n\n');
|
|
418
|
-
}
|
|
419
|
-
else if (!hadTools)
|
|
420
|
-
process.stderr.write(`${C.bold}agent>${C.reset} ${renderMarkdown(chunk.content || '')}\n\n`);
|
|
421
|
-
break;
|
|
422
|
-
case 'max_iterations':
|
|
423
|
-
clearSpinner();
|
|
424
|
-
hitMaxIterations = true;
|
|
425
|
-
break;
|
|
426
|
-
case 'interrupted':
|
|
427
|
-
clearSpinner();
|
|
428
|
-
interrupted = true;
|
|
429
|
-
if (hasText) {
|
|
430
|
-
flushLines(true);
|
|
431
|
-
process.stderr.write('\n');
|
|
432
|
-
}
|
|
433
|
-
const summary = chunk.content || 'stopped';
|
|
434
|
-
process.stderr.write(` ${C.yellow}⚡ Interrupted${C.reset} ${C.dim}(${summary})${C.reset}\n\n`);
|
|
435
|
-
break;
|
|
442
|
+
const cmdPreview = truncateCommand(chunk.content || '', 60);
|
|
443
|
+
setSpinner(startSpinner(`[${chunk.toolName}] ${cmdPreview}`));
|
|
444
|
+
break;
|
|
436
445
|
}
|
|
446
|
+
case 'tool_end': {
|
|
447
|
+
clearSpinner();
|
|
448
|
+
hadTools = true;
|
|
449
|
+
let endLabel = chunk.toolName || '';
|
|
450
|
+
const activeSkills = this.agent.getActiveSkillNames();
|
|
451
|
+
if (endLabel === 'bash' && activeSkills.length > 0) {
|
|
452
|
+
endLabel = `${endLabel} via ${activeSkills[activeSkills.length - 1]}`;
|
|
453
|
+
}
|
|
454
|
+
const icon = chunk.success ? `${C.green}✓` : `${C.red}✗`;
|
|
455
|
+
const preview = (chunk.content || '').slice(0, 150).split('\n')[0];
|
|
456
|
+
process.stderr.write(` ${icon} ${C.dim}[${endLabel}]${C.reset} ${C.dim}${preview}${(chunk.content || '').length > 150 ? '...' : ''}${C.reset}\n`);
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
case 'done':
|
|
460
|
+
clearSpinner();
|
|
461
|
+
if (hasText) {
|
|
462
|
+
flushLines(true);
|
|
463
|
+
process.stderr.write('\n\n');
|
|
464
|
+
}
|
|
465
|
+
else if (!hadTools)
|
|
466
|
+
process.stderr.write(`${C.bold}agent>${C.reset} ${renderMarkdown(chunk.content || '')}\n\n`);
|
|
467
|
+
break;
|
|
468
|
+
case 'max_iterations':
|
|
469
|
+
clearSpinner();
|
|
470
|
+
hitMaxIterations = true;
|
|
471
|
+
break;
|
|
472
|
+
case 'steer':
|
|
473
|
+
break;
|
|
474
|
+
case 'interrupted':
|
|
475
|
+
clearSpinner();
|
|
476
|
+
interrupted = true;
|
|
477
|
+
if (hasText) {
|
|
478
|
+
flushLines(true);
|
|
479
|
+
process.stderr.write('\n');
|
|
480
|
+
}
|
|
481
|
+
process.stderr.write(` ${C.yellow}⚡ Interrupted${C.reset} ${C.dim}(${chunk.content || 'stopped'})${C.reset}\n\n`);
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
try {
|
|
486
|
+
for await (const chunk of this.agent.chatStream(message, controller.signal)) {
|
|
487
|
+
if (steerActive) {
|
|
488
|
+
chunkBuffer.push(chunk);
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
renderChunk(chunk);
|
|
437
492
|
}
|
|
438
493
|
clearSpinner();
|
|
439
494
|
}
|
|
@@ -448,10 +503,14 @@ export class REPL {
|
|
|
448
503
|
}
|
|
449
504
|
}
|
|
450
505
|
finally {
|
|
451
|
-
this.agent.setSpinnerControl(null);
|
|
452
506
|
if (process.stdin.isTTY) {
|
|
453
507
|
process.stdin.removeListener('keypress', onKeypress);
|
|
454
508
|
}
|
|
509
|
+
this.agent.setSpinnerControl(null);
|
|
510
|
+
// Restore original confirm callback if we wrapped it
|
|
511
|
+
if (this.confirmCb) {
|
|
512
|
+
this.agent.setConfirmToolCall(this.confirmCb);
|
|
513
|
+
}
|
|
455
514
|
}
|
|
456
515
|
};
|
|
457
516
|
await runAgent(input);
|
|
@@ -602,6 +661,7 @@ export class REPL {
|
|
|
602
661
|
console.error(` Global: ${stats.globalMemory ? C.green + 'yes' : C.dim + 'none'}${C.reset}`);
|
|
603
662
|
console.error(` Project: ${stats.projectMemory ? C.green + 'yes' : C.dim + 'none'}${C.reset}`);
|
|
604
663
|
console.error(` Plans: ${C.cyan}${stats.planCount}${C.reset}`);
|
|
664
|
+
console.error(` Tasks: ${C.cyan}${stats.taskCount}${C.reset}`);
|
|
605
665
|
console.error(` History: ${C.cyan}${stats.historyLines}${C.reset} messages`);
|
|
606
666
|
if (global)
|
|
607
667
|
console.error(`\n${C.bold}Global:${C.reset}\n${renderMarkdown(global)}`);
|
|
@@ -699,7 +759,12 @@ export class REPL {
|
|
|
699
759
|
}
|
|
700
760
|
let parsed = value;
|
|
701
761
|
if (key === 'maxIterations') {
|
|
702
|
-
|
|
762
|
+
const n = parseInt(value, 10);
|
|
763
|
+
if (isNaN(n) || n <= 0) {
|
|
764
|
+
console.error(`${C.red}Invalid number: ${value}${C.reset}\n`);
|
|
765
|
+
break;
|
|
766
|
+
}
|
|
767
|
+
parsed = n;
|
|
703
768
|
}
|
|
704
769
|
else if (key === 'autoApprove') {
|
|
705
770
|
parsed = ['true', '1', 'yes'].includes(value.toLowerCase());
|