@dench.com/cli 2.0.1 → 2.0.2
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/README.md +33 -27
- package/dench.ts +21 -393
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,17 +4,21 @@ Agent-facing CLI for the Dench agent workspace.
|
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
7
|
-
Run without installing
|
|
7
|
+
Run without installing. The npm package is `@dench.com/cli`, but the binary
|
|
8
|
+
it installs is named `dench`, so always invoke it as
|
|
9
|
+
`npx -y -p @dench.com/cli dench <command>`. A bare
|
|
10
|
+
`npx -y @dench.com/cli <command>` will fail because `npx` looks for a bin
|
|
11
|
+
matching the package's last path segment (`cli`) and there isn't one.
|
|
8
12
|
|
|
9
13
|
```bash
|
|
10
|
-
npx -y @dench.com/cli
|
|
14
|
+
npx -y -p @dench.com/cli dench signin --name "AI Agent - Billing Repo"
|
|
11
15
|
```
|
|
12
16
|
|
|
13
17
|
Or install globally:
|
|
14
18
|
|
|
15
19
|
```bash
|
|
16
20
|
npm install -g @dench.com/cli
|
|
17
|
-
dench
|
|
21
|
+
dench signin --name "AI Agent - Billing Repo"
|
|
18
22
|
```
|
|
19
23
|
|
|
20
24
|
`--kind` accepts any string. Suggested values: `claude_code`, `codex`, `cursor`,
|
|
@@ -47,11 +51,13 @@ DENCH_HOST=https://example.com dench <cmd>
|
|
|
47
51
|
|
|
48
52
|
The smooth setup flow is:
|
|
49
53
|
|
|
50
|
-
1. Run `dench
|
|
54
|
+
1. Run `dench signin --name "AI Agent - Billing Repo"` once.
|
|
51
55
|
2. Let the CLI open the approval link. If it cannot, ask the human to open the
|
|
52
56
|
printed link and confirm the email/workspace. Use `--no-open` to print the
|
|
53
57
|
link without opening it.
|
|
54
|
-
3. Run `dench status --mine --json` and `dench
|
|
58
|
+
3. Run `dench status --mine --json` and `dench crm entries list task --json`
|
|
59
|
+
to verify setup. Tasks live as CRM `task` entries — there is no separate
|
|
60
|
+
`dench tasks` command.
|
|
55
61
|
|
|
56
62
|
The CLI selects the approved session for later commands automatically.
|
|
57
63
|
Setup is complete after approval, both verification commands work, and you know
|
|
@@ -71,11 +77,11 @@ dench sessions
|
|
|
71
77
|
dench use <session-key-or-workspace-slug>
|
|
72
78
|
```
|
|
73
79
|
|
|
74
|
-
Use a human-readable `DENCH_SESSION_KEY` at
|
|
80
|
+
Use a human-readable `DENCH_SESSION_KEY` at sign-in time only for long-lived
|
|
75
81
|
agents or when the human asks for a stable identity:
|
|
76
82
|
|
|
77
83
|
```bash
|
|
78
|
-
DENCH_SESSION_KEY=billing-repo-agent dench
|
|
84
|
+
DENCH_SESSION_KEY=billing-repo-agent dench signin --name "AI Agent - Billing Repo"
|
|
79
85
|
DENCH_SESSION_KEY=billing-repo-agent dench status --mine --json
|
|
80
86
|
```
|
|
81
87
|
|
|
@@ -88,18 +94,18 @@ context. Other saved sessions can still be reused by future chats. To remove the
|
|
|
88
94
|
wrong local session, run `dench logout --session <session-key>`. Use
|
|
89
95
|
`dench logout --all` only when you want to clear every local Dench session.
|
|
90
96
|
|
|
91
|
-
Do not create or edit local agent memory files during setup. Use Dench
|
|
92
|
-
|
|
93
|
-
saving a stable workspace fact.
|
|
97
|
+
Do not create or edit local agent memory files during setup. Use Dench
|
|
98
|
+
memory only when the human asks or when saving a stable workspace fact.
|
|
94
99
|
|
|
95
|
-
|
|
96
|
-
task
|
|
97
|
-
|
|
98
|
-
|
|
100
|
+
Tasks live as CRM `task` entries — there is no separate `dench tasks`,
|
|
101
|
+
`dench task`, `dench claim`, or `dench log` command. Create one via
|
|
102
|
+
`dench crm entries create task --cells '{"Name":"…","Status":"Open"}'`
|
|
103
|
+
only when the human assigns durable work or coordination benefits from
|
|
104
|
+
a tracked entry. For ad-hoc requests, work directly.
|
|
99
105
|
|
|
100
|
-
Use `dench context` when you need to know who you are, which workspace you
|
|
101
|
-
using,
|
|
102
|
-
|
|
106
|
+
Use `dench context` when you need to know who you are, which workspace you
|
|
107
|
+
are using, pending approvals you requested, connected apps, and the best
|
|
108
|
+
next commands. Add `--json` for structured output.
|
|
103
109
|
|
|
104
110
|
## Past chat threads
|
|
105
111
|
|
|
@@ -123,7 +129,7 @@ text — pick concrete tokens that the prior chat would have used (file
|
|
|
123
129
|
paths, product names, error strings) rather than paraphrases.
|
|
124
130
|
|
|
125
131
|
Inside a sandbox, `dench chat` uses `DENCH_API_KEY` + `DENCH_RUN_ID`
|
|
126
|
-
automatically; locally, run `dench
|
|
132
|
+
automatically; locally, run `dench signin` first.
|
|
127
133
|
|
|
128
134
|
## Billing
|
|
129
135
|
|
|
@@ -190,16 +196,16 @@ Run `dench tool --help` or `dench apps --help` for command help.
|
|
|
190
196
|
For staging:
|
|
191
197
|
|
|
192
198
|
```bash
|
|
193
|
-
dench
|
|
194
|
-
dench
|
|
199
|
+
dench signin --staging
|
|
200
|
+
dench signin --host https://workspace-staging.dench.com
|
|
195
201
|
```
|
|
196
202
|
|
|
197
|
-
## Sandbox / API key auth (no `dench
|
|
203
|
+
## Sandbox / API key auth (no `dench signin` required)
|
|
198
204
|
|
|
199
205
|
Inside a Daytona sandbox the unified Dench API key is baked into envVars
|
|
200
206
|
at create time (see `src/lib/secrets/sandbox-tokens.ts`). When
|
|
201
207
|
`DENCH_API_KEY` and `CONVEX_URL` are both present, the CLI skips the
|
|
202
|
-
`dench
|
|
208
|
+
`dench signin` flow entirely and uses the API key as a bearer for every
|
|
203
209
|
org-scoped command — `dench crm`, `dench files`, `dench fs sync`, etc.
|
|
204
210
|
|
|
205
211
|
```bash
|
|
@@ -217,7 +223,7 @@ Auth precedence:
|
|
|
217
223
|
|
|
218
224
|
1. Explicit `--dev` flag → use the dev workspace env (`NEXT_PUBLIC_CONVEX_URL`,
|
|
219
225
|
`DENCH_WORKSPACE`, `DENCH_DEV_AGENT_KEY`).
|
|
220
|
-
2. A locally-stored `dench
|
|
226
|
+
2. A locally-stored `dench signin` session for the current backend (set via
|
|
221
227
|
`dench backend`, `--host`, `--prod`, or `--staging`).
|
|
222
228
|
3. `DENCH_API_KEY` + `CONVEX_URL` (sandbox / automation path).
|
|
223
229
|
|
|
@@ -243,7 +249,7 @@ Auto-load now turns on only when one of:
|
|
|
243
249
|
Explicit shell exports (`GATEWAY_URL=… ./dench …`) always win regardless.
|
|
244
250
|
|
|
245
251
|
Commands that need to impersonate a specific agent (`dench memory`,
|
|
246
|
-
`dench
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
252
|
+
`dench approval request`, etc.) still require an agent session
|
|
253
|
+
(`dench signin`) — the unified API key is org-scoped and cannot speak
|
|
254
|
+
as a single agent. Those commands return a clear "agent session
|
|
255
|
+
required" error in API-key mode.
|
package/dench.ts
CHANGED
|
@@ -97,7 +97,6 @@ type ConfigFile = {
|
|
|
97
97
|
type WorkspaceOverview = {
|
|
98
98
|
agents: Array<{ _id: string } & JsonRecord>;
|
|
99
99
|
projects: JsonRecord[];
|
|
100
|
-
tasks: JsonRecord[];
|
|
101
100
|
approvals: Array<{ status?: string } & JsonRecord>;
|
|
102
101
|
rules: JsonRecord[];
|
|
103
102
|
recentArtifacts?: JsonRecord[];
|
|
@@ -119,33 +118,12 @@ type AgentStatus = {
|
|
|
119
118
|
const api = {
|
|
120
119
|
functions: {
|
|
121
120
|
agentWorkspace: {
|
|
122
|
-
agentAppendLog: makeFunctionReference<"mutation">(
|
|
123
|
-
"functions/agentWorkspace:agentAppendLog",
|
|
124
|
-
),
|
|
125
|
-
agentClaimTask: makeFunctionReference<"mutation">(
|
|
126
|
-
"functions/agentWorkspace:agentClaimTask",
|
|
127
|
-
),
|
|
128
|
-
agentCreateTask: makeFunctionReference<"mutation">(
|
|
129
|
-
"functions/agentWorkspace:agentCreateTask",
|
|
130
|
-
),
|
|
131
|
-
agentAddTaskComment: makeFunctionReference<"mutation">(
|
|
132
|
-
"functions/agentWorkspace:agentAddTaskComment",
|
|
133
|
-
),
|
|
134
|
-
agentAddTaskDependency: makeFunctionReference<"mutation">(
|
|
135
|
-
"functions/agentWorkspace:agentAddTaskDependency",
|
|
136
|
-
),
|
|
137
|
-
agentConvertSuggestionToTask: makeFunctionReference<"mutation">(
|
|
138
|
-
"functions/agentWorkspace:agentConvertSuggestionToTask",
|
|
139
|
-
),
|
|
140
121
|
agentDecideApproval: makeFunctionReference<"mutation">(
|
|
141
122
|
"functions/agentWorkspace:agentDecideApproval",
|
|
142
123
|
),
|
|
143
124
|
agentListArtifacts: makeFunctionReference<"query">(
|
|
144
125
|
"functions/agentWorkspace:agentListArtifacts",
|
|
145
126
|
),
|
|
146
|
-
agentListTasks: makeFunctionReference<"query">(
|
|
147
|
-
"functions/agentWorkspace:agentListTasks",
|
|
148
|
-
),
|
|
149
127
|
agentRequestApproval: makeFunctionReference<"mutation">(
|
|
150
128
|
"functions/agentWorkspace:agentRequestApproval",
|
|
151
129
|
),
|
|
@@ -161,24 +139,12 @@ const api = {
|
|
|
161
139
|
getAgentBillingStatus: makeFunctionReference<"query">(
|
|
162
140
|
"functions/agentWorkspace:getAgentBillingStatus",
|
|
163
141
|
),
|
|
164
|
-
agentUpdateTaskStatus: makeFunctionReference<"mutation">(
|
|
165
|
-
"functions/agentWorkspace:agentUpdateTaskStatus",
|
|
166
|
-
),
|
|
167
142
|
createSignInRequest: makeFunctionReference<"mutation">(
|
|
168
143
|
"functions/agentWorkspace:createSignInRequest",
|
|
169
144
|
),
|
|
170
|
-
devAppendLog: makeFunctionReference<"mutation">(
|
|
171
|
-
"functions/agentWorkspace:devAppendLog",
|
|
172
|
-
),
|
|
173
|
-
devClaimTask: makeFunctionReference<"mutation">(
|
|
174
|
-
"functions/agentWorkspace:devClaimTask",
|
|
175
|
-
),
|
|
176
145
|
devCreateProject: makeFunctionReference<"mutation">(
|
|
177
146
|
"functions/agentWorkspace:devCreateProject",
|
|
178
147
|
),
|
|
179
|
-
devCreateTask: makeFunctionReference<"mutation">(
|
|
180
|
-
"functions/agentWorkspace:devCreateTask",
|
|
181
|
-
),
|
|
182
148
|
devListWorkspaceOverview: makeFunctionReference<"query">(
|
|
183
149
|
"functions/agentWorkspace:devListWorkspaceOverview",
|
|
184
150
|
),
|
|
@@ -431,20 +397,11 @@ Usage:
|
|
|
431
397
|
dench backend [show|set|clear] [<production|staging|local|<url>>] [--json]
|
|
432
398
|
dench context [--json]
|
|
433
399
|
dench status [--mine|--self] [--json]
|
|
434
|
-
dench tasks [--json]
|
|
435
|
-
dench task create "title" [--description "..."] [--priority low|medium|high] [--risk low|medium|high] [--json]
|
|
436
|
-
dench task status <taskId> <open|claimed|in_progress|waiting_approval|completed|canceled> [--note "..."] [--json]
|
|
437
|
-
dench task comment <taskId> "message" [--json]
|
|
438
|
-
dench task handoff <taskId> "message" --agent <agentId> [--json]
|
|
439
|
-
dench task block <taskId> "message" [--json]
|
|
440
|
-
dench claim <taskId> [--json]
|
|
441
|
-
dench log "message" [--task <taskId>] [--json]
|
|
442
400
|
dench memory search "query" [--limit 8] [--json]
|
|
443
401
|
dench memory save <key> "text" [--kind fact|decision|preference|goal|tool_note|other] [--tags a,b] [--sensitivity normal|broad|sensitive] [--json]
|
|
444
402
|
dench artifacts [--limit 25] [--json]
|
|
445
403
|
dench suggested-work [--json]
|
|
446
|
-
dench
|
|
447
|
-
dench approval request "message" [--task <taskId>] [--json]
|
|
404
|
+
dench approval request "message" [--json]
|
|
448
405
|
dench approval approve <approvalId> [--evidence "User said yes in chat"] [--json]
|
|
449
406
|
dench approval reject <approvalId> [--evidence "User said no in chat"] [--json]
|
|
450
407
|
dench billing status [--json]
|
|
@@ -483,7 +440,7 @@ Workspace members (for CRM \`user\`-type fields):
|
|
|
483
440
|
cells assign to real members instead of being stored as unlinked
|
|
484
441
|
display-name strings. See \`dench members help\`.
|
|
485
442
|
|
|
486
|
-
Live web search (Exa via the Dench Cloud Gateway, auths with DENCH_API_KEY):
|
|
443
|
+
Live web search (Exa via the Dench Cloud Gateway, auths with the active \`dench signin\` agent session or DENCH_API_KEY):
|
|
487
444
|
dench search "<query>" [--num-results N] [--type auto|fast|deep|deep-reasoning|neural] [--category news|company|people|...] [--include-domains a.com,b.com] [--exclude-domains c.com] [--max-chars 800] [--json]
|
|
488
445
|
dench search contents <url> [<url>...] [--max-chars 4000] [--summary "..."] [--json]
|
|
489
446
|
dench search answer "<query>" [--json]
|
|
@@ -579,8 +536,9 @@ Agent setup:
|
|
|
579
536
|
Defaults to "other" when omitted. Values are normalized to lowercase
|
|
580
537
|
snake_case before send (e.g. "Claude Code" -> claude_code).
|
|
581
538
|
After sign-in, run dench context --json and dench crm objects list --json
|
|
582
|
-
to verify the workspace + CRM are wired up.
|
|
583
|
-
|
|
539
|
+
to verify the workspace + CRM are wired up. Tasks live as CRM \`task\`
|
|
540
|
+
entries — there is no separate \`dench tasks\` / \`dench task\` /
|
|
541
|
+
\`dench claim\` / \`dench log\` command.
|
|
584
542
|
|
|
585
543
|
Backends and hosts:
|
|
586
544
|
Default backend: ${DEFAULT_HOST} (overridden by \`dench backend set\`)
|
|
@@ -622,10 +580,11 @@ Usage:
|
|
|
622
580
|
dench tool disconnect <connectionId> [--json]
|
|
623
581
|
|
|
624
582
|
Auth:
|
|
625
|
-
All commands authenticate with
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
583
|
+
All commands authenticate with the active \`dench signin\` agent
|
|
584
|
+
session OR with DENCH_API_KEY (Bearer), whichever is set. Inside a
|
|
585
|
+
Dench sandbox DENCH_API_KEY is baked into the env automatically; on
|
|
586
|
+
a developer machine \`dench signin\` to a paid workspace works the
|
|
587
|
+
same way (the CLI exchanges the session for a gateway key on demand).
|
|
629
588
|
|
|
630
589
|
Notes:
|
|
631
590
|
dench apps is an alias for dench tool status.
|
|
@@ -664,10 +623,8 @@ function artifactsHelp() {
|
|
|
664
623
|
Usage:
|
|
665
624
|
dench artifacts [--limit 25] [--json]
|
|
666
625
|
dench suggested-work [--json]
|
|
667
|
-
dench suggested-work task <artifactId> [--json]
|
|
668
626
|
|
|
669
|
-
Artifacts are durable outputs for human or agent review.
|
|
670
|
-
be converted into a workspace task.
|
|
627
|
+
Artifacts are durable outputs for human or agent review.
|
|
671
628
|
`);
|
|
672
629
|
}
|
|
673
630
|
|
|
@@ -727,20 +684,6 @@ Notes:
|
|
|
727
684
|
`);
|
|
728
685
|
}
|
|
729
686
|
|
|
730
|
-
function tasksHelp() {
|
|
731
|
-
console.log(`Dench tasks
|
|
732
|
-
|
|
733
|
-
Usage:
|
|
734
|
-
dench tasks [--json]
|
|
735
|
-
|
|
736
|
-
Notes:
|
|
737
|
-
List workspace tasks before creating new ones.
|
|
738
|
-
Do not create, claim, or log a setup task by default.
|
|
739
|
-
Only create or claim a task if the human assigns work, an open matching task
|
|
740
|
-
exists, or coordination benefits from creating one.
|
|
741
|
-
`);
|
|
742
|
-
}
|
|
743
|
-
|
|
744
687
|
function logoutHelp() {
|
|
745
688
|
console.log(`Dench logout
|
|
746
689
|
|
|
@@ -761,9 +704,9 @@ Usage:
|
|
|
761
704
|
dench apps [--json]
|
|
762
705
|
|
|
763
706
|
Lists all external apps connected to this organization (Slack, Gmail,
|
|
764
|
-
GitHub, etc.). Authenticates with
|
|
765
|
-
|
|
766
|
-
|
|
707
|
+
GitHub, etc.). Authenticates with the active \`dench signin\` agent
|
|
708
|
+
session or DENCH_API_KEY (Bearer), whichever is set. Alias for
|
|
709
|
+
\`dench tool status\`.
|
|
767
710
|
`);
|
|
768
711
|
}
|
|
769
712
|
|
|
@@ -2616,10 +2559,9 @@ function agentSessionRequiredError(command: string) {
|
|
|
2616
2559
|
}
|
|
2617
2560
|
|
|
2618
2561
|
/**
|
|
2619
|
-
*
|
|
2620
|
-
*
|
|
2621
|
-
*
|
|
2622
|
-
* this to short-circuit those branches with a clear error.
|
|
2562
|
+
* `dench approval request` has separate session vs dev branches. With
|
|
2563
|
+
* apiKey mode added, the dev branch would silently receive partial args.
|
|
2564
|
+
* Use this to short-circuit that branch with a clear error.
|
|
2623
2565
|
*
|
|
2624
2566
|
* Asserts away the `apiKey` mode so the caller's downstream type
|
|
2625
2567
|
* narrowing (e.g. `runtime.workspaceArgs`) keeps working.
|
|
@@ -2710,8 +2652,7 @@ function workspaceUrls(host: string, workspaceSlug: string | undefined) {
|
|
|
2710
2652
|
function nextContextCommands() {
|
|
2711
2653
|
return [
|
|
2712
2654
|
"dench context --json",
|
|
2713
|
-
"dench
|
|
2714
|
-
'dench log "Brief progress update"',
|
|
2655
|
+
"dench crm entries list task --json",
|
|
2715
2656
|
'dench tool search "what you need" --toolkit <app>',
|
|
2716
2657
|
'dench approval request "Risky action to approve"',
|
|
2717
2658
|
];
|
|
@@ -2797,15 +2738,6 @@ function formatContext(context: JsonRecord) {
|
|
|
2797
2738
|
const workspace = asRecord(context.workspace);
|
|
2798
2739
|
const connectedApps = asRecord(context.connectedApps);
|
|
2799
2740
|
const connections = asRecordArray(connectedApps?.connections);
|
|
2800
|
-
const tasksRecord = asRecord(context.tasks);
|
|
2801
|
-
const tasks =
|
|
2802
|
-
asRecordArray(tasksRecord?.assignedToMe).length > 0 ||
|
|
2803
|
-
asRecordArray(tasksRecord?.open).length > 0
|
|
2804
|
-
? [
|
|
2805
|
-
...asRecordArray(tasksRecord?.assignedToMe),
|
|
2806
|
-
...asRecordArray(tasksRecord?.open),
|
|
2807
|
-
]
|
|
2808
|
-
: asRecordArray(context.tasks);
|
|
2809
2741
|
const approvals = asRecordArray(context.pendingApprovals);
|
|
2810
2742
|
const suggestedWork = asRecordArray(context.suggestedWork);
|
|
2811
2743
|
const memories = asRecordArray(context.memory);
|
|
@@ -2828,10 +2760,7 @@ function formatContext(context: JsonRecord) {
|
|
|
2828
2760
|
`Agent: ${agentDisplayName(agent)}${
|
|
2829
2761
|
stringField(agent, "kind") ? ` [${stringField(agent, "kind")}]` : ""
|
|
2830
2762
|
}`,
|
|
2831
|
-
`Counts: ${formatCount(
|
|
2832
|
-
counts?.myAssignedTasks ??
|
|
2833
|
-
asRecordArray(tasksRecord?.assignedToMe).length,
|
|
2834
|
-
)} assigned to me, ${formatCount(
|
|
2763
|
+
`Counts: ${formatCount(
|
|
2835
2764
|
counts?.myPendingApprovals ?? approvals.length,
|
|
2836
2765
|
)} pending approvals`,
|
|
2837
2766
|
];
|
|
@@ -2845,21 +2774,6 @@ function formatContext(context: JsonRecord) {
|
|
|
2845
2774
|
);
|
|
2846
2775
|
}
|
|
2847
2776
|
|
|
2848
|
-
lines.push("", "Assigned tasks:");
|
|
2849
|
-
|
|
2850
|
-
if (tasks.length === 0) {
|
|
2851
|
-
lines.push(" none");
|
|
2852
|
-
} else {
|
|
2853
|
-
lines.push(
|
|
2854
|
-
...tasks
|
|
2855
|
-
.slice(0, 5)
|
|
2856
|
-
.map(
|
|
2857
|
-
(task) =>
|
|
2858
|
-
` - ${stringField(task, "title") ?? stringField(task, "id") ?? "untitled"} [${stringField(task, "status") ?? "unknown"}]`,
|
|
2859
|
-
),
|
|
2860
|
-
);
|
|
2861
|
-
}
|
|
2862
|
-
|
|
2863
2777
|
lines.push("", "Pending approvals requested by me:");
|
|
2864
2778
|
if (approvals.length === 0) {
|
|
2865
2779
|
lines.push(" none");
|
|
@@ -2958,7 +2872,6 @@ function summarizeDevOverview(workspaceSlug: string, data: WorkspaceOverview) {
|
|
|
2958
2872
|
workspace: workspaceSlug,
|
|
2959
2873
|
agents: data.agents.length,
|
|
2960
2874
|
projects: data.projects.length,
|
|
2961
|
-
tasks: data.tasks.length,
|
|
2962
2875
|
approvals: data.approvals.filter(
|
|
2963
2876
|
(approval) => approval.status === "pending",
|
|
2964
2877
|
).length,
|
|
@@ -2966,37 +2879,18 @@ function summarizeDevOverview(workspaceSlug: string, data: WorkspaceOverview) {
|
|
|
2966
2879
|
};
|
|
2967
2880
|
}
|
|
2968
2881
|
|
|
2969
|
-
function compactTask(task: JsonRecord) {
|
|
2970
|
-
return {
|
|
2971
|
-
id: task._id ?? task.id,
|
|
2972
|
-
title: task.title,
|
|
2973
|
-
status: task.status,
|
|
2974
|
-
priority: task.priority,
|
|
2975
|
-
risk: task.risk,
|
|
2976
|
-
assignedAgentId: task.assignedAgentId,
|
|
2977
|
-
};
|
|
2978
|
-
}
|
|
2979
|
-
|
|
2980
2882
|
function compactApproval(approval: JsonRecord) {
|
|
2981
2883
|
return {
|
|
2982
2884
|
id: approval.id ?? approval._id,
|
|
2983
2885
|
title: approval.title,
|
|
2984
2886
|
risk: approval.risk,
|
|
2985
2887
|
status: approval.status,
|
|
2986
|
-
taskId: approval.taskId,
|
|
2987
2888
|
createdAt: approval.createdAt,
|
|
2988
2889
|
};
|
|
2989
2890
|
}
|
|
2990
2891
|
|
|
2991
|
-
function summarizeAgentStatus(
|
|
2992
|
-
status: AgentStatus,
|
|
2993
|
-
tasks: JsonRecord[],
|
|
2994
|
-
host?: string,
|
|
2995
|
-
) {
|
|
2892
|
+
function summarizeAgentStatus(status: AgentStatus, host?: string) {
|
|
2996
2893
|
const agentId = status.agent?.id;
|
|
2997
|
-
const assignedTasks = agentId
|
|
2998
|
-
? tasks.filter((task) => task.assignedAgentId === agentId)
|
|
2999
|
-
: [];
|
|
3000
2894
|
const pendingApprovals = (status.approvals ?? []).filter(
|
|
3001
2895
|
(approval) => approval.status === "pending" && approval.agentId === agentId,
|
|
3002
2896
|
);
|
|
@@ -3009,11 +2903,9 @@ function summarizeAgentStatus(
|
|
|
3009
2903
|
agent: status.agent,
|
|
3010
2904
|
counts: {
|
|
3011
2905
|
...(status.counts ?? {}),
|
|
3012
|
-
myAssignedTasks: assignedTasks.length,
|
|
3013
2906
|
myPendingApprovals: pendingApprovals.length,
|
|
3014
2907
|
},
|
|
3015
2908
|
rules: status.rules ?? [],
|
|
3016
|
-
tasks: assignedTasks.map(compactTask),
|
|
3017
2909
|
pendingApprovals: pendingApprovals.map(compactApproval),
|
|
3018
2910
|
};
|
|
3019
2911
|
}
|
|
@@ -3021,7 +2913,6 @@ function summarizeAgentStatus(
|
|
|
3021
2913
|
function summarizeDevMine(workspaceSlug: string, data: WorkspaceOverview) {
|
|
3022
2914
|
const agentId = option("--agent") ?? data.agents[0]?._id;
|
|
3023
2915
|
const agent = data.agents.find((item) => item._id === agentId) ?? null;
|
|
3024
|
-
const tasks = data.tasks.filter((task) => task.assignedAgentId === agentId);
|
|
3025
2916
|
const pendingApprovals = data.approvals.filter(
|
|
3026
2917
|
(approval) => approval.status === "pending" && approval.agentId === agentId,
|
|
3027
2918
|
);
|
|
@@ -3032,33 +2923,17 @@ function summarizeDevMine(workspaceSlug: string, data: WorkspaceOverview) {
|
|
|
3032
2923
|
counts: {
|
|
3033
2924
|
agents: data.agents.length,
|
|
3034
2925
|
projects: data.projects.length,
|
|
3035
|
-
tasks: data.tasks.length,
|
|
3036
2926
|
pendingApprovals: data.approvals.filter(
|
|
3037
2927
|
(approval) => approval.status === "pending",
|
|
3038
2928
|
).length,
|
|
3039
2929
|
rules: data.rules.length,
|
|
3040
|
-
myAssignedTasks: tasks.length,
|
|
3041
2930
|
myPendingApprovals: pendingApprovals.length,
|
|
3042
2931
|
},
|
|
3043
2932
|
rules: data.rules,
|
|
3044
|
-
tasks: tasks.map(compactTask),
|
|
3045
2933
|
pendingApprovals: pendingApprovals.map(compactApproval),
|
|
3046
2934
|
};
|
|
3047
2935
|
}
|
|
3048
2936
|
|
|
3049
|
-
async function defaultDevAgentId(
|
|
3050
|
-
runtime: Awaited<ReturnType<typeof getRuntime>>,
|
|
3051
|
-
) {
|
|
3052
|
-
const data = await devOverview(runtime);
|
|
3053
|
-
const agent = data.agents[0];
|
|
3054
|
-
if (!agent) {
|
|
3055
|
-
throw new Error(
|
|
3056
|
-
'No agent registered yet. Run: dench signin --kind <kind> --name "AI Agent - Project"',
|
|
3057
|
-
);
|
|
3058
|
-
}
|
|
3059
|
-
return agent._id;
|
|
3060
|
-
}
|
|
3061
|
-
|
|
3062
2937
|
async function listArtifacts(runtime: Runtime, limit?: number) {
|
|
3063
2938
|
if (runtime.mode === "session") {
|
|
3064
2939
|
try {
|
|
@@ -3840,11 +3715,6 @@ async function main() {
|
|
|
3840
3715
|
return;
|
|
3841
3716
|
}
|
|
3842
3717
|
|
|
3843
|
-
if (command === "tasks" && hasFlag("--help")) {
|
|
3844
|
-
tasksHelp();
|
|
3845
|
-
return;
|
|
3846
|
-
}
|
|
3847
|
-
|
|
3848
3718
|
if (command === "logout" && hasFlag("--help")) {
|
|
3849
3719
|
logoutHelp();
|
|
3850
3720
|
return;
|
|
@@ -4343,50 +4213,6 @@ async function main() {
|
|
|
4343
4213
|
}
|
|
4344
4214
|
|
|
4345
4215
|
if (command === "suggested-work") {
|
|
4346
|
-
if (subcommand === "task") {
|
|
4347
|
-
const sessionRuntime = requireSessionRuntime(
|
|
4348
|
-
runtime,
|
|
4349
|
-
"dench suggested-work task",
|
|
4350
|
-
);
|
|
4351
|
-
const artifactId = positional(2);
|
|
4352
|
-
if (!artifactId) {
|
|
4353
|
-
throw new Error("Usage: dench suggested-work task <artifactId>");
|
|
4354
|
-
}
|
|
4355
|
-
print(
|
|
4356
|
-
await sessionRuntime.client
|
|
4357
|
-
.mutation(api.functions.agentWorkspace.agentConvertSuggestionToTask, {
|
|
4358
|
-
sessionToken: sessionRuntime.sessionToken,
|
|
4359
|
-
artifactId: artifactId as never,
|
|
4360
|
-
})
|
|
4361
|
-
.catch(async (error) => {
|
|
4362
|
-
if (!isMissingConvexFunction(error)) throw error;
|
|
4363
|
-
const suggestion = (await listSuggestedWork(runtime)).find(
|
|
4364
|
-
(item) => stringField(item, "id") === artifactId,
|
|
4365
|
-
);
|
|
4366
|
-
if (!suggestion) throw error;
|
|
4367
|
-
const title = stringField(suggestion, "title") ?? "Suggested work";
|
|
4368
|
-
const created = (await sessionRuntime.client.mutation(
|
|
4369
|
-
api.functions.agentWorkspace.agentCreateTask,
|
|
4370
|
-
{
|
|
4371
|
-
sessionToken: sessionRuntime.sessionToken,
|
|
4372
|
-
title,
|
|
4373
|
-
description: stringField(suggestion, "content"),
|
|
4374
|
-
priority: "medium",
|
|
4375
|
-
risk: "medium",
|
|
4376
|
-
},
|
|
4377
|
-
)) as JsonRecord;
|
|
4378
|
-
return {
|
|
4379
|
-
ok: true,
|
|
4380
|
-
fallback: true,
|
|
4381
|
-
artifactId,
|
|
4382
|
-
title,
|
|
4383
|
-
taskId: created.taskId,
|
|
4384
|
-
note: "Created a task from suggested work. Artifact status will update after the backend conversion function is deployed.",
|
|
4385
|
-
};
|
|
4386
|
-
}),
|
|
4387
|
-
);
|
|
4388
|
-
return;
|
|
4389
|
-
}
|
|
4390
4216
|
print(await listSuggestedWork(runtime));
|
|
4391
4217
|
return;
|
|
4392
4218
|
}
|
|
@@ -4400,13 +4226,7 @@ async function main() {
|
|
|
4400
4226
|
},
|
|
4401
4227
|
)) as AgentStatus;
|
|
4402
4228
|
if (scopedStatus) {
|
|
4403
|
-
|
|
4404
|
-
api.functions.agentWorkspace.agentListTasks,
|
|
4405
|
-
{
|
|
4406
|
-
sessionToken: runtime.sessionToken,
|
|
4407
|
-
},
|
|
4408
|
-
)) as JsonRecord[];
|
|
4409
|
-
print(summarizeAgentStatus(status, tasks, runtime.host));
|
|
4229
|
+
print(summarizeAgentStatus(status, runtime.host));
|
|
4410
4230
|
return;
|
|
4411
4231
|
}
|
|
4412
4232
|
print(status);
|
|
@@ -4429,26 +4249,6 @@ async function main() {
|
|
|
4429
4249
|
return;
|
|
4430
4250
|
}
|
|
4431
4251
|
|
|
4432
|
-
if (command === "tasks") {
|
|
4433
|
-
if (runtime.mode === "session") {
|
|
4434
|
-
print(
|
|
4435
|
-
await runtime.client.query(
|
|
4436
|
-
api.functions.agentWorkspace.agentListTasks,
|
|
4437
|
-
{
|
|
4438
|
-
sessionToken: runtime.sessionToken,
|
|
4439
|
-
},
|
|
4440
|
-
),
|
|
4441
|
-
);
|
|
4442
|
-
return;
|
|
4443
|
-
}
|
|
4444
|
-
if (runtime.mode === "apiKey") {
|
|
4445
|
-
throw loginRequiredError("dench tasks (agent-scoped task list)");
|
|
4446
|
-
}
|
|
4447
|
-
const data = await devOverview(runtime);
|
|
4448
|
-
print(data.tasks);
|
|
4449
|
-
return;
|
|
4450
|
-
}
|
|
4451
|
-
|
|
4452
4252
|
if (command === "agents") {
|
|
4453
4253
|
if (runtime.mode === "session") {
|
|
4454
4254
|
const status = await runtime.client.query(
|
|
@@ -4508,176 +4308,6 @@ async function main() {
|
|
|
4508
4308
|
return;
|
|
4509
4309
|
}
|
|
4510
4310
|
|
|
4511
|
-
if (command === "task" && subcommand === "create") {
|
|
4512
|
-
const title = positional(2);
|
|
4513
|
-
if (!title) throw new Error("Missing task title");
|
|
4514
|
-
const taskArgs = {
|
|
4515
|
-
title,
|
|
4516
|
-
description: option("--description"),
|
|
4517
|
-
priority: (option("--priority") ?? "medium") as "low" | "medium" | "high",
|
|
4518
|
-
risk: (option("--risk") ?? "medium") as "low" | "medium" | "high",
|
|
4519
|
-
};
|
|
4520
|
-
if (runtime.mode === "session") {
|
|
4521
|
-
print(
|
|
4522
|
-
await runtime.client.mutation(
|
|
4523
|
-
api.functions.agentWorkspace.agentCreateTask,
|
|
4524
|
-
{
|
|
4525
|
-
sessionToken: runtime.sessionToken,
|
|
4526
|
-
...taskArgs,
|
|
4527
|
-
},
|
|
4528
|
-
),
|
|
4529
|
-
);
|
|
4530
|
-
return;
|
|
4531
|
-
}
|
|
4532
|
-
rejectApiKeyForAgentCommand(runtime, "dench task create");
|
|
4533
|
-
const taskId = await runtime.client.mutation(
|
|
4534
|
-
api.functions.agentWorkspace.devCreateTask,
|
|
4535
|
-
{
|
|
4536
|
-
...runtime.workspaceArgs,
|
|
4537
|
-
...taskArgs,
|
|
4538
|
-
},
|
|
4539
|
-
);
|
|
4540
|
-
print({ ok: true, taskId });
|
|
4541
|
-
return;
|
|
4542
|
-
}
|
|
4543
|
-
|
|
4544
|
-
if (command === "task" && subcommand === "status") {
|
|
4545
|
-
const sessionRuntime = requireSessionRuntime(runtime, "dench task status");
|
|
4546
|
-
const taskId = positional(2);
|
|
4547
|
-
const status = positional(3);
|
|
4548
|
-
if (!taskId || !status) {
|
|
4549
|
-
throw new Error("Usage: dench task status <taskId> <status>");
|
|
4550
|
-
}
|
|
4551
|
-
print(
|
|
4552
|
-
await sessionRuntime.client.mutation(
|
|
4553
|
-
api.functions.agentWorkspace.agentUpdateTaskStatus,
|
|
4554
|
-
{
|
|
4555
|
-
sessionToken: sessionRuntime.sessionToken,
|
|
4556
|
-
taskId: taskId as never,
|
|
4557
|
-
status: status as never,
|
|
4558
|
-
note: option("--note"),
|
|
4559
|
-
},
|
|
4560
|
-
),
|
|
4561
|
-
);
|
|
4562
|
-
return;
|
|
4563
|
-
}
|
|
4564
|
-
|
|
4565
|
-
if (
|
|
4566
|
-
command === "task" &&
|
|
4567
|
-
(subcommand === "comment" ||
|
|
4568
|
-
subcommand === "handoff" ||
|
|
4569
|
-
subcommand === "block")
|
|
4570
|
-
) {
|
|
4571
|
-
const sessionRuntime = requireSessionRuntime(
|
|
4572
|
-
runtime,
|
|
4573
|
-
`dench task ${subcommand}`,
|
|
4574
|
-
);
|
|
4575
|
-
const taskId = positional(2);
|
|
4576
|
-
const body = positionalsFrom(3).join(" ").trim();
|
|
4577
|
-
if (!taskId || !body) {
|
|
4578
|
-
throw new Error(`Usage: dench task ${subcommand} <taskId> "message"`);
|
|
4579
|
-
}
|
|
4580
|
-
print(
|
|
4581
|
-
await sessionRuntime.client.mutation(
|
|
4582
|
-
api.functions.agentWorkspace.agentAddTaskComment,
|
|
4583
|
-
{
|
|
4584
|
-
sessionToken: sessionRuntime.sessionToken,
|
|
4585
|
-
taskId: taskId as never,
|
|
4586
|
-
kind:
|
|
4587
|
-
subcommand === "handoff"
|
|
4588
|
-
? "handoff"
|
|
4589
|
-
: subcommand === "block"
|
|
4590
|
-
? "blocker"
|
|
4591
|
-
: "comment",
|
|
4592
|
-
body,
|
|
4593
|
-
targetAgentId: option("--agent") as never,
|
|
4594
|
-
},
|
|
4595
|
-
),
|
|
4596
|
-
);
|
|
4597
|
-
return;
|
|
4598
|
-
}
|
|
4599
|
-
|
|
4600
|
-
if (command === "task" && subcommand === "depends-on") {
|
|
4601
|
-
const sessionRuntime = requireSessionRuntime(
|
|
4602
|
-
runtime,
|
|
4603
|
-
"dench task depends-on",
|
|
4604
|
-
);
|
|
4605
|
-
const taskId = positional(2);
|
|
4606
|
-
const dependsOnTaskId = positional(3);
|
|
4607
|
-
if (!taskId || !dependsOnTaskId) {
|
|
4608
|
-
throw new Error(
|
|
4609
|
-
"Usage: dench task depends-on <taskId> <dependsOnTaskId>",
|
|
4610
|
-
);
|
|
4611
|
-
}
|
|
4612
|
-
print(
|
|
4613
|
-
await sessionRuntime.client.mutation(
|
|
4614
|
-
api.functions.agentWorkspace.agentAddTaskDependency,
|
|
4615
|
-
{
|
|
4616
|
-
sessionToken: sessionRuntime.sessionToken,
|
|
4617
|
-
taskId: taskId as never,
|
|
4618
|
-
dependsOnTaskId: dependsOnTaskId as never,
|
|
4619
|
-
note: option("--note"),
|
|
4620
|
-
},
|
|
4621
|
-
),
|
|
4622
|
-
);
|
|
4623
|
-
return;
|
|
4624
|
-
}
|
|
4625
|
-
|
|
4626
|
-
if (command === "claim") {
|
|
4627
|
-
const taskId = positional(1);
|
|
4628
|
-
if (!taskId) throw new Error("Missing task id");
|
|
4629
|
-
if (runtime.mode === "session") {
|
|
4630
|
-
print(
|
|
4631
|
-
await runtime.client.mutation(
|
|
4632
|
-
api.functions.agentWorkspace.agentClaimTask,
|
|
4633
|
-
{
|
|
4634
|
-
sessionToken: runtime.sessionToken,
|
|
4635
|
-
taskId: taskId as never,
|
|
4636
|
-
},
|
|
4637
|
-
),
|
|
4638
|
-
);
|
|
4639
|
-
return;
|
|
4640
|
-
}
|
|
4641
|
-
rejectApiKeyForAgentCommand(runtime, "dench claim");
|
|
4642
|
-
const agentId = option("--agent") ?? (await defaultDevAgentId(runtime));
|
|
4643
|
-
print(
|
|
4644
|
-
await runtime.client.mutation(api.functions.agentWorkspace.devClaimTask, {
|
|
4645
|
-
...runtime.workspaceArgs,
|
|
4646
|
-
taskId: taskId as never,
|
|
4647
|
-
agentId: agentId as never,
|
|
4648
|
-
}),
|
|
4649
|
-
);
|
|
4650
|
-
return;
|
|
4651
|
-
}
|
|
4652
|
-
|
|
4653
|
-
if (command === "log") {
|
|
4654
|
-
const message = positional(1);
|
|
4655
|
-
if (!message) throw new Error("Missing log message");
|
|
4656
|
-
if (runtime.mode === "session") {
|
|
4657
|
-
print(
|
|
4658
|
-
await runtime.client.mutation(
|
|
4659
|
-
api.functions.agentWorkspace.agentAppendLog,
|
|
4660
|
-
{
|
|
4661
|
-
sessionToken: runtime.sessionToken,
|
|
4662
|
-
message,
|
|
4663
|
-
taskId: option("--task") as never,
|
|
4664
|
-
},
|
|
4665
|
-
),
|
|
4666
|
-
);
|
|
4667
|
-
return;
|
|
4668
|
-
}
|
|
4669
|
-
rejectApiKeyForAgentCommand(runtime, "dench log");
|
|
4670
|
-
print(
|
|
4671
|
-
await runtime.client.mutation(api.functions.agentWorkspace.devAppendLog, {
|
|
4672
|
-
...runtime.workspaceArgs,
|
|
4673
|
-
message,
|
|
4674
|
-
agentId: option("--agent") as never,
|
|
4675
|
-
taskId: option("--task") as never,
|
|
4676
|
-
}),
|
|
4677
|
-
);
|
|
4678
|
-
return;
|
|
4679
|
-
}
|
|
4680
|
-
|
|
4681
4311
|
if (command === "approval" && subcommand === "request") {
|
|
4682
4312
|
const title = positional(2);
|
|
4683
4313
|
if (!title) throw new Error("Missing approval title");
|
|
@@ -4690,7 +4320,6 @@ async function main() {
|
|
|
4690
4320
|
title,
|
|
4691
4321
|
reason: option("--reason"),
|
|
4692
4322
|
risk: (option("--risk") ?? "high") as "low" | "medium" | "high",
|
|
4693
|
-
taskId: option("--task") as never,
|
|
4694
4323
|
},
|
|
4695
4324
|
),
|
|
4696
4325
|
);
|
|
@@ -4707,7 +4336,6 @@ async function main() {
|
|
|
4707
4336
|
"Agent requests human approval before a risky action.",
|
|
4708
4337
|
risk: (option("--risk") ?? "high") as "low" | "medium" | "high",
|
|
4709
4338
|
agentId: option("--agent") as never,
|
|
4710
|
-
taskId: option("--task") as never,
|
|
4711
4339
|
},
|
|
4712
4340
|
);
|
|
4713
4341
|
print({ ok: true, approvalId });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dench.com/cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Dench agent workspace CLI. v2 unifies auth behind `dench signin`; the legacy `dench login` / `dench onboard` / `dench setup` / `dench what-can-i-do` / `dench register` commands now error with a redirect.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|