@tyvm/knowhow 0.0.146 → 0.0.148
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/autodoc/cli-reference.md +36 -7
- package/bin/knowhow.js +8 -6
- package/package.json +1 -1
- package/src/agents/base/base.ts +51 -23
- package/src/agents/historyRollback.ts +36 -0
- package/src/agents/tools/execCommand.ts +102 -320
- package/src/agents/tools/list.ts +2 -2
- package/src/agents/tools/startAgentTask.ts +91 -34
- package/src/ai.ts +4 -1
- package/src/auth/browserLogin.ts +9 -3
- package/src/auth/keyAuth.ts +115 -0
- package/src/auth/keyManager.ts +166 -0
- package/src/chat/CliChatService.ts +23 -2
- package/src/chat/modules/AgentModule.ts +114 -33
- package/src/chat/modules/AskModule.ts +2 -0
- package/src/chat/modules/BaseChatModule.ts +0 -1
- package/src/chat/modules/CustomCommandsModule.ts +2 -0
- package/src/chat/modules/InternalChatModule.ts +7 -0
- package/src/chat/modules/RemoteSyncModule.ts +4 -0
- package/src/chat/modules/RendererModule.ts +2 -0
- package/src/chat/modules/SearchModule.ts +2 -0
- package/src/chat/modules/SessionsModule.ts +103 -34
- package/src/chat/modules/SetupModule.ts +2 -0
- package/src/chat/modules/ShellCommandModule.ts +2 -0
- package/src/chat/modules/SystemModule.ts +2 -0
- package/src/chat/modules/ToolCommandModule.ts +102 -0
- package/src/chat/modules/index.ts +1 -0
- package/src/chat/types.ts +3 -1
- package/src/cli.ts +10 -3
- package/src/clients/http.ts +67 -7
- package/src/clients/index.ts +4 -0
- package/src/commands/agent.ts +1 -38
- package/src/commands/agents.ts +455 -60
- package/src/commands/misc.ts +3 -2
- package/src/commands/processes.ts +138 -0
- package/src/commands/services.ts +23 -1
- package/src/index.ts +1 -0
- package/src/login.ts +89 -28
- package/src/processes/ProcessManager.ts +95 -0
- package/src/processes/managedProcessShim.ts +115 -0
- package/src/services/AgentService.ts +2 -0
- package/src/services/AgentSyncFs.ts +77 -1
- package/src/services/AgentSyncKnowhowWeb.ts +22 -4
- package/src/services/BehaviorsService.ts +2 -0
- package/src/services/DockerService.ts +2 -0
- package/src/services/EmbeddingService.ts +2 -0
- package/src/services/EmbeddingsService.ts +3 -0
- package/src/services/ExtensionsService.ts +25 -0
- package/src/services/KnowhowClient.ts +68 -7
- package/src/services/LazyToolsService.ts +24 -20
- package/src/services/Mcp.ts +2 -0
- package/src/services/McpServer.ts +2 -0
- package/src/services/MessageProcessor.ts +2 -0
- package/src/services/MinimalToolsService.ts +2 -0
- package/src/services/SessionManager.ts +5 -0
- package/src/services/SkillsService.ts +2 -0
- package/src/services/SyncedAgentWatcher.ts +2 -0
- package/src/services/SyncerService.ts +23 -8
- package/src/services/TaskRegistry.ts +2 -0
- package/src/services/Tools.ts +12 -0
- package/src/services/index.ts +6 -0
- package/src/services/modules/index.ts +10 -1
- package/src/services/modules/types.ts +4 -0
- package/src/types.ts +2 -0
- package/src/util/Trace.ts +1 -1
- package/src/utils/http.ts +18 -2
- package/tests/unit/agents/historyRollback.test.ts +53 -0
- package/tests/unit/auth/keyAuth.test.ts +102 -0
- package/tests/unit/auth/keyManager.test.ts +67 -0
- package/tests/unit/chat/ToolCommandModule.test.ts +71 -0
- package/tests/unit/chat/historyCommandArgs.test.ts +37 -0
- package/tests/unit/commands/agents.test.ts +111 -0
- package/tests/unit/login.test.ts +119 -0
- package/tests/unit/services/AgentSyncKnowhowWeb.test.ts +38 -0
- package/tests/unit/services/LazyToolsService.test.ts +53 -0
- package/tests/unit/services/SessionManager.test.ts +43 -0
- package/tests/unit/services/SyncerService.test.ts +45 -0
- package/tests/unit/util/Trace.test.ts +119 -0
- package/tests/unit/utils/http.test.ts +43 -0
- package/ts_build/package.json +1 -1
- package/ts_build/src/agents/base/base.d.ts +2 -1
- package/ts_build/src/agents/base/base.js +47 -14
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/historyRollback.d.ts +2 -0
- package/ts_build/src/agents/historyRollback.js +22 -0
- package/ts_build/src/agents/historyRollback.js.map +1 -0
- package/ts_build/src/agents/tools/execCommand.d.ts +4 -1
- package/ts_build/src/agents/tools/execCommand.js +100 -223
- package/ts_build/src/agents/tools/execCommand.js.map +1 -1
- package/ts_build/src/agents/tools/list.js +2 -2
- package/ts_build/src/agents/tools/list.js.map +1 -1
- package/ts_build/src/agents/tools/startAgentTask.d.ts +16 -1
- package/ts_build/src/agents/tools/startAgentTask.js +71 -28
- package/ts_build/src/agents/tools/startAgentTask.js.map +1 -1
- package/ts_build/src/ai.js +2 -1
- package/ts_build/src/ai.js.map +1 -1
- package/ts_build/src/auth/browserLogin.d.ts +1 -0
- package/ts_build/src/auth/browserLogin.js +5 -2
- package/ts_build/src/auth/browserLogin.js.map +1 -1
- package/ts_build/src/auth/keyAuth.d.ts +5 -0
- package/ts_build/src/auth/keyAuth.js +79 -0
- package/ts_build/src/auth/keyAuth.js.map +1 -0
- package/ts_build/src/auth/keyManager.d.ts +14 -0
- package/ts_build/src/auth/keyManager.js +145 -0
- package/ts_build/src/auth/keyManager.js.map +1 -0
- package/ts_build/src/chat/CliChatService.d.ts +6 -0
- package/ts_build/src/chat/CliChatService.js +17 -2
- package/ts_build/src/chat/CliChatService.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.d.ts +13 -1
- package/ts_build/src/chat/modules/AgentModule.js +83 -24
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/chat/modules/AskModule.js +12 -2
- package/ts_build/src/chat/modules/AskModule.js.map +1 -1
- package/ts_build/src/chat/modules/BaseChatModule.js.map +1 -1
- package/ts_build/src/chat/modules/CustomCommandsModule.js +12 -2
- package/ts_build/src/chat/modules/CustomCommandsModule.js.map +1 -1
- package/ts_build/src/chat/modules/InternalChatModule.d.ts +1 -0
- package/ts_build/src/chat/modules/InternalChatModule.js +21 -2
- package/ts_build/src/chat/modules/InternalChatModule.js.map +1 -1
- package/ts_build/src/chat/modules/RemoteSyncModule.js +19 -2
- package/ts_build/src/chat/modules/RemoteSyncModule.js.map +1 -1
- package/ts_build/src/chat/modules/RendererModule.js +17 -2
- package/ts_build/src/chat/modules/RendererModule.js.map +1 -1
- package/ts_build/src/chat/modules/SearchModule.js +12 -2
- package/ts_build/src/chat/modules/SearchModule.js.map +1 -1
- package/ts_build/src/chat/modules/SessionsModule.d.ts +6 -0
- package/ts_build/src/chat/modules/SessionsModule.js +113 -18
- package/ts_build/src/chat/modules/SessionsModule.js.map +1 -1
- package/ts_build/src/chat/modules/SetupModule.js +17 -2
- package/ts_build/src/chat/modules/SetupModule.js.map +1 -1
- package/ts_build/src/chat/modules/ShellCommandModule.js +12 -2
- package/ts_build/src/chat/modules/ShellCommandModule.js.map +1 -1
- package/ts_build/src/chat/modules/SystemModule.js +12 -2
- package/ts_build/src/chat/modules/SystemModule.js.map +1 -1
- package/ts_build/src/chat/modules/ToolCommandModule.d.ts +10 -0
- package/ts_build/src/chat/modules/ToolCommandModule.js +86 -0
- package/ts_build/src/chat/modules/ToolCommandModule.js.map +1 -0
- package/ts_build/src/chat/modules/index.d.ts +1 -0
- package/ts_build/src/chat/modules/index.js +3 -1
- package/ts_build/src/chat/modules/index.js.map +1 -1
- package/ts_build/src/chat/types.d.ts +3 -1
- package/ts_build/src/cli.js +7 -3
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/clients/http.d.ts +4 -0
- package/ts_build/src/clients/http.js +68 -6
- package/ts_build/src/clients/http.js.map +1 -1
- package/ts_build/src/clients/index.js +23 -4
- package/ts_build/src/clients/index.js.map +1 -1
- package/ts_build/src/commands/agent.js +1 -21
- package/ts_build/src/commands/agent.js.map +1 -1
- package/ts_build/src/commands/agents.d.ts +2 -1
- package/ts_build/src/commands/agents.js +216 -23
- package/ts_build/src/commands/agents.js.map +1 -1
- package/ts_build/src/commands/misc.js +3 -2
- package/ts_build/src/commands/misc.js.map +1 -1
- package/ts_build/src/commands/processes.d.ts +2 -0
- package/ts_build/src/commands/processes.js +213 -0
- package/ts_build/src/commands/processes.js.map +1 -0
- package/ts_build/src/commands/services.js +11 -1
- package/ts_build/src/commands/services.js.map +1 -1
- package/ts_build/src/index.d.ts +1 -0
- package/ts_build/src/index.js +1 -0
- package/ts_build/src/index.js.map +1 -1
- package/ts_build/src/login.d.ts +1 -1
- package/ts_build/src/login.js +53 -15
- package/ts_build/src/login.js.map +1 -1
- package/ts_build/src/processes/ProcessManager.d.ts +51 -0
- package/ts_build/src/processes/ProcessManager.js +160 -0
- package/ts_build/src/processes/ProcessManager.js.map +1 -0
- package/ts_build/src/processes/managedProcessShim.d.ts +1 -0
- package/ts_build/src/processes/managedProcessShim.js +161 -0
- package/ts_build/src/processes/managedProcessShim.js.map +1 -0
- package/ts_build/src/services/AgentService.js +18 -2
- package/ts_build/src/services/AgentService.js.map +1 -1
- package/ts_build/src/services/AgentSyncFs.d.ts +3 -0
- package/ts_build/src/services/AgentSyncFs.js +68 -16
- package/ts_build/src/services/AgentSyncFs.js.map +1 -1
- package/ts_build/src/services/AgentSyncKnowhowWeb.d.ts +2 -0
- package/ts_build/src/services/AgentSyncKnowhowWeb.js +28 -6
- package/ts_build/src/services/AgentSyncKnowhowWeb.js.map +1 -1
- package/ts_build/src/services/BehaviorsService.js +12 -2
- package/ts_build/src/services/BehaviorsService.js.map +1 -1
- package/ts_build/src/services/DockerService.js +20 -8
- package/ts_build/src/services/DockerService.js.map +1 -1
- package/ts_build/src/services/EmbeddingService.js +16 -2
- package/ts_build/src/services/EmbeddingService.js.map +1 -1
- package/ts_build/src/services/EmbeddingsService.js +12 -2
- package/ts_build/src/services/EmbeddingsService.js.map +1 -1
- package/ts_build/src/services/ExtensionsService.d.ts +10 -0
- package/ts_build/src/services/ExtensionsService.js +17 -0
- package/ts_build/src/services/ExtensionsService.js.map +1 -0
- package/ts_build/src/services/KnowhowClient.d.ts +7 -2
- package/ts_build/src/services/KnowhowClient.js +108 -10
- package/ts_build/src/services/KnowhowClient.js.map +1 -1
- package/ts_build/src/services/LazyToolsService.d.ts +2 -0
- package/ts_build/src/services/LazyToolsService.js +26 -9
- package/ts_build/src/services/LazyToolsService.js.map +1 -1
- package/ts_build/src/services/Mcp.js +12 -2
- package/ts_build/src/services/Mcp.js.map +1 -1
- package/ts_build/src/services/McpServer.js +17 -2
- package/ts_build/src/services/McpServer.js.map +1 -1
- package/ts_build/src/services/MessageProcessor.js +16 -2
- package/ts_build/src/services/MessageProcessor.js.map +1 -1
- package/ts_build/src/services/MinimalToolsService.js +16 -2
- package/ts_build/src/services/MinimalToolsService.js.map +1 -1
- package/ts_build/src/services/SessionManager.js +19 -2
- package/ts_build/src/services/SessionManager.js.map +1 -1
- package/ts_build/src/services/SkillsService.js +16 -2
- package/ts_build/src/services/SkillsService.js.map +1 -1
- package/ts_build/src/services/SyncedAgentWatcher.js +16 -2
- package/ts_build/src/services/SyncedAgentWatcher.js.map +1 -1
- package/ts_build/src/services/SyncerService.d.ts +1 -0
- package/ts_build/src/services/SyncerService.js +27 -5
- package/ts_build/src/services/SyncerService.js.map +1 -1
- package/ts_build/src/services/TaskRegistry.js +12 -2
- package/ts_build/src/services/TaskRegistry.js.map +1 -1
- package/ts_build/src/services/Tools.d.ts +1 -0
- package/ts_build/src/services/Tools.js +19 -2
- package/ts_build/src/services/Tools.js.map +1 -1
- package/ts_build/src/services/index.d.ts +5 -0
- package/ts_build/src/services/index.js +7 -2
- package/ts_build/src/services/index.js.map +1 -1
- package/ts_build/src/services/modules/index.d.ts +4 -1
- package/ts_build/src/services/modules/index.js +6 -1
- package/ts_build/src/services/modules/index.js.map +1 -1
- package/ts_build/src/services/modules/types.d.ts +3 -0
- package/ts_build/src/types.d.ts +1 -0
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/util/Trace.d.ts +1 -3
- package/ts_build/src/utils/http.d.ts +6 -2
- package/ts_build/src/utils/http.js +8 -2
- package/ts_build/src/utils/http.js.map +1 -1
- package/ts_build/tests/unit/agents/historyRollback.test.d.ts +1 -0
- package/ts_build/tests/unit/agents/historyRollback.test.js +42 -0
- package/ts_build/tests/unit/agents/historyRollback.test.js.map +1 -0
- package/ts_build/tests/unit/auth/keyAuth.test.d.ts +1 -0
- package/ts_build/tests/unit/auth/keyAuth.test.js +77 -0
- package/ts_build/tests/unit/auth/keyAuth.test.js.map +1 -0
- package/ts_build/tests/unit/auth/keyManager.test.d.ts +1 -0
- package/ts_build/tests/unit/auth/keyManager.test.js +52 -0
- package/ts_build/tests/unit/auth/keyManager.test.js.map +1 -0
- package/ts_build/tests/unit/chat/ToolCommandModule.test.d.ts +1 -0
- package/ts_build/tests/unit/chat/ToolCommandModule.test.js +61 -0
- package/ts_build/tests/unit/chat/ToolCommandModule.test.js.map +1 -0
- package/ts_build/tests/unit/chat/historyCommandArgs.test.d.ts +1 -0
- package/ts_build/tests/unit/chat/historyCommandArgs.test.js +29 -0
- package/ts_build/tests/unit/chat/historyCommandArgs.test.js.map +1 -0
- package/ts_build/tests/unit/commands/agents.test.d.ts +1 -0
- package/ts_build/tests/unit/commands/agents.test.js +119 -0
- package/ts_build/tests/unit/commands/agents.test.js.map +1 -0
- package/ts_build/tests/unit/login.test.d.ts +1 -0
- package/ts_build/tests/unit/login.test.js +97 -0
- package/ts_build/tests/unit/login.test.js.map +1 -0
- package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.d.ts +1 -0
- package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.js +32 -0
- package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.js.map +1 -0
- package/ts_build/tests/unit/services/LazyToolsService.test.d.ts +1 -0
- package/ts_build/tests/unit/services/LazyToolsService.test.js +47 -0
- package/ts_build/tests/unit/services/LazyToolsService.test.js.map +1 -0
- package/ts_build/tests/unit/services/SessionManager.test.d.ts +1 -0
- package/ts_build/tests/unit/services/SessionManager.test.js +72 -0
- package/ts_build/tests/unit/services/SessionManager.test.js.map +1 -0
- package/ts_build/tests/unit/services/SyncerService.test.d.ts +1 -0
- package/ts_build/tests/unit/services/SyncerService.test.js +40 -0
- package/ts_build/tests/unit/services/SyncerService.test.js.map +1 -0
- package/ts_build/tests/unit/util/Trace.test.d.ts +1 -0
- package/ts_build/tests/unit/util/Trace.test.js +107 -0
- package/ts_build/tests/unit/util/Trace.test.js.map +1 -0
- package/ts_build/tests/unit/utils/http.test.d.ts +1 -0
- package/ts_build/tests/unit/utils/http.test.js +69 -0
- package/ts_build/tests/unit/utils/http.test.js.map +1 -0
package/src/commands/agents.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* knowhow agents status <taskId> — one-line summary (status, last tool, cost, elapsed)
|
|
7
7
|
* knowhow agents tail <taskId> — print last N messages; without -f behaves like read-only attach
|
|
8
8
|
* knowhow agents attach <taskId> — open the full knowhow chat interface attached to the agent
|
|
9
|
+
* knowhow agents resume <taskId> — resume a task, optionally rolling back interactions
|
|
10
|
+
* knowhow agents fork <taskId> — branch a task's history into a new task
|
|
9
11
|
*
|
|
10
12
|
* Both `status` and `tail` accept:
|
|
11
13
|
* - A full task ID
|
|
@@ -19,11 +21,32 @@
|
|
|
19
21
|
import { Command } from "commander";
|
|
20
22
|
import * as fs from "fs";
|
|
21
23
|
import * as path from "path";
|
|
24
|
+
import { AgentModule } from "../chat/modules/AgentModule";
|
|
22
25
|
import { startChat } from "../chat";
|
|
26
|
+
import { PlainRenderer } from "../chat/renderer/PlainRenderer";
|
|
27
|
+
import { loadRenderer } from "../chat/renderer/loadRenderer";
|
|
28
|
+
import {
|
|
29
|
+
CompletionOptions,
|
|
30
|
+
isReasoningEffort,
|
|
31
|
+
REASONING_EFFORTS,
|
|
32
|
+
} from "../clients/types";
|
|
33
|
+
import { getConfig } from "../config";
|
|
23
34
|
|
|
24
35
|
const AGENTS_DIR = path.join(".knowhow", "processes", "agents");
|
|
25
36
|
const SESSIONS_DIR = path.join(".knowhow", "chats", "sessions");
|
|
26
37
|
|
|
38
|
+
const TERMINAL_STATUSES = new Set([
|
|
39
|
+
"completed",
|
|
40
|
+
"failed",
|
|
41
|
+
"killed",
|
|
42
|
+
"error",
|
|
43
|
+
"done",
|
|
44
|
+
]);
|
|
45
|
+
const ACTIVE_STATUSES = new Set(["running", "paused"]);
|
|
46
|
+
// Older task records did not persist a pid. After this grace period, report
|
|
47
|
+
// them as unverifiable rather than continuing to claim they are running.
|
|
48
|
+
const UNVERIFIED_TASK_GRACE_MS = 5 * 60 * 1000;
|
|
49
|
+
|
|
27
50
|
// ---------------------------------------------------------------------------
|
|
28
51
|
// Helpers
|
|
29
52
|
// ---------------------------------------------------------------------------
|
|
@@ -57,11 +80,42 @@ function loadStatus(taskId: string): string {
|
|
|
57
80
|
}
|
|
58
81
|
}
|
|
59
82
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
83
|
+
function pidAlive(pid: number): boolean {
|
|
84
|
+
try {
|
|
85
|
+
process.kill(pid, 0);
|
|
86
|
+
return true;
|
|
87
|
+
} catch (error: any) {
|
|
88
|
+
// EPERM means the process exists but cannot be signalled by this user.
|
|
89
|
+
return error?.code === "EPERM";
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get the effective status, reconciling persisted state with process liveness.
|
|
95
|
+
* An agent can be terminated before AgentSyncFs gets a chance to finalize its
|
|
96
|
+
* files; those records must not remain "running" forever.
|
|
97
|
+
*/
|
|
98
|
+
export function getStatus(taskId: string, meta: any | null): string {
|
|
99
|
+
const persisted = meta?.status || loadStatus(taskId) || "unknown";
|
|
100
|
+
if (TERMINAL_STATUSES.has(persisted)) return persisted;
|
|
101
|
+
if (meta?.inProgress === false) return "completed";
|
|
102
|
+
if (!ACTIVE_STATUSES.has(persisted)) return persisted;
|
|
103
|
+
|
|
104
|
+
const pid = meta?.pid ?? meta?.processId;
|
|
105
|
+
if (typeof pid === "number") {
|
|
106
|
+
return pidAlive(pid) ? persisted : "failed";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const lastKnownTime = meta?.lastUpdate ?? meta?.startTime;
|
|
110
|
+
const lastKnownMs = lastKnownTime ? new Date(lastKnownTime).getTime() : NaN;
|
|
111
|
+
if (
|
|
112
|
+
!Number.isFinite(lastKnownMs) ||
|
|
113
|
+
Date.now() - lastKnownMs > UNVERIFIED_TASK_GRACE_MS
|
|
114
|
+
) {
|
|
115
|
+
return "stale";
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return persisted;
|
|
65
119
|
}
|
|
66
120
|
|
|
67
121
|
function elapsedStr(startIso: string | undefined, endIso?: string): string {
|
|
@@ -70,8 +124,11 @@ function elapsedStr(startIso: string | undefined, endIso?: string): string {
|
|
|
70
124
|
const end = endIso ? new Date(endIso).getTime() : Date.now();
|
|
71
125
|
const ms = end - start;
|
|
72
126
|
if (ms < 60_000) return `${Math.floor(ms / 1000)}s`;
|
|
73
|
-
if (ms < 3_600_000)
|
|
74
|
-
|
|
127
|
+
if (ms < 3_600_000)
|
|
128
|
+
return `${Math.floor(ms / 60_000)}m ${Math.floor((ms % 60_000) / 1000)}s`;
|
|
129
|
+
return `${Math.floor(ms / 3_600_000)}h ${Math.floor(
|
|
130
|
+
(ms % 3_600_000) / 60_000
|
|
131
|
+
)}m`;
|
|
75
132
|
}
|
|
76
133
|
|
|
77
134
|
function shortId(taskId: string, maxLen = 52): string {
|
|
@@ -103,7 +160,11 @@ function lastAssistantMessage(thread: any[]): string | undefined {
|
|
|
103
160
|
function lastToolCall(thread: any[]): string | undefined {
|
|
104
161
|
for (let i = thread.length - 1; i >= 0; i--) {
|
|
105
162
|
const msg = thread[i];
|
|
106
|
-
if (
|
|
163
|
+
if (
|
|
164
|
+
msg.role === "assistant" &&
|
|
165
|
+
Array.isArray(msg.tool_calls) &&
|
|
166
|
+
msg.tool_calls.length > 0
|
|
167
|
+
) {
|
|
107
168
|
const last = msg.tool_calls[msg.tool_calls.length - 1];
|
|
108
169
|
return last?.function?.name;
|
|
109
170
|
}
|
|
@@ -126,25 +187,40 @@ function formatMessage(msg: any, index: number): string {
|
|
|
126
187
|
.join(" | ");
|
|
127
188
|
}
|
|
128
189
|
|
|
129
|
-
if (
|
|
190
|
+
if (
|
|
191
|
+
msg.role === "assistant" &&
|
|
192
|
+
Array.isArray(msg.tool_calls) &&
|
|
193
|
+
msg.tool_calls.length > 0
|
|
194
|
+
) {
|
|
130
195
|
const tools = msg.tool_calls.map((tc: any) => {
|
|
131
196
|
const name = tc?.function?.name ?? "?";
|
|
132
197
|
let args = "";
|
|
133
198
|
try {
|
|
134
199
|
const parsed = JSON.parse(tc?.function?.arguments ?? "{}");
|
|
135
200
|
const entries = Object.entries(parsed).slice(0, 2);
|
|
136
|
-
args = entries
|
|
201
|
+
args = entries
|
|
202
|
+
.map(([k, v]) => `${k}=${String(v).slice(0, 40)}`)
|
|
203
|
+
.join(", ");
|
|
137
204
|
} catch {
|
|
138
205
|
args = (tc?.function?.arguments ?? "").slice(0, 80);
|
|
139
206
|
}
|
|
140
207
|
return `[TOOL] ${name}(${args})`;
|
|
141
208
|
});
|
|
142
|
-
content = content
|
|
209
|
+
content = content
|
|
210
|
+
? content + "\n " + tools.join("\n ")
|
|
211
|
+
: tools.join("\n ");
|
|
143
212
|
}
|
|
144
213
|
|
|
145
214
|
if (msg.role === "tool") {
|
|
146
|
-
const result =
|
|
147
|
-
|
|
215
|
+
const result =
|
|
216
|
+
typeof msg.content === "string"
|
|
217
|
+
? msg.content.slice(0, 200)
|
|
218
|
+
: JSON.stringify(msg.content).slice(0, 200);
|
|
219
|
+
content = `[RESULT] ${result}${
|
|
220
|
+
(typeof msg.content === "string" ? msg.content : "").length > 200
|
|
221
|
+
? "…"
|
|
222
|
+
: ""
|
|
223
|
+
}`;
|
|
148
224
|
}
|
|
149
225
|
|
|
150
226
|
return ` #${String(index).padStart(3)} [${role}] ${content}`;
|
|
@@ -155,8 +231,8 @@ function formatMessage(msg: any, index: number): string {
|
|
|
155
231
|
// ---------------------------------------------------------------------------
|
|
156
232
|
|
|
157
233
|
type Row = {
|
|
158
|
-
taskId: string;
|
|
159
|
-
displayId: string;
|
|
234
|
+
taskId: string; // full task ID (not truncated)
|
|
235
|
+
displayId: string; // truncated for display
|
|
160
236
|
agentName: string;
|
|
161
237
|
status: string;
|
|
162
238
|
cost: string;
|
|
@@ -170,9 +246,9 @@ function buildRows(includeAll: boolean): Row[] {
|
|
|
170
246
|
|
|
171
247
|
for (const taskId of taskIds) {
|
|
172
248
|
const meta = loadMeta(taskId);
|
|
173
|
-
const status =
|
|
249
|
+
const status = getStatus(taskId, meta);
|
|
174
250
|
|
|
175
|
-
if (!includeAll && (status
|
|
251
|
+
if (!includeAll && (TERMINAL_STATUSES.has(status) || status === "stale")) {
|
|
176
252
|
const lastUpdate = meta?.lastUpdate ?? "";
|
|
177
253
|
if (lastUpdate) {
|
|
178
254
|
const age = Date.now() - new Date(lastUpdate).getTime();
|
|
@@ -182,9 +258,19 @@ function buildRows(includeAll: boolean): Row[] {
|
|
|
182
258
|
}
|
|
183
259
|
}
|
|
184
260
|
|
|
185
|
-
const cost =
|
|
186
|
-
|
|
187
|
-
|
|
261
|
+
const cost =
|
|
262
|
+
meta?.totalCostUsd != null
|
|
263
|
+
? `$${(meta.totalCostUsd as number).toFixed(3)}`
|
|
264
|
+
: "";
|
|
265
|
+
const elapsed = elapsedStr(
|
|
266
|
+
meta?.startTime,
|
|
267
|
+
TERMINAL_STATUSES.has(status) || status === "stale"
|
|
268
|
+
? meta?.lastUpdate
|
|
269
|
+
: undefined
|
|
270
|
+
);
|
|
271
|
+
const lastUpdate = meta?.lastUpdate
|
|
272
|
+
? new Date(meta.lastUpdate).toLocaleString()
|
|
273
|
+
: "?";
|
|
188
274
|
|
|
189
275
|
rows.push({
|
|
190
276
|
taskId,
|
|
@@ -221,7 +307,6 @@ function resolveTaskId(value: string, includeAll = false): string | null {
|
|
|
221
307
|
return all.find((id) => id.includes(value)) ?? null;
|
|
222
308
|
}
|
|
223
309
|
|
|
224
|
-
|
|
225
310
|
// ---------------------------------------------------------------------------
|
|
226
311
|
// Command handlers
|
|
227
312
|
// ---------------------------------------------------------------------------
|
|
@@ -233,15 +318,30 @@ async function cmdList(opts: { all: boolean; json: boolean }): Promise<void> {
|
|
|
233
318
|
if (agentTaskIds().length === 0) {
|
|
234
319
|
console.log("No agent task directories found under", AGENTS_DIR);
|
|
235
320
|
} else {
|
|
236
|
-
console.log(
|
|
321
|
+
console.log(
|
|
322
|
+
"No active agent tasks. Use --all to include completed tasks."
|
|
323
|
+
);
|
|
237
324
|
}
|
|
238
325
|
return;
|
|
239
326
|
}
|
|
240
327
|
|
|
241
328
|
if (opts.json) {
|
|
242
|
-
console.log(
|
|
243
|
-
|
|
244
|
-
|
|
329
|
+
console.log(
|
|
330
|
+
JSON.stringify(
|
|
331
|
+
rows.map(
|
|
332
|
+
({ taskId, agentName, status, cost, elapsed, lastUpdate }) => ({
|
|
333
|
+
taskId,
|
|
334
|
+
agentName,
|
|
335
|
+
status,
|
|
336
|
+
cost,
|
|
337
|
+
elapsed,
|
|
338
|
+
lastUpdate,
|
|
339
|
+
})
|
|
340
|
+
),
|
|
341
|
+
null,
|
|
342
|
+
2
|
|
343
|
+
)
|
|
344
|
+
);
|
|
245
345
|
return;
|
|
246
346
|
}
|
|
247
347
|
|
|
@@ -277,12 +377,15 @@ async function cmdList(opts: { all: boolean; json: boolean }): Promise<void> {
|
|
|
277
377
|
"\n"
|
|
278
378
|
);
|
|
279
379
|
});
|
|
280
|
-
console.log(
|
|
380
|
+
console.log(
|
|
381
|
+
"\nTip: use -i <#> with tail/status/attach to select by row number, e.g. knowhow agents attach -i 1\n"
|
|
382
|
+
);
|
|
281
383
|
}
|
|
282
384
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
385
|
+
async function cmdStatus(
|
|
386
|
+
taskIdOrIndex: string | undefined,
|
|
387
|
+
opts: { index?: string }
|
|
388
|
+
): Promise<void> {
|
|
286
389
|
const value = opts.index ?? taskIdOrIndex;
|
|
287
390
|
if (!value) {
|
|
288
391
|
console.error("Provide a task ID or use -i <number> to select by index.");
|
|
@@ -312,9 +415,23 @@ async function cmdStatus(taskIdOrIndex: string | undefined, opts: { index?: stri
|
|
|
312
415
|
console.log(`Task ID: ${resolvedId}`);
|
|
313
416
|
console.log(`Agent: ${meta?.agentName ?? "?"}`);
|
|
314
417
|
console.log(`Status: ${status}`);
|
|
315
|
-
console.log(
|
|
316
|
-
|
|
317
|
-
|
|
418
|
+
console.log(
|
|
419
|
+
`Cost: ${
|
|
420
|
+
meta?.totalCostUsd != null
|
|
421
|
+
? "$" + (meta.totalCostUsd as number).toFixed(4)
|
|
422
|
+
: "?"
|
|
423
|
+
}`
|
|
424
|
+
);
|
|
425
|
+
console.log(
|
|
426
|
+
`Started: ${
|
|
427
|
+
meta?.startTime ? new Date(meta.startTime).toLocaleString() : "?"
|
|
428
|
+
}`
|
|
429
|
+
);
|
|
430
|
+
console.log(
|
|
431
|
+
`Last update:${
|
|
432
|
+
meta?.lastUpdate ? " " + new Date(meta.lastUpdate).toLocaleString() : " ?"
|
|
433
|
+
}`
|
|
434
|
+
);
|
|
318
435
|
console.log(`Elapsed: ${elapsedStr(meta?.startTime)}`);
|
|
319
436
|
|
|
320
437
|
const threads: any[][] = meta?.threads ?? [];
|
|
@@ -342,7 +459,10 @@ async function cmdStatus(taskIdOrIndex: string | undefined, opts: { index?: stri
|
|
|
342
459
|
console.log("─".repeat(60));
|
|
343
460
|
}
|
|
344
461
|
|
|
345
|
-
async function cmdTail(
|
|
462
|
+
async function cmdTail(
|
|
463
|
+
taskIdOrIndex: string | undefined,
|
|
464
|
+
opts: { count: number; raw: boolean; follow: boolean; index?: string }
|
|
465
|
+
): Promise<void> {
|
|
346
466
|
const value = opts.index ?? taskIdOrIndex;
|
|
347
467
|
if (!value) {
|
|
348
468
|
console.error("Provide a task ID or use -i <number> to select by index.");
|
|
@@ -373,7 +493,9 @@ async function cmdTail(taskIdOrIndex: string | undefined, opts: { count: number;
|
|
|
373
493
|
|
|
374
494
|
const threads: any[][] = meta.threads ?? [];
|
|
375
495
|
if (threads.length === 0) {
|
|
376
|
-
console.log(
|
|
496
|
+
console.log(
|
|
497
|
+
"No thread data found in metadata.json (agent may not have started yet)."
|
|
498
|
+
);
|
|
377
499
|
return;
|
|
378
500
|
}
|
|
379
501
|
|
|
@@ -389,7 +511,11 @@ async function cmdTail(taskIdOrIndex: string | undefined, opts: { count: number;
|
|
|
389
511
|
const startIndex = lastThread.length - slice.length;
|
|
390
512
|
|
|
391
513
|
console.log(`\n📜 Last ${slice.length} messages for task: ${resolvedId}`);
|
|
392
|
-
console.log(
|
|
514
|
+
console.log(
|
|
515
|
+
` Agent: ${meta.agentName} | Status: ${
|
|
516
|
+
meta.status ?? loadStatus(resolvedId)
|
|
517
|
+
} | Total messages: ${lastThread.length}`
|
|
518
|
+
);
|
|
393
519
|
console.log("─".repeat(80));
|
|
394
520
|
|
|
395
521
|
for (let i = 0; i < slice.length; i++) {
|
|
@@ -398,12 +524,20 @@ async function cmdTail(taskIdOrIndex: string | undefined, opts: { count: number;
|
|
|
398
524
|
|
|
399
525
|
console.log("─".repeat(80));
|
|
400
526
|
|
|
401
|
-
const cost =
|
|
527
|
+
const cost =
|
|
528
|
+
meta.totalCostUsd != null
|
|
529
|
+
? `$${(meta.totalCostUsd as number).toFixed(4)}`
|
|
530
|
+
: "?";
|
|
402
531
|
const elapsed = elapsedStr(meta.startTime);
|
|
403
532
|
const status = getStatus(resolvedId, meta);
|
|
404
|
-
console.log(
|
|
533
|
+
console.log(
|
|
534
|
+
`Cost: ${cost} | Elapsed: ${elapsed} | Last update: ${
|
|
535
|
+
meta.lastUpdate ? new Date(meta.lastUpdate).toLocaleString() : "?"
|
|
536
|
+
}`
|
|
537
|
+
);
|
|
405
538
|
|
|
406
|
-
const isDone =
|
|
539
|
+
const isDone =
|
|
540
|
+
status === "completed" || status === "failed" || status === "killed";
|
|
407
541
|
|
|
408
542
|
if (opts.follow) {
|
|
409
543
|
if (isDone) {
|
|
@@ -423,13 +557,20 @@ async function cmdTail(taskIdOrIndex: string | undefined, opts: { count: number;
|
|
|
423
557
|
* Poll metadata.json every second, printing any new messages as they arrive.
|
|
424
558
|
* Exits when the agent status becomes completed/failed/killed.
|
|
425
559
|
*/
|
|
426
|
-
async function followTask(
|
|
560
|
+
async function followTask(
|
|
561
|
+
resolvedId: string,
|
|
562
|
+
seenCount: number
|
|
563
|
+
): Promise<void> {
|
|
427
564
|
console.log(`\n👁 Following agent output… (Ctrl+C to stop)\n`);
|
|
428
565
|
|
|
429
566
|
// Check upfront — if already done, exit immediately
|
|
430
567
|
const initialMeta = loadMeta(resolvedId);
|
|
431
568
|
const initialStatus = getStatus(resolvedId, initialMeta);
|
|
432
|
-
if (
|
|
569
|
+
if (
|
|
570
|
+
initialStatus === "completed" ||
|
|
571
|
+
initialStatus === "failed" ||
|
|
572
|
+
initialStatus === "killed"
|
|
573
|
+
) {
|
|
433
574
|
console.log(`✅ Agent already ${initialStatus}. Nothing to follow.\n`);
|
|
434
575
|
return;
|
|
435
576
|
}
|
|
@@ -452,9 +593,19 @@ async function followTask(resolvedId: string, seenCount: number): Promise<void>
|
|
|
452
593
|
}
|
|
453
594
|
const status = getStatus(resolvedId, meta);
|
|
454
595
|
if (status === "completed" || status === "failed" || status === "killed") {
|
|
455
|
-
const cost =
|
|
456
|
-
|
|
457
|
-
|
|
596
|
+
const cost =
|
|
597
|
+
meta.totalCostUsd != null
|
|
598
|
+
? `$${(meta.totalCostUsd as number).toFixed(4)}`
|
|
599
|
+
: "?";
|
|
600
|
+
console.log(
|
|
601
|
+
`\n─────────────────────────────────────────────────────────────────────────────────`
|
|
602
|
+
);
|
|
603
|
+
console.log(
|
|
604
|
+
`✅ Agent ${status}. Cost: ${cost} | Elapsed: ${elapsedStr(
|
|
605
|
+
meta.startTime,
|
|
606
|
+
meta.lastUpdate
|
|
607
|
+
)}`
|
|
608
|
+
);
|
|
458
609
|
clearInterval(interval);
|
|
459
610
|
process.exit(0);
|
|
460
611
|
}
|
|
@@ -464,7 +615,10 @@ async function followTask(resolvedId: string, seenCount: number): Promise<void>
|
|
|
464
615
|
await new Promise<void>(() => {});
|
|
465
616
|
}
|
|
466
617
|
|
|
467
|
-
async function cmdAttach(
|
|
618
|
+
async function cmdAttach(
|
|
619
|
+
taskIdOrIndex: string | undefined,
|
|
620
|
+
opts: { index?: string }
|
|
621
|
+
): Promise<void> {
|
|
468
622
|
const value = opts.index ?? taskIdOrIndex;
|
|
469
623
|
if (!value) {
|
|
470
624
|
console.error("Provide a task ID or use -i <number> to select by index.");
|
|
@@ -551,28 +705,189 @@ async function cmdAnswer(
|
|
|
551
705
|
console.log(`\n📭 No final answer available for task: ${resolvedId}`);
|
|
552
706
|
console.log(` Status: ${status}`);
|
|
553
707
|
if (status !== "completed") {
|
|
554
|
-
console.log(
|
|
708
|
+
console.log(
|
|
709
|
+
` The agent hasn't finished yet — attach with 'knowhow agents attach' to follow it.`
|
|
710
|
+
);
|
|
555
711
|
}
|
|
556
712
|
return;
|
|
557
713
|
}
|
|
558
714
|
|
|
559
715
|
console.log(`\n💬 Final answer for task: ${resolvedId}`);
|
|
560
|
-
console.log(
|
|
716
|
+
console.log(
|
|
717
|
+
` Agent: ${meta.agentName ?? "?"} | Status: ${status} | Cost: ${
|
|
718
|
+
meta.totalCostUsd != null
|
|
719
|
+
? "$" + (meta.totalCostUsd as number).toFixed(4)
|
|
720
|
+
: "?"
|
|
721
|
+
}`
|
|
722
|
+
);
|
|
561
723
|
console.log("─".repeat(80));
|
|
562
724
|
console.log(answer);
|
|
563
725
|
console.log("─".repeat(80) + "\n");
|
|
564
726
|
}
|
|
565
727
|
|
|
728
|
+
interface HistoryRunOptions {
|
|
729
|
+
rollback: string;
|
|
730
|
+
input?: string;
|
|
731
|
+
taskId?: string;
|
|
732
|
+
messageId?: string;
|
|
733
|
+
syncFs?: boolean;
|
|
734
|
+
provider?: string;
|
|
735
|
+
model?: string;
|
|
736
|
+
agentName?: string;
|
|
737
|
+
reasoningEffort?: string;
|
|
738
|
+
renderer?: string;
|
|
739
|
+
index?: string;
|
|
740
|
+
headless?: boolean;
|
|
741
|
+
}
|
|
566
742
|
|
|
743
|
+
async function runFromHistory(
|
|
744
|
+
sourceTaskId: string,
|
|
745
|
+
options: HistoryRunOptions,
|
|
746
|
+
fork: boolean,
|
|
747
|
+
getChatService: () => any
|
|
748
|
+
): Promise<void> {
|
|
749
|
+
const rollback = Number(options.rollback);
|
|
750
|
+
if (!Number.isInteger(rollback) || rollback < 0) {
|
|
751
|
+
throw new Error("--rollback must be a non-negative integer");
|
|
752
|
+
}
|
|
753
|
+
const hasHeadlessOverrides = !!(
|
|
754
|
+
options.input || options.messageId || options.syncFs || options.provider ||
|
|
755
|
+
options.model || options.agentName || options.reasoningEffort ||
|
|
756
|
+
options.renderer || options.taskId
|
|
757
|
+
);
|
|
758
|
+
if (process.stdin.isTTY && !options.headless && !hasHeadlessOverrides) {
|
|
759
|
+
const command = fork ? "/fork" : "/resume";
|
|
760
|
+
const { setupServices } = await import("./services");
|
|
761
|
+
await setupServices();
|
|
762
|
+
await startChat(`${command} ${sourceTaskId} --rollback ${rollback}`);
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
const requestedReasoningEffortValue = options.reasoningEffort;
|
|
766
|
+
if (
|
|
767
|
+
requestedReasoningEffortValue !== undefined &&
|
|
768
|
+
!isReasoningEffort(requestedReasoningEffortValue)
|
|
769
|
+
) {
|
|
770
|
+
throw new Error(
|
|
771
|
+
`Invalid reasoning effort "${requestedReasoningEffortValue}". Expected one of: ${REASONING_EFFORTS.join(
|
|
772
|
+
", "
|
|
773
|
+
)}.`
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
const requestedReasoningEffort =
|
|
777
|
+
requestedReasoningEffortValue as CompletionOptions["reasoning_effort"];
|
|
778
|
+
|
|
779
|
+
const { setupServices } = await import("./services");
|
|
780
|
+
await setupServices();
|
|
781
|
+
const chatService = getChatService();
|
|
782
|
+
let config: any = {};
|
|
783
|
+
try {
|
|
784
|
+
config = await getConfig();
|
|
785
|
+
} catch (_) {}
|
|
786
|
+
const rendererSpecifier =
|
|
787
|
+
options.renderer ?? config.chat?.renderer ?? "basic";
|
|
788
|
+
const resolvedRenderer =
|
|
789
|
+
rendererSpecifier === "basic" && !process.stdout.isTTY
|
|
790
|
+
? "plain"
|
|
791
|
+
: rendererSpecifier;
|
|
792
|
+
try {
|
|
793
|
+
chatService.setContext({ renderer: await loadRenderer(resolvedRenderer) });
|
|
794
|
+
} catch (err: any) {
|
|
795
|
+
console.warn(
|
|
796
|
+
`⚠ Could not load renderer "${resolvedRenderer}": ${err.message}`
|
|
797
|
+
);
|
|
798
|
+
chatService.setContext({
|
|
799
|
+
renderer: !process.stdout.isTTY
|
|
800
|
+
? new PlainRenderer()
|
|
801
|
+
: await loadRenderer("basic"),
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
const agentModule = new AgentModule();
|
|
806
|
+
const threads = await agentModule.loadThreadsForTask(
|
|
807
|
+
sourceTaskId,
|
|
808
|
+
options.messageId
|
|
809
|
+
);
|
|
810
|
+
const savedSettings = await agentModule.loadTaskSettings(
|
|
811
|
+
sourceTaskId,
|
|
812
|
+
options.messageId
|
|
813
|
+
);
|
|
814
|
+
await agentModule.initialize(chatService);
|
|
815
|
+
const { taskCompleted } = await agentModule.resumeFromMessages({
|
|
816
|
+
agentName: options.agentName || savedSettings.agentName || "Patcher",
|
|
817
|
+
input: options.input || "Please continue from where you left off.",
|
|
818
|
+
threads,
|
|
819
|
+
messageId: fork ? undefined : options.messageId,
|
|
820
|
+
taskId: fork ? options.taskId : sourceTaskId,
|
|
821
|
+
// sourceTaskId may itself be a remote UUID when there is no local metadata;
|
|
822
|
+
// AgentModule validates it and rejects filesystem slugs.
|
|
823
|
+
remoteTaskId: fork ? undefined : savedSettings.remoteTaskId || sourceTaskId,
|
|
824
|
+
syncFs: options.syncFs,
|
|
825
|
+
rollback,
|
|
826
|
+
fork,
|
|
827
|
+
model: options.model || savedSettings.model,
|
|
828
|
+
provider: options.provider || savedSettings.provider,
|
|
829
|
+
reasoningEffort: requestedReasoningEffort || savedSettings.reasoningEffort,
|
|
830
|
+
summarizeReasoning: savedSettings.summarizeReasoning,
|
|
831
|
+
enabledTools: savedSettings.enabledTools,
|
|
832
|
+
});
|
|
833
|
+
await taskCompleted;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
function addHistoryRunOptions(
|
|
837
|
+
command: Command,
|
|
838
|
+
includeDestinationTaskId: boolean
|
|
839
|
+
): Command {
|
|
840
|
+
command
|
|
841
|
+
.option(
|
|
842
|
+
"-i, --index <number>",
|
|
843
|
+
"Select task by row number from 'agents list'"
|
|
844
|
+
)
|
|
845
|
+
.option(
|
|
846
|
+
"--rollback <count>",
|
|
847
|
+
"Discard the newest N agent interactions before continuing",
|
|
848
|
+
"0"
|
|
849
|
+
)
|
|
850
|
+
.option("--input <text>", "Message to send after restoring history")
|
|
851
|
+
.option(
|
|
852
|
+
"--message-id <messageId>",
|
|
853
|
+
"Knowhow message ID for remote task lookup"
|
|
854
|
+
)
|
|
855
|
+
.option("--sync-fs", "Enable filesystem-based synchronization")
|
|
856
|
+
.option("--provider <provider>", "Override the saved AI provider")
|
|
857
|
+
.option("--model <model>", "Override the saved model")
|
|
858
|
+
.option("--agent-name <name>", "Override the saved agent")
|
|
859
|
+
.option(
|
|
860
|
+
"--reasoning-effort <effort>",
|
|
861
|
+
`Reasoning effort: ${REASONING_EFFORTS.join(", ")}`
|
|
862
|
+
)
|
|
863
|
+
.option(
|
|
864
|
+
"--renderer <name>",
|
|
865
|
+
"Renderer to use (default: from config or basic)"
|
|
866
|
+
)
|
|
867
|
+
.option(
|
|
868
|
+
"--headless",
|
|
869
|
+
"Run to completion without opening the attached chat interface"
|
|
870
|
+
);
|
|
871
|
+
if (includeDestinationTaskId) {
|
|
872
|
+
command.option(
|
|
873
|
+
"--task-id <taskId>",
|
|
874
|
+
"Explicit task ID for the newly forked task"
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
return command;
|
|
878
|
+
}
|
|
567
879
|
|
|
568
880
|
// ---------------------------------------------------------------------------
|
|
569
881
|
// Command registration
|
|
570
882
|
// ---------------------------------------------------------------------------
|
|
571
883
|
|
|
572
|
-
export function addAgentsCommand(
|
|
884
|
+
export function addAgentsCommand(
|
|
885
|
+
program: Command,
|
|
886
|
+
getChatService: () => any
|
|
887
|
+
): void {
|
|
573
888
|
const agents = program
|
|
574
889
|
.command("agents")
|
|
575
|
-
.description("
|
|
890
|
+
.description("Manage running, recent, and historical agent tasks");
|
|
576
891
|
|
|
577
892
|
agents
|
|
578
893
|
.command("list")
|
|
@@ -592,7 +907,10 @@ export function addAgentsCommand(program: Command): void {
|
|
|
592
907
|
"Show a summary for a specific agent task: status, last tool, cost, elapsed. " +
|
|
593
908
|
"Accepts a full task ID, partial substring, or -i <number> for row index from 'agents list'."
|
|
594
909
|
)
|
|
595
|
-
.option(
|
|
910
|
+
.option(
|
|
911
|
+
"-i, --index <number>",
|
|
912
|
+
"Select task by row number from 'agents list'"
|
|
913
|
+
)
|
|
596
914
|
.action(async (taskId: string | undefined, opts: { index?: string }) => {
|
|
597
915
|
await cmdStatus(taskId, opts);
|
|
598
916
|
});
|
|
@@ -604,13 +922,26 @@ export function addAgentsCommand(program: Command): void {
|
|
|
604
922
|
"Accepts a full task ID, partial substring, or -i <number> for row index from 'agents list'. " +
|
|
605
923
|
"Use -f to follow live output."
|
|
606
924
|
)
|
|
607
|
-
.option(
|
|
608
|
-
|
|
925
|
+
.option(
|
|
926
|
+
"-i, --index <number>",
|
|
927
|
+
"Select task by row number from 'agents list'"
|
|
928
|
+
)
|
|
929
|
+
.option(
|
|
930
|
+
"-n, --count <number>",
|
|
931
|
+
"Number of messages to show",
|
|
932
|
+
(v) => parseInt(v, 10),
|
|
933
|
+
20
|
|
934
|
+
)
|
|
609
935
|
.option("--raw", "Output raw JSON of messages", false)
|
|
610
936
|
.option("-f, --follow", "Follow live output (poll for new messages)", false)
|
|
611
|
-
.action(
|
|
612
|
-
|
|
613
|
-
|
|
937
|
+
.action(
|
|
938
|
+
async (
|
|
939
|
+
taskId: string | undefined,
|
|
940
|
+
opts: { count: number; raw: boolean; follow: boolean; index?: string }
|
|
941
|
+
) => {
|
|
942
|
+
await cmdTail(taskId, opts);
|
|
943
|
+
}
|
|
944
|
+
);
|
|
614
945
|
|
|
615
946
|
agents
|
|
616
947
|
.command("attach [taskId]")
|
|
@@ -619,7 +950,10 @@ export function addAgentsCommand(program: Command): void {
|
|
|
619
950
|
"Shows recent history then streams new messages as they arrive. " +
|
|
620
951
|
"Accepts a full task ID, partial substring, or -i <number> for row index from 'agents list'."
|
|
621
952
|
)
|
|
622
|
-
.option(
|
|
953
|
+
.option(
|
|
954
|
+
"-i, --index <number>",
|
|
955
|
+
"Select task by row number from 'agents list'"
|
|
956
|
+
)
|
|
623
957
|
.action(async (taskId: string | undefined, opts: { index?: string }) => {
|
|
624
958
|
await cmdAttach(taskId, opts);
|
|
625
959
|
});
|
|
@@ -631,9 +965,70 @@ export function addAgentsCommand(program: Command): void {
|
|
|
631
965
|
"Reads metadata.result, falling back to the last assistant message. " +
|
|
632
966
|
"Accepts a full task ID, partial substring, or -i <number> for row index from 'agents list'."
|
|
633
967
|
)
|
|
634
|
-
.option(
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
968
|
+
.option(
|
|
969
|
+
"-i, --index <number>",
|
|
970
|
+
"Select task by row number from 'agents list'"
|
|
971
|
+
)
|
|
972
|
+
.option(
|
|
973
|
+
"--raw",
|
|
974
|
+
"Print only the raw answer text (no header/formatting)",
|
|
975
|
+
false
|
|
976
|
+
)
|
|
977
|
+
.action(
|
|
978
|
+
async (
|
|
979
|
+
taskId: string | undefined,
|
|
980
|
+
opts: { index?: string; raw: boolean }
|
|
981
|
+
) => {
|
|
982
|
+
await cmdAnswer(taskId, opts);
|
|
983
|
+
}
|
|
984
|
+
);
|
|
985
|
+
addHistoryRunOptions(
|
|
986
|
+
agents
|
|
987
|
+
.command("resume [taskId]")
|
|
988
|
+
.description(
|
|
989
|
+
"Resume an existing agent task. Accepts a task ID, partial substring, or -i <number> for row index from 'agents list'."
|
|
990
|
+
),
|
|
991
|
+
false
|
|
992
|
+
).action(async (taskId: string | undefined, opts: HistoryRunOptions) => {
|
|
993
|
+
try {
|
|
994
|
+
const value = opts.index ?? taskId;
|
|
995
|
+
if (!value) {
|
|
996
|
+
throw new Error("Provide a task ID or use -i <number> to select by index.");
|
|
997
|
+
}
|
|
998
|
+
const resolvedId = resolveTaskId(value);
|
|
999
|
+
if (!resolvedId) {
|
|
1000
|
+
throw new Error(`Task not found: ${value}`);
|
|
1001
|
+
}
|
|
1002
|
+
await runFromHistory(resolvedId, opts, false, getChatService);
|
|
1003
|
+
} catch (error) {
|
|
1004
|
+
console.error("Error resuming agent:", error);
|
|
1005
|
+
process.exitCode = 1;
|
|
1006
|
+
}
|
|
1007
|
+
});
|
|
1008
|
+
|
|
1009
|
+
addHistoryRunOptions(
|
|
1010
|
+
agents
|
|
1011
|
+
.command("fork [sourceTaskId]")
|
|
1012
|
+
.description(
|
|
1013
|
+
"Fork an existing agent task into a new task. Accepts a task ID, partial substring, or -i <number> for row index from 'agents list'."
|
|
1014
|
+
),
|
|
1015
|
+
true
|
|
1016
|
+
).action(async (sourceTaskId: string | undefined, opts: HistoryRunOptions) => {
|
|
1017
|
+
try {
|
|
1018
|
+
const value = opts.index ?? sourceTaskId;
|
|
1019
|
+
if (!value) {
|
|
1020
|
+
throw new Error(
|
|
1021
|
+
"Provide a task ID or use -i <number> to select by index."
|
|
1022
|
+
);
|
|
1023
|
+
}
|
|
1024
|
+
const resolvedId = resolveTaskId(value);
|
|
1025
|
+
if (!resolvedId) {
|
|
1026
|
+
throw new Error(`Task not found: ${value}`);
|
|
1027
|
+
}
|
|
1028
|
+
await runFromHistory(resolvedId, opts, true, getChatService);
|
|
1029
|
+
} catch (error) {
|
|
1030
|
+
console.error("Error forking agent:", error);
|
|
1031
|
+
process.exitCode = 1;
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
639
1034
|
}
|