@dench.com/cli 2.0.3 → 2.0.4

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/agent-config.ts CHANGED
@@ -34,11 +34,51 @@ import { mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
34
34
  import { tmpdir } from "node:os";
35
35
  import { join } from "node:path";
36
36
  import type { ConvexHttpClient } from "convex/browser";
37
- import { api } from "@/../convex/_generated/api";
37
+ import { makeFunctionReference } from "convex/server";
38
38
  import { CliArgError, getFlag, hasFlag } from "./lib/cli-args";
39
39
 
40
40
  class AgentConfigCliError extends Error {}
41
41
 
42
+ const api = {
43
+ functions: {
44
+ agentConfig: {
45
+ getAgentConfig: makeFunctionReference<"query">(
46
+ "functions/agentConfig:getAgentConfig",
47
+ ),
48
+ updateIdentity: makeFunctionReference<"mutation">(
49
+ "functions/agentConfig:updateIdentity",
50
+ ),
51
+ updateOrganisation: makeFunctionReference<"mutation">(
52
+ "functions/agentConfig:updateOrganisation",
53
+ ),
54
+ updateMemory: makeFunctionReference<"mutation">(
55
+ "functions/agentConfig:updateMemory",
56
+ ),
57
+ updateToolsNotes: makeFunctionReference<"mutation">(
58
+ "functions/agentConfig:updateToolsNotes",
59
+ ),
60
+ updateUserProfile: makeFunctionReference<"mutation">(
61
+ "functions/agentConfig:updateUserProfile",
62
+ ),
63
+ updateHeartbeat: makeFunctionReference<"mutation">(
64
+ "functions/agentConfig:updateHeartbeat",
65
+ ),
66
+ updateBootstrapTemplate: makeFunctionReference<"mutation">(
67
+ "functions/agentConfig:updateBootstrapTemplate",
68
+ ),
69
+ completeBootstrap: makeFunctionReference<"mutation">(
70
+ "functions/agentConfig:completeBootstrap",
71
+ ),
72
+ setDefaultChatModelV2: makeFunctionReference<"mutation">(
73
+ "functions/agentConfig:setDefaultChatModelV2",
74
+ ),
75
+ setThreadModelOverride: makeFunctionReference<"mutation">(
76
+ "functions/agentConfig:setThreadModelOverride",
77
+ ),
78
+ },
79
+ },
80
+ };
81
+
42
82
  type CliCtx = {
43
83
  convex: ConvexHttpClient;
44
84
  args: string[];
@@ -86,7 +126,9 @@ async function readContentFromStdin(): Promise<string> {
86
126
  return new Promise((resolve, reject) => {
87
127
  const chunks: Buffer[] = [];
88
128
  process.stdin.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
89
- process.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
129
+ process.stdin.on("end", () =>
130
+ resolve(Buffer.concat(chunks).toString("utf8")),
131
+ );
90
132
  process.stdin.on("error", reject);
91
133
  });
92
134
  }
@@ -150,7 +192,10 @@ async function loadAgentConfig(ctx: CliCtx): Promise<{
150
192
  userProfile: { content: string; updatedAt: number } | null;
151
193
  organizationId: string;
152
194
  }> {
153
- const result = (await runQuery(ctx, api.functions.agentConfig.getAgentConfig)) as {
195
+ const result = (await runQuery(
196
+ ctx,
197
+ api.functions.agentConfig.getAgentConfig,
198
+ )) as {
154
199
  agentConfig: {
155
200
  identity: { content: string; updatedAt: number } | null;
156
201
  organisation: { content: string; updatedAt: number } | null;
@@ -212,14 +257,14 @@ async function handleSimpleMagicFile(
212
257
  } else {
213
258
  const config = await loadAgentConfig(ctx);
214
259
  const initial = opts.perMember
215
- ? config.userProfile?.content ?? ""
260
+ ? (config.userProfile?.content ?? "")
216
261
  : opts.field === "memoryAggregate"
217
- ? config.agentConfig.memoryAggregate?.content ?? ""
262
+ ? (config.agentConfig.memoryAggregate?.content ?? "")
218
263
  : opts.field === "toolsNotes"
219
- ? config.agentConfig.toolsNotes?.content ?? ""
264
+ ? (config.agentConfig.toolsNotes?.content ?? "")
220
265
  : opts.field === "identity"
221
- ? config.agentConfig.identity?.content ?? ""
222
- : config.agentConfig.organisation?.content ?? "";
266
+ ? (config.agentConfig.identity?.content ?? "")
267
+ : (config.agentConfig.organisation?.content ?? "");
223
268
  content = openEditor(initial, opts.label);
224
269
  }
225
270
  if (!content.trim().length) {
@@ -519,8 +564,7 @@ export async function runMemoryAggregateCommand(ctx: CliCtx): Promise<void> {
519
564
  }
520
565
  if (sub === "append") {
521
566
  const text = ctx.args.slice(1).join(" ").trim();
522
- if (!text)
523
- throw new AgentConfigCliError("Usage: dench mem append <text>");
567
+ if (!text) throw new AgentConfigCliError("Usage: dench mem append <text>");
524
568
  await runMutation(ctx, api.functions.agentConfig.updateMemory, {
525
569
  content: text,
526
570
  append: true,
@@ -593,9 +637,7 @@ export async function runDailyCommand(ctx: CliCtx): Promise<void> {
593
637
  if (sub === "show") {
594
638
  const date = ctx.args[1];
595
639
  if (!date) {
596
- throw new AgentConfigCliError(
597
- "Usage: dench daily show <YYYY-MM-DD>",
598
- );
640
+ throw new AgentConfigCliError("Usage: dench daily show <YYYY-MM-DD>");
599
641
  }
600
642
  out(
601
643
  ctx,
package/chat-spawn.ts CHANGED
@@ -16,8 +16,6 @@
16
16
  * (`/api/chat/[runId]/stream`) and pretty-prints text deltas + tool
17
17
  * calls until the workflow finishes.
18
18
  */
19
-
20
- import { getCurrentRuntimeTimeZone } from "@/lib/timezone";
21
19
  import { hasFlag } from "./lib/cli-args";
22
20
 
23
21
  class ChatSpawnError extends Error {}
@@ -33,6 +31,18 @@ type ChatSpawnContext = {
33
31
  jsonOutput: boolean;
34
32
  };
35
33
 
34
+ function getCurrentRuntimeTimeZone(): string | null {
35
+ try {
36
+ const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
37
+ if (!timeZone || timeZone.length > 100) return null;
38
+ // Validate that Intl accepts the resolved value before forwarding it.
39
+ Intl.DateTimeFormat("en-US", { timeZone }).format(new Date());
40
+ return timeZone;
41
+ } catch {
42
+ return null;
43
+ }
44
+ }
45
+
36
46
  function consumeFlagValue(args: string[], name: string): string | undefined {
37
47
  const idx = args.indexOf(name);
38
48
  if (idx === -1) return undefined;
package/dench.ts CHANGED
@@ -440,13 +440,13 @@ Workspace members (for CRM \`user\`-type fields):
440
440
  cells assign to real members instead of being stored as unlinked
441
441
  display-name strings. See \`dench members help\`.
442
442
 
443
- Live web search (Exa via the Dench Cloud Gateway, auths with the active \`dench signin\` agent session or DENCH_API_KEY):
443
+ Live web search (Exa via the Dench Gateway, auths with the active \`dench signin\` agent session or DENCH_API_KEY):
444
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]
445
445
  dench search contents <url> [<url>...] [--max-chars 4000] [--summary "..."] [--json]
446
446
  dench search answer "<query>" [--json]
447
447
  Help: dench search help
448
448
 
449
- Image generation / editing (gpt-image-2 via the Dench Cloud Gateway):
449
+ Image generation / editing (via the Dench Gateway):
450
450
  dench image generate "<prompt>" [--size 1024x1024] [--quality auto|low|medium|high] [--format png|jpeg|webp] [--save-path /workspace/path/file.png] [--output <local file>] [--no-write] [--json]
451
451
  dench image edit "<prompt>" --input <path> [--input <path> ...] [--mask <path>] [--size ...] [--quality ...] [--format ...] [--save-path ...] [--output ...] [--json]
452
452
  Help: dench image help
@@ -472,7 +472,7 @@ Spawn a new chat-turn workflow (same as the web UI):
472
472
 
473
473
  Help: dench chat help
474
474
 
475
- File sync (Daytona-native rewrite):
475
+ File sync:
476
476
  dench fs status [--json] [--workspace /workspace] [--no-hash] [--drift-limit N]
477
477
  dench fs sync --initial --org-id <orgId> [--workspace /workspace]
478
478
  dench fs stream-open <path>
@@ -488,7 +488,7 @@ returns ENOSYS on the FUSE-backed volume mount):
488
488
  Persist scratch -> workspace (cp from /tmp into /workspace + Convex sync):
489
489
  dench stage <local-path> [<workspace-dest>] [--clean] [--json]
490
490
 
491
- Subagents (Daytona-native rewrite):
491
+ Subagents:
492
492
  dench agent spawn '<goal>' [--parent-run-id <id>] [--sandbox own|share_parent] [--time-budget-ms N]
493
493
  dench agent await --hook <token> | --children id1,id2,id3
494
494
  dench agent message <toRunId> '<text>' [--from-run-id <id>]
@@ -501,7 +501,7 @@ Subagents (Daytona-native rewrite):
501
501
 
502
502
  dench --version
503
503
 
504
- Self-updating agent harness (OpenClaw parity):
504
+ Self-updating agent harness:
505
505
  dench identity show | edit IDENTITY.md (org-wide)
506
506
  dench organisation show | edit ORGANISATION.md
507
507
  dench user show | edit USER.md (per-member)
@@ -2038,25 +2038,31 @@ function parseBillingTopupAmountUsd() {
2038
2038
  }
2039
2039
 
2040
2040
  async function billingStatus(runtime: Runtime) {
2041
- const sessionRuntime = requireSessionRuntime(runtime, "dench billing status");
2042
- const status = await sessionRuntime.client.query(
2041
+ const authedRuntime = requireAuthenticatedRuntime(
2042
+ runtime,
2043
+ "dench billing status",
2044
+ );
2045
+ const status = await authedRuntime.client.query(
2043
2046
  api.functions.agentWorkspace.getAgentBillingStatus,
2044
- { sessionToken: sessionRuntime.sessionToken },
2047
+ { sessionToken: authedRuntime.sessionToken },
2045
2048
  );
2046
2049
  print(json ? status : formatBillingStatus(status));
2047
2050
  }
2048
2051
 
2049
2052
  async function billingTopup(runtime: Runtime) {
2050
- const sessionRuntime = requireSessionRuntime(runtime, "dench billing topup");
2053
+ const authedRuntime = requireAuthenticatedRuntime(
2054
+ runtime,
2055
+ "dench billing topup",
2056
+ );
2051
2057
  const amountUsd = parseBillingTopupAmountUsd();
2052
2058
  const response = await fetch(
2053
- `${sessionRuntime.host.replace(/\/+$/, "")}/api/stripe/create-ai-topup`,
2059
+ `${authedRuntime.host.replace(/\/+$/, "")}/api/stripe/create-ai-topup`,
2054
2060
  {
2055
2061
  method: "POST",
2056
2062
  headers: {
2057
2063
  accept: "application/json",
2058
2064
  "content-type": "application/json",
2059
- authorization: `Bearer ${sessionRuntime.sessionToken}`,
2065
+ authorization: `Bearer ${authedRuntime.sessionToken}`,
2060
2066
  },
2061
2067
  body: JSON.stringify({
2062
2068
  amountUsd,
@@ -2123,7 +2129,7 @@ async function billingTopup(runtime: Runtime) {
2123
2129
  * needed in that case). We surface either outcome cleanly.
2124
2130
  */
2125
2131
  async function denchUpgrade(runtime: Runtime) {
2126
- const sessionRuntime = requireSessionRuntime(runtime, "dench upgrade");
2132
+ const authedRuntime = requireAuthenticatedRuntime(runtime, "dench upgrade");
2127
2133
  const tierFlag = option("--tier")?.trim().toLowerCase() || "pro";
2128
2134
  const cycleFlag =
2129
2135
  option("--cycle")?.trim().toLowerCase() ||
@@ -2146,13 +2152,13 @@ async function denchUpgrade(runtime: Runtime) {
2146
2152
  const internalTier = tierFlag === "pro" ? "desktop" : "cloud";
2147
2153
 
2148
2154
  const response = await fetch(
2149
- `${sessionRuntime.host.replace(/\/+$/, "")}/api/stripe/create-checkout`,
2155
+ `${authedRuntime.host.replace(/\/+$/, "")}/api/stripe/create-checkout`,
2150
2156
  {
2151
2157
  method: "POST",
2152
2158
  headers: {
2153
2159
  accept: "application/json",
2154
2160
  "content-type": "application/json",
2155
- authorization: `Bearer ${sessionRuntime.sessionToken}`,
2161
+ authorization: `Bearer ${authedRuntime.sessionToken}`,
2156
2162
  },
2157
2163
  body: JSON.stringify({
2158
2164
  tier: internalTier,
@@ -2394,25 +2400,6 @@ function stripRuntimeFlags(args: string[]) {
2394
2400
  return stripped;
2395
2401
  }
2396
2402
 
2397
- /**
2398
- * `session` mode is required for `agentWorkspace.*` calls because they
2399
- * gate on `validateAgentSession` server-side, which only accepts the
2400
- * `dch_agent_*` token format. Sandboxes that only have a unified
2401
- * `DENCH_API_KEY` (apiKey mode) cannot impersonate a specific agent
2402
- * and will fail at the server with `Invalid agent session` — surface
2403
- * that here as a clear error instead.
2404
- */
2405
- function requireSessionRuntime(
2406
- runtime: Runtime,
2407
- command: string,
2408
- ): Extract<Runtime, { mode: "session" }> {
2409
- if (runtime.mode === "session") return runtime;
2410
- if (runtime.mode === "apiKey") {
2411
- throw agentSessionRequiredError(command);
2412
- }
2413
- throw loginRequiredError(command);
2414
- }
2415
-
2416
2403
  /**
2417
2404
  * Org-scoped commands (`dench crm`, `dench files`, etc.) accept either
2418
2405
  * a `dch_agent_*` agent session token OR a unified Dench API key
@@ -2543,36 +2530,6 @@ function encodeDevCrmSessionToken(args: {
2543
2530
  return `dch_dev_${encodeURIComponent(args.workspaceSlug)}:${encodeURIComponent(args.devKey)}`;
2544
2531
  }
2545
2532
 
2546
- function agentSessionRequiredError(command: string) {
2547
- return new CliError(
2548
- `${command} requires an agent session — DENCH_API_KEY is org-scoped and cannot impersonate a specific agent`,
2549
- {
2550
- code: "agent_session_required",
2551
- nextActions: [
2552
- 'Run dench signin --kind <kind> --name "AI Agent - Project" to mint an agent session for this command.',
2553
- "Or run the equivalent action via the workspace UI / dench crm if it is org-level (e.g. CRM data, files).",
2554
- ],
2555
- },
2556
- );
2557
- }
2558
-
2559
- /**
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.
2563
- *
2564
- * Asserts away the `apiKey` mode so the caller's downstream type
2565
- * narrowing (e.g. `runtime.workspaceArgs`) keeps working.
2566
- */
2567
- function rejectApiKeyForAgentCommand(
2568
- runtime: Runtime,
2569
- command: string,
2570
- ): asserts runtime is Exclude<Runtime, { mode: "apiKey" }> {
2571
- if (runtime.mode === "apiKey") {
2572
- throw agentSessionRequiredError(command);
2573
- }
2574
- }
2575
-
2576
2533
  function asRecord(value: unknown): JsonRecord | undefined {
2577
2534
  if (!value || typeof value !== "object" || Array.isArray(value)) {
2578
2535
  return undefined;
@@ -2679,7 +2636,7 @@ async function connectedAppsContext(runtime: Runtime) {
2679
2636
  async function buildContext(runtime: Runtime) {
2680
2637
  let mine: JsonRecord;
2681
2638
  let urls: JsonRecord;
2682
- if (runtime.mode === "session") {
2639
+ if (runtime.mode === "session" || runtime.mode === "apiKey") {
2683
2640
  mine = (await runtime.client.query(
2684
2641
  api.functions.agentWorkspace.whatCanIDoHere,
2685
2642
  { sessionToken: runtime.sessionToken },
@@ -2692,20 +2649,7 @@ async function buildContext(runtime: Runtime) {
2692
2649
  );
2693
2650
  urls = {};
2694
2651
  } else {
2695
- // apiKey mode: no agent session is available, so we can't call
2696
- // `whatCanIDoHere` (it gates on `validateAgentSession`). Return a
2697
- // minimal context derived from sandbox envVars so dench-cli help
2698
- // surfaces still work without a full login.
2699
- mine = {
2700
- authMode: "apiKey",
2701
- organization: runtime.organization ?? null,
2702
- runId: process.env.DENCH_RUN_ID?.trim() ?? null,
2703
- parentRunId: process.env.DENCH_PARENT_RUN_ID?.trim() ?? null,
2704
- rootRunId: process.env.DENCH_ROOT_RUN_ID?.trim() ?? null,
2705
- };
2706
- urls = runtime.host
2707
- ? workspaceUrls(runtime.host, runtime.organization?.slug)
2708
- : {};
2652
+ throw loginRequiredError("dench context");
2709
2653
  }
2710
2654
 
2711
2655
  return {
@@ -2933,7 +2877,7 @@ function summarizeDevMine(workspaceSlug: string, data: WorkspaceOverview) {
2933
2877
  }
2934
2878
 
2935
2879
  async function listArtifacts(runtime: Runtime, limit?: number) {
2936
- if (runtime.mode === "session") {
2880
+ if (runtime.mode === "session" || runtime.mode === "apiKey") {
2937
2881
  try {
2938
2882
  return (await runtime.client.query(
2939
2883
  api.functions.agentWorkspace.agentListArtifacts,
@@ -2951,12 +2895,6 @@ async function listArtifacts(runtime: Runtime, limit?: number) {
2951
2895
  );
2952
2896
  }
2953
2897
  }
2954
- if (runtime.mode === "apiKey") {
2955
- // No agent identity → no artifact list. Return empty so callers
2956
- // (e.g. `dench artifacts`, `dench suggested-work`) degrade gracefully
2957
- // instead of throwing for sandbox callers.
2958
- return [] as JsonRecord[];
2959
- }
2960
2898
  const data = await devOverview(runtime);
2961
2899
  return asRecordArray(data.recentArtifacts);
2962
2900
  }
@@ -4165,15 +4103,15 @@ async function main() {
4165
4103
  }
4166
4104
 
4167
4105
  if (command === "memory") {
4168
- const sessionRuntime = requireSessionRuntime(runtime, "dench memory");
4106
+ const authedRuntime = requireAuthenticatedRuntime(runtime, "dench memory");
4169
4107
  if (subcommand === "search") {
4170
4108
  const query = positionalsFrom(2).join(" ").trim();
4171
4109
  if (!query) throw new Error('Usage: dench memory search "query"');
4172
4110
  print(
4173
- await sessionRuntime.client.query(
4111
+ await authedRuntime.client.query(
4174
4112
  api.functions.agentWorkspace.agentSearchMemory,
4175
4113
  {
4176
- sessionToken: sessionRuntime.sessionToken,
4114
+ sessionToken: authedRuntime.sessionToken,
4177
4115
  query,
4178
4116
  limit: parseNumberOption("--limit"),
4179
4117
  },
@@ -4188,10 +4126,10 @@ async function main() {
4188
4126
  throw new Error('Usage: dench memory save <key> "text"');
4189
4127
  }
4190
4128
  print(
4191
- await sessionRuntime.client.mutation(
4129
+ await authedRuntime.client.mutation(
4192
4130
  api.functions.agentWorkspace.agentSaveMemory,
4193
4131
  {
4194
- sessionToken: sessionRuntime.sessionToken,
4132
+ sessionToken: authedRuntime.sessionToken,
4195
4133
  key,
4196
4134
  kind: (option("--kind") ?? "fact") as never,
4197
4135
  text,
@@ -4216,9 +4154,9 @@ async function main() {
4216
4154
  }
4217
4155
 
4218
4156
  if (command === "status") {
4219
- if (runtime.mode === "session") {
4157
+ if (runtime.mode === "session" || runtime.mode === "apiKey") {
4220
4158
  const status = (await runtime.client.query(
4221
- api.functions.agentWorkspace.agentStatus,
4159
+ api.functions.agentWorkspace.whatCanIDoHere,
4222
4160
  {
4223
4161
  sessionToken: runtime.sessionToken,
4224
4162
  },
@@ -4230,13 +4168,6 @@ async function main() {
4230
4168
  print(status);
4231
4169
  return;
4232
4170
  }
4233
- if (runtime.mode === "apiKey") {
4234
- // No agent session → no agent-status query. Fall back to a thin
4235
- // env-derived snapshot so sandbox callers still get something
4236
- // useful from `dench status`.
4237
- print(await buildContext(runtime));
4238
- return;
4239
- }
4240
4171
  const data = await devOverview(runtime);
4241
4172
  const output = scopedStatus
4242
4173
  ? summarizeDevMine(runtime.workspaceArgs.workspaceSlug, data)
@@ -4248,9 +4179,9 @@ async function main() {
4248
4179
  }
4249
4180
 
4250
4181
  if (command === "agents") {
4251
- if (runtime.mode === "session") {
4182
+ if (runtime.mode === "session" || runtime.mode === "apiKey") {
4252
4183
  const status = await runtime.client.query(
4253
- api.functions.agentWorkspace.agentStatus,
4184
+ api.functions.agentWorkspace.whatCanIDoHere,
4254
4185
  {
4255
4186
  sessionToken: runtime.sessionToken,
4256
4187
  },
@@ -4258,18 +4189,15 @@ async function main() {
4258
4189
  print(status.agents);
4259
4190
  return;
4260
4191
  }
4261
- if (runtime.mode === "apiKey") {
4262
- throw loginRequiredError("dench agents");
4263
- }
4264
4192
  const data = await devOverview(runtime);
4265
4193
  print(data.agents);
4266
4194
  return;
4267
4195
  }
4268
4196
 
4269
4197
  if (command === "approvals") {
4270
- if (runtime.mode === "session") {
4198
+ if (runtime.mode === "session" || runtime.mode === "apiKey") {
4271
4199
  const status = await runtime.client.query(
4272
- api.functions.agentWorkspace.agentStatus,
4200
+ api.functions.agentWorkspace.whatCanIDoHere,
4273
4201
  {
4274
4202
  sessionToken: runtime.sessionToken,
4275
4203
  },
@@ -4277,9 +4205,6 @@ async function main() {
4277
4205
  print(status.approvals);
4278
4206
  return;
4279
4207
  }
4280
- if (runtime.mode === "apiKey") {
4281
- throw loginRequiredError("dench approvals");
4282
- }
4283
4208
  const data = await devOverview(runtime);
4284
4209
  print(data.approvals);
4285
4210
  return;
@@ -4309,7 +4234,7 @@ async function main() {
4309
4234
  if (command === "approval" && subcommand === "request") {
4310
4235
  const title = positional(2);
4311
4236
  if (!title) throw new Error("Missing approval title");
4312
- if (runtime.mode === "session") {
4237
+ if (runtime.mode === "session" || runtime.mode === "apiKey") {
4313
4238
  print(
4314
4239
  await runtime.client.mutation(
4315
4240
  api.functions.agentWorkspace.agentRequestApproval,
@@ -4323,7 +4248,6 @@ async function main() {
4323
4248
  );
4324
4249
  return;
4325
4250
  }
4326
- rejectApiKeyForAgentCommand(runtime, "dench approval request");
4327
4251
  const approvalId = await runtime.client.mutation(
4328
4252
  api.functions.agentWorkspace.devRequestApproval,
4329
4253
  {
@@ -4346,15 +4270,15 @@ async function main() {
4346
4270
  ) {
4347
4271
  const approvalId = positional(2);
4348
4272
  if (!approvalId) throw new Error("Missing approval id");
4349
- const sessionRuntime = requireSessionRuntime(
4273
+ const authedRuntime = requireAuthenticatedRuntime(
4350
4274
  runtime,
4351
4275
  "dench approval approve/reject",
4352
4276
  );
4353
4277
  const decision = subcommand === "approve" ? "approved" : "rejected";
4354
- const result = await sessionRuntime.client.mutation(
4278
+ const result = await authedRuntime.client.mutation(
4355
4279
  api.functions.agentWorkspace.agentDecideApproval,
4356
4280
  {
4357
- sessionToken: sessionRuntime.sessionToken,
4281
+ sessionToken: authedRuntime.sessionToken,
4358
4282
  approvalId: approvalId as never,
4359
4283
  decision,
4360
4284
  evidence: option("--evidence"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dench.com/cli",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
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": {