@bastani/atomic 0.9.57-alpha.1 → 0.9.58-alpha.1
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 +52 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +12 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +39 -5
- package/dist/builtin/web-access/CHANGELOG.md +12 -0
- package/dist/builtin/web-access/index.bundle.mjs +2 -2
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +42 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +885 -228
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +933 -175
- package/dist/builtin/workflows/src/index.js +630 -162
- package/dist/builtin/workflows/src/local-worker-entry.mjs +933 -175
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +1 -1
- package/dist/builtin/workflows/src/shared/workflow-infrastructure-error.d.ts +13 -0
- package/dist/builtin/workflows/src/workers/public-options.d.ts +10 -0
- package/dist/core/agent-session-persistent-custom-messages.d.ts +5 -0
- package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.js +16 -0
- package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
- package/dist/core/agent-session-tasks.d.ts.map +1 -1
- package/dist/core/agent-session-tasks.js +20 -0
- package/dist/core/agent-session-tasks.js.map +1 -1
- package/dist/core/settings-defaults.d.ts +4 -0
- package/dist/core/settings-defaults.d.ts.map +1 -1
- package/dist/core/settings-defaults.js +4 -0
- package/dist/core/settings-defaults.js.map +1 -1
- package/dist/core/settings-manager-resource-accessors.d.ts +2 -0
- package/dist/core/settings-manager-resource-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-resource-accessors.js +6 -0
- package/dist/core/settings-manager-resource-accessors.js.map +1 -1
- package/dist/core/settings-schema.d.ts +9 -0
- package/dist/core/settings-schema.d.ts.map +1 -1
- package/dist/core/settings-schema.js +11 -0
- package/dist/core/settings-schema.js.map +1 -1
- package/dist/core/settings-types.d.ts +1 -1
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/tasks/agent-adapter.d.ts +10 -1
- package/dist/core/tasks/agent-adapter.d.ts.map +1 -1
- package/dist/core/tasks/agent-adapter.js +20 -0
- package/dist/core/tasks/agent-adapter.js.map +1 -1
- package/dist/core/tasks/contracts.d.ts +6 -0
- package/dist/core/tasks/contracts.d.ts.map +1 -1
- package/dist/core/tasks/contracts.js.map +1 -1
- package/dist/core/tasks/heartbeat-notice.d.ts +64 -0
- package/dist/core/tasks/heartbeat-notice.d.ts.map +1 -0
- package/dist/core/tasks/heartbeat-notice.js +98 -0
- package/dist/core/tasks/heartbeat-notice.js.map +1 -0
- package/dist/core/tasks/heartbeat.d.ts +75 -0
- package/dist/core/tasks/heartbeat.d.ts.map +1 -0
- package/dist/core/tasks/heartbeat.js +440 -0
- package/dist/core/tasks/heartbeat.js.map +1 -0
- package/dist/core/tasks/supervisor.d.ts +2 -0
- package/dist/core/tasks/supervisor.d.ts.map +1 -1
- package/dist/core/tasks/supervisor.js +32 -4
- package/dist/core/tasks/supervisor.js.map +1 -1
- package/dist/core/tasks/task-view-source.d.ts +72 -0
- package/dist/core/tasks/task-view-source.d.ts.map +1 -0
- package/dist/core/tasks/task-view-source.js +155 -0
- package/dist/core/tasks/task-view-source.js.map +1 -0
- package/dist/core/tools/bash-pty-native.d.ts +2 -0
- package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
- package/dist/core/tools/bash-pty-native.js +1 -0
- package/dist/core/tools/bash-pty-native.js.map +1 -1
- package/dist/core/tools/bash.d.ts +3 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +20 -2
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/powershell.d.ts +16 -8
- package/dist/core/tools/powershell.d.ts.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.js +7 -0
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.d.ts +3 -0
- package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.js +4 -0
- package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-types.d.ts +11 -0
- package/dist/modes/interactive/components/chat-session-host-types.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-types.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.d.ts +2 -0
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +15 -8
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +12 -0
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/task-detail.d.ts.map +1 -1
- package/dist/modes/interactive/components/task-detail.js +5 -0
- package/dist/modes/interactive/components/task-detail.js.map +1 -1
- package/dist/modes/interactive/components/task-heartbeat-message.d.ts +14 -0
- package/dist/modes/interactive/components/task-heartbeat-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/task-heartbeat-message.js +76 -0
- package/dist/modes/interactive/components/task-heartbeat-message.js.map +1 -0
- package/dist/modes/interactive/components/task-inspector.d.ts +6 -3
- package/dist/modes/interactive/components/task-inspector.d.ts.map +1 -1
- package/dist/modes/interactive/components/task-inspector.js +53 -100
- package/dist/modes/interactive/components/task-inspector.js.map +1 -1
- package/dist/modes/interactive/skill-command-autocomplete.d.ts +22 -2
- package/dist/modes/interactive/skill-command-autocomplete.d.ts.map +1 -1
- package/dist/modes/interactive/skill-command-autocomplete.js +28 -9
- package/dist/modes/interactive/skill-command-autocomplete.js.map +1 -1
- package/docs/background-tasks.md +65 -1
- package/docs/settings.md +12 -0
- package/docs/subagents.md +2 -0
- package/docs/tools.md +2 -1
- package/docs/workflows/operations.md +5 -3
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
- package/schemas/settings.schema.json +24 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { repairOrphanToolResults } from "../../../core/messages.js";
|
|
2
2
|
import { SessionManager } from "../../../core/session-manager.js";
|
|
3
3
|
import { getOwnerTaskStore, watchOwnerTaskStoreBinding } from "../../../core/tasks/owner-store.js";
|
|
4
|
+
import { ownerTaskViewSource } from "../../../core/tasks/task-view-source.js";
|
|
4
5
|
import { abortChatSessionBash, abortChatSessionCompaction, interruptChatSession, restoreQueuedMessagesToEditor, submitChatSession, } from "./chat-session-host-actions.js";
|
|
5
6
|
import { createChatSessionEditor, handleChatSessionInput, setChatSessionEditorText, } from "./chat-session-host-editor.js";
|
|
6
7
|
import { applyChatSessionAgentEvent, compactionStatusMessage } from "./chat-session-host-events.js";
|
|
@@ -13,6 +14,8 @@ export class ChatSessionHost {
|
|
|
13
14
|
focused = true;
|
|
14
15
|
state;
|
|
15
16
|
taskStore;
|
|
17
|
+
/** What `/tasks` and the task footer show: the session's task store, or the host's own task source. */
|
|
18
|
+
taskSource;
|
|
16
19
|
taskRowsInChat;
|
|
17
20
|
unsubscribeTasks;
|
|
18
21
|
taskSession;
|
|
@@ -39,12 +42,12 @@ export class ChatSessionHost {
|
|
|
39
42
|
if (session && !getOwnerTaskStore(session))
|
|
40
43
|
session.getAgentTaskHost?.();
|
|
41
44
|
this.refreshTaskStore();
|
|
42
|
-
if (!this.
|
|
45
|
+
if (!this.taskSource) {
|
|
43
46
|
this.showWarning("Launched agents and shells will appear here.");
|
|
44
47
|
return true;
|
|
45
48
|
}
|
|
46
49
|
this.taskInspector?.dispose();
|
|
47
|
-
this.taskInspector = new TaskInspector(this.
|
|
50
|
+
this.taskInspector = new TaskInspector(this.taskSource, () => this.state.requestRender?.(), () => this.closeTasks());
|
|
48
51
|
this.taskInspector.open(id);
|
|
49
52
|
this.state.requestRender?.();
|
|
50
53
|
return true;
|
|
@@ -128,24 +131,28 @@ export class ChatSessionHost {
|
|
|
128
131
|
: undefined;
|
|
129
132
|
}
|
|
130
133
|
const store = session ? getOwnerTaskStore(session) : undefined;
|
|
131
|
-
|
|
134
|
+
// A session in another process (a workflow stage on a local worker) has no store here; the host
|
|
135
|
+
// supplies a source that reads its tasks there.
|
|
136
|
+
const source = store ? ownerTaskViewSource(store) : this.state.getTaskSource?.();
|
|
137
|
+
if (store === this.taskStore && source === this.taskSource)
|
|
132
138
|
return;
|
|
133
139
|
this.closeTasks();
|
|
134
140
|
this.unsubscribeTasks?.();
|
|
135
141
|
this.taskStore = store;
|
|
142
|
+
this.taskSource = source;
|
|
136
143
|
this.unsubscribeTasks = undefined;
|
|
137
144
|
this.state.liveChat.clearTasks();
|
|
138
145
|
this.state.transcriptComponent.invalidate();
|
|
139
146
|
this.state.requestRender?.();
|
|
140
|
-
if (!
|
|
147
|
+
if (!source)
|
|
141
148
|
return;
|
|
142
149
|
const update = () => {
|
|
143
150
|
if (this.taskRowsInChat)
|
|
144
|
-
this.state.liveChat.upsertTasks(
|
|
151
|
+
this.state.liveChat.upsertTasks(source.tasks, store);
|
|
145
152
|
this.state.transcriptComponent.invalidate();
|
|
146
153
|
this.state.requestRender?.();
|
|
147
154
|
};
|
|
148
|
-
this.unsubscribeTasks =
|
|
155
|
+
this.unsubscribeTasks = source.subscribe(update);
|
|
149
156
|
update();
|
|
150
157
|
}
|
|
151
158
|
applyAgentEvent(event) {
|
|
@@ -242,11 +249,11 @@ export class ChatSessionHost {
|
|
|
242
249
|
return renderChatSessionEditor(this.state, width, this.focused);
|
|
243
250
|
}
|
|
244
251
|
renderTaskFooter(width) {
|
|
245
|
-
return renderTaskFooter(this.
|
|
252
|
+
return renderTaskFooter(this.taskSource?.backgroundTasks ?? [], width);
|
|
246
253
|
}
|
|
247
254
|
renderFooter(width) {
|
|
248
255
|
const footer = renderChatSessionFooter(this.state, width, this.hasTaskInspector && !this.taskInspectorFullscreen);
|
|
249
|
-
return footer.length ? footer : renderTaskFooter(this.
|
|
256
|
+
return footer.length ? footer : renderTaskFooter(this.taskSource?.backgroundTasks ?? [], width);
|
|
250
257
|
}
|
|
251
258
|
handleScrollInput(data) {
|
|
252
259
|
return this.state.bodyViewport.handleInput(data);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-session-host.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Component, Focusable } from \"@earendil-works/pi-tui\";\nimport type { AgentSessionEvent, CompactionReason } from \"../../../core/agent-session.js\";\nimport { repairOrphanToolResults } from \"../../../core/messages.ts\";\nimport { SessionManager } from \"../../../core/session-manager.ts\";\nimport type { SessionStore } from \"../../../core/storage/session/types.js\";\nimport type { TaskId } from \"../../../core/tasks/contracts.js\";\nimport { getOwnerTaskStore, type OwnerTaskStore, watchOwnerTaskStoreBinding } from \"../../../core/tasks/owner-store.js\";\nimport {\n\tabortChatSessionBash,\n\tabortChatSessionCompaction,\n\tinterruptChatSession,\n\trestoreQueuedMessagesToEditor,\n\tsubmitChatSession,\n} from \"./chat-session-host-actions.ts\";\nimport {\n\tcreateChatSessionEditor,\n\thandleChatSessionInput,\n\tsetChatSessionEditorText,\n} from \"./chat-session-host-editor.ts\";\nimport { applyChatSessionAgentEvent, compactionStatusMessage } from \"./chat-session-host-events.ts\";\nimport {\n\trenderChatSessionBody,\n\trenderChatSessionEditor,\n\trenderChatSessionEntry,\n\trenderChatSessionFooter,\n\trenderChatSessionPendingMessages,\n\trenderChatSessionUsage,\n\trenderChatSessionWorkingStatus,\n\ttranscriptCacheKey,\n} from \"./chat-session-host-rendering.ts\";\nimport {\n\tclearChatSessionBusyForTerminalWorkflowStage,\n\tdisposeChatSession,\n\tisChatSessionBashRunning,\n\tisChatSessionStreaming,\n\treassertChatSessionExternalPromptLifecycle,\n\tsettleChatSessionPromptLifecycle,\n\tstartChatSessionExternalPromptLifecycle,\n\tsyncChatSessionAnimationTick,\n} from \"./chat-session-host-runtime.ts\";\nimport { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport type {\n\tAgentSnapshotMessage,\n\tChatSessionHostEntry,\n\tChatSessionHostOpts,\n\tChatSessionSubmitMode,\n} from \"./chat-session-host-types.ts\";\nimport type { ChatTranscriptEntryLike } from \"./chat-transcript.js\";\nimport { TaskInspector } from \"./task-inspector.js\";\nimport { renderTaskFooter } from \"./task-list.js\";\n\nexport type {\n\tChatSessionHostBashRequest,\n\tChatSessionHostCommands,\n\tChatSessionHostEntry,\n\tChatSessionHostOpts,\n\tChatSessionHostStyle,\n\tChatSessionSubmitMode,\n} from \"./chat-session-host-types.ts\";\n\nexport class ChatSessionHost<TExtraEntry extends ChatTranscriptEntryLike = never> implements Component, Focusable {\n\tfocused = true;\n\n\tprivate readonly state: ChatSessionHostState<TExtraEntry>;\n\tprivate taskStore?: OwnerTaskStore;\n\tprivate readonly taskRowsInChat: boolean;\n\tprivate unsubscribeTasks?: () => void;\n\tprivate taskSession?: object;\n\tprivate unsubscribeTaskBinding?: () => void;\n\tprivate taskInspector?: TaskInspector;\n\tprivate historyHydrated = false;\n\n\tconstructor(opts: ChatSessionHostOpts<TExtraEntry>) {\n\t\t// `/tasks` stays a local action owned by the host's `commands.handleSlashCommand`\n\t\t// (see submitChatSession). Hosts that mount the inspector call `openTasks` from\n\t\t// that callback; the host must not intercept it ahead of the owner.\n\t\tthis.taskRowsInChat = opts.taskRowsInChat ?? true;\n\t\tthis.state = new ChatSessionHostState(opts, {\n\t\t\trenderEntry: (state, entry) => renderChatSessionEntry(state, entry),\n\t\t\ttranscriptCacheKey: (state, entry, index) => transcriptCacheKey(state, entry, index),\n\t\t});\n\t\tthis.state.editor = createChatSessionEditor(\n\t\t\tthis.state,\n\t\t\topts.tui,\n\t\t\topts.keybindings,\n\t\t\topts.editorTheme,\n\t\t\topts.editorFactory,\n\t\t\tthis.editorCallbacks(),\n\t\t);\n\t\tif (opts.autocompleteProvider) this.state.editor?.setAutocompleteProvider?.(opts.autocompleteProvider);\n\t\tthis.syncAnimationTick();\n\t\tthis.refreshTaskStore();\n\t}\n\n\topenTasks(id?: string): boolean {\n\t\tconst session = this.state.getAgentSession?.();\n\t\tif (session && !getOwnerTaskStore(session)) session.getAgentTaskHost?.();\n\t\tthis.refreshTaskStore();\n\t\tif (!this.taskStore) {\n\t\t\tthis.showWarning(\"Launched agents and shells will appear here.\");\n\t\t\treturn true;\n\t\t}\n\t\tthis.taskInspector?.dispose();\n\t\tthis.taskInspector = new TaskInspector(\n\t\t\tthis.taskStore,\n\t\t\t() => this.state.requestRender?.(),\n\t\t\t() => this.closeTasks(),\n\t\t);\n\t\tthis.taskInspector.open(id as TaskId | undefined);\n\t\tthis.state.requestRender?.();\n\t\treturn true;\n\t}\n\tget hasTaskInspector(): boolean {\n\t\treturn this.taskInspector !== undefined;\n\t}\n\tget taskInspectorFullscreen(): boolean {\n\t\treturn this.taskInspector?.fullscreen === true;\n\t}\n\tcloseTasks(): void {\n\t\tthis.taskInspector?.dispose();\n\t\tthis.taskInspector = undefined;\n\t\tthis.state.requestRender?.();\n\t}\n\thandleTaskInput(data: string): boolean {\n\t\tif (!this.taskInspector) return false;\n\t\tthis.taskInspector.handleInput(data);\n\t\treturn true;\n\t}\n\tappendMessages(messages: readonly AgentSnapshotMessage[]): void {\n\t\tthis.state.liveChat.appendMessages(messages);\n\t}\n\n\t/**\n\t * Adopt the assistant message a live session is part-way through streaming.\n\t *\n\t * A host mounted mid-turn missed the `message_start` and every delta that\n\t * came before it, and delta-only updates never restate them, so the session's\n\t * in-flight message is the only place that text still exists. Ignored once\n\t * this host is already following a stream of its own.\n\t */\n\thydrateStreamingAssistantMessage(message: AgentSnapshotMessage | undefined): void {\n\t\tif (message === undefined) return;\n\t\tif (this.state.liveChat.hydrateStreamingAssistantMessage(message)) this.state.requestRender?.();\n\t}\n\n\tasync loadSession(store: SessionStore, sessionId: string | undefined): Promise<boolean> {\n\t\tif (\n\t\t\tthis.historyHydrated ||\n\t\t\tthis.state.transcript.length > this.state.extraEntries.length ||\n\t\t\tsessionId === undefined\n\t\t)\n\t\t\treturn true;\n\t\tlet messages: readonly AgentSnapshotMessage[];\n\t\ttry {\n\t\t\tconst manager = await SessionManager.open(store, sessionId);\n\t\t\tmessages = repairOrphanToolResults(manager.buildSessionContext().messages, {\n\t\t\t\trepairTrailing: true,\n\t\t\t}) as readonly AgentSnapshotMessage[];\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.state.disposed) return false;\n\t\tif (this.historyHydrated || this.state.transcript.length > this.state.extraEntries.length) return true;\n\t\tthis.historyHydrated = true;\n\t\tconst extras = this.state.transcript.splice(0);\n\t\tthis.state.liveChat.appendMessages(messages);\n\t\tthis.state.transcript.push(...extras);\n\t\tthis.state.requestRender?.();\n\t\treturn true;\n\t}\n\n\tappendExtraEntry(entry: TExtraEntry): void {\n\t\tthis.state.extraEntries.push(entry);\n\t\tthis.state.transcript.push(entry);\n\t}\n\n\tentries(): readonly ChatSessionHostEntry<TExtraEntry>[] {\n\t\treturn this.state.transcript;\n\t}\n\n\t/** Tasks outlive tools and turns; only host/session binding grants this read projection. */\n\trefreshTaskStore(): void {\n\t\tconst session = this.state.getAgentSession?.();\n\t\tconst sessionChanged = session !== this.taskSession;\n\t\tif (sessionChanged) {\n\t\t\tthis.unsubscribeTaskBinding?.();\n\t\t\tthis.taskSession = session;\n\t\t\tthis.unsubscribeTaskBinding = session\n\t\t\t\t? watchOwnerTaskStoreBinding(session, () => this.refreshTaskStore())\n\t\t\t\t: undefined;\n\t\t}\n\t\tconst store = session ? getOwnerTaskStore(session) : undefined;\n\t\tif (store === this.taskStore) return;\n\t\tthis.closeTasks();\n\t\tthis.unsubscribeTasks?.();\n\t\tthis.taskStore = store;\n\t\tthis.unsubscribeTasks = undefined;\n\t\tthis.state.liveChat.clearTasks();\n\t\tthis.state.transcriptComponent.invalidate();\n\t\tthis.state.requestRender?.();\n\t\tif (!store) return;\n\t\tconst update = () => {\n\t\t\tif (this.taskRowsInChat) this.state.liveChat.upsertTasks(store.tasks, store);\n\t\t\tthis.state.transcriptComponent.invalidate();\n\t\t\tthis.state.requestRender?.();\n\t\t};\n\t\tthis.unsubscribeTasks = store.subscribe(update);\n\t\tupdate();\n\t}\n\tapplyAgentEvent(event: AgentSessionEvent): boolean {\n\t\tthis.refreshTaskStore();\n\t\treturn applyChatSessionAgentEvent(this.state, event);\n\t}\n\n\t/**\n\t * Restore the factual compaction indicator on a host mounted after the\n\t * `compaction_start` it never saw. The label resolves through the same\n\t * mapping the live event path uses, so the two cannot drift.\n\t *\n\t * Branch summaries deliberately do not paint here: their label belongs to\n\t * a retry lifecycle this re-attached host is not inside, and no event exists\n\t * to clear it after the summary finishes. An absent paintable reason is a\n\t * no-op unless this host is actively showing a compaction label, so unrelated\n\t * workflow delivery busy state is preserved.\n\t */\n\thydrateCompactionStatus(reason: CompactionReason | undefined): void {\n\t\tconst compactionReason = reason === \"branchSummary\" ? undefined : reason;\n\t\tif (compactionReason === undefined) {\n\t\t\tif (!this.state.compacting) return;\n\t\t\tthis.state.compacting = false;\n\t\t\tthis.state.statusMessage = \"\";\n\t\t} else {\n\t\t\tthis.state.compacting = true;\n\t\t\tthis.state.sdkBusy = true;\n\t\t\tthis.state.statusMessage = compactionStatusMessage(compactionReason);\n\t\t}\n\t\tthis.syncAnimationTick();\n\t\tthis.state.requestRender?.();\n\t}\n\n\trender(width: number): string[] {\n\t\treturn this.renderBody(width, 1);\n\t}\n\n\tinvalidate(): void {\n\t\tthis.taskInspector?.invalidate();\n\t\tthis.state.transcriptComponent.invalidate();\n\t\tthis.state.bodyViewport.invalidate();\n\t\tthis.state.editor?.invalidate();\n\t}\n\n\trenderBody(width: number, budget: number): string[] {\n\t\tif (this.taskInspector) {\n\t\t\tif (this.taskInspector.fullscreen) return this.taskInspector.renderViewport(width, budget);\n\t\t\tconst picker = this.taskInspector.renderPicker(width, budget);\n\t\t\tconst remaining = Math.max(0, budget - picker.length);\n\t\t\tconst body = remaining ? renderChatSessionBody(this.state, width, remaining) : [];\n\t\t\treturn [...body, ...Array.from({ length: Math.max(0, remaining - body.length) }, () => \"\"), ...picker];\n\t\t}\n\t\treturn renderChatSessionBody(this.state, width, budget);\n\t}\n\n\t/**\n\t * Rows the body occupies at `width`, whether or not they are on screen.\n\t *\n\t * Pair with `renderBodyRows` to read the whole transcript, not only the\n\t * window the reader is parked on. Both measure the component stack the last\n\t * `renderBody` installed, so call them after at least one body render.\n\t */\n\tbodyRowCount(width: number): number {\n\t\treturn this.state.bodyViewport.rowCount(width);\n\t}\n\n\t/** Body rows `startRow` (inclusive) to `endRow` (exclusive), unscrolled. */\n\trenderBodyRows(width: number, startRow: number, endRow: number): string[] {\n\t\treturn this.state.bodyViewport.renderRows(width, startRow, endRow);\n\t}\n\n\t/**\n\t * Render a live assistant entry whole, or only its tail (the default).\n\t *\n\t * The tail window keeps a fast-streaming turn cheap for a reader following\n\t * the bottom of the body; it also drops everything above the last 240 lines\n\t * from what `bodyRowCount` and `renderBodyRows` report. Returns whether the\n\t * setting changed, so the caller can invalidate the rows that were rendered\n\t * under the old rule.\n\t */\n\tsetStreamingTailWindowEnabled(enabled: boolean): boolean {\n\t\tif (this.state.streamingTailWindowEnabled === enabled) return false;\n\t\tthis.state.streamingTailWindowEnabled = enabled;\n\t\tthis.invalidate();\n\t\treturn true;\n\t}\n\n\trenderPendingMessages(width: number): string[] {\n\t\treturn renderChatSessionPendingMessages(this.state, width);\n\t}\n\n\trenderWorkingStatus(width: number): string[] {\n\t\treturn renderChatSessionWorkingStatus(this.state, width);\n\t}\n\n\trenderUsage(width: number): string[] {\n\t\treturn renderChatSessionUsage(this.state, width);\n\t}\n\n\trenderEditor(width: number): string[] {\n\t\treturn renderChatSessionEditor(this.state, width, this.focused);\n\t}\n\n\trenderTaskFooter(width: number): string[] {\n\t\treturn renderTaskFooter(this.taskStore?.backgroundTasks ?? [], width);\n\t}\n\trenderFooter(width: number): string[] {\n\t\tconst footer = renderChatSessionFooter(this.state, width, this.hasTaskInspector && !this.taskInspectorFullscreen);\n\t\treturn footer.length ? footer : renderTaskFooter(this.taskStore?.backgroundTasks ?? [], width);\n\t}\n\n\thandleScrollInput(data: string): boolean {\n\t\treturn this.state.bodyViewport.handleInput(data);\n\t}\n\n\thandleInput(data: string): boolean {\n\t\treturn handleChatSessionInput(this.state, data, this.editorCallbacks());\n\t}\n\n\tinterrupt(options?: { restoreQueuedMessages?: boolean }): Promise<void> {\n\t\t// Keep the observed settlement: an async wrapper would orphan rejections from Escape callers.\n\t\treturn interruptChatSession(this.state, options);\n\t}\n\n\tasync submit(mode: ChatSessionSubmitMode = \"auto\", submittedText?: string): Promise<void> {\n\t\tawait submitChatSession(this.state, mode, submittedText);\n\t}\n\n\tisStreaming(): boolean {\n\t\treturn isChatSessionStreaming(this.state);\n\t}\n\n\tisBashRunning(): boolean {\n\t\treturn isChatSessionBashRunning(this.state);\n\t}\n\n\tisEditingBashCommand(): boolean {\n\t\treturn this.state.isBashMode;\n\t}\n\n\tisCompacting(): boolean {\n\t\treturn this.state.compacting;\n\t}\n\n\thasInputText(): boolean {\n\t\treturn this.state.inputBuffer.length > 0;\n\t}\n\n\thasAnimationTick(): boolean {\n\t\treturn this.state.animationTimer !== undefined;\n\t}\n\n\tbodyScrollFromBottom(): number {\n\t\treturn this.state.bodyViewport.getScrollFromBottom();\n\t}\n\n\tbodyMaxScroll(): number {\n\t\treturn this.state.bodyViewport.getMaxScroll();\n\t}\n\n\tinputText(): string {\n\t\treturn this.state.inputBuffer;\n\t}\n\tsetInputText(text: string): void {\n\t\tsetChatSessionEditorText(this.state, text);\n\t}\n\n\tstatusText(): string {\n\t\treturn this.state.statusMessage;\n\t}\n\n\tshowWarning(message: string): void {\n\t\tthis.state.statusMessage = message;\n\t\tthis.state.lastWarningMessage = message;\n\t\tthis.state.requestRender?.();\n\t}\n\n\tscrollToBottom(): void {\n\t\tthis.state.bodyViewport.scrollToBottom();\n\t}\n\n\t/**\n\t * Park the body with absolute row `row` at the top of its window, clamped\n\t * to the last rendered layout. Used to reveal a search match the reader\n\t * cannot currently see.\n\t */\n\tscrollBodyTo(row: number): void {\n\t\tthis.state.bodyViewport.scrollTo(row);\n\t}\n\n\tsyncAnimationTick(): void {\n\t\tsyncChatSessionAnimationTick(this.state);\n\t}\n\n\tclearBusyForTerminalWorkflowStage(): void {\n\t\tclearChatSessionBusyForTerminalWorkflowStage(this.state);\n\t}\n\n\t/**\n\t * Start Working for an accepted prompt delivered outside this host — a\n\t * workflow definition auto-sending to its own retained stage. Returns the\n\t * lifecycle token to hand back to `settleExternalPromptLifecycle`.\n\t */\n\tbeginExternalPromptLifecycle(): number | undefined {\n\t\treturn startChatSessionExternalPromptLifecycle(this.state);\n\t}\n\n\t/**\n\t * Reopen Working for a delivery still active after a temporary overlay — a\n\t * pre-turn compaction — cleared it. Preserves factual status text.\n\t */\n\treassertExternalPromptLifecycle(): number | undefined {\n\t\treturn reassertChatSessionExternalPromptLifecycle(this.state);\n\t}\n\n\t/** Settle a lifecycle from `beginExternalPromptLifecycle`. Stale tokens no-op. */\n\tsettleExternalPromptLifecycle(generation: number | undefined): void {\n\t\tsettleChatSessionPromptLifecycle(this.state, generation);\n\t\tsyncChatSessionAnimationTick(this.state);\n\t\tthis.state.requestRender?.();\n\t}\n\n\tdispose(): void {\n\t\tthis.taskInspector?.dispose();\n\t\tthis.unsubscribeTasks?.();\n\t\tthis.unsubscribeTaskBinding?.();\n\t\tdisposeChatSession(this.state);\n\t}\n\n\trestoreQueuedMessagesToEditor(): boolean {\n\t\treturn restoreQueuedMessagesToEditor(this.state);\n\t}\n\n\tprivate editorCallbacks(): {\n\t\tsubmit: (mode: \"auto\" | \"followUp\", submittedText?: string) => void | Promise<void>;\n\t\trestoreQueuedMessagesToEditor: () => boolean;\n\t\tabortCompaction: () => void | Promise<void>;\n\t\tinterrupt: (options?: { restoreQueuedMessages?: boolean }) => void | Promise<void>;\n\t\tabortBash: () => void | Promise<void>;\n\t} {\n\t\treturn {\n\t\t\tsubmit: (mode, submittedText) => this.submit(mode, submittedText),\n\t\t\trestoreQueuedMessagesToEditor: () => this.restoreQueuedMessagesToEditor(),\n\t\t\tabortCompaction: () => abortChatSessionCompaction(this.state),\n\t\t\tinterrupt: (options) => this.interrupt(options),\n\t\t\tabortBash: () => abortChatSessionBash(this.state),\n\t\t};\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"chat-session-host.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Component, Focusable } from \"@earendil-works/pi-tui\";\nimport type { AgentSessionEvent, CompactionReason } from \"../../../core/agent-session.js\";\nimport { repairOrphanToolResults } from \"../../../core/messages.ts\";\nimport { SessionManager } from \"../../../core/session-manager.ts\";\nimport type { SessionStore } from \"../../../core/storage/session/types.js\";\nimport type { TaskId } from \"../../../core/tasks/contracts.js\";\nimport { getOwnerTaskStore, type OwnerTaskStore, watchOwnerTaskStoreBinding } from \"../../../core/tasks/owner-store.js\";\nimport { ownerTaskViewSource, type TaskViewSource } from \"../../../core/tasks/task-view-source.js\";\nimport {\n\tabortChatSessionBash,\n\tabortChatSessionCompaction,\n\tinterruptChatSession,\n\trestoreQueuedMessagesToEditor,\n\tsubmitChatSession,\n} from \"./chat-session-host-actions.ts\";\nimport {\n\tcreateChatSessionEditor,\n\thandleChatSessionInput,\n\tsetChatSessionEditorText,\n} from \"./chat-session-host-editor.ts\";\nimport { applyChatSessionAgentEvent, compactionStatusMessage } from \"./chat-session-host-events.ts\";\nimport {\n\trenderChatSessionBody,\n\trenderChatSessionEditor,\n\trenderChatSessionEntry,\n\trenderChatSessionFooter,\n\trenderChatSessionPendingMessages,\n\trenderChatSessionUsage,\n\trenderChatSessionWorkingStatus,\n\ttranscriptCacheKey,\n} from \"./chat-session-host-rendering.ts\";\nimport {\n\tclearChatSessionBusyForTerminalWorkflowStage,\n\tdisposeChatSession,\n\tisChatSessionBashRunning,\n\tisChatSessionStreaming,\n\treassertChatSessionExternalPromptLifecycle,\n\tsettleChatSessionPromptLifecycle,\n\tstartChatSessionExternalPromptLifecycle,\n\tsyncChatSessionAnimationTick,\n} from \"./chat-session-host-runtime.ts\";\nimport { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport type {\n\tAgentSnapshotMessage,\n\tChatSessionHostEntry,\n\tChatSessionHostOpts,\n\tChatSessionSubmitMode,\n} from \"./chat-session-host-types.ts\";\nimport type { ChatTranscriptEntryLike } from \"./chat-transcript.js\";\nimport { TaskInspector } from \"./task-inspector.js\";\nimport { renderTaskFooter } from \"./task-list.js\";\n\nexport type {\n\tChatSessionHostBashRequest,\n\tChatSessionHostCommands,\n\tChatSessionHostEntry,\n\tChatSessionHostOpts,\n\tChatSessionHostStyle,\n\tChatSessionSubmitMode,\n} from \"./chat-session-host-types.ts\";\n\nexport class ChatSessionHost<TExtraEntry extends ChatTranscriptEntryLike = never> implements Component, Focusable {\n\tfocused = true;\n\n\tprivate readonly state: ChatSessionHostState<TExtraEntry>;\n\tprivate taskStore?: OwnerTaskStore;\n\t/** What `/tasks` and the task footer show: the session's task store, or the host's own task source. */\n\tprivate taskSource?: TaskViewSource;\n\tprivate readonly taskRowsInChat: boolean;\n\tprivate unsubscribeTasks?: () => void;\n\tprivate taskSession?: object;\n\tprivate unsubscribeTaskBinding?: () => void;\n\tprivate taskInspector?: TaskInspector;\n\tprivate historyHydrated = false;\n\n\tconstructor(opts: ChatSessionHostOpts<TExtraEntry>) {\n\t\t// `/tasks` stays a local action owned by the host's `commands.handleSlashCommand`\n\t\t// (see submitChatSession). Hosts that mount the inspector call `openTasks` from\n\t\t// that callback; the host must not intercept it ahead of the owner.\n\t\tthis.taskRowsInChat = opts.taskRowsInChat ?? true;\n\t\tthis.state = new ChatSessionHostState(opts, {\n\t\t\trenderEntry: (state, entry) => renderChatSessionEntry(state, entry),\n\t\t\ttranscriptCacheKey: (state, entry, index) => transcriptCacheKey(state, entry, index),\n\t\t});\n\t\tthis.state.editor = createChatSessionEditor(\n\t\t\tthis.state,\n\t\t\topts.tui,\n\t\t\topts.keybindings,\n\t\t\topts.editorTheme,\n\t\t\topts.editorFactory,\n\t\t\tthis.editorCallbacks(),\n\t\t);\n\t\tif (opts.autocompleteProvider) this.state.editor?.setAutocompleteProvider?.(opts.autocompleteProvider);\n\t\tthis.syncAnimationTick();\n\t\tthis.refreshTaskStore();\n\t}\n\n\topenTasks(id?: string): boolean {\n\t\tconst session = this.state.getAgentSession?.();\n\t\tif (session && !getOwnerTaskStore(session)) session.getAgentTaskHost?.();\n\t\tthis.refreshTaskStore();\n\t\tif (!this.taskSource) {\n\t\t\tthis.showWarning(\"Launched agents and shells will appear here.\");\n\t\t\treturn true;\n\t\t}\n\t\tthis.taskInspector?.dispose();\n\t\tthis.taskInspector = new TaskInspector(\n\t\t\tthis.taskSource,\n\t\t\t() => this.state.requestRender?.(),\n\t\t\t() => this.closeTasks(),\n\t\t);\n\t\tthis.taskInspector.open(id as TaskId | undefined);\n\t\tthis.state.requestRender?.();\n\t\treturn true;\n\t}\n\tget hasTaskInspector(): boolean {\n\t\treturn this.taskInspector !== undefined;\n\t}\n\tget taskInspectorFullscreen(): boolean {\n\t\treturn this.taskInspector?.fullscreen === true;\n\t}\n\tcloseTasks(): void {\n\t\tthis.taskInspector?.dispose();\n\t\tthis.taskInspector = undefined;\n\t\tthis.state.requestRender?.();\n\t}\n\thandleTaskInput(data: string): boolean {\n\t\tif (!this.taskInspector) return false;\n\t\tthis.taskInspector.handleInput(data);\n\t\treturn true;\n\t}\n\tappendMessages(messages: readonly AgentSnapshotMessage[]): void {\n\t\tthis.state.liveChat.appendMessages(messages);\n\t}\n\n\t/**\n\t * Adopt the assistant message a live session is part-way through streaming.\n\t *\n\t * A host mounted mid-turn missed the `message_start` and every delta that\n\t * came before it, and delta-only updates never restate them, so the session's\n\t * in-flight message is the only place that text still exists. Ignored once\n\t * this host is already following a stream of its own.\n\t */\n\thydrateStreamingAssistantMessage(message: AgentSnapshotMessage | undefined): void {\n\t\tif (message === undefined) return;\n\t\tif (this.state.liveChat.hydrateStreamingAssistantMessage(message)) this.state.requestRender?.();\n\t}\n\n\tasync loadSession(store: SessionStore, sessionId: string | undefined): Promise<boolean> {\n\t\tif (\n\t\t\tthis.historyHydrated ||\n\t\t\tthis.state.transcript.length > this.state.extraEntries.length ||\n\t\t\tsessionId === undefined\n\t\t)\n\t\t\treturn true;\n\t\tlet messages: readonly AgentSnapshotMessage[];\n\t\ttry {\n\t\t\tconst manager = await SessionManager.open(store, sessionId);\n\t\t\tmessages = repairOrphanToolResults(manager.buildSessionContext().messages, {\n\t\t\t\trepairTrailing: true,\n\t\t\t}) as readonly AgentSnapshotMessage[];\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.state.disposed) return false;\n\t\tif (this.historyHydrated || this.state.transcript.length > this.state.extraEntries.length) return true;\n\t\tthis.historyHydrated = true;\n\t\tconst extras = this.state.transcript.splice(0);\n\t\tthis.state.liveChat.appendMessages(messages);\n\t\tthis.state.transcript.push(...extras);\n\t\tthis.state.requestRender?.();\n\t\treturn true;\n\t}\n\n\tappendExtraEntry(entry: TExtraEntry): void {\n\t\tthis.state.extraEntries.push(entry);\n\t\tthis.state.transcript.push(entry);\n\t}\n\n\tentries(): readonly ChatSessionHostEntry<TExtraEntry>[] {\n\t\treturn this.state.transcript;\n\t}\n\n\t/** Tasks outlive tools and turns; only host/session binding grants this read projection. */\n\trefreshTaskStore(): void {\n\t\tconst session = this.state.getAgentSession?.();\n\t\tconst sessionChanged = session !== this.taskSession;\n\t\tif (sessionChanged) {\n\t\t\tthis.unsubscribeTaskBinding?.();\n\t\t\tthis.taskSession = session;\n\t\t\tthis.unsubscribeTaskBinding = session\n\t\t\t\t? watchOwnerTaskStoreBinding(session, () => this.refreshTaskStore())\n\t\t\t\t: undefined;\n\t\t}\n\t\tconst store = session ? getOwnerTaskStore(session) : undefined;\n\t\t// A session in another process (a workflow stage on a local worker) has no store here; the host\n\t\t// supplies a source that reads its tasks there.\n\t\tconst source = store ? ownerTaskViewSource(store) : this.state.getTaskSource?.();\n\t\tif (store === this.taskStore && source === this.taskSource) return;\n\t\tthis.closeTasks();\n\t\tthis.unsubscribeTasks?.();\n\t\tthis.taskStore = store;\n\t\tthis.taskSource = source;\n\t\tthis.unsubscribeTasks = undefined;\n\t\tthis.state.liveChat.clearTasks();\n\t\tthis.state.transcriptComponent.invalidate();\n\t\tthis.state.requestRender?.();\n\t\tif (!source) return;\n\t\tconst update = () => {\n\t\t\tif (this.taskRowsInChat) this.state.liveChat.upsertTasks(source.tasks, store);\n\t\t\tthis.state.transcriptComponent.invalidate();\n\t\t\tthis.state.requestRender?.();\n\t\t};\n\t\tthis.unsubscribeTasks = source.subscribe(update);\n\t\tupdate();\n\t}\n\tapplyAgentEvent(event: AgentSessionEvent): boolean {\n\t\tthis.refreshTaskStore();\n\t\treturn applyChatSessionAgentEvent(this.state, event);\n\t}\n\n\t/**\n\t * Restore the factual compaction indicator on a host mounted after the\n\t * `compaction_start` it never saw. The label resolves through the same\n\t * mapping the live event path uses, so the two cannot drift.\n\t *\n\t * Branch summaries deliberately do not paint here: their label belongs to\n\t * a retry lifecycle this re-attached host is not inside, and no event exists\n\t * to clear it after the summary finishes. An absent paintable reason is a\n\t * no-op unless this host is actively showing a compaction label, so unrelated\n\t * workflow delivery busy state is preserved.\n\t */\n\thydrateCompactionStatus(reason: CompactionReason | undefined): void {\n\t\tconst compactionReason = reason === \"branchSummary\" ? undefined : reason;\n\t\tif (compactionReason === undefined) {\n\t\t\tif (!this.state.compacting) return;\n\t\t\tthis.state.compacting = false;\n\t\t\tthis.state.statusMessage = \"\";\n\t\t} else {\n\t\t\tthis.state.compacting = true;\n\t\t\tthis.state.sdkBusy = true;\n\t\t\tthis.state.statusMessage = compactionStatusMessage(compactionReason);\n\t\t}\n\t\tthis.syncAnimationTick();\n\t\tthis.state.requestRender?.();\n\t}\n\n\trender(width: number): string[] {\n\t\treturn this.renderBody(width, 1);\n\t}\n\n\tinvalidate(): void {\n\t\tthis.taskInspector?.invalidate();\n\t\tthis.state.transcriptComponent.invalidate();\n\t\tthis.state.bodyViewport.invalidate();\n\t\tthis.state.editor?.invalidate();\n\t}\n\n\trenderBody(width: number, budget: number): string[] {\n\t\tif (this.taskInspector) {\n\t\t\tif (this.taskInspector.fullscreen) return this.taskInspector.renderViewport(width, budget);\n\t\t\tconst picker = this.taskInspector.renderPicker(width, budget);\n\t\t\tconst remaining = Math.max(0, budget - picker.length);\n\t\t\tconst body = remaining ? renderChatSessionBody(this.state, width, remaining) : [];\n\t\t\treturn [...body, ...Array.from({ length: Math.max(0, remaining - body.length) }, () => \"\"), ...picker];\n\t\t}\n\t\treturn renderChatSessionBody(this.state, width, budget);\n\t}\n\n\t/**\n\t * Rows the body occupies at `width`, whether or not they are on screen.\n\t *\n\t * Pair with `renderBodyRows` to read the whole transcript, not only the\n\t * window the reader is parked on. Both measure the component stack the last\n\t * `renderBody` installed, so call them after at least one body render.\n\t */\n\tbodyRowCount(width: number): number {\n\t\treturn this.state.bodyViewport.rowCount(width);\n\t}\n\n\t/** Body rows `startRow` (inclusive) to `endRow` (exclusive), unscrolled. */\n\trenderBodyRows(width: number, startRow: number, endRow: number): string[] {\n\t\treturn this.state.bodyViewport.renderRows(width, startRow, endRow);\n\t}\n\n\t/**\n\t * Render a live assistant entry whole, or only its tail (the default).\n\t *\n\t * The tail window keeps a fast-streaming turn cheap for a reader following\n\t * the bottom of the body; it also drops everything above the last 240 lines\n\t * from what `bodyRowCount` and `renderBodyRows` report. Returns whether the\n\t * setting changed, so the caller can invalidate the rows that were rendered\n\t * under the old rule.\n\t */\n\tsetStreamingTailWindowEnabled(enabled: boolean): boolean {\n\t\tif (this.state.streamingTailWindowEnabled === enabled) return false;\n\t\tthis.state.streamingTailWindowEnabled = enabled;\n\t\tthis.invalidate();\n\t\treturn true;\n\t}\n\n\trenderPendingMessages(width: number): string[] {\n\t\treturn renderChatSessionPendingMessages(this.state, width);\n\t}\n\n\trenderWorkingStatus(width: number): string[] {\n\t\treturn renderChatSessionWorkingStatus(this.state, width);\n\t}\n\n\trenderUsage(width: number): string[] {\n\t\treturn renderChatSessionUsage(this.state, width);\n\t}\n\n\trenderEditor(width: number): string[] {\n\t\treturn renderChatSessionEditor(this.state, width, this.focused);\n\t}\n\n\trenderTaskFooter(width: number): string[] {\n\t\treturn renderTaskFooter(this.taskSource?.backgroundTasks ?? [], width);\n\t}\n\trenderFooter(width: number): string[] {\n\t\tconst footer = renderChatSessionFooter(this.state, width, this.hasTaskInspector && !this.taskInspectorFullscreen);\n\t\treturn footer.length ? footer : renderTaskFooter(this.taskSource?.backgroundTasks ?? [], width);\n\t}\n\n\thandleScrollInput(data: string): boolean {\n\t\treturn this.state.bodyViewport.handleInput(data);\n\t}\n\n\thandleInput(data: string): boolean {\n\t\treturn handleChatSessionInput(this.state, data, this.editorCallbacks());\n\t}\n\n\tinterrupt(options?: { restoreQueuedMessages?: boolean }): Promise<void> {\n\t\t// Keep the observed settlement: an async wrapper would orphan rejections from Escape callers.\n\t\treturn interruptChatSession(this.state, options);\n\t}\n\n\tasync submit(mode: ChatSessionSubmitMode = \"auto\", submittedText?: string): Promise<void> {\n\t\tawait submitChatSession(this.state, mode, submittedText);\n\t}\n\n\tisStreaming(): boolean {\n\t\treturn isChatSessionStreaming(this.state);\n\t}\n\n\tisBashRunning(): boolean {\n\t\treturn isChatSessionBashRunning(this.state);\n\t}\n\n\tisEditingBashCommand(): boolean {\n\t\treturn this.state.isBashMode;\n\t}\n\n\tisCompacting(): boolean {\n\t\treturn this.state.compacting;\n\t}\n\n\thasInputText(): boolean {\n\t\treturn this.state.inputBuffer.length > 0;\n\t}\n\n\thasAnimationTick(): boolean {\n\t\treturn this.state.animationTimer !== undefined;\n\t}\n\n\tbodyScrollFromBottom(): number {\n\t\treturn this.state.bodyViewport.getScrollFromBottom();\n\t}\n\n\tbodyMaxScroll(): number {\n\t\treturn this.state.bodyViewport.getMaxScroll();\n\t}\n\n\tinputText(): string {\n\t\treturn this.state.inputBuffer;\n\t}\n\tsetInputText(text: string): void {\n\t\tsetChatSessionEditorText(this.state, text);\n\t}\n\n\tstatusText(): string {\n\t\treturn this.state.statusMessage;\n\t}\n\n\tshowWarning(message: string): void {\n\t\tthis.state.statusMessage = message;\n\t\tthis.state.lastWarningMessage = message;\n\t\tthis.state.requestRender?.();\n\t}\n\n\tscrollToBottom(): void {\n\t\tthis.state.bodyViewport.scrollToBottom();\n\t}\n\n\t/**\n\t * Park the body with absolute row `row` at the top of its window, clamped\n\t * to the last rendered layout. Used to reveal a search match the reader\n\t * cannot currently see.\n\t */\n\tscrollBodyTo(row: number): void {\n\t\tthis.state.bodyViewport.scrollTo(row);\n\t}\n\n\tsyncAnimationTick(): void {\n\t\tsyncChatSessionAnimationTick(this.state);\n\t}\n\n\tclearBusyForTerminalWorkflowStage(): void {\n\t\tclearChatSessionBusyForTerminalWorkflowStage(this.state);\n\t}\n\n\t/**\n\t * Start Working for an accepted prompt delivered outside this host — a\n\t * workflow definition auto-sending to its own retained stage. Returns the\n\t * lifecycle token to hand back to `settleExternalPromptLifecycle`.\n\t */\n\tbeginExternalPromptLifecycle(): number | undefined {\n\t\treturn startChatSessionExternalPromptLifecycle(this.state);\n\t}\n\n\t/**\n\t * Reopen Working for a delivery still active after a temporary overlay — a\n\t * pre-turn compaction — cleared it. Preserves factual status text.\n\t */\n\treassertExternalPromptLifecycle(): number | undefined {\n\t\treturn reassertChatSessionExternalPromptLifecycle(this.state);\n\t}\n\n\t/** Settle a lifecycle from `beginExternalPromptLifecycle`. Stale tokens no-op. */\n\tsettleExternalPromptLifecycle(generation: number | undefined): void {\n\t\tsettleChatSessionPromptLifecycle(this.state, generation);\n\t\tsyncChatSessionAnimationTick(this.state);\n\t\tthis.state.requestRender?.();\n\t}\n\n\tdispose(): void {\n\t\tthis.taskInspector?.dispose();\n\t\tthis.unsubscribeTasks?.();\n\t\tthis.unsubscribeTaskBinding?.();\n\t\tdisposeChatSession(this.state);\n\t}\n\n\trestoreQueuedMessagesToEditor(): boolean {\n\t\treturn restoreQueuedMessagesToEditor(this.state);\n\t}\n\n\tprivate editorCallbacks(): {\n\t\tsubmit: (mode: \"auto\" | \"followUp\", submittedText?: string) => void | Promise<void>;\n\t\trestoreQueuedMessagesToEditor: () => boolean;\n\t\tabortCompaction: () => void | Promise<void>;\n\t\tinterrupt: (options?: { restoreQueuedMessages?: boolean }) => void | Promise<void>;\n\t\tabortBash: () => void | Promise<void>;\n\t} {\n\t\treturn {\n\t\t\tsubmit: (mode, submittedText) => this.submit(mode, submittedText),\n\t\t\trestoreQueuedMessagesToEditor: () => this.restoreQueuedMessagesToEditor(),\n\t\t\tabortCompaction: () => abortChatSessionCompaction(this.state),\n\t\t\tinterrupt: (options) => this.interrupt(options),\n\t\t\tabortBash: () => abortChatSessionBash(this.state),\n\t\t};\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-message.ts"],"names":[],"mappings":"AAEA,OAAO,EAAO,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AACpG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"custom-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-message.ts"],"names":[],"mappings":"AAEA,OAAO,EAAO,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AACpG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAmB/D;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,cAAc,CAAC,CAAkB;IACzC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,eAAe,CAAC,CAAY;IACpC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAU;IAE7B,YACC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,EAC/B,cAAc,CAAC,EAAE,eAAe,EAChC,aAAa,GAAE,aAAkC,EACjD,SAAS,SAAI,EACb,WAAW,UAAO,EAelB;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAKnC;IAED,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAIpC;IAEQ,UAAU,IAAI,IAAI,CAG1B;IAED,OAAO,CAAC,OAAO;CAoGf"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Box, Container, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
|
|
2
2
|
import { TASK_COMPLETION_MESSAGE_TYPE } from "../../../core/tasks/completion.js";
|
|
3
|
+
import { TASK_HEARTBEAT_MESSAGE_TYPE } from "../../../core/tasks/heartbeat-notice.js";
|
|
3
4
|
import { getMarkdownTheme, theme } from "../theme/theme.js";
|
|
4
5
|
import { keyHint, keyText } from "./keybinding-hints.js";
|
|
5
6
|
import { completionNoticeFromDetails, TaskCompletionMessage } from "./task-completion-message.js";
|
|
7
|
+
import { heartbeatDetailsFrom, TaskHeartbeatMessage } from "./task-heartbeat-message.js";
|
|
6
8
|
/**
|
|
7
9
|
* Type guard ensuring a value returned by an extension's custom renderer is a
|
|
8
10
|
* real TUI Component (exposes a callable `render`). Extension renderer output is
|
|
@@ -77,6 +79,16 @@ export class CustomMessageComponent extends Container {
|
|
|
77
79
|
return;
|
|
78
80
|
}
|
|
79
81
|
}
|
|
82
|
+
if (this.message.customType === TASK_HEARTBEAT_MESSAGE_TYPE) {
|
|
83
|
+
const details = heartbeatDetailsFrom(this.message.details);
|
|
84
|
+
if (details) {
|
|
85
|
+
this.spacer = new Spacer(1);
|
|
86
|
+
this.customComponent = new TaskHeartbeatMessage(details, this._expanded);
|
|
87
|
+
this.addChild(this.spacer);
|
|
88
|
+
this.addChild(this.customComponent);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
80
92
|
// Try custom renderer first - it handles its own styling
|
|
81
93
|
if (this.customRenderer) {
|
|
82
94
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-message.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TextContent } from \"@bastani/pi-ai/compat\";\nimport type { Component } from \"@earendil-works/pi-tui\";\nimport { Box, Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { MessageRenderer } from \"../../../core/extensions/types.ts\";\nimport type { CustomMessage } from \"../../../core/messages.ts\";\nimport { TASK_COMPLETION_MESSAGE_TYPE } from \"../../../core/tasks/completion.js\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.js\";\nimport { keyHint, keyText } from \"./keybinding-hints.js\";\nimport { completionNoticeFromDetails, TaskCompletionMessage } from \"./task-completion-message.js\";\n\n/**\n * Type guard ensuring a value returned by an extension's custom renderer is a\n * real TUI Component (exposes a callable `render`). Extension renderer output is\n * untrusted at runtime: a renderer that returns a string or other non-Component\n * value would otherwise be added as a child and crash `Container.render()` with\n * \"child.render is not a function\".\n */\nfunction isRenderableComponent(value: unknown): value is Component {\n\treturn typeof value === \"object\" && value !== null && typeof (value as { render?: unknown }).render === \"function\";\n}\n\n/**\n * Component that renders a custom message entry from extensions.\n * Uses distinct styling to differentiate from user messages.\n */\nexport class CustomMessageComponent extends Container {\n\tprivate message: CustomMessage<unknown>;\n\tprivate customRenderer?: MessageRenderer;\n\tprivate box: Box;\n\tprivate spacer?: Spacer;\n\tprivate customComponent?: Component;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate _expanded = false;\n\tprivate outputPad: number;\n\tprivate renderLatex: boolean;\n\n\tconstructor(\n\t\tmessage: CustomMessage<unknown>,\n\t\tcustomRenderer?: MessageRenderer,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\toutputPad = 1,\n\t\trenderLatex = true,\n\t) {\n\t\tsuper();\n\t\tthis.message = message;\n\t\tthis.customRenderer = customRenderer;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.outputPad = outputPad;\n\t\tthis.renderLatex = renderLatex;\n\n\t\t// Create box with purple background (used for default rendering)\n\t\tthis.box = new Box(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\n\t\t// The leading spacer is mounted in rebuild() alongside actual content, so a\n\t\t// renderer that suppresses output (returns null) leaves no blank row.\n\t\tthis.rebuild();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tif (this._expanded !== expanded) {\n\t\t\tthis._expanded = expanded;\n\t\t\tthis.rebuild();\n\t\t}\n\t}\n\n\tsetOutputPad(outputPad: number): void {\n\t\tif (this.outputPad === outputPad) return;\n\t\tthis.outputPad = outputPad;\n\t\tthis.rebuild();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.rebuild();\n\t}\n\n\tprivate rebuild(): void {\n\t\t// Remove previously mounted content (spacer + content) before rebuilding.\n\t\tif (this.customComponent) {\n\t\t\tthis.removeChild(this.customComponent);\n\t\t\tthis.customComponent = undefined;\n\t\t}\n\t\tif (this.spacer) {\n\t\t\tthis.removeChild(this.spacer);\n\t\t\tthis.spacer = undefined;\n\t\t}\n\t\tthis.removeChild(this.box);\n\t\tif (this.message.customType === TASK_COMPLETION_MESSAGE_TYPE) {\n\t\t\tconst notice = completionNoticeFromDetails(this.message.details);\n\t\t\tif (notice) {\n\t\t\t\tthis.spacer = new Spacer(1);\n\t\t\t\tthis.customComponent = new TaskCompletionMessage(notice, this._expanded);\n\t\t\t\tthis.addChild(this.spacer);\n\t\t\t\tthis.addChild(this.customComponent);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Try custom renderer first - it handles its own styling\n\t\tif (this.customRenderer) {\n\t\t\ttry {\n\t\t\t\tconst component = this.customRenderer(\n\t\t\t\t\tthis.message,\n\t\t\t\t\t{ expanded: this._expanded, outputPad: this.outputPad, keyText, keyHint },\n\t\t\t\t\ttheme,\n\t\t\t\t);\n\t\t\t\t// Explicit null = \"handled; render nothing\". Skip the leading spacer\n\t\t\t\t// and the default box entirely so the entry occupies zero rows. The\n\t\t\t\t// workflows inline-form renderer returns null for a rehydrated\n\t\t\t\t// input-form card on /resume so the input widget does not reappear.\n\t\t\t\tif (component === null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Only mount the result if it is a real Component. A non-Component,\n\t\t\t\t// non-null return (string, number, plain object, …) is ignored so we\n\t\t\t\t// fall through to the default rendering path instead of crashing\n\t\t\t\t// Container.render().\n\t\t\t\tif (isRenderableComponent(component)) {\n\t\t\t\t\t// Custom renderer provides its own styled component\n\t\t\t\t\tthis.spacer = new Spacer(1);\n\t\t\t\t\tthis.addChild(this.spacer);\n\t\t\t\t\tthis.customComponent = component;\n\t\t\t\t\tthis.addChild(component);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Fall through to default rendering\n\t\t\t}\n\t\t}\n\n\t\t// Default rendering uses our box, preceded by the standard leading spacer.\n\t\tthis.spacer = new Spacer(1);\n\t\tthis.addChild(this.spacer);\n\t\tthis.addChild(this.box);\n\t\tthis.box.clear();\n\t\tthis.box.setPaddingX(this.outputPad);\n\n\t\t// Default rendering: label + content\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[${this.message.customType}]\\x1b[22m`);\n\t\tthis.box.addChild(new Text(label, 0, 0));\n\t\tthis.box.addChild(new Spacer(1));\n\n\t\t// Extract text content\n\t\tlet text: string;\n\t\tif (typeof this.message.content === \"string\") {\n\t\t\ttext = this.message.content;\n\t\t} else {\n\t\t\ttext = this.message.content\n\t\t\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\\n\");\n\t\t}\n\n\t\tthis.box.addChild(\n\t\t\tnew Markdown(\n\t\t\t\ttext,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\tthis.markdownTheme,\n\t\t\t\t{\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t},\n\t\t\t\t{ renderLatex: this.renderLatex },\n\t\t\t),\n\t\t);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"custom-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-message.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TextContent } from \"@bastani/pi-ai/compat\";\nimport type { Component } from \"@earendil-works/pi-tui\";\nimport { Box, Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { MessageRenderer } from \"../../../core/extensions/types.ts\";\nimport type { CustomMessage } from \"../../../core/messages.ts\";\nimport { TASK_COMPLETION_MESSAGE_TYPE } from \"../../../core/tasks/completion.js\";\nimport { TASK_HEARTBEAT_MESSAGE_TYPE } from \"../../../core/tasks/heartbeat-notice.js\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.js\";\nimport { keyHint, keyText } from \"./keybinding-hints.js\";\nimport { completionNoticeFromDetails, TaskCompletionMessage } from \"./task-completion-message.js\";\nimport { heartbeatDetailsFrom, TaskHeartbeatMessage } from \"./task-heartbeat-message.js\";\n\n/**\n * Type guard ensuring a value returned by an extension's custom renderer is a\n * real TUI Component (exposes a callable `render`). Extension renderer output is\n * untrusted at runtime: a renderer that returns a string or other non-Component\n * value would otherwise be added as a child and crash `Container.render()` with\n * \"child.render is not a function\".\n */\nfunction isRenderableComponent(value: unknown): value is Component {\n\treturn typeof value === \"object\" && value !== null && typeof (value as { render?: unknown }).render === \"function\";\n}\n\n/**\n * Component that renders a custom message entry from extensions.\n * Uses distinct styling to differentiate from user messages.\n */\nexport class CustomMessageComponent extends Container {\n\tprivate message: CustomMessage<unknown>;\n\tprivate customRenderer?: MessageRenderer;\n\tprivate box: Box;\n\tprivate spacer?: Spacer;\n\tprivate customComponent?: Component;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate _expanded = false;\n\tprivate outputPad: number;\n\tprivate renderLatex: boolean;\n\n\tconstructor(\n\t\tmessage: CustomMessage<unknown>,\n\t\tcustomRenderer?: MessageRenderer,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\toutputPad = 1,\n\t\trenderLatex = true,\n\t) {\n\t\tsuper();\n\t\tthis.message = message;\n\t\tthis.customRenderer = customRenderer;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.outputPad = outputPad;\n\t\tthis.renderLatex = renderLatex;\n\n\t\t// Create box with purple background (used for default rendering)\n\t\tthis.box = new Box(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\n\t\t// The leading spacer is mounted in rebuild() alongside actual content, so a\n\t\t// renderer that suppresses output (returns null) leaves no blank row.\n\t\tthis.rebuild();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tif (this._expanded !== expanded) {\n\t\t\tthis._expanded = expanded;\n\t\t\tthis.rebuild();\n\t\t}\n\t}\n\n\tsetOutputPad(outputPad: number): void {\n\t\tif (this.outputPad === outputPad) return;\n\t\tthis.outputPad = outputPad;\n\t\tthis.rebuild();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.rebuild();\n\t}\n\n\tprivate rebuild(): void {\n\t\t// Remove previously mounted content (spacer + content) before rebuilding.\n\t\tif (this.customComponent) {\n\t\t\tthis.removeChild(this.customComponent);\n\t\t\tthis.customComponent = undefined;\n\t\t}\n\t\tif (this.spacer) {\n\t\t\tthis.removeChild(this.spacer);\n\t\t\tthis.spacer = undefined;\n\t\t}\n\t\tthis.removeChild(this.box);\n\t\tif (this.message.customType === TASK_COMPLETION_MESSAGE_TYPE) {\n\t\t\tconst notice = completionNoticeFromDetails(this.message.details);\n\t\t\tif (notice) {\n\t\t\t\tthis.spacer = new Spacer(1);\n\t\t\t\tthis.customComponent = new TaskCompletionMessage(notice, this._expanded);\n\t\t\t\tthis.addChild(this.spacer);\n\t\t\t\tthis.addChild(this.customComponent);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif (this.message.customType === TASK_HEARTBEAT_MESSAGE_TYPE) {\n\t\t\tconst details = heartbeatDetailsFrom(this.message.details);\n\t\t\tif (details) {\n\t\t\t\tthis.spacer = new Spacer(1);\n\t\t\t\tthis.customComponent = new TaskHeartbeatMessage(details, this._expanded);\n\t\t\t\tthis.addChild(this.spacer);\n\t\t\t\tthis.addChild(this.customComponent);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Try custom renderer first - it handles its own styling\n\t\tif (this.customRenderer) {\n\t\t\ttry {\n\t\t\t\tconst component = this.customRenderer(\n\t\t\t\t\tthis.message,\n\t\t\t\t\t{ expanded: this._expanded, outputPad: this.outputPad, keyText, keyHint },\n\t\t\t\t\ttheme,\n\t\t\t\t);\n\t\t\t\t// Explicit null = \"handled; render nothing\". Skip the leading spacer\n\t\t\t\t// and the default box entirely so the entry occupies zero rows. The\n\t\t\t\t// workflows inline-form renderer returns null for a rehydrated\n\t\t\t\t// input-form card on /resume so the input widget does not reappear.\n\t\t\t\tif (component === null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Only mount the result if it is a real Component. A non-Component,\n\t\t\t\t// non-null return (string, number, plain object, …) is ignored so we\n\t\t\t\t// fall through to the default rendering path instead of crashing\n\t\t\t\t// Container.render().\n\t\t\t\tif (isRenderableComponent(component)) {\n\t\t\t\t\t// Custom renderer provides its own styled component\n\t\t\t\t\tthis.spacer = new Spacer(1);\n\t\t\t\t\tthis.addChild(this.spacer);\n\t\t\t\t\tthis.customComponent = component;\n\t\t\t\t\tthis.addChild(component);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Fall through to default rendering\n\t\t\t}\n\t\t}\n\n\t\t// Default rendering uses our box, preceded by the standard leading spacer.\n\t\tthis.spacer = new Spacer(1);\n\t\tthis.addChild(this.spacer);\n\t\tthis.addChild(this.box);\n\t\tthis.box.clear();\n\t\tthis.box.setPaddingX(this.outputPad);\n\n\t\t// Default rendering: label + content\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[${this.message.customType}]\\x1b[22m`);\n\t\tthis.box.addChild(new Text(label, 0, 0));\n\t\tthis.box.addChild(new Spacer(1));\n\n\t\t// Extract text content\n\t\tlet text: string;\n\t\tif (typeof this.message.content === \"string\") {\n\t\t\ttext = this.message.content;\n\t\t} else {\n\t\t\ttext = this.message.content\n\t\t\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\\n\");\n\t\t}\n\n\t\tthis.box.addChild(\n\t\t\tnew Markdown(\n\t\t\t\ttext,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\tthis.markdownTheme,\n\t\t\t\t{\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t},\n\t\t\t\t{ renderLatex: this.renderLatex },\n\t\t\t),\n\t\t);\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-detail.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/task-detail.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAA2C,MAAM,wBAAwB,CAAC;AACjG,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"task-detail.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/task-detail.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAA2C,MAAM,wBAAwB,CAAC;AACjG,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAEzF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAKvE,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG,YAAY,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AAE7F,wBAAgB,iBAAiB,CAChC,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,OAAO,GACrB,gBAAgB,EAAE,CASpB;AAED,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAM7D,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACnC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAW1D;AAKD,oFAAoF;AACpF,qBAAa,UAAW,YAAW,SAAS;IAC3C,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,OAAO,CAAoB;IACnC,YAAY,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAGvD;IAED,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,oBAAe,GAAG,IAAI,CAGrD;IAED,UAAU,IAAI,IAAI,CAAG;IAErB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAe9B;IAED,6FAA6F;IAC7F,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAwErC;CACD"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { stripVTControlCharacters } from "node:util";
|
|
2
2
|
import { Text, truncateToWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
|
|
3
|
+
import { formatTaskHeartbeatDuration } from "../../../core/tasks/heartbeat-notice.js";
|
|
3
4
|
import { theme } from "../theme/theme.js";
|
|
4
5
|
import { keyHintIfBound } from "./keybinding-hints.js";
|
|
5
6
|
import { taskDisplayText, taskMetricsText, taskModelText, taskStatusAppearance } from "./task-row.js";
|
|
@@ -65,6 +66,10 @@ export class TaskDetail {
|
|
|
65
66
|
const lines = [];
|
|
66
67
|
if (task.kind === "agent")
|
|
67
68
|
lines.push(...wrapTextWithAnsi(theme.fg("dim", taskModelText(task)), Math.max(1, width)));
|
|
69
|
+
if (task.execution.kind !== "settled" && task.heartbeatMs !== undefined)
|
|
70
|
+
lines.push(theme.fg("dim", task.heartbeatMs === 0
|
|
71
|
+
? "Heartbeat off"
|
|
72
|
+
: `Heartbeat every ${formatTaskHeartbeatDuration(task.heartbeatMs)}`));
|
|
68
73
|
const section = (label, text, limit, tail = false) => {
|
|
69
74
|
const wrapped = wrapTextWithAnsi(displayMultiline(text), Math.max(1, width));
|
|
70
75
|
lines.push("", theme.fg("muted", theme.bold(label)), ...(tail ? wrapped.slice(-limit) : wrapped.slice(0, limit)));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-detail.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/task-detail.ts"],"names":[],"mappings":"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","sourcesContent":["import { stripVTControlCharacters } from \"node:util\";\nimport { type Component, Text, truncateToWidth, wrapTextWithAnsi } from \"@earendil-works/pi-tui\";\nimport type { Attention, Execution, TaskRecord } from \"../../../core/tasks/contracts.js\";\nimport type { TaskActivity } from \"../../../core/tasks/owner-store.js\";\nimport { theme } from \"../theme/theme.js\";\nimport { keyHintIfBound } from \"./keybinding-hints.js\";\nimport { taskDisplayText, taskMetricsText, taskModelText, taskStatusAppearance } from \"./task-row.js\";\n\nexport type TaskDetailAction = \"transcript\" | \"foreground\" | \"cancel\" | \"input\" | \"question\";\n\nexport function taskDetailActions(\n\texecution: Execution,\n\tattention: Attention,\n\tstdinAvailable: boolean,\n): TaskDetailAction[] {\n\tif (execution.kind === \"settled\") return [\"transcript\"];\n\treturn [\n\t\t\"transcript\",\n\t\t\"foreground\",\n\t\t\"cancel\",\n\t\t...(stdinAvailable ? [\"input\" as const] : []),\n\t\t...(attention.kind === \"input-needed\" ? [\"question\" as const] : []),\n\t];\n}\n\nexport const taskDetailLabels: Record<TaskDetailAction, string> = {\n\ttranscript: \"Inspect transcript\",\n\tforeground: \"Foreground wait\",\n\tcancel: \"Cancel task…\",\n\tinput: \"Input\",\n\tquestion: \"Open question\",\n};\n\nexport type TaskDetailContent = {\n\tprompt?: string;\n\toutput?: string;\n\toutputOmitted?: boolean;\n\tstdinAvailable: boolean;\n\tactivity?: readonly TaskActivity[];\n\tactivityOmitted?: boolean;\n};\n\nexport function taskDetailSummary(task: TaskRecord): string {\n\tconst status = taskStatusAppearance(task);\n\tconst metrics = taskMetricsText(task);\n\tconst exit =\n\t\ttask.execution.kind === \"settled\" && task.execution.result.kind !== \"cancelled\"\n\t\t\t? task.execution.result.exitCode\n\t\t\t: undefined;\n\treturn (\n\t\ttheme.fg(status.color, `${status.icon} ${status.label}`) +\n\t\ttheme.fg(\"dim\", `${metrics ? ` · ${metrics}` : \"\"}${exit === undefined ? \"\" : ` · exit ${exit}`}`)\n\t);\n}\n\nconst displayMultiline = (text: string) =>\n\tstripVTControlCharacters(text).replace(/[\\x00-\\x08\\x0b-\\x1f\\x7f-\\x9f]/g, \" \");\n\n/** A focused view of the same record, never another lifecycle transcript anchor. */\nexport class TaskDetail implements Component {\n\tprivate task: TaskRecord;\n\tprivate content: TaskDetailContent;\n\tconstructor(task: TaskRecord, content: TaskDetailContent) {\n\t\tthis.task = task;\n\t\tthis.content = content;\n\t}\n\n\tupdate(task: TaskRecord, content = this.content): void {\n\t\tthis.task = task;\n\t\tthis.content = content;\n\t}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tconst lines = [\n\t\t\ttheme.bold(taskDisplayText(this.task.title)),\n\t\t\ttaskDetailSummary(this.task),\n\t\t\t...this.renderContent(width),\n\t\t];\n\t\tlines.push(\"\", theme.fg(\"muted\", theme.bold(\"Actions\")));\n\t\tfor (const action of taskDetailActions(this.task.execution, this.task.attention, this.content.stdinAvailable)) {\n\t\t\tconst hint =\n\t\t\t\taction === \"foreground\" || action === \"cancel\" || action === \"input\"\n\t\t\t\t\t? keyHintIfBound(`app.tasks.${action}`, taskDetailLabels[action])\n\t\t\t\t\t: \"\";\n\t\t\tlines.push(hint || taskDetailLabels[action]);\n\t\t}\n\t\treturn new Text(lines.join(\"\\n\"), 0, 0).render(width);\n\t}\n\n\t/** Body only: viewport owners pin identity, status and actions outside scrolling content. */\n\trenderContent(width: number): string[] {\n\t\tconst task = this.task;\n\t\tconst lines: string[] = [];\n\t\tif (task.kind === \"agent\")\n\t\t\tlines.push(...wrapTextWithAnsi(theme.fg(\"dim\", taskModelText(task)), Math.max(1, width)));\n\t\tconst section = (label: string, text: string, limit: number, tail = false) => {\n\t\t\tconst wrapped = wrapTextWithAnsi(displayMultiline(text), Math.max(1, width));\n\t\t\tlines.push(\n\t\t\t\t\"\",\n\t\t\t\ttheme.fg(\"muted\", theme.bold(label)),\n\t\t\t\t...(tail ? wrapped.slice(-limit) : wrapped.slice(0, limit)),\n\t\t\t);\n\t\t\tif (wrapped.length > limit || (tail && this.content.outputOmitted))\n\t\t\t\tlines.push(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"dim\",\n\t\t\t\t\t\ttail ? \"Earlier output omitted · retained tail shown\" : \"… Inspect transcript for the full text\",\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t};\n\t\tif (task.execution.kind === \"settled\" && task.execution.result.kind === \"failed\") {\n\t\t\tlines.push(theme.fg(\"error\", theme.bold(\"Error\")));\n\t\t\tlines.push(\n\t\t\t\t...wrapTextWithAnsi(theme.fg(\"error\", displayMultiline(task.execution.result.message)), Math.max(1, width)),\n\t\t\t);\n\t\t}\n\t\tif (task.execution.kind !== \"settled\" && task.attention.kind === \"input-needed\")\n\t\t\tsection(\"Input needed\", task.attention.prompt, 5);\n\t\tif (task.execution.kind !== \"settled\" && task.attention.kind === \"no-recent-activity\")\n\t\t\tlines.push(theme.fg(\"warning\", \"No recent activity reported\"));\n\t\tconst activities = (this.content.activity ?? []).flatMap(({ report }) =>\n\t\t\treport.change.kind === \"action\" ? [`${report.change.tool} ${report.change.text}`] : [],\n\t\t);\n\t\tif (task.currentAction) {\n\t\t\tconst current = `${task.currentAction.tool} ${task.currentAction.text}`;\n\t\t\tif (activities[activities.length - 1] !== current) activities.push(current);\n\t\t}\n\t\tif (activities.length) {\n\t\t\tlines.push(\"\", theme.fg(\"muted\", theme.bold(\"Recent activity\")));\n\t\t\tif (this.content.activityOmitted || activities.length > 5)\n\t\t\t\tlines.push(theme.fg(\"dim\", \"Earlier activity omitted\"));\n\t\t\tconst recent = activities.slice(-5);\n\t\t\tlines.push(\n\t\t\t\t...recent.map((text, index) =>\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\tindex === recent.length - 1 ? \"muted\" : \"dim\",\n\t\t\t\t\t\ttruncateToWidth(`${index === recent.length - 1 ? \"›\" : \" \"} ${taskDisplayText(text)}`, width),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tif (task.kind === \"command\") {\n\t\t\tsection(\"Command\", this.content.prompt ?? task.title, 3);\n\t\t\tsection(\"Output\", this.content.output || \"No output available\", 10, true);\n\t\t} else {\n\t\t\tif (this.content.prompt !== undefined) section(\"Prompt\", this.content.prompt, 3);\n\t\t\tif (this.content.output) section(\"Latest response\", this.content.output, 5);\n\t\t}\n\t\tlines.push(\n\t\t\t\"\",\n\t\t\ttheme.fg(\"dim\", `Owner ${taskDisplayText(task.ref.ownerId)} · Task ${taskDisplayText(task.ref.taskId)}`),\n\t\t);\n\t\treturn new Text(lines.join(\"\\n\"), 0, 0).render(width);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"task-detail.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/task-detail.ts"],"names":[],"mappings":"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","sourcesContent":["import { stripVTControlCharacters } from \"node:util\";\nimport { type Component, Text, truncateToWidth, wrapTextWithAnsi } from \"@earendil-works/pi-tui\";\nimport type { Attention, Execution, TaskRecord } from \"../../../core/tasks/contracts.js\";\nimport { formatTaskHeartbeatDuration } from \"../../../core/tasks/heartbeat-notice.js\";\nimport type { TaskActivity } from \"../../../core/tasks/owner-store.js\";\nimport { theme } from \"../theme/theme.js\";\nimport { keyHintIfBound } from \"./keybinding-hints.js\";\nimport { taskDisplayText, taskMetricsText, taskModelText, taskStatusAppearance } from \"./task-row.js\";\n\nexport type TaskDetailAction = \"transcript\" | \"foreground\" | \"cancel\" | \"input\" | \"question\";\n\nexport function taskDetailActions(\n\texecution: Execution,\n\tattention: Attention,\n\tstdinAvailable: boolean,\n): TaskDetailAction[] {\n\tif (execution.kind === \"settled\") return [\"transcript\"];\n\treturn [\n\t\t\"transcript\",\n\t\t\"foreground\",\n\t\t\"cancel\",\n\t\t...(stdinAvailable ? [\"input\" as const] : []),\n\t\t...(attention.kind === \"input-needed\" ? [\"question\" as const] : []),\n\t];\n}\n\nexport const taskDetailLabels: Record<TaskDetailAction, string> = {\n\ttranscript: \"Inspect transcript\",\n\tforeground: \"Foreground wait\",\n\tcancel: \"Cancel task…\",\n\tinput: \"Input\",\n\tquestion: \"Open question\",\n};\n\nexport type TaskDetailContent = {\n\tprompt?: string;\n\toutput?: string;\n\toutputOmitted?: boolean;\n\tstdinAvailable: boolean;\n\tactivity?: readonly TaskActivity[];\n\tactivityOmitted?: boolean;\n};\n\nexport function taskDetailSummary(task: TaskRecord): string {\n\tconst status = taskStatusAppearance(task);\n\tconst metrics = taskMetricsText(task);\n\tconst exit =\n\t\ttask.execution.kind === \"settled\" && task.execution.result.kind !== \"cancelled\"\n\t\t\t? task.execution.result.exitCode\n\t\t\t: undefined;\n\treturn (\n\t\ttheme.fg(status.color, `${status.icon} ${status.label}`) +\n\t\ttheme.fg(\"dim\", `${metrics ? ` · ${metrics}` : \"\"}${exit === undefined ? \"\" : ` · exit ${exit}`}`)\n\t);\n}\n\nconst displayMultiline = (text: string) =>\n\tstripVTControlCharacters(text).replace(/[\\x00-\\x08\\x0b-\\x1f\\x7f-\\x9f]/g, \" \");\n\n/** A focused view of the same record, never another lifecycle transcript anchor. */\nexport class TaskDetail implements Component {\n\tprivate task: TaskRecord;\n\tprivate content: TaskDetailContent;\n\tconstructor(task: TaskRecord, content: TaskDetailContent) {\n\t\tthis.task = task;\n\t\tthis.content = content;\n\t}\n\n\tupdate(task: TaskRecord, content = this.content): void {\n\t\tthis.task = task;\n\t\tthis.content = content;\n\t}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tconst lines = [\n\t\t\ttheme.bold(taskDisplayText(this.task.title)),\n\t\t\ttaskDetailSummary(this.task),\n\t\t\t...this.renderContent(width),\n\t\t];\n\t\tlines.push(\"\", theme.fg(\"muted\", theme.bold(\"Actions\")));\n\t\tfor (const action of taskDetailActions(this.task.execution, this.task.attention, this.content.stdinAvailable)) {\n\t\t\tconst hint =\n\t\t\t\taction === \"foreground\" || action === \"cancel\" || action === \"input\"\n\t\t\t\t\t? keyHintIfBound(`app.tasks.${action}`, taskDetailLabels[action])\n\t\t\t\t\t: \"\";\n\t\t\tlines.push(hint || taskDetailLabels[action]);\n\t\t}\n\t\treturn new Text(lines.join(\"\\n\"), 0, 0).render(width);\n\t}\n\n\t/** Body only: viewport owners pin identity, status and actions outside scrolling content. */\n\trenderContent(width: number): string[] {\n\t\tconst task = this.task;\n\t\tconst lines: string[] = [];\n\t\tif (task.kind === \"agent\")\n\t\t\tlines.push(...wrapTextWithAnsi(theme.fg(\"dim\", taskModelText(task)), Math.max(1, width)));\n\t\tif (task.execution.kind !== \"settled\" && task.heartbeatMs !== undefined)\n\t\t\tlines.push(\n\t\t\t\ttheme.fg(\n\t\t\t\t\t\"dim\",\n\t\t\t\t\ttask.heartbeatMs === 0\n\t\t\t\t\t\t? \"Heartbeat off\"\n\t\t\t\t\t\t: `Heartbeat every ${formatTaskHeartbeatDuration(task.heartbeatMs)}`,\n\t\t\t\t),\n\t\t\t);\n\t\tconst section = (label: string, text: string, limit: number, tail = false) => {\n\t\t\tconst wrapped = wrapTextWithAnsi(displayMultiline(text), Math.max(1, width));\n\t\t\tlines.push(\n\t\t\t\t\"\",\n\t\t\t\ttheme.fg(\"muted\", theme.bold(label)),\n\t\t\t\t...(tail ? wrapped.slice(-limit) : wrapped.slice(0, limit)),\n\t\t\t);\n\t\t\tif (wrapped.length > limit || (tail && this.content.outputOmitted))\n\t\t\t\tlines.push(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"dim\",\n\t\t\t\t\t\ttail ? \"Earlier output omitted · retained tail shown\" : \"… Inspect transcript for the full text\",\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t};\n\t\tif (task.execution.kind === \"settled\" && task.execution.result.kind === \"failed\") {\n\t\t\tlines.push(theme.fg(\"error\", theme.bold(\"Error\")));\n\t\t\tlines.push(\n\t\t\t\t...wrapTextWithAnsi(theme.fg(\"error\", displayMultiline(task.execution.result.message)), Math.max(1, width)),\n\t\t\t);\n\t\t}\n\t\tif (task.execution.kind !== \"settled\" && task.attention.kind === \"input-needed\")\n\t\t\tsection(\"Input needed\", task.attention.prompt, 5);\n\t\tif (task.execution.kind !== \"settled\" && task.attention.kind === \"no-recent-activity\")\n\t\t\tlines.push(theme.fg(\"warning\", \"No recent activity reported\"));\n\t\tconst activities = (this.content.activity ?? []).flatMap(({ report }) =>\n\t\t\treport.change.kind === \"action\" ? [`${report.change.tool} ${report.change.text}`] : [],\n\t\t);\n\t\tif (task.currentAction) {\n\t\t\tconst current = `${task.currentAction.tool} ${task.currentAction.text}`;\n\t\t\tif (activities[activities.length - 1] !== current) activities.push(current);\n\t\t}\n\t\tif (activities.length) {\n\t\t\tlines.push(\"\", theme.fg(\"muted\", theme.bold(\"Recent activity\")));\n\t\t\tif (this.content.activityOmitted || activities.length > 5)\n\t\t\t\tlines.push(theme.fg(\"dim\", \"Earlier activity omitted\"));\n\t\t\tconst recent = activities.slice(-5);\n\t\t\tlines.push(\n\t\t\t\t...recent.map((text, index) =>\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\tindex === recent.length - 1 ? \"muted\" : \"dim\",\n\t\t\t\t\t\ttruncateToWidth(`${index === recent.length - 1 ? \"›\" : \" \"} ${taskDisplayText(text)}`, width),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tif (task.kind === \"command\") {\n\t\t\tsection(\"Command\", this.content.prompt ?? task.title, 3);\n\t\t\tsection(\"Output\", this.content.output || \"No output available\", 10, true);\n\t\t} else {\n\t\t\tif (this.content.prompt !== undefined) section(\"Prompt\", this.content.prompt, 3);\n\t\t\tif (this.content.output) section(\"Latest response\", this.content.output, 5);\n\t\t}\n\t\tlines.push(\n\t\t\t\"\",\n\t\t\ttheme.fg(\"dim\", `Owner ${taskDisplayText(task.ref.ownerId)} · Task ${taskDisplayText(task.ref.taskId)}`),\n\t\t);\n\t\treturn new Text(lines.join(\"\\n\"), 0, 0).render(width);\n\t}\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Component } from "@earendil-works/pi-tui";
|
|
2
|
+
import { type TaskHeartbeatDetails } from "../../../core/tasks/heartbeat-notice.js";
|
|
3
|
+
/** The structured heartbeat a card was raised with, or `undefined` when the entry does not carry one. */
|
|
4
|
+
export declare function heartbeatDetailsFrom(details: unknown): TaskHeartbeatDetails | undefined;
|
|
5
|
+
/** Compact heartbeat card in the owning chat: one row per task, status and output lines when expanded. */
|
|
6
|
+
export declare class TaskHeartbeatMessage implements Component {
|
|
7
|
+
private readonly details;
|
|
8
|
+
private readonly expanded;
|
|
9
|
+
constructor(details: TaskHeartbeatDetails, expanded: boolean);
|
|
10
|
+
invalidate(): void;
|
|
11
|
+
render(width: number): string[];
|
|
12
|
+
private renderContent;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=task-heartbeat-message.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-heartbeat-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/task-heartbeat-message.ts"],"names":[],"mappings":"AACA,OAAO,EAAO,KAAK,SAAS,EAAqC,MAAM,wBAAwB,CAAC;AAChG,OAAO,EAGN,KAAK,oBAAoB,EAGzB,MAAM,yCAAyC,CAAC;AAoBjD,yGAAyG;AACzG,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,oBAAoB,GAAG,SAAS,CAUvF;AAID,0GAA0G;AAC1G,qBAAa,oBAAqB,YAAW,SAAS;IACrD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,YAAY,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,OAAO,EAG3D;IACD,UAAU,IAAI,IAAI,CAAG;IACrB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ9B;IACD,OAAO,CAAC,aAAa;CAuBrB"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { stripVTControlCharacters } from "node:util";
|
|
2
|
+
import { Box, truncateToWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
|
|
3
|
+
import { formatTaskHeartbeatDuration, formatTaskHeartbeatStatus, taskHeartbeatKindLabel, } from "../../../core/tasks/heartbeat-notice.js";
|
|
4
|
+
import { theme } from "../theme/theme.js";
|
|
5
|
+
import { keyHintIfBound } from "./keybinding-hints.js";
|
|
6
|
+
function isNamedTask(value) {
|
|
7
|
+
if (!value || typeof value !== "object")
|
|
8
|
+
return false;
|
|
9
|
+
const task = value;
|
|
10
|
+
return (typeof task.taskId === "string" &&
|
|
11
|
+
(task.kind === "agent" || task.kind === "command") &&
|
|
12
|
+
typeof task.title === "string");
|
|
13
|
+
}
|
|
14
|
+
function isHeartbeatTask(value) {
|
|
15
|
+
if (!isNamedTask(value))
|
|
16
|
+
return false;
|
|
17
|
+
const task = value;
|
|
18
|
+
return typeof task.elapsedMs === "number" && typeof task.intervalMs === "number";
|
|
19
|
+
}
|
|
20
|
+
/** The structured heartbeat a card was raised with, or `undefined` when the entry does not carry one. */
|
|
21
|
+
export function heartbeatDetailsFrom(details) {
|
|
22
|
+
if (!details || typeof details !== "object")
|
|
23
|
+
return undefined;
|
|
24
|
+
const candidate = details;
|
|
25
|
+
if (!Array.isArray(candidate.tasks) || !candidate.tasks.every(isHeartbeatTask))
|
|
26
|
+
return undefined;
|
|
27
|
+
return {
|
|
28
|
+
scheduledAt: typeof candidate.scheduledAt === "number" ? candidate.scheduledAt : 0,
|
|
29
|
+
tasks: candidate.tasks,
|
|
30
|
+
more: Array.isArray(candidate.more) ? candidate.more.filter(isNamedTask) : [],
|
|
31
|
+
moreCount: typeof candidate.moreCount === "number" ? candidate.moreCount : 0,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const clean = (value) => stripVTControlCharacters(value).replace(/[\x00-\x1f\x7f-\x9f]+/g, " ");
|
|
35
|
+
/** Compact heartbeat card in the owning chat: one row per task, status and output lines when expanded. */
|
|
36
|
+
export class TaskHeartbeatMessage {
|
|
37
|
+
details;
|
|
38
|
+
expanded;
|
|
39
|
+
constructor(details, expanded) {
|
|
40
|
+
this.details = details;
|
|
41
|
+
this.expanded = expanded;
|
|
42
|
+
}
|
|
43
|
+
invalidate() { }
|
|
44
|
+
render(width) {
|
|
45
|
+
if (width < 1)
|
|
46
|
+
return [];
|
|
47
|
+
const card = new Box(width >= 3 ? 1 : 0, 1, (line) => theme.bg("customMessageBg", line));
|
|
48
|
+
card.addChild({
|
|
49
|
+
invalidate() { },
|
|
50
|
+
render: (innerWidth) => this.renderContent(innerWidth),
|
|
51
|
+
});
|
|
52
|
+
return card.render(width);
|
|
53
|
+
}
|
|
54
|
+
renderContent(width) {
|
|
55
|
+
const { tasks, moreCount } = this.details;
|
|
56
|
+
const total = tasks.length + moreCount;
|
|
57
|
+
const lines = [
|
|
58
|
+
theme.fg("accent", theme.bold(`♥ Task heartbeat · ${total === 1 ? "1 task" : `${total} tasks`} still running`)),
|
|
59
|
+
];
|
|
60
|
+
for (const task of tasks) {
|
|
61
|
+
lines.push(` ${theme.fg("accent", `${taskHeartbeatKindLabel(task.kind)} ${task.taskId}`)} ${theme.fg("text", clean(task.title))} ${theme.fg("dim", `· ${formatTaskHeartbeatDuration(task.elapsedMs)}`)}`);
|
|
62
|
+
if (!this.expanded)
|
|
63
|
+
continue;
|
|
64
|
+
for (const row of wrapTextWithAnsi(clean(formatTaskHeartbeatStatus(task)), Math.max(1, width - 4)))
|
|
65
|
+
lines.push(theme.fg("muted", ` ${row}`));
|
|
66
|
+
for (const line of task.output?.tail ?? [])
|
|
67
|
+
lines.push(theme.fg("dim", ` │ ${clean(line)}`));
|
|
68
|
+
}
|
|
69
|
+
if (moreCount > 0)
|
|
70
|
+
lines.push(theme.fg("muted", ` and ${moreCount} more`));
|
|
71
|
+
const expand = this.expanded ? "" : keyHintIfBound("app.tools.expand", "Expand");
|
|
72
|
+
lines.push(theme.fg("dim", `${expand ? `(${expand}) · ` : ""}periodic check · /tasks to inspect`));
|
|
73
|
+
return lines.map((line) => truncateToWidth(line, Math.max(1, width)));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=task-heartbeat-message.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-heartbeat-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/task-heartbeat-message.ts"],"names":[],"mappings":"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","sourcesContent":["import { stripVTControlCharacters } from \"node:util\";\nimport { Box, type Component, truncateToWidth, wrapTextWithAnsi } from \"@earendil-works/pi-tui\";\nimport {\n\tformatTaskHeartbeatDuration,\n\tformatTaskHeartbeatStatus,\n\ttype TaskHeartbeatDetails,\n\ttype TaskHeartbeatTask,\n\ttaskHeartbeatKindLabel,\n} from \"../../../core/tasks/heartbeat-notice.js\";\nimport { theme } from \"../theme/theme.js\";\nimport { keyHintIfBound } from \"./keybinding-hints.js\";\n\nfunction isNamedTask(value: unknown): value is TaskHeartbeatDetails[\"more\"][number] {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst task = value as Partial<TaskHeartbeatTask>;\n\treturn (\n\t\ttypeof task.taskId === \"string\" &&\n\t\t(task.kind === \"agent\" || task.kind === \"command\") &&\n\t\ttypeof task.title === \"string\"\n\t);\n}\n\nfunction isHeartbeatTask(value: unknown): value is TaskHeartbeatTask {\n\tif (!isNamedTask(value)) return false;\n\tconst task = value as Partial<TaskHeartbeatTask>;\n\treturn typeof task.elapsedMs === \"number\" && typeof task.intervalMs === \"number\";\n}\n\n/** The structured heartbeat a card was raised with, or `undefined` when the entry does not carry one. */\nexport function heartbeatDetailsFrom(details: unknown): TaskHeartbeatDetails | undefined {\n\tif (!details || typeof details !== \"object\") return undefined;\n\tconst candidate = details as Partial<TaskHeartbeatDetails>;\n\tif (!Array.isArray(candidate.tasks) || !candidate.tasks.every(isHeartbeatTask)) return undefined;\n\treturn {\n\t\tscheduledAt: typeof candidate.scheduledAt === \"number\" ? candidate.scheduledAt : 0,\n\t\ttasks: candidate.tasks,\n\t\tmore: Array.isArray(candidate.more) ? candidate.more.filter(isNamedTask) : [],\n\t\tmoreCount: typeof candidate.moreCount === \"number\" ? candidate.moreCount : 0,\n\t};\n}\n\nconst clean = (value: string) => stripVTControlCharacters(value).replace(/[\\x00-\\x1f\\x7f-\\x9f]+/g, \" \");\n\n/** Compact heartbeat card in the owning chat: one row per task, status and output lines when expanded. */\nexport class TaskHeartbeatMessage implements Component {\n\tprivate readonly details: TaskHeartbeatDetails;\n\tprivate readonly expanded: boolean;\n\tconstructor(details: TaskHeartbeatDetails, expanded: boolean) {\n\t\tthis.details = details;\n\t\tthis.expanded = expanded;\n\t}\n\tinvalidate(): void {}\n\trender(width: number): string[] {\n\t\tif (width < 1) return [];\n\t\tconst card = new Box(width >= 3 ? 1 : 0, 1, (line) => theme.bg(\"customMessageBg\", line));\n\t\tcard.addChild({\n\t\t\tinvalidate() {},\n\t\t\trender: (innerWidth) => this.renderContent(innerWidth),\n\t\t});\n\t\treturn card.render(width);\n\t}\n\tprivate renderContent(width: number): string[] {\n\t\tconst { tasks, moreCount } = this.details;\n\t\tconst total = tasks.length + moreCount;\n\t\tconst lines = [\n\t\t\ttheme.fg(\n\t\t\t\t\"accent\",\n\t\t\t\ttheme.bold(`♥ Task heartbeat · ${total === 1 ? \"1 task\" : `${total} tasks`} still running`),\n\t\t\t),\n\t\t];\n\t\tfor (const task of tasks) {\n\t\t\tlines.push(\n\t\t\t\t` ${theme.fg(\"accent\", `${taskHeartbeatKindLabel(task.kind)} ${task.taskId}`)} ${theme.fg(\"text\", clean(task.title))} ${theme.fg(\"dim\", `· ${formatTaskHeartbeatDuration(task.elapsedMs)}`)}`,\n\t\t\t);\n\t\t\tif (!this.expanded) continue;\n\t\t\tfor (const row of wrapTextWithAnsi(clean(formatTaskHeartbeatStatus(task)), Math.max(1, width - 4)))\n\t\t\t\tlines.push(theme.fg(\"muted\", ` ${row}`));\n\t\t\tfor (const line of task.output?.tail ?? []) lines.push(theme.fg(\"dim\", ` │ ${clean(line)}`));\n\t\t}\n\t\tif (moreCount > 0) lines.push(theme.fg(\"muted\", ` and ${moreCount} more`));\n\t\tconst expand = this.expanded ? \"\" : keyHintIfBound(\"app.tools.expand\", \"Expand\");\n\t\tlines.push(theme.fg(\"dim\", `${expand ? `(${expand}) · ` : \"\"}periodic check · /tasks to inspect`));\n\t\treturn lines.map((line) => truncateToWidth(line, Math.max(1, width)));\n\t}\n}\n"]}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type Component } from "@earendil-works/pi-tui";
|
|
2
2
|
import type { PromptRoute, TaskId } from "../../../core/tasks/contracts.js";
|
|
3
|
-
import
|
|
3
|
+
import { OwnerTaskStore } from "../../../core/tasks/owner-store.js";
|
|
4
|
+
import { type TaskViewSource } from "../../../core/tasks/task-view-source.js";
|
|
4
5
|
import { TaskNavigation } from "./task-navigation.js";
|
|
5
|
-
/** Focused view only. The
|
|
6
|
+
/** Focused view only. The task source and original session remain the authorities. */
|
|
6
7
|
export declare class TaskInspector implements Component {
|
|
7
8
|
readonly navigation: TaskNavigation;
|
|
8
9
|
private actionIndex;
|
|
@@ -16,6 +17,8 @@ export declare class TaskInspector implements Component {
|
|
|
16
17
|
private transcriptPageRows;
|
|
17
18
|
private cursor?;
|
|
18
19
|
private status;
|
|
20
|
+
/** Why the last stop did not reach its task; shown under the list until the next key. */
|
|
21
|
+
private stopFailure;
|
|
19
22
|
private scroll;
|
|
20
23
|
private detailContent;
|
|
21
24
|
private detailTaskId?;
|
|
@@ -24,7 +27,7 @@ export declare class TaskInspector implements Component {
|
|
|
24
27
|
private statusWatch?;
|
|
25
28
|
private readonly input;
|
|
26
29
|
private readonly unsubscribe;
|
|
27
|
-
constructor(privateStore: OwnerTaskStore, privateRender: () => void, privateClose: () => void, openQuestion?: (route: PromptRoute) => void);
|
|
30
|
+
constructor(privateStore: OwnerTaskStore | TaskViewSource, privateRender: () => void, privateClose: () => void, openQuestion?: (route: PromptRoute) => void);
|
|
28
31
|
private readonly store;
|
|
29
32
|
private readonly requestRender;
|
|
30
33
|
private readonly close;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-inspector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/task-inspector.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"task-inspector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/task-inspector.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,SAAS,EAOd,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAenG,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,sFAAsF;AACtF,qBAAa,aAAc,YAAW,SAAS;IAC9C,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,YAAY,CAAC,CAA4B;IACjD,OAAO,CAAC,UAAU,CAAC,CAAc;IACjC,OAAO,CAAC,cAAc,CAAC,CAAqB;IAC5C,OAAO,CAAC,wBAAwB,CAAS;IACzC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,MAAM,CAAM;IACpB,yFAAyF;IACzF,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,aAAa,CAAiD;IACtE,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAC,CAA0C;IAC9D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,YACC,YAAY,EAAE,cAAc,GAAG,cAAc,EAC7C,aAAa,EAAE,MAAM,IAAI,EACzB,YAAY,EAAE,MAAM,IAAI,EACxB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,EA8D3C;IACD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAa;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IACnC,IAAI,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAEtB;IACD,OAAO,CAAC,eAAe;IAGvB,OAAO,IAAI,IAAI,CAMd;IACD,UAAU,IAAI,IAAI,CAEjB;IACD,OAAO,CAAC,QAAQ;IAGhB,OAAO,CAAC,cAAc;YAKR,SAAS;IAQvB,OAAO,CAAC,kBAAkB;IAI1B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAgBtB,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,iBAAiB;YAUX,cAAc;YAkFd,UAAU;IAyCxB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAyFjC;IACD,OAAO,CAAC,iBAAiB;IAKzB,qFAAqF;IACrF,IAAI,UAAU,IAAI,OAAO,CAMxB;IACD,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,CAE3D;IACD,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE9B;IACD,OAAO,CAAC,wBAAwB;IAsChC,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CA0EtD;IACD,OAAO,CAAC,SAAS;CAsDjB"}
|