@monster-orange/den 0.4.7 → 0.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +174 -0
- package/README.md +7 -7
- package/docs/distributions.md +243 -1
- package/package.json +1 -1
- package/schemas/den.plugin.v1.json +3 -2
- package/src/shared/agents/den-claude.ts +57 -3
- package/src/shared/agents/guardrails/hooks.json +23 -0
- package/src/shared/agents/guardrails/instructions.md +23 -0
- package/src/shared/agents/guardrails/rotation-hook.ts +127 -0
- package/src/shared/agents/guardrails/stop-hook.ts +48 -2
- package/src/shared/agents/guardrails.ts +38 -7
- package/src/shared/agents/handoff.ts +118 -0
- package/src/shared/agents/personas.ts +11 -1
- package/src/shared/agents/records.ts +122 -1
- package/src/shared/agents/rotation.ts +362 -0
- package/src/shared/agents/runtime.ts +27 -0
- package/src/shared/den-config.ts +72 -1
- package/src/shared/git/gh-pr-state.ts +32 -0
- package/src/shared/plugins/manifest.ts +3 -0
- package/src/shared/usage/paths.ts +16 -0
- package/src/shared/usage/report.ts +377 -0
- package/src/shared/usage/sources.ts +127 -0
- package/src/shared/usage/transcript.ts +319 -0
- package/src/ui/cli/agent-ops.ts +678 -51
- package/src/ui/cli/agents-command.ts +192 -22
- package/src/ui/cli/index.ts +13 -1
- package/src/ui/cli/usage-command.ts +323 -0
- package/src/ui/mcp/api.ts +10 -1
- package/src/ui/mcp/server.ts +34 -0
- package/src/ui/mcp/tools.ts +50 -0
- package/src/ui/server/agent-resume-grant.ts +53 -0
- package/src/ui/server/agent-routes.ts +247 -9
- package/src/ui/server/audit.ts +68 -1
- package/src/ui/server/index.ts +16 -5
- package/src/ui/server/public/agents-page.js +400 -13
- package/src/ui/server/public/agents-section.js +17 -3
- package/src/ui/server/public/agents.html +44 -0
- package/src/ui/server/public/i18n/es.js +40 -0
- package/src/ui/server/public/i18n/ja.js +36 -0
- package/src/ui/server/public/shell.js +79 -0
- package/src/ui/server/request-guard.ts +21 -1
- package/src/ui/server/route-classes.ts +29 -0
- package/src/ui/server/session-routes.ts +60 -5
- package/src/ui/server/sudo-store.ts +36 -7
|
@@ -20,10 +20,17 @@
|
|
|
20
20
|
* persona, runtime and model; a record whose session is gone is
|
|
21
21
|
* listed as stopped or ended. A plain session is not an agent.
|
|
22
22
|
* stop ends its session (TERM) and marks the record stopped.
|
|
23
|
-
* resume only when its runtime declares resume
|
|
24
|
-
*
|
|
23
|
+
* resume only when its runtime declares resume, its record holds the
|
|
24
|
+
* runtime's resume token, and its session is not running: a new
|
|
25
|
+
* session, in the same cwd and workspace with the grants it had,
|
|
26
|
+
* continuing the last conversation (den-claude: --resume <token>);
|
|
25
27
|
* when that session was never prompted, a fresh start under the
|
|
26
28
|
* same conversation id (there is nothing to continue).
|
|
29
|
+
* --all-interrupted (AG-14.3): every agent interrupted when Den or
|
|
30
|
+
* the machine restarted that can resume.
|
|
31
|
+
* rm (AG-14.1b) forgets a stopped, interrupted or exited agent (never
|
|
32
|
+
* a running one); --stopped forgets every one of -w <ws> (or of
|
|
33
|
+
* every workspace). The runtime's own history stays.
|
|
27
34
|
* doctor (AG-0.3, AG-0.5) each runtime of the catalog, installed
|
|
28
35
|
* first: its status, the CLI it runs and where that came from
|
|
29
36
|
* (workspace or user.yml setting, login shell, PATH, install
|
|
@@ -36,6 +43,14 @@
|
|
|
36
43
|
* handback-check <file|-> (den#5) the hand-back check (handback.ts) on a
|
|
37
44
|
* file or stdin: each problem on its own line, exit 1 when there
|
|
38
45
|
* is one, 0 when the hand-back is complete and plain.
|
|
46
|
+
* relaunch (den#4, session rotation) once an agent's session rotated
|
|
47
|
+
* (after agents.rotate.after_compactions compactions, or its pull
|
|
48
|
+
* request merged) and its handoff.md passes the check: a fresh
|
|
49
|
+
* conversation, same persona, workspace, folder and grants, whose
|
|
50
|
+
* first prompt is the handoff. `resume` on a rotated agent
|
|
51
|
+
* refuses (exit 1) and names relaunch.
|
|
52
|
+
* handoff-check <id|file|-> (den#4) the handoff check (handoff.ts), like
|
|
53
|
+
* handback-check.
|
|
39
54
|
*
|
|
40
55
|
* Nothing here takes a grant: grants come from the org config only. The
|
|
41
56
|
* host enforces agents.max_concurrent on every start, counting agents only.
|
|
@@ -45,14 +60,25 @@ import { DEFAULT_RUNTIME_ID } from "../../shared/agents/runtimes.js";
|
|
|
45
60
|
import { initLoginPath } from "../../shared/agents/runtime-search.js";
|
|
46
61
|
import { HostError } from "../../shared/sessions/client.js";
|
|
47
62
|
import { checkHandback } from "../../shared/agents/handback.js";
|
|
63
|
+
import { checkHandoff } from "../../shared/agents/handoff.js";
|
|
64
|
+
import { handoffFile, reasonText } from "../../shared/agents/rotation.js";
|
|
65
|
+
import {
|
|
66
|
+
agentFilesDir,
|
|
67
|
+
listRecords,
|
|
68
|
+
readRecord,
|
|
69
|
+
} from "../../shared/agents/records.js";
|
|
48
70
|
import {
|
|
49
71
|
AgentError,
|
|
50
72
|
listAgents,
|
|
51
73
|
listPersonas as personaList,
|
|
52
74
|
listRuntimes,
|
|
53
75
|
loadAgentWorkspaces,
|
|
76
|
+
relaunchAgent,
|
|
77
|
+
removeAgent,
|
|
78
|
+
removeStopped,
|
|
54
79
|
resolveAgentsDeps,
|
|
55
80
|
resumeAgent,
|
|
81
|
+
resumeInterrupted,
|
|
56
82
|
startAgent,
|
|
57
83
|
stopAgent,
|
|
58
84
|
type AgentsDeps,
|
|
@@ -80,19 +106,37 @@ export {
|
|
|
80
106
|
} from "./agent-ops.js";
|
|
81
107
|
|
|
82
108
|
export const AGENTS_HELP = {
|
|
83
|
-
usage:
|
|
109
|
+
usage:
|
|
110
|
+
"agents <list|start|stop|resume|relaunch|rm|personas|doctor|handback-check|handoff-check> ...",
|
|
84
111
|
lines: [
|
|
85
112
|
"Agents: a persona and a workspace, run by a runtime in a session that",
|
|
86
113
|
"outlives the web server (see `{cli} sessions`).",
|
|
87
114
|
"",
|
|
88
|
-
"{cli} agents list -w <ws> [--json]",
|
|
115
|
+
"{cli} agents list -w <ws> [--stopped] [--json]",
|
|
116
|
+
" --stopped: only the stopped, interrupted and exited ones",
|
|
89
117
|
"{cli} agents start -w <ws> --persona <p> [--runtime <r>] [--model <m>] [--id <id>]",
|
|
90
118
|
" runs in the workspace's dir as <dist>-<ws>:<id>; its MCP is pinned to <ws>",
|
|
91
119
|
" (plus agents.<id>.grants); capped by agents.max_concurrent",
|
|
92
|
-
"{cli} agents stop <id> [-w <ws>]",
|
|
120
|
+
"{cli} agents stop <id> [-w <ws>] [--no-wait]",
|
|
121
|
+
" waits up to 5 s for the session to end (else: still stopping, exit 1);",
|
|
122
|
+
" --no-wait: return once TERM is sent",
|
|
93
123
|
"{cli} agents resume <id> [-w <ws>]",
|
|
94
|
-
"
|
|
95
|
-
"
|
|
124
|
+
"{cli} agents resume --all-interrupted [-w <ws>]",
|
|
125
|
+
" the same conversation, persona, workspace and folder, when its runtime",
|
|
126
|
+
" can resume one and its session has ended; with nothing to resume yet,",
|
|
127
|
+
" it starts fresh under the same conversation id. --all-interrupted: every",
|
|
128
|
+
" agent interrupted when Den or the machine restarted. A rotated agent",
|
|
129
|
+
" is not resumed: relaunch it",
|
|
130
|
+
"{cli} agents relaunch <id> [-w <ws>]",
|
|
131
|
+
" session rotation: once a session ended after agents.rotate.after_compactions",
|
|
132
|
+
" compactions (default 3) or its pull request merged, and its handoff.md",
|
|
133
|
+
" passes the check, a fresh conversation (same persona, workspace, folder,",
|
|
134
|
+
" grants) whose first prompt is the handoff",
|
|
135
|
+
"{cli} agents rm <id> [-w <ws>]",
|
|
136
|
+
"{cli} agents rm --stopped [-w <ws>]",
|
|
137
|
+
" forget a stopped, interrupted or exited agent (never a running one);",
|
|
138
|
+
" the runtime keeps its own history. agents.remove_stopped_after in",
|
|
139
|
+
" user.yml (never, 1d, 7d) forgets stopped ones on its own",
|
|
96
140
|
"{cli} agents personas [--json]",
|
|
97
141
|
" Den's default pack, then agents.persona_packs (a later pack wins by id)",
|
|
98
142
|
"{cli} agents doctor [-w <ws>] [--json]",
|
|
@@ -103,6 +147,10 @@ export const AGENTS_HELP = {
|
|
|
103
147
|
" checks a hand-back to a person: URL, machine, branch, what changed, what",
|
|
104
148
|
" to click and decisions are all there, every ID is explained, and each",
|
|
105
149
|
" decision is a numbered yes/no question; exit 1 with what to fix",
|
|
150
|
+
"{cli} agents handoff-check <id|file|-> [--json]",
|
|
151
|
+
" checks an agent's handoff.md (or a file, or stdin): Objective, State, Open items, How to QA and Next step",
|
|
152
|
+
" are all there and filled in, and every ID is explained; exit 1 with what",
|
|
153
|
+
" to fix",
|
|
106
154
|
"",
|
|
107
155
|
"Runtimes: den-claude (default; Claude Code's claude), codex (OpenAI's Codex",
|
|
108
156
|
"CLI), gemini (Google's Gemini CLI), grok (xAI's Grok Build), and generic (the",
|
|
@@ -120,17 +168,27 @@ export const AGENTS_HELP = {
|
|
|
120
168
|
|
|
121
169
|
async function list(args: string[], d: AgentsResolved): Promise<number> {
|
|
122
170
|
const where = "agents list";
|
|
123
|
-
const p = parseArgs(where, args, {
|
|
171
|
+
const p = parseArgs(where, args, {
|
|
172
|
+
"--workspace": true,
|
|
173
|
+
"--json": false,
|
|
174
|
+
"--stopped": false,
|
|
175
|
+
});
|
|
124
176
|
noExtra(where, p);
|
|
125
177
|
const ws = workspaceFlag(where, p);
|
|
126
178
|
if (!ws) throw new UsageError(`${where} needs -w <workspace>`);
|
|
127
|
-
const rows = await listAgents(d, ws
|
|
179
|
+
const rows = await listAgents(d, ws, {
|
|
180
|
+
stopped: p.flags["--stopped"] === true,
|
|
181
|
+
});
|
|
128
182
|
if (p.flags["--json"]) {
|
|
129
183
|
d.out(JSON.stringify(rows, null, 2));
|
|
130
184
|
return 0;
|
|
131
185
|
}
|
|
132
186
|
if (!rows.length) {
|
|
133
|
-
d.out(
|
|
187
|
+
d.out(
|
|
188
|
+
p.flags["--stopped"]
|
|
189
|
+
? `no stopped agents in ${ws}`
|
|
190
|
+
: `no agents in ${ws}`,
|
|
191
|
+
);
|
|
134
192
|
return 0;
|
|
135
193
|
}
|
|
136
194
|
for (const l of columns([
|
|
@@ -148,7 +206,9 @@ async function list(args: string[], d: AgentsResolved): Promise<number> {
|
|
|
148
206
|
r.agent,
|
|
149
207
|
r.persona ?? "-",
|
|
150
208
|
r.runtime ?? "-",
|
|
151
|
-
r.
|
|
209
|
+
r.rotation?.due
|
|
210
|
+
? `${r.state}, ${r.rotation.ready ? "ready to relaunch" : "handoff due"} (${reasonText(r.rotation.due, r.rotation.compactions)})`
|
|
211
|
+
: r.state,
|
|
152
212
|
r.model ?? "-",
|
|
153
213
|
r.session && !r.session.exited ? String(r.session.pid) : "-",
|
|
154
214
|
r.session?.startedAt ?? "-",
|
|
@@ -232,22 +292,40 @@ function idAndWorkspace(
|
|
|
232
292
|
}
|
|
233
293
|
|
|
234
294
|
async function stop(args: string[], d: AgentsResolved): Promise<number> {
|
|
235
|
-
|
|
236
|
-
const
|
|
295
|
+
// --no-wait: return once TERM is sent (before 0.4.8, always).
|
|
296
|
+
const wait = !args.includes("--no-wait");
|
|
297
|
+
const { id, ws } = idAndWorkspace(
|
|
298
|
+
"agents stop",
|
|
299
|
+
args.filter((a) => a !== "--no-wait"),
|
|
300
|
+
);
|
|
301
|
+
const {
|
|
302
|
+
rec,
|
|
303
|
+
session: s,
|
|
304
|
+
stillStopping,
|
|
305
|
+
} = await stopAgent(d, id, ws, {
|
|
306
|
+
wait,
|
|
307
|
+
});
|
|
308
|
+
if (stillStopping) {
|
|
309
|
+
d.err(
|
|
310
|
+
`${rec.id} is still stopping (sent TERM to ${s!.name}, pid ${s!.pid}; not ended after ${d.stopWaitMs / 1000} s)`,
|
|
311
|
+
);
|
|
312
|
+
return 1;
|
|
313
|
+
}
|
|
237
314
|
d.out(
|
|
238
315
|
s
|
|
239
|
-
? `stopped agent ${rec.id} (sent TERM to ${s.name}, pid ${s.pid})`
|
|
316
|
+
? `stopped agent ${rec.id} (sent TERM to ${s.name}, pid ${s.pid}${wait && d.stopWaitMs > 0 ? "; it has ended" : ""})`
|
|
240
317
|
: `agent ${rec.id} was not running; marked stopped`,
|
|
241
318
|
);
|
|
242
319
|
return 0;
|
|
243
320
|
}
|
|
244
321
|
|
|
245
322
|
async function resume(args: string[], d: AgentsResolved): Promise<number> {
|
|
323
|
+
if (args.includes("--all-interrupted")) return resumeAll(args, d);
|
|
246
324
|
const { id, ws } = idAndWorkspace("agents resume", args);
|
|
247
325
|
const s = await resumeAgent(d, id, ws);
|
|
248
326
|
if (s.fresh)
|
|
249
327
|
d.out(
|
|
250
|
-
`agent ${s.rec.id}:
|
|
328
|
+
`agent ${s.rec.id}: nothing to resume yet; started fresh (same conversation id, folder and scope)`,
|
|
251
329
|
);
|
|
252
330
|
return report(
|
|
253
331
|
d,
|
|
@@ -256,6 +334,69 @@ async function resume(args: string[], d: AgentsResolved): Promise<number> {
|
|
|
256
334
|
);
|
|
257
335
|
}
|
|
258
336
|
|
|
337
|
+
/** `agents relaunch <id> [-w <ws>]` (den#4). */
|
|
338
|
+
async function relaunch(args: string[], d: AgentsResolved): Promise<number> {
|
|
339
|
+
const { id, ws } = idAndWorkspace("agents relaunch", args);
|
|
340
|
+
const s = await relaunchAgent(d, id, ws);
|
|
341
|
+
return report(
|
|
342
|
+
d,
|
|
343
|
+
s,
|
|
344
|
+
`relaunched agent ${s.rec.id} from its handoff (the last session ended after ${s.why}) as ${s.rec.sessionName} in ${s.rec.cwd}`,
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** `agents resume --all-interrupted [-w <ws>]` (AG-14.3). */
|
|
349
|
+
async function resumeAll(args: string[], d: AgentsResolved): Promise<number> {
|
|
350
|
+
const where = "agents resume";
|
|
351
|
+
const p = parseArgs(where, args, {
|
|
352
|
+
"--workspace": true,
|
|
353
|
+
"--all-interrupted": false,
|
|
354
|
+
});
|
|
355
|
+
noExtra(where, p);
|
|
356
|
+
const ws = workspaceFlag(where, p);
|
|
357
|
+
const r = await resumeInterrupted(d, ws ? [ws] : undefined);
|
|
358
|
+
if (!r.resumed.length && !r.failed.length) {
|
|
359
|
+
d.out(`no interrupted agents${ws ? ` in ${ws}` : ""}`);
|
|
360
|
+
return 0;
|
|
361
|
+
}
|
|
362
|
+
for (const x of r.resumed)
|
|
363
|
+
d.out(
|
|
364
|
+
`${x.fresh ? "started" : "resumed"} agent ${x.rec.id} as ${x.rec.sessionName} in ${x.rec.cwd}`,
|
|
365
|
+
);
|
|
366
|
+
for (const f of r.failed) d.err(`✗ agent ${f.agent}: ${f.why}`);
|
|
367
|
+
return r.failed.length ? 1 : 0;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/** `agents rm <id> [-w <ws>]`, `agents rm --stopped [-w <ws>]` (AG-14.1b). */
|
|
371
|
+
async function rm(args: string[], d: AgentsResolved): Promise<number> {
|
|
372
|
+
const where = "agents rm";
|
|
373
|
+
const p = parseArgs(where, args, { "--workspace": true, "--stopped": false });
|
|
374
|
+
noExtra(where, p, 1);
|
|
375
|
+
const ws = workspaceFlag(where, p);
|
|
376
|
+
const id = p.positional[0];
|
|
377
|
+
if (p.flags["--stopped"]) {
|
|
378
|
+
if (id) throw new UsageError(`${where}: give <id> or --stopped, not both`);
|
|
379
|
+
if (ws && !d.workspaceExists(ws))
|
|
380
|
+
throw new UsageError(`${where}: workspace "${ws}" does not exist`);
|
|
381
|
+
const wss = ws
|
|
382
|
+
? [ws]
|
|
383
|
+
: [...new Set(listRecords(d.stateDir()).map((r) => r.workspace))];
|
|
384
|
+
const gone = await removeStopped(d, wss);
|
|
385
|
+
d.out(
|
|
386
|
+
gone.length
|
|
387
|
+
? `removed ${gone.length} stopped ${gone.length === 1 ? "agent" : "agents"}: ${gone.map((g) => g.agent).join(", ")}`
|
|
388
|
+
: `no stopped agents${ws ? ` in ${ws}` : ""}`,
|
|
389
|
+
);
|
|
390
|
+
return 0;
|
|
391
|
+
}
|
|
392
|
+
if (!id) throw new UsageError(`${where} needs <id> or --stopped`);
|
|
393
|
+
const [gone] = await removeAgent(d, id, ws);
|
|
394
|
+
d.out(
|
|
395
|
+
`removed agent ${gone?.agent ?? id}; its conversation stays in the runtime's own history`,
|
|
396
|
+
);
|
|
397
|
+
return 0;
|
|
398
|
+
}
|
|
399
|
+
|
|
259
400
|
async function listPersonas(
|
|
260
401
|
args: string[],
|
|
261
402
|
d: AgentsResolved,
|
|
@@ -296,17 +437,37 @@ async function readFileOrStdin(src: string): Promise<string> {
|
|
|
296
437
|
return text;
|
|
297
438
|
}
|
|
298
439
|
|
|
299
|
-
/** `agents handback-check <file|-> [--json]
|
|
440
|
+
/** `agents handback-check <file|-> [--json]`, or handoff-check (den#4). */
|
|
300
441
|
async function handbackCheck(
|
|
301
442
|
args: string[],
|
|
302
443
|
d: AgentsResolved,
|
|
303
444
|
deps: AgentsDoctorDeps,
|
|
445
|
+
kind: "handback" | "handoff" = "handback",
|
|
304
446
|
): Promise<number> {
|
|
305
|
-
const where =
|
|
447
|
+
const where = `agents ${kind}-check`;
|
|
306
448
|
const p = parseArgs(where, args, { "--json": false });
|
|
307
449
|
if (p.positional.length !== 1 || p.rest)
|
|
308
|
-
throw new UsageError(
|
|
309
|
-
|
|
450
|
+
throw new UsageError(
|
|
451
|
+
kind === "handoff"
|
|
452
|
+
? `${where} takes an agent id, a file, or - for stdin`
|
|
453
|
+
: `${where} takes one file, or - for stdin`,
|
|
454
|
+
);
|
|
455
|
+
let src = p.positional[0];
|
|
456
|
+
// handoff-check <id>: that agent's handoff.md, when no such file is here.
|
|
457
|
+
if (
|
|
458
|
+
kind === "handoff" &&
|
|
459
|
+
src !== "-" &&
|
|
460
|
+
!fs.existsSync(src) &&
|
|
461
|
+
/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(src) &&
|
|
462
|
+
readRecord(d.stateDir(), src)
|
|
463
|
+
) {
|
|
464
|
+
const file = handoffFile(agentFilesDir(d.stateDir(), src));
|
|
465
|
+
if (!fs.existsSync(file)) {
|
|
466
|
+
d.err(`✗ ${where}: no handoff.md yet for agent ${src} (${file})`);
|
|
467
|
+
return 1;
|
|
468
|
+
}
|
|
469
|
+
src = file;
|
|
470
|
+
}
|
|
310
471
|
let text: string;
|
|
311
472
|
try {
|
|
312
473
|
text = await (deps.readHandback ?? readFileOrStdin)(src);
|
|
@@ -316,11 +477,12 @@ async function handbackCheck(
|
|
|
316
477
|
);
|
|
317
478
|
return 1;
|
|
318
479
|
}
|
|
319
|
-
const r = checkHandback(text);
|
|
480
|
+
const r = kind === "handoff" ? checkHandoff(text) : checkHandback(text);
|
|
481
|
+
const what = kind === "handoff" ? "handoff" : "hand-back";
|
|
320
482
|
if (p.flags["--json"]) d.out(JSON.stringify(r, null, 2));
|
|
321
|
-
else if (r.ok) d.out(
|
|
483
|
+
else if (r.ok) d.out(`✓ the ${what} is complete and plain`);
|
|
322
484
|
else {
|
|
323
|
-
d.out(
|
|
485
|
+
d.out(`✗ the ${what} is not ready:`);
|
|
324
486
|
for (const l of r.problems) d.out(` - ${l}`);
|
|
325
487
|
}
|
|
326
488
|
return r.ok ? 0 : 1;
|
|
@@ -441,6 +603,12 @@ export async function cmdAgents(
|
|
|
441
603
|
case "resume":
|
|
442
604
|
await loadAgentWorkspaces(deps);
|
|
443
605
|
return await resume(rest, d);
|
|
606
|
+
case "relaunch":
|
|
607
|
+
await loadAgentWorkspaces(deps);
|
|
608
|
+
return await relaunch(rest, d);
|
|
609
|
+
case "rm":
|
|
610
|
+
await loadAgentWorkspaces(deps);
|
|
611
|
+
return await rm(rest, d);
|
|
444
612
|
case "personas":
|
|
445
613
|
return await listPersonas(rest, d);
|
|
446
614
|
case "doctor":
|
|
@@ -449,6 +617,8 @@ export async function cmdAgents(
|
|
|
449
617
|
return await doctor(rest, d, deps);
|
|
450
618
|
case "handback-check":
|
|
451
619
|
return await handbackCheck(rest, d, deps);
|
|
620
|
+
case "handoff-check":
|
|
621
|
+
return await handbackCheck(rest, d, deps, "handoff");
|
|
452
622
|
default:
|
|
453
623
|
throw new UsageError(`unknown agents command "${sub}"`);
|
|
454
624
|
}
|
package/src/ui/cli/index.ts
CHANGED
|
@@ -196,6 +196,7 @@ import { cmdEdge } from "./edge-command.js";
|
|
|
196
196
|
import { cmdDoctor } from "./doctor-command.js";
|
|
197
197
|
import { cmdSessions, SESSIONS_HELP } from "./sessions-command.js";
|
|
198
198
|
import { AGENTS_HELP, cmdAgents } from "./agents-command.js";
|
|
199
|
+
import { USAGE_HELP, cmdUsage } from "./usage-command.js";
|
|
199
200
|
import { cmdService } from "./service-command.js";
|
|
200
201
|
import { cmdStack } from "./stack-command.js";
|
|
201
202
|
import { cmdTheme } from "./theme-command.js";
|
|
@@ -536,6 +537,7 @@ const COMMAND_HELP: Record<string, { usage: string; lines: string[] }> = {
|
|
|
536
537
|
},
|
|
537
538
|
sessions: SESSIONS_HELP,
|
|
538
539
|
agents: AGENTS_HELP,
|
|
540
|
+
usage: USAGE_HELP,
|
|
539
541
|
};
|
|
540
542
|
|
|
541
543
|
function resolveCliBaseApiUrl(explicitBaseApiUrl?: string): string | undefined {
|
|
@@ -588,6 +590,7 @@ const TELEMETRY_COMMANDS = new Set<string>([
|
|
|
588
590
|
"mcp",
|
|
589
591
|
"sessions",
|
|
590
592
|
"agents",
|
|
593
|
+
"usage",
|
|
591
594
|
"service",
|
|
592
595
|
"theme",
|
|
593
596
|
"plugin",
|
|
@@ -616,6 +619,8 @@ const CONFIG_FREE_COMMANDS = new Set<string>([
|
|
|
616
619
|
// listing a session is never stranded by a config that fails (AG-3a).
|
|
617
620
|
"sessions",
|
|
618
621
|
"agents",
|
|
622
|
+
// den#6: reads local transcripts and agent records, no org data.
|
|
623
|
+
"usage",
|
|
619
624
|
]);
|
|
620
625
|
|
|
621
626
|
function configCheckedCommand(command: string): boolean {
|
|
@@ -1082,6 +1087,10 @@ class DenCLI {
|
|
|
1082
1087
|
process.exitCode = await cmdAgents(args.slice(1));
|
|
1083
1088
|
break;
|
|
1084
1089
|
|
|
1090
|
+
case "usage":
|
|
1091
|
+
process.exitCode = await cmdUsage(args.slice(1));
|
|
1092
|
+
break;
|
|
1093
|
+
|
|
1085
1094
|
case "mcp": {
|
|
1086
1095
|
// Setup subcommands: register the server with agents.
|
|
1087
1096
|
const { MCP_CONNECT_SUBCOMMANDS, runMcpConnect } =
|
|
@@ -5298,7 +5307,10 @@ class DenCLI {
|
|
|
5298
5307
|
);
|
|
5299
5308
|
console.log(" agents list -w <ws> The workspace's agents");
|
|
5300
5309
|
console.log(
|
|
5301
|
-
" agents start -w <ws> --persona <p> Run a persona in the workspace (stop, resume, personas)",
|
|
5310
|
+
" agents start -w <ws> --persona <p> Run a persona in the workspace (stop, resume, rm, personas)",
|
|
5311
|
+
);
|
|
5312
|
+
console.log(
|
|
5313
|
+
" usage agents|report Agents' tokens and outcomes, from local transcripts (never sent)",
|
|
5302
5314
|
);
|
|
5303
5315
|
console.log();
|
|
5304
5316
|
console.log(
|