@dench.com/cli 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/chat.ts +215 -8
- package/cron.ts +8 -4
- package/dench.ts +106 -27
- package/package.json +1 -1
package/chat.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `dench chat <subcommand>` — CLI surface for browsing
|
|
3
|
-
* in the user's workspace.
|
|
2
|
+
* `dench chat <subcommand>` — CLI surface for browsing and managing
|
|
3
|
+
* past chat threads in the user's workspace.
|
|
4
4
|
*
|
|
5
5
|
* Mirrors the `dench crm` pattern: a thin command dispatcher on top of
|
|
6
|
-
* Convex public queries (`functions/chat:listPastChats`,
|
|
7
|
-
* `searchPastChats`, `readPastChat`)
|
|
8
|
-
* "own + shared in this org" visibility
|
|
6
|
+
* Convex public queries/mutations (`functions/chat:listPastChats`,
|
|
7
|
+
* `searchPastChats`, `readPastChat`, `renameThreads`, `deleteThreads`)
|
|
8
|
+
* which themselves enforce the "own + shared in this org" visibility
|
|
9
|
+
* rule (`requireThreadAccess`).
|
|
9
10
|
*
|
|
10
11
|
* Auth: every call forwards a single bearer token via `sessionToken`
|
|
11
12
|
* (either a `dch_agent_*` agent session minted by `dench login` or a
|
|
@@ -16,9 +17,13 @@
|
|
|
16
17
|
* inside a sandbox without extra flags.
|
|
17
18
|
*
|
|
18
19
|
* Subcommands:
|
|
19
|
-
* chat list
|
|
20
|
-
* chat search
|
|
21
|
-
* chat read
|
|
20
|
+
* chat list [--query <substr>] [--limit N] [--include-archived]
|
|
21
|
+
* chat search <query> [--limit N] [--include-current]
|
|
22
|
+
* chat read <thread-id> [--limit N]
|
|
23
|
+
* chat rename <thread-id> <new-title> # single rename
|
|
24
|
+
* chat rename --from-stdin # batch via JSON {items:[...]}
|
|
25
|
+
* chat delete <thread-id> [<thread-id>...] # 1–25 ids, --yes to skip prompt
|
|
26
|
+
* chat delete --ids id1,id2,id3 # comma-separated form
|
|
22
27
|
*/
|
|
23
28
|
import type { ConvexHttpClient } from "convex/browser";
|
|
24
29
|
import { makeFunctionReference } from "convex/server";
|
|
@@ -67,6 +72,12 @@ const api = {
|
|
|
67
72
|
readPastChat: makeFunctionReference<"query">(
|
|
68
73
|
"functions/chat:readPastChat",
|
|
69
74
|
),
|
|
75
|
+
renameThreads: makeFunctionReference<"mutation">(
|
|
76
|
+
"functions/chat:renameThreads",
|
|
77
|
+
),
|
|
78
|
+
deleteThreads: makeFunctionReference<"mutation">(
|
|
79
|
+
"functions/chat:deleteThreads",
|
|
80
|
+
),
|
|
70
81
|
};
|
|
71
82
|
|
|
72
83
|
function commonArgs(ctx: ChatCliContext) {
|
|
@@ -84,6 +95,14 @@ async function callQuery(
|
|
|
84
95
|
return ctx.convex.query(fn, { ...args, ...commonArgs(ctx) } as never);
|
|
85
96
|
}
|
|
86
97
|
|
|
98
|
+
async function callMutation(
|
|
99
|
+
ctx: ChatCliContext,
|
|
100
|
+
fn: Parameters<ConvexHttpClient["mutation"]>[0],
|
|
101
|
+
args: Record<string, unknown> = {},
|
|
102
|
+
): Promise<unknown> {
|
|
103
|
+
return ctx.convex.mutation(fn, { ...args, ...commonArgs(ctx) } as never);
|
|
104
|
+
}
|
|
105
|
+
|
|
87
106
|
function out(ctx: ChatCliContext, value: unknown): void {
|
|
88
107
|
if (ctx.jsonOutput) {
|
|
89
108
|
console.log(JSON.stringify(value, null, 2));
|
|
@@ -108,6 +127,19 @@ Full-text search across past chat messages (own + shared):
|
|
|
108
127
|
Read messages from a specific past chat thread:
|
|
109
128
|
dench chat read <thread-id> [--limit N] [--json]
|
|
110
129
|
|
|
130
|
+
Rename one or more past chat threads (own + shared):
|
|
131
|
+
dench chat rename <thread-id> <new-title> [--json]
|
|
132
|
+
dench chat rename --from-stdin [--json]
|
|
133
|
+
Reads JSON {"items":[{"threadId":"...","title":"..."}, ...]} from stdin.
|
|
134
|
+
Up to 50 items per call. Titles are trimmed and clamped to 200 chars.
|
|
135
|
+
|
|
136
|
+
PERMANENTLY delete one or more past chat threads (and all their messages):
|
|
137
|
+
dench chat delete <thread-id> [<thread-id>...] [--yes] [--json]
|
|
138
|
+
dench chat delete --ids id1,id2,id3 [--yes] [--json]
|
|
139
|
+
Up to 25 ids per call. IRREVERSIBLE — the messages are removed too.
|
|
140
|
+
Without --yes, the CLI prompts for confirmation when stdin is a TTY.
|
|
141
|
+
In non-interactive contexts (sandboxes, scripts), --yes is required.
|
|
142
|
+
|
|
111
143
|
Spawn a new chat-turn workflow (same agent loop as the web UI):
|
|
112
144
|
dench chat new "<prompt>" [--model <m>] [--file-context <path>] [--visibility private|shared] [--title T] [--yolo] [--follow] [--json]
|
|
113
145
|
dench chat send <thread-id> "<message>" [--model <m>] [--yolo] [--follow] [--json]
|
|
@@ -163,6 +195,11 @@ export async function runChatCommand(opts: {
|
|
|
163
195
|
return await runChatReadCommand(ctx);
|
|
164
196
|
case "tree":
|
|
165
197
|
return await runChatTreeCommand(ctx);
|
|
198
|
+
case "rename":
|
|
199
|
+
return await runChatRenameCommand(ctx);
|
|
200
|
+
case "delete":
|
|
201
|
+
case "rm":
|
|
202
|
+
return await runChatDeleteCommand(ctx);
|
|
166
203
|
default:
|
|
167
204
|
throw new ChatCliError(`Unknown chat subcommand: ${subcommand}`);
|
|
168
205
|
}
|
|
@@ -222,6 +259,176 @@ async function runChatReadCommand(ctx: ChatCliContext): Promise<void> {
|
|
|
222
259
|
);
|
|
223
260
|
}
|
|
224
261
|
|
|
262
|
+
async function readStdin(): Promise<string> {
|
|
263
|
+
if (process.stdin.isTTY) {
|
|
264
|
+
throw new ChatCliError(
|
|
265
|
+
"--from-stdin requires JSON piped on stdin (got TTY).",
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
const chunks: Buffer[] = [];
|
|
269
|
+
for await (const chunk of process.stdin as AsyncIterable<Buffer>) {
|
|
270
|
+
chunks.push(chunk);
|
|
271
|
+
}
|
|
272
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async function runChatRenameCommand(ctx: ChatCliContext): Promise<void> {
|
|
276
|
+
const fromStdin = hasFlag(ctx.args, "--from-stdin");
|
|
277
|
+
let items: Array<{ threadId: string; title: string }>;
|
|
278
|
+
if (fromStdin) {
|
|
279
|
+
const raw = (await readStdin()).trim();
|
|
280
|
+
if (!raw) {
|
|
281
|
+
throw new ChatCliError(
|
|
282
|
+
'Empty --from-stdin payload; expected {"items":[...]}.',
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
let parsed: unknown;
|
|
286
|
+
try {
|
|
287
|
+
parsed = JSON.parse(raw);
|
|
288
|
+
} catch (error) {
|
|
289
|
+
throw new ChatCliError(
|
|
290
|
+
`Invalid JSON on stdin: ${
|
|
291
|
+
error instanceof Error ? error.message : String(error)
|
|
292
|
+
}`,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
if (
|
|
296
|
+
!parsed ||
|
|
297
|
+
typeof parsed !== "object" ||
|
|
298
|
+
!Array.isArray((parsed as { items?: unknown }).items)
|
|
299
|
+
) {
|
|
300
|
+
throw new ChatCliError(
|
|
301
|
+
'Stdin JSON must be {"items":[{"threadId":"...","title":"..."}]}.',
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
const rawItems = (parsed as { items: unknown[] }).items;
|
|
305
|
+
items = rawItems.map((entry, index) => {
|
|
306
|
+
if (
|
|
307
|
+
!entry ||
|
|
308
|
+
typeof entry !== "object" ||
|
|
309
|
+
typeof (entry as { threadId?: unknown }).threadId !== "string" ||
|
|
310
|
+
typeof (entry as { title?: unknown }).title !== "string"
|
|
311
|
+
) {
|
|
312
|
+
throw new ChatCliError(
|
|
313
|
+
`items[${index}] must be { threadId: string, title: string }.`,
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
const item = entry as { threadId: string; title: string };
|
|
317
|
+
if (!item.threadId.trim()) {
|
|
318
|
+
throw new ChatCliError(`items[${index}].threadId is empty.`);
|
|
319
|
+
}
|
|
320
|
+
if (!item.title.trim()) {
|
|
321
|
+
throw new ChatCliError(`items[${index}].title is empty.`);
|
|
322
|
+
}
|
|
323
|
+
return { threadId: item.threadId.trim(), title: item.title };
|
|
324
|
+
});
|
|
325
|
+
} else {
|
|
326
|
+
const threadId = shift(ctx.args, "thread id").trim();
|
|
327
|
+
const titleParts: string[] = [];
|
|
328
|
+
while (ctx.args.length > 0) {
|
|
329
|
+
const next = ctx.args.shift();
|
|
330
|
+
if (next === undefined) break;
|
|
331
|
+
if (next.startsWith("--")) {
|
|
332
|
+
ctx.args.unshift(next);
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
titleParts.push(next);
|
|
336
|
+
}
|
|
337
|
+
const title = titleParts.join(" ").trim();
|
|
338
|
+
if (!title) {
|
|
339
|
+
throw new ChatCliError(
|
|
340
|
+
"Usage: dench chat rename <thread-id> <new-title>",
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
items = [{ threadId, title }];
|
|
344
|
+
}
|
|
345
|
+
if (items.length === 0) {
|
|
346
|
+
throw new ChatCliError("Nothing to rename.");
|
|
347
|
+
}
|
|
348
|
+
if (items.length > 50) {
|
|
349
|
+
throw new ChatCliError(
|
|
350
|
+
`Too many items (${items.length}); the server caps each call at 50.`,
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
out(ctx, await callMutation(ctx, api.renameThreads, { items }));
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
async function promptYesNo(question: string): Promise<boolean> {
|
|
357
|
+
if (!process.stdin.isTTY) return false;
|
|
358
|
+
process.stdout.write(`${question} [y/N] `);
|
|
359
|
+
return new Promise<boolean>((resolve) => {
|
|
360
|
+
const onData = (chunk: Buffer) => {
|
|
361
|
+
const answer = chunk.toString("utf8").trim().toLowerCase();
|
|
362
|
+
cleanup();
|
|
363
|
+
resolve(answer === "y" || answer === "yes");
|
|
364
|
+
};
|
|
365
|
+
const cleanup = () => {
|
|
366
|
+
process.stdin.off("data", onData);
|
|
367
|
+
try {
|
|
368
|
+
process.stdin.pause();
|
|
369
|
+
} catch {
|
|
370
|
+
// ignore: stdin may already be closed.
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
process.stdin.resume();
|
|
374
|
+
process.stdin.once("data", onData);
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
async function runChatDeleteCommand(ctx: ChatCliContext): Promise<void> {
|
|
379
|
+
const idsFlag = getFlag(ctx.args, "--ids");
|
|
380
|
+
const skipConfirm = hasFlag(ctx.args, "--yes") || hasFlag(ctx.args, "-y");
|
|
381
|
+
const collected: string[] = [];
|
|
382
|
+
if (idsFlag) {
|
|
383
|
+
for (const part of idsFlag.split(",")) {
|
|
384
|
+
const trimmed = part.trim();
|
|
385
|
+
if (trimmed) collected.push(trimmed);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
while (ctx.args.length > 0) {
|
|
389
|
+
const next = ctx.args.shift();
|
|
390
|
+
if (next === undefined) break;
|
|
391
|
+
if (next.startsWith("--")) {
|
|
392
|
+
ctx.args.unshift(next);
|
|
393
|
+
break;
|
|
394
|
+
}
|
|
395
|
+
if (next.trim()) collected.push(next.trim());
|
|
396
|
+
}
|
|
397
|
+
const seen = new Set<string>();
|
|
398
|
+
const threadIds = collected.filter((id) => {
|
|
399
|
+
if (seen.has(id)) return false;
|
|
400
|
+
seen.add(id);
|
|
401
|
+
return true;
|
|
402
|
+
});
|
|
403
|
+
if (threadIds.length === 0) {
|
|
404
|
+
throw new ChatCliError(
|
|
405
|
+
"Usage: dench chat delete <thread-id> [<thread-id>...] (or --ids id1,id2,...)",
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
if (threadIds.length > 25) {
|
|
409
|
+
throw new ChatCliError(
|
|
410
|
+
`Too many thread ids (${threadIds.length}); the server caps each call at 25. Run multiple invocations.`,
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
if (!skipConfirm) {
|
|
414
|
+
if (!process.stdin.isTTY) {
|
|
415
|
+
throw new ChatCliError(
|
|
416
|
+
"Refusing to delete without --yes in non-interactive mode (no TTY).",
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
const ok = await promptYesNo(
|
|
420
|
+
`PERMANENTLY delete ${threadIds.length} chat${
|
|
421
|
+
threadIds.length === 1 ? "" : "s"
|
|
422
|
+
} and all their messages?`,
|
|
423
|
+
);
|
|
424
|
+
if (!ok) {
|
|
425
|
+
console.error("Aborted.");
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
out(ctx, await callMutation(ctx, api.deleteThreads, { threadIds }));
|
|
430
|
+
}
|
|
431
|
+
|
|
225
432
|
/**
|
|
226
433
|
* `dench chat tree [<root-thread-id>] [--limit N] [--json]` — print the
|
|
227
434
|
* parent-child chat thread hierarchy rooted at the given thread (or
|
package/cron.ts
CHANGED
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
* Each cron is a row in the Convex `triggers` table that, when due,
|
|
6
6
|
* spawns a fresh chat thread (the `target: "chat_turn"` path — new
|
|
7
7
|
* default) running in YOLO mode and seeded with the cron's prompt as
|
|
8
|
-
* the first user message.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* the first user message. Scheduling is owned by the
|
|
9
|
+
* `@convex-dev/crons` component: each create/update/enable mutation
|
|
10
|
+
* registers a component cron under name=triggerId; the component fires
|
|
11
|
+
* `internal.functions.triggersNode.fireDenchTrigger` at the precise
|
|
12
|
+
* scheduled time, which then POSTs to `/api/runs/spawn-{chat,child}`
|
|
13
|
+
* to start the workflow.
|
|
12
14
|
*
|
|
13
15
|
* Auth: prefers the unified Dench API key from `DENCH_API_KEY`
|
|
14
16
|
* (sandbox envVar baked at create time). Falls back to `dench login`
|
|
@@ -504,6 +506,8 @@ async function runHistory(ctx: CronCliContext): Promise<void> {
|
|
|
504
506
|
|
|
505
507
|
function cronHelp(): void {
|
|
506
508
|
console.log(`Usage: dench cron <subcommand>
|
|
509
|
+
dench routine <subcommand> (alias)
|
|
510
|
+
dench routines <subcommand> (alias)
|
|
507
511
|
|
|
508
512
|
Browse:
|
|
509
513
|
dench cron list [--enabled-only] [--json]
|
package/dench.ts
CHANGED
|
@@ -492,6 +492,10 @@ Past chat threads (own + shared in this workspace):
|
|
|
492
492
|
dench chat list [--query <substr>] [--limit N] [--include-archived] [--json]
|
|
493
493
|
dench chat search "<query>" [--limit N] [--include-current] [--json]
|
|
494
494
|
dench chat read <thread-id> [--limit N] [--json]
|
|
495
|
+
dench chat rename <thread-id> <new-title> [--json]
|
|
496
|
+
dench chat rename --from-stdin [--json] (batch via JSON {items:[...]})
|
|
497
|
+
dench chat delete <thread-id> [<thread-id>...] [--yes] [--json]
|
|
498
|
+
dench chat delete --ids id1,id2 [--yes] [--json] (PERMANENTLY deletes threads)
|
|
495
499
|
|
|
496
500
|
Spawn a new chat-turn workflow (same as the web UI):
|
|
497
501
|
dench chat new "<prompt>" [--model <m>] [--file-context <path>] [--visibility private|shared] [--title T] [--yolo] [--follow] [--json]
|
|
@@ -534,6 +538,20 @@ Subagents (Daytona-native rewrite):
|
|
|
534
538
|
|
|
535
539
|
dench --version
|
|
536
540
|
|
|
541
|
+
Self-updating agent harness (OpenClaw parity):
|
|
542
|
+
dench identity show | edit IDENTITY.md (org-wide)
|
|
543
|
+
dench organisation show | edit ORGANISATION.md
|
|
544
|
+
dench user show | edit USER.md (per-member)
|
|
545
|
+
dench tools show | edit TOOLS.md notes section
|
|
546
|
+
dench mem show | append "<text>" | set MEMORY.md aggregate
|
|
547
|
+
dench heartbeat status | enable | disable
|
|
548
|
+
| interval <30m|1h|…> | instructions
|
|
549
|
+
dench bootstrap status | complete | reopen | template
|
|
550
|
+
dench model default <id|clear>
|
|
551
|
+
dench model thread <threadId> <id|clear>
|
|
552
|
+
dench daily today | show <YYYY-MM-DD>
|
|
553
|
+
Help: dench identity help
|
|
554
|
+
|
|
537
555
|
External tools:
|
|
538
556
|
dench apps is an alias for dench tool status -- it lists connected apps.
|
|
539
557
|
dench tool with no subcommand prints tool help.
|
|
@@ -1794,30 +1812,6 @@ async function getRuntime() {
|
|
|
1794
1812
|
});
|
|
1795
1813
|
}
|
|
1796
1814
|
|
|
1797
|
-
// Sandbox session-mode path: workflow minting provisions a real
|
|
1798
|
-
// dch_agent_* token at sandbox-create time. Prefer it over apiKey so
|
|
1799
|
-
// agentWorkspace.* commands (Composio tools) work inside sandboxes.
|
|
1800
|
-
const sandboxAgentToken = process.env.DENCH_AGENT_SESSION_TOKEN?.trim();
|
|
1801
|
-
const sandboxConvexUrl = resolveApiKeyConvexUrl();
|
|
1802
|
-
if (sandboxAgentToken && sandboxConvexUrl) {
|
|
1803
|
-
const orgId = process.env.DENCH_ORG_ID?.trim();
|
|
1804
|
-
const orgSlug = process.env.DENCH_ORG_SLUG?.trim();
|
|
1805
|
-
const apiHost =
|
|
1806
|
-
process.env.DENCH_API_URL?.trim() ||
|
|
1807
|
-
process.env.DENCH_INTERNAL_BASE?.trim() ||
|
|
1808
|
-
host;
|
|
1809
|
-
return {
|
|
1810
|
-
mode: "session" as const,
|
|
1811
|
-
host: apiHost,
|
|
1812
|
-
client: new ConvexHttpClient(sandboxConvexUrl),
|
|
1813
|
-
sessionToken: sandboxAgentToken,
|
|
1814
|
-
organization:
|
|
1815
|
-
orgId && orgSlug
|
|
1816
|
-
? { id: orgId, name: orgSlug, slug: orgSlug }
|
|
1817
|
-
: undefined,
|
|
1818
|
-
};
|
|
1819
|
-
}
|
|
1820
|
-
|
|
1821
1815
|
// Sandbox / automation path: the unified Dench API key + Convex URL
|
|
1822
1816
|
// baked into sandbox envVars (see
|
|
1823
1817
|
// src/lib/secrets/sandbox-tokens.ts) is enough to drive every
|
|
@@ -3713,8 +3707,11 @@ async function main() {
|
|
|
3713
3707
|
return;
|
|
3714
3708
|
}
|
|
3715
3709
|
|
|
3716
|
-
|
|
3717
|
-
|
|
3710
|
+
// `dench routine` / `dench routines` are UI-friendly aliases for
|
|
3711
|
+
// `dench cron`. Same dispatch, same auth, same handler — only the
|
|
3712
|
+
// top-level command name differs to match the workspace UI rename.
|
|
3713
|
+
if (command === "cron" || command === "routine" || command === "routines") {
|
|
3714
|
+
const subArgs = args.slice(args.indexOf(command) + 1);
|
|
3718
3715
|
const sub = subArgs[0];
|
|
3719
3716
|
// Help is a no-auth path so users can read the surface without a
|
|
3720
3717
|
// session — mirrors `dench crm help`.
|
|
@@ -3733,7 +3730,10 @@ async function main() {
|
|
|
3733
3730
|
// bearer prefix and resolves the org for both. The Bearer token
|
|
3734
3731
|
// must carry `crons:read` (queries) or `crons:write` (mutations)
|
|
3735
3732
|
// scope, or the wildcard `*`.
|
|
3736
|
-
const authedRuntime = requireAuthenticatedRuntime(
|
|
3733
|
+
const authedRuntime = requireAuthenticatedRuntime(
|
|
3734
|
+
runtime,
|
|
3735
|
+
`dench ${command}`,
|
|
3736
|
+
);
|
|
3737
3737
|
await runCronCommand({
|
|
3738
3738
|
convex: authedRuntime.client,
|
|
3739
3739
|
args: subArgs,
|
|
@@ -3742,6 +3742,85 @@ async function main() {
|
|
|
3742
3742
|
return;
|
|
3743
3743
|
}
|
|
3744
3744
|
|
|
3745
|
+
// ── OpenClaw-parity self-update CLI surface ──────────────────────────
|
|
3746
|
+
//
|
|
3747
|
+
// Dispatch all `dench identity / organisation / user / tools / mem /
|
|
3748
|
+
// heartbeat / bootstrap / model / daily` traffic through the shared
|
|
3749
|
+
// agent-config CLI module. Each command requires the same auth shape
|
|
3750
|
+
// as `dench cron` (Bearer DENCH_API_KEY or `dench login` session
|
|
3751
|
+
// token) so server-side `requireCronAccess` accepts both.
|
|
3752
|
+
const AGENT_CONFIG_COMMANDS = new Set([
|
|
3753
|
+
"identity",
|
|
3754
|
+
"organisation",
|
|
3755
|
+
"user",
|
|
3756
|
+
"tools",
|
|
3757
|
+
"mem",
|
|
3758
|
+
"heartbeat",
|
|
3759
|
+
"bootstrap",
|
|
3760
|
+
"model",
|
|
3761
|
+
"daily",
|
|
3762
|
+
]);
|
|
3763
|
+
if (AGENT_CONFIG_COMMANDS.has(command)) {
|
|
3764
|
+
const subArgs = args.slice(args.indexOf(command) + 1);
|
|
3765
|
+
if (
|
|
3766
|
+
subArgs[0] === "help" ||
|
|
3767
|
+
subArgs.includes("--help") ||
|
|
3768
|
+
subArgs.includes("-h")
|
|
3769
|
+
) {
|
|
3770
|
+
const { printAgentConfigCliHelp } = await import("./agent-config");
|
|
3771
|
+
printAgentConfigCliHelp();
|
|
3772
|
+
return;
|
|
3773
|
+
}
|
|
3774
|
+
const runtime = await getRuntime();
|
|
3775
|
+
const authedRuntime = requireAuthenticatedRuntime(
|
|
3776
|
+
runtime,
|
|
3777
|
+
`dench ${command}`,
|
|
3778
|
+
);
|
|
3779
|
+
const ctxBase = {
|
|
3780
|
+
convex: authedRuntime.client,
|
|
3781
|
+
args: subArgs,
|
|
3782
|
+
jsonOutput: json,
|
|
3783
|
+
sessionToken: authedRuntime.sessionToken,
|
|
3784
|
+
};
|
|
3785
|
+
const mod = await import("./agent-config");
|
|
3786
|
+
if (command === "identity") {
|
|
3787
|
+
await mod.runIdentityCommand(ctxBase);
|
|
3788
|
+
return;
|
|
3789
|
+
}
|
|
3790
|
+
if (command === "organisation") {
|
|
3791
|
+
await mod.runOrganisationCommand(ctxBase);
|
|
3792
|
+
return;
|
|
3793
|
+
}
|
|
3794
|
+
if (command === "user") {
|
|
3795
|
+
await mod.runUserCommand(ctxBase);
|
|
3796
|
+
return;
|
|
3797
|
+
}
|
|
3798
|
+
if (command === "tools") {
|
|
3799
|
+
await mod.runToolsCommand(ctxBase);
|
|
3800
|
+
return;
|
|
3801
|
+
}
|
|
3802
|
+
if (command === "mem") {
|
|
3803
|
+
await mod.runMemoryAggregateCommand(ctxBase);
|
|
3804
|
+
return;
|
|
3805
|
+
}
|
|
3806
|
+
if (command === "heartbeat") {
|
|
3807
|
+
await mod.runHeartbeatCommand(ctxBase);
|
|
3808
|
+
return;
|
|
3809
|
+
}
|
|
3810
|
+
if (command === "bootstrap") {
|
|
3811
|
+
await mod.runBootstrapCommand(ctxBase);
|
|
3812
|
+
return;
|
|
3813
|
+
}
|
|
3814
|
+
if (command === "model") {
|
|
3815
|
+
await mod.runModelCommand(ctxBase);
|
|
3816
|
+
return;
|
|
3817
|
+
}
|
|
3818
|
+
if (command === "daily") {
|
|
3819
|
+
await mod.runDailyCommand(ctxBase);
|
|
3820
|
+
return;
|
|
3821
|
+
}
|
|
3822
|
+
}
|
|
3823
|
+
|
|
3745
3824
|
if (command === "login") {
|
|
3746
3825
|
await login();
|
|
3747
3826
|
return;
|