@aragon-agent/cli 0.5.8 → 0.5.9

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 (123) hide show
  1. package/CHANGELOG.md +279 -0
  2. package/README.md +1429 -1163
  3. package/dist/agent/coalesce.d.ts +13 -0
  4. package/dist/agent/coalesce.js +50 -11
  5. package/dist/agent/controller.d.ts +141 -2
  6. package/dist/agent/controller.js +396 -4
  7. package/dist/agent/headless.d.ts +8 -0
  8. package/dist/agent/headless.js +40 -0
  9. package/dist/agent/reducer.d.ts +245 -3
  10. package/dist/agent/reducer.js +490 -17
  11. package/dist/agent/retry-view.d.ts +68 -0
  12. package/dist/agent/retry-view.js +95 -0
  13. package/dist/agent/system-prompt.d.ts +11 -0
  14. package/dist/agent/system-prompt.js +2 -0
  15. package/dist/cli.js +86 -2
  16. package/dist/commands/builtins.d.ts +1 -1
  17. package/dist/commands/builtins.js +308 -2
  18. package/dist/config/cli-commands.d.ts +53 -2
  19. package/dist/config/cli-commands.js +136 -3
  20. package/dist/config/env.d.ts +6 -3
  21. package/dist/config/env.js +103 -3
  22. package/dist/config/load.d.ts +49 -0
  23. package/dist/config/load.js +83 -1
  24. package/dist/config/schema.d.ts +212 -2
  25. package/dist/config/schema.js +207 -1
  26. package/dist/config/store.js +20 -1
  27. package/dist/fast/critique.d.ts +43 -0
  28. package/dist/fast/critique.js +62 -0
  29. package/dist/fast/digest.d.ts +42 -0
  30. package/dist/fast/digest.js +85 -0
  31. package/dist/fast/frames.d.ts +99 -0
  32. package/dist/fast/frames.js +180 -0
  33. package/dist/fast/limits.d.ts +98 -0
  34. package/dist/fast/limits.js +98 -0
  35. package/dist/fast/prompt.d.ts +72 -0
  36. package/dist/fast/prompt.js +94 -0
  37. package/dist/fast/resolve.d.ts +43 -0
  38. package/dist/fast/resolve.js +105 -0
  39. package/dist/fast/review-call.d.ts +99 -0
  40. package/dist/fast/review-call.js +130 -0
  41. package/dist/fast/reviewer.d.ts +248 -0
  42. package/dist/fast/reviewer.js +664 -0
  43. package/dist/fast/types.d.ts +128 -0
  44. package/dist/fast/types.js +14 -0
  45. package/dist/fast/wiring.d.ts +170 -0
  46. package/dist/fast/wiring.js +316 -0
  47. package/dist/logging/install.d.ts +15 -1
  48. package/dist/logging/install.js +37 -4
  49. package/dist/logging/logger.d.ts +1 -1
  50. package/dist/session/persist.js +57 -1
  51. package/dist/team/normalize.d.ts +26 -1
  52. package/dist/team/normalize.js +23 -3
  53. package/dist/team/prompt.d.ts +11 -0
  54. package/dist/team/prompt.js +10 -0
  55. package/dist/team/report.d.ts +18 -0
  56. package/dist/team/report.js +27 -1
  57. package/dist/team/runtime.d.ts +13 -2
  58. package/dist/team/runtime.js +33 -6
  59. package/dist/team/subagent.d.ts +19 -1
  60. package/dist/team/subagent.js +72 -10
  61. package/dist/team/task-tool.d.ts +26 -0
  62. package/dist/team/task-tool.js +48 -4
  63. package/dist/team/types.d.ts +80 -1
  64. package/dist/tools/bash-tool.js +19 -3
  65. package/dist/tools/diff.d.ts +25 -5
  66. package/dist/tools/diff.js +72 -41
  67. package/dist/tools/file-change-store.d.ts +34 -0
  68. package/dist/tools/file-change-store.js +57 -0
  69. package/dist/tools/fs-tools.d.ts +26 -0
  70. package/dist/tools/fs-tools.js +62 -5
  71. package/dist/tools/index.d.ts +31 -0
  72. package/dist/tools/index.js +7 -1
  73. package/dist/tools/patch.d.ts +115 -0
  74. package/dist/tools/patch.js +453 -0
  75. package/dist/tools/terminal-output.d.ts +107 -0
  76. package/dist/tools/terminal-output.js +198 -0
  77. package/dist/tools/tool-output-store.d.ts +68 -0
  78. package/dist/tools/tool-output-store.js +102 -0
  79. package/dist/ui/ActivityLine.d.ts +48 -0
  80. package/dist/ui/ActivityLine.js +22 -0
  81. package/dist/ui/App.d.ts +1 -4
  82. package/dist/ui/App.js +273 -37
  83. package/dist/ui/BottomStatusRow.d.ts +43 -0
  84. package/dist/ui/BottomStatusRow.js +14 -0
  85. package/dist/ui/Composer.d.ts +1 -6
  86. package/dist/ui/Composer.js +2 -2
  87. package/dist/ui/PromptInput.d.ts +1 -15
  88. package/dist/ui/PromptInput.js +1 -38
  89. package/dist/ui/StatusBar.d.ts +37 -0
  90. package/dist/ui/StatusBar.js +5 -3
  91. package/dist/ui/TeamPanel.d.ts +5 -4
  92. package/dist/ui/TeamPanel.js +1 -1
  93. package/dist/ui/TodoPanel.d.ts +5 -4
  94. package/dist/ui/Transcript.d.ts +26 -3
  95. package/dist/ui/Transcript.js +76 -10
  96. package/dist/ui/activity-phrases.d.ts +33 -0
  97. package/dist/ui/activity-phrases.js +50 -0
  98. package/dist/ui/entries/AssistantEntry.d.ts +20 -0
  99. package/dist/ui/entries/AssistantEntry.js +3 -2
  100. package/dist/ui/entries/DiffView.d.ts +67 -0
  101. package/dist/ui/entries/DiffView.js +103 -0
  102. package/dist/ui/entries/FastCard.d.ts +53 -0
  103. package/dist/ui/entries/FastCard.js +87 -0
  104. package/dist/ui/entries/RetryCard.d.ts +56 -0
  105. package/dist/ui/entries/RetryCard.js +60 -0
  106. package/dist/ui/entries/TeamCard.js +6 -1
  107. package/dist/ui/entries/ToolCard.d.ts +38 -1
  108. package/dist/ui/entries/ToolCard.js +68 -5
  109. package/dist/ui/glyphs.d.ts +9 -0
  110. package/dist/ui/glyphs.js +2 -0
  111. package/dist/ui/layout/AppShell.d.ts +13 -22
  112. package/dist/ui/layout/AppShell.js +3 -38
  113. package/dist/ui/layout/virtual-window.d.ts +1 -1
  114. package/dist/ui/layout/virtual-window.js +109 -5
  115. package/dist/ui/overlays/HelpOverlay.js +16 -2
  116. package/dist/ui/overlays/SettingsScreen.d.ts +82 -1
  117. package/dist/ui/overlays/SettingsScreen.js +147 -1
  118. package/dist/ui/transcript-text.js +27 -0
  119. package/dist/ui/use-wheel-routing.d.ts +16 -32
  120. package/dist/ui/use-wheel-routing.js +21 -38
  121. package/package.json +2 -2
  122. package/dist/ui/layout/regions.d.ts +0 -55
  123. package/dist/ui/layout/regions.js +0 -52
@@ -8,6 +8,19 @@
8
8
  * App buffers per-event actions and runs them through this before dispatching,
9
9
  * so a fast token stream re-renders the transcript once per frame instead of
10
10
  * once per token. The reducer and event semantics are unchanged.
11
+ *
12
+ * A THIRD MERGED KIND ARRIVED WITH THE LIVE TOOL TAIL
13
+ * (agent-activity-presentation-live §3.3.2 / D-30), and it merges differently:
14
+ * `toolOutputDelta` carries the store's WHOLE tail rather than an increment, so
15
+ * consecutive ones with the same `toolCallId` collapse to the LAST rather than
16
+ * concatenating, and a differing id starts a new pending action because merging
17
+ * across ids would paint one command's output onto another's card.
18
+ *
19
+ * ONE PENDING SLOT, DISCRIMINATED, NEVER TWO (P1-5). A second, independent slot
20
+ * for the object-shaped payload would let a chunk overtake a token and reorder
21
+ * the two streams — exactly what I-L4-1 (`ui/render-governor.ts:14-19`) forbids:
22
+ * "the governor changes only HOW OFTEN the view updates. Never what is
23
+ * dispatched, never the order."
11
24
  */
12
25
  import type { ViewAction } from './reducer.js';
13
26
  /** Merge consecutive same-kind deltas; flush on kind change or a non-delta. */
@@ -8,28 +8,67 @@
8
8
  * App buffers per-event actions and runs them through this before dispatching,
9
9
  * so a fast token stream re-renders the transcript once per frame instead of
10
10
  * once per token. The reducer and event semantics are unchanged.
11
+ *
12
+ * A THIRD MERGED KIND ARRIVED WITH THE LIVE TOOL TAIL
13
+ * (agent-activity-presentation-live §3.3.2 / D-30), and it merges differently:
14
+ * `toolOutputDelta` carries the store's WHOLE tail rather than an increment, so
15
+ * consecutive ones with the same `toolCallId` collapse to the LAST rather than
16
+ * concatenating, and a differing id starts a new pending action because merging
17
+ * across ids would paint one command's output onto another's card.
18
+ *
19
+ * ONE PENDING SLOT, DISCRIMINATED, NEVER TWO (P1-5). A second, independent slot
20
+ * for the object-shaped payload would let a chunk overtake a token and reorder
21
+ * the two streams — exactly what I-L4-1 (`ui/render-governor.ts:14-19`) forbids:
22
+ * "the governor changes only HOW OFTEN the view updates. Never what is
23
+ * dispatched, never the order."
11
24
  */
12
- function isDelta(action) {
25
+ function isTextDelta(action) {
13
26
  return action.type === 'textDelta' || action.type === 'thinkingDelta';
14
27
  }
28
+ function isToolOutputDelta(action) {
29
+ return action.type === 'toolOutputDelta';
30
+ }
15
31
  /** Merge consecutive same-kind deltas; flush on kind change or a non-delta. */
16
32
  export function mergeDeltas(actions) {
17
33
  const out = [];
18
- let pendingType = null;
19
- let pendingDelta = '';
34
+ let pending = null;
20
35
  const flush = () => {
21
- if (pendingType !== null) {
22
- out.push({ type: pendingType, delta: pendingDelta });
23
- pendingType = null;
24
- pendingDelta = '';
36
+ if (pending !== null) {
37
+ out.push(pending.action);
38
+ pending = null;
25
39
  }
26
40
  };
27
41
  for (const action of actions) {
28
- if (isDelta(action)) {
29
- if (pendingType !== null && pendingType !== action.type)
42
+ // Read into a local before the branch: `flush` clears the slot, so the value
43
+ // a merge decision needs is the one held HERE, before any flush.
44
+ //
45
+ // The assertion restores the DECLARED type and asserts nothing beyond it.
46
+ // `flush` assigns `pending = null` from inside a closure, which TypeScript's
47
+ // flow analysis does not model, so it pins the reference at this point to
48
+ // the declaration's `null` and every `prev.kind` below reads as `never`.
49
+ const prev = pending;
50
+ if (isTextDelta(action)) {
51
+ // A pending TOOL tail flushes first, so a chunk cannot overtake a token.
52
+ const carry = prev !== null && prev.kind === 'text' && prev.action.type === action.type
53
+ ? prev.action.delta
54
+ : null;
55
+ if (carry === null)
56
+ flush();
57
+ pending = {
58
+ kind: 'text',
59
+ action: { type: action.type, delta: (carry ?? '') + action.delta },
60
+ };
61
+ }
62
+ else if (isToolOutputDelta(action)) {
63
+ // A pending TEXT run flushes first, for the mirror-image reason, and so
64
+ // does a tail belonging to a DIFFERENT call: merging across ids would
65
+ // paint one command's output onto another's card.
66
+ const merges = prev !== null && prev.kind === 'tool' && prev.action.toolCallId === action.toolCallId;
67
+ if (!merges)
30
68
  flush();
31
- pendingType = action.type;
32
- pendingDelta += action.delta;
69
+ // LAST WINS. The payload is the store's whole tail rather than an
70
+ // increment, so merging means replacing (D-30).
71
+ pending = { kind: 'tool', action };
33
72
  }
34
73
  else {
35
74
  flush();
@@ -8,10 +8,14 @@
8
8
  * success — that promise resolves even on failure. Success/failure is derived
9
9
  * from the event stream by the reducer (TUI) and the headless writer.
10
10
  */
11
- import { ModelRegistry, type AgentEvent, type AgentTool, type Message, type ModelInfo, type ProviderRegistry, type ThinkingLevel } from '@aragon-agent/core';
12
- import type { CliConfig, TeamConfig, ThemeName, TodoConfig } from '../config/schema.js';
11
+ import { ModelRegistry, type AgentEvent, type AgentTool, type Message, type ModelInfo, type ModelRef, type ProviderRegistry, type ThinkingLevel } from '@aragon-agent/core';
12
+ import type { CliConfig, FastConfig, RetryConfig, TeamConfig, ThemeName, TodoConfig } from '../config/schema.js';
13
13
  import { type ConfirmRequest } from '../tools/index.js';
14
+ import { type ToolOutputListener } from '../tools/tool-output-store.js';
15
+ import type { FilePatch } from '../tools/patch.js';
14
16
  import type { TeamEvent, TeamSnapshot } from '../team/types.js';
17
+ import { type FastStatus } from '../fast/wiring.js';
18
+ import type { FastEventListener } from '../fast/types.js';
15
19
  import type { TodoEventListener, TodoSnapshot } from '../todo/types.js';
16
20
  import { type HumanInputGate } from '../tools/human-input.js';
17
21
  import { SkillService, type ApprovalGate } from '../skills/service.js';
@@ -107,6 +111,44 @@ export declare class AgentController {
107
111
  private readonly todos;
108
112
  /** Static: whether this session could ever render the rail. See the dep. */
109
113
  private readonly todoPanelCapable;
114
+ /**
115
+ * Structured file diffs on their way to the UI (agent-activity-presentation
116
+ * §3.3.5). A bounded, take-once ring; see `file-change-store.ts` for why each
117
+ * of those three words is load-bearing.
118
+ *
119
+ * DECLARED WITH AN INITIALIZER, so it exists before `createBuiltinTools` runs
120
+ * in the constructor body and the recorder closure it hands over is valid from
121
+ * the first tool call.
122
+ */
123
+ private readonly fileChanges;
124
+ /**
125
+ * A running tool's output on its way to the UI
126
+ * (agent-activity-presentation-live §3.1.3).
127
+ *
128
+ * NULL WHEN THE FEATURE IS OFF (P1-6). `fileChanges` next door is declared
129
+ * with an initializer because it is unconditional; this one cannot be, since a
130
+ * field initializer cannot read a constructor parameter -- and an
131
+ * unconditional initializer would allocate on every construction and make
132
+ * AC-31's "no store is allocated" false by construction. `private readonly
133
+ * fast: FastWiring | null` below is the same declaration shape in the same
134
+ * class.
135
+ *
136
+ * ASSIGNED IN THE CONSTRUCTOR BODY, ABOVE THE `createBuiltinTools` CALL, not
137
+ * near `this.fast` which runs after it. The binding there is spread
138
+ * CONDITIONALLY on this field, so an assignment placed after the call would
139
+ * read `undefined`, add no property, and produce a build in which the feature
140
+ * is silently off with the key on.
141
+ */
142
+ private readonly toolOutputs;
143
+ private readonly outputListeners;
144
+ private readonly fast;
145
+ /**
146
+ * Set SYNCHRONOUSLY by `abort()` before `agent.abort()` (§3.5.4a guard 1).
147
+ * Cleared at the next `agent_start`.
148
+ */
149
+ private abortRequested;
150
+ /** User messages queued since the last `turn_start` (§3.5.4a guard 2). */
151
+ private userSteerCount;
110
152
  constructor(config: CliConfig, deps?: ControllerDeps);
111
153
  private resolveKey;
112
154
  /**
@@ -299,12 +341,56 @@ export declare class AgentController {
299
341
  restoreTodos(items: unknown): void;
300
342
  /** `/todo clear`. A user override of a projection; refused mid-run by `/todo`. */
301
343
  clearTodos(): void;
344
+ getRetryConfig(): RetryConfig;
345
+ /**
346
+ * Adopt a new retry config for this session AND PUSH IT INTO THE REGISTRY.
347
+ *
348
+ * THE SECOND CALL IS REQUIRED, NOT A NICETY (§6.3). Without it `/retry off`
349
+ * would persist correctly and change nothing until the next launch — the
350
+ * precise failure `config/schema.ts` warns about twice already, and the one a
351
+ * user reports as "the setting does nothing".
352
+ *
353
+ * Clamped here as well as on the persist path, so a bad value can reach neither
354
+ * the runtime nor the file.
355
+ */
356
+ setRetryConfig(patch: Partial<RetryConfig>): RetryConfig;
302
357
  setModel(provider: string, model: string, baseUrl?: string): void;
303
358
  setThinkingLevel(level: ThinkingLevel): void;
304
359
  setMaxTokens(value: number | undefined): void;
305
360
  setApiKey(provider: string, key: string): void;
306
361
  setCwd(cwd: string): void;
307
362
  getCwd(): string;
363
+ /**
364
+ * The structured diff a file tool left behind, CONSUMED ONCE.
365
+ *
366
+ * Called by `reduceEvent` on `tool_execution_end` and nowhere else, which is
367
+ * what keeps the store at constant size however many files a session edits.
368
+ * `undefined` is an ordinary answer — a tool that records nothing, a toolset
369
+ * built without a recorder, or an entry the 64-write ring has already evicted
370
+ * — and every one of those falls back to `ToolPreview`.
371
+ */
372
+ takeFilePatch(toolCallId: string): FilePatch | undefined;
373
+ /**
374
+ * Sanitise a chunk into the store and hand the resulting tail to the view.
375
+ *
376
+ * SYNCHRONOUS, INSIDE THE CHILD-PROCESS DATA HANDLER. The alternative (queue
377
+ * plus timer) adds a second clock to a component that already has one, and
378
+ * `App` coalesces at the other end anyway (D-34).
379
+ *
380
+ * EVERY LISTENER IS WRAPPED, and that is not defensive noise (R-5 / AC-35): a
381
+ * throw here propagates into `child.stdout.on('data')`, which is the reason a
382
+ * render-side bug could otherwise kill a ten-minute build. `debug` rather than
383
+ * `warn` because a listener that throws once throws on every chunk.
384
+ */
385
+ private emitToolOutput;
386
+ /**
387
+ * Subscribe to the CLI-local live tool-output stream (§3.1.3).
388
+ *
389
+ * Returns a no-op unsubscribe when `liveToolOutput` was off at construction,
390
+ * so every caller can subscribe unconditionally -- the contract
391
+ * `subscribeTeam` / `subscribeTodos` / `subscribeFast` already set.
392
+ */
393
+ subscribeToolOutput(listener: ToolOutputListener): () => void;
308
394
  clearMessages(): void;
309
395
  /** Read-only view of the live system prompt (regression tests, /debug). */
310
396
  getSystemPrompt(): string;
@@ -316,6 +402,59 @@ export declare class AgentController {
316
402
  getModelRegistry(): ModelRegistry;
317
403
  /** Resolve `ModelInfo` for the active model, falling back to a runtime model. */
318
404
  getModelInfo(): ModelInfo;
405
+ /**
406
+ * Resolve `ModelInfo` for ANY model (fast-model-tier §3.6 / RV-4).
407
+ *
408
+ * ONE RESOLUTION PATH, which is the same reason §3.2 has exactly one
409
+ * `resolveFastTier`: `getModelInfo()` above is now a call into this, so "the
410
+ * cost table for the model that actually billed" cannot drift from "the cost
411
+ * table for the session's model" as two separate bodies.
412
+ */
413
+ getModelInfoFor(ref: Pick<ModelRef, 'providerId' | 'modelId'>): ModelInfo;
414
+ /**
415
+ * Whether the STATIC table knows this model's price (C-11 / RV-4).
416
+ *
417
+ * `buildRuntimeModel` returns `cost: { input: 0, output: 0 }` for a model it
418
+ * has never seen — a table of zeros, not a missing one — so every consumer
419
+ * that renders spend needs to be able to tell "free" from "unknown". The fast
420
+ * tier is precisely where an unrecognised id is likely, and `$0.00` on a
421
+ * feature that is spending money is the same class of lie as pricing a Haiku
422
+ * child at Sonnet rates.
423
+ */
424
+ isPricedModel(ref: Pick<ModelRef, 'providerId' | 'modelId'>): boolean;
425
+ /** Whether `task`'s schema carries `model`. Fixed at construction (C-2). */
426
+ isFastRegistered(): boolean;
427
+ /** Whether the tier will actually be used. Flipped live by `/fast on|off`. */
428
+ isFastEnabled(): boolean;
429
+ /**
430
+ * Flip the live switch and re-render the prompt.
431
+ *
432
+ * Turning it ON in a session that started without the tier deliberately does
433
+ * NOT register it: the tool array is immutable (C-2), and advertising a schema
434
+ * field that is not there is the dead end `/team on` already documents.
435
+ * `/fast` reports that honestly by checking `isFastRegistered()` first.
436
+ */
437
+ setFastEnabled(enabled: boolean): void;
438
+ getFastConfig(): FastConfig;
439
+ /**
440
+ * Adopt a new fast config for this session.
441
+ *
442
+ * THE RE-RESOLUTION IS NOT OPTIONAL (§3.2 rule 8). `App` reads
443
+ * `controller.getConfig()` on every render and the block interpolates the
444
+ * model id, so a persist without this call reports success and changes
445
+ * nothing until relaunch — the failure `/todo panel` records (P1-2).
446
+ */
447
+ setFastConfig(patch: Partial<FastConfig>): FastConfig;
448
+ /** Everything `/fast status`, the settings line and the chip read. */
449
+ getFastStatus(): FastStatus;
450
+ /**
451
+ * Subscribe to the CLI-local fast event stream.
452
+ *
453
+ * Returns a no-op unsubscribe when the tier was off at construction, so every
454
+ * caller can subscribe unconditionally — the contract `subscribeTeam` and
455
+ * `subscribeTodos` already set.
456
+ */
457
+ subscribeFast(listener: FastEventListener): () => void;
319
458
  /** List usable tools (name + description) for the /tools command. */
320
459
  listTools(): AgentTool[];
321
460
  }