@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.
- package/CHANGELOG.md +255 -0
- package/README.md +42 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +24 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/acp.d.ts.map +1 -1
- package/dist/commands/acp.js +6 -1
- package/dist/commands/acp.js.map +1 -1
- package/dist/commands/run-stream.d.ts.map +1 -1
- package/dist/commands/run-stream.js +9 -1
- package/dist/commands/run-stream.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +14 -11
- package/dist/commands/run.js.map +1 -1
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +21 -0
- package/dist/config/load.js.map +1 -1
- package/dist/config/schema.d.ts +11 -4
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/doctor/checks/chain.d.ts.map +1 -1
- package/dist/doctor/checks/chain.js +11 -5
- package/dist/doctor/checks/chain.js.map +1 -1
- package/dist/doctor/checks/credentials.d.ts.map +1 -1
- package/dist/doctor/checks/credentials.js +5 -1
- package/dist/doctor/checks/credentials.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/providers/access.d.ts +7 -0
- package/dist/integrations/providers/access.d.ts.map +1 -0
- package/dist/integrations/providers/access.js +17 -0
- package/dist/integrations/providers/access.js.map +1 -0
- package/dist/integrations/providers/discover.d.ts +17 -54
- package/dist/integrations/providers/discover.d.ts.map +1 -1
- package/dist/integrations/providers/discover.js +46 -58
- package/dist/integrations/providers/discover.js.map +1 -1
- package/dist/integrations/providers/harness-credentials.d.ts +14 -0
- package/dist/integrations/providers/harness-credentials.d.ts.map +1 -1
- package/dist/integrations/providers/harness-credentials.js +46 -0
- package/dist/integrations/providers/harness-credentials.js.map +1 -1
- package/dist/integrations/providers/model-reasoning.d.ts +4 -0
- package/dist/integrations/providers/model-reasoning.d.ts.map +1 -0
- package/dist/integrations/providers/model-reasoning.js +46 -0
- package/dist/integrations/providers/model-reasoning.js.map +1 -0
- package/dist/integrations/providers/register.d.ts +1 -1
- package/dist/integrations/providers/register.d.ts.map +1 -1
- package/dist/integrations/providers/register.js +11 -1
- package/dist/integrations/providers/register.js.map +1 -1
- package/dist/integrations/providers/registry.d.ts +4 -4
- package/dist/integrations/providers/registry.d.ts.map +1 -1
- package/dist/integrations/providers/registry.js +23 -0
- package/dist/integrations/providers/registry.js.map +1 -1
- package/dist/integrations/sessions/context-inventory.d.ts +4 -0
- package/dist/integrations/sessions/context-inventory.d.ts.map +1 -0
- package/dist/integrations/sessions/context-inventory.js +44 -0
- package/dist/integrations/sessions/context-inventory.js.map +1 -0
- package/dist/integrations/sessions/conversation-search.d.ts +60 -0
- package/dist/integrations/sessions/conversation-search.d.ts.map +1 -0
- package/dist/integrations/sessions/conversation-search.js +461 -0
- package/dist/integrations/sessions/conversation-search.js.map +1 -0
- package/dist/integrations/sessions/task-context.d.ts +4 -0
- package/dist/integrations/sessions/task-context.d.ts.map +1 -0
- package/dist/integrations/sessions/task-context.js +73 -0
- package/dist/integrations/sessions/task-context.js.map +1 -0
- package/dist/integrations/subagents/activity.d.ts +3 -1
- package/dist/integrations/subagents/activity.d.ts.map +1 -1
- package/dist/integrations/subagents/activity.js +20 -2
- package/dist/integrations/subagents/activity.js.map +1 -1
- package/dist/integrations/subagents/runtime.d.ts +7 -4
- package/dist/integrations/subagents/runtime.d.ts.map +1 -1
- package/dist/integrations/subagents/runtime.js +105 -17
- package/dist/integrations/subagents/runtime.js.map +1 -1
- package/dist/memory/io.d.ts +12 -0
- package/dist/memory/io.d.ts.map +1 -0
- package/dist/memory/io.js +177 -0
- package/dist/memory/io.js.map +1 -0
- package/dist/memory/presentation.d.ts +4 -1
- package/dist/memory/presentation.d.ts.map +1 -1
- package/dist/memory/presentation.js +16 -2
- package/dist/memory/presentation.js.map +1 -1
- package/dist/memory/store.d.ts +17 -3
- package/dist/memory/store.d.ts.map +1 -1
- package/dist/memory/store.js +61 -35
- package/dist/memory/store.js.map +1 -1
- package/dist/output-schema.d.ts +4 -0
- package/dist/output-schema.d.ts.map +1 -0
- package/dist/output-schema.js +18 -0
- package/dist/output-schema.js.map +1 -0
- package/dist/tui/AgentExplorer.d.ts +13 -2
- package/dist/tui/AgentExplorer.d.ts.map +1 -1
- package/dist/tui/AgentExplorer.js +85 -23
- package/dist/tui/AgentExplorer.js.map +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +454 -64
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/BrandHeader.d.ts +1 -4
- package/dist/tui/BrandHeader.d.ts.map +1 -1
- package/dist/tui/BrandHeader.js +2 -6
- package/dist/tui/BrandHeader.js.map +1 -1
- package/dist/tui/Composer.d.ts +2 -1
- package/dist/tui/Composer.d.ts.map +1 -1
- package/dist/tui/Composer.js +9 -2
- package/dist/tui/Composer.js.map +1 -1
- package/dist/tui/PermissionOverlay.d.ts +1 -1
- package/dist/tui/PermissionOverlay.d.ts.map +1 -1
- package/dist/tui/PermissionOverlay.js +8 -1
- package/dist/tui/PermissionOverlay.js.map +1 -1
- package/dist/tui/Picker.d.ts.map +1 -1
- package/dist/tui/Picker.js +94 -21
- package/dist/tui/Picker.js.map +1 -1
- package/dist/tui/TextPrompt.d.ts +3 -1
- package/dist/tui/TextPrompt.d.ts.map +1 -1
- package/dist/tui/TextPrompt.js +55 -9
- package/dist/tui/TextPrompt.js.map +1 -1
- package/dist/tui/Transcript.d.ts.map +1 -1
- package/dist/tui/Transcript.js +1 -1
- package/dist/tui/Transcript.js.map +1 -1
- package/dist/tui/agent.d.ts +18 -3
- package/dist/tui/agent.d.ts.map +1 -1
- package/dist/tui/agent.js +174 -58
- package/dist/tui/agent.js.map +1 -1
- package/dist/tui/model-choices.d.ts +3 -1
- package/dist/tui/model-choices.d.ts.map +1 -1
- package/dist/tui/model-choices.js +12 -1
- package/dist/tui/model-choices.js.map +1 -1
- package/dist/tui/model-search.d.ts +4 -0
- package/dist/tui/model-search.d.ts.map +1 -0
- package/dist/tui/model-search.js +11 -0
- package/dist/tui/model-search.js.map +1 -0
- package/dist/tui/model-selection-intent.d.ts +8 -0
- package/dist/tui/model-selection-intent.d.ts.map +1 -0
- package/dist/tui/model-selection-intent.js +96 -0
- package/dist/tui/model-selection-intent.js.map +1 -0
- package/dist/tui/model-switch-tool.d.ts +7 -0
- package/dist/tui/model-switch-tool.d.ts.map +1 -0
- package/dist/tui/model-switch-tool.js +74 -0
- package/dist/tui/model-switch-tool.js.map +1 -0
- package/dist/tui/model-switch.d.ts +35 -0
- package/dist/tui/model-switch.d.ts.map +1 -0
- package/dist/tui/model-switch.js +106 -0
- package/dist/tui/model-switch.js.map +1 -0
- package/dist/tui/permission-review.d.ts.map +1 -1
- package/dist/tui/permission-review.js +25 -12
- package/dist/tui/permission-review.js.map +1 -1
- package/dist/tui/run-interruption.d.ts +7 -0
- package/dist/tui/run-interruption.d.ts.map +1 -1
- package/dist/tui/run-interruption.js +41 -0
- package/dist/tui/run-interruption.js.map +1 -1
- package/dist/tui/slashCommands.d.ts.map +1 -1
- package/dist/tui/slashCommands.js +2 -1
- package/dist/tui/slashCommands.js.map +1 -1
- package/dist/tui/types.d.ts +3 -1
- package/dist/tui/types.d.ts.map +1 -1
- 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
|
-
|
|
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,
|
|
1
|
+
{"version":3,"file":"presentation.js","sourceRoot":"","sources":["../../src/memory/presentation.ts"],"names":[],"mappings":"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"}
|
package/dist/memory/store.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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;
|
|
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"}
|
package/dist/memory/store.js
CHANGED
|
@@ -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
|
|
19
|
+
* which holds structured records retrieved by tools or bounded automatic recall.
|
|
20
20
|
*/
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
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
|
-
|
|
26
|
-
|
|
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
|
-
|
|
50
|
-
|
|
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
|
|
61
|
-
|
|
62
|
-
|
|
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
|
|
59
|
+
/** Read bounded, valid UTF-8 files; distinguish missing/empty files from refused content. */
|
|
70
60
|
export function readMemory(home, cwd) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
139
|
+
location = projectLocation(cwd);
|
|
118
140
|
}
|
|
119
141
|
else {
|
|
120
|
-
|
|
142
|
+
location = { path: memoryFilePath(home), root: memoryDir(home) };
|
|
121
143
|
}
|
|
122
144
|
if (trimmed.length === 0)
|
|
123
|
-
return path;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
package/dist/memory/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -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;
|
|
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":"
|
|
1
|
+
{"version":3,"file":"AgentExplorer.d.ts","sourceRoot":"","sources":["../../src/tui/AgentExplorer.tsx"],"names":[],"mappings":"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"}
|
|
@@ -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
|
|
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
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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:
|
|
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:
|
|
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 -
|
|
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;
|
|
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 -
|
|
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
|
-
//
|
|
180
|
-
return Math.max(1, terminalRows -
|
|
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
|
|
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':
|