@dench.com/cli 2.0.0 → 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/crm.ts +60 -26
- package/dench.ts +245 -467
- package/image.ts +49 -40
- package/lib/enrichment-gateway.ts +2 -2
- package/package.json +1 -1
- package/search.ts +56 -48
- package/tools.ts +59 -34
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
|
|
|
@@ -966,11 +909,12 @@ function backendSnapshot(config: ConfigFile) {
|
|
|
966
909
|
: null;
|
|
967
910
|
const envHost = process.env.DENCH_HOST?.trim() || null;
|
|
968
911
|
const argBackend =
|
|
969
|
-
option("--backend") ??
|
|
912
|
+
option("--backend") ??
|
|
913
|
+
(hasFlag("--prod")
|
|
970
914
|
? "production"
|
|
971
915
|
: hasFlag("--staging")
|
|
972
916
|
? "staging"
|
|
973
|
-
: option("--host") ?? null);
|
|
917
|
+
: (option("--host") ?? null));
|
|
974
918
|
|
|
975
919
|
let source: "flag" | "env" | "config" | "default";
|
|
976
920
|
if (argBackend) source = "flag";
|
|
@@ -1078,7 +1022,9 @@ async function backendSet() {
|
|
|
1078
1022
|
"Local backend selected. dench will now also load .env / .env.local from the workspace so GATEWAY_URL etc. are picked up.",
|
|
1079
1023
|
);
|
|
1080
1024
|
}
|
|
1081
|
-
print(
|
|
1025
|
+
print(
|
|
1026
|
+
"Future `dench` commands without --prod/--staging/--host will target this backend.",
|
|
1027
|
+
);
|
|
1082
1028
|
}
|
|
1083
1029
|
|
|
1084
1030
|
async function backendClear() {
|
|
@@ -1706,8 +1652,7 @@ async function signinViaBrowser(input: {
|
|
|
1706
1652
|
agentName: input.agentName,
|
|
1707
1653
|
agentKind: input.agentKind,
|
|
1708
1654
|
intent: input.intent,
|
|
1709
|
-
proposedOrganizationName:
|
|
1710
|
-
input.proposedOrganizationName ?? undefined,
|
|
1655
|
+
proposedOrganizationName: input.proposedOrganizationName ?? undefined,
|
|
1711
1656
|
requestedOrganizationSelector: input.orgSelector ?? undefined,
|
|
1712
1657
|
userAgent: "@dench.com/cli",
|
|
1713
1658
|
},
|
|
@@ -1841,7 +1786,8 @@ async function signinViaOtp(input: {
|
|
|
1841
1786
|
// resolvable (single admin org or create_workspace intent) and the
|
|
1842
1787
|
// server hands us a session, OR we get an auth token + list and
|
|
1843
1788
|
// need a third call.
|
|
1844
|
-
const code =
|
|
1789
|
+
const code =
|
|
1790
|
+
option("--otp-code")?.trim() || (await promptLine("Paste OTP: "));
|
|
1845
1791
|
if (!/^\d{6}$/.test(code)) {
|
|
1846
1792
|
throw new CliError("OTP code must be exactly 6 digits.", {
|
|
1847
1793
|
code: "invalid_otp_code",
|
|
@@ -1857,8 +1803,7 @@ async function signinViaOtp(input: {
|
|
|
1857
1803
|
agentKind: input.agentKind,
|
|
1858
1804
|
sessionTokenHash: input.sessionTokenHash,
|
|
1859
1805
|
intent: input.intent,
|
|
1860
|
-
proposedOrganizationName:
|
|
1861
|
-
input.proposedOrganizationName ?? undefined,
|
|
1806
|
+
proposedOrganizationName: input.proposedOrganizationName ?? undefined,
|
|
1862
1807
|
organizationSelector: input.orgSelector ?? undefined,
|
|
1863
1808
|
userAgent: "@dench.com/cli",
|
|
1864
1809
|
}),
|
|
@@ -1878,8 +1823,15 @@ async function signinViaOtp(input: {
|
|
|
1878
1823
|
|
|
1879
1824
|
// Branch A: server minted the session in one shot.
|
|
1880
1825
|
if (result.kind === "completed") {
|
|
1881
|
-
assertOtpCompletedOrgMatchesSelector(
|
|
1882
|
-
|
|
1826
|
+
assertOtpCompletedOrgMatchesSelector(
|
|
1827
|
+
result.organization,
|
|
1828
|
+
input.orgSelector,
|
|
1829
|
+
);
|
|
1830
|
+
await finalizeOtpSession(
|
|
1831
|
+
input,
|
|
1832
|
+
result.organization,
|
|
1833
|
+
result.sessionExpiresAt,
|
|
1834
|
+
);
|
|
1883
1835
|
return;
|
|
1884
1836
|
}
|
|
1885
1837
|
|
|
@@ -2020,7 +1972,11 @@ async function resolveOrgChoiceForOtp(input: {
|
|
|
2020
1972
|
|
|
2021
1973
|
const answer = await promptLine("Pick a number: ");
|
|
2022
1974
|
const choice = Number(answer);
|
|
2023
|
-
if (
|
|
1975
|
+
if (
|
|
1976
|
+
!Number.isFinite(choice) ||
|
|
1977
|
+
choice < 1 ||
|
|
1978
|
+
choice > input.organizations.length + 1
|
|
1979
|
+
) {
|
|
2024
1980
|
throw new CliError(`Invalid choice: ${answer}`, {
|
|
2025
1981
|
code: "invalid_org_choice",
|
|
2026
1982
|
});
|
|
@@ -2234,9 +2190,7 @@ async function denchUpgrade(runtime: Runtime) {
|
|
|
2234
2190
|
if (updatedInPlace) {
|
|
2235
2191
|
const message = `Upgraded to Dench ${tierFlag === "pro" ? "Pro" : "Max"} in place — no Stripe Checkout needed.`;
|
|
2236
2192
|
print(
|
|
2237
|
-
json
|
|
2238
|
-
? { ok: true, updated: true, tier: tierFlag, message }
|
|
2239
|
-
: message,
|
|
2193
|
+
json ? { ok: true, updated: true, tier: tierFlag, message } : message,
|
|
2240
2194
|
);
|
|
2241
2195
|
return;
|
|
2242
2196
|
}
|
|
@@ -2487,6 +2441,103 @@ function requireAuthenticatedRuntime(
|
|
|
2487
2441
|
throw loginRequiredError(command);
|
|
2488
2442
|
}
|
|
2489
2443
|
|
|
2444
|
+
type GatewayCommandAuth = {
|
|
2445
|
+
bearerToken: string;
|
|
2446
|
+
gatewayBaseUrl?: string;
|
|
2447
|
+
};
|
|
2448
|
+
|
|
2449
|
+
function gatewayBaseUrlForCli(value: unknown): string | undefined {
|
|
2450
|
+
if (typeof value !== "string") return undefined;
|
|
2451
|
+
const trimmed = value.trim().replace(/\/+$/, "");
|
|
2452
|
+
if (!trimmed) return undefined;
|
|
2453
|
+
// The desktop endpoint returns a `/v1` base; CLI gateway modules append
|
|
2454
|
+
// `/v1/...` paths themselves, so normalize to the root origin here.
|
|
2455
|
+
return trimmed.replace(/\/v1$/, "");
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2458
|
+
async function parseJsonResponseBody(response: Response): Promise<JsonRecord> {
|
|
2459
|
+
const text = await response.text().catch(() => "");
|
|
2460
|
+
if (!text.trim()) return {};
|
|
2461
|
+
try {
|
|
2462
|
+
const parsed = JSON.parse(text);
|
|
2463
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
2464
|
+
? (parsed as JsonRecord)
|
|
2465
|
+
: {};
|
|
2466
|
+
} catch {
|
|
2467
|
+
return { error: text };
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
|
|
2471
|
+
function gatewayAuthError(
|
|
2472
|
+
command: string,
|
|
2473
|
+
response: Response,
|
|
2474
|
+
body: JsonRecord,
|
|
2475
|
+
) {
|
|
2476
|
+
const code =
|
|
2477
|
+
typeof body.error === "string" && body.error.trim()
|
|
2478
|
+
? body.error.trim()
|
|
2479
|
+
: `gateway_key_${response.status}`;
|
|
2480
|
+
if (response.status === 403 && code === "no_active_subscription") {
|
|
2481
|
+
return new CliError(`${command} requires a paid Dench workspace`, {
|
|
2482
|
+
code: "paid_workspace_required",
|
|
2483
|
+
nextActions: [
|
|
2484
|
+
"Run dench upgrade --tier pro or dench upgrade --tier max, then retry.",
|
|
2485
|
+
],
|
|
2486
|
+
});
|
|
2487
|
+
}
|
|
2488
|
+
if (response.status === 401) {
|
|
2489
|
+
return loginRequiredError(command);
|
|
2490
|
+
}
|
|
2491
|
+
return new CliError(`${command} could not get a gateway key (${code})`, {
|
|
2492
|
+
code,
|
|
2493
|
+
status: response.status,
|
|
2494
|
+
nextActions: [
|
|
2495
|
+
"Confirm this agent is signed in to the intended workspace.",
|
|
2496
|
+
"If the workspace is paid, retry after a minute in case gateway key provisioning is still finishing.",
|
|
2497
|
+
],
|
|
2498
|
+
});
|
|
2499
|
+
}
|
|
2500
|
+
|
|
2501
|
+
async function resolveGatewayCommandAuth(
|
|
2502
|
+
runtime: Runtime,
|
|
2503
|
+
command: string,
|
|
2504
|
+
): Promise<GatewayCommandAuth> {
|
|
2505
|
+
if (runtime.mode === "apiKey") {
|
|
2506
|
+
return { bearerToken: runtime.sessionToken };
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
if (runtime.mode === "session") {
|
|
2510
|
+
const response = await fetch(
|
|
2511
|
+
`${runtime.host.replace(/\/+$/, "")}/api/desktop/organizations/gateway-key`,
|
|
2512
|
+
{
|
|
2513
|
+
headers: {
|
|
2514
|
+
accept: "application/json",
|
|
2515
|
+
authorization: `Bearer ${runtime.sessionToken}`,
|
|
2516
|
+
},
|
|
2517
|
+
},
|
|
2518
|
+
);
|
|
2519
|
+
const body = await parseJsonResponseBody(response);
|
|
2520
|
+
if (!response.ok) {
|
|
2521
|
+
throw gatewayAuthError(command, response, body);
|
|
2522
|
+
}
|
|
2523
|
+
const gatewayKey =
|
|
2524
|
+
typeof body.gatewayKey === "string" ? body.gatewayKey.trim() : "";
|
|
2525
|
+
if (!gatewayKey) {
|
|
2526
|
+
throw new CliError(`${command} could not get a gateway key`, {
|
|
2527
|
+
code: "missing_gateway_key",
|
|
2528
|
+
});
|
|
2529
|
+
}
|
|
2530
|
+
return {
|
|
2531
|
+
bearerToken: gatewayKey,
|
|
2532
|
+
gatewayBaseUrl: gatewayBaseUrlForCli(body.gatewayBaseUrl),
|
|
2533
|
+
};
|
|
2534
|
+
}
|
|
2535
|
+
|
|
2536
|
+
const envApiKey = process.env.DENCH_API_KEY?.trim();
|
|
2537
|
+
if (envApiKey) return { bearerToken: envApiKey };
|
|
2538
|
+
throw loginRequiredError(command);
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2490
2541
|
function encodeDevCrmSessionToken(args: {
|
|
2491
2542
|
workspaceSlug: string;
|
|
2492
2543
|
devKey: string;
|
|
@@ -2508,10 +2559,9 @@ function agentSessionRequiredError(command: string) {
|
|
|
2508
2559
|
}
|
|
2509
2560
|
|
|
2510
2561
|
/**
|
|
2511
|
-
*
|
|
2512
|
-
*
|
|
2513
|
-
*
|
|
2514
|
-
* 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.
|
|
2515
2565
|
*
|
|
2516
2566
|
* Asserts away the `apiKey` mode so the caller's downstream type
|
|
2517
2567
|
* narrowing (e.g. `runtime.workspaceArgs`) keeps working.
|
|
@@ -2602,19 +2652,30 @@ function workspaceUrls(host: string, workspaceSlug: string | undefined) {
|
|
|
2602
2652
|
function nextContextCommands() {
|
|
2603
2653
|
return [
|
|
2604
2654
|
"dench context --json",
|
|
2605
|
-
"dench
|
|
2606
|
-
'dench log "Brief progress update"',
|
|
2655
|
+
"dench crm entries list task --json",
|
|
2607
2656
|
'dench tool search "what you need" --toolkit <app>',
|
|
2608
2657
|
'dench approval request "Risky action to approve"',
|
|
2609
2658
|
];
|
|
2610
2659
|
}
|
|
2611
2660
|
|
|
2612
|
-
async function connectedAppsContext(
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2661
|
+
async function connectedAppsContext(runtime: Runtime) {
|
|
2662
|
+
try {
|
|
2663
|
+
const gatewayAuth = await resolveGatewayCommandAuth(
|
|
2664
|
+
runtime,
|
|
2665
|
+
"dench context",
|
|
2666
|
+
);
|
|
2667
|
+
return fetchConnectedAppsSummary({
|
|
2668
|
+
bearerToken: gatewayAuth.bearerToken,
|
|
2669
|
+
gatewayBaseUrl: gatewayAuth.gatewayBaseUrl,
|
|
2670
|
+
});
|
|
2671
|
+
} catch (error) {
|
|
2672
|
+
return {
|
|
2673
|
+
available: false,
|
|
2674
|
+
reason: errorMessage(error),
|
|
2675
|
+
count: 0,
|
|
2676
|
+
connections: [],
|
|
2677
|
+
};
|
|
2678
|
+
}
|
|
2618
2679
|
}
|
|
2619
2680
|
|
|
2620
2681
|
async function buildContext(runtime: Runtime) {
|
|
@@ -2677,15 +2738,6 @@ function formatContext(context: JsonRecord) {
|
|
|
2677
2738
|
const workspace = asRecord(context.workspace);
|
|
2678
2739
|
const connectedApps = asRecord(context.connectedApps);
|
|
2679
2740
|
const connections = asRecordArray(connectedApps?.connections);
|
|
2680
|
-
const tasksRecord = asRecord(context.tasks);
|
|
2681
|
-
const tasks =
|
|
2682
|
-
asRecordArray(tasksRecord?.assignedToMe).length > 0 ||
|
|
2683
|
-
asRecordArray(tasksRecord?.open).length > 0
|
|
2684
|
-
? [
|
|
2685
|
-
...asRecordArray(tasksRecord?.assignedToMe),
|
|
2686
|
-
...asRecordArray(tasksRecord?.open),
|
|
2687
|
-
]
|
|
2688
|
-
: asRecordArray(context.tasks);
|
|
2689
2741
|
const approvals = asRecordArray(context.pendingApprovals);
|
|
2690
2742
|
const suggestedWork = asRecordArray(context.suggestedWork);
|
|
2691
2743
|
const memories = asRecordArray(context.memory);
|
|
@@ -2708,10 +2760,7 @@ function formatContext(context: JsonRecord) {
|
|
|
2708
2760
|
`Agent: ${agentDisplayName(agent)}${
|
|
2709
2761
|
stringField(agent, "kind") ? ` [${stringField(agent, "kind")}]` : ""
|
|
2710
2762
|
}`,
|
|
2711
|
-
`Counts: ${formatCount(
|
|
2712
|
-
counts?.myAssignedTasks ??
|
|
2713
|
-
asRecordArray(tasksRecord?.assignedToMe).length,
|
|
2714
|
-
)} assigned to me, ${formatCount(
|
|
2763
|
+
`Counts: ${formatCount(
|
|
2715
2764
|
counts?.myPendingApprovals ?? approvals.length,
|
|
2716
2765
|
)} pending approvals`,
|
|
2717
2766
|
];
|
|
@@ -2725,21 +2774,6 @@ function formatContext(context: JsonRecord) {
|
|
|
2725
2774
|
);
|
|
2726
2775
|
}
|
|
2727
2776
|
|
|
2728
|
-
lines.push("", "Assigned tasks:");
|
|
2729
|
-
|
|
2730
|
-
if (tasks.length === 0) {
|
|
2731
|
-
lines.push(" none");
|
|
2732
|
-
} else {
|
|
2733
|
-
lines.push(
|
|
2734
|
-
...tasks
|
|
2735
|
-
.slice(0, 5)
|
|
2736
|
-
.map(
|
|
2737
|
-
(task) =>
|
|
2738
|
-
` - ${stringField(task, "title") ?? stringField(task, "id") ?? "untitled"} [${stringField(task, "status") ?? "unknown"}]`,
|
|
2739
|
-
),
|
|
2740
|
-
);
|
|
2741
|
-
}
|
|
2742
|
-
|
|
2743
2777
|
lines.push("", "Pending approvals requested by me:");
|
|
2744
2778
|
if (approvals.length === 0) {
|
|
2745
2779
|
lines.push(" none");
|
|
@@ -2838,7 +2872,6 @@ function summarizeDevOverview(workspaceSlug: string, data: WorkspaceOverview) {
|
|
|
2838
2872
|
workspace: workspaceSlug,
|
|
2839
2873
|
agents: data.agents.length,
|
|
2840
2874
|
projects: data.projects.length,
|
|
2841
|
-
tasks: data.tasks.length,
|
|
2842
2875
|
approvals: data.approvals.filter(
|
|
2843
2876
|
(approval) => approval.status === "pending",
|
|
2844
2877
|
).length,
|
|
@@ -2846,37 +2879,18 @@ function summarizeDevOverview(workspaceSlug: string, data: WorkspaceOverview) {
|
|
|
2846
2879
|
};
|
|
2847
2880
|
}
|
|
2848
2881
|
|
|
2849
|
-
function compactTask(task: JsonRecord) {
|
|
2850
|
-
return {
|
|
2851
|
-
id: task._id ?? task.id,
|
|
2852
|
-
title: task.title,
|
|
2853
|
-
status: task.status,
|
|
2854
|
-
priority: task.priority,
|
|
2855
|
-
risk: task.risk,
|
|
2856
|
-
assignedAgentId: task.assignedAgentId,
|
|
2857
|
-
};
|
|
2858
|
-
}
|
|
2859
|
-
|
|
2860
2882
|
function compactApproval(approval: JsonRecord) {
|
|
2861
2883
|
return {
|
|
2862
2884
|
id: approval.id ?? approval._id,
|
|
2863
2885
|
title: approval.title,
|
|
2864
2886
|
risk: approval.risk,
|
|
2865
2887
|
status: approval.status,
|
|
2866
|
-
taskId: approval.taskId,
|
|
2867
2888
|
createdAt: approval.createdAt,
|
|
2868
2889
|
};
|
|
2869
2890
|
}
|
|
2870
2891
|
|
|
2871
|
-
function summarizeAgentStatus(
|
|
2872
|
-
status: AgentStatus,
|
|
2873
|
-
tasks: JsonRecord[],
|
|
2874
|
-
host?: string,
|
|
2875
|
-
) {
|
|
2892
|
+
function summarizeAgentStatus(status: AgentStatus, host?: string) {
|
|
2876
2893
|
const agentId = status.agent?.id;
|
|
2877
|
-
const assignedTasks = agentId
|
|
2878
|
-
? tasks.filter((task) => task.assignedAgentId === agentId)
|
|
2879
|
-
: [];
|
|
2880
2894
|
const pendingApprovals = (status.approvals ?? []).filter(
|
|
2881
2895
|
(approval) => approval.status === "pending" && approval.agentId === agentId,
|
|
2882
2896
|
);
|
|
@@ -2889,11 +2903,9 @@ function summarizeAgentStatus(
|
|
|
2889
2903
|
agent: status.agent,
|
|
2890
2904
|
counts: {
|
|
2891
2905
|
...(status.counts ?? {}),
|
|
2892
|
-
myAssignedTasks: assignedTasks.length,
|
|
2893
2906
|
myPendingApprovals: pendingApprovals.length,
|
|
2894
2907
|
},
|
|
2895
2908
|
rules: status.rules ?? [],
|
|
2896
|
-
tasks: assignedTasks.map(compactTask),
|
|
2897
2909
|
pendingApprovals: pendingApprovals.map(compactApproval),
|
|
2898
2910
|
};
|
|
2899
2911
|
}
|
|
@@ -2901,7 +2913,6 @@ function summarizeAgentStatus(
|
|
|
2901
2913
|
function summarizeDevMine(workspaceSlug: string, data: WorkspaceOverview) {
|
|
2902
2914
|
const agentId = option("--agent") ?? data.agents[0]?._id;
|
|
2903
2915
|
const agent = data.agents.find((item) => item._id === agentId) ?? null;
|
|
2904
|
-
const tasks = data.tasks.filter((task) => task.assignedAgentId === agentId);
|
|
2905
2916
|
const pendingApprovals = data.approvals.filter(
|
|
2906
2917
|
(approval) => approval.status === "pending" && approval.agentId === agentId,
|
|
2907
2918
|
);
|
|
@@ -2912,33 +2923,17 @@ function summarizeDevMine(workspaceSlug: string, data: WorkspaceOverview) {
|
|
|
2912
2923
|
counts: {
|
|
2913
2924
|
agents: data.agents.length,
|
|
2914
2925
|
projects: data.projects.length,
|
|
2915
|
-
tasks: data.tasks.length,
|
|
2916
2926
|
pendingApprovals: data.approvals.filter(
|
|
2917
2927
|
(approval) => approval.status === "pending",
|
|
2918
2928
|
).length,
|
|
2919
2929
|
rules: data.rules.length,
|
|
2920
|
-
myAssignedTasks: tasks.length,
|
|
2921
2930
|
myPendingApprovals: pendingApprovals.length,
|
|
2922
2931
|
},
|
|
2923
2932
|
rules: data.rules,
|
|
2924
|
-
tasks: tasks.map(compactTask),
|
|
2925
2933
|
pendingApprovals: pendingApprovals.map(compactApproval),
|
|
2926
2934
|
};
|
|
2927
2935
|
}
|
|
2928
2936
|
|
|
2929
|
-
async function defaultDevAgentId(
|
|
2930
|
-
runtime: Awaited<ReturnType<typeof getRuntime>>,
|
|
2931
|
-
) {
|
|
2932
|
-
const data = await devOverview(runtime);
|
|
2933
|
-
const agent = data.agents[0];
|
|
2934
|
-
if (!agent) {
|
|
2935
|
-
throw new Error(
|
|
2936
|
-
'No agent registered yet. Run: dench signin --kind <kind> --name "AI Agent - Project"',
|
|
2937
|
-
);
|
|
2938
|
-
}
|
|
2939
|
-
return agent._id;
|
|
2940
|
-
}
|
|
2941
|
-
|
|
2942
2937
|
async function listArtifacts(runtime: Runtime, limit?: number) {
|
|
2943
2938
|
if (runtime.mode === "session") {
|
|
2944
2939
|
try {
|
|
@@ -3024,26 +3019,12 @@ function normalizeFilesPath(input: string): string {
|
|
|
3024
3019
|
return cleaned;
|
|
3025
3020
|
}
|
|
3026
3021
|
|
|
3027
|
-
function
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
const apiKey = filesApiKey(runtime);
|
|
3034
|
-
if (!apiKey) {
|
|
3035
|
-
throw new CliError(
|
|
3036
|
-
`${command} needs DENCH_API_KEY (or a sandbox-baked api-key session). It bypasses the user-session auth path.`,
|
|
3037
|
-
{
|
|
3038
|
-
code: "files_api_key_required",
|
|
3039
|
-
nextActions: [
|
|
3040
|
-
"Run inside a Dench sandbox where DENCH_API_KEY is baked in.",
|
|
3041
|
-
"Or export DENCH_API_KEY=<key> first (see dench signin output).",
|
|
3042
|
-
],
|
|
3043
|
-
},
|
|
3044
|
-
);
|
|
3045
|
-
}
|
|
3046
|
-
return apiKey;
|
|
3022
|
+
async function requireFilesApiKey(
|
|
3023
|
+
runtime: Runtime,
|
|
3024
|
+
command: string,
|
|
3025
|
+
): Promise<string> {
|
|
3026
|
+
const auth = await resolveGatewayCommandAuth(runtime, command);
|
|
3027
|
+
return auth.bearerToken;
|
|
3047
3028
|
}
|
|
3048
3029
|
|
|
3049
3030
|
type FileTreeRow = {
|
|
@@ -3143,7 +3124,7 @@ async function uploadConvexFileBytes(
|
|
|
3143
3124
|
|
|
3144
3125
|
async function runFilesLs() {
|
|
3145
3126
|
const runtime = await getRuntime();
|
|
3146
|
-
const apiKey = requireFilesApiKey(runtime, "dench files ls");
|
|
3127
|
+
const apiKey = await requireFilesApiKey(runtime, "dench files ls");
|
|
3147
3128
|
const target = normalizeFilesPath(positional(2) ?? "/");
|
|
3148
3129
|
const recursive = hasFlag("--recursive") || hasFlag("-r");
|
|
3149
3130
|
const rows = recursive
|
|
@@ -3180,7 +3161,7 @@ async function runFilesLs() {
|
|
|
3180
3161
|
|
|
3181
3162
|
async function runFilesMv() {
|
|
3182
3163
|
const runtime = await getRuntime();
|
|
3183
|
-
const apiKey = requireFilesApiKey(runtime, "dench files mv");
|
|
3164
|
+
const apiKey = await requireFilesApiKey(runtime, "dench files mv");
|
|
3184
3165
|
const fromRaw = positional(2);
|
|
3185
3166
|
const toRaw = positional(3);
|
|
3186
3167
|
if (!fromRaw || !toRaw) {
|
|
@@ -3252,7 +3233,7 @@ async function runFilesMv() {
|
|
|
3252
3233
|
|
|
3253
3234
|
async function runFilesRm() {
|
|
3254
3235
|
const runtime = await getRuntime();
|
|
3255
|
-
const apiKey = requireFilesApiKey(runtime, "dench files rm");
|
|
3236
|
+
const apiKey = await requireFilesApiKey(runtime, "dench files rm");
|
|
3256
3237
|
const targetRaw = positional(2);
|
|
3257
3238
|
if (!targetRaw) {
|
|
3258
3239
|
throw new CliError("Usage: dench files rm <path> [--recursive]", {
|
|
@@ -3439,7 +3420,7 @@ async function* walkLocalFiles(
|
|
|
3439
3420
|
|
|
3440
3421
|
async function runStage() {
|
|
3441
3422
|
const runtime = await getRuntime();
|
|
3442
|
-
const apiKey = requireFilesApiKey(runtime, "dench stage");
|
|
3423
|
+
const apiKey = await requireFilesApiKey(runtime, "dench stage");
|
|
3443
3424
|
const localRaw = positional(1);
|
|
3444
3425
|
const destRaw = positional(2);
|
|
3445
3426
|
if (!localRaw) {
|
|
@@ -3694,15 +3675,13 @@ async function main() {
|
|
|
3694
3675
|
// clean redirect to the new unified surface so old `npx` caches and
|
|
3695
3676
|
// pre-existing agent prompts get a one-line nudge instead of an
|
|
3696
3677
|
// opaque "Unknown command" error.
|
|
3697
|
-
if (
|
|
3698
|
-
isDeprecatedAuthCommand
|
|
3699
|
-
) {
|
|
3678
|
+
if (isDeprecatedAuthCommand) {
|
|
3700
3679
|
throw new CliError(
|
|
3701
3680
|
`\`dench ${command}\` was removed in @dench.com/cli v2. Run \`dench signin\` instead.`,
|
|
3702
3681
|
{
|
|
3703
3682
|
code: "deprecated_command",
|
|
3704
3683
|
nextActions: [
|
|
3705
|
-
|
|
3684
|
+
"Run `dench signin` to connect this agent to an existing workspace.",
|
|
3706
3685
|
'Run `dench signin --new-workspace --org-name "<name>"` to create a free CRM-only workspace.',
|
|
3707
3686
|
"Upgrade the CLI globally with `npm install -g @dench.com/cli@latest`.",
|
|
3708
3687
|
],
|
|
@@ -3736,20 +3715,12 @@ async function main() {
|
|
|
3736
3715
|
return;
|
|
3737
3716
|
}
|
|
3738
3717
|
|
|
3739
|
-
if (command === "tasks" && hasFlag("--help")) {
|
|
3740
|
-
tasksHelp();
|
|
3741
|
-
return;
|
|
3742
|
-
}
|
|
3743
|
-
|
|
3744
3718
|
if (command === "logout" && hasFlag("--help")) {
|
|
3745
3719
|
logoutHelp();
|
|
3746
3720
|
return;
|
|
3747
3721
|
}
|
|
3748
3722
|
|
|
3749
|
-
if (
|
|
3750
|
-
command === "backend" &&
|
|
3751
|
-
(subcommand === "help" || hasFlag("--help"))
|
|
3752
|
-
) {
|
|
3723
|
+
if (command === "backend" && (subcommand === "help" || hasFlag("--help"))) {
|
|
3753
3724
|
backendHelp();
|
|
3754
3725
|
return;
|
|
3755
3726
|
}
|
|
@@ -3776,18 +3747,38 @@ async function main() {
|
|
|
3776
3747
|
// `requireCrmAccess` (convex/lib/crm/access.ts) dispatches on the
|
|
3777
3748
|
// bearer prefix and resolves the org for both.
|
|
3778
3749
|
if (runtime.mode === "dev") {
|
|
3750
|
+
const gatewayAuth =
|
|
3751
|
+
subArgs[0] === "enrich"
|
|
3752
|
+
? await resolveGatewayCommandAuth(runtime, "dench crm enrich")
|
|
3753
|
+
: undefined;
|
|
3779
3754
|
await runCrmCommand({
|
|
3780
3755
|
convex: runtime.client,
|
|
3781
3756
|
args: subArgs,
|
|
3782
3757
|
sessionToken: encodeDevCrmSessionToken(runtime.workspaceArgs),
|
|
3758
|
+
enrichmentGateway: gatewayAuth
|
|
3759
|
+
? {
|
|
3760
|
+
apiKey: gatewayAuth.bearerToken,
|
|
3761
|
+
baseUrl: gatewayAuth.gatewayBaseUrl,
|
|
3762
|
+
}
|
|
3763
|
+
: undefined,
|
|
3783
3764
|
});
|
|
3784
3765
|
return;
|
|
3785
3766
|
}
|
|
3786
3767
|
const authedRuntime = requireAuthenticatedRuntime(runtime, "dench crm");
|
|
3768
|
+
const gatewayAuth =
|
|
3769
|
+
subArgs[0] === "enrich"
|
|
3770
|
+
? await resolveGatewayCommandAuth(authedRuntime, "dench crm enrich")
|
|
3771
|
+
: undefined;
|
|
3787
3772
|
await runCrmCommand({
|
|
3788
3773
|
convex: authedRuntime.client,
|
|
3789
3774
|
args: subArgs,
|
|
3790
3775
|
sessionToken: authedRuntime.sessionToken,
|
|
3776
|
+
enrichmentGateway: gatewayAuth
|
|
3777
|
+
? {
|
|
3778
|
+
apiKey: gatewayAuth.bearerToken,
|
|
3779
|
+
baseUrl: gatewayAuth.gatewayBaseUrl,
|
|
3780
|
+
}
|
|
3781
|
+
: undefined,
|
|
3791
3782
|
});
|
|
3792
3783
|
return;
|
|
3793
3784
|
}
|
|
@@ -3820,10 +3811,7 @@ async function main() {
|
|
|
3820
3811
|
});
|
|
3821
3812
|
return;
|
|
3822
3813
|
}
|
|
3823
|
-
const authedRuntime = requireAuthenticatedRuntime(
|
|
3824
|
-
runtime,
|
|
3825
|
-
"dench members",
|
|
3826
|
-
);
|
|
3814
|
+
const authedRuntime = requireAuthenticatedRuntime(runtime, "dench members");
|
|
3827
3815
|
await runMembersCommand({
|
|
3828
3816
|
convex: authedRuntime.client,
|
|
3829
3817
|
args: subArgs,
|
|
@@ -3848,44 +3836,76 @@ async function main() {
|
|
|
3848
3836
|
}
|
|
3849
3837
|
|
|
3850
3838
|
if (command === "search") {
|
|
3851
|
-
// `dench search` talks straight to the gateway over HTTP using
|
|
3852
|
-
// DENCH_API_KEY; it deliberately bypasses requireSessionRuntime so
|
|
3853
|
-
// it works in any sandbox / CI environment that has the key.
|
|
3854
3839
|
const subArgs = args.slice(args.indexOf("search") + 1);
|
|
3855
3840
|
const filteredSubArgs = subArgs.filter((a) => a !== "--json");
|
|
3856
3841
|
const { runSearchCommand } = await import("./search");
|
|
3857
|
-
|
|
3842
|
+
const sub = filteredSubArgs[0];
|
|
3843
|
+
if (!sub || sub === "help" || sub === "--help" || sub === "-h") {
|
|
3844
|
+
await runSearchCommand({ args: filteredSubArgs, jsonOutput: json });
|
|
3845
|
+
return;
|
|
3846
|
+
}
|
|
3847
|
+
const runtime = await getRuntime();
|
|
3848
|
+
const gatewayAuth = await resolveGatewayCommandAuth(
|
|
3849
|
+
runtime,
|
|
3850
|
+
"dench search",
|
|
3851
|
+
);
|
|
3852
|
+
await runSearchCommand({
|
|
3853
|
+
args: filteredSubArgs,
|
|
3854
|
+
jsonOutput: json,
|
|
3855
|
+
bearerToken: gatewayAuth.bearerToken,
|
|
3856
|
+
gatewayBaseUrl: gatewayAuth.gatewayBaseUrl,
|
|
3857
|
+
});
|
|
3858
3858
|
return;
|
|
3859
3859
|
}
|
|
3860
3860
|
|
|
3861
3861
|
if (command === "image") {
|
|
3862
|
-
// `dench image generate|edit` mirrors `dench search`: straight HTTP
|
|
3863
|
-
// to the gateway with DENCH_API_KEY, no Convex session required.
|
|
3864
|
-
// The gateway writes the bytes to Convex Storage on success; we
|
|
3865
|
-
// also drop them on local disk so the next bash command sees them.
|
|
3866
3862
|
const subArgs = args.slice(args.indexOf("image") + 1);
|
|
3867
3863
|
const filteredSubArgs = subArgs.filter((a) => a !== "--json");
|
|
3868
3864
|
const { runImageCommand } = await import("./image");
|
|
3869
|
-
|
|
3865
|
+
const sub = filteredSubArgs[0];
|
|
3866
|
+
if (!sub || sub === "help" || sub === "--help" || sub === "-h") {
|
|
3867
|
+
await runImageCommand({ args: filteredSubArgs, jsonOutput: json });
|
|
3868
|
+
return;
|
|
3869
|
+
}
|
|
3870
|
+
const runtime = await getRuntime();
|
|
3871
|
+
const gatewayAuth = await resolveGatewayCommandAuth(runtime, "dench image");
|
|
3872
|
+
await runImageCommand({
|
|
3873
|
+
args: filteredSubArgs,
|
|
3874
|
+
jsonOutput: json,
|
|
3875
|
+
bearerToken: gatewayAuth.bearerToken,
|
|
3876
|
+
gatewayBaseUrl: gatewayAuth.gatewayBaseUrl,
|
|
3877
|
+
});
|
|
3870
3878
|
return;
|
|
3871
3879
|
}
|
|
3872
3880
|
|
|
3873
3881
|
if (command === "apps") {
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3882
|
+
const runtime = await getRuntime();
|
|
3883
|
+
const gatewayAuth = await resolveGatewayCommandAuth(runtime, "dench apps");
|
|
3884
|
+
await runToolCommand({
|
|
3885
|
+
args: ["status"],
|
|
3886
|
+
jsonOutput: json,
|
|
3887
|
+
bearerToken: gatewayAuth.bearerToken,
|
|
3888
|
+
gatewayBaseUrl: gatewayAuth.gatewayBaseUrl,
|
|
3889
|
+
});
|
|
3878
3890
|
return;
|
|
3879
3891
|
}
|
|
3880
3892
|
|
|
3881
3893
|
if (command === "tool") {
|
|
3882
|
-
// `dench tool {status,connect,search,run,disconnect}` is the model-facing
|
|
3883
|
-
// composio surface and only needs DENCH_API_KEY (Bearer) on the
|
|
3884
|
-
// gateway. Bypasses requireSessionRuntime entirely so it works in
|
|
3885
|
-
// every sandbox / API-key context.
|
|
3886
3894
|
const subArgs = stripRuntimeFlags(args.slice(args.indexOf("tool") + 1));
|
|
3887
3895
|
const filteredSubArgs = subArgs.filter((a) => a !== "--json");
|
|
3888
|
-
|
|
3896
|
+
const sub = filteredSubArgs[0];
|
|
3897
|
+
if (!sub || sub === "help" || sub === "--help" || sub === "-h") {
|
|
3898
|
+
await runToolCommand({ args: filteredSubArgs, jsonOutput: json });
|
|
3899
|
+
return;
|
|
3900
|
+
}
|
|
3901
|
+
const runtime = await getRuntime();
|
|
3902
|
+
const gatewayAuth = await resolveGatewayCommandAuth(runtime, "dench tool");
|
|
3903
|
+
await runToolCommand({
|
|
3904
|
+
args: filteredSubArgs,
|
|
3905
|
+
jsonOutput: json,
|
|
3906
|
+
bearerToken: gatewayAuth.bearerToken,
|
|
3907
|
+
gatewayBaseUrl: gatewayAuth.gatewayBaseUrl,
|
|
3908
|
+
});
|
|
3889
3909
|
return;
|
|
3890
3910
|
}
|
|
3891
3911
|
|
|
@@ -4193,50 +4213,6 @@ async function main() {
|
|
|
4193
4213
|
}
|
|
4194
4214
|
|
|
4195
4215
|
if (command === "suggested-work") {
|
|
4196
|
-
if (subcommand === "task") {
|
|
4197
|
-
const sessionRuntime = requireSessionRuntime(
|
|
4198
|
-
runtime,
|
|
4199
|
-
"dench suggested-work task",
|
|
4200
|
-
);
|
|
4201
|
-
const artifactId = positional(2);
|
|
4202
|
-
if (!artifactId) {
|
|
4203
|
-
throw new Error("Usage: dench suggested-work task <artifactId>");
|
|
4204
|
-
}
|
|
4205
|
-
print(
|
|
4206
|
-
await sessionRuntime.client
|
|
4207
|
-
.mutation(api.functions.agentWorkspace.agentConvertSuggestionToTask, {
|
|
4208
|
-
sessionToken: sessionRuntime.sessionToken,
|
|
4209
|
-
artifactId: artifactId as never,
|
|
4210
|
-
})
|
|
4211
|
-
.catch(async (error) => {
|
|
4212
|
-
if (!isMissingConvexFunction(error)) throw error;
|
|
4213
|
-
const suggestion = (await listSuggestedWork(runtime)).find(
|
|
4214
|
-
(item) => stringField(item, "id") === artifactId,
|
|
4215
|
-
);
|
|
4216
|
-
if (!suggestion) throw error;
|
|
4217
|
-
const title = stringField(suggestion, "title") ?? "Suggested work";
|
|
4218
|
-
const created = (await sessionRuntime.client.mutation(
|
|
4219
|
-
api.functions.agentWorkspace.agentCreateTask,
|
|
4220
|
-
{
|
|
4221
|
-
sessionToken: sessionRuntime.sessionToken,
|
|
4222
|
-
title,
|
|
4223
|
-
description: stringField(suggestion, "content"),
|
|
4224
|
-
priority: "medium",
|
|
4225
|
-
risk: "medium",
|
|
4226
|
-
},
|
|
4227
|
-
)) as JsonRecord;
|
|
4228
|
-
return {
|
|
4229
|
-
ok: true,
|
|
4230
|
-
fallback: true,
|
|
4231
|
-
artifactId,
|
|
4232
|
-
title,
|
|
4233
|
-
taskId: created.taskId,
|
|
4234
|
-
note: "Created a task from suggested work. Artifact status will update after the backend conversion function is deployed.",
|
|
4235
|
-
};
|
|
4236
|
-
}),
|
|
4237
|
-
);
|
|
4238
|
-
return;
|
|
4239
|
-
}
|
|
4240
4216
|
print(await listSuggestedWork(runtime));
|
|
4241
4217
|
return;
|
|
4242
4218
|
}
|
|
@@ -4250,13 +4226,7 @@ async function main() {
|
|
|
4250
4226
|
},
|
|
4251
4227
|
)) as AgentStatus;
|
|
4252
4228
|
if (scopedStatus) {
|
|
4253
|
-
|
|
4254
|
-
api.functions.agentWorkspace.agentListTasks,
|
|
4255
|
-
{
|
|
4256
|
-
sessionToken: runtime.sessionToken,
|
|
4257
|
-
},
|
|
4258
|
-
)) as JsonRecord[];
|
|
4259
|
-
print(summarizeAgentStatus(status, tasks, runtime.host));
|
|
4229
|
+
print(summarizeAgentStatus(status, runtime.host));
|
|
4260
4230
|
return;
|
|
4261
4231
|
}
|
|
4262
4232
|
print(status);
|
|
@@ -4279,26 +4249,6 @@ async function main() {
|
|
|
4279
4249
|
return;
|
|
4280
4250
|
}
|
|
4281
4251
|
|
|
4282
|
-
if (command === "tasks") {
|
|
4283
|
-
if (runtime.mode === "session") {
|
|
4284
|
-
print(
|
|
4285
|
-
await runtime.client.query(
|
|
4286
|
-
api.functions.agentWorkspace.agentListTasks,
|
|
4287
|
-
{
|
|
4288
|
-
sessionToken: runtime.sessionToken,
|
|
4289
|
-
},
|
|
4290
|
-
),
|
|
4291
|
-
);
|
|
4292
|
-
return;
|
|
4293
|
-
}
|
|
4294
|
-
if (runtime.mode === "apiKey") {
|
|
4295
|
-
throw loginRequiredError("dench tasks (agent-scoped task list)");
|
|
4296
|
-
}
|
|
4297
|
-
const data = await devOverview(runtime);
|
|
4298
|
-
print(data.tasks);
|
|
4299
|
-
return;
|
|
4300
|
-
}
|
|
4301
|
-
|
|
4302
4252
|
if (command === "agents") {
|
|
4303
4253
|
if (runtime.mode === "session") {
|
|
4304
4254
|
const status = await runtime.client.query(
|
|
@@ -4358,176 +4308,6 @@ async function main() {
|
|
|
4358
4308
|
return;
|
|
4359
4309
|
}
|
|
4360
4310
|
|
|
4361
|
-
if (command === "task" && subcommand === "create") {
|
|
4362
|
-
const title = positional(2);
|
|
4363
|
-
if (!title) throw new Error("Missing task title");
|
|
4364
|
-
const taskArgs = {
|
|
4365
|
-
title,
|
|
4366
|
-
description: option("--description"),
|
|
4367
|
-
priority: (option("--priority") ?? "medium") as "low" | "medium" | "high",
|
|
4368
|
-
risk: (option("--risk") ?? "medium") as "low" | "medium" | "high",
|
|
4369
|
-
};
|
|
4370
|
-
if (runtime.mode === "session") {
|
|
4371
|
-
print(
|
|
4372
|
-
await runtime.client.mutation(
|
|
4373
|
-
api.functions.agentWorkspace.agentCreateTask,
|
|
4374
|
-
{
|
|
4375
|
-
sessionToken: runtime.sessionToken,
|
|
4376
|
-
...taskArgs,
|
|
4377
|
-
},
|
|
4378
|
-
),
|
|
4379
|
-
);
|
|
4380
|
-
return;
|
|
4381
|
-
}
|
|
4382
|
-
rejectApiKeyForAgentCommand(runtime, "dench task create");
|
|
4383
|
-
const taskId = await runtime.client.mutation(
|
|
4384
|
-
api.functions.agentWorkspace.devCreateTask,
|
|
4385
|
-
{
|
|
4386
|
-
...runtime.workspaceArgs,
|
|
4387
|
-
...taskArgs,
|
|
4388
|
-
},
|
|
4389
|
-
);
|
|
4390
|
-
print({ ok: true, taskId });
|
|
4391
|
-
return;
|
|
4392
|
-
}
|
|
4393
|
-
|
|
4394
|
-
if (command === "task" && subcommand === "status") {
|
|
4395
|
-
const sessionRuntime = requireSessionRuntime(runtime, "dench task status");
|
|
4396
|
-
const taskId = positional(2);
|
|
4397
|
-
const status = positional(3);
|
|
4398
|
-
if (!taskId || !status) {
|
|
4399
|
-
throw new Error("Usage: dench task status <taskId> <status>");
|
|
4400
|
-
}
|
|
4401
|
-
print(
|
|
4402
|
-
await sessionRuntime.client.mutation(
|
|
4403
|
-
api.functions.agentWorkspace.agentUpdateTaskStatus,
|
|
4404
|
-
{
|
|
4405
|
-
sessionToken: sessionRuntime.sessionToken,
|
|
4406
|
-
taskId: taskId as never,
|
|
4407
|
-
status: status as never,
|
|
4408
|
-
note: option("--note"),
|
|
4409
|
-
},
|
|
4410
|
-
),
|
|
4411
|
-
);
|
|
4412
|
-
return;
|
|
4413
|
-
}
|
|
4414
|
-
|
|
4415
|
-
if (
|
|
4416
|
-
command === "task" &&
|
|
4417
|
-
(subcommand === "comment" ||
|
|
4418
|
-
subcommand === "handoff" ||
|
|
4419
|
-
subcommand === "block")
|
|
4420
|
-
) {
|
|
4421
|
-
const sessionRuntime = requireSessionRuntime(
|
|
4422
|
-
runtime,
|
|
4423
|
-
`dench task ${subcommand}`,
|
|
4424
|
-
);
|
|
4425
|
-
const taskId = positional(2);
|
|
4426
|
-
const body = positionalsFrom(3).join(" ").trim();
|
|
4427
|
-
if (!taskId || !body) {
|
|
4428
|
-
throw new Error(`Usage: dench task ${subcommand} <taskId> "message"`);
|
|
4429
|
-
}
|
|
4430
|
-
print(
|
|
4431
|
-
await sessionRuntime.client.mutation(
|
|
4432
|
-
api.functions.agentWorkspace.agentAddTaskComment,
|
|
4433
|
-
{
|
|
4434
|
-
sessionToken: sessionRuntime.sessionToken,
|
|
4435
|
-
taskId: taskId as never,
|
|
4436
|
-
kind:
|
|
4437
|
-
subcommand === "handoff"
|
|
4438
|
-
? "handoff"
|
|
4439
|
-
: subcommand === "block"
|
|
4440
|
-
? "blocker"
|
|
4441
|
-
: "comment",
|
|
4442
|
-
body,
|
|
4443
|
-
targetAgentId: option("--agent") as never,
|
|
4444
|
-
},
|
|
4445
|
-
),
|
|
4446
|
-
);
|
|
4447
|
-
return;
|
|
4448
|
-
}
|
|
4449
|
-
|
|
4450
|
-
if (command === "task" && subcommand === "depends-on") {
|
|
4451
|
-
const sessionRuntime = requireSessionRuntime(
|
|
4452
|
-
runtime,
|
|
4453
|
-
"dench task depends-on",
|
|
4454
|
-
);
|
|
4455
|
-
const taskId = positional(2);
|
|
4456
|
-
const dependsOnTaskId = positional(3);
|
|
4457
|
-
if (!taskId || !dependsOnTaskId) {
|
|
4458
|
-
throw new Error(
|
|
4459
|
-
"Usage: dench task depends-on <taskId> <dependsOnTaskId>",
|
|
4460
|
-
);
|
|
4461
|
-
}
|
|
4462
|
-
print(
|
|
4463
|
-
await sessionRuntime.client.mutation(
|
|
4464
|
-
api.functions.agentWorkspace.agentAddTaskDependency,
|
|
4465
|
-
{
|
|
4466
|
-
sessionToken: sessionRuntime.sessionToken,
|
|
4467
|
-
taskId: taskId as never,
|
|
4468
|
-
dependsOnTaskId: dependsOnTaskId as never,
|
|
4469
|
-
note: option("--note"),
|
|
4470
|
-
},
|
|
4471
|
-
),
|
|
4472
|
-
);
|
|
4473
|
-
return;
|
|
4474
|
-
}
|
|
4475
|
-
|
|
4476
|
-
if (command === "claim") {
|
|
4477
|
-
const taskId = positional(1);
|
|
4478
|
-
if (!taskId) throw new Error("Missing task id");
|
|
4479
|
-
if (runtime.mode === "session") {
|
|
4480
|
-
print(
|
|
4481
|
-
await runtime.client.mutation(
|
|
4482
|
-
api.functions.agentWorkspace.agentClaimTask,
|
|
4483
|
-
{
|
|
4484
|
-
sessionToken: runtime.sessionToken,
|
|
4485
|
-
taskId: taskId as never,
|
|
4486
|
-
},
|
|
4487
|
-
),
|
|
4488
|
-
);
|
|
4489
|
-
return;
|
|
4490
|
-
}
|
|
4491
|
-
rejectApiKeyForAgentCommand(runtime, "dench claim");
|
|
4492
|
-
const agentId = option("--agent") ?? (await defaultDevAgentId(runtime));
|
|
4493
|
-
print(
|
|
4494
|
-
await runtime.client.mutation(api.functions.agentWorkspace.devClaimTask, {
|
|
4495
|
-
...runtime.workspaceArgs,
|
|
4496
|
-
taskId: taskId as never,
|
|
4497
|
-
agentId: agentId as never,
|
|
4498
|
-
}),
|
|
4499
|
-
);
|
|
4500
|
-
return;
|
|
4501
|
-
}
|
|
4502
|
-
|
|
4503
|
-
if (command === "log") {
|
|
4504
|
-
const message = positional(1);
|
|
4505
|
-
if (!message) throw new Error("Missing log message");
|
|
4506
|
-
if (runtime.mode === "session") {
|
|
4507
|
-
print(
|
|
4508
|
-
await runtime.client.mutation(
|
|
4509
|
-
api.functions.agentWorkspace.agentAppendLog,
|
|
4510
|
-
{
|
|
4511
|
-
sessionToken: runtime.sessionToken,
|
|
4512
|
-
message,
|
|
4513
|
-
taskId: option("--task") as never,
|
|
4514
|
-
},
|
|
4515
|
-
),
|
|
4516
|
-
);
|
|
4517
|
-
return;
|
|
4518
|
-
}
|
|
4519
|
-
rejectApiKeyForAgentCommand(runtime, "dench log");
|
|
4520
|
-
print(
|
|
4521
|
-
await runtime.client.mutation(api.functions.agentWorkspace.devAppendLog, {
|
|
4522
|
-
...runtime.workspaceArgs,
|
|
4523
|
-
message,
|
|
4524
|
-
agentId: option("--agent") as never,
|
|
4525
|
-
taskId: option("--task") as never,
|
|
4526
|
-
}),
|
|
4527
|
-
);
|
|
4528
|
-
return;
|
|
4529
|
-
}
|
|
4530
|
-
|
|
4531
4311
|
if (command === "approval" && subcommand === "request") {
|
|
4532
4312
|
const title = positional(2);
|
|
4533
4313
|
if (!title) throw new Error("Missing approval title");
|
|
@@ -4540,7 +4320,6 @@ async function main() {
|
|
|
4540
4320
|
title,
|
|
4541
4321
|
reason: option("--reason"),
|
|
4542
4322
|
risk: (option("--risk") ?? "high") as "low" | "medium" | "high",
|
|
4543
|
-
taskId: option("--task") as never,
|
|
4544
4323
|
},
|
|
4545
4324
|
),
|
|
4546
4325
|
);
|
|
@@ -4557,7 +4336,6 @@ async function main() {
|
|
|
4557
4336
|
"Agent requests human approval before a risky action.",
|
|
4558
4337
|
risk: (option("--risk") ?? "high") as "low" | "medium" | "high",
|
|
4559
4338
|
agentId: option("--agent") as never,
|
|
4560
|
-
taskId: option("--task") as never,
|
|
4561
4339
|
},
|
|
4562
4340
|
);
|
|
4563
4341
|
print({ ok: true, approvalId });
|