@namzu/cli 20.0.0 → 21.0.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.
Files changed (155) hide show
  1. package/CHANGELOG.md +255 -0
  2. package/README.md +42 -2
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +24 -2
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/acp.d.ts.map +1 -1
  7. package/dist/commands/acp.js +6 -1
  8. package/dist/commands/acp.js.map +1 -1
  9. package/dist/commands/run-stream.d.ts.map +1 -1
  10. package/dist/commands/run-stream.js +9 -1
  11. package/dist/commands/run-stream.js.map +1 -1
  12. package/dist/commands/run.d.ts.map +1 -1
  13. package/dist/commands/run.js +14 -11
  14. package/dist/commands/run.js.map +1 -1
  15. package/dist/config/load.d.ts.map +1 -1
  16. package/dist/config/load.js +21 -0
  17. package/dist/config/load.js.map +1 -1
  18. package/dist/config/schema.d.ts +11 -4
  19. package/dist/config/schema.d.ts.map +1 -1
  20. package/dist/config/schema.js.map +1 -1
  21. package/dist/doctor/checks/chain.d.ts.map +1 -1
  22. package/dist/doctor/checks/chain.js +11 -5
  23. package/dist/doctor/checks/chain.js.map +1 -1
  24. package/dist/doctor/checks/credentials.d.ts.map +1 -1
  25. package/dist/doctor/checks/credentials.js +5 -1
  26. package/dist/doctor/checks/credentials.js.map +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/integrations/providers/access.d.ts +7 -0
  31. package/dist/integrations/providers/access.d.ts.map +1 -0
  32. package/dist/integrations/providers/access.js +17 -0
  33. package/dist/integrations/providers/access.js.map +1 -0
  34. package/dist/integrations/providers/discover.d.ts +17 -54
  35. package/dist/integrations/providers/discover.d.ts.map +1 -1
  36. package/dist/integrations/providers/discover.js +46 -58
  37. package/dist/integrations/providers/discover.js.map +1 -1
  38. package/dist/integrations/providers/harness-credentials.d.ts +14 -0
  39. package/dist/integrations/providers/harness-credentials.d.ts.map +1 -1
  40. package/dist/integrations/providers/harness-credentials.js +46 -0
  41. package/dist/integrations/providers/harness-credentials.js.map +1 -1
  42. package/dist/integrations/providers/model-reasoning.d.ts +4 -0
  43. package/dist/integrations/providers/model-reasoning.d.ts.map +1 -0
  44. package/dist/integrations/providers/model-reasoning.js +46 -0
  45. package/dist/integrations/providers/model-reasoning.js.map +1 -0
  46. package/dist/integrations/providers/register.d.ts +1 -1
  47. package/dist/integrations/providers/register.d.ts.map +1 -1
  48. package/dist/integrations/providers/register.js +11 -1
  49. package/dist/integrations/providers/register.js.map +1 -1
  50. package/dist/integrations/providers/registry.d.ts +4 -4
  51. package/dist/integrations/providers/registry.d.ts.map +1 -1
  52. package/dist/integrations/providers/registry.js +23 -0
  53. package/dist/integrations/providers/registry.js.map +1 -1
  54. package/dist/integrations/sessions/context-inventory.d.ts +4 -0
  55. package/dist/integrations/sessions/context-inventory.d.ts.map +1 -0
  56. package/dist/integrations/sessions/context-inventory.js +44 -0
  57. package/dist/integrations/sessions/context-inventory.js.map +1 -0
  58. package/dist/integrations/sessions/conversation-search.d.ts +60 -0
  59. package/dist/integrations/sessions/conversation-search.d.ts.map +1 -0
  60. package/dist/integrations/sessions/conversation-search.js +461 -0
  61. package/dist/integrations/sessions/conversation-search.js.map +1 -0
  62. package/dist/integrations/sessions/task-context.d.ts +4 -0
  63. package/dist/integrations/sessions/task-context.d.ts.map +1 -0
  64. package/dist/integrations/sessions/task-context.js +73 -0
  65. package/dist/integrations/sessions/task-context.js.map +1 -0
  66. package/dist/integrations/subagents/activity.d.ts +3 -1
  67. package/dist/integrations/subagents/activity.d.ts.map +1 -1
  68. package/dist/integrations/subagents/activity.js +20 -2
  69. package/dist/integrations/subagents/activity.js.map +1 -1
  70. package/dist/integrations/subagents/runtime.d.ts +7 -4
  71. package/dist/integrations/subagents/runtime.d.ts.map +1 -1
  72. package/dist/integrations/subagents/runtime.js +105 -17
  73. package/dist/integrations/subagents/runtime.js.map +1 -1
  74. package/dist/memory/io.d.ts +12 -0
  75. package/dist/memory/io.d.ts.map +1 -0
  76. package/dist/memory/io.js +177 -0
  77. package/dist/memory/io.js.map +1 -0
  78. package/dist/memory/presentation.d.ts +4 -1
  79. package/dist/memory/presentation.d.ts.map +1 -1
  80. package/dist/memory/presentation.js +16 -2
  81. package/dist/memory/presentation.js.map +1 -1
  82. package/dist/memory/store.d.ts +17 -3
  83. package/dist/memory/store.d.ts.map +1 -1
  84. package/dist/memory/store.js +61 -35
  85. package/dist/memory/store.js.map +1 -1
  86. package/dist/output-schema.d.ts +4 -0
  87. package/dist/output-schema.d.ts.map +1 -0
  88. package/dist/output-schema.js +18 -0
  89. package/dist/output-schema.js.map +1 -0
  90. package/dist/tui/AgentExplorer.d.ts +13 -2
  91. package/dist/tui/AgentExplorer.d.ts.map +1 -1
  92. package/dist/tui/AgentExplorer.js +85 -23
  93. package/dist/tui/AgentExplorer.js.map +1 -1
  94. package/dist/tui/App.d.ts.map +1 -1
  95. package/dist/tui/App.js +454 -64
  96. package/dist/tui/App.js.map +1 -1
  97. package/dist/tui/BrandHeader.d.ts +1 -4
  98. package/dist/tui/BrandHeader.d.ts.map +1 -1
  99. package/dist/tui/BrandHeader.js +2 -6
  100. package/dist/tui/BrandHeader.js.map +1 -1
  101. package/dist/tui/Composer.d.ts +2 -1
  102. package/dist/tui/Composer.d.ts.map +1 -1
  103. package/dist/tui/Composer.js +9 -2
  104. package/dist/tui/Composer.js.map +1 -1
  105. package/dist/tui/PermissionOverlay.d.ts +1 -1
  106. package/dist/tui/PermissionOverlay.d.ts.map +1 -1
  107. package/dist/tui/PermissionOverlay.js +8 -1
  108. package/dist/tui/PermissionOverlay.js.map +1 -1
  109. package/dist/tui/Picker.d.ts.map +1 -1
  110. package/dist/tui/Picker.js +94 -21
  111. package/dist/tui/Picker.js.map +1 -1
  112. package/dist/tui/TextPrompt.d.ts +3 -1
  113. package/dist/tui/TextPrompt.d.ts.map +1 -1
  114. package/dist/tui/TextPrompt.js +55 -9
  115. package/dist/tui/TextPrompt.js.map +1 -1
  116. package/dist/tui/Transcript.d.ts.map +1 -1
  117. package/dist/tui/Transcript.js +1 -1
  118. package/dist/tui/Transcript.js.map +1 -1
  119. package/dist/tui/agent.d.ts +18 -3
  120. package/dist/tui/agent.d.ts.map +1 -1
  121. package/dist/tui/agent.js +174 -58
  122. package/dist/tui/agent.js.map +1 -1
  123. package/dist/tui/model-choices.d.ts +3 -1
  124. package/dist/tui/model-choices.d.ts.map +1 -1
  125. package/dist/tui/model-choices.js +12 -1
  126. package/dist/tui/model-choices.js.map +1 -1
  127. package/dist/tui/model-search.d.ts +4 -0
  128. package/dist/tui/model-search.d.ts.map +1 -0
  129. package/dist/tui/model-search.js +11 -0
  130. package/dist/tui/model-search.js.map +1 -0
  131. package/dist/tui/model-selection-intent.d.ts +8 -0
  132. package/dist/tui/model-selection-intent.d.ts.map +1 -0
  133. package/dist/tui/model-selection-intent.js +96 -0
  134. package/dist/tui/model-selection-intent.js.map +1 -0
  135. package/dist/tui/model-switch-tool.d.ts +7 -0
  136. package/dist/tui/model-switch-tool.d.ts.map +1 -0
  137. package/dist/tui/model-switch-tool.js +74 -0
  138. package/dist/tui/model-switch-tool.js.map +1 -0
  139. package/dist/tui/model-switch.d.ts +35 -0
  140. package/dist/tui/model-switch.d.ts.map +1 -0
  141. package/dist/tui/model-switch.js +106 -0
  142. package/dist/tui/model-switch.js.map +1 -0
  143. package/dist/tui/permission-review.d.ts.map +1 -1
  144. package/dist/tui/permission-review.js +25 -12
  145. package/dist/tui/permission-review.js.map +1 -1
  146. package/dist/tui/run-interruption.d.ts +7 -0
  147. package/dist/tui/run-interruption.d.ts.map +1 -1
  148. package/dist/tui/run-interruption.js +41 -0
  149. package/dist/tui/run-interruption.js.map +1 -1
  150. package/dist/tui/slashCommands.d.ts.map +1 -1
  151. package/dist/tui/slashCommands.js +2 -1
  152. package/dist/tui/slashCommands.js.map +1 -1
  153. package/dist/tui/types.d.ts +3 -1
  154. package/dist/tui/types.d.ts.map +1 -1
  155. package/package.json +8 -7
@@ -1,4 +1,4 @@
1
- import { memoryFilePath, projectMemoryFilePath, userFilePath } from './store.js';
1
+ import { MEMORY_SECTION_MAX_CHARS, memoryFilePath, projectMemoryFilePath, userFilePath, } from './store.js';
2
2
  export const MEMORY_PREVIEW_MAX_CHARS = 2_000;
3
3
  export const MEMORY_PREVIEW_MAX_LINES = 20;
4
4
  function preview(text, path) {
@@ -27,11 +27,25 @@ export function renderMemoryReport(content, options) {
27
27
  if (text)
28
28
  sections.push(`${label}\n${path}\n\n${preview(text, path)}`);
29
29
  };
30
- add('Project memory', content.project, projectMemoryFilePath(options.cwd));
30
+ if (content.project)
31
+ add('Project memory', content.project, projectMemoryFilePath(options.cwd));
31
32
  add('User memory (all projects)', content.memory, memoryFilePath(options.home));
32
33
  add('About you', content.user, userFilePath(options.home));
34
+ sections.push(...formatMemoryDiagnostics(content));
33
35
  return sections.length > 0
34
36
  ? sections.join('\n\n')
35
37
  : 'No saved memory. Use /memory add <text> for this project, or /memory --user add <text> for all projects.';
36
38
  }
39
+ /** Operator notices for refused files; these are not model prompt instructions. */
40
+ export function formatMemoryDiagnostics(content) {
41
+ return (content.diagnostics ?? []).map(({ path, reason }) => `Memory not loaded: ${path} — ${reason}`);
42
+ }
43
+ export function renderMemorySaveResult(result, text) {
44
+ if (!result.appended)
45
+ return `No memory added (${result.path}). Use /memory add <text>.`;
46
+ if (!result.includedInPrompt) {
47
+ return `Saved to ${result.path}, but this note will not be fully included in the next prompt because the section exceeds ${MEMORY_SECTION_MAX_CHARS.toLocaleString('en-US')} characters. Curate that file to include the note.`;
48
+ }
49
+ return `Remembered ${result.scope === 'user' ? 'for every project' : 'for this project'} (${result.path}): ${text}`;
50
+ }
37
51
  //# sourceMappingURL=presentation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"presentation.js","sourceRoot":"","sources":["../../src/memory/presentation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,cAAc,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEpG,MAAM,CAAC,MAAM,wBAAwB,GAAG,KAAK,CAAA;AAC7C,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,CAAA;AAE1C,SAAS,OAAO,CAAC,IAAY,EAAE,IAAY;IAC1C,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAA;IACzD,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,wBAAwB,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;QAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;QAC5C,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,IAAI,GAAG;YAAE,MAAK;QACxC,IAAI,IAAI,KAAK,wBAAwB,GAAG,CAAC;YAAE,GAAG,GAAG,OAAO,CAAA;QACxD,QAAQ,GAAG,OAAO,GAAG,CAAC,CAAA;IACvB,CAAC;IACD,IAAI,GAAG,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IACpC,kEAAkE;IAClE,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAA;IACrC,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM;QAAE,GAAG,IAAI,CAAC,CAAA;IAC9C,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,QAAQ,IAAI,CAAC,MAAM,GAAG,GAAG,wCAAwC,IAAI,GAAG,CAAA;AACrG,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,kBAAkB,CACjC,OAAsB,EACtB,OAAyD;IAEzD,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,MAAM,GAAG,GAAG,CAAC,KAAa,EAAE,IAAmB,EAAE,IAAY,EAAQ,EAAE;QACtE,IAAI,IAAI;YAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,KAAK,IAAI,OAAO,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAA;IACvE,CAAC,CAAA;IACD,GAAG,CAAC,gBAAgB,EAAE,OAAO,CAAC,OAAO,EAAE,qBAAqB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;IAC1E,GAAG,CAAC,4BAA4B,EAAE,OAAO,CAAC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IAC/E,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IAC1D,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC;QACzB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;QACvB,CAAC,CAAC,0GAA0G,CAAA;AAC9G,CAAC"}
1
+ {"version":3,"file":"presentation.js","sourceRoot":"","sources":["../../src/memory/presentation.ts"],"names":[],"mappings":"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"}
@@ -16,8 +16,9 @@
16
16
  * to edit the file — which is the whole point of a curated memory.
17
17
  *
18
18
  * Separate from the kernel's memory store (`save_memory` / `search_memory`),
19
- * which holds what the agent chose to keep and is searched, not injected.
19
+ * which holds structured records retrieved by tools or bounded automatic recall.
20
20
  */
21
+ export { MEMORY_FILE_MAX_BYTES } from './io.js';
21
22
  /** Characters of one section injected before the rest is left to the file. */
22
23
  export declare const MEMORY_SECTION_MAX_CHARS = 8000;
23
24
  export type MemoryScope = 'project' | 'user';
@@ -26,13 +27,18 @@ export declare function userFilePath(home?: string): string;
26
27
  export declare function memoryFilePath(home?: string): string;
27
28
  /** Share checkout memory unless this directory already owns a memory file. */
28
29
  export declare function projectMemoryFilePath(cwd: string): string;
30
+ export interface MemoryDiagnostic {
31
+ readonly path: string;
32
+ readonly reason: string;
33
+ }
29
34
  export interface MemoryContent {
30
35
  readonly user: string | null;
31
36
  readonly memory: string | null;
32
- /** The project's own file; null when no working directory was given or the file is empty. */
37
+ /** The project's own file; null when absent, empty, or refused with a diagnostic. */
33
38
  readonly project: string | null;
39
+ readonly diagnostics?: readonly MemoryDiagnostic[];
34
40
  }
35
- /** Read the user files under `home` and, when `cwd` is given, the project file. */
41
+ /** Read bounded, valid UTF-8 files; distinguish missing/empty files from refused content. */
36
42
  export declare function readMemory(home?: string, cwd?: string): MemoryContent;
37
43
  export declare function composeMemoryPrompt(content: MemoryContent): string | null;
38
44
  export interface AppendMemoryTarget {
@@ -46,4 +52,12 @@ export interface AppendMemoryTarget {
46
52
  * second argument names the application home and means the user scope.
47
53
  */
48
54
  export declare function appendMemory(text: string, target?: string | AppendMemoryTarget): string;
55
+ export interface AppendMemoryResult {
56
+ readonly path: string;
57
+ readonly scope: MemoryScope;
58
+ readonly appended: boolean;
59
+ /** Whether the entire appended note fits in this section's next prompt snapshot. */
60
+ readonly includedInPrompt: boolean;
61
+ }
62
+ export declare function appendMemoryWithStatus(text: string, target?: string | AppendMemoryTarget): AppendMemoryResult;
49
63
  //# sourceMappingURL=store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAWH,8EAA8E;AAC9E,eAAO,MAAM,wBAAwB,OAAQ,CAAA;AAE7C,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,CAAA;AAE5C,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,8EAA8E;AAC9E,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAgBzD;AAED,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,6FAA6F;IAC7F,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B;AAWD,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,aAAa,CAMrE;AAUD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAezE;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,sCAAsC;IACtC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,kBAAkB,GAAG,MAAM,CAgBvF"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAUH,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAE/C,8EAA8E;AAC9E,eAAO,MAAM,wBAAwB,OAAQ,CAAA;AAE7C,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,CAAA;AAE5C,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,8EAA8E;AAC9E,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAYzD;AAED,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,qFAAqF;IACrF,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAA;CAClD;AAOD,6FAA6F;AAC7F,wBAAgB,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,aAAa,CA8BrE;AAaD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAezE;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,sCAAsC;IACtC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,kBAAkB,GAAG,MAAM,CAEvF;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,oFAAoF;IACpF,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAA;CAClC;AAED,wBAAgB,sBAAsB,CACrC,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,GAAG,kBAAkB,GAClC,kBAAkB,CAqBpB"}
@@ -16,14 +16,14 @@
16
16
  * to edit the file — which is the whole point of a curated memory.
17
17
  *
18
18
  * Separate from the kernel's memory store (`save_memory` / `search_memory`),
19
- * which holds what the agent chose to keep and is searched, not injected.
19
+ * which holds structured records retrieved by tools or bounded automatic recall.
20
20
  */
21
- import { appendFileSync, lstatSync, mkdirSync, readFileSync, realpathSync } from 'node:fs';
22
- import { dirname, join, resolve } from 'node:path';
21
+ import { realpathSync } from 'node:fs';
22
+ import { join, resolve } from 'node:path';
23
23
  import { namzuHomePath } from '../integrations/state/home.js';
24
24
  import { cliProjectRoot } from '../integrations/state/project.js';
25
- const DIR_MODE = 0o700;
26
- const FILE_MODE = 0o600;
25
+ import { appendMemoryFile, readMemoryFile, resolveMemoryPath } from './io.js';
26
+ export { MEMORY_FILE_MAX_BYTES } from './io.js';
27
27
  /** Characters of one section injected before the rest is left to the file. */
28
28
  export const MEMORY_SECTION_MAX_CHARS = 8_000;
29
29
  export function memoryDir(home) {
@@ -45,39 +45,58 @@ export function projectMemoryFilePath(cwd) {
45
45
  if (error.code !== 'ENOENT')
46
46
  throw error;
47
47
  }
48
+ const root = cliProjectRoot(directory);
48
49
  const local = join(directory, '.namzu', 'MEMORY.md');
49
- try {
50
- // An empty file or symlink is still an intentional directory-local file.
51
- lstatSync(local);
50
+ // An empty file or an in-scope symlink remains an intentional local file.
51
+ if (resolveMemoryPath({ path: local, root }) !== null)
52
52
  return local;
53
- }
54
- catch (error) {
55
- if (error.code !== 'ENOENT')
56
- throw error;
57
- }
58
- return join(cliProjectRoot(directory), '.namzu', 'MEMORY.md');
53
+ return join(root, '.namzu', 'MEMORY.md');
59
54
  }
60
- function readIfPresent(path) {
61
- try {
62
- const text = readFileSync(path, 'utf8').trim();
63
- return text.length > 0 ? text : null;
64
- }
65
- catch {
66
- return null;
67
- }
55
+ function projectLocation(cwd) {
56
+ const directory = realpathSync(resolve(cwd));
57
+ return { path: projectMemoryFilePath(directory), root: cliProjectRoot(directory) };
68
58
  }
69
- /** Read the user files under `home` and, when `cwd` is given, the project file. */
59
+ /** Read bounded, valid UTF-8 files; distinguish missing/empty files from refused content. */
70
60
  export function readMemory(home, cwd) {
71
- return {
72
- user: readIfPresent(userFilePath(home)),
73
- memory: readIfPresent(memoryFilePath(home)),
74
- project: cwd ? readIfPresent(projectMemoryFilePath(cwd)) : null,
61
+ const diagnostics = [];
62
+ const read = (path, location) => {
63
+ let selectedPath = path;
64
+ try {
65
+ const selected = location();
66
+ selectedPath = selected.path;
67
+ const text = readMemoryFile(selected)?.trim();
68
+ return text || null;
69
+ }
70
+ catch (error) {
71
+ diagnostics.push({
72
+ path: selectedPath,
73
+ reason: error instanceof Error ? error.message : String(error),
74
+ });
75
+ return null;
76
+ }
75
77
  };
78
+ const userRoot = memoryDir(home);
79
+ const user = read(join(userRoot, 'USER.md'), () => ({
80
+ root: userRoot,
81
+ path: join(userRoot, 'USER.md'),
82
+ }));
83
+ const memory = read(join(userRoot, 'MEMORY.md'), () => ({
84
+ root: userRoot,
85
+ path: join(userRoot, 'MEMORY.md'),
86
+ }));
87
+ const project = cwd
88
+ ? read(join(resolve(cwd), '.namzu', 'MEMORY.md'), () => projectLocation(cwd))
89
+ : null;
90
+ return { user, memory, project, ...(diagnostics.length > 0 ? { diagnostics } : {}) };
76
91
  }
77
92
  function capped(text, file) {
78
93
  if (text.length <= MEMORY_SECTION_MAX_CHARS)
79
94
  return text;
80
- const head = text.slice(0, MEMORY_SECTION_MAX_CHARS);
95
+ let end = MEMORY_SECTION_MAX_CHARS;
96
+ const last = text.charCodeAt(end - 1);
97
+ if (last >= 0xd800 && last <= 0xdbff)
98
+ end -= 1;
99
+ const head = text.slice(0, end);
81
100
  const cut = head.lastIndexOf('\n');
82
101
  const kept = cut > MEMORY_SECTION_MAX_CHARS / 2 ? head.slice(0, cut) : head;
83
102
  return `${kept}\n\n(… ${text.length - kept.length} more characters in ${file} were not included; the file wants curating.)`;
@@ -106,23 +125,30 @@ export function composeMemoryPrompt(content) {
106
125
  * second argument names the application home and means the user scope.
107
126
  */
108
127
  export function appendMemory(text, target) {
128
+ return appendMemoryWithStatus(text, target).path;
129
+ }
130
+ export function appendMemoryWithStatus(text, target) {
109
131
  const trimmed = text.trim();
110
132
  const scope = typeof target === 'object' ? target.scope : 'user';
111
133
  const home = typeof target === 'object' ? target.home : target;
112
- let path;
134
+ let location;
113
135
  if (scope === 'project') {
114
136
  const cwd = typeof target === 'object' ? target.cwd : undefined;
115
137
  if (!cwd)
116
138
  throw new Error('A project memory needs the working directory it belongs to.');
117
- path = projectMemoryFilePath(cwd);
139
+ location = projectLocation(cwd);
118
140
  }
119
141
  else {
120
- path = memoryFilePath(home);
142
+ location = { path: memoryFilePath(home), root: memoryDir(home) };
121
143
  }
122
144
  if (trimmed.length === 0)
123
- return path;
124
- mkdirSync(dirname(path), { recursive: true, mode: DIR_MODE });
125
- appendFileSync(path, `- ${trimmed}\n`, { mode: FILE_MODE });
126
- return path;
145
+ return { path: location.path, scope, appended: false, includedInPrompt: false };
146
+ const combined = appendMemoryFile(location, `- ${trimmed}\n`);
147
+ return {
148
+ path: location.path,
149
+ scope,
150
+ appended: true,
151
+ includedInPrompt: combined.trim().length <= MEMORY_SECTION_MAX_CHARS,
152
+ };
127
153
  }
128
154
  //# sourceMappingURL=store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type StructuredOutputConfig } from '@namzu/sdk';
2
+ /** Resolve once at launch; the schema remains fixed for the session. */
3
+ export declare function loadOutputSchema(path: string): StructuredOutputConfig;
4
+ //# sourceMappingURL=output-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-schema.d.ts","sourceRoot":"","sources":["../src/output-schema.ts"],"names":[],"mappings":"AAEA,OAAO,EAEN,KAAK,sBAAsB,EAG3B,MAAM,YAAY,CAAA;AAEnB,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,sBAAsB,CAcrE"}
@@ -0,0 +1,18 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { isDeepStrictEqual } from 'node:util';
3
+ import { mcpJsonSchemaToZod, renderToolSchema, } from '@namzu/sdk';
4
+ /** Resolve once at launch; the schema remains fixed for the session. */
5
+ export function loadOutputSchema(path) {
6
+ const value = JSON.parse(readFileSync(path, 'utf8'));
7
+ if (!value || typeof value !== 'object' || Array.isArray(value))
8
+ throw new Error('Output schema must be a JSON Schema object.');
9
+ const schema = mcpJsonSchemaToZod(value);
10
+ const { $schema: _dialect, ...expected } = value;
11
+ if (!isDeepStrictEqual(renderToolSchema(schema), expected))
12
+ throw new Error('Output schema cannot be represented losslessly. Use an explicit object schema with properties, required and additionalProperties; unsupported constraints are not discarded.');
13
+ return {
14
+ mode: 'native',
15
+ schema,
16
+ };
17
+ }
18
+ //# sourceMappingURL=output-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-schema.js","sourceRoot":"","sources":["../src/output-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,EAGN,kBAAkB,EAClB,gBAAgB,GAChB,MAAM,YAAY,CAAA;AAEnB,wEAAwE;AACxE,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC5C,MAAM,KAAK,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;IAC7D,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;IAC/D,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAsB,CAAC,CAAA;IACzD,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAgC,CAAA;IAC3E,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC;QACzD,MAAM,IAAI,KAAK,CACd,8KAA8K,CAC9K,CAAA;IACF,OAAO;QACN,IAAI,EAAE,QAAQ;QACd,MAAM;KACN,CAAA;AACF,CAAC"}
@@ -20,7 +20,15 @@ export declare function agentTaskPanelPageSize(terminalRows: number | undefined)
20
20
  * retained by the monitor for explicit history but never reappear here.
21
21
  */
22
22
  export declare function activeSubagentCohorts(agents: readonly SubagentActivity[]): readonly SubagentActivity[];
23
- export type AgentCockpitFocus = 'phases' | 'agents';
23
+ export type AgentCockpitFocus = 'workflows' | 'phases' | 'agents';
24
+ export interface AgentWorkflow {
25
+ readonly id: string;
26
+ readonly name: string;
27
+ readonly startedAt: number;
28
+ readonly status: SubagentActivityStatus;
29
+ readonly phases: readonly AgentPhase[];
30
+ readonly agents: readonly SubagentActivity[];
31
+ }
24
32
  export interface AgentPhase {
25
33
  readonly id: string;
26
34
  readonly workflowId: string;
@@ -46,6 +54,9 @@ export interface AgentCockpitProps {
46
54
  */
47
55
  export declare function AgentCockpit({ agents, selectedPhaseId, selectedId, focus, terminalRows, terminalColumns, }: AgentCockpitProps): import("react/jsx-runtime").JSX.Element;
48
56
  export declare function agentCockpitIsWide(terminalColumns: number): boolean;
57
+ /** Group retained work before exposing phases. Labels do not create execution dependencies. */
58
+ export declare function agentWorkflows(agents: readonly SubagentActivity[]): readonly AgentWorkflow[];
59
+ export declare function agentWorkflowPageSize(terminalRows: number): number;
49
60
  export declare function agentPhases(agents: readonly SubagentActivity[]): readonly AgentPhase[];
50
61
  export declare function agentPhasePageSize(terminalRows: number, wide?: boolean): number;
51
62
  export interface AgentTranscriptProps {
@@ -55,7 +66,7 @@ export interface AgentTranscriptProps {
55
66
  readonly terminalRows: number;
56
67
  readonly terminalColumns: number;
57
68
  }
58
- /** Child screen; the parent keeps its Static owner and two footer rows mounted. */
69
+ /** Child screen; leave two parent footer rows and one terminal cursor row free. */
59
70
  export declare function AgentTranscript({ agent, tailOffset, terminalRows, terminalColumns, }: AgentTranscriptProps): import("react/jsx-runtime").JSX.Element;
60
71
  export declare function agentPickerPageSize(terminalRows: number, wide?: boolean): number;
61
72
  export declare function agentTranscriptPageSize(terminalRows: number): number;
@@ -1 +1 @@
1
- {"version":3,"file":"AgentExplorer.d.ts","sourceRoot":"","sources":["../../src/tui/AgentExplorer.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AgentExplorer.d.ts","sourceRoot":"","sources":["../../src/tui/AgentExplorer.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACX,gBAAgB,EAChB,sBAAsB,EACtB,MAAM,uCAAuC,CAAA;AAW9C,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAA;IAC5C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;CAChC;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,eAAe,EAAE,EAAE,mBAAmB,2CAsD5F;AAED,6EAA6E;AAC7E,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAG/E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACpC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GACjC,SAAS,gBAAgB,EAAE,CAK7B;AAMD,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAEjE,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAA;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAA;IACtC,QAAQ,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAA;CAC5C;AAED,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAA;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAA;CAC5C;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAA;IAC5C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAA;IACjC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;CAChC;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAC5B,MAAM,EACN,eAAe,EACf,UAAU,EACV,KAAK,EACL,YAAY,EACZ,eAAe,GACf,EAAE,iBAAiB,2CAiKnB;AAsGD,wBAAgB,kBAAkB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAEnE;AAED,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,SAAS,aAAa,EAAE,CAiB5F;AAED,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,SAAS,UAAU,EAAE,CA+DtF;AAED,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,UAAO,GAAG,MAAM,CAK5E;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;IAChC,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;CAChC;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,EAC/B,KAAK,EACL,UAAU,EACV,YAAY,EACZ,eAAe,GACf,EAAE,oBAAoB,2CA+EtB;AAED,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,UAAO,GAAG,MAAM,CAK7E;AAED,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAGpE;AAED,wBAAgB,4BAA4B,CAC3C,KAAK,EAAE,gBAAgB,EACvB,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,GACrB,MAAM,CAKR;AAED,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,gBAAgB,EACvB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,GACrB;IACF,QAAQ,CAAC,IAAI,EAAE,SAAS,mBAAmB,EAAE,CAAA;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACtB,CAcA;AAED,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;IAC9B,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;CAClE;AAED,wEAAwE;AACxE,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,gBAAgB,EACvB,eAAe,EAAE,MAAM,GAAG,SAAS,GACjC,SAAS,mBAAmB,EAAE,CAiDhC"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Box, Text } from 'ink';
3
3
  import { useEffect, useState } from 'react';
4
+ import stringWidth from 'string-width';
4
5
  import { formatElapsed } from './LiveActivity.js';
5
6
  import { selectionWindow } from './selection-window.js';
6
7
  import { terminalDisplayText } from './terminal-display.js';
@@ -8,6 +9,7 @@ import { theme } from './theme.js';
8
9
  const MAX_PICKER_ROWS = 9;
9
10
  const COCKPIT_FRAME_COLUMNS = 4;
10
11
  const WIDE_COCKPIT_INNER_COLUMNS = 84;
12
+ const graphemes = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
11
13
  /**
12
14
  * Compact, automatic view of every cohort that still owns live work.
13
15
  *
@@ -54,30 +56,45 @@ function agentCohortKey(agent) {
54
56
  * bounded scheduler state it receives and never invents orchestration state.
55
57
  */
56
58
  export function AgentCockpit({ agents, selectedPhaseId, selectedId, focus, terminalRows, terminalColumns, }) {
57
- const phases = agentPhases(agents);
59
+ const workflows = agentWorkflows(agents);
60
+ const workflowIndex = Math.max(0, workflows.findIndex((workflow) => workflow.phases.some((phase) => phase.id === selectedPhaseId)));
61
+ const workflow = workflows[workflowIndex];
62
+ const phases = workflow?.phases ?? [];
58
63
  const selectedPhaseIndex = Math.max(0, phases.findIndex((phase) => phase.id === selectedPhaseId));
59
64
  const selectedPhase = phases[selectedPhaseIndex];
60
65
  const phaseAgents = selectedPhase?.agents ?? [];
61
66
  const selectedAgentIndex = Math.max(0, phaseAgents.findIndex((agent) => agent.viewId === selectedId));
62
67
  const now = useLiveNow(agents.some((agent) => agent.completedAt === undefined));
63
- const active = agents.filter((agent) => !isTerminalStatus(agent.status)).length;
68
+ const active = workflow?.agents.filter((agent) => !isTerminalStatus(agent.status)).length ?? 0;
64
69
  const wide = agentCockpitIsWide(terminalColumns);
65
70
  const compact = terminalRows < 20;
66
- const sideBySide = wide || compact;
67
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.border.default, paddingX: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { color: theme.text.primary, bold: true, wrap: "truncate-end", children: selectedPhase?.workflow ?? 'Delegated work' }), _jsxs(Text, { color: theme.text.muted, children: [active, " active \u00B7 ", agents.length, " total"] })] }), compact ? null : (_jsx(Text, { color: theme.text.muted, children: "Live delegated work \u00B7 select a phase, then inspect a child." })), _jsxs(Box, { flexDirection: sideBySide ? 'row' : 'column', paddingTop: compact ? 0 : 1, children: [_jsx(Box, { flexDirection: "column", width: sideBySide
68
- ? compact
69
- ? Math.max(18, Math.min(26, Math.floor(terminalColumns * 0.4)))
70
- : Math.max(28, Math.min(42, Math.floor(terminalColumns * 0.32)))
71
- : undefined, marginRight: sideBySide ? 2 : 0, children: _jsx(PhasePane, { phases: phases, selected: selectedPhaseIndex, focused: focus === 'phases', pageSize: compact ? 1 : agentPhasePageSize(terminalRows, wide) }) }), _jsx(Box, { flexDirection: "column", flexGrow: 1, paddingTop: sideBySide ? 0 : 1, children: _jsx(AgentPane, { agents: phaseAgents, selected: selectedAgentIndex, focused: focus === 'agents', pageSize: compact ? 1 : agentPickerPageSize(terminalRows, wide), now: now, wide: wide }) })] }), _jsx(Box, { paddingTop: compact ? 0 : 1, children: _jsx(Text, { color: theme.text.muted, children: compact
72
- ? '←→ pane · ↑↓ navigate · enter select · esc return'
73
- : '←→ pane · ↑↓ navigate · PgUp/PgDn jump · enter select · esc return' }) })] }));
71
+ const sideBySide = wide;
72
+ if (focus === 'workflows') {
73
+ const { items } = selectionWindow(workflows, workflowIndex, agentWorkflowPageSize(terminalRows));
74
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.border.default, paddingX: 1, children: [_jsxs(Text, { color: theme.accent.assistant, bold: true, wrap: "truncate-end", children: ["Workflows \u00B7 ", workflowIndex + 1, "/", workflows.length] }), compact ? null : (_jsx(Text, { color: theme.text.muted, wrap: "truncate-end", children: "Select a workflow to inspect its phases and agents." })), _jsx(Box, { flexDirection: "column", paddingTop: compact ? 0 : 1, children: items.map((item) => (_jsxs(Box, { height: 1, flexShrink: 0, children: [_jsx(Box, { width: 4, flexShrink: 0, children: _jsxs(Text, { color: item.id === workflow?.id ? theme.accent.assistant : theme.text.muted, children: [item.id === workflow?.id ? '›' : ' ', " ", statusGlyph(item.status)] }) }), _jsx(Box, { flexGrow: 1, minWidth: 0, children: _jsx(Text, { color: theme.text.primary, bold: item.id === workflow?.id, wrap: "truncate-end", children: oneLine(item.name) }) }), _jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsxs(Text, { color: statusColor(item.status), wrap: "truncate-end", children: [terminalColumns >= 70
75
+ ? `${item.phases.length} ${item.phases.length === 1 ? 'phase' : 'phases'} · `
76
+ : '', item.agents.length, " agents \u00B7 ", statusLabel(item.status)] }) })] }, item.id))) }), _jsx(Box, { paddingTop: compact ? 0 : 1, children: _jsx(Text, { color: theme.text.muted, wrap: "truncate-end", children: terminalColumns >= 60
77
+ ? '↑↓ navigate · PgUp/PgDn jump · enter select · esc return'
78
+ : '↑↓ · enter select · esc return' }) })] }));
79
+ }
80
+ const navigation = terminalColumns >= 90
81
+ ? '←→ pane · ↑↓ navigate · PgUp/PgDn jump · enter select · esc return'
82
+ : terminalColumns >= 60
83
+ ? '←→ pane · ↑↓ navigate · enter select · esc return'
84
+ : terminalColumns >= 38
85
+ ? '←→ pane · ↑↓ · enter · esc return'
86
+ : 'enter · esc return';
87
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.border.default, paddingX: 1, children: [_jsxs(Box, { height: 1, flexShrink: 0, children: [_jsx(Box, { flexGrow: 1, minWidth: 0, children: _jsx(Text, { color: theme.text.primary, bold: true, wrap: "truncate-end", children: oneLine(selectedPhase?.workflow ?? 'Delegated work') }) }), _jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsxs(Text, { color: theme.text.muted, wrap: "truncate-end", children: [active, " active \u00B7 ", workflow?.agents.length ?? 0, " total"] }) })] }), compact ? null : (_jsx(Text, { color: theme.text.muted, wrap: "truncate-end", children: workflows.length > 1
88
+ ? 'Select a phase, then inspect a child. Esc returns to workflows.'
89
+ : 'Select a phase, then inspect a child.' })), _jsxs(Box, { flexDirection: sideBySide ? 'row' : 'column', paddingTop: compact ? 0 : 1, children: [_jsx(Box, { flexDirection: "column", width: sideBySide
90
+ ? Math.max(24, Math.min(36, Math.floor(terminalColumns * 0.3)))
91
+ : undefined, flexShrink: 0, children: _jsx(PhasePane, { phases: phases, selected: selectedPhaseIndex, focused: focus === 'phases', pageSize: compact ? 1 : agentPhasePageSize(terminalRows, wide) }) }), sideBySide ? (_jsx(Box, { width: 1, marginX: 1, flexShrink: 0, borderStyle: "single", borderColor: theme.border.default, borderTop: false, borderBottom: false, borderRight: false })) : null, _jsx(Box, { flexDirection: "column", flexGrow: 1, minWidth: 0, paddingTop: sideBySide || compact ? 0 : 1, children: _jsx(AgentPane, { agents: phaseAgents, selected: selectedAgentIndex, focused: focus === 'agents', pageSize: compact ? 1 : agentPickerPageSize(terminalRows, wide), now: now, wide: wide }) })] }), _jsx(Box, { paddingTop: compact ? 0 : 1, children: _jsx(Text, { color: theme.text.muted, wrap: "truncate-end", children: navigation }) })] }));
74
92
  }
75
93
  function PhasePane({ phases, selected, focused, pageSize, }) {
76
94
  const { start, items } = selectionWindow(phases, selected, pageSize);
77
- const multipleWorkflows = new Set(phases.map((phase) => phase.workflowId)).size > 1;
78
95
  return (_jsxs(_Fragment, { children: [_jsxs(Text, { color: focused ? theme.accent.assistant : theme.text.secondary, bold: true, children: ["Phases ", phases.length > 0 ? `· ${selected + 1}/${phases.length}` : ''] }), items.map((phase, visibleIndex) => {
79
96
  const active = start + visibleIndex === selected;
80
- return (_jsxs(Box, { children: [_jsx(Box, { width: 3, flexShrink: 0, children: _jsxs(Text, { color: active && focused ? theme.accent.assistant : theme.text.muted, children: [active ? '›' : ' ', " ", statusGlyph(phase.status)] }) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, children: _jsxs(Text, { color: active ? theme.text.primary : theme.text.secondary, bold: active && focused, wrap: "truncate-end", children: [phase.order !== undefined ? `${phase.order + 1} ` : '', oneLine(multipleWorkflows ? `${phase.workflow} / ${phase.name}` : phase.name)] }) }), _jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsx(Text, { color: statusColor(phase.status), children: phaseProgress(phase) }) })] }, phase.id));
97
+ return (_jsxs(Box, { children: [_jsx(Box, { width: 4, flexShrink: 0, children: _jsxs(Text, { color: active && focused ? theme.accent.assistant : theme.text.muted, children: [active ? '›' : ' ', " ", statusGlyph(phase.status)] }) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, children: _jsxs(Text, { color: active ? theme.text.primary : theme.text.secondary, bold: active && focused, wrap: "truncate-end", children: [phase.order !== undefined ? `${phase.order + 1} ` : '', oneLine(phase.name)] }) }), _jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsx(Text, { color: statusColor(phase.status), children: phaseProgress(phase) }) })] }, phase.id));
81
98
  })] }));
82
99
  }
83
100
  function AgentPane({ agents, selected, focused, pageSize, now, wide, }) {
@@ -85,12 +102,36 @@ function AgentPane({ agents, selected, focused, pageSize, now, wide, }) {
85
102
  return (_jsxs(_Fragment, { children: [_jsxs(Text, { color: focused ? theme.accent.assistant : theme.text.secondary, bold: true, children: ["Agents ", agents.length > 0 ? `· ${selected + 1}/${agents.length}` : ''] }), items.map((agent, visibleIndex) => {
86
103
  const active = start + visibleIndex === selected;
87
104
  const elapsed = formatElapsed((agent.completedAt ?? now) - agent.startedAt);
88
- return (_jsxs(Box, { children: [_jsx(Box, { width: 3, flexShrink: 0, children: _jsxs(Text, { color: active && focused ? theme.accent.assistant : theme.text.muted, children: [active ? '›' : ' ', " ", statusGlyph(agent.status)] }) }), _jsx(Box, { width: wide ? 28 : undefined, flexGrow: wide ? 0 : 1, flexShrink: wide ? 0 : 1, children: _jsx(Text, { color: active ? theme.text.primary : theme.text.secondary, bold: active && focused, wrap: "truncate-end", children: oneLine(agent.description || agent.agentId) }) }), _jsx(Box, { flexGrow: wide ? 1 : 0, children: _jsxs(Text, { color: theme.text.secondary, wrap: "truncate-end", children: [wide ? `${statusLabel(agent.status)} · ` : ' · ', elapsed, agent.latestActivity ? ` · ${oneLine(agent.latestActivity)}` : ''] }) })] }, agent.viewId));
105
+ return (_jsxs(Box, { children: [_jsx(Box, { width: 4, flexShrink: 0, children: _jsxs(Text, { color: active && focused ? theme.accent.assistant : theme.text.muted, children: [active ? '›' : ' ', " ", statusGlyph(agent.status)] }) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, minWidth: 0, children: _jsx(Text, { color: active ? theme.text.primary : theme.text.secondary, bold: active && focused, wrap: "truncate-end", children: oneLine(agent.description || agent.agentId) }) }), _jsx(Box, { marginLeft: 1, flexShrink: 0, width: wide ? '50%' : undefined, children: _jsxs(Text, { color: theme.text.secondary, wrap: "truncate-end", children: [statusLabel(agent.status), " \u00B7", ' ', elapsed, wide && distinctActivity(agent) ? ` · ${distinctActivity(agent)}` : ''] }) })] }, agent.viewId));
89
106
  })] }));
90
107
  }
91
108
  export function agentCockpitIsWide(terminalColumns) {
92
109
  return Math.max(0, terminalColumns - COCKPIT_FRAME_COLUMNS) >= WIDE_COCKPIT_INNER_COLUMNS;
93
110
  }
111
+ /** Group retained work before exposing phases. Labels do not create execution dependencies. */
112
+ export function agentWorkflows(agents) {
113
+ const groups = new Map();
114
+ for (const agent of agents) {
115
+ const group = groups.get(agent.workflowGroupId);
116
+ if (group)
117
+ group.push(agent);
118
+ else
119
+ groups.set(agent.workflowGroupId, [agent]);
120
+ }
121
+ return [...groups]
122
+ .map(([id, members]) => ({
123
+ id,
124
+ name: members[0]?.workflow ?? 'Delegated work',
125
+ startedAt: Math.min(...members.map((agent) => agent.startedAt)),
126
+ status: phaseStatus(members),
127
+ phases: agentPhases(members),
128
+ agents: members,
129
+ }))
130
+ .sort((left, right) => left.startedAt - right.startedAt || left.id.localeCompare(right.id));
131
+ }
132
+ export function agentWorkflowPageSize(terminalRows) {
133
+ return Math.max(1, Math.min(MAX_PICKER_ROWS, terminalRows - 10));
134
+ }
94
135
  export function agentPhases(agents) {
95
136
  const records = new Map();
96
137
  const workflowStartedAt = new Map();
@@ -147,12 +188,12 @@ export function agentPhases(agents) {
147
188
  });
148
189
  }
149
190
  export function agentPhasePageSize(terminalRows, wide = true) {
150
- const available = Math.max(2, terminalRows - 10);
191
+ const available = Math.max(2, terminalRows - (wide ? 14 : 16));
151
192
  return wide
152
193
  ? Math.max(1, Math.min(MAX_PICKER_ROWS, available))
153
194
  : Math.max(1, Math.min(4, Math.floor(available * 0.4)));
154
195
  }
155
- /** Child screen; the parent keeps its Static owner and two footer rows mounted. */
196
+ /** Child screen; leave two parent footer rows and one terminal cursor row free. */
156
197
  export function AgentTranscript({ agent, tailOffset, terminalRows, terminalColumns, }) {
157
198
  const page = agentTranscriptPage(agent, tailOffset, terminalRows, terminalColumns);
158
199
  const now = useLiveNow(agent.completedAt === undefined);
@@ -165,19 +206,19 @@ export function AgentTranscript({ agent, tailOffset, terminalRows, terminalColum
165
206
  : terminalColumns >= 30
166
207
  ? '↑↓ · esc list · q parent'
167
208
  : 'esc list · q parent';
168
- return (_jsxs(Box, { flexDirection: "column", height: page.pageSize + 8, flexShrink: 0, borderStyle: "single", borderColor: theme.accent.assistant, paddingX: 1, children: [_jsxs(Box, { justifyContent: "space-between", height: 1, flexShrink: 0, children: [_jsx(Box, { flexGrow: 1, minWidth: 0, children: _jsx(Text, { color: theme.accent.assistant, bold: true, wrap: "truncate-end", children: "Subagent" }) }), _jsx(Box, { flexShrink: 0, children: _jsxs(Text, { color: statusColor(agent.status), wrap: "truncate-end", children: [statusLabel(agent.status), terminalColumns >= 40 ? ` · ${elapsed}` : ''] }) })] }), _jsx(Text, { color: theme.text.primary, bold: true, wrap: "truncate-end", children: oneLine(agent.description || agent.agentId) }), _jsx(Box, { flexDirection: "column", marginTop: 1, height: page.pageSize, flexShrink: 0, children: page.rows.length === 0 ? (_jsx(Text, { color: theme.text.muted, wrap: "truncate-end", children: "Waiting for child output\u2026" })) : (page.rows.map((line) => (_jsxs(Box, { height: 1, flexShrink: 0, children: [_jsx(Box, { width: 3, flexShrink: 0, children: _jsx(Text, { color: line.source !== 'prompt' && line.source.kind === 'tool'
209
+ return (_jsxs(Box, { flexDirection: "column", height: page.pageSize + 8, flexShrink: 0, borderStyle: "single", borderColor: theme.accent.assistant, paddingX: 1, overflow: "hidden", children: [_jsxs(Box, { justifyContent: "space-between", height: 1, flexShrink: 0, children: [_jsx(Box, { flexGrow: 1, minWidth: 0, children: _jsx(Text, { color: theme.accent.assistant, bold: true, wrap: "truncate-end", children: "Subagent" }) }), _jsx(Box, { flexShrink: 0, children: _jsxs(Text, { color: statusColor(agent.status), wrap: "truncate-end", children: [statusLabel(agent.status), terminalColumns >= 40 ? ` · ${elapsed}` : ''] }) })] }), _jsx(Text, { color: theme.text.primary, bold: true, wrap: "truncate-end", children: oneLine(agent.description || agent.agentId) }), _jsx(Box, { flexDirection: "column", marginTop: 1, height: page.pageSize, flexShrink: 0, children: page.rows.length === 0 ? (_jsx(Text, { color: theme.text.muted, wrap: "truncate-end", children: "Waiting for child output\u2026" })) : (page.rows.map((line) => (_jsxs(Box, { height: 1, flexShrink: 0, overflow: "hidden", children: [_jsx(Box, { width: 3, flexShrink: 0, children: _jsx(Text, { color: line.source !== 'prompt' && line.source.kind === 'tool'
169
210
  ? statusColor(line.source.status)
170
- : lineColor(line), children: line.continuation ? ' ' : lineGlyph(line) }) }), _jsx(Text, { color: lineColor(line), children: line.text })] }, line.id)))) }), _jsxs(Box, { flexDirection: "column", marginTop: 1, height: 2, flexShrink: 0, children: [_jsxs(Text, { color: theme.text.muted, wrap: "truncate-end", children: [page.last === page.total ? tailLabel : 'History', " \u00B7", ' ', page.total === 0 ? '0/0' : `${page.first}-${page.last}/${page.total}`] }), _jsx(Text, { color: theme.text.muted, wrap: "truncate-end", children: navigation })] })] }));
211
+ : lineColor(line), children: line.continuation ? ' ' : lineGlyph(line) }) }), _jsx(Box, { flexGrow: 1, minWidth: 0, children: _jsx(Text, { color: lineColor(line), wrap: "truncate-end", children: line.text }) })] }, line.id)))) }), _jsxs(Box, { flexDirection: "column", marginTop: 1, height: 2, flexShrink: 0, children: [_jsxs(Text, { color: theme.text.muted, wrap: "truncate-end", children: [page.last === page.total ? tailLabel : 'History', " \u00B7", ' ', page.total === 0 ? '0/0' : `${page.first}-${page.last}/${page.total}`] }), _jsx(Text, { color: theme.text.muted, wrap: "truncate-end", children: navigation })] })] }));
171
212
  }
172
213
  export function agentPickerPageSize(terminalRows, wide = true) {
173
- const available = Math.max(2, terminalRows - 10);
214
+ const available = Math.max(2, terminalRows - (wide ? 14 : 16));
174
215
  return wide
175
216
  ? Math.max(1, Math.min(MAX_PICKER_ROWS, available))
176
217
  : Math.max(1, Math.min(MAX_PICKER_ROWS, available - agentPhasePageSize(terminalRows, false)));
177
218
  }
178
219
  export function agentTranscriptPageSize(terminalRows) {
179
- // Two parent footer rows plus borders, heading, title, spacing and navigation.
180
- return Math.max(1, terminalRows - 10);
220
+ // Parent footer, cursor row, borders, heading, title, spacing and navigation.
221
+ return Math.max(1, terminalRows - 11);
181
222
  }
182
223
  export function maxAgentTranscriptTailOffset(agent, terminalRows, terminalColumns) {
183
224
  return Math.max(0, agentTranscriptRows(agent, terminalColumns).length - agentTranscriptPageSize(terminalRows));
@@ -218,9 +259,8 @@ export function agentTranscriptRows(agent, terminalColumns) {
218
259
  let text = '';
219
260
  let cells = 0;
220
261
  let continuation = sourceLine > 0;
221
- for (const point of logical) {
222
- const codePoint = point.codePointAt(0);
223
- const pointCells = codePoint !== undefined && codePoint <= 0x7e ? 1 : 2;
262
+ for (const { segment: point } of graphemes.segment(expandTabs(logical))) {
263
+ const pointCells = stringWidth(point);
224
264
  if (text.length > 0 && cells + pointCells > width) {
225
265
  lines.push({
226
266
  id: `${source.id}:${sourceLine++}`,
@@ -245,14 +285,34 @@ export function agentTranscriptRows(agent, terminalColumns) {
245
285
  }
246
286
  return lines;
247
287
  }
288
+ /** Resolve indentation before paging; raw tabs can move the terminal beyond a row's box. */
289
+ function expandTabs(line) {
290
+ let text = '';
291
+ let cells = 0;
292
+ for (const { segment } of graphemes.segment(line)) {
293
+ const point = segment === '\t' ? ' '.repeat(8 - (cells % 8)) : segment;
294
+ text += point;
295
+ cells += stringWidth(point);
296
+ }
297
+ return text;
298
+ }
248
299
  function oneLine(text) {
249
300
  return terminalDisplayText(text).replace(/\r?\n/g, ' ↵ ').replace(/\t/g, ' ⇥ ');
250
301
  }
302
+ function distinctActivity(agent) {
303
+ const activity = agent.latestActivity ? oneLine(agent.latestActivity) : undefined;
304
+ if (!activity || activity.toLowerCase() === agent.status)
305
+ return undefined;
306
+ const prefix = `${statusLabel(agent.status)} · `;
307
+ return activity.startsWith(prefix) ? activity.slice(prefix.length) : activity;
308
+ }
251
309
  function phaseStatus(agents) {
252
310
  if (agents.some((agent) => agent.status === 'failed'))
253
311
  return 'failed';
254
312
  if (agents.some((agent) => agent.status === 'working'))
255
313
  return 'working';
314
+ if (agents.some((agent) => agent.status === 'queued'))
315
+ return 'queued';
256
316
  if (agents.some((agent) => agent.status === 'starting'))
257
317
  return 'starting';
258
318
  if (agents.some((agent) => agent.status === 'cancelled'))
@@ -275,6 +335,7 @@ function isTerminalStatus(status) {
275
335
  function statusGlyph(status) {
276
336
  switch (status) {
277
337
  case 'starting':
338
+ case 'queued':
278
339
  return '◌';
279
340
  case 'working':
280
341
  return '●';
@@ -296,6 +357,7 @@ function statusColor(status) {
296
357
  case 'failed':
297
358
  return theme.status.error;
298
359
  case 'starting':
360
+ case 'queued':
299
361
  case 'working':
300
362
  return theme.accent.assistant;
301
363
  case 'cancelled':