@dench.com/cli 2.0.1 → 2.0.3
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 +37 -411
- package/host.ts +17 -2
- 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
|
@@ -16,11 +16,11 @@ import { ConvexHttpClient } from "convex/browser";
|
|
|
16
16
|
import { makeFunctionReference } from "convex/server";
|
|
17
17
|
import { agentKindLabel, normalizeAgentKind } from "./agentKind";
|
|
18
18
|
import {
|
|
19
|
+
apiHostForDenchHost,
|
|
19
20
|
DEFAULT_HOST,
|
|
20
21
|
isLocalHost,
|
|
21
22
|
LOCAL_HOST,
|
|
22
23
|
normalizeHost,
|
|
23
|
-
PRODUCTION_API_URL,
|
|
24
24
|
PRODUCTION_CONVEX_URL,
|
|
25
25
|
PRODUCTION_HOST,
|
|
26
26
|
resolveBackendAlias,
|
|
@@ -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
|
|
|
@@ -2050,16 +1993,6 @@ async function resolveOrgChoiceForOtp(input: {
|
|
|
2050
1993
|
return { newOrganizationName: newName.trim() };
|
|
2051
1994
|
}
|
|
2052
1995
|
|
|
2053
|
-
function normalizeApiBase(input: string) {
|
|
2054
|
-
const trimmed = input.trim();
|
|
2055
|
-
const withProtocol = /^https?:\/\//.test(trimmed)
|
|
2056
|
-
? trimmed
|
|
2057
|
-
: /^(localhost|127\.0\.0\.1|\[::1\])(?::|$)/.test(trimmed)
|
|
2058
|
-
? `http://${trimmed}`
|
|
2059
|
-
: `https://${trimmed}`;
|
|
2060
|
-
return new URL(withProtocol).origin;
|
|
2061
|
-
}
|
|
2062
|
-
|
|
2063
1996
|
async function parseResponseBody(response: Response) {
|
|
2064
1997
|
const text = await response.text();
|
|
2065
1998
|
if (!text) return {};
|
|
@@ -2313,16 +2246,14 @@ function resolveApiKeyConvexUrl(): string | undefined {
|
|
|
2313
2246
|
/**
|
|
2314
2247
|
* Resolve the Next.js API host the CLI should hit for HTTP calls (e.g.
|
|
2315
2248
|
* Stripe billing topup, the gateway proxy). Same defense-in-depth
|
|
2316
|
-
* pattern as `resolveApiKeyConvexUrl`: env wins, then the
|
|
2317
|
-
* Dench host the runtime is targeting
|
|
2318
|
-
* `PRODUCTION_API_URL` as the last resort.
|
|
2249
|
+
* pattern as `resolveApiKeyConvexUrl`: env wins, then the canonical API
|
|
2250
|
+
* origin for the Dench host the runtime is targeting.
|
|
2319
2251
|
*/
|
|
2320
2252
|
function resolveApiHost(fallbackHost: string): string {
|
|
2321
2253
|
return (
|
|
2322
2254
|
process.env.DENCH_API_URL?.trim() ||
|
|
2323
2255
|
process.env.DENCH_INTERNAL_BASE?.trim() ||
|
|
2324
|
-
fallbackHost
|
|
2325
|
-
PRODUCTION_API_URL
|
|
2256
|
+
apiHostForDenchHost(fallbackHost)
|
|
2326
2257
|
);
|
|
2327
2258
|
}
|
|
2328
2259
|
|
|
@@ -2362,7 +2293,7 @@ async function getRuntime() {
|
|
|
2362
2293
|
if (stored.status === "found") {
|
|
2363
2294
|
return {
|
|
2364
2295
|
mode: "session" as const,
|
|
2365
|
-
host,
|
|
2296
|
+
host: resolveApiHost(host),
|
|
2366
2297
|
client: new ConvexHttpClient(stored.session.convexUrl),
|
|
2367
2298
|
sessionToken: stored.session.sessionToken,
|
|
2368
2299
|
organization: stored.session.organization,
|
|
@@ -2543,7 +2474,17 @@ function gatewayAuthError(
|
|
|
2543
2474
|
});
|
|
2544
2475
|
}
|
|
2545
2476
|
if (response.status === 401) {
|
|
2546
|
-
return
|
|
2477
|
+
return new CliError(
|
|
2478
|
+
`${command} could not exchange the active Dench session for a gateway key (${code})`,
|
|
2479
|
+
{
|
|
2480
|
+
code,
|
|
2481
|
+
status: response.status,
|
|
2482
|
+
nextActions: [
|
|
2483
|
+
"Run dench sessions --json to confirm the selected session.",
|
|
2484
|
+
'Run dench signin --kind <kind> --name "AI Agent - Project" to refresh the agent session if it expired.',
|
|
2485
|
+
],
|
|
2486
|
+
},
|
|
2487
|
+
);
|
|
2547
2488
|
}
|
|
2548
2489
|
return new CliError(`${command} could not get a gateway key (${code})`, {
|
|
2549
2490
|
code,
|
|
@@ -2616,10 +2557,9 @@ function agentSessionRequiredError(command: string) {
|
|
|
2616
2557
|
}
|
|
2617
2558
|
|
|
2618
2559
|
/**
|
|
2619
|
-
*
|
|
2620
|
-
*
|
|
2621
|
-
*
|
|
2622
|
-
* this to short-circuit those branches with a clear error.
|
|
2560
|
+
* `dench approval request` has separate session vs dev branches. With
|
|
2561
|
+
* apiKey mode added, the dev branch would silently receive partial args.
|
|
2562
|
+
* Use this to short-circuit that branch with a clear error.
|
|
2623
2563
|
*
|
|
2624
2564
|
* Asserts away the `apiKey` mode so the caller's downstream type
|
|
2625
2565
|
* narrowing (e.g. `runtime.workspaceArgs`) keeps working.
|
|
@@ -2710,8 +2650,7 @@ function workspaceUrls(host: string, workspaceSlug: string | undefined) {
|
|
|
2710
2650
|
function nextContextCommands() {
|
|
2711
2651
|
return [
|
|
2712
2652
|
"dench context --json",
|
|
2713
|
-
"dench
|
|
2714
|
-
'dench log "Brief progress update"',
|
|
2653
|
+
"dench crm entries list task --json",
|
|
2715
2654
|
'dench tool search "what you need" --toolkit <app>',
|
|
2716
2655
|
'dench approval request "Risky action to approve"',
|
|
2717
2656
|
];
|
|
@@ -2797,15 +2736,6 @@ function formatContext(context: JsonRecord) {
|
|
|
2797
2736
|
const workspace = asRecord(context.workspace);
|
|
2798
2737
|
const connectedApps = asRecord(context.connectedApps);
|
|
2799
2738
|
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
2739
|
const approvals = asRecordArray(context.pendingApprovals);
|
|
2810
2740
|
const suggestedWork = asRecordArray(context.suggestedWork);
|
|
2811
2741
|
const memories = asRecordArray(context.memory);
|
|
@@ -2828,10 +2758,7 @@ function formatContext(context: JsonRecord) {
|
|
|
2828
2758
|
`Agent: ${agentDisplayName(agent)}${
|
|
2829
2759
|
stringField(agent, "kind") ? ` [${stringField(agent, "kind")}]` : ""
|
|
2830
2760
|
}`,
|
|
2831
|
-
`Counts: ${formatCount(
|
|
2832
|
-
counts?.myAssignedTasks ??
|
|
2833
|
-
asRecordArray(tasksRecord?.assignedToMe).length,
|
|
2834
|
-
)} assigned to me, ${formatCount(
|
|
2761
|
+
`Counts: ${formatCount(
|
|
2835
2762
|
counts?.myPendingApprovals ?? approvals.length,
|
|
2836
2763
|
)} pending approvals`,
|
|
2837
2764
|
];
|
|
@@ -2845,21 +2772,6 @@ function formatContext(context: JsonRecord) {
|
|
|
2845
2772
|
);
|
|
2846
2773
|
}
|
|
2847
2774
|
|
|
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
2775
|
lines.push("", "Pending approvals requested by me:");
|
|
2864
2776
|
if (approvals.length === 0) {
|
|
2865
2777
|
lines.push(" none");
|
|
@@ -2958,7 +2870,6 @@ function summarizeDevOverview(workspaceSlug: string, data: WorkspaceOverview) {
|
|
|
2958
2870
|
workspace: workspaceSlug,
|
|
2959
2871
|
agents: data.agents.length,
|
|
2960
2872
|
projects: data.projects.length,
|
|
2961
|
-
tasks: data.tasks.length,
|
|
2962
2873
|
approvals: data.approvals.filter(
|
|
2963
2874
|
(approval) => approval.status === "pending",
|
|
2964
2875
|
).length,
|
|
@@ -2966,37 +2877,18 @@ function summarizeDevOverview(workspaceSlug: string, data: WorkspaceOverview) {
|
|
|
2966
2877
|
};
|
|
2967
2878
|
}
|
|
2968
2879
|
|
|
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
2880
|
function compactApproval(approval: JsonRecord) {
|
|
2981
2881
|
return {
|
|
2982
2882
|
id: approval.id ?? approval._id,
|
|
2983
2883
|
title: approval.title,
|
|
2984
2884
|
risk: approval.risk,
|
|
2985
2885
|
status: approval.status,
|
|
2986
|
-
taskId: approval.taskId,
|
|
2987
2886
|
createdAt: approval.createdAt,
|
|
2988
2887
|
};
|
|
2989
2888
|
}
|
|
2990
2889
|
|
|
2991
|
-
function summarizeAgentStatus(
|
|
2992
|
-
status: AgentStatus,
|
|
2993
|
-
tasks: JsonRecord[],
|
|
2994
|
-
host?: string,
|
|
2995
|
-
) {
|
|
2890
|
+
function summarizeAgentStatus(status: AgentStatus, host?: string) {
|
|
2996
2891
|
const agentId = status.agent?.id;
|
|
2997
|
-
const assignedTasks = agentId
|
|
2998
|
-
? tasks.filter((task) => task.assignedAgentId === agentId)
|
|
2999
|
-
: [];
|
|
3000
2892
|
const pendingApprovals = (status.approvals ?? []).filter(
|
|
3001
2893
|
(approval) => approval.status === "pending" && approval.agentId === agentId,
|
|
3002
2894
|
);
|
|
@@ -3009,11 +2901,9 @@ function summarizeAgentStatus(
|
|
|
3009
2901
|
agent: status.agent,
|
|
3010
2902
|
counts: {
|
|
3011
2903
|
...(status.counts ?? {}),
|
|
3012
|
-
myAssignedTasks: assignedTasks.length,
|
|
3013
2904
|
myPendingApprovals: pendingApprovals.length,
|
|
3014
2905
|
},
|
|
3015
2906
|
rules: status.rules ?? [],
|
|
3016
|
-
tasks: assignedTasks.map(compactTask),
|
|
3017
2907
|
pendingApprovals: pendingApprovals.map(compactApproval),
|
|
3018
2908
|
};
|
|
3019
2909
|
}
|
|
@@ -3021,7 +2911,6 @@ function summarizeAgentStatus(
|
|
|
3021
2911
|
function summarizeDevMine(workspaceSlug: string, data: WorkspaceOverview) {
|
|
3022
2912
|
const agentId = option("--agent") ?? data.agents[0]?._id;
|
|
3023
2913
|
const agent = data.agents.find((item) => item._id === agentId) ?? null;
|
|
3024
|
-
const tasks = data.tasks.filter((task) => task.assignedAgentId === agentId);
|
|
3025
2914
|
const pendingApprovals = data.approvals.filter(
|
|
3026
2915
|
(approval) => approval.status === "pending" && approval.agentId === agentId,
|
|
3027
2916
|
);
|
|
@@ -3032,33 +2921,17 @@ function summarizeDevMine(workspaceSlug: string, data: WorkspaceOverview) {
|
|
|
3032
2921
|
counts: {
|
|
3033
2922
|
agents: data.agents.length,
|
|
3034
2923
|
projects: data.projects.length,
|
|
3035
|
-
tasks: data.tasks.length,
|
|
3036
2924
|
pendingApprovals: data.approvals.filter(
|
|
3037
2925
|
(approval) => approval.status === "pending",
|
|
3038
2926
|
).length,
|
|
3039
2927
|
rules: data.rules.length,
|
|
3040
|
-
myAssignedTasks: tasks.length,
|
|
3041
2928
|
myPendingApprovals: pendingApprovals.length,
|
|
3042
2929
|
},
|
|
3043
2930
|
rules: data.rules,
|
|
3044
|
-
tasks: tasks.map(compactTask),
|
|
3045
2931
|
pendingApprovals: pendingApprovals.map(compactApproval),
|
|
3046
2932
|
};
|
|
3047
2933
|
}
|
|
3048
2934
|
|
|
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
2935
|
async function listArtifacts(runtime: Runtime, limit?: number) {
|
|
3063
2936
|
if (runtime.mode === "session") {
|
|
3064
2937
|
try {
|
|
@@ -3840,11 +3713,6 @@ async function main() {
|
|
|
3840
3713
|
return;
|
|
3841
3714
|
}
|
|
3842
3715
|
|
|
3843
|
-
if (command === "tasks" && hasFlag("--help")) {
|
|
3844
|
-
tasksHelp();
|
|
3845
|
-
return;
|
|
3846
|
-
}
|
|
3847
|
-
|
|
3848
3716
|
if (command === "logout" && hasFlag("--help")) {
|
|
3849
3717
|
logoutHelp();
|
|
3850
3718
|
return;
|
|
@@ -4343,50 +4211,6 @@ async function main() {
|
|
|
4343
4211
|
}
|
|
4344
4212
|
|
|
4345
4213
|
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
4214
|
print(await listSuggestedWork(runtime));
|
|
4391
4215
|
return;
|
|
4392
4216
|
}
|
|
@@ -4400,13 +4224,7 @@ async function main() {
|
|
|
4400
4224
|
},
|
|
4401
4225
|
)) as AgentStatus;
|
|
4402
4226
|
if (scopedStatus) {
|
|
4403
|
-
|
|
4404
|
-
api.functions.agentWorkspace.agentListTasks,
|
|
4405
|
-
{
|
|
4406
|
-
sessionToken: runtime.sessionToken,
|
|
4407
|
-
},
|
|
4408
|
-
)) as JsonRecord[];
|
|
4409
|
-
print(summarizeAgentStatus(status, tasks, runtime.host));
|
|
4227
|
+
print(summarizeAgentStatus(status, runtime.host));
|
|
4410
4228
|
return;
|
|
4411
4229
|
}
|
|
4412
4230
|
print(status);
|
|
@@ -4429,26 +4247,6 @@ async function main() {
|
|
|
4429
4247
|
return;
|
|
4430
4248
|
}
|
|
4431
4249
|
|
|
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
4250
|
if (command === "agents") {
|
|
4453
4251
|
if (runtime.mode === "session") {
|
|
4454
4252
|
const status = await runtime.client.query(
|
|
@@ -4508,176 +4306,6 @@ async function main() {
|
|
|
4508
4306
|
return;
|
|
4509
4307
|
}
|
|
4510
4308
|
|
|
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
4309
|
if (command === "approval" && subcommand === "request") {
|
|
4682
4310
|
const title = positional(2);
|
|
4683
4311
|
if (!title) throw new Error("Missing approval title");
|
|
@@ -4690,7 +4318,6 @@ async function main() {
|
|
|
4690
4318
|
title,
|
|
4691
4319
|
reason: option("--reason"),
|
|
4692
4320
|
risk: (option("--risk") ?? "high") as "low" | "medium" | "high",
|
|
4693
|
-
taskId: option("--task") as never,
|
|
4694
4321
|
},
|
|
4695
4322
|
),
|
|
4696
4323
|
);
|
|
@@ -4707,7 +4334,6 @@ async function main() {
|
|
|
4707
4334
|
"Agent requests human approval before a risky action.",
|
|
4708
4335
|
risk: (option("--risk") ?? "high") as "low" | "medium" | "high",
|
|
4709
4336
|
agentId: option("--agent") as never,
|
|
4710
|
-
taskId: option("--task") as never,
|
|
4711
4337
|
},
|
|
4712
4338
|
);
|
|
4713
4339
|
print({ ok: true, approvalId });
|
package/host.ts
CHANGED
|
@@ -14,7 +14,8 @@ export const DEFAULT_HOST = PRODUCTION_HOST;
|
|
|
14
14
|
* deployment + Next.js host backs `https://www.dench.com`.
|
|
15
15
|
*/
|
|
16
16
|
export const PRODUCTION_API_URL = "https://www.dench.com";
|
|
17
|
-
export const PRODUCTION_CONVEX_URL =
|
|
17
|
+
export const PRODUCTION_CONVEX_URL =
|
|
18
|
+
"https://beaming-alligator-67.convex.cloud";
|
|
18
19
|
export const PRODUCTION_GATEWAY_URL = "https://gateway.merseoriginals.com";
|
|
19
20
|
|
|
20
21
|
export type BackendAlias = "production" | "prod" | "staging" | "local";
|
|
@@ -52,6 +53,16 @@ export function isLocalHost(input: string) {
|
|
|
52
53
|
);
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
export function apiHostForDenchHost(input: string | undefined) {
|
|
57
|
+
if (!input?.trim()) return PRODUCTION_API_URL;
|
|
58
|
+
const normalized = normalizeHost(input);
|
|
59
|
+
// `dench.com` redirects to `www.dench.com` in production. Fetch drops the
|
|
60
|
+
// Authorization header across that redirect, so CLI API calls must start on
|
|
61
|
+
// the canonical API origin.
|
|
62
|
+
if (normalized === PRODUCTION_HOST) return PRODUCTION_API_URL;
|
|
63
|
+
return normalized;
|
|
64
|
+
}
|
|
65
|
+
|
|
55
66
|
/**
|
|
56
67
|
* Resolve `local|staging|prod|production|<url>` -> a normalized host
|
|
57
68
|
* origin. Aliases let `dench backend set <alias>` (and `--backend
|
|
@@ -73,7 +84,11 @@ export function resolveBackendAlias(input: string): string {
|
|
|
73
84
|
if (normalized === "staging" || normalized === "stage") {
|
|
74
85
|
return STAGING_HOST;
|
|
75
86
|
}
|
|
76
|
-
if (
|
|
87
|
+
if (
|
|
88
|
+
normalized === "local" ||
|
|
89
|
+
normalized === "localhost" ||
|
|
90
|
+
normalized === "dev"
|
|
91
|
+
) {
|
|
77
92
|
return LOCAL_HOST;
|
|
78
93
|
}
|
|
79
94
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dench.com/cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
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": {
|