@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/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 suggested-work task <artifactId> [--json]
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
- Do not create, claim, or log a setup task by default.
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 DENCH_API_KEY (Bearer) directly to the
626
- Dench Cloud Gateway. No \`dench signin\` agent session is required —
627
- inside a Dench sandbox the key is baked into the env automatically;
628
- outside, export DENCH_API_KEY=<key> first.
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. Suggested work can
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 DENCH_API_KEY (Bearer) directly to the
765
- Dench Cloud Gateway no \`dench signin\` agent session required. Alias
766
- for \`dench tool status\`.
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") ?? (hasFlag("--prod")
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("Future `dench` commands without --prod/--staging/--host will target this backend.");
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 = option("--otp-code")?.trim() || (await promptLine("Paste OTP: "));
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(result.organization, input.orgSelector);
1882
- await finalizeOtpSession(input, result.organization, result.sessionExpiresAt);
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 (!Number.isFinite(choice) || choice < 1 || choice > input.organizations.length + 1) {
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
- * Some legacy `agentWorkspace.*` commands (task create / claim / log /
2512
- * approval request) have separate session vs dev branches. With apiKey
2513
- * mode added, the dev branch would silently receive partial args. Use
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 tasks --json",
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(_runtime: Runtime) {
2613
- // Reach the Dench gateway directly with DENCH_API_KEY (mirrors the
2614
- // denchclaw pattern). This works for every Runtime mode — session,
2615
- // apiKey, dev — because the gateway only cares about the bearer key,
2616
- // not which Convex session is calling.
2617
- return fetchConnectedAppsSummary();
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(counts?.tasks ?? tasks.length)} visible tasks, ${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 filesApiKey(runtime: Runtime): string | undefined {
3028
- if (runtime.mode === "apiKey") return runtime.sessionToken;
3029
- return process.env.DENCH_API_KEY?.trim() || undefined;
3030
- }
3031
-
3032
- function requireFilesApiKey(runtime: Runtime, command: string): string {
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
- 'Run `dench signin` to connect this agent to an existing workspace.',
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
- await runSearchCommand({ args: filteredSubArgs, jsonOutput: json });
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
- await runImageCommand({ args: filteredSubArgs, jsonOutput: json });
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
- // `dench apps` is an alias for `dench tool status`. Both speak
3875
- // straight HTTP to the Dench Cloud Gateway with DENCH_API_KEY —
3876
- // mirrors the denchclaw pattern. No Convex session involved.
3877
- await runToolCommand({ args: ["status"], jsonOutput: json });
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
- await runToolCommand({ args: filteredSubArgs, jsonOutput: json });
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
- const tasks = (await runtime.client.query(
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 });