@tyvm/knowhow 0.0.146 → 0.0.147
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 +24 -0
- package/src/agents/historyRollback.ts +36 -0
- package/src/agents/tools/startAgentTask.ts +41 -9
- package/src/auth/browserLogin.ts +9 -3
- package/src/auth/keyAuth.ts +115 -0
- package/src/auth/keyManager.ts +166 -0
- 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 +2 -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/types.ts +2 -0
- package/src/cli.ts +1 -1
- package/src/clients/index.ts +2 -0
- package/src/commands/agent.ts +1 -38
- package/src/commands/agents.ts +403 -53
- package/src/commands/misc.ts +3 -2
- package/src/login.ts +89 -28
- package/src/services/AgentService.ts +2 -0
- package/src/services/AgentSyncFs.ts +65 -0
- 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/KnowhowClient.ts +68 -7
- package/src/services/LazyToolsService.ts +9 -0
- 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 +2 -0
- package/src/services/index.ts +2 -0
- package/src/services/modules/index.ts +4 -1
- 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/historyCommandArgs.test.ts +37 -0
- package/tests/unit/commands/agents.test.ts +68 -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 +29 -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 +1 -0
- package/ts_build/src/agents/base/base.js +31 -2
- 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/startAgentTask.d.ts +2 -0
- package/ts_build/src/agents/tools/startAgentTask.js +36 -9
- package/ts_build/src/agents/tools/startAgentTask.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/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.js +16 -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/types.d.ts +2 -0
- package/ts_build/src/cli.js +1 -1
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/clients/index.js +19 -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 +1 -1
- package/ts_build/src/commands/agents.js +174 -16
- 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/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/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 +62 -15
- 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/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 +1 -0
- package/ts_build/src/services/LazyToolsService.js +21 -2
- 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.js +16 -2
- package/ts_build/src/services/Tools.js.map +1 -1
- package/ts_build/src/services/index.d.ts +2 -0
- package/ts_build/src/services/index.js +4 -2
- package/ts_build/src/services/index.js.map +1 -1
- package/ts_build/src/services/modules/index.d.ts +2 -1
- package/ts_build/src/services/modules/index.js +1 -1
- package/ts_build/src/services/modules/index.js.map +1 -1
- 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/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 +91 -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 +27 -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,7 +21,16 @@
|
|
|
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");
|
|
@@ -70,8 +81,11 @@ function elapsedStr(startIso: string | undefined, endIso?: string): string {
|
|
|
70
81
|
const end = endIso ? new Date(endIso).getTime() : Date.now();
|
|
71
82
|
const ms = end - start;
|
|
72
83
|
if (ms < 60_000) return `${Math.floor(ms / 1000)}s`;
|
|
73
|
-
if (ms < 3_600_000)
|
|
74
|
-
|
|
84
|
+
if (ms < 3_600_000)
|
|
85
|
+
return `${Math.floor(ms / 60_000)}m ${Math.floor((ms % 60_000) / 1000)}s`;
|
|
86
|
+
return `${Math.floor(ms / 3_600_000)}h ${Math.floor(
|
|
87
|
+
(ms % 3_600_000) / 60_000
|
|
88
|
+
)}m`;
|
|
75
89
|
}
|
|
76
90
|
|
|
77
91
|
function shortId(taskId: string, maxLen = 52): string {
|
|
@@ -103,7 +117,11 @@ function lastAssistantMessage(thread: any[]): string | undefined {
|
|
|
103
117
|
function lastToolCall(thread: any[]): string | undefined {
|
|
104
118
|
for (let i = thread.length - 1; i >= 0; i--) {
|
|
105
119
|
const msg = thread[i];
|
|
106
|
-
if (
|
|
120
|
+
if (
|
|
121
|
+
msg.role === "assistant" &&
|
|
122
|
+
Array.isArray(msg.tool_calls) &&
|
|
123
|
+
msg.tool_calls.length > 0
|
|
124
|
+
) {
|
|
107
125
|
const last = msg.tool_calls[msg.tool_calls.length - 1];
|
|
108
126
|
return last?.function?.name;
|
|
109
127
|
}
|
|
@@ -126,25 +144,40 @@ function formatMessage(msg: any, index: number): string {
|
|
|
126
144
|
.join(" | ");
|
|
127
145
|
}
|
|
128
146
|
|
|
129
|
-
if (
|
|
147
|
+
if (
|
|
148
|
+
msg.role === "assistant" &&
|
|
149
|
+
Array.isArray(msg.tool_calls) &&
|
|
150
|
+
msg.tool_calls.length > 0
|
|
151
|
+
) {
|
|
130
152
|
const tools = msg.tool_calls.map((tc: any) => {
|
|
131
153
|
const name = tc?.function?.name ?? "?";
|
|
132
154
|
let args = "";
|
|
133
155
|
try {
|
|
134
156
|
const parsed = JSON.parse(tc?.function?.arguments ?? "{}");
|
|
135
157
|
const entries = Object.entries(parsed).slice(0, 2);
|
|
136
|
-
args = entries
|
|
158
|
+
args = entries
|
|
159
|
+
.map(([k, v]) => `${k}=${String(v).slice(0, 40)}`)
|
|
160
|
+
.join(", ");
|
|
137
161
|
} catch {
|
|
138
162
|
args = (tc?.function?.arguments ?? "").slice(0, 80);
|
|
139
163
|
}
|
|
140
164
|
return `[TOOL] ${name}(${args})`;
|
|
141
165
|
});
|
|
142
|
-
content = content
|
|
166
|
+
content = content
|
|
167
|
+
? content + "\n " + tools.join("\n ")
|
|
168
|
+
: tools.join("\n ");
|
|
143
169
|
}
|
|
144
170
|
|
|
145
171
|
if (msg.role === "tool") {
|
|
146
|
-
const result =
|
|
147
|
-
|
|
172
|
+
const result =
|
|
173
|
+
typeof msg.content === "string"
|
|
174
|
+
? msg.content.slice(0, 200)
|
|
175
|
+
: JSON.stringify(msg.content).slice(0, 200);
|
|
176
|
+
content = `[RESULT] ${result}${
|
|
177
|
+
(typeof msg.content === "string" ? msg.content : "").length > 200
|
|
178
|
+
? "…"
|
|
179
|
+
: ""
|
|
180
|
+
}`;
|
|
148
181
|
}
|
|
149
182
|
|
|
150
183
|
return ` #${String(index).padStart(3)} [${role}] ${content}`;
|
|
@@ -155,8 +188,8 @@ function formatMessage(msg: any, index: number): string {
|
|
|
155
188
|
// ---------------------------------------------------------------------------
|
|
156
189
|
|
|
157
190
|
type Row = {
|
|
158
|
-
taskId: string;
|
|
159
|
-
displayId: string;
|
|
191
|
+
taskId: string; // full task ID (not truncated)
|
|
192
|
+
displayId: string; // truncated for display
|
|
160
193
|
agentName: string;
|
|
161
194
|
status: string;
|
|
162
195
|
cost: string;
|
|
@@ -182,9 +215,17 @@ function buildRows(includeAll: boolean): Row[] {
|
|
|
182
215
|
}
|
|
183
216
|
}
|
|
184
217
|
|
|
185
|
-
const cost =
|
|
186
|
-
|
|
187
|
-
|
|
218
|
+
const cost =
|
|
219
|
+
meta?.totalCostUsd != null
|
|
220
|
+
? `$${(meta.totalCostUsd as number).toFixed(3)}`
|
|
221
|
+
: "";
|
|
222
|
+
const elapsed = elapsedStr(
|
|
223
|
+
meta?.startTime,
|
|
224
|
+
meta?.status === "completed" ? meta?.lastUpdate : undefined
|
|
225
|
+
);
|
|
226
|
+
const lastUpdate = meta?.lastUpdate
|
|
227
|
+
? new Date(meta.lastUpdate).toLocaleString()
|
|
228
|
+
: "?";
|
|
188
229
|
|
|
189
230
|
rows.push({
|
|
190
231
|
taskId,
|
|
@@ -221,7 +262,6 @@ function resolveTaskId(value: string, includeAll = false): string | null {
|
|
|
221
262
|
return all.find((id) => id.includes(value)) ?? null;
|
|
222
263
|
}
|
|
223
264
|
|
|
224
|
-
|
|
225
265
|
// ---------------------------------------------------------------------------
|
|
226
266
|
// Command handlers
|
|
227
267
|
// ---------------------------------------------------------------------------
|
|
@@ -233,15 +273,30 @@ async function cmdList(opts: { all: boolean; json: boolean }): Promise<void> {
|
|
|
233
273
|
if (agentTaskIds().length === 0) {
|
|
234
274
|
console.log("No agent task directories found under", AGENTS_DIR);
|
|
235
275
|
} else {
|
|
236
|
-
console.log(
|
|
276
|
+
console.log(
|
|
277
|
+
"No active agent tasks. Use --all to include completed tasks."
|
|
278
|
+
);
|
|
237
279
|
}
|
|
238
280
|
return;
|
|
239
281
|
}
|
|
240
282
|
|
|
241
283
|
if (opts.json) {
|
|
242
|
-
console.log(
|
|
243
|
-
|
|
244
|
-
|
|
284
|
+
console.log(
|
|
285
|
+
JSON.stringify(
|
|
286
|
+
rows.map(
|
|
287
|
+
({ taskId, agentName, status, cost, elapsed, lastUpdate }) => ({
|
|
288
|
+
taskId,
|
|
289
|
+
agentName,
|
|
290
|
+
status,
|
|
291
|
+
cost,
|
|
292
|
+
elapsed,
|
|
293
|
+
lastUpdate,
|
|
294
|
+
})
|
|
295
|
+
),
|
|
296
|
+
null,
|
|
297
|
+
2
|
|
298
|
+
)
|
|
299
|
+
);
|
|
245
300
|
return;
|
|
246
301
|
}
|
|
247
302
|
|
|
@@ -277,12 +332,15 @@ async function cmdList(opts: { all: boolean; json: boolean }): Promise<void> {
|
|
|
277
332
|
"\n"
|
|
278
333
|
);
|
|
279
334
|
});
|
|
280
|
-
console.log(
|
|
335
|
+
console.log(
|
|
336
|
+
"\nTip: use -i <#> with tail/status/attach to select by row number, e.g. knowhow agents attach -i 1\n"
|
|
337
|
+
);
|
|
281
338
|
}
|
|
282
339
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
340
|
+
async function cmdStatus(
|
|
341
|
+
taskIdOrIndex: string | undefined,
|
|
342
|
+
opts: { index?: string }
|
|
343
|
+
): Promise<void> {
|
|
286
344
|
const value = opts.index ?? taskIdOrIndex;
|
|
287
345
|
if (!value) {
|
|
288
346
|
console.error("Provide a task ID or use -i <number> to select by index.");
|
|
@@ -312,9 +370,23 @@ async function cmdStatus(taskIdOrIndex: string | undefined, opts: { index?: stri
|
|
|
312
370
|
console.log(`Task ID: ${resolvedId}`);
|
|
313
371
|
console.log(`Agent: ${meta?.agentName ?? "?"}`);
|
|
314
372
|
console.log(`Status: ${status}`);
|
|
315
|
-
console.log(
|
|
316
|
-
|
|
317
|
-
|
|
373
|
+
console.log(
|
|
374
|
+
`Cost: ${
|
|
375
|
+
meta?.totalCostUsd != null
|
|
376
|
+
? "$" + (meta.totalCostUsd as number).toFixed(4)
|
|
377
|
+
: "?"
|
|
378
|
+
}`
|
|
379
|
+
);
|
|
380
|
+
console.log(
|
|
381
|
+
`Started: ${
|
|
382
|
+
meta?.startTime ? new Date(meta.startTime).toLocaleString() : "?"
|
|
383
|
+
}`
|
|
384
|
+
);
|
|
385
|
+
console.log(
|
|
386
|
+
`Last update:${
|
|
387
|
+
meta?.lastUpdate ? " " + new Date(meta.lastUpdate).toLocaleString() : " ?"
|
|
388
|
+
}`
|
|
389
|
+
);
|
|
318
390
|
console.log(`Elapsed: ${elapsedStr(meta?.startTime)}`);
|
|
319
391
|
|
|
320
392
|
const threads: any[][] = meta?.threads ?? [];
|
|
@@ -342,7 +414,10 @@ async function cmdStatus(taskIdOrIndex: string | undefined, opts: { index?: stri
|
|
|
342
414
|
console.log("─".repeat(60));
|
|
343
415
|
}
|
|
344
416
|
|
|
345
|
-
async function cmdTail(
|
|
417
|
+
async function cmdTail(
|
|
418
|
+
taskIdOrIndex: string | undefined,
|
|
419
|
+
opts: { count: number; raw: boolean; follow: boolean; index?: string }
|
|
420
|
+
): Promise<void> {
|
|
346
421
|
const value = opts.index ?? taskIdOrIndex;
|
|
347
422
|
if (!value) {
|
|
348
423
|
console.error("Provide a task ID or use -i <number> to select by index.");
|
|
@@ -373,7 +448,9 @@ async function cmdTail(taskIdOrIndex: string | undefined, opts: { count: number;
|
|
|
373
448
|
|
|
374
449
|
const threads: any[][] = meta.threads ?? [];
|
|
375
450
|
if (threads.length === 0) {
|
|
376
|
-
console.log(
|
|
451
|
+
console.log(
|
|
452
|
+
"No thread data found in metadata.json (agent may not have started yet)."
|
|
453
|
+
);
|
|
377
454
|
return;
|
|
378
455
|
}
|
|
379
456
|
|
|
@@ -389,7 +466,11 @@ async function cmdTail(taskIdOrIndex: string | undefined, opts: { count: number;
|
|
|
389
466
|
const startIndex = lastThread.length - slice.length;
|
|
390
467
|
|
|
391
468
|
console.log(`\n📜 Last ${slice.length} messages for task: ${resolvedId}`);
|
|
392
|
-
console.log(
|
|
469
|
+
console.log(
|
|
470
|
+
` Agent: ${meta.agentName} | Status: ${
|
|
471
|
+
meta.status ?? loadStatus(resolvedId)
|
|
472
|
+
} | Total messages: ${lastThread.length}`
|
|
473
|
+
);
|
|
393
474
|
console.log("─".repeat(80));
|
|
394
475
|
|
|
395
476
|
for (let i = 0; i < slice.length; i++) {
|
|
@@ -398,12 +479,20 @@ async function cmdTail(taskIdOrIndex: string | undefined, opts: { count: number;
|
|
|
398
479
|
|
|
399
480
|
console.log("─".repeat(80));
|
|
400
481
|
|
|
401
|
-
const cost =
|
|
482
|
+
const cost =
|
|
483
|
+
meta.totalCostUsd != null
|
|
484
|
+
? `$${(meta.totalCostUsd as number).toFixed(4)}`
|
|
485
|
+
: "?";
|
|
402
486
|
const elapsed = elapsedStr(meta.startTime);
|
|
403
487
|
const status = getStatus(resolvedId, meta);
|
|
404
|
-
console.log(
|
|
488
|
+
console.log(
|
|
489
|
+
`Cost: ${cost} | Elapsed: ${elapsed} | Last update: ${
|
|
490
|
+
meta.lastUpdate ? new Date(meta.lastUpdate).toLocaleString() : "?"
|
|
491
|
+
}`
|
|
492
|
+
);
|
|
405
493
|
|
|
406
|
-
const isDone =
|
|
494
|
+
const isDone =
|
|
495
|
+
status === "completed" || status === "failed" || status === "killed";
|
|
407
496
|
|
|
408
497
|
if (opts.follow) {
|
|
409
498
|
if (isDone) {
|
|
@@ -423,13 +512,20 @@ async function cmdTail(taskIdOrIndex: string | undefined, opts: { count: number;
|
|
|
423
512
|
* Poll metadata.json every second, printing any new messages as they arrive.
|
|
424
513
|
* Exits when the agent status becomes completed/failed/killed.
|
|
425
514
|
*/
|
|
426
|
-
async function followTask(
|
|
515
|
+
async function followTask(
|
|
516
|
+
resolvedId: string,
|
|
517
|
+
seenCount: number
|
|
518
|
+
): Promise<void> {
|
|
427
519
|
console.log(`\n👁 Following agent output… (Ctrl+C to stop)\n`);
|
|
428
520
|
|
|
429
521
|
// Check upfront — if already done, exit immediately
|
|
430
522
|
const initialMeta = loadMeta(resolvedId);
|
|
431
523
|
const initialStatus = getStatus(resolvedId, initialMeta);
|
|
432
|
-
if (
|
|
524
|
+
if (
|
|
525
|
+
initialStatus === "completed" ||
|
|
526
|
+
initialStatus === "failed" ||
|
|
527
|
+
initialStatus === "killed"
|
|
528
|
+
) {
|
|
433
529
|
console.log(`✅ Agent already ${initialStatus}. Nothing to follow.\n`);
|
|
434
530
|
return;
|
|
435
531
|
}
|
|
@@ -452,9 +548,19 @@ async function followTask(resolvedId: string, seenCount: number): Promise<void>
|
|
|
452
548
|
}
|
|
453
549
|
const status = getStatus(resolvedId, meta);
|
|
454
550
|
if (status === "completed" || status === "failed" || status === "killed") {
|
|
455
|
-
const cost =
|
|
456
|
-
|
|
457
|
-
|
|
551
|
+
const cost =
|
|
552
|
+
meta.totalCostUsd != null
|
|
553
|
+
? `$${(meta.totalCostUsd as number).toFixed(4)}`
|
|
554
|
+
: "?";
|
|
555
|
+
console.log(
|
|
556
|
+
`\n─────────────────────────────────────────────────────────────────────────────────`
|
|
557
|
+
);
|
|
558
|
+
console.log(
|
|
559
|
+
`✅ Agent ${status}. Cost: ${cost} | Elapsed: ${elapsedStr(
|
|
560
|
+
meta.startTime,
|
|
561
|
+
meta.lastUpdate
|
|
562
|
+
)}`
|
|
563
|
+
);
|
|
458
564
|
clearInterval(interval);
|
|
459
565
|
process.exit(0);
|
|
460
566
|
}
|
|
@@ -464,7 +570,10 @@ async function followTask(resolvedId: string, seenCount: number): Promise<void>
|
|
|
464
570
|
await new Promise<void>(() => {});
|
|
465
571
|
}
|
|
466
572
|
|
|
467
|
-
async function cmdAttach(
|
|
573
|
+
async function cmdAttach(
|
|
574
|
+
taskIdOrIndex: string | undefined,
|
|
575
|
+
opts: { index?: string }
|
|
576
|
+
): Promise<void> {
|
|
468
577
|
const value = opts.index ?? taskIdOrIndex;
|
|
469
578
|
if (!value) {
|
|
470
579
|
console.error("Provide a task ID or use -i <number> to select by index.");
|
|
@@ -551,28 +660,189 @@ async function cmdAnswer(
|
|
|
551
660
|
console.log(`\n📭 No final answer available for task: ${resolvedId}`);
|
|
552
661
|
console.log(` Status: ${status}`);
|
|
553
662
|
if (status !== "completed") {
|
|
554
|
-
console.log(
|
|
663
|
+
console.log(
|
|
664
|
+
` The agent hasn't finished yet — attach with 'knowhow agents attach' to follow it.`
|
|
665
|
+
);
|
|
555
666
|
}
|
|
556
667
|
return;
|
|
557
668
|
}
|
|
558
669
|
|
|
559
670
|
console.log(`\n💬 Final answer for task: ${resolvedId}`);
|
|
560
|
-
console.log(
|
|
671
|
+
console.log(
|
|
672
|
+
` Agent: ${meta.agentName ?? "?"} | Status: ${status} | Cost: ${
|
|
673
|
+
meta.totalCostUsd != null
|
|
674
|
+
? "$" + (meta.totalCostUsd as number).toFixed(4)
|
|
675
|
+
: "?"
|
|
676
|
+
}`
|
|
677
|
+
);
|
|
561
678
|
console.log("─".repeat(80));
|
|
562
679
|
console.log(answer);
|
|
563
680
|
console.log("─".repeat(80) + "\n");
|
|
564
681
|
}
|
|
565
682
|
|
|
683
|
+
interface HistoryRunOptions {
|
|
684
|
+
rollback: string;
|
|
685
|
+
input?: string;
|
|
686
|
+
taskId?: string;
|
|
687
|
+
messageId?: string;
|
|
688
|
+
syncFs?: boolean;
|
|
689
|
+
provider?: string;
|
|
690
|
+
model?: string;
|
|
691
|
+
agentName?: string;
|
|
692
|
+
reasoningEffort?: string;
|
|
693
|
+
renderer?: string;
|
|
694
|
+
index?: string;
|
|
695
|
+
headless?: boolean;
|
|
696
|
+
}
|
|
566
697
|
|
|
698
|
+
async function runFromHistory(
|
|
699
|
+
sourceTaskId: string,
|
|
700
|
+
options: HistoryRunOptions,
|
|
701
|
+
fork: boolean,
|
|
702
|
+
getChatService: () => any
|
|
703
|
+
): Promise<void> {
|
|
704
|
+
const rollback = Number(options.rollback);
|
|
705
|
+
if (!Number.isInteger(rollback) || rollback < 0) {
|
|
706
|
+
throw new Error("--rollback must be a non-negative integer");
|
|
707
|
+
}
|
|
708
|
+
const hasHeadlessOverrides = !!(
|
|
709
|
+
options.input || options.messageId || options.syncFs || options.provider ||
|
|
710
|
+
options.model || options.agentName || options.reasoningEffort ||
|
|
711
|
+
options.renderer || options.taskId
|
|
712
|
+
);
|
|
713
|
+
if (process.stdin.isTTY && !options.headless && !hasHeadlessOverrides) {
|
|
714
|
+
const command = fork ? "/fork" : "/resume";
|
|
715
|
+
const { setupServices } = await import("./services");
|
|
716
|
+
await setupServices();
|
|
717
|
+
await startChat(`${command} ${sourceTaskId} --rollback ${rollback}`);
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
const requestedReasoningEffortValue = options.reasoningEffort;
|
|
721
|
+
if (
|
|
722
|
+
requestedReasoningEffortValue !== undefined &&
|
|
723
|
+
!isReasoningEffort(requestedReasoningEffortValue)
|
|
724
|
+
) {
|
|
725
|
+
throw new Error(
|
|
726
|
+
`Invalid reasoning effort "${requestedReasoningEffortValue}". Expected one of: ${REASONING_EFFORTS.join(
|
|
727
|
+
", "
|
|
728
|
+
)}.`
|
|
729
|
+
);
|
|
730
|
+
}
|
|
731
|
+
const requestedReasoningEffort =
|
|
732
|
+
requestedReasoningEffortValue as CompletionOptions["reasoning_effort"];
|
|
733
|
+
|
|
734
|
+
const { setupServices } = await import("./services");
|
|
735
|
+
await setupServices();
|
|
736
|
+
const chatService = getChatService();
|
|
737
|
+
let config: any = {};
|
|
738
|
+
try {
|
|
739
|
+
config = await getConfig();
|
|
740
|
+
} catch (_) {}
|
|
741
|
+
const rendererSpecifier =
|
|
742
|
+
options.renderer ?? config.chat?.renderer ?? "basic";
|
|
743
|
+
const resolvedRenderer =
|
|
744
|
+
rendererSpecifier === "basic" && !process.stdout.isTTY
|
|
745
|
+
? "plain"
|
|
746
|
+
: rendererSpecifier;
|
|
747
|
+
try {
|
|
748
|
+
chatService.setContext({ renderer: await loadRenderer(resolvedRenderer) });
|
|
749
|
+
} catch (err: any) {
|
|
750
|
+
console.warn(
|
|
751
|
+
`⚠ Could not load renderer "${resolvedRenderer}": ${err.message}`
|
|
752
|
+
);
|
|
753
|
+
chatService.setContext({
|
|
754
|
+
renderer: !process.stdout.isTTY
|
|
755
|
+
? new PlainRenderer()
|
|
756
|
+
: await loadRenderer("basic"),
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
const agentModule = new AgentModule();
|
|
761
|
+
const threads = await agentModule.loadThreadsForTask(
|
|
762
|
+
sourceTaskId,
|
|
763
|
+
options.messageId
|
|
764
|
+
);
|
|
765
|
+
const savedSettings = await agentModule.loadTaskSettings(
|
|
766
|
+
sourceTaskId,
|
|
767
|
+
options.messageId
|
|
768
|
+
);
|
|
769
|
+
await agentModule.initialize(chatService);
|
|
770
|
+
const { taskCompleted } = await agentModule.resumeFromMessages({
|
|
771
|
+
agentName: options.agentName || savedSettings.agentName || "Patcher",
|
|
772
|
+
input: options.input || "Please continue from where you left off.",
|
|
773
|
+
threads,
|
|
774
|
+
messageId: fork ? undefined : options.messageId,
|
|
775
|
+
taskId: fork ? options.taskId : sourceTaskId,
|
|
776
|
+
// sourceTaskId may itself be a remote UUID when there is no local metadata;
|
|
777
|
+
// AgentModule validates it and rejects filesystem slugs.
|
|
778
|
+
remoteTaskId: fork ? undefined : savedSettings.remoteTaskId || sourceTaskId,
|
|
779
|
+
syncFs: options.syncFs,
|
|
780
|
+
rollback,
|
|
781
|
+
fork,
|
|
782
|
+
model: options.model || savedSettings.model,
|
|
783
|
+
provider: options.provider || savedSettings.provider,
|
|
784
|
+
reasoningEffort: requestedReasoningEffort || savedSettings.reasoningEffort,
|
|
785
|
+
summarizeReasoning: savedSettings.summarizeReasoning,
|
|
786
|
+
enabledTools: savedSettings.enabledTools,
|
|
787
|
+
});
|
|
788
|
+
await taskCompleted;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
function addHistoryRunOptions(
|
|
792
|
+
command: Command,
|
|
793
|
+
includeDestinationTaskId: boolean
|
|
794
|
+
): Command {
|
|
795
|
+
command
|
|
796
|
+
.option(
|
|
797
|
+
"-i, --index <number>",
|
|
798
|
+
"Select task by row number from 'agents list'"
|
|
799
|
+
)
|
|
800
|
+
.option(
|
|
801
|
+
"--rollback <count>",
|
|
802
|
+
"Discard the newest N agent interactions before continuing",
|
|
803
|
+
"0"
|
|
804
|
+
)
|
|
805
|
+
.option("--input <text>", "Message to send after restoring history")
|
|
806
|
+
.option(
|
|
807
|
+
"--message-id <messageId>",
|
|
808
|
+
"Knowhow message ID for remote task lookup"
|
|
809
|
+
)
|
|
810
|
+
.option("--sync-fs", "Enable filesystem-based synchronization")
|
|
811
|
+
.option("--provider <provider>", "Override the saved AI provider")
|
|
812
|
+
.option("--model <model>", "Override the saved model")
|
|
813
|
+
.option("--agent-name <name>", "Override the saved agent")
|
|
814
|
+
.option(
|
|
815
|
+
"--reasoning-effort <effort>",
|
|
816
|
+
`Reasoning effort: ${REASONING_EFFORTS.join(", ")}`
|
|
817
|
+
)
|
|
818
|
+
.option(
|
|
819
|
+
"--renderer <name>",
|
|
820
|
+
"Renderer to use (default: from config or basic)"
|
|
821
|
+
)
|
|
822
|
+
.option(
|
|
823
|
+
"--headless",
|
|
824
|
+
"Run to completion without opening the attached chat interface"
|
|
825
|
+
);
|
|
826
|
+
if (includeDestinationTaskId) {
|
|
827
|
+
command.option(
|
|
828
|
+
"--task-id <taskId>",
|
|
829
|
+
"Explicit task ID for the newly forked task"
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
return command;
|
|
833
|
+
}
|
|
567
834
|
|
|
568
835
|
// ---------------------------------------------------------------------------
|
|
569
836
|
// Command registration
|
|
570
837
|
// ---------------------------------------------------------------------------
|
|
571
838
|
|
|
572
|
-
export function addAgentsCommand(
|
|
839
|
+
export function addAgentsCommand(
|
|
840
|
+
program: Command,
|
|
841
|
+
getChatService: () => any
|
|
842
|
+
): void {
|
|
573
843
|
const agents = program
|
|
574
844
|
.command("agents")
|
|
575
|
-
.description("
|
|
845
|
+
.description("Manage running, recent, and historical agent tasks");
|
|
576
846
|
|
|
577
847
|
agents
|
|
578
848
|
.command("list")
|
|
@@ -592,7 +862,10 @@ export function addAgentsCommand(program: Command): void {
|
|
|
592
862
|
"Show a summary for a specific agent task: status, last tool, cost, elapsed. " +
|
|
593
863
|
"Accepts a full task ID, partial substring, or -i <number> for row index from 'agents list'."
|
|
594
864
|
)
|
|
595
|
-
.option(
|
|
865
|
+
.option(
|
|
866
|
+
"-i, --index <number>",
|
|
867
|
+
"Select task by row number from 'agents list'"
|
|
868
|
+
)
|
|
596
869
|
.action(async (taskId: string | undefined, opts: { index?: string }) => {
|
|
597
870
|
await cmdStatus(taskId, opts);
|
|
598
871
|
});
|
|
@@ -604,13 +877,26 @@ export function addAgentsCommand(program: Command): void {
|
|
|
604
877
|
"Accepts a full task ID, partial substring, or -i <number> for row index from 'agents list'. " +
|
|
605
878
|
"Use -f to follow live output."
|
|
606
879
|
)
|
|
607
|
-
.option(
|
|
608
|
-
|
|
880
|
+
.option(
|
|
881
|
+
"-i, --index <number>",
|
|
882
|
+
"Select task by row number from 'agents list'"
|
|
883
|
+
)
|
|
884
|
+
.option(
|
|
885
|
+
"-n, --count <number>",
|
|
886
|
+
"Number of messages to show",
|
|
887
|
+
(v) => parseInt(v, 10),
|
|
888
|
+
20
|
|
889
|
+
)
|
|
609
890
|
.option("--raw", "Output raw JSON of messages", false)
|
|
610
891
|
.option("-f, --follow", "Follow live output (poll for new messages)", false)
|
|
611
|
-
.action(
|
|
612
|
-
|
|
613
|
-
|
|
892
|
+
.action(
|
|
893
|
+
async (
|
|
894
|
+
taskId: string | undefined,
|
|
895
|
+
opts: { count: number; raw: boolean; follow: boolean; index?: string }
|
|
896
|
+
) => {
|
|
897
|
+
await cmdTail(taskId, opts);
|
|
898
|
+
}
|
|
899
|
+
);
|
|
614
900
|
|
|
615
901
|
agents
|
|
616
902
|
.command("attach [taskId]")
|
|
@@ -619,7 +905,10 @@ export function addAgentsCommand(program: Command): void {
|
|
|
619
905
|
"Shows recent history then streams new messages as they arrive. " +
|
|
620
906
|
"Accepts a full task ID, partial substring, or -i <number> for row index from 'agents list'."
|
|
621
907
|
)
|
|
622
|
-
.option(
|
|
908
|
+
.option(
|
|
909
|
+
"-i, --index <number>",
|
|
910
|
+
"Select task by row number from 'agents list'"
|
|
911
|
+
)
|
|
623
912
|
.action(async (taskId: string | undefined, opts: { index?: string }) => {
|
|
624
913
|
await cmdAttach(taskId, opts);
|
|
625
914
|
});
|
|
@@ -631,9 +920,70 @@ export function addAgentsCommand(program: Command): void {
|
|
|
631
920
|
"Reads metadata.result, falling back to the last assistant message. " +
|
|
632
921
|
"Accepts a full task ID, partial substring, or -i <number> for row index from 'agents list'."
|
|
633
922
|
)
|
|
634
|
-
.option(
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
923
|
+
.option(
|
|
924
|
+
"-i, --index <number>",
|
|
925
|
+
"Select task by row number from 'agents list'"
|
|
926
|
+
)
|
|
927
|
+
.option(
|
|
928
|
+
"--raw",
|
|
929
|
+
"Print only the raw answer text (no header/formatting)",
|
|
930
|
+
false
|
|
931
|
+
)
|
|
932
|
+
.action(
|
|
933
|
+
async (
|
|
934
|
+
taskId: string | undefined,
|
|
935
|
+
opts: { index?: string; raw: boolean }
|
|
936
|
+
) => {
|
|
937
|
+
await cmdAnswer(taskId, opts);
|
|
938
|
+
}
|
|
939
|
+
);
|
|
940
|
+
addHistoryRunOptions(
|
|
941
|
+
agents
|
|
942
|
+
.command("resume [taskId]")
|
|
943
|
+
.description(
|
|
944
|
+
"Resume an existing agent task. Accepts a task ID, partial substring, or -i <number> for row index from 'agents list'."
|
|
945
|
+
),
|
|
946
|
+
false
|
|
947
|
+
).action(async (taskId: string | undefined, opts: HistoryRunOptions) => {
|
|
948
|
+
try {
|
|
949
|
+
const value = opts.index ?? taskId;
|
|
950
|
+
if (!value) {
|
|
951
|
+
throw new Error("Provide a task ID or use -i <number> to select by index.");
|
|
952
|
+
}
|
|
953
|
+
const resolvedId = resolveTaskId(value);
|
|
954
|
+
if (!resolvedId) {
|
|
955
|
+
throw new Error(`Task not found: ${value}`);
|
|
956
|
+
}
|
|
957
|
+
await runFromHistory(resolvedId, opts, false, getChatService);
|
|
958
|
+
} catch (error) {
|
|
959
|
+
console.error("Error resuming agent:", error);
|
|
960
|
+
process.exitCode = 1;
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
addHistoryRunOptions(
|
|
965
|
+
agents
|
|
966
|
+
.command("fork [sourceTaskId]")
|
|
967
|
+
.description(
|
|
968
|
+
"Fork an existing agent task into a new task. Accepts a task ID, partial substring, or -i <number> for row index from 'agents list'."
|
|
969
|
+
),
|
|
970
|
+
true
|
|
971
|
+
).action(async (sourceTaskId: string | undefined, opts: HistoryRunOptions) => {
|
|
972
|
+
try {
|
|
973
|
+
const value = opts.index ?? sourceTaskId;
|
|
974
|
+
if (!value) {
|
|
975
|
+
throw new Error(
|
|
976
|
+
"Provide a task ID or use -i <number> to select by index."
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
const resolvedId = resolveTaskId(value);
|
|
980
|
+
if (!resolvedId) {
|
|
981
|
+
throw new Error(`Task not found: ${value}`);
|
|
982
|
+
}
|
|
983
|
+
await runFromHistory(resolvedId, opts, true, getChatService);
|
|
984
|
+
} catch (error) {
|
|
985
|
+
console.error("Error forking agent:", error);
|
|
986
|
+
process.exitCode = 1;
|
|
987
|
+
}
|
|
988
|
+
});
|
|
639
989
|
}
|
package/src/commands/misc.ts
CHANGED
|
@@ -23,8 +23,9 @@ export function addLoginCommand(program: Command): void {
|
|
|
23
23
|
.command("login")
|
|
24
24
|
.description("Login to knowhow")
|
|
25
25
|
.option("--jwt", "Use manual JWT input instead of browser login")
|
|
26
|
-
.
|
|
27
|
-
|
|
26
|
+
.option("-i, --identity <path>", "Ed25519 private key to use for public-key login")
|
|
27
|
+
.action(async (options: { jwt?: boolean; identity?: string }) => {
|
|
28
|
+
await login(options.jwt, options.identity);
|
|
28
29
|
});
|
|
29
30
|
}
|
|
30
31
|
|