amicus 4.9.2 → 4.9.4

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.
Files changed (72) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +324 -0
  3. package/README.md +1 -1
  4. package/bin/amicus.js +6 -0
  5. package/docs/ROADMAP.md +5 -4
  6. package/docs/architecture-map.md +732 -0
  7. package/docs/configuration.md +175 -1
  8. package/docs/council.md +9 -0
  9. package/docs/doc-system.md +12 -9
  10. package/docs/testing.md +2 -1
  11. package/docs/troubleshooting.md +76 -0
  12. package/docs/usage.md +14 -6
  13. package/electron/main.js +25 -2
  14. package/electron/setup-ui-alias-groups.js +161 -0
  15. package/electron/setup-ui-alias-script.js +70 -4
  16. package/electron/setup-ui-aliases.js +25 -21
  17. package/electron/setup-ui.js +11 -1
  18. package/package.json +1 -1
  19. package/schemas/model-catalog.schema.json +2 -1
  20. package/schemas/run.schema.json +13 -0
  21. package/skills/sidecar/SKILL.md +1 -8
  22. package/src/cli-handlers-doctor.js +12 -16
  23. package/src/cli-handlers-fanout.js +10 -1
  24. package/src/cli-handlers-resume-continue.js +25 -0
  25. package/src/cli-handlers.js +17 -1
  26. package/src/cli.js +5 -8
  27. package/src/council/briefings-chair.js +4 -2
  28. package/src/council/run-assemble.js +7 -2
  29. package/src/council/run-retry-notes.js +21 -1
  30. package/src/council/run-stages.js +8 -1
  31. package/src/headless.js +125 -7
  32. package/src/mcp-server.js +26 -0
  33. package/src/mcp-tools.js +4 -4
  34. package/src/opencode-client.js +84 -8
  35. package/src/pack/pack-validate.js +3 -0
  36. package/src/session-manager.js +2 -2
  37. package/src/sidecar/continue.js +6 -1
  38. package/src/sidecar/conversation-mirror.js +35 -11
  39. package/src/sidecar/fanout-leg-fallback.js +1 -0
  40. package/src/sidecar/fanout-leg.js +10 -2
  41. package/src/sidecar/fanout.js +2 -2
  42. package/src/sidecar/interactive.js +31 -4
  43. package/src/sidecar/models-ceiling-line.js +72 -0
  44. package/src/sidecar/models.js +4 -2
  45. package/src/sidecar/reopen-notices.js +97 -0
  46. package/src/sidecar/reopen-spend.js +3 -2
  47. package/src/sidecar/resume.js +15 -2
  48. package/src/sidecar/session-finalize.js +4 -1
  49. package/src/sidecar/session-utils.js +5 -1
  50. package/src/sidecar/start-metadata.js +1 -1
  51. package/src/sidecar/start.js +10 -5
  52. package/src/utils/api-key-validation.js +183 -94
  53. package/src/utils/config.js +65 -2
  54. package/src/utils/curated-models.js +8 -8
  55. package/src/utils/degrade.js +7 -0
  56. package/src/utils/doctor-credit-check.js +61 -0
  57. package/src/utils/doctor-key-auth-check.js +271 -0
  58. package/src/utils/doctor-output-budget-check.js +198 -0
  59. package/src/utils/engine-output-flag.js +105 -0
  60. package/src/utils/engine-variants.js +298 -0
  61. package/src/utils/http-get.js +284 -0
  62. package/src/utils/live-probes.js +53 -0
  63. package/src/utils/model-catalog.js +36 -4
  64. package/src/utils/model-ceilings-modelsdev.js +230 -0
  65. package/src/utils/model-fetcher.js +14 -36
  66. package/src/utils/model-output-limit.js +132 -0
  67. package/src/utils/openrouter-credit.js +104 -0
  68. package/src/utils/output-length.js +90 -0
  69. package/src/utils/result-schema.js +7 -2
  70. package/src/utils/spend-ledger.js +5 -1
  71. package/src/utils/thinking-validators.js +27 -80
  72. package/src/utils/validators.js +2 -3
@@ -0,0 +1,732 @@
1
+ # Architecture Map
2
+
3
+ Generated inventory of this repository: the directory tree and the module table.
4
+
5
+ The sections between `<!-- AUTO:... -->` markers are maintained by
6
+ `scripts/generate-docs.js` and regenerated by the pre-commit hook. Do NOT edit
7
+ them by hand -- run `node scripts/generate-docs.js` instead.
8
+
9
+ This file lists **what exists**. For **how it connects** -- which test suites drive
10
+ a source file, what a module reaches -- query the graphify index instead; see
11
+ [Finding Things in This Repo](../CLAUDE.md#finding-things-in-this-repo).
12
+
13
+ ---
14
+
15
+ ## Directory Structure
16
+
17
+ <!-- AUTO:tree -->
18
+ bin/
19
+ └── amicus.js # Amicus CLI Entry Point
20
+ src/
21
+ ├── council/
22
+ │ ├── anonymize.js
23
+ │ ├── briefings-chair-task.js
24
+ │ ├── briefings-chair.js
25
+ │ ├── briefings-debate.js
26
+ │ ├── briefings-stage2-task.js
27
+ │ ├── briefings-stage2.js
28
+ │ ├── briefings-task.js
29
+ │ ├── briefings.js
30
+ │ ├── chair-fallback.js
31
+ │ ├── debate.js
32
+ │ ├── findings.js
33
+ │ ├── ledger-join.js
34
+ │ ├── ledger-stats.js
35
+ │ ├── ledger.js
36
+ │ ├── parse-stage2.js
37
+ │ ├── peer-split.js
38
+ │ ├── presets-cli.js
39
+ │ ├── report-cost.js
40
+ │ ├── report-html.js
41
+ │ ├── report-md.js
42
+ │ ├── report.js
43
+ │ ├── run-assemble.js
44
+ │ ├── run-budget.js
45
+ │ ├── run-chair.js
46
+ │ ├── run-debate-revote.js
47
+ │ ├── run-debate-stage.js
48
+ │ ├── run-debate.js
49
+ │ ├── run-degrade.js
50
+ │ ├── run-finalize.js
51
+ │ ├── run-finish.js
52
+ │ ├── run-launch.js
53
+ │ ├── run-retry-group.js
54
+ │ ├── run-retry-keys.js
55
+ │ ├── run-retry-launch.js
56
+ │ ├── run-retry-notes.js
57
+ │ ├── run-retry-window.js # The Stage-1 retry's no-output window: how long a RELAUNCHED leg may stay
58
+ │ ├── run-retry.js
59
+ │ ├── run-server.js
60
+ │ ├── run-stage1-launch.js # Stage-1 launch pass for the council engine.
61
+ │ ├── run-stage1-rows.js
62
+ │ ├── run-stage1-superseded.js
63
+ │ ├── run-stage2.js
64
+ │ ├── run-stages.js
65
+ │ ├── run-state.js
66
+ │ ├── run-stats-entry.js
67
+ │ ├── run-verdict-files.js
68
+ │ ├── run.js
69
+ │ ├── seats.js
70
+ │ ├── stage1-bind.js
71
+ │ ├── street-cred.js
72
+ │ ├── tally.js
73
+ │ ├── verdict-seat-loss.js
74
+ │ ├── verdict-seats-reviewed.js # #202: the bench-seat census for verdict.json, as a spreadable fragment.
75
+ │ └── verdict.js
76
+ ├── design/
77
+ │ ├── fonts/
78
+ │ │ ├── IBMPlexMono-400.ttf
79
+ │ │ ├── IBMPlexMono-500.ttf
80
+ │ │ ├── IBMPlexMono-600.ttf
81
+ │ │ ├── Outfit-300.ttf
82
+ │ │ ├── Outfit-400.ttf
83
+ │ │ ├── Outfit-500.ttf
84
+ │ │ ├── Outfit-600.ttf
85
+ │ │ ├── Outfit-700.ttf
86
+ │ │ └── Outfit-800.ttf
87
+ │ ├── tokens.css
88
+ │ └── tokens.js
89
+ ├── observe/
90
+ │ ├── council-legs.js
91
+ │ ├── events.js
92
+ │ ├── follow.js
93
+ │ ├── live-doc.js
94
+ │ ├── on-complete.js
95
+ │ └── watch-render.js
96
+ ├── pack/
97
+ │ ├── pack-cli.js
98
+ │ ├── pack-forward.js
99
+ │ ├── pack-resolve.js
100
+ │ ├── pack-store.js
101
+ │ └── pack-validate.js
102
+ ├── prompts/
103
+ │ └── cowork-agent-prompt.js # Cowork Agent Prompt
104
+ ├── sidecar/
105
+ │ ├── budget.js
106
+ │ ├── child-sessions.js
107
+ │ ├── context-builder.js # Context Builder Module
108
+ │ ├── continue.js # Sidecar Continue Operations - Handles continuing from previous sessions
109
+ │ ├── conversation-mirror.js
110
+ │ ├── crash-handler.js # Crash Handler - Updates metadata to 'error' on uncaught exceptions
111
+ │ ├── electron-cache.js # Electron download-cache root resolution (#53 helper).
112
+ │ ├── electron-ensure.js # ensureElectron() — lazy first-GUI provisioning (#55).
113
+ │ ├── electron-install.js # Electron self-heal primitive (#53, #59).
114
+ │ ├── electron-lock.js # Stale-aware single-flight lock for the electron self-heal (#53).
115
+ │ ├── electron-quarantine.js # AV / antivirus quarantine detection for the electron self-heal (#53).
116
+ │ ├── electron-state.js # Electron install-state probes (#76).
117
+ │ ├── fallback-chains.js
118
+ │ ├── fanout-budget.js
119
+ │ ├── fanout-leg-fallback.js
120
+ │ ├── fanout-leg.js
121
+ │ ├── fanout-output.js
122
+ │ ├── fanout-retry.js
123
+ │ ├── fanout-signals.js
124
+ │ ├── fanout-validate.js
125
+ │ ├── fanout-wave-io.js
126
+ │ ├── fanout.js
127
+ │ ├── interactive-abort.js
128
+ │ ├── interactive-mirror.js
129
+ │ ├── interactive-process.js # Sidecar Interactive Process Helpers - Electron probe/env/process-exit plumbing
130
+ │ ├── interactive.js # Sidecar Interactive Mode - Electron GUI session management
131
+ │ ├── leg-ids.js
132
+ │ ├── list-council.js # Council rows on the CLI `amicus list` surface (v4.9 W12).
133
+ │ ├── list-limit.js # The `--limit` core behind `amicus list` (v4.7 PR3 rider).
134
+ │ ├── list-search.js # The `--search` core behind both list surfaces (F8 D15, errata E-PR3-5).
135
+ │ ├── models-ceiling-line.js # The one `Ceilings:` line `amicus models --refresh` prints (#218 P3).
136
+ │ ├── models-probe.js
137
+ │ ├── models-render.js # Presentation helpers for `amicus models` -- pure string formatting, no I/O.
138
+ │ ├── models.js # `amicus models` (F5) — list/search the catalog, refresh it, audit aliases.
139
+ │ ├── progress-fields.js # Derived, agent-facing progress fields shared by the MCP status/list
140
+ │ ├── progress.js # Sidecar Progress Reader
141
+ │ ├── read.js # Sidecar Read Operations Module
142
+ │ ├── reopen-notices.js # The stderr Notice a reopen owes the user for the effort level it does NOT carry (#218 PR 4, council #235 r5 J1/A3).
143
+ │ ├── reopen-spend.js # Spend finalization for a REOPENED session (continue/resume). Split out of
144
+ │ ├── resume.js # Sidecar Resume Operations - Handles resuming previous sidecar sessions
145
+ │ ├── session-finalize.js
146
+ │ ├── session-utils.js # Sidecar Session Utilities - Shared functionality for session management
147
+ │ ├── setup-local.js # The readline setup wizard's local / self-hosted provider add step (v4.2 §4.6, Task 12).
148
+ │ ├── setup-window.js # Setup Window Launcher
149
+ │ ├── setup.js # Sidecar Setup Wizard
150
+ │ ├── start-metadata.js
151
+ │ ├── start.js # Sidecar Start Operations - Handles starting new sidecar sessions
152
+ │ ├── tool-part.js
153
+ │ ├── unzip.js # Robust unzip for the electron self-heal (#53 follow-up; extract-zip-node24).
154
+ │ ├── wave-progress.js
155
+ │ ├── workspace-auto-open.js # Workspace Auto-Open Decision Helper
156
+ │ └── workspace-window.js # Council Workspace launcher (v4.4 §4.3/§4.4) — setup-window.js pattern:
157
+ ├── template/
158
+ │ ├── apply.js
159
+ │ ├── render.js
160
+ │ └── store.js
161
+ ├── utils/
162
+ │ ├── abort-coordinator.js
163
+ │ ├── abort-result.js # The abort-result document builder for `abort <taskId|--all> --json` (B21-rest).
164
+ │ ├── activity-poller.js
165
+ │ ├── agent-mapping.js # Agent Mapping Module
166
+ │ ├── alias-audit.js # Alias Audit (F5) — report + suggest for most classes; doctor --fix auto-repairs one narrow, mechanically-unambiguous class (B3).
167
+ │ ├── alias-resolver.js # Alias Resolver Utilities
168
+ │ ├── alias-shadow-writer.js # The alias-shadow notice's WRITE half: say it without ever sinking the run.
169
+ │ ├── alias-shadow.js # Alias-shadow self-diagnosis — name a local alias that repoints a curated one.
170
+ │ ├── api-key-store.js # API Key Store — reading, saving, and validating API keys.
171
+ │ ├── api-key-validation.js # API Key Validation — test API keys against provider endpoints.
172
+ │ ├── atomic-write.js # Atomic file write helper.
173
+ │ ├── auth-json.js # Auth JSON Reader
174
+ │ ├── base-url-classify.js # v4.6.2 PR1 (spec §4, D1/D2): ANTHROPIC_BASE_URL classification, the
175
+ │ ├── claude-register.js # Registration core for amicus: skill install (chat skill + LLM Council),
176
+ │ ├── cli-preflight.js # Tiny shared preflight guards used by more than one CLI run handler
177
+ │ ├── client-detect.js # Detects which caller (Claude Code vs. Cowork/Claude Desktop) spawned this
178
+ │ ├── config.js # Amicus Config Module
179
+ │ ├── council-presets.js # Built-in council benches (B23).
180
+ │ ├── curated-models.js # Family definitions + pinned fallbacks for the wizard model picker (v2).
181
+ │ ├── degrade.js
182
+ │ ├── doctor-alias-check.js
183
+ │ ├── doctor-base-url-check.js # v4.6.2 PR1 (spec §4): the 'anthropic-base-url' doctor row.
184
+ │ ├── doctor-credit-check.js # The `openrouter-credit` doctor row (#43), split out of
185
+ │ ├── doctor-degrade.js
186
+ │ ├── doctor-electron-mcp-check.js # The `electron-mcp` doctor check ("Electron (MCP launch path)"), split out of
187
+ │ ├── doctor-engine-check.js # The `engine-mcp` doctor check ("OpenCode engine (MCP launch path)"), split out
188
+ │ ├── doctor-key-auth-check.js # The `key-auth` doctor row (issue #210), split out of src/cli-handlers-doctor.js
189
+ │ ├── doctor-local-providers-check.js # The `local-providers` doctor check (v4.2 §4.7 C8), split out of
190
+ │ ├── doctor-mcp-checks.js # B14/Task 4.3: the two MCP-registration doctor checks ('mcp' and
191
+ │ ├── doctor-output-budget-check.js # #218 PR 2: the 'output-budget' doctor row.
192
+ │ ├── doctor-summary.js # Compact doctor summary (v4.2 §4.7 C8). All-ok -> one line; otherwise the
193
+ │ ├── engine-ensure.js # ensureEngine() — runtime engine self-heal at server start (report #2).
194
+ │ ├── engine-install-scan.js # Discover + probe every amicus install that could serve the MCP (running,
195
+ │ ├── engine-lock.js # Stale-aware single-flight lock for the engine self-heal (report #2).
196
+ │ ├── engine-log-parse.js # Line-shape parsing for the engine log: level, session, message.
197
+ │ ├── engine-log-tail.js # One engine-log FILE: read its tail, find the newest usable excerpt in it.
198
+ │ ├── engine-log.js # Resolve the OpenCode engine's own error line for one session.
199
+ │ ├── engine-output-flag.js # #218 PR 2 — the one engine env flag amicus sets: OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX.
200
+ │ ├── engine-repair.js # Engine self-heal primitive (report #2): make the opencode engine present ON
201
+ │ ├── engine-skew-records.js # Server identity and the bounded store of standing engine-skew records.
202
+ │ ├── engine-skew.js # Runtime detection of an opencode ENGINE version skew: server vs installed.
203
+ │ ├── engine-variants.js # The effort lever (#218 PR 4): --thinking sent as the engine's variant field, validated against the engine's own declaration.
204
+ │ ├── env-loader.js # Credential Loader
205
+ │ ├── env-num.js
206
+ │ ├── env-raw-store.js # Arbitrary-env-var writes to the amicus .env (local-provider bearers, v4.2 §4.6).
207
+ │ ├── error-classify.js
208
+ │ ├── error-doc.js
209
+ │ ├── fold-marker.js # Fold marker construction/parsing helpers — shared by prompt-builder.js
210
+ │ ├── format-duration.js
211
+ │ ├── free-models.js # Free OpenRouter model detection (Unit A).
212
+ │ ├── gateway-route-audit.js # Per-gateway-form audit for curated DEFAULT aliases (Task 6, #gwid).
213
+ │ ├── gateway-route-catalog.js # Conservative cross-gateway catalog pairing helper (Task 5, #gwid).
214
+ │ ├── gateway-router.js # Pure gateway router (#61). Decides direct vs OpenRouter for a request using
215
+ │ ├── http-get.js # One HTTPS GET, always resolved, never rejected — the timer/destroy/failure
216
+ │ ├── idle-watchdog.js # IdleWatchdog - BUSY/IDLE state machine with self-terminating timer.
217
+ │ ├── input-validators.js
218
+ │ ├── known-flags.js
219
+ │ ├── legacy-mcp-migration.js
220
+ │ ├── lifecycle.js
221
+ │ ├── live-probes.js # The single gate on outbound AUTHENTICATED network probes made by diagnostics
222
+ │ ├── local-probe.js
223
+ │ ├── local-providers.js
224
+ │ ├── logger.js # Structured Logger Module
225
+ │ ├── mcp-discovery.js # MCP Discovery - Discovers MCP servers from parent LLM configuration
226
+ │ ├── mcp-self-identity.js
227
+ │ ├── mcp-validators.js # MCP Validators
228
+ │ ├── model-canonicalization.js # Direct-first id canonicalization, guarded by `classifyModel`
229
+ │ ├── model-catalog.js # OpenRouter model catalog cache (F3 #18 / F5 foundation).
230
+ │ ├── model-ceilings-modelsdev.js # #218 P3 — output ceilings for the direct-provider catalog rows.
231
+ │ ├── model-classification.js # Tri-state catalog classification (#61).
232
+ │ ├── model-descriptor.js # Model-descriptor grammar + RouteResult factories (#61).
233
+ │ ├── model-fetcher.js # Model Fetcher
234
+ │ ├── model-input-default.js
235
+ │ ├── model-output-limit.js # Issue #218 — the per-model `limit` descriptor amicus hands opencode.
236
+ │ ├── model-shortlist.js # Vendor model shortlist (#138) -- the family -> model second level.
237
+ │ ├── model-tiers.js # Per-vendor cost tiers (economy/balanced/frontier) + resolution against the
238
+ │ ├── model-validator.js # Model Validator
239
+ │ ├── no-output-backstop.js # v4.6.2 PR2 (spec §5, D4): fail a headless leg fast when the model produces
240
+ │ ├── node-version-guard.js
241
+ │ ├── openrouter-credit.js # The OpenRouter credit/limit probe, split out of api-key-validation.js to keep
242
+ │ ├── output-length.js # #218 PR 3: name the "Mode 2" death.
243
+ │ ├── path-fence.js # Shared realpath-containment fence.
244
+ │ ├── path-setup.js
245
+ │ ├── port-pid.js # Cross-platform listener-PID lookup.
246
+ │ ├── pricing.js
247
+ │ ├── project-path.js # Canonical project-path helper.
248
+ │ ├── project-root-sanity.js
249
+ │ ├── prompt-source.js
250
+ │ ├── provider-default-picker.js # Provider-default picker core (Part 2, Task 4).
251
+ │ ├── provider-default-prompt.js # Provider-default prompt flow (Part 2, Task 6/7 shared helper).
252
+ │ ├── provider-registry.js # Provider-capability registry — the single source of truth for provider
253
+ │ ├── quick-picks.js # Quick-pick resolution (wizard Step 2) — resolves each curated family to
254
+ │ ├── read-slice.js # Byte-bounded slicing for amicus_read (15a.3 / B17).
255
+ │ ├── remediation-hints.js
256
+ │ ├── result-schema-rebuild.js
257
+ │ ├── result-schema-version.js # The single SCHEMA_VERSION constant shared by result-schema.js and
258
+ │ ├── result-schema.js
259
+ │ ├── route-error.js # Shared renderer (#61 Task 6.1): turns a router RouteResult — an error or a
260
+ │ ├── route-launch.js # Route-launch views (#61 gateway routing integration, Task 4.2).
261
+ │ ├── route-suggestions.js
262
+ │ ├── server-setup.js # Server Setup Utilities
263
+ │ ├── session-abort.js # Session abort utilities: signal handler installation and terminal metadata writes.
264
+ │ ├── session-index-prune.js
265
+ │ ├── session-index-tmp-sweep.js
266
+ │ ├── session-index.js # Global session index (issue #40).
267
+ │ ├── session-lock.js
268
+ │ ├── session-metadata-tmp-sweep.js
269
+ │ ├── session-path.js # Session path resolution.
270
+ │ ├── session-status.js # #202: render the engine's SESSION STATUS as a clause on a leg's death report.
271
+ │ ├── shared-server.js
272
+ │ ├── spend-ledger.js
273
+ │ ├── start-helpers.js # Start Command Helpers
274
+ │ ├── text-sanitize.js # One third-party string, safe to render: no escapes, no bidi, one short line.
275
+ │ ├── thinking-validators.js # Thinking Level Validators
276
+ │ ├── ttft.js # The one honesty predicate for the time-to-first-token probe (v4.9 W13).
277
+ │ ├── untrusted-fence.js # Untrusted sidecar output fence.
278
+ │ ├── update-notice.js # The MCP server is the one entry point that skips bin/amicus.js's update
279
+ │ ├── update-notifier-loader.js # update-notifier Loader
280
+ │ ├── updater.js # Updater Module
281
+ │ ├── validators.js # Input Validators
282
+ │ └── version-info.js # After an `npm i -g amicus` upgrade, a long-lived MCP server process keeps
283
+ ├── workspace/
284
+ │ ├── artifact-guard.js # Council Workspace — artifact read guard (v4.4 §4.5 workspace:read-artifact).
285
+ │ ├── artifact-names.js # Council Workspace — artifact NAME derivation (v4.8 PR5a).
286
+ │ ├── blind-mode.js # Council Workspace — blind-mode name mapping (v4.4 §6.3).
287
+ │ ├── fold-format.js # Council Workspace — fold payload builder (v4.4 §7).
288
+ │ ├── live-normalize.js # Council Workspace — live-doc normalization (v4.4 §3 A1/A2/A4 seam).
289
+ │ ├── matrix-model.js # Council Workspace — adjudication matrix view model (v4.4 §5.2).
290
+ │ ├── run-detail.js # Council Workspace — run detail: defensive parse of run.json / tally.json /
291
+ │ ├── run-scan.js # Council Workspace — run discovery (v4.4 spec §4.3 / §5.1).
292
+ │ └── seat-space.js # Council Workspace — the seat-space PREDICATES (v4.8 PR5b).
293
+ ├── cli-council-run-bench.js # Bench and input resolution for the council run command.
294
+ ├── cli-council-run-render.js
295
+ ├── cli-handlers-abort.js # CLI Abort Handler (B21-rest extraction)
296
+ ├── cli-handlers-council-run.js
297
+ ├── cli-handlers-council.js
298
+ ├── cli-handlers-doctor.js
299
+ ├── cli-handlers-fanout.js # CLI handler for the fanout command (multi-model parallel runs).
300
+ ├── cli-handlers-init.js # `amicus init [--claude] [--desktop] [--json]` (v4.2 §4.8, C2). Re-runs the
301
+ ├── cli-handlers-key-local.js # amicus key <localId> — bearer lifecycle for a config-defined local /
302
+ ├── cli-handlers-pack.js
303
+ ├── cli-handlers-provider.js # `amicus provider add|list|test|remove` (v4.2 §4.6): configure local /
304
+ ├── cli-handlers-resume-continue.js # CLI Resume/Continue Handlers (B21-rest extraction)
305
+ ├── cli-handlers-run.js # CLI Run Handlers (WS-2 extraction)
306
+ ├── cli-handlers-spend.js
307
+ ├── cli-handlers-status.js # `amicus status <task_id>` — one-shot human/JSON status for a session or wave.
308
+ ├── cli-handlers-template.js
309
+ ├── cli-handlers-watch.js
310
+ ├── cli-handlers.js # CLI Command Handlers
311
+ ├── cli-template-args.js
312
+ ├── cli.js # CLI Argument Parser
313
+ ├── conflict.js # File Conflict Detection Module
314
+ ├── context-compression.js # Context Compression Module
315
+ ├── context.js # Context Filtering Module
316
+ ├── drift.js # Context Drift Detection Module
317
+ ├── environment.js # Environment Detection Module
318
+ ├── headless.js # Headless Mode Runner
319
+ ├── index.js # Amicus - Main Module
320
+ ├── jsonl-parser.js # JSONL Parser
321
+ ├── mcp-council-awareness.js
322
+ ├── mcp-council-bench.js
323
+ ├── mcp-council-run.js
324
+ ├── mcp-notify.js # Pure helpers + in-process registry for the MCP `onComplete: 'mcp-notify'`
325
+ ├── mcp-server.js # @module mcp-server — Amicus MCP Server (stdio transport)
326
+ ├── mcp-spend.js
327
+ ├── mcp-tools.js # MCP Tool Definitions for Amicus
328
+ ├── mcp-wait.js # Engine for the amicus_wait MCP tool: blocks inside one tool call until a session/wave reaches a terminal state or the wait window closes.
329
+ ├── opencode-client.js # OpenCode SDK Client Wrapper
330
+ ├── project-root-allowlist.js # The MCP `project` / cwd input becomes the session-store parent AND the spawned
331
+ ├── prompt-builder.js # System Prompt Builder
332
+ ├── session-manager.js # Session Manager Module
333
+ ├── session.js # Session Resolver
334
+ └── spend-query.js
335
+ electron/
336
+ ├── assets/
337
+ │ ├── icon.png
338
+ │ └── icon.svg
339
+ ├── workspace-ui/
340
+ │ ├── index.html
341
+ │ ├── live-dead-seats.js
342
+ │ ├── live-model.js # Council Workspace — pure renderer-side view logic (poll cadence, seat row
343
+ │ ├── live-seats.js
344
+ │ ├── md-lite.js # markdown-lite — dependency-free renderer for untrusted model prose
345
+ │ ├── workspace-app.js # Council Workspace — application state + wiring (v4.4 §5).
346
+ │ ├── workspace-banners.js # Council Workspace — the run-detail banner ladder (v4.4 §9, spec's "graceful when present").
347
+ │ ├── workspace-lazy.js # Council Workspace — lazy prose-panel loading (v4.4 §5.2). v4.7 PR7 extraction of the
348
+ │ ├── workspace-matrix.js # Council Workspace — adjudication matrix + verdict panel painters.
349
+ │ ├── workspace-panels.js # Council Workspace — name resolution + the matrix/verdict/seats panel adapters
350
+ │ ├── workspace-render.js # Council Workspace — DOM painters (run list, header, stage rail, seats,
351
+ │ ├── workspace-seats.js # Council Workspace — seats panel painter (v4.4 §5). D8 extraction (Task 1, v4.6.2 PR4): moved
352
+ │ ├── workspace-verbs.js # Council Workspace — action verbs (v4.4 §5, ⚠️ DE-ROT F05 split of
353
+ │ └── workspace.css
354
+ ├── close-guard.js # Close Guard — auto-fold on window close (backlog B01)
355
+ ├── fold.js # Fold Logic
356
+ ├── ipc-guard.js # IPC Guard Helpers
357
+ ├── ipc-setup-local.js # IPC handlers for the Electron wizard's "Local server" card (Task 13, v4.2 §4.6).
358
+ ├── ipc-setup.js # IPC Setup Handlers
359
+ ├── ipc-workspace.js # Council Workspace IPC (v4.4 §4.5) — all seven workspace: channels.
360
+ ├── load-failsafe.js # Load Failsafe
361
+ ├── main.js # Amicus Electron Shell - v3
362
+ ├── offer-session.js # Offer-session catalog snapshots for the setup wizard's provider-default
363
+ ├── opencode-theme.js
364
+ ├── preload-content.js # Content Preload - OpenCode WebContentsView (minimal, no privileged bridge)
365
+ ├── preload-setup.js # Sidecar Preload - Setup Mode
366
+ ├── preload-workspace.js # Council Workspace Preload — minimal typed IPC bridge (v4.4 §4.2/§4.5).
367
+ ├── preload.js # Sidecar Preload - v3 Minimal
368
+ ├── session-route.js # Web-UI session route builder (#45).
369
+ ├── setup-ui-alias-groups.js # Setup UI - Alias grouping rule (issue 213)
370
+ ├── setup-ui-alias-script.js # Setup UI - Alias Editor Script
371
+ ├── setup-ui-aliases.js # Setup UI - Alias Editor
372
+ ├── setup-ui-council.js # Setup UI — Free OpenRouter council picker (mounted on the Models step).
373
+ ├── setup-ui-keys-script.js # Setup UI - Step 1 Key Management Script
374
+ ├── setup-ui-keys.js # Setup UI - Step 1: API Keys
375
+ ├── setup-ui-local-script.js # Setup UI — Local server widget runtime script (Task 13, v4.2 §4.6).
376
+ ├── setup-ui-local.js # Setup UI — "Local server" step-1 add-on widget (Task 13, v4.2 §4.6).
377
+ ├── setup-ui-model.js # Setup UI - Step 2: Default Model Selection
378
+ ├── setup-ui-provider-default.js # Setup UI — Per-provider default model picker (Part 2, Task 8).
379
+ ├── setup-ui-styles.js # Setup UI - Shared CSS Styles (clay/gold token-driven)
380
+ ├── setup-ui.js # Setup UI - Wizard Orchestrator: API Keys → Models → Aliases → Review
381
+ ├── summary.js # Summary Generation via OpenCode API
382
+ ├── toolbar.js # Amicus Toolbar HTML Builder
383
+ ├── window-position.js # Window Position Calculator
384
+ └── workspace-shell.js # Council Workspace window (v4.4 §4.1/§4.2) — the third Electron mode's
385
+ scripts/
386
+ ├── benchmark-api-direct.js # Direct OpenRouter API Benchmark for Thinking Levels
387
+ ├── benchmark-thinking.js # Benchmark Thinking Levels
388
+ ├── check-ci-alias-pins.js # Drift gate for the CI alias map (.github/amicus-ci-aliases.json).
389
+ ├── check-citations.js # Cross-file citation enforcement for the pre-commit hook and the whole-tree
390
+ ├── check-file-sizes.js # File size enforcement for the pre-commit hook and the whole-tree CI gate (--all).
391
+ ├── check-global-install.js # CI assertion (Windows install-smoke job, #35): after a REAL global install
392
+ ├── check-html.js
393
+ ├── check-secrets.js # Secret detection for the pre-commit hook and the whole-tree CI gate (--all).
394
+ ├── check-tarball-lifecycle.js # CI guard: assert every script referenced by an npm *lifecycle* hook actually
395
+ ├── check-ui.js
396
+ ├── debug-cdp.js
397
+ ├── eval-with-monitoring.sh
398
+ ├── extract-workflow-env.js # Extract the workflow-level and job-level `env:` blocks of a GitHub Actions
399
+ ├── generate-docs-helpers.js # Helper functions for generate-docs.js.
400
+ ├── generate-docs.js # Auto-generate documentation sections from source code.
401
+ ├── generate-icon.js # Generate app icon PNG from SVG source.
402
+ ├── git-index.js # Read file content from the git INDEX rather than the working tree, and list
403
+ ├── integration-test.sh
404
+ ├── mark-test-passed.js # Writes the current git HEAD SHA to .test-passed for the pre-push SHA cache
405
+ ├── postinstall.js # Post-install script for amicus
406
+ ├── probe-max-tokens.js # Wire probe for issue #218: what max_tokens / reasoning / thinking does the
407
+ ├── run-integration-keyless.js
408
+ ├── setup-hooks.js # Configure git to run the version-controlled hooks in .husky/.
409
+ ├── test-tools.sh
410
+ ├── validate-docs.js # CLAUDE.md drift detection script.
411
+ ├── validate-thinking.js
412
+ └── validate-ui.js
413
+ evals/
414
+ ├── tests/
415
+ │ ├── claude_runner.test.js
416
+ │ ├── eval_tasks.test.js
417
+ │ ├── evaluator.test.js
418
+ │ ├── result_writer.test.js
419
+ │ └── transcript_parser.test.js
420
+ ├── claude_runner.js
421
+ ├── eval_tasks.json
422
+ ├── evaluator.js
423
+ ├── README.md
424
+ ├── result_writer.js
425
+ ├── run_eval.js # Sidecar Agentic Eval Runner
426
+ └── transcript_parser.js # Parse Claude Code stream-json output into structured transcript.
427
+ <!-- /AUTO:tree -->
428
+
429
+ ---
430
+
431
+ ## Key Modules
432
+
433
+ <!-- AUTO:modules -->
434
+ | Module | Purpose | Key Exports |
435
+ |--------|---------|-------------|
436
+ | `cli-council-run-bench.js` | Bench and input resolution for the council run command. | `resolveBench()`, `resolveChair()`, `resolveCritic()`, `CHAIR_DEFAULT()`, `parseList()` |
437
+ | `cli-council-run-render.js` | | `renderRunHuman()` |
438
+ | `cli-handlers-abort.js` | CLI Abort Handler (B21-rest extraction) | `handleAbort()` |
439
+ | `cli-handlers-council-run.js` | | `handleCouncilRun()`, `renderRunHuman()`, `CHAIR_DEFAULT()` |
440
+ | `cli-handlers-council.js` | | `handleCouncil()` |
441
+ | `cli-handlers-doctor.js` | | `runDoctorChecks()`, `handleDoctor()`, `MAX_CATALOG_AGE_MS()` |
442
+ | `cli-handlers-fanout.js` | CLI handler for the fanout command (multi-model parallel runs). | `handleFanout()` |
443
+ | `cli-handlers-init.js` | `amicus init [--claude] [--desktop] [--json]` (v4.2 §4.8, C2). Re-runs the | `handleInit()` |
444
+ | `cli-handlers-key-local.js` | amicus key <localId> — bearer lifecycle for a config-defined local / | `handleLocalKey()`, `formatLocalKeyList()`, `maskKey()` |
445
+ | `cli-handlers-pack.js` | | `handlePack()` |
446
+ | `cli-handlers-provider.js` | `amicus provider add|list|test|remove` (v4.2 §4.6): configure local / | `handleProvider()`, `isLoopbackUrl()`, `isPlaintextRemote()` |
447
+ | `cli-handlers-resume-continue.js` | CLI Resume/Continue Handlers (B21-rest extraction) | `handleResume()`, `handleContinue()` |
448
+ | `cli-handlers-run.js` | CLI Run Handlers (WS-2 extraction) | `handleStart()`, `handleFanout()`, `handleRead()` |
449
+ | `cli-handlers-spend.js` | | `handleSpend()`, `aggregateSpend()`, `buildSpendDoc()`, `parseSinceDays()`, `filterRows()` |
450
+ | `cli-handlers-status.js` | `amicus status <task_id>` — one-shot human/JSON status for a session or wave. | `handleStatus()`, `formatRunHuman()`, `formatWaveHumanStatus()`, `formatCouncilHuman()` |
451
+ | `cli-handlers-template.js` | | `handleTemplate()` |
452
+ | `cli-handlers-watch.js` | | `handleWatch()`, `resolveWatchTarget()` |
453
+ | `cli-handlers.js` | CLI Command Handlers | `handleSetup()`, `handleAbort()`, `handleUpdate()`, `handleMcp()`, `handleKey()` |
454
+ | `cli-template-args.js` | | `applyTemplateForArgs()`, `NEEDS_TEMPLATE_MSG()` |
455
+ | `cli.js` | CLI Argument Parser | `parseArgs()`, `validateStartArgs()`, `getUsage()`, `getCommandNames()`, `getBooleanFlags()` |
456
+ | `conflict.js` | File Conflict Detection Module | `detectConflicts()`, `formatConflictWarning()` |
457
+ | `context-compression.js` | Context Compression Module | `compressContext()`, `estimateTokenCount()`, `buildPreamble()`, `DEFAULT_TOKEN_LIMIT()` |
458
+ | `context.js` | Context Filtering Module | `filterContext()`, `parseDuration()`, `estimateTokens()`, `takeLastNTurns()` |
459
+ | `drift.js` | Context Drift Detection Module | `calculateDrift()`, `formatDriftWarning()`, `countTurnsSince()`, `isDriftSignificant()` |
460
+ | `environment.js` | Environment Detection Module | `inferClient()`, `getSessionRoot()`, `detectEnvironment()`, `VALID_CLIENTS()` |
461
+ | `headless.js` | Headless Mode Runner | `runHeadless()`, `waitForServer()`, `withTimeout()`, `extractSummary()`, `findTrailingFoldMarker()` |
462
+ | `index.js` | Amicus - Main Module | `startAmicus()`, `listAmicus()`, `resumeAmicus()`, `continueAmicus()`, `readAmicus()` |
463
+ | `jsonl-parser.js` | JSONL Parser | `parseJSONLLine()`, `readJSONL()`, `extractTimestamp()`, `formatMessage()`, `formatContext()` |
464
+ | `mcp-council-awareness.js` | | `subWaveIds()`, `countWaveLegs()`, `elapsedOf()`, `enginePid()`, `buildCouncilStatusPayload()` |
465
+ | `mcp-council-bench.js` | | `resolveBenchInput()`, `auditBenchAliases()` |
466
+ | `mcp-council-run.js` | | `handleCouncilRunTool()`, `COUNCIL_PACK_PARAM_MAP()`, `buildCouncilStatusPayload()`, `listCouncilRuns()`, `abortCouncilRun()` |
467
+ | `mcp-notify.js` | Pure helpers + in-process registry for the MCP `onComplete: 'mcp-notify'` | `validateOnComplete()`, `buildNotifyPayload()`, `requestMcpNotify()`, `consumeMcpNotify()` |
468
+ | `mcp-server.js` | @module mcp-server — Amicus MCP Server (stdio transport) | `handlers()`, `startMcpServer()`, `getProjectDir()`, `resolveProjectDir()`, `getClientRoot()` |
469
+ | `mcp-spend.js` | | `amicus_spend()`, `buildSpendResult()` |
470
+ | `mcp-tools.js` | MCP Tool Definitions for Amicus | `getTools()`, `getGuideText()`, `safeTaskId()`, `safeModel()` |
471
+ | `mcp-wait.js` | Engine for the amicus_wait MCP tool: blocks inside one tool call until a session/wave reaches a terminal state or the wait window closes. | `runWait()`, `registerInProcessRun()`, `settleInProcessRun()`, `hasInProcessRun()`, `clampTimeout()` |
472
+ | `opencode-client.js` | OpenCode SDK Client Wrapper | `INSUFFICIENT_CREDITS_REASON()`, `providerErrorReason()`, `parseModelString()`, `createClient()`, `createSession()` |
473
+ | `project-root-allowlist.js` | The MCP `project` / cwd input becomes the session-store parent AND the spawned | `isAllowedProjectRoot()`, `isPathInside()`, `allowedRoots()` |
474
+ | `prompt-builder.js` | System Prompt Builder | `buildSystemPrompt()`, `buildPrompts()`, `buildEnvironmentSection()`, `getSummaryTemplate()`, `SUMMARY_TEMPLATE()` |
475
+ | `session-manager.js` | Session Manager Module | `createSession()`, `updateSession()`, `getSession()`, `saveConversation()`, `saveSummary()` |
476
+ | `session.js` | Session Resolver | `encodeProjectPath()`, `getSessionDirectory()`, `getSessionId()`, `resolveSession()` |
477
+ | `spend-query.js` | | `filterRows()`, `groupRows()`, `computeWasted()`, `emptyTokens()`, `addTokens()` |
478
+ | `council/anonymize.js` | | `assignLabels()`, `toGlobalId()`, `toGlobalFindings()`, `rankingToOrder()`, `LETTERS()` |
479
+ | `council/briefings-chair-task.js` | | `CHAIR_ANSWER_VALUES()`, `ANSWER_SCALE_ADDENDUM()`, `TASK_CHAIR_SYNTHESIS()`, `TASK_CHAIR_SYNTHESIS_NO_CLAIMS()`, `TASK_CONCURRENCE_CAVEAT()` |
480
+ | `council/briefings-chair.js` | | `dateLine()`, `CHAIR_NO_TOOLS_PREAMBLE()`, `chairRepairPromptFor()`, `CHAIR_VERDICT_VALUES()`, `VERDICT_SCALE_ADDENDUM()` |
481
+ | `council/briefings-debate.js` | | `DEBATE_NO_TOOLS_PREAMBLE()`, `DEFENSE_CONTRACT()`, `REVOTE_CONTRACT()`, `buildDefenseBrief()`, `buildRevoteBundle()` |
482
+ | `council/briefings-stage2-task.js` | | `TASK_JUDGE_FRAME()`, `TASK_JUDGE_A()`, `TASK_JUDGE_B()`, `TASK_JUDGE_B_NO_CLAIMS()`, `NO_CLAIMS_INDEX()` |
483
+ | `council/briefings-stage2.js` | | `JUDGE_NO_TOOLS_PREAMBLE()`, `CHAIR_NO_TOOLS_PREAMBLE()`, `CHAIR_VERDICT_VALUES()`, `JUDGE_OUTPUT_CONTRACT()`, `VERDICT_SCALE_ADDENDUM()` |
484
+ | `council/briefings-task.js` | | `TASK_ANTI_SYCOPHANCY_CLAUSE()`, `TASK_FINDINGS_JSON_SHAPE()`, `TASK_FINDINGS_CONTRACT()`, `buildTaskSeatBriefing()`, `buildTaskCriticBriefing()` |
485
+ | `council/briefings.js` | | `ANTI_SYCOPHANCY_CLAUSE()`, `FINDINGS_CONTRACT()`, `FINDINGS_JSON_SHAPE()`, `FINDINGS_TWO_PART_FRAMING()`, `buildSeatBriefing()` |
486
+ | `council/chair-fallback.js` | | `pickFallbackChair()`, `classifyChairAttempt()` |
487
+ | `council/debate.js` | | `applyDebate()`, `decorateRecord()`, `debateRunStatsRows()`, `PAST_TENSE()`, `DEBATE_ROLES()` |
488
+ | `council/findings.js` | | `validateFindings()`, `buildValidateDoc()`, `SEVERITIES()`, `lastJsonBlock()`, `countAttemptedFindings()` |
489
+ | `council/ledger-join.js` | | `benchLegs()`, `credFor()`, `splitFindingsBySeat()`, `meanCred()` |
490
+ | `council/ledger-stats.js` | | `LEDGER_FILE()`, `readRows()`, `avg()`, `countRuns()`, `deriveReliability()` |
491
+ | `council/ledger.js` | | `buildLedgerRows()`, `appendRun()`, `deriveReliability()`, `buildStatsDoc()`, `LEDGER_FILE()` |
492
+ | `council/parse-stage2.js` | | `parseJudgeOutput()`, `parseChairVerdict()`, `CHAIR_VERDICTS()`, `JUDGE_VERDICTS()`, `parseChairAnswer()` |
493
+ | `council/peer-split.js` | | `peersOf()`, `unattributedPeerDrops()` |
494
+ | `council/presets-cli.js` | | `runSave()`, `runList()`, `runShow()` |
495
+ | `council/report-cost.js` | | `buildCostModel()` |
496
+ | `council/report-html.js` | | `renderHtml()` |
497
+ | `council/report-md.js` | | `renderMd()` |
498
+ | `council/report.js` | | `buildReport()`, `toModel()`, `TIER_ORDER()`, `SYMBOL()`, `isSeatSpace()` |
499
+ | `council/run-assemble.js` | | `buildRunStatsEntry()`, `worseConformance()`, `buildTallyInput()`, `writeTallyFiles()`, `writeVerdictFiles()` |
500
+ | `council/run-budget.js` | | `createBudget()` |
501
+ | `council/run-chair.js` | | `runChair()`, `pickFallbackChair()`, `classifyChairAttempt()` |
502
+ | `council/run-debate-revote.js` | | `legOpts()`, `legRow()`, `runRevoteWave()` |
503
+ | `council/run-debate-stage.js` | | `runDebateStage()` |
504
+ | `council/run-debate.js` | | `runDebate()`, `nothingToDebate()`, `disputingJudges()`, `debateTargets()` |
505
+ | `council/run-degrade.js` | | `createDegradeSink()` |
506
+ | `council/run-finalize.js` | | `statusForExit()`, `resolveTerminalExit()`, `writeRunTerminal()`, `SIGNAL_EXIT()` |
507
+ | `council/run-finish.js` | | `finishRun()` |
508
+ | `council/run-launch.js` | | `createLaunchers()`, `materializeReviews()`, `materializeDebate()`, `sanitizeName()`, `isAbortExit()` |
509
+ | `council/run-retry-group.js` | | `lensIndexOf()`, `recordFailure()`, `groupStage1Losses()`, `planStillDeadSources()`, `seatKey()` |
510
+ | `council/run-retry-keys.js` | | `seatKey()`, `twinAliases()`, `legLossKey()`, `srcLegClaimer()` |
511
+ | `council/run-retry-launch.js` | | `briefingFor()`, `bindRetryWave()` |
512
+ | `council/run-retry-notes.js` | | `waveStillDeadNote()`, `skippedWaveNote()`, `srcLegStillDeadNote()`, `retryLegStillDeadNote()`, `missingLegStillDeadNote()` |
513
+ | `council/run-retry-window.js` | The Stage-1 retry's no-output window: how long a RELAUNCHED leg may stay | `retryBackstopMs()` |
514
+ | `council/run-retry.js` | | `groupStage1Losses()`, `retryStage1Losses()` |
515
+ | `council/run-server.js` | | `acquireRunServer()`, `releaseRunServer()`, `resolveRunServerModels()`, `recordServerFate()` |
516
+ | `council/run-stage1-launch.js` | Stage-1 launch pass for the council engine. | `launchStage1()` |
517
+ | `council/run-stage1-rows.js` | | `pushDeadSeatRows()`, `supersededRows()` |
518
+ | `council/run-stage1-superseded.js` | | `supersededRows()` |
519
+ | `council/run-stage2.js` | | `runStage2()` |
520
+ | `council/run-stages.js` | | `runStage1()`, `runStage2()`, `isAbortExit()`, `slug()`, `roleFor()` |
521
+ | `council/run-state.js` | | `RUN_FILE()`, `readRun()`, `initRun()`, `initCouncilRun()`, `checkpoint()` |
522
+ | `council/run-stats-entry.js` | | `buildRunStatsEntry()` |
523
+ | `council/run-verdict-files.js` | | `writeVerdictFiles()` |
524
+ | `council/run.js` | | `runCouncil()`, `pickFallbackChair()`, `SIGNAL_EXIT()` |
525
+ | `council/seats.js` | | `buildSeats()`, `roleAt()`, `bindSeats()`, `artifactName()`, `displayName()` |
526
+ | `council/stage1-bind.js` | | `bindStage1Waves()`, `orphanLegNote()`, `missingSeatDeadWave()`, `bindPaddedWave()` |
527
+ | `council/street-cred.js` | | `computeStreetCred()`, `rankPositions()`, `credSeats()` |
528
+ | `council/tally.js` | | `assignTier()`, `computeStreetCred()`, `tally()`, `COUNCIL_SCHEMA_VERSION()` |
529
+ | `council/verdict-seat-loss.js` | | `summarizeSeatLoss()`, `deriveSeatLoss()` |
530
+ | `council/verdict-seats-reviewed.js` | #202: the bench-seat census for verdict.json, as a spreadable fragment. | `seatsReviewedOf()` |
531
+ | `council/verdict.js` | | `buildVerdict()`, `summarizeSeatLoss()`, `deriveSeatLoss()`, `readOverallVerdict()`, `readPriorVerdictSurfaces()` |
532
+ | `design/tokens.js` | | `tokenCss()`, `TOKENS()` |
533
+ | `observe/council-legs.js` | | `buildLegRows()` |
534
+ | `observe/events.js` | | `appendEvent()`, `createEventTail()`, `EVENTS_FILE()`, `EVENTS_SCHEMA_VERSION()`, `emitWaveStarted()` |
535
+ | `observe/follow.js` | | `createFollowPrinter()` |
536
+ | `observe/live-doc.js` | | `enrichLegUsage()`, `markLive()`, `rollupWaveUsage()`, `TERMINAL()` |
537
+ | `observe/on-complete.js` | | `buildHookEnv()`, `runOnComplete()`, `fireWaveOnComplete()`, `fireCouncilOnComplete()`, `HOOK_TIMEOUT_MS()` |
538
+ | `observe/watch-render.js` | | `renderTable()`, `renderPlainLines()`, `mapExitCode()`, `emitJsonChange()`, `runWatchLoop()` |
539
+ | `pack/pack-cli.js` | | `applyPackOrExit()` |
540
+ | `pack/pack-forward.js` | | `prepareForward()` |
541
+ | `pack/pack-resolve.js` | | `applyPackToArgs()`, `applyPackToMcpInput()` |
542
+ | `pack/pack-store.js` | | `packsDir()`, `canonicalHash()`, `resolvePackRef()`, `readPack()`, `writePack()` |
543
+ | `pack/pack-validate.js` | | `validatePack()`, `KIND_OPTIONS()`, `KINDS()` |
544
+ | `prompts/cowork-agent-prompt.js` | Cowork Agent Prompt | `buildCoworkAgentPrompt()` |
545
+ | `sidecar/budget.js` | | `checkBudget()`, `formatBudgetError()`, `DEFAULT_MAX_COST_PER_MTOK()`, `ASSUMED_OUTPUT_TOKENS()` |
546
+ | `sidecar/child-sessions.js` | | `collectSubtreeUsage()`, `subtreeIsUnknown()`, `SUBTREE_MAX_DEPTH()`, `SUBTREE_MAX_SESSIONS()` |
547
+ | `sidecar/context-builder.js` | Context Builder Module | `buildContext()`, `parseDuration()`, `resolveSessionFile()`, `applyContextFilters()`, `findCoworkSession()` |
548
+ | `sidecar/continue.js` | Sidecar Continue Operations - Handles continuing from previous sessions | `loadPreviousSession()`, `buildContinuationContext()`, `createContinueSessionMetadata()`, `continueSidecar()` |
549
+ | `sidecar/conversation-mirror.js` | | `createMirrorState()`, `mirrorMessages()`, `logMessage()`, `mirrorUsageOnly()`, `allAssistantUsagePresent()` |
550
+ | `sidecar/crash-handler.js` | Crash Handler - Updates metadata to 'error' on uncaught exceptions | `installCrashHandler()` |
551
+ | `sidecar/electron-cache.js` | Electron download-cache root resolution (#53 helper). | `resolveCacheRoots()`, `defaultCacheRoot()` |
552
+ | `sidecar/electron-ensure.js` | ensureElectron() — lazy first-GUI provisioning (#55). | `ensureElectron()`, `_resetEnsureElectron()` |
553
+ | `sidecar/electron-install.js` | Electron self-heal primitive (#53, #59). | `resolveElectronBinary()`, `isElectronUsable()`, `cachedZip()`, `repairElectron()`, `platformExe()` |
554
+ | `sidecar/electron-lock.js` | Stale-aware single-flight lock for the electron self-heal (#53). | `acquireRepairLock()`, `isStaleLock()`, `lockPathFor()`, `STALE_MS()` |
555
+ | `sidecar/electron-quarantine.js` | AV / antivirus quarantine detection for the electron self-heal (#53). | `avHint()`, `quarantineReason()`, `verifyExtractOutcome()` |
556
+ | `sidecar/electron-state.js` | Electron install-state probes (#76). | `electronDirFor()`, `probeElectronState()` |
557
+ | `sidecar/fallback-chains.js` | | `resolveFallbackConfig()`, `deriveChain()`, `vendorOf()`, `DEFAULT_MAX_SUBSTITUTIONS()` |
558
+ | `sidecar/fanout-budget.js` | | `preflightBudget()` |
559
+ | `sidecar/fanout-leg-fallback.js` | | `runLegWithFallback()`, `recordAttemptSpend()`, `sumAttemptUsage()` |
560
+ | `sidecar/fanout-leg.js` | | `legStatusFromResult()`, `writeLegPatch()`, `runLeg()`, `buildRoutingFailureLeg()`, `runSingleAttempt()` |
561
+ | `sidecar/fanout-output.js` | | `formatWaveHuman()`, `fmtDuration()` |
562
+ | `sidecar/fanout-retry.js` | | `ELIGIBLE_RETRY()`, `parseInitialContext()`, `buildRetryPlan()`, `retryFailedWave()` |
563
+ | `sidecar/fanout-signals.js` | | `installWaveAbort()`, `WAVE_FORCE_EXIT_MS()` |
564
+ | `sidecar/fanout-validate.js` | | `parseModelsList()`, `DEFAULT_MAX_LEGS()`, `validateFanoutModels()` |
565
+ | `sidecar/fanout-wave-io.js` | | `writeWaveMetadata()`, `writeWaveDoc()`, `finishWave()`, `stampLegAttribution()` |
566
+ | `sidecar/fanout.js` | | `parseModelsList()`, `deriveLegIds()`, `validateFanoutModels()`, `DEFAULT_MAX_LEGS()`, `runFanout()` |
567
+ | `sidecar/interactive-abort.js` | | `startAbortWatch()`, `markResultAborted()`, `readAbortedMarker()`, `DEFAULT_INTERVAL_MS()` |
568
+ | `sidecar/interactive-mirror.js` | | `startInteractiveMirror()` |
569
+ | `sidecar/interactive-process.js` | Sidecar Interactive Process Helpers - Electron probe/env/process-exit plumbing | `getElectronPath()`, `checkElectronAvailable()`, `buildElectronEnv()`, `handleElectronProcess()` |
570
+ | `sidecar/interactive.js` | Sidecar Interactive Mode - Electron GUI session management | `runInteractive()` |
571
+ | `sidecar/leg-ids.js` | | `deriveLegIds()` |
572
+ | `sidecar/list-council.js` | Council rows on the CLI `amicus list` surface (v4.9 W12). | `padModel()`, `modelCell()`, `mergeCouncilRows()`, `councilScopeNotice()` |
573
+ | `sidecar/list-limit.js` | The `--limit` core behind `amicus list` (v4.7 PR3 rider). | `normalizeLimit()`, `truncationNotice()` |
574
+ | `sidecar/list-search.js` | The `--search` core behind both list surfaces (F8 D15, errata E-PR3-5). | `searchSessions()` |
575
+ | `sidecar/models-ceiling-line.js` | The one `Ceilings:` line `amicus models --refresh` prints (#218 P3). | `fmtCeilingLine()` |
576
+ | `sidecar/models-probe.js` | | `probeStoredAliases()`, `selectStoredAliases()`, `PROBE_WINDOW_MS()`, `PROBE_PROMPT()` |
577
+ | `sidecar/models-render.js` | Presentation helpers for `amicus models` -- pure string formatting, no I/O. | `perMtok()`, `fmtRow()`, `fmtGatewayFinding()`, `PROBE_LABELS()`, `fmtProbeCost()` |
578
+ | `sidecar/models.js` | `amicus models` (F5) — list/search the catalog, refresh it, audit aliases. | `handleModels()`, `buildFallbackDriftReport()` |
579
+ | `sidecar/progress-fields.js` | Derived, agent-facing progress fields shared by the MCP status/list | `sanitizePreview()`, `latestAssistantPreview()`, `deriveStage()`, `COARSE_STAGES()`, `TERMINAL_PROGRESS_STAGES()` |
580
+ | `sidecar/progress.js` | Sidecar Progress Reader | `readProgress()`, `writeProgress()`, `writeTerminalProgressSafe()`, `extractLatest()`, `computeLastActivity()` |
581
+ | `sidecar/read.js` | Sidecar Read Operations Module | `formatAge()`, `enumerateSessions()`, `enumerateAllProjects()`, `searchSessions()`, `listSidecars()` |
582
+ | `sidecar/reopen-notices.js` | The stderr Notice a reopen owes the user for the effort level it does NOT carry (#218 PR 4, council #235 r5 J1/A3). | `formatDroppedLevelNotice()`, `noticeDroppedLevel()` |
583
+ | `sidecar/reopen-spend.js` | Spend finalization for a REOPENED session (continue/resume). Split out of | `finalizeSpendForReopen()` |
584
+ | `sidecar/resume.js` | Sidecar Resume Operations - Handles resuming previous sidecar sessions | `loadSessionMetadata()`, `loadInitialContext()`, `checkFileDrift()`, `buildDriftWarning()`, `buildResumeUserMessage()` |
585
+ | `sidecar/session-finalize.js` | | `resolveTerminalState()`, `finalizeHeadlessResult()` |
586
+ | `sidecar/session-utils.js` | Sidecar Session Utilities - Shared functionality for session management | `HEARTBEAT_INTERVAL()`, `SessionPaths()`, `saveInitialContext()`, `finalizeSession()`, `outputSummary()` |
587
+ | `sidecar/setup-local.js` | The readline setup wizard's local / self-hosted provider add step (v4.2 §4.6, Task 12). | `addLocalProviderInteractive()` |
588
+ | `sidecar/setup-window.js` | Setup Window Launcher | `launchSetupWindow()` |
589
+ | `sidecar/setup.js` | Sidecar Setup Wizard | `addAlias()`, `addLocalProviderInteractive()`, `createDefaultConfig()`, `deriveFreeAlias()`, `detectApiKeys()` |
590
+ | `sidecar/start-metadata.js` | | `createSessionMetadata()` |
591
+ | `sidecar/start.js` | Sidecar Start Operations - Handles starting new sidecar sessions | `generateTaskId()`, `createSessionMetadata()`, `buildMcpConfig()`, `checkElectronAvailable()`, `runInteractive()` |
592
+ | `sidecar/tool-part.js` | | `TERMINAL_TOOL_STATUSES()`, `LIVE_TOOL_STATUSES()`, `isToolPart()`, `toolPartName()`, `toolPartInput()` |
593
+ | `sidecar/unzip.js` | Robust unzip for the electron self-heal (#53 follow-up; extract-zip-node24). | `robustExtract()`, `nativeUnzipPlan()`, `IDLE_MS()`, `MAX_MS()` |
594
+ | `sidecar/wave-progress.js` | | `formatWaveProgress()`, `readLegState()`, `createWaveHeartbeat()`, `WAVE_HEARTBEAT_INTERVAL()` |
595
+ | `sidecar/workspace-auto-open.js` | Workspace Auto-Open Decision Helper | `shouldAutoOpenWorkspace()` |
596
+ | `sidecar/workspace-window.js` | Council Workspace launcher (v4.4 §4.3/§4.4) — setup-window.js pattern: | `launchWorkspaceWindow()`, `launchWorkspaceWindowDetached()` |
597
+ | `template/apply.js` | | `applyTemplate()`, `ARTIFACT_CAP_BYTES()` |
598
+ | `template/render.js` | | `renderTemplate()`, `KNOWN_VARIABLES()` |
599
+ | `template/store.js` | | `templatesDir()`, `resolveTemplate()`, `listTemplates()`, `BUILTIN_TEMPLATES()` |
600
+ | `utils/abort-coordinator.js` | | `abortGraceMs()`, `isAlive()`, `killPidBestEffort()`, `killPidHard()`, `waitThenKill()` |
601
+ | `utils/abort-result.js` | The abort-result document builder for `abort <taskId|--all> --json` (B21-rest). | `buildAbortResult()` |
602
+ | `utils/activity-poller.js` | | `createActivityPoller()`, `killIfAlive()` |
603
+ | `utils/agent-mapping.js` | Agent Mapping Module | `PRIMARY_AGENTS()`, `OPENCODE_AGENTS()`, `HEADLESS_SAFE_AGENTS()`, `mapAgentToOpenCode()`, `isValidAgent()` |
604
+ | `utils/alias-audit.js` | Alias Audit (F5) — report + suggest for most classes; doctor --fix auto-repairs one narrow, mechanically-unambiguous class (B3). | `collectAliasSources()`, `findStaleAliases()`, `findDriftedStoredAliases()`, `suggestReplacements()`, `findFabricatedAliasRepairs()` |
605
+ | `utils/alias-resolver.js` | Alias Resolver Utilities | `autoRepairAlias()` |
606
+ | `utils/alias-shadow-writer.js` | The alias-shadow notice's WRITE half: say it without ever sinking the run. | `safeWrite()`, `armStream()`, `writeNoticeToStderr()` |
607
+ | `utils/alias-shadow.js` | Alias-shadow self-diagnosis — name a local alias that repoints a curated one. | `findAliasShadows()`, `formatAliasShadow()`, `noteAliasShadows()`, `auditAliasShadows()` |
608
+ | `utils/api-key-store.js` | API Key Store — reading, saving, and validating API keys. | `getEnvPath()`, `loadEnvEntries()`, `readApiKeys()`, `readApiKeyHints()`, `readApiKeyValues()` |
609
+ | `utils/api-key-validation.js` | API Key Validation — test API keys against provider endpoints. | `validateApiKey()`, `redactSecret()`, `validateOpenRouterKey()`, `checkOpenRouterCredit()`, `OPENROUTER_NO_CREDIT_WARNING()` |
610
+ | `utils/atomic-write.js` | Atomic file write helper. | `writeFileAtomic()` |
611
+ | `utils/auth-json.js` | Auth JSON Reader | `readAuthJsonKeys()`, `importFromAuthJson()`, `checkAuthJson()`, `removeFromAuthJson()`, `AUTH_JSON_PATH()` |
612
+ | `utils/base-url-classify.js` | v4.6.2 PR1 (spec §4, D1/D2): ANTHROPIC_BASE_URL classification, the | `classifyBaseUrl()`, `resolveBaseUrlOverride()`, `announceBaseUrlNormalizationOnce()`, `_resetBaseUrlNotice()` |
613
+ | `utils/claude-register.js` | Registration core for amicus: skill install (chat skill + LLM Council), | `MCP_CONFIG()`, `addMcpToConfigFile()`, `installSkill()`, `installCouncilSkill()`, `readPrevClaudeCodeAmicusEntry()` |
614
+ | `utils/cli-preflight.js` | Tiny shared preflight guards used by more than one CLI run handler | `requireNoUiForJson()`, `requireValidTaskId()`, `packSaveVersionConflict()` |
615
+ | `utils/client-detect.js` | Detects which caller (Claude Code vs. Cowork/Claude Desktop) spawned this | `detectClient()`, `matchClientName()` |
616
+ | `utils/config.js` | Amicus Config Module | `getConfigDir()`, `getConfigPath()`, `loadConfig()`, `saveConfig()`, `getDefaultAliases()` |
617
+ | `utils/council-presets.js` | Built-in council benches (B23). | `BUDGET_ALIASES()`, `FRONTIER_ALIASES()`, `resolveBuiltinCouncil()`, `listBuiltinCouncilNames()` |
618
+ | `utils/curated-models.js` | Family definitions + pinned fallbacks for the wizard model picker (v2). | `getFamilies()`, `toDefaultAliases()`, `stripGatewayPrefix()`, `listCuratedRoutes()`, `toGatewayRoutes()` |
619
+ | `utils/degrade.js` | | `makeDegrade()`, `formatDegrade()`, `DEGRADE_CHANNELS()` |
620
+ | `utils/doctor-alias-check.js` | | `evaluateAliasesCheck()`, `repairAlias()` |
621
+ | `utils/doctor-base-url-check.js` | v4.6.2 PR1 (spec §4): the 'anthropic-base-url' doctor row. | `evaluateAnthropicBaseUrl()` |
622
+ | `utils/doctor-credit-check.js` | The `openrouter-credit` doctor row (#43), split out of | `evaluateOpenRouterCredit()` |
623
+ | `utils/doctor-degrade.js` | | `collectDoctorDegrades()` |
624
+ | `utils/doctor-electron-mcp-check.js` | The `electron-mcp` doctor check ("Electron (MCP launch path)"), split out of | `scanElectronInstalls()`, `evaluateElectronInstalls()`, `evaluateElectronMcp()`, `evaluateElectronInteractive()` |
625
+ | `utils/doctor-engine-check.js` | The `engine-mcp` doctor check ("OpenCode engine (MCP launch path)"), split out | `evaluateEngineInstalls()`, `evaluateEngineMcp()` |
626
+ | `utils/doctor-key-auth-check.js` | The `key-auth` doctor row (issue #210), split out of src/cli-handlers-doctor.js | `evaluateKeyAuth()`, `classifyProbeFailure()`, `probeApiKey()`, `probeOpenRouterCredit()`, `liveProbesDisabled()` |
627
+ | `utils/doctor-local-providers-check.js` | The `local-providers` doctor check (v4.2 §4.7 C8), split out of | `evaluateLocalProviders()` |
628
+ | `utils/doctor-mcp-checks.js` | B14/Task 4.3: the two MCP-registration doctor checks ('mcp' and | `evaluateMcpRegistration()`, `evaluateLegacyMcpEntry()` |
629
+ | `utils/doctor-output-budget-check.js` | #218 PR 2: the 'output-budget' doctor row. | `evaluateOutputBudget()` |
630
+ | `utils/doctor-summary.js` | Compact doctor summary (v4.2 §4.7 C8). All-ok -> one line; otherwise the | `summarizeDoctor()` |
631
+ | `utils/engine-ensure.js` | ensureEngine() — runtime engine self-heal at server start (report #2). | `ensureEngine()`, `_resetEnsureEngine()` |
632
+ | `utils/engine-install-scan.js` | Discover + probe every amicus install that could serve the MCP (running, | `listAmicusInstalls()`, `scanEngineInstalls()`, `classifyLaunch()`, `resolveNpmRootG()` |
633
+ | `utils/engine-lock.js` | Stale-aware single-flight lock for the engine self-heal (report #2). | `acquireRepairLock()`, `isStaleLock()`, `lockPathFor()`, `STALE_MS()` |
634
+ | `utils/engine-log-parse.js` | Line-shape parsing for the engine log: level, session, message. | `isErrorLine()`, `extractMessage()`, `collapseExcerpt()`, `mentionsSession()`, `lineIsAboutSession()` |
635
+ | `utils/engine-log-tail.js` | One engine-log FILE: read its tail, find the newest usable excerpt in it. | `newestExcerptInFile()` |
636
+ | `utils/engine-log.js` | Resolve the OpenCode engine's own error line for one session. | `engineErrorForSession()`, `engineLogDirCandidates()`, `isErrorLine()`, `extractMessage()`, `collapseExcerpt()` |
637
+ | `utils/engine-output-flag.js` | #218 PR 2 — the one engine env flag amicus sets: OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX. | `withOutputTokenFlag()`, `outputTokenFlagValue()`, `OUTPUT_TOKEN_FLAG()`, `ENGINE_DEFAULT_OUTPUT_TOKENS()`, `PLAIN_OUTPUT_TOKEN_FLAG()` |
638
+ | `utils/engine-repair.js` | Engine self-heal primitive (report #2): make the opencode engine present ON | `repairEngine()`, `findDonor()`, `engineSourceRoot()`, `copyEnginePackages()`, `runningPkgDir()` |
639
+ | `utils/engine-skew-records.js` | Server identity and the bounded store of standing engine-skew records. | `serverKeyForClient()`, `currentEngineSkew()`, `skewForKey()`, `rememberSkew()`, `forgetSkew()` |
640
+ | `utils/engine-skew.js` | Runtime detection of an opencode ENGINE version skew: server vs installed. | `noteSessionVersion()`, `currentEngineSkew()`, `serverKeyForClient()`, `formatSkewWarning()`, `formatSkewSuffix()` |
641
+ | `utils/engine-variants.js` | The effort lever (#218 PR 4): --thinking sent as the engine's variant field, validated against the engine's own declaration. | `VARIANT_LEVELS()`, `VariantRefusedError()`, `readModelDeclaration()`, `checkVariant()`, `formatUnverifiedVariantNote()` |
642
+ | `utils/env-loader.js` | Credential Loader | `loadCredentials()` |
643
+ | `utils/env-num.js` | | `envNumber()` |
644
+ | `utils/env-raw-store.js` | Arbitrary-env-var writes to the amicus .env (local-provider bearers, v4.2 §4.6). | `saveRawEnv()`, `removeRawEnv()`, `upsertEnvLine()`, `deleteEnvLine()` |
645
+ | `utils/error-classify.js` | | `classifyLegError()`, `isRetryable()` |
646
+ | `utils/error-doc.js` | | `ERROR_CODES()`, `buildErrorDoc()`, `failJson()` |
647
+ | `utils/fold-marker.js` | Fold marker construction/parsing helpers — shared by prompt-builder.js | `FOLD_MARKER_PREFIX()`, `generateFoldNonce()`, `buildFoldMarker()`, `trailingFoldMarkerRegex()`, `extractNonceFromText()` |
648
+ | `utils/format-duration.js` | | `formatDuration()` |
649
+ | `utils/free-models.js` | Free OpenRouter model detection (Unit A). | `isFreeModel()`, `listFreeModels()`, `suggestFreeCouncil()`, `PINNED_FREE_MODELS()` |
650
+ | `utils/gateway-route-audit.js` | Per-gateway-form audit for curated DEFAULT aliases (Task 6, #gwid). | `auditGatewayRoutes()` |
651
+ | `utils/gateway-route-catalog.js` | Conservative cross-gateway catalog pairing helper (Task 5, #gwid). | `pairAcrossGateways()` |
652
+ | `utils/gateway-router.js` | Pure gateway router (#61). Decides direct vs OpenRouter for a request using | `gatewayOf()`, `resolveRoute()` |
653
+ | `utils/http-get.js` | One HTTPS GET, always resolved, never rejected — the timer/destroy/failure | `httpGetText()`, `getJson()`, `DEFAULT_TIMEOUT_MS()`, `DEFAULT_MAX_BYTES()`, `MAX_REDIRECTS()` |
654
+ | `utils/idle-watchdog.js` | IdleWatchdog - BUSY/IDLE state machine with self-terminating timer. | `IdleWatchdog()`, `resolveTimeout()` |
655
+ | `utils/input-validators.js` | | `validateStartInputs()`, `levenshteinDistance()`, `suggestCommand()` |
656
+ | `utils/known-flags.js` | | `getKnownFlags()`, `unknownFlags()`, `INTERNAL_FLAGS()` |
657
+ | `utils/legacy-mcp-migration.js` | | `claudeCodeConfigPath()`, `claudeDesktopConfigPath()`, `inspectLegacySidecarEntry()`, `removeLegacySidecarEntry()`, `inspectAllLegacySidecarEntries()` |
658
+ | `utils/lifecycle.js` | | `isOneShotCommand()`, `armExitWatchdog()`, `exitReaping()`, `ONE_SHOT_COMMANDS()` |
659
+ | `utils/live-probes.js` | The single gate on outbound AUTHENTICATED network probes made by diagnostics | `enableLiveProbes()`, `liveProbesAllowed()`, `_resetLiveProbes()` |
660
+ | `utils/local-probe.js` | | `probeLocalProvider()`, `listLocalModels()` |
661
+ | `utils/local-providers.js` | | `getLocalProviders()`, `isLocalProvider()`, `deriveKeyEnv()`, `validateProviderEntry()`, `resolveLocalRouteInputs()` |
662
+ | `utils/logger.js` | Structured Logger Module | `logger()`, `LOG_LEVELS()` |
663
+ | `utils/mcp-discovery.js` | MCP Discovery - Discovers MCP servers from parent LLM configuration | `discoverParentMcps()`, `discoverClaudeCodeMcps()`, `discoverCoworkMcps()`, `hasAmicusRegistration()`, `readAmicusMcpConfig()` |
664
+ | `utils/mcp-self-identity.js` | | `SELF_MCP_NAMES()`, `isAmicusMcpConfig()`, `stripSelfMcpEntries()`, `normalizeToken()` |
665
+ | `utils/mcp-validators.js` | MCP Validators | `validateMcpSpec()`, `validateMcpConfigFile()` |
666
+ | `utils/model-canonicalization.js` | Direct-first id canonicalization, guarded by `classifyModel` | `directFormIfSafe()`, `directFormIfProven()`, `namespaceFetchFailed()`, `vendorOfId()` |
667
+ | `utils/model-catalog.js` | OpenRouter model catalog cache (F3 #18 / F5 foundation). | `getCatalog()`, `refreshCatalog()`, `catalogPath()`, `getCatalogInfo()`, `readCache()` |
668
+ | `utils/model-ceilings-modelsdev.js` | #218 P3 — output ceilings for the direct-provider catalog rows. | `enrichCeilings()`, `fillCeilings()`, `needsFillCount()`, `limitsFromModelsDev()`, `emptyOutcome()` |
669
+ | `utils/model-classification.js` | Tri-state catalog classification (#61). | `classifyModel()` |
670
+ | `utils/model-descriptor.js` | Model-descriptor grammar + RouteResult factories (#61). | `GATEWAY_MODES()`, `parseDescriptor()`, `resolved()`, `selectionRequired()`, `routeError()` |
671
+ | `utils/model-fetcher.js` | Model Fetcher | `fetchModelsFromProvider()`, `fetchAllModels()`, `fetchAllModelsDetailed()`, `fetchModelsFromProviderDetailed()`, `providersToFetch()` |
672
+ | `utils/model-input-default.js` | | `resolveModelInputOrDefault()` |
673
+ | `utils/model-output-limit.js` | Issue #218 — the per-model `limit` descriptor amicus hands opencode. | `normalizeOutputBudget()`, `buildLimitLookup()`, `computeModelLimit()`, `positiveCount()` |
674
+ | `utils/model-shortlist.js` | Vendor model shortlist (#138) -- the family -> model second level. | `buildModelShortlist()`, `compareShortlistRows()`, `SHORTLIST_LIMIT()` |
675
+ | `utils/model-tiers.js` | Per-vendor cost tiers (economy/balanced/frontier) + resolution against the | `TIERS()`, `TIER_ORDER()`, `resolveTier()` |
676
+ | `utils/model-validator.js` | Model Validator | `filterRelevantModels()`, `normalizeModelId()`, `validateAgainstCatalog()`, `warnIfNotInCatalog()`, `promptRouteSelection()` |
677
+ | `utils/no-output-backstop.js` | v4.6.2 PR2 (spec §5, D4): fail a headless leg fast when the model produces | `resolveNoOutputBackstopMs()`, `createNoOutputBackstop()`, `DEFAULT_NO_OUTPUT_BACKSTOP_MS()` |
678
+ | `utils/node-version-guard.js` | | `checkNodeVersion()`, `MIN_NODE()` |
679
+ | `utils/openrouter-credit.js` | The OpenRouter credit/limit probe, split out of api-key-validation.js to keep | `checkOpenRouterCredit()`, `OPENROUTER_NO_CREDIT_WARNING()`, `OPENROUTER_FREE_TIER_WARNING()` |
680
+ | `utils/output-length.js` | #218 PR 3: name the "Mode 2" death. | `OUTPUT_LENGTH_PREFIX()`, `isOutputLengthDeath()`, `formatOutputLengthReason()` |
681
+ | `utils/path-fence.js` | Shared realpath-containment fence. | `isRealpathContained()`, `containsOnDisk()` |
682
+ | `utils/path-setup.js` | | `ensureNodeModulesBinInPath()`, `hasOpencodeBinary()`, `opencodeRoots()` |
683
+ | `utils/port-pid.js` | Cross-platform listener-PID lookup. | `findListenerPid()` |
684
+ | `utils/pricing.js` | | `emptyUsageTotals()`, `sumPerMessageUsage()`, `lookupPricing()`, `hasObservedTokens()`, `resolveLegCost()` |
685
+ | `utils/project-path.js` | Canonical project-path helper. | `canonicalProjectPath()` |
686
+ | `utils/project-root-sanity.js` | | `assessProjectRoot()`, `looksLikeInstallDir()`, `INSTALL_PATTERNS()` |
687
+ | `utils/prompt-source.js` | | `resolvePromptSource()` |
688
+ | `utils/provider-default-picker.js` | Provider-default picker core (Part 2, Task 4). | `buildProviderDefaultChoices()`, `applyProviderDefault()`, `pricePerMInputFrom()`, `directFormIfSafe()`, `directFormIfProven()` |
689
+ | `utils/provider-default-prompt.js` | Provider-default prompt flow (Part 2, Task 6/7 shared helper). | `runProviderDefaultFlow()`, `formatPrice()`, `formatRow()` |
690
+ | `utils/provider-registry.js` | Provider-capability registry — the single source of truth for provider | `PROVIDERS()`, `getProvider()`, `isDirectProvider()`, `listDirectProviders()`, `PROVIDER_ENV_MAP()` |
691
+ | `utils/quick-picks.js` | Quick-pick resolution (wizard Step 2) — resolves each curated family to | `compareIdsDesc()`, `canonicalRoutesFor()`, `pickCurrent()`, `resolveQuickPicks()`, `toLiveSeedAliases()` |
692
+ | `utils/read-slice.js` | Byte-bounded slicing for amicus_read (15a.3 / B17). | `sliceForRead()`, `READ_CAP_BYTES()` |
693
+ | `utils/remediation-hints.js` | | |
694
+ | `utils/result-schema-rebuild.js` | | `buildRunResultFromSession()`, `buildWaveResultFromSession()` |
695
+ | `utils/result-schema-version.js` | The single SCHEMA_VERSION constant shared by result-schema.js and | `SCHEMA_VERSION()` |
696
+ | `utils/result-schema.js` | | `SCHEMA_VERSION()`, `TERMINAL_STATUSES()`, `durationBetween()`, `statusFromResult()`, `buildRunResult()` |
697
+ | `utils/route-error.js` | Shared renderer (#61 Task 6.1): turns a router RouteResult — an error or a | `toStructuredError()`, `toCliMessage()`, `toErrorDocFields()`, `REASON_TEXT()`, `ROUTE_ERROR_REASONS()` |
698
+ | `utils/route-launch.js` | Route-launch views (#61 gateway routing integration, Task 4.2). | `buildLaunchKeys()`, `getRouteCatalogInfo()`, `resolveRouteForLaunch()`, `buildSuggestions()`, `ROUTE_VERSION()` |
699
+ | `utils/route-suggestions.js` | | `buildSuggestions()`, `applySuggestions()` |
700
+ | `utils/server-setup.js` | Server Setup Utilities | `DEFAULT_PORT()`, `LOCK_RETRY_DELAYS_MS()`, `isPortInUse()`, `getPortPid()`, `killPortProcess()` |
701
+ | `utils/session-abort.js` | Session abort utilities: signal handler installation and terminal metadata writes. | `markTerminal()`, `markAborted()`, `installSignalAbort()`, `idleBackstopTeardown()` |
702
+ | `utils/session-index-prune.js` | | `listStaleSessionIndexEntries()`, `pruneStaleSessionIndexEntries()`, `evaluateSessionIndexPrune()` |
703
+ | `utils/session-index-tmp-sweep.js` | | `AGE_THRESHOLD_MS()`, `listSessionIndexTmpFiles()`, `unlinkSessionIndexTmp()`, `evaluateSessionIndexTmpSweep()` |
704
+ | `utils/session-index.js` | Global session index (issue #40). | `INDEX_FILENAME()`, `recordSession()`, `lookupSessionProject()`, `readIndex()` |
705
+ | `utils/session-lock.js` | | `acquireLock()`, `releaseLock()`, `isLockStale()`, `isPidAlive()` |
706
+ | `utils/session-metadata-tmp-sweep.js` | | `AGE_THRESHOLD_MS()`, `listSessionMetadataTmpFiles()`, `unlinkSessionMetadataTmp()`, `evaluateSessionMetadataTmpSweep()` |
707
+ | `utils/session-path.js` | Session path resolution. | `safeSessionDir()`, `safeSessionDirUnder()` |
708
+ | `utils/session-status.js` | #202: render the engine's SESSION STATUS as a clause on a leg's death report. | `formatSessionStatusSuffix()`, `MAX_STATUS_MESSAGE_CHARS()` |
709
+ | `utils/shared-server.js` | | `SharedServerManager()` |
710
+ | `utils/spend-ledger.js` | | `appendSpend()`, `readSpendRows()`, `SPEND_LEDGER_FILE()`, `SPEND_LEDGER_SCHEMA_VERSION()` |
711
+ | `utils/start-helpers.js` | Start Command Helpers | `resolveLaunchModel()`, `deriveAlias()`, `maybeOfferProviderDefaults()` |
712
+ | `utils/text-sanitize.js` | One third-party string, safe to render: no escapes, no bidi, one short line. | `collapseExcerpt()`, `MAX_EXCERPT_CHARS()` |
713
+ | `utils/thinking-validators.js` | Thinking Level Validators | `VARIANT_LEVELS()`, `validateThinkingLevel()` |
714
+ | `utils/ttft.js` | The one honesty predicate for the time-to-first-token probe (v4.9 W13). | `isMeasuredTtft()` |
715
+ | `utils/untrusted-fence.js` | Untrusted sidecar output fence. | `fenceSidecarOutput()`, `defangOutboundFenceTags()`, `OUTBOUND_FENCE_TAGS()` |
716
+ | `utils/update-notice.js` | The MCP server is the one entry point that skips bin/amicus.js's update | `classifySelfInstall()`, `upgradeInstruction()`, `buildUpdateNotice()`, `maybeAppendUpdateNotice()`, `guideUpdateLine()` |
717
+ | `utils/update-notifier-loader.js` | update-notifier Loader | `loadUpdateNotifier()` |
718
+ | `utils/updater.js` | Updater Module | `initUpdateCheck()`, `getUpdateInfo()`, `notifyUpdate()`, `performUpdate()` |
719
+ | `utils/validators.js` | Input Validators | `VALID_AGENT_MODES()`, `PROVIDER_KEY_MAP()`, `VARIANT_LEVELS()`, `TASK_ID_PATTERN()`, `validateTaskId()` |
720
+ | `utils/version-info.js` | After an `npm i -g amicus` upgrade, a long-lived MCP server process keeps | `RUNNING_VERSION()`, `readOnDiskVersion()`, `versionWarning()`, `PKG_PATH()` |
721
+ | `workspace/artifact-guard.js` | Council Workspace — artifact read guard (v4.4 §4.5 workspace:read-artifact). | `artifactAllowlist()`, `isSeatTable()`, `readRunArtifact()`, `isRealpathContained()`, `FIXED_ARTIFACTS()` |
722
+ | `workspace/artifact-names.js` | Council Workspace — artifact NAME derivation (v4.8 PR5a). | `artifactAllowlist()`, `isSeatTable()`, `orphanExonerations()`, `FIXED_ARTIFACTS()`, `DEBATE_ARTIFACTS()` |
723
+ | `workspace/blind-mode.js` | Council Workspace — blind-mode name mapping (v4.4 §6.3). | `buildNamePairs()`, `labelFor()`, `pairFor()` |
724
+ | `workspace/fold-format.js` | Council Workspace — fold payload builder (v4.4 §7). | `buildFoldText()` |
725
+ | `workspace/live-normalize.js` | Council Workspace — live-doc normalization (v4.4 §3 A1/A2/A4 seam). | `normalizeLive()` |
726
+ | `workspace/matrix-model.js` | Council Workspace — adjudication matrix view model (v4.4 §5.2). | `buildMatrixModel()` |
727
+ | `workspace/run-detail.js` | Council Workspace — run detail: defensive parse of run.json / tally.json / | `getRunDetail()`, `costPanel()`, `TERMINAL_STATUSES()`, `STAGE_LABELS()` |
728
+ | `workspace/run-scan.js` | Council Workspace — run discovery (v4.4 spec §4.3 / §5.1). | `scanCouncilRuns()`, `readPointer()`, `POINTER_RE()` |
729
+ | `workspace/seat-space.js` | Council Workspace — the seat-space PREDICATES (v4.8 PR5b). | `isSeatTable()`, `orphanExonerations()` |
730
+ <!-- /AUTO:modules -->
731
+
732
+ ---