praxis-agent 0.34.0 → 0.36.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 (78) hide show
  1. package/README.md +9 -1
  2. package/dist/application/background-agent-manager.d.ts +16 -6
  3. package/dist/application/background-agent-manager.js +139 -97
  4. package/dist/application/context-engine.d.ts +56 -0
  5. package/dist/application/context-engine.js +129 -0
  6. package/dist/application/session-service.d.ts +8 -5
  7. package/dist/application/session-service.js +1824 -1728
  8. package/dist/application/subagent-service.js +385 -193
  9. package/dist/application/top-level-agent-manager.d.ts +1 -0
  10. package/dist/application/top-level-agent-manager.js +1025 -403
  11. package/dist/application/transcript-projection.d.ts +33 -0
  12. package/dist/application/transcript-projection.js +110 -0
  13. package/dist/application/turn-lifecycle.d.ts +40 -0
  14. package/dist/application/turn-lifecycle.js +36 -0
  15. package/dist/application/turn-memory-coordinator.d.ts +43 -0
  16. package/dist/application/turn-memory-coordinator.js +98 -0
  17. package/dist/cli/agents-dashboard.js +10 -5
  18. package/dist/cli/interactive.js +279 -209
  19. package/dist/cli/protocol.js +5 -2
  20. package/dist/cli/tui/claude-style.d.ts +5 -48
  21. package/dist/cli/tui/claude-style.js +167 -197
  22. package/dist/cli/tui/task-panel.js +10 -1
  23. package/dist/cli/tui/theme.d.ts +46 -3
  24. package/dist/cli/tui/theme.js +414 -56
  25. package/dist/cli/tui/tool-permission.js +9 -5
  26. package/dist/cli/tui/transcript-presentation.d.ts +89 -0
  27. package/dist/cli/tui/transcript-presentation.js +169 -0
  28. package/dist/cli/tui/transcript-viewport.d.ts +5 -34
  29. package/dist/cli/tui/transcript-viewport.js +639 -158
  30. package/dist/cli/tui/tui-interaction-router.d.ts +78 -0
  31. package/dist/cli/tui/tui-interaction-router.js +127 -0
  32. package/dist/cli/tui/tui-view-model.d.ts +6 -2
  33. package/dist/cli/tui/tui-view-model.js +23 -6
  34. package/dist/cli-runtime.d.ts +2 -2
  35. package/dist/compatibility/claude/context.d.ts +2 -2
  36. package/dist/compatibility/claude/context.js +2 -14
  37. package/dist/compatibility/claude/data-plane-adapter.d.ts +9 -0
  38. package/dist/compatibility/claude/data-plane-adapter.js +44 -0
  39. package/dist/compatibility/claude/paths.js +2 -2
  40. package/dist/compatibility/claude/shared-resources.d.ts +7 -38
  41. package/dist/compatibility/claude/transcript-codec.d.ts +21 -0
  42. package/dist/compatibility/claude/transcript-codec.js +512 -0
  43. package/dist/core/agent-orchestration.d.ts +31 -0
  44. package/dist/core/agent-orchestration.js +235 -0
  45. package/dist/core/context.d.ts +25 -7
  46. package/dist/core/context.js +46 -0
  47. package/dist/core/prompt-composer.d.ts +8 -16
  48. package/dist/core/prompt-composer.js +65 -25
  49. package/dist/core/resources.d.ts +39 -0
  50. package/dist/core/resources.js +2 -0
  51. package/dist/core/runtime.d.ts +6 -1
  52. package/dist/core/runtime.js +15 -1
  53. package/dist/core/session.d.ts +2 -0
  54. package/dist/core/session.js +5 -0
  55. package/dist/core/transcript-codec.d.ts +70 -0
  56. package/dist/core/transcript-codec.js +60 -0
  57. package/dist/core/transcript-event.d.ts +33 -0
  58. package/dist/core/transcript-event.js +198 -0
  59. package/dist/persistence/claude-job-store.d.ts +58 -0
  60. package/dist/persistence/claude-job-store.js +483 -1
  61. package/dist/persistence/data-plane-adapter.d.ts +32 -0
  62. package/dist/persistence/data-plane-adapter.js +2 -0
  63. package/dist/persistence/data-plane.d.ts +4 -20
  64. package/dist/persistence/data-plane.js +10 -47
  65. package/dist/persistence/native-data-plane-adapter.d.ts +9 -0
  66. package/dist/persistence/native-data-plane-adapter.js +39 -0
  67. package/dist/persistence/native-resources.d.ts +4 -4
  68. package/dist/persistence/native-transcript-codec.d.ts +13 -0
  69. package/dist/persistence/native-transcript-codec.js +102 -0
  70. package/dist/persistence/native-transcript-reader.d.ts +53 -0
  71. package/dist/persistence/native-transcript-reader.js +283 -0
  72. package/dist/persistence/subagent-lifecycle-store.d.ts +41 -8
  73. package/dist/persistence/subagent-lifecycle-store.js +373 -146
  74. package/dist/platform/exclusive-file-lease.d.ts +3 -0
  75. package/dist/platform/exclusive-file-lease.js +3 -0
  76. package/dist/tools/claude-user-message.d.ts +0 -1
  77. package/dist/tools/claude-user-message.js +0 -1
  78. package/package.json +6 -2
@@ -0,0 +1,33 @@
1
+ import type { ModelMessage, ModelToolCall } from '../core/runtime.js';
2
+ import type { TranscriptEvent } from '../core/transcript-event.js';
3
+ export type TranscriptDisplayItem = {
4
+ kind: 'user' | 'assistant' | 'thinking';
5
+ text: string;
6
+ } | {
7
+ kind: 'compact';
8
+ summary: string;
9
+ } | {
10
+ kind: 'tool';
11
+ call: ModelToolCall;
12
+ detail: string;
13
+ } | {
14
+ kind: 'tool-result';
15
+ callId: string;
16
+ text: string;
17
+ isError: boolean;
18
+ } | {
19
+ kind: 'shell';
20
+ callId: string;
21
+ command: string;
22
+ } | {
23
+ kind: 'shell-result';
24
+ callId: string;
25
+ stdout: string;
26
+ stderr: string;
27
+ isError: boolean;
28
+ };
29
+ export declare function activeEvents(events: readonly TranscriptEvent[], checkpoint?: string): TranscriptEvent[];
30
+ export declare function projectActiveMessages(events: readonly TranscriptEvent[], checkpoint?: string): ModelMessage[];
31
+ export declare function projectTranscriptDisplay(events: readonly TranscriptEvent[], checkpoint?: string): TranscriptDisplayItem[];
32
+ export declare function lastUserPrompt(events: readonly TranscriptEvent[], checkpoint?: string): string | null;
33
+ //# sourceMappingURL=transcript-projection.d.ts.map
@@ -0,0 +1,110 @@
1
+ function effectiveParentId(event) {
2
+ return event.kind === 'context-boundary'
3
+ ? event.logicalParentId
4
+ : event.parentId;
5
+ }
6
+ function bashEnvelope(content) {
7
+ const input = /^<bash-input>([\s\S]*)<\/bash-input>$/u.exec(content);
8
+ if (input)
9
+ return { kind: 'input', command: input[1] ?? '' };
10
+ const output = /^<bash-stdout>([\s\S]*)<\/bash-stdout><bash-stderr>([\s\S]*)<\/bash-stderr>$/u.exec(content);
11
+ return output
12
+ ? { kind: 'output', stdout: output[1] ?? '', stderr: output[2] ?? '' }
13
+ : null;
14
+ }
15
+ export function activeEvents(events, checkpoint) {
16
+ const all = [...events];
17
+ const byId = new Map(all.map((event) => [event.id, event]));
18
+ const parentIds = new Set(all.flatMap((event) => {
19
+ const parentId = effectiveParentId(event);
20
+ return parentId === null ? [] : [parentId];
21
+ }));
22
+ const newest = (list) => [...list]
23
+ .sort((a, b) => a.timestamp.localeCompare(b.timestamp) || a.id.localeCompare(b.id))
24
+ .at(-1);
25
+ let leaf = checkpoint === undefined
26
+ ? (newest(all.filter((event) => !parentIds.has(event.id))) ?? newest(all))
27
+ : byId.get(checkpoint);
28
+ if (checkpoint !== undefined && !leaf)
29
+ throw new Error(`Unknown transcript checkpoint: ${checkpoint}`);
30
+ if (!leaf)
31
+ return [];
32
+ const selected = [];
33
+ const seen = new Set();
34
+ while (leaf && !seen.has(leaf.id)) {
35
+ selected.push(leaf);
36
+ seen.add(leaf.id);
37
+ const parentId = effectiveParentId(leaf);
38
+ leaf = parentId ? byId.get(parentId) : undefined;
39
+ }
40
+ return selected.reverse();
41
+ }
42
+ export function projectActiveMessages(events, checkpoint) {
43
+ return activeEvents(events, checkpoint).flatMap((event) => event.kind === 'messages' ? [...event.messages] : []);
44
+ }
45
+ export function projectTranscriptDisplay(events, checkpoint) {
46
+ const items = [];
47
+ let pendingShell = null;
48
+ for (const event of activeEvents(events, checkpoint)) {
49
+ if (event.kind === 'context-summary') {
50
+ items.push({ kind: 'compact', summary: event.summary });
51
+ continue;
52
+ }
53
+ if (event.kind !== 'messages')
54
+ continue;
55
+ for (const message of event.messages) {
56
+ if (message.role === 'user') {
57
+ const shell = bashEnvelope(message.content);
58
+ if (shell?.kind === 'input') {
59
+ pendingShell = { callId: event.id, command: shell.command };
60
+ items.push({ kind: 'shell', ...pendingShell });
61
+ continue;
62
+ }
63
+ if (shell?.kind === 'output' && pendingShell) {
64
+ items.push({
65
+ kind: 'shell-result',
66
+ callId: pendingShell.callId,
67
+ stdout: shell.stdout,
68
+ stderr: shell.stderr,
69
+ isError: shell.stderr.length > 0,
70
+ });
71
+ pendingShell = null;
72
+ continue;
73
+ }
74
+ if (message.content)
75
+ items.push({ kind: 'user', text: message.content });
76
+ continue;
77
+ }
78
+ if (message.role === 'assistant') {
79
+ for (const thinking of message.thinkingBlocks ?? [])
80
+ if (thinking.type === 'thinking' && thinking.thinking)
81
+ items.push({ kind: 'thinking', text: thinking.thinking });
82
+ if (message.content)
83
+ items.push({ kind: 'assistant', text: message.content });
84
+ for (const call of message.toolCalls ?? [])
85
+ items.push({ kind: 'tool', call, detail: '' });
86
+ continue;
87
+ }
88
+ if (message.role === 'tool')
89
+ items.push({
90
+ kind: 'tool-result',
91
+ callId: message.toolCallId,
92
+ text: message.content,
93
+ isError: message.isError,
94
+ });
95
+ }
96
+ }
97
+ return items;
98
+ }
99
+ export function lastUserPrompt(events, checkpoint) {
100
+ const messages = projectActiveMessages(events, checkpoint);
101
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
102
+ const message = messages[index];
103
+ if (message?.role === 'user' &&
104
+ message.content &&
105
+ bashEnvelope(message.content) === null)
106
+ return message.content;
107
+ }
108
+ return null;
109
+ }
110
+ //# sourceMappingURL=transcript-projection.js.map
@@ -0,0 +1,40 @@
1
+ import { type ModelDocument, type ModelImage, type RuntimeEventSink } from '../core/runtime.js';
2
+ import type { LifecycleState } from '../core/agent-orchestration.js';
3
+ export type TurnTerminalState = Extract<LifecycleState, 'completed' | 'failed' | 'cancelled'>;
4
+ export type TurnActivation = {
5
+ kind: 'start';
6
+ sessionId: string;
7
+ name?: string;
8
+ } | {
9
+ kind: 'resume';
10
+ sessionId: string;
11
+ name?: string;
12
+ atMessageId?: string;
13
+ };
14
+ export type TurnSubmission = {
15
+ kind: 'prompt';
16
+ text: string;
17
+ images?: readonly ModelImage[];
18
+ documents?: readonly ModelDocument[];
19
+ } | {
20
+ kind: 'shell';
21
+ command: string;
22
+ } | {
23
+ kind: 'retry';
24
+ prompt: string;
25
+ };
26
+ export interface TurnRequest {
27
+ activation: TurnActivation;
28
+ submission: TurnSubmission;
29
+ signal?: AbortSignal;
30
+ }
31
+ export declare class TurnTerminalController {
32
+ private readonly sink;
33
+ private terminal;
34
+ constructor(sink: RuntimeEventSink);
35
+ emit: RuntimeEventSink;
36
+ complete(): void;
37
+ fail(error: unknown, signal?: AbortSignal): void;
38
+ private transition;
39
+ }
40
+ //# sourceMappingURL=turn-lifecycle.d.ts.map
@@ -0,0 +1,36 @@
1
+ import { AgentRunCancelledError, ModelProviderError, } from '../core/runtime.js';
2
+ export class TurnTerminalController {
3
+ sink;
4
+ terminal = false;
5
+ constructor(sink) {
6
+ this.sink = sink;
7
+ }
8
+ emit = (event) => {
9
+ if (event.type === 'state' &&
10
+ (event.state === 'completed' ||
11
+ event.state === 'cancelled' ||
12
+ event.state === 'failed')) {
13
+ return;
14
+ }
15
+ this.sink(event);
16
+ };
17
+ complete() {
18
+ this.transition('completed');
19
+ }
20
+ fail(error, signal) {
21
+ if (this.terminal)
22
+ return;
23
+ const cancelled = signal?.aborted === true ||
24
+ error instanceof AgentRunCancelledError ||
25
+ (error instanceof ModelProviderError && error.kind === 'cancelled');
26
+ this.transition(cancelled ? 'cancelled' : 'failed');
27
+ }
28
+ transition(state) {
29
+ if (this.terminal) {
30
+ throw new Error('Turn terminal transition already emitted');
31
+ }
32
+ this.terminal = true;
33
+ this.sink({ type: 'state', state });
34
+ }
35
+ }
36
+ //# sourceMappingURL=turn-lifecycle.js.map
@@ -0,0 +1,43 @@
1
+ import type { ModelMessage } from '../core/runtime.js';
2
+ import type { ProjectMemoryExtractionRuntime, ProjectMemoryMessage, ProjectMemoryRecallRuntime } from './project-memory.js';
3
+ export interface TurnSessionMemoryRuntime {
4
+ summary(): Promise<string>;
5
+ waitForCompact(): Promise<void>;
6
+ observeContext(currentTokens: number, turnToolCalls: number, messageId: string, messages?: readonly ModelMessage[]): Promise<boolean>;
7
+ }
8
+ export interface TurnMemoryCoordinatorOptions {
9
+ sessionId: string;
10
+ session?: TurnSessionMemoryRuntime;
11
+ projectRecall?: ProjectMemoryRecallRuntime;
12
+ projectExtraction?: ProjectMemoryExtractionRuntime;
13
+ warn?: (message: string) => void;
14
+ }
15
+ /** Turn-scoped, best-effort coordination for both derived memory stores. */
16
+ export declare class TurnMemoryCoordinator {
17
+ private readonly options;
18
+ private recall;
19
+ constructor(options: TurnMemoryCoordinatorOptions);
20
+ prefetch(input: {
21
+ turnId: string;
22
+ prompt: string;
23
+ signal?: AbortSignal;
24
+ }): void;
25
+ sessionSummary(): Promise<string>;
26
+ consumeRecall(): {
27
+ content: string;
28
+ attachmentCount: number;
29
+ } | null;
30
+ recordRead(path: string): void;
31
+ beforeCompact(): Promise<void>;
32
+ afterCompact(): Promise<void>;
33
+ observeSuccess(input: {
34
+ messageId?: string;
35
+ occupancyTokens: number;
36
+ toolCalls: number;
37
+ messages: readonly ModelMessage[];
38
+ projectMessages: readonly ProjectMemoryMessage[];
39
+ directMaintenance?: boolean;
40
+ }): Promise<void>;
41
+ private warn;
42
+ }
43
+ //# sourceMappingURL=turn-memory-coordinator.d.ts.map
@@ -0,0 +1,98 @@
1
+ /** Turn-scoped, best-effort coordination for both derived memory stores. */
2
+ export class TurnMemoryCoordinator {
3
+ options;
4
+ recall;
5
+ constructor(options) {
6
+ this.options = options;
7
+ }
8
+ prefetch(input) {
9
+ if (!this.options.projectRecall)
10
+ return;
11
+ try {
12
+ this.recall = this.options.projectRecall.prefetch({
13
+ sessionId: this.options.sessionId,
14
+ ...input,
15
+ });
16
+ }
17
+ catch (error) {
18
+ this.warn('Project memory recall prefetch failed', error);
19
+ }
20
+ }
21
+ async sessionSummary() {
22
+ if (!this.options.session)
23
+ return '';
24
+ try {
25
+ return await this.options.session.summary();
26
+ }
27
+ catch (error) {
28
+ this.warn('Session memory summary failed', error);
29
+ return '';
30
+ }
31
+ }
32
+ consumeRecall() {
33
+ try {
34
+ return this.recall?.consumeIfSettled() ?? null;
35
+ }
36
+ catch (error) {
37
+ this.warn('Project memory recall consumption failed', error);
38
+ return null;
39
+ }
40
+ }
41
+ recordRead(path) {
42
+ try {
43
+ this.options.projectRecall?.recordRead(this.options.sessionId, path);
44
+ }
45
+ catch (error) {
46
+ this.warn('Project memory read observation failed', error);
47
+ }
48
+ }
49
+ async beforeCompact() {
50
+ if (!this.options.session)
51
+ return;
52
+ try {
53
+ await this.options.session.waitForCompact();
54
+ }
55
+ catch (error) {
56
+ this.warn('Session memory compact coordination failed', error);
57
+ }
58
+ }
59
+ async afterCompact() {
60
+ try {
61
+ this.options.projectRecall?.recordCompact(this.options.sessionId);
62
+ }
63
+ catch (error) {
64
+ this.warn('Project memory compact observation failed', error);
65
+ }
66
+ }
67
+ async observeSuccess(input) {
68
+ if (this.options.session && input.messageId !== undefined) {
69
+ try {
70
+ await this.options.session.observeContext(input.occupancyTokens, input.toolCalls, input.messageId, input.messages);
71
+ }
72
+ catch (error) {
73
+ this.warn('Session memory observation failed', error);
74
+ }
75
+ }
76
+ try {
77
+ this.options.projectExtraction?.observe({
78
+ sessionId: this.options.sessionId,
79
+ messages: input.projectMessages,
80
+ ...(input.directMaintenance === undefined
81
+ ? {}
82
+ : { directMaintenance: input.directMaintenance }),
83
+ });
84
+ }
85
+ catch (error) {
86
+ this.warn('Project memory extraction observation failed', error);
87
+ }
88
+ }
89
+ warn(prefix, error) {
90
+ try {
91
+ this.options.warn?.(`${prefix}: ${error instanceof Error ? error.message : String(error)}`);
92
+ }
93
+ catch {
94
+ // Warning sinks are deliberately non-authoritative.
95
+ }
96
+ }
97
+ }
98
+ //# sourceMappingURL=turn-memory-coordinator.js.map
@@ -2,7 +2,7 @@ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useRef, useState, } from 'react';
3
3
  import { Box, Text, render, useApp, useInput } from 'ink';
4
4
  import { loadTuiThemeSettings } from './tui/theme-settings.js';
5
- import { DEFAULT_TUI_THEME_SETTINGS, TuiThemeProvider, useTuiPalette, } from './tui/theme.js';
5
+ import { DEFAULT_TUI_THEME_SETTINGS, TuiThemeProvider, useTuiTheme, } from './tui/theme.js';
6
6
  const DASHBOARD_SECTIONS = [
7
7
  'Ready for review',
8
8
  'Needs input',
@@ -74,12 +74,17 @@ function groupAgents(agents) {
74
74
  return DASHBOARD_SECTIONS.flatMap((section) => agents.filter((agent) => sectionFor(agent) === section));
75
75
  }
76
76
  function AgentSection({ title, agents, selected, }) {
77
- const palette = useTuiPalette();
78
- return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { bold: true, children: [title, " (", agents.length, ")"] }), agents.length === 0 ? (_jsx(Text, { dimColor: true, children: " None" })) : (agents.map((agent) => (_jsxs(Text, { ...(agent === selected ? { color: palette.accent } : {}), children: [agent === selected ? '› ' : ' ', agent.name, " \u00B7 ", agentStatus(agent), " \u00B7 ", agentKey(agent)] }, agentKey(agent)))))] }));
77
+ const theme = useTuiTheme();
78
+ const semanticSelection = theme.screenReader || theme.noColor;
79
+ return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { ...theme.text.heading, bold: true, children: [title, " (", agents.length, ")"] }), agents.length === 0 ? (_jsx(Text, { dimColor: true, children: " None" })) : (agents.map((agent) => (_jsxs(Text, { ...(agent === selected ? theme.text.selectedRow : {}), children: [agent === selected
80
+ ? semanticSelection
81
+ ? 'Selected: '
82
+ : '› '
83
+ : ' ', agent.name, " \u00B7", ' ', _jsx(Text, { ...(sectionFor(agent) === 'Working' ? theme.text.active : {}), children: agentStatus(agent) }), ' ', "\u00B7 ", agentKey(agent)] }, agentKey(agent)))))] }));
79
84
  }
80
85
  export function AgentsDashboardApp({ manager, defaults, signal, refreshIntervalMs = 1_000, onCancel, }) {
81
86
  const { exit } = useApp();
82
- const palette = useTuiPalette();
87
+ const theme = useTuiTheme();
83
88
  const [agents, setAgents] = useState([]);
84
89
  const [selectedIndex, setSelectedIndex] = useState(0);
85
90
  const selectedIndexRef = useRef(0);
@@ -414,7 +419,7 @@ export function AgentsDashboardApp({ manager, defaults, signal, refreshIntervalM
414
419
  editInput();
415
420
  });
416
421
  const selected = agents[selectedIndex];
417
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, color: palette.accent, children: "Praxis agents" }), _jsxs(Text, { dimColor: true, children: [agents.length, " sessions \u00B7 live refresh"] }), DASHBOARD_SECTIONS.map((title) => (_jsx(AgentSection, { title: title, agents: agents.filter((agent) => sectionFor(agent) === title), ...(selected === undefined ? {} : { selected }) }, title))), mode === 'attach' ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["Attached to ", attachedId] }), attachedOutput ? (_jsx(Text, { children: attachedOutput })) : (_jsx(Text, { dimColor: true, children: "Waiting for output\u2026" })), _jsxs(Text, { children: ["\u203A ", input] }), _jsx(Text, { dimColor: true, children: "Enter sends \u00B7 Esc detaches \u00B7 Ctrl+C exits" })] })) : mode === 'review' ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["Reviewing ", reviewAgent ? agentKey(reviewAgent) : ''] }), _jsx(Text, { children: attachedOutput || 'No review output.' }), _jsxs(Text, { children: ["\u203A ", input] }), _jsx(Text, { dimColor: true, children: "Enter resumes with prompt \u00B7 Esc returns to list" })] })) : (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["\u203A ", input || 'describe a task for a new background agent'] }), _jsx(Text, { dimColor: true, children: "Enter dispatches \u00B7 \u2191/\u2193 select \u00B7 Enter empty attaches \u00B7 Ctrl+X stops \u00B7 Ctrl+R refreshes \u00B7 ? help \u00B7 Esc exits" }), selected ? (_jsxs(Text, { dimColor: true, children: ["Selected ", agentKey(selected)] })) : null] })), busy ? _jsx(Text, { dimColor: true, children: "Working\u2026" }) : null, notice ? _jsx(Text, { color: palette.warning, children: notice }) : null, showHelp ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, children: "Shortcuts" }), _jsx(Text, { children: "Enter dispatches or attaches \u00B7 Esc detaches/exits \u00B7 Ctrl+X stops local background agents \u00B7 Ctrl+R refreshes \u00B7 ? closes help" })] })) : null] }));
422
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { ...theme.text.heading, ...theme.text.productIdentity, children: "Praxis agents" }), _jsxs(Text, { dimColor: true, children: [agents.length, " sessions \u00B7 live refresh"] }), DASHBOARD_SECTIONS.map((title) => (_jsx(AgentSection, { title: title, agents: agents.filter((agent) => sectionFor(agent) === title), ...(selected === undefined ? {} : { selected }) }, title))), mode === 'attach' ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["Attached to ", attachedId] }), attachedOutput ? (_jsx(Text, { children: attachedOutput })) : (_jsx(Text, { dimColor: true, children: "Waiting for output\u2026" })), _jsxs(Text, { children: ["\u203A ", input] }), _jsx(Text, { dimColor: true, children: "Enter sends \u00B7 Esc detaches \u00B7 Ctrl+C exits" })] })) : mode === 'review' ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["Reviewing ", reviewAgent ? agentKey(reviewAgent) : ''] }), _jsx(Text, { children: attachedOutput || 'No review output.' }), _jsxs(Text, { children: ["\u203A ", input] }), _jsx(Text, { dimColor: true, children: "Enter resumes with prompt \u00B7 Esc returns to list" })] })) : (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["\u203A ", input || 'describe a task for a new background agent'] }), _jsx(Text, { dimColor: true, children: "Enter dispatches \u00B7 \u2191/\u2193 select \u00B7 Enter empty attaches \u00B7 Ctrl+X stops \u00B7 Ctrl+R refreshes \u00B7 ? help \u00B7 Esc exits" }), selected ? (_jsxs(Text, { dimColor: true, children: ["Selected ", agentKey(selected)] })) : null] })), busy ? _jsx(Text, { dimColor: true, children: "Working\u2026" }) : null, notice ? _jsx(Text, { ...theme.text.warning, children: notice }) : null, showHelp ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, children: "Shortcuts" }), _jsx(Text, { children: "Enter dispatches or attaches \u00B7 Esc detaches/exits \u00B7 Ctrl+X stops local background agents \u00B7 Ctrl+R refreshes \u00B7 ? closes help" })] })) : null] }));
418
423
  }
419
424
  export async function runAgentsDashboard(options, dependencies = {}) {
420
425
  const controller = new AbortController();