aegiscode 6.1.0 → 6.2.0

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 CHANGED
@@ -9,6 +9,7 @@ an editor — built on the same two shared pieces and no others:
9
9
  | `client/aegis.js` | The thin transport. Holds the API key, speaks HTTP/SSE. No brain logic. |
10
10
  | `mcp/tools.js` | The tool registry — names, JSON schemas, result formatting. |
11
11
  | `desktop/renderer/usage.js` | The token-usage → number mapping, shared with the GUI so the two can never disagree. |
12
+ | `desktop/lib/local/` | The agent-loop engine — persistent-shell exec, read/write/edit/glob/grep, Task subagents. The CLI runs the same loop the GUI does, scoped to the AEGIS class. |
12
13
 
13
14
  Routing, model tiers, memory and billing all stay behind aegiscloud.org.
14
15
 
@@ -53,64 +54,46 @@ echo "q" | aegiscode -p - # prompt on stdin
53
54
  aegiscode -m deepseek/deepseek-v4-flash -p "..." # pin a model
54
55
  ```
55
56
 
56
- In a session, plain text is a prompt. `/help` lists commands:
57
+ In a session, plain text is a prompt. `/help` lists commands, grouped by
58
+ category, the way `aegiscodex-dev` does. The registry is that client's, ported
59
+ command for command — 75 entries across nine categories:
57
60
 
58
- | Command | What it does |
61
+ | Category | Commands |
59
62
  |---|---|
60
- | `/ask <prompt>` | Pooled inference (identical to typing the prompt) |
61
- | `/status` | Key, plan, account, memory state |
62
- | `/models` | The model ids you can pin |
63
- | `/balance` | Token-bank balance and recent spend — tokens beside € |
64
- | `/recall <query>` | Search cloud memory |
65
- | `/remember <text>` | Save a durable note |
66
- | `/memory` `/import` | Review or import memory from other tools |
67
- | `/byok` `/byok-set` `/byok-rm` | Bring-your-own-key status and management (the key is prompted, never echoed) |
68
- | `/model` `/stream` `/theme` `/cost` `/clear` `/help` `/quit` | Session controls |
69
- | `/tool <name> [json]` | Call any registry tool directly |
70
-
71
- Every command above that talks to AEGIS names a tool from `mcp/tools.js`, and
72
- the test suite asserts both directions: no command points at a tool that does
73
- not exist, and no tool is unreachable from the prompt.
74
-
75
- Command names, aliases and categories follow `aegiscodex-dev`'s registry, so the
76
- vocabulary matches the other terminal host: the AEGIS family is spelled
77
- `/aegis-ask`, `/aegis-status`, `/aegis-recall`, `/aegis-remember`, `/aegis-import`
78
- (with `/ask`, `/status`, `/recall`, `/remember` kept as aliases), and the session
79
- and model controls are its `help`/`?`/`h`, `exit`/`quit`, `clear`/`cls`,
80
- `theme`/`t`, `version`/`v` and `model`/`m`. Commands that need a local agent loop
81
- this client deliberately does not have `/login`, `/doctor`, `/permissions`,
82
- `/mcp`, `/skills`, `/hooks`, `/agents`, `/resume` and a few more are listed but
83
- answer honestly with the reason and the nearest working alternative rather than
84
- pretending to work.
85
-
86
- ## What it looks like
63
+ | Session & context | `/clear` `/compact` `/cost` `/exit` `/new` `/recap` `/resume` `/rewind` `/agents` `/status` `/teleport` `/version` `/clone` `/schedule` |
64
+ | Workspace | `/run` `/build` `/cd` `/copy` `/init` `/review` `/prs` |
65
+ | Model & behavior | `/model` `/effort` `/thinking` `/theme` `/vim` `/router` `/confirm` `/yolo` `/permissions` `/hooks` `/skills` `/mcp` |
66
+ | Data | `/context` `/export` `/tokens` |
67
+ | Auth | `/credentials` `/byok` `/byok-set` `/byok-rm` |
68
+ | Support | `/help` `/doctor` `/troubleshooting` `/feedback` `/bug` `/issue` `/onboarding` `/benchmark` `/release-notes` `/billing` `/cloud` |
69
+ | Aegis plugin | `/aegis-ask` `/aegis-status` `/aegis-recall` `/aegis-remember` `/memory` `/aegis-council` `/aegis-multi` `/aegis-print` `/aegis-import` `/tool` |
70
+ | Fun | `/radio` `/waifu` |
71
+
72
+ `/help` shows the live list with hints; aliases are searchable in the `/`
73
+ palette exactly as they are there (`/ask` → `/aegis-ask`, `?` → `/help`,
74
+ `quit` `/exit`, `tok` `/tokens`, …).
75
+
76
+ Every command that talks to AEGIS names a tool from `mcp/tools.js`, and the test
77
+ suite asserts both directions: no command points at a tool that does not exist,
78
+ and no tool is unreachable from the prompt. Everything else is a real local
79
+ handler `/run` detects and drives this project's dev command, `/init` sniffs
80
+ the project and writes `AEGIS.md`, `/export` writes the transcript out,
81
+ `/resume` and `/rewind` read the session store, `/cd` moves the working
82
+ directory, `/doctor` runs diagnostics.
83
+
84
+ The only two commands that answer "not available" are `/login` and `/logout`:
85
+ their whole premise is Claude Code's own auth loop, which this client does not
86
+ participate in — it authenticates with an AEGIS key (or your own provider key
87
+ via `/byok-set`). They say so, and point at the working alternative.
88
+
89
+ ## The chatflow
90
+
91
+ The session is `aegiscodex-dev`'s loop, ported rather than approximated: an
92
+ alternate-screen frame of header rule, transcript viewport, spinner/effort line,
93
+ input line and status line, driven by a raw key stream.
87
94
 
88
95
  ```
89
- ━────────────────────────────────────────────────────────────────────────────━
90
-
91
- ✦ █████▓▓░ ▓▓▓▓▓▓▓▓▓ ✦ ▒▒▒▒▒▒▒▒▒▒▒▒
92
- ✦ ███▓░ ░░ ▓▓▓▓▓▓▓░░░ ▒▒▒▒▒▒▒▒▒▒▒▒▒
93
- ░░░░ ███▓░ ▓▓▓▓░░░░░░ ██▒▒▒▒▒▒▒▒▒▒▒▒▓▓
94
- ░░░░░░░░ ███▓░ ░░░░░░ ██▒▒▒▒▒▒▒▒▒▒▒▒▓
95
- ░░░░░░░░░░░░ ███▓░ ✦ · · ▒▒▒▒▒▒▒▒▒▒▒▒▒▒
96
- ██▓░░ ▓ ░░░░░░░░░░░░
97
- ░▓▓███▓▓░
98
- ▐▛███▜▌
99
- ▝▜█████▛▘
100
- ▘▘ ▝▝
101
-
102
- Welcome to AEGIS Code
103
- v6.1.0 · Cloud brain in your shell.
104
-
105
- ───────────────────────────────── aegiscode ──────────────────────────────────
106
- version v6.1.0
107
- model nexus-brain
108
- base https://aegiscloud.org
109
- key aegis_••••4f2a
110
- render streaming
111
-
112
- type /help for commands · /quit to exit
113
-
96
+ ╭───────────────────────────── AEGIS Code v6.2.0 ─────────────────────────────╮
114
97
  ❯ summarise what changed in the token accounting
115
98
  ● Three things changed, and one of them was costing you money:
116
99
 
@@ -118,16 +101,51 @@ pretending to work.
118
101
  - cache reads and writes are billed, not ignored
119
102
  - a zero-token call no longer refunds its reservation
120
103
 
121
- merge_usage({input_tokens: 1250}, {output_tokens: 312})
122
- => 1562 total
123
-
124
- Use /balance to see tokens beside € on every row.
125
- ⎿ nexus-brain · 1,562 tok · 1,250/312 · €0.0007 · 4.2s · 4 calls
126
-
127
- * Consulting… (2.1s) esc to interrupt
128
- aegis · nexus-brain · 1,562 tok · €0.0007 · stream ctrl+c quit
104
+ Running 1 shell command…
105
+ ⎿ $ git log --oneline -3
106
+ Ran 1 shell command
107
+ Worked for 6s
108
+ ⎿ nexus-brain · 1,562 tok · 1,250/312 · €0.0007 · 4.2s
109
+ ● high · /effort
110
+ ────────────────────────────────────────────────────────────────────────────────
111
+ ❯ Try "edit <filepath> to..."
112
+ ────────────────────────────────────────────────────────────────────────────────
113
+ ⏸ manual mode on · ? for shortcuts · ← for agents
129
114
  ```
130
115
 
116
+ What the loop does, in the order a turn happens:
117
+
118
+ - **You type.** The input line has history (`↑`/`↓`), tab completion for `/…`,
119
+ word motions, a rotating suggestion when empty, horizontal scrolling for a
120
+ long line, and a collapsed one-line preview for a multi-line paste (the full
121
+ text is still what gets submitted).
122
+ - **The turn starts.** A random verb from the reference set shimmers in coral
123
+ beside the spinner, with elapsed time and a live token estimate.
124
+ - **The answer streams into a row**, markdown-rendered, opening with `●` and
125
+ trailing a live cursor while it grows.
126
+ - **Tool calls become rows.** `● Running 1 shell command… · 3s` resolves to
127
+ `Ran 1 shell command` when the call returns — paired by tool-call id, so
128
+ parallel same-name calls and nested subagent rows stay separate, and the
129
+ plural is right.
130
+ - **The turn ends** with `✻ Churned for Ns` (no tools) or `✻ Worked for Ns`
131
+ (tools), then an accounting row: `⎿ nexus-brain · 1,562 tok · 1,250/312 ·
132
+ €0.0007 · 4.2s`.
133
+ - **Esc interrupts.** The abort reaches the transport through an
134
+ `AbortSignal`, so the in-flight provider call is genuinely cancelled — it
135
+ does not keep running and billing behind a "stopped" label — and whatever had
136
+ already streamed is kept, marked `(stopped)`.
137
+ - **Keys work mid-turn.** Esc/Ctrl-C abort; PgUp/PgDn and the wheel scroll the
138
+ transcript live (and scrolling up is anchored to an absolute line index, so an
139
+ arriving delta does not drag the reader back to the bottom); everything else
140
+ you type is replayed into the input line afterwards.
141
+ - **Overlays**: `/` the palette, `alt+p` the model picker, `/effort` the effort
142
+ picker, `/resume` the session list, `?` the shortcut grid, and a centred
143
+ Yes/No dialog when a mutating tool needs approval.
144
+
145
+ Anything that is not a real terminal — a pipe, `-p`, a CI run — stays a linear
146
+ transcript written once to scrollback, so output remains pipeable and
147
+ scriptable.
148
+
131
149
  Render it yourself, with no key and no network:
132
150
 
133
151
  ```bash
@@ -147,31 +165,56 @@ and art row to that source so the two hosts cannot drift apart. (An earlier
147
165
  revision of this CLI was a deliberate divergence — a violet/cyan "Signal" theme
148
166
  with a test asserting it. That direction is gone.)
149
167
 
150
- **A linear transcript, not a full-screen TUI.** Finished turns are written once
151
- to the scrollback; only the one live line (spinner, elapsed time) is redrawn.
152
- Output stays selectable, searchable and pipeable, which matters for a tool you
153
- script.
168
+ **A full-screen chatflow on a terminal, a linear transcript everywhere else.**
169
+ On a TTY the session is the reference's loop: alternate screen, header rule,
170
+ transcript viewport, spinner, effort line, input line, status line, overlays.
171
+ Anywhere else — a pipe, `-p`, CI — turns are written once to the scrollback
172
+ instead, so output stays selectable, searchable and pipeable. A tool you script
173
+ should not become un-scriptable because the interactive mode got nicer.
174
+
175
+ **The command registry is `aegiscodex-dev`'s, ported.** Names, aliases,
176
+ categories, the palette grouping and the handlers themselves come from it, with
177
+ `test/cli-commands.test.mjs` asserting the full name list so a silent drop
178
+ fails the build. Local capability that the reference has — a dev-server runner,
179
+ project sniffing, an export path, a session store, checkpoints, permission
180
+ rules, subagent presets — was ported with it rather than stubbed.
154
181
 
155
182
  **Tokens beside money, always.** A turn prints what it consumed and what it
156
183
  settled at, in the same line: `1,562 tok ∙ 1,250/312 ∙ €0.0007`. Sub-cent
157
184
  amounts keep four decimals, because a €0.0007 call rendered at 2dp reads as
158
185
  free usage next to a token count.
159
186
 
187
+ **Esc really stops the call.** The interrupt travels as an `AbortSignal` into
188
+ the transport, and the engine does not re-dispatch after an abort — a cancelled
189
+ turn used to fire a second billed provider request ("the model said nothing"
190
+ recovery, triggered by the empty result an abort produces) and stream the
191
+ partial answer twice. `test/local-engine.test.mjs` pins the dispatch count.
192
+
160
193
  ## Tests
161
194
 
162
195
  ```bash
163
- node ../../test/cli-conformance.test.mjs # the design guard: palette, glyphs, art, verbs
164
- node ../../test/cli-render.test.mjs # width safety, accounting, live region
165
- node ../../test/cli-overlays.test.mjs # the / palette, model + effort pickers, resume list
166
- node ../../test/cli-fuzzy.test.mjs # palette ranking and match positions
167
- node ../../test/cli-markdown.test.mjs # span-line markdown, cell widths
168
- node ../../test/cli-tools.test.mjs # registry parity with the MCP host + dispatch
169
- node ../../test/cli-run.test.mjs # the real binary against a real backend
170
- node ../../test/cli-package.test.mjs # the published layout, isolated from the repo
196
+ node ../test/cli-chatflow.test.mjs # the session loop, driven with a synthetic key stream
197
+ node ../test/cli-commands.test.mjs # the full command table, aliases, dispatch contract
198
+ node ../test/cli-panels.test.mjs # every panel builder, defensive against missing data
199
+ node ../test/cli-support.test.mjs # config/history/tokens/agents/export/checkpoints
200
+ node ../test/cli-conformance.test.mjs # the design guard: palette, glyphs, art, verbs
201
+ node ../test/cli-render.test.mjs # width safety, accounting, live region
202
+ node ../test/cli-overlays.test.mjs # the / palette, model + effort pickers, resume list
203
+ node ../test/cli-fuzzy.test.mjs # palette ranking and match positions
204
+ node ../test/cli-markdown.test.mjs # span-line markdown, cell widths
205
+ node ../test/cli-tools.test.mjs # registry parity with the MCP host + dispatch
206
+ node ../test/cli-run.test.mjs # the real binary against a real backend
207
+ node ../test/cli-package.test.mjs # the published layout, isolated from the repo
171
208
  npm test # all of the above
172
209
  ```
173
210
 
174
- `npm run predist` stages `client/`, `mcp/tools.js` and the desktop's `usage.js`
175
- into `cli/vendor/` (gitignored) so the published package resolves its own
176
- modules. `test/cli-package.test.mjs` copies that tree somewhere with no repo
177
- around it and runs the binary there.
211
+ The chatflow test drives `runSession` for real: a synthetic key stream, stdout
212
+ captured, and the app entered exactly as `bin/aegiscode.js` enters it. It covers
213
+ the turn lifecycle, tool-row pairing, the interrupt reaching the transport, the
214
+ viewport anchor, the input line's cell maths and an abort that must not
215
+ re-dispatch.
216
+
217
+ `npm run predist` stages `client/`, `mcp/tools.js` and the desktop's `usage.js`,
218
+ `local/engine.js` and `local/agents.js` into `cli/vendor/` (gitignored) so the
219
+ published package resolves its own modules. `test/cli-package.test.mjs` copies
220
+ that tree somewhere with no repo around it and runs the binary there.
package/bin/aegiscode.js CHANGED
@@ -33,11 +33,14 @@ Options:
33
33
  --max-tokens <n> output ceiling hint
34
34
  --light light theme
35
35
  --width <cols> force a render width (useful for piping/logs)
36
+ --yolo skip tool-approval prompts (exec/writeFile/editFile
37
+ run without asking) — same as the in-session /yolo
36
38
  -h, --help this text
37
39
  -v, --version print the version
38
40
 
39
41
  In-session: type /help for commands, /quit to exit, esc/ctrl+c to interrupt a
40
- running call. Plain text is a prompt (identical to /ask).
42
+ running call. Plain text is a prompt (identical to /ask) — a question that
43
+ needs a file read, a shell command, or an edit is handled the same turn.
41
44
  `;
42
45
 
43
46
  function parseArgs(argv) {
@@ -50,6 +53,7 @@ function parseArgs(argv) {
50
53
  maxTokens: undefined,
51
54
  light: false,
52
55
  width: null,
56
+ yolo: false,
53
57
  prompt: null,
54
58
  help: false,
55
59
  version: false,
@@ -102,6 +106,9 @@ function parseArgs(argv) {
102
106
  case '--light':
103
107
  opts.light = true;
104
108
  break;
109
+ case '--yolo':
110
+ opts.yolo = true;
111
+ break;
105
112
  case '--width':
106
113
  opts.width = Number(next());
107
114
  break;
@@ -172,6 +179,7 @@ async function main(argv = process.argv.slice(2)) {
172
179
  maxTokens: opts.maxTokens,
173
180
  width: opts.width ? () => opts.width : undefined,
174
181
  interactive: !prompt && Boolean(process.stdin.isTTY),
182
+ confirmMode: !opts.yolo,
175
183
  });
176
184
 
177
185
  if (prompt) return app.runOnce(prompt, { json: opts.json });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aegiscode",
3
3
  "productName": "AEGIS Code",
4
- "version": "6.1.0",
4
+ "version": "6.2.0",
5
5
  "description": "aegiscode — the command-line version of AEGIS Desktop. The shared tool surface in your shell, over the same thin transport and tool registry as the MCP plugin and the desktop app. Ships transport + UI only; no brain.",
6
6
  "author": {
7
7
  "name": "AEGIS Code",
@@ -31,8 +31,8 @@
31
31
  "start": "node bin/aegiscode.js",
32
32
  "predist": "node scripts/predist.mjs",
33
33
  "prepublishOnly": "npm run predist",
34
- "check": "node --check bin/aegiscode.js && node --check src/theme.js && node --check src/art.js && node --check src/screen.js && node --check src/format.js && node --check src/fuzzy.js && node --check src/markdown.js && node --check src/render.js && node --check src/overlays.js && node --check src/commands.js && node --check src/deps.js && node --check src/app.js && node --check scripts/predist.mjs",
35
- "test": "for f in ../../test/cli-*.test.mjs; do node \"$f\" || exit 1; done"
34
+ "check": "node --check bin/aegiscode.js && for f in src/*.js; do node --check \"$f\" || exit 1; done && node --check scripts/predist.mjs",
35
+ "test": "for f in ../test/cli-*.test.mjs; do node \"$f\" || exit 1; done"
36
36
  },
37
37
  "keywords": [
38
38
  "aegis",
@@ -11,7 +11,8 @@
11
11
  * cli/ repo/
12
12
  * vendor/mcp/tools.js ≡ mcp/tools.js
13
13
  * vendor/client/*.js ≡ client/*.js
14
- * vendor/desktop/... ≡ desktop/renderer/usage.js
14
+ * vendor/desktop/... ≡ desktop/renderer/usage.js,
15
+ * desktop/lib/local/{engine,tools,shell,agents,prompt}.js
15
16
  *
16
17
  * The shape matters: `mcp/tools.js` requires `../client/foreign-memory.js`, and
17
18
  * because the staged tree mirrors the repo, that path resolves *inside* the
@@ -39,6 +40,15 @@ const FILES = [
39
40
  'client/foreign-memory.js',
40
41
  'mcp/tools.js',
41
42
  'desktop/renderer/usage.js',
43
+ // The agent-loop engine (persistent shell, editFile/grep/exec, Task
44
+ // subagents) the desktop app already ships (desktop/lib/local/). The CLI
45
+ // reuses it as-is, scoped to the 'aegis' class only (see src/engine.js) —
46
+ // one tool loop implementation, not a second one drifting alongside it.
47
+ 'desktop/lib/local/engine.js',
48
+ 'desktop/lib/local/tools.js',
49
+ 'desktop/lib/local/shell.js',
50
+ 'desktop/lib/local/agents.js',
51
+ 'desktop/lib/local/prompt.js',
42
52
  ];
43
53
 
44
54
  function main() {
package/src/agents.js ADDED
@@ -0,0 +1,136 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Sub-agent prompt presets — ported verbatim from aegiscodex-dev/src/agents.js
5
+ * (which in turn came from the reference's slash-commands builtinCommands.ts
6
+ * buildMultiAgents() and the research-council member prompts). This build has
7
+ * no parallel-agent runtime, so the presets are prompt composition:
8
+ * /agents <role> <task> and /research <question> build the same specialist
9
+ * prompts the reference hands to real sub-agents and run them through the
10
+ * normal chat flow (c.runPrompt).
11
+ */
12
+
13
+ /** Role → system prompt, verbatim from the reference's buildMultiAgents. */
14
+ const AGENT_PRESETS = {
15
+ synthesizer: `You are a senior technical lead. Given analysis from multiple specialist agents, synthesize their findings into a clear, actionable summary.
16
+ Structure your response as: key findings, recommended approach, top action items.
17
+ Be direct, concrete, and avoid repeating everything the agents said.
18
+ Focus on delivering a decision-ready synthesis.`,
19
+
20
+ architect: `You are a System Architect. Design the new application architecture.
21
+ Define: project structure, tech stack, directory layout, key modules, data flow, API design.
22
+ Consider: scalability, maintainability, testing strategy, deployment.
23
+ Output a concrete file tree and architecture decisions log. Be specific.`,
24
+
25
+ scaffolder: `You are a Project Scaffolder. Build the complete application from scratch.
26
+
27
+ YOUR JOB IS TO CREATE ALL PROJECT FILES - not just describe them.
28
+
29
+ Use Write to create: package.json, tsconfig.json, source files, configs, tests.
30
+ Generate COMPLETE, WORKING code - not stubs or placeholders.
31
+ Set up build scripts, lint config, and any necessary tooling.
32
+
33
+ After creating files, use Bash to run: npm/pnpm install, then build/compile.
34
+ Fix any errors until the project builds successfully.
35
+
36
+ Be thorough - a real, runnable project is the goal.`,
37
+
38
+ planner: `You are a Refactoring Planner. Given the analyzer findings, create a step-by-step plan.
39
+ Each step: file path, what to change, why, risk level (LOW/MEDIUM/HIGH).
40
+ Include before/after snippets. Order by impact. Be concrete.`,
41
+
42
+ implementer: `You are an Implementation Engineer. Execute the refactoring plan.
43
+ Use Edit and Write to make actual code changes.
44
+ After each change, use Read to verify correctness. Keep existing code style.
45
+ Run build commands to ensure nothing is broken.`,
46
+
47
+ reviewer: `You are a Code Reviewer. Review the approach and code.
48
+ Check: logic errors, type safety, error handling, performance, security.
49
+ Be critical but constructive. Report specific issues with file paths.`,
50
+
51
+ debugger: `You are a Debugging Specialist. Analyze potential issues and edge cases.
52
+ Identify: failure modes, error handling gaps, testing considerations.
53
+ Think about what could go wrong and how to prevent it.`,
54
+
55
+ scanner: `You are a Security Vulnerability Scanner.
56
+ Scan for: hardcoded API keys/secrets, SQL injection, XSS, unsafe eval/exec, path traversal.
57
+ Use Grep with targeted patterns. Report every finding with: file path, severity (CRITICAL/HIGH/MEDIUM/LOW), line number.`,
58
+
59
+ analyzer: `You are a Code Analyzer. Find refactoring opportunities.
60
+ Look for: duplicated code, long functions (>20 lines), complex conditionals, unused imports,
61
+ circular dependencies, inconsistent patterns. Report with file paths and line numbers.`,
62
+ };
63
+
64
+ /** Human-readable role label for a preset id (falls back to the id). */
65
+ function agentRoleLabel(role) {
66
+ const labels = {
67
+ synthesizer: 'Technical Lead', architect: 'System Architect',
68
+ scaffolder: 'Project Scaffolder', planner: 'Refactoring Planner',
69
+ implementer: 'Implementation Engineer', reviewer: 'Code Reviewer',
70
+ debugger: 'Debugging Specialist', scanner: 'Vulnerability Scanner',
71
+ analyzer: 'Code Analyzer',
72
+ };
73
+ return labels[role] || role;
74
+ }
75
+
76
+ /** Compose a sub-agent prompt: the role's system prompt + the task. */
77
+ function composeAgentPrompt(role, task) {
78
+ return `${AGENT_PRESETS[role]}\n\nTask: ${task}\n\nRespond directly — no preamble.`;
79
+ }
80
+
81
+ /** Every preset id, in palette order. */
82
+ function agentRoles() {
83
+ return Object.keys(AGENT_PRESETS);
84
+ }
85
+
86
+ /**
87
+ * The research-council prompt (Analyst/Architect/Ethicist/Pragmatist),
88
+ * ported from the reference's /research command. Includes the workspace
89
+ * context note so the model can read real files.
90
+ */
91
+ function composeResearchPrompt(question, workspaceRoot = process.cwd()) {
92
+ return [
93
+ `Research the following question from four perspectives, then synthesize:`,
94
+ ``,
95
+ `Question: ${question}`,
96
+ ``,
97
+ `You are a research council with these members:`,
98
+ `- Analyst: reasons from data, statistics, and empirical evidence; values measurable outcomes.`,
99
+ `- Architect: evaluates designs, tradeoffs, and architectural decisions; focuses on scalability, maintainability, and system coherence.`,
100
+ `- Ethicist: evaluates safety, fairness, privacy, and societal impact; raises concerns others miss.`,
101
+ `- Pragmatist: evaluates practicality, implementation effort, and real-world constraints; balances idealism with what works in production.`,
102
+ ``,
103
+ `Workspace: ${workspaceRoot} — read files with Read, search with Grep, browse with Glob, and check recent git changes with Git to ground your analysis in the real codebase.`,
104
+ ``,
105
+ `Format: one reasoned section per perspective, then a Synthesis with a clear recommendation. Always state VOTE: approve, reject, or abstain and REASONING with clear justification.`,
106
+ ].join('\n');
107
+ }
108
+
109
+ /**
110
+ * A structured debate prompt for the current model (the reference runs a
111
+ * real multi-model DiscussionRoom; this build simulates the debate on the
112
+ * one configured backend, which the note makes explicit).
113
+ */
114
+ function composeDebatePrompt(topic, modelId = '') {
115
+ return [
116
+ `Hold a structured debate on: ${topic}`,
117
+ ``,
118
+ `Present two opposing positions fairly (with the strongest argument FOR and AGAINST), then act as moderator:`,
119
+ `1. Opening statements for each side.`,
120
+ `2. Rebuttals — each side attacks the other's weakest claim.`,
121
+ `3. Cross-examination questions and answers.`,
122
+ `4. Closing statements.`,
123
+ `5. A moderator verdict summarizing where each side won and a final recommendation.`,
124
+ ``,
125
+ `Be rigorous and balanced — steelman both sides before judging.${modelId ? ` (Simulated on ${modelId} — the reference runs a multi-model discussion.)` : ''}`,
126
+ ].join('\n');
127
+ }
128
+
129
+ module.exports = {
130
+ AGENT_PRESETS,
131
+ agentRoleLabel,
132
+ composeAgentPrompt,
133
+ agentRoles,
134
+ composeResearchPrompt,
135
+ composeDebatePrompt,
136
+ };