@cmmd-center/forge 0.13.133 → 0.13.135

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.
Files changed (32) hide show
  1. package/dist/bin.cjs +467 -42
  2. package/dist/bin.mjs +491 -66
  3. package/dist/client/assets/{CanvasPanel-BZ55yFCm.js → CanvasPanel-56JpVM3f.js} +2 -2
  4. package/dist/client/assets/{DiffPanel-RwcR62h1.js → DiffPanel-C4C2m32Y.js} +2 -2
  5. package/dist/client/assets/{DiffPanel.logic-p0v4whSE.js → DiffPanel.logic-CMUCAPGP.js} +2 -2
  6. package/dist/client/assets/{DiffWorkerPoolProvider-DuQCCe4H.js → DiffWorkerPoolProvider-DoKh3mrq.js} +2 -2
  7. package/dist/client/assets/{PullRequestCodePanel-dQ0P1BYv.js → PullRequestCodePanel-BBbZXqYj.js} +2 -2
  8. package/dist/client/assets/{ThemeEditorPanel-Bgrpa0cR.js → ThemeEditorPanel-BdgROB68.js} +2 -2
  9. package/dist/client/assets/{Virtualizer-B7qA3afH.js → Virtualizer-CO7g3RAZ.js} +2 -2
  10. package/dist/client/assets/{WorkerPoolContext-DJIHDFVZ.js → WorkerPoolContext-CWq7MuOM.js} +2 -2
  11. package/dist/client/assets/{cmmdAuthRedirect-B_Ad6N4c.js → cmmdAuthRedirect-Cpw3QgrC.js} +2 -2
  12. package/dist/client/assets/cmmdForgeRuntimeListResource-JkNFZeb3.js +1008 -0
  13. package/dist/client/assets/{currentForgeWorkspaceStore-DgPGQMqz.js → currentForgeWorkspaceStore-DIu1_8w3.js} +2 -2
  14. package/dist/client/assets/{dialog-DMVibvkf.js → dialog-BSwJ44Xn.js} +2 -2
  15. package/dist/client/assets/index-D-9jWQjN.js +301 -0
  16. package/dist/client/assets/{popover-DZpHoNco.js → popover-ZNCjh9sJ.js} +2 -2
  17. package/dist/client/assets/{scroll-area-dh4WduWB.js → scroll-area-By2Wg8Aw.js} +2 -2
  18. package/dist/client/assets/{sidebarV2CustomSnoozeDialog-DsUlSvAq.js → sidebarV2CustomSnoozeDialog-B_dtRwFZ.js} +2 -2
  19. package/dist/client/assets/src-e9jwz4Nc.js +3 -0
  20. package/dist/client/assets/{switch-Bt0PG_99.js → switch-opCmyrUy.js} +2 -2
  21. package/dist/client/assets/{themePalette-rKk-Jh5K.js → themePalette-DchQFoHe.js} +2 -2
  22. package/dist/client/assets/{toggle-CM3FO84q.js → toggle-CGX6qKVS.js} +2 -2
  23. package/dist/client/assets/{toggle-group-sUSKwOOz.js → toggle-group-BRN0oZh2.js} +2 -2
  24. package/dist/client/assets/{tooltip-DHkQTarv.js → tooltip-Bh_PspOm.js} +2 -2
  25. package/dist/client/assets/{utils-B9FLzOgF.js → utils-MX9zGa4a.js} +2 -2
  26. package/dist/client/index.html +18 -18
  27. package/dist/forge-build.json +1 -1
  28. package/dist/{open-2-reBrpv.mjs → open-yHTUkd2Y.mjs} +3 -3
  29. package/package.json +1 -1
  30. package/dist/client/assets/cmmdForgeRuntimeListResource-uAVdZfT3.js +0 -1008
  31. package/dist/client/assets/index-BSqrLyPh.js +0 -301
  32. package/dist/client/assets/src-DpAPOFgC.js +0 -3
package/dist/bin.mjs CHANGED
@@ -23,7 +23,7 @@ import { createCipheriv, createDecipheriv, createHash, createHmac, createPublicK
23
23
  import * as FS$1 from "node:fs";
24
24
  import fs, { accessSync, chmodSync, constants, createReadStream, existsSync, mkdirSync, mkdtempSync, promises, readFile, readFileSync, readdir, readdirSync, realpathSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
25
25
  import * as NodeOS from "node:os";
26
- import $U, { homedir, networkInterfaces, tmpdir } from "node:os";
26
+ import os, { homedir, networkInterfaces, tmpdir } from "node:os";
27
27
  import * as Path$1 from "node:path";
28
28
  import path, { basename, delimiter, dirname, extname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
29
29
  import { pathToFileURL } from "node:url";
@@ -17438,6 +17438,22 @@ const RuntimeMode$1 = Literals([
17438
17438
  "full-access"
17439
17439
  ]);
17440
17440
  const DEFAULT_RUNTIME_MODE$2 = "full-access";
17441
+ /**
17442
+ * Which wallet pays for a CMMD Work Session's provider usage. The values
17443
+ * match CMMD's `forgeWorkSessionWallets` in `shared/schema/forge-work-sessions.ts`.
17444
+ *
17445
+ * CMMD stamps it on the kick `thread.turn.start` (CMMD#5917). An absent value
17446
+ * means the turn carries no wallet claim, which Forge treats the way it
17447
+ * treated every turn before the field existed: on the personal login. On a
17448
+ * CMMD cloud runtime a `workspace` Claude turn must run through CMMD's metered
17449
+ * egress and is refused if CMMD will not mint for it. It never falls back to
17450
+ * the personal login in the VM.
17451
+ */
17452
+ const WorkSessionWallet = Literals([
17453
+ "personal",
17454
+ "workspace",
17455
+ "byok"
17456
+ ]);
17441
17457
  const ProviderInteractionMode = Literals(["default", "plan"]);
17442
17458
  const DEFAULT_PROVIDER_INTERACTION_MODE = "default";
17443
17459
  const ProviderRequestKind = Literals([
@@ -17795,6 +17811,7 @@ const OrchestrationThread = Struct({
17795
17811
  workerRole: NullOr(WorkerRole).pipe(withDecodingDefault(succeed(null))),
17796
17812
  workSessionId: optionalKey(NullOr(String$1)),
17797
17813
  workSessionBoundAt: optionalKey(NullOr(String$1)),
17814
+ wallet: optionalKey(NullOr(WorkSessionWallet)),
17798
17815
  pendingAutoCreatePrompt: optional$4(NullOr(AutoCreateTaskPrompt)).pipe(withDecodingDefault(succeed(null))),
17799
17816
  goal: NullOr(TrimmedNonEmptyString).pipe(withDecodingDefault(succeed(null))),
17800
17817
  titleRegeneration: NullOr(ThreadTitleRegeneration).pipe(withDecodingDefault(succeed(null))),
@@ -17965,6 +17982,7 @@ const ThreadCreateCommand = Struct({
17965
17982
  anchorKind: optional$4(CmmdAnchorKind),
17966
17983
  anchorCmmdId: optional$4(NullOr(String$1)),
17967
17984
  workSessionId: optional$4(NullOr(CommandWorkSessionId)),
17985
+ wallet: optional$4(WorkSessionWallet),
17968
17986
  goal: optional$4(NullOr(TrimmedNonEmptyString)),
17969
17987
  linkedPullRequest: optional$4(NullOr(LinkedPullRequest)),
17970
17988
  kind: optional$4(ThreadKind),
@@ -18075,7 +18093,8 @@ const ThreadTurnStartCommand = Struct({
18075
18093
  kind: optional$4(ThreadKind),
18076
18094
  parentThreadId: optional$4(NullOr(ThreadId)),
18077
18095
  createdAt: IsoDateTime,
18078
- workSessionId: optional$4(NullOr(CommandWorkSessionId))
18096
+ workSessionId: optional$4(NullOr(CommandWorkSessionId)),
18097
+ wallet: optional$4(WorkSessionWallet)
18079
18098
  });
18080
18099
  const ClientThreadTurnStartCommand = Struct({
18081
18100
  type: Literal("thread.turn.start"),
@@ -18099,7 +18118,8 @@ const ClientThreadTurnStartCommand = Struct({
18099
18118
  kind: optional$4(ThreadKind),
18100
18119
  parentThreadId: optional$4(NullOr(ThreadId)),
18101
18120
  createdAt: IsoDateTime,
18102
- workSessionId: optional$4(NullOr(CommandWorkSessionId))
18121
+ workSessionId: optional$4(NullOr(CommandWorkSessionId)),
18122
+ wallet: optional$4(WorkSessionWallet)
18103
18123
  });
18104
18124
  const ThreadTurnInterruptCommand = Struct({
18105
18125
  type: Literal("thread.turn.interrupt"),
@@ -18377,6 +18397,7 @@ const ThreadCreatedPayload$1 = Struct({
18377
18397
  anchorCmmdId: NullOr(String$1).pipe(withDecodingDefault(succeed(null))),
18378
18398
  workSessionId: optionalKey(NullOr(String$1)),
18379
18399
  workSessionBoundAt: optionalKey(NullOr(String$1)),
18400
+ wallet: optionalKey(NullOr(WorkSessionWallet)),
18380
18401
  goal: optionalKey(NullOr(TrimmedNonEmptyString)),
18381
18402
  linkedPullRequest: optionalKey(NullOr(LinkedPullRequest)),
18382
18403
  kind: ThreadKind.pipe(withDecodingDefault(succeed("master"))),
@@ -18420,6 +18441,7 @@ const ThreadMetaUpdatedPayload$1 = Struct({
18420
18441
  workerRole: optional$4(NullOr(WorkerRole)),
18421
18442
  workSessionId: optional$4(NullOr(String$1)),
18422
18443
  workSessionBoundAt: optional$4(String$1),
18444
+ wallet: optional$4(WorkSessionWallet),
18423
18445
  goal: optional$4(NullOr(TrimmedNonEmptyString)),
18424
18446
  linkedPullRequest: optional$4(NullOr(LinkedPullRequest)),
18425
18447
  regenerateTitle: optional$4(Literal(true)),
@@ -18456,6 +18478,7 @@ const ThreadTurnStartRequestedPayload = Struct({
18456
18478
  runtimeMode: RuntimeMode$1.pipe(withDecodingDefault(succeed(DEFAULT_RUNTIME_MODE$2))),
18457
18479
  interactionMode: ProviderInteractionMode.pipe(withDecodingDefault(succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
18458
18480
  sourceProposedPlan: optional$4(SourceProposedPlanReference),
18481
+ wallet: optional$4(WorkSessionWallet),
18459
18482
  createdAt: IsoDateTime
18460
18483
  });
18461
18484
  const ThreadTurnInterruptRequestedPayload = Struct({
@@ -20921,7 +20944,8 @@ const ProviderSessionStartInput = Struct({
20921
20944
  resumeCursor: optional$4(Unknown),
20922
20945
  approvalPolicy: optional$4(ProviderApprovalPolicy),
20923
20946
  sandboxMode: optional$4(ProviderSandboxMode),
20924
- runtimeMode: RuntimeMode$1
20947
+ runtimeMode: RuntimeMode$1,
20948
+ wallet: optional$4(WorkSessionWallet)
20925
20949
  });
20926
20950
  const ProviderSendTurnInput = Struct({
20927
20951
  threadId: ThreadId,
@@ -50727,7 +50751,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
50727
50751
  const min = forceColor || 0;
50728
50752
  if (env.TERM === "dumb") return min;
50729
50753
  if (process$1.platform === "win32") {
50730
- const osRelease = $U.release().split(".");
50754
+ const osRelease = os.release().split(".");
50731
50755
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
50732
50756
  return 1;
50733
50757
  }
@@ -53170,7 +53194,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
53170
53194
  exports.processDetector = void 0;
53171
53195
  const api_1 = (init_esm$1(), __toCommonJS(esm_exports$1));
53172
53196
  const semconv_1 = require_semconv$1();
53173
- const os$3 = __require("os");
53197
+ const os$4 = __require("os");
53174
53198
  /**
53175
53199
  * ProcessDetector will be used to detect the resources related current process running
53176
53200
  * and being instrumented from the NodeJS Process module.
@@ -53192,7 +53216,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
53192
53216
  };
53193
53217
  if (process.argv.length > 1) attributes[semconv_1.ATTR_PROCESS_COMMAND] = process.argv[1];
53194
53218
  try {
53195
- const userInfo = os$3.userInfo();
53219
+ const userInfo = os$4.userInfo();
53196
53220
  attributes[semconv_1.ATTR_PROCESS_OWNER] = userInfo.username;
53197
53221
  } catch (e) {
53198
53222
  api_1.diag.debug(`error obtaining process owner: ${e}`);
@@ -66115,7 +66139,7 @@ function normalizeNumberish(value) {
66115
66139
  }
66116
66140
  //#endregion
66117
66141
  //#region package.json
66118
- var version$1 = "0.13.133";
66142
+ var version$1 = "0.13.135";
66119
66143
  //#endregion
66120
66144
  //#region src/sentry.ts
66121
66145
  const SERVER_APP_NAME = "forge-server";
@@ -75882,7 +75906,7 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
75882
75906
  var fs$6 = __require("fs");
75883
75907
  var path$5 = __require("path");
75884
75908
  var url$1 = __require("url");
75885
- var os$2 = __require("os");
75909
+ var os$3 = __require("os");
75886
75910
  var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
75887
75911
  var vars = process.config && process.config.variables || {};
75888
75912
  var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
@@ -75890,8 +75914,8 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
75890
75914
  var abi = versions.modules;
75891
75915
  if (versions.deno || process.isBun) abi = "unsupported";
75892
75916
  var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
75893
- var arch = process.env.npm_config_arch || os$2.arch();
75894
- var platform = process.env.npm_config_platform || os$2.platform();
75917
+ var arch = process.env.npm_config_arch || os$3.arch();
75918
+ var platform = process.env.npm_config_platform || os$3.platform();
75895
75919
  var libc = process.env.LIBC || (isMusl(platform) ? "musl" : "glibc");
75896
75920
  var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || "";
75897
75921
  var uv = (versions.uv || "").split(".")[0];
@@ -93735,7 +93759,7 @@ const launchDetached = (launch) => gen(function* () {
93735
93759
  });
93736
93760
  const OpenLive = effect(Open, gen(function* () {
93737
93761
  const open = yield* tryPromise({
93738
- try: () => import("./open-2-reBrpv.mjs"),
93762
+ try: () => import("./open-yHTUkd2Y.mjs"),
93739
93763
  catch: (cause) => new OpenError$1({
93740
93764
  message: "failed to load browser opener",
93741
93765
  cause
@@ -97817,6 +97841,16 @@ const PUBLIC_PROVIDER_LEAK_PATTERNS = [
97817
97841
  /https?:\/\/[^\s'"<>)]*(?:apex|deepseek|moonshot|kimi)[^\s'"<>)]*/i
97818
97842
  ];
97819
97843
  const DEFAULT_PUBLIC_PROVIDER_ERROR = "CMMD is temporarily unavailable. Check the workspace AI connection and retry.";
97844
+ /**
97845
+ * The sentence a Workspace-wallet Claude turn fails with on a CMMD runtime when
97846
+ * CMMD will not mint its egress token (CMMD#5917). The Claude adapter opens its
97847
+ * refusal with it, and `categorizePublicProviderError` returns it unchanged, so
97848
+ * the refusal still reads as a refusal when a production stack forces the
97849
+ * failure detail through sanitization. Anything else would read as an outage
97850
+ * and invite a retry on the personal login.
97851
+ */
97852
+ const CLAUDE_WORKSPACE_EGRESS_REFUSAL = "Claude could not get a Workspace egress token from CMMD for this turn. Refusing rather than falling back to the personal login.";
97853
+ const CLAUDE_WORKSPACE_EGRESS_REFUSAL_LOWER = CLAUDE_WORKSPACE_EGRESS_REFUSAL.toLowerCase();
97820
97854
  function isProviderRateOrQuotaError(message) {
97821
97855
  if (!message) return false;
97822
97856
  const normalized = message.toLowerCase();
@@ -97840,6 +97874,7 @@ function providerLifecycleOrAccountCopy(message) {
97840
97874
  function categorizePublicProviderError(message) {
97841
97875
  if (!message) return null;
97842
97876
  const m = message.toLowerCase();
97877
+ if (m.includes(CLAUDE_WORKSPACE_EGRESS_REFUSAL_LOWER)) return CLAUDE_WORKSPACE_EGRESS_REFUSAL;
97843
97878
  const lifecycleOrAccountCopy = providerLifecycleOrAccountCopy(m);
97844
97879
  if (lifecycleOrAccountCopy !== null) return lifecycleOrAccountCopy;
97845
97880
  if (/\bforge_provider_model_not_allowed\b/.test(m) || /\bnot\s+scoped\s+to\s+the\s+requested\s+model\b/.test(m)) return "The workspace AI credential does not cover the model this turn asked for. Retry, or pick that model for the thread.";
@@ -115458,7 +115493,7 @@ const postgresSchemaStatements = [
115458
115493
  "CREATE TABLE IF NOT EXISTS checkpoint_diff_blobs (\n thread_id TEXT NOT NULL,\n from_turn_count INTEGER NOT NULL,\n to_turn_count INTEGER NOT NULL,\n diff TEXT NOT NULL,\n created_at TEXT NOT NULL,\n UNIQUE (thread_id, from_turn_count, to_turn_count)\n )",
115459
115494
  "CREATE TABLE IF NOT EXISTS provider_session_runtime (\n thread_id TEXT PRIMARY KEY,\n provider_name TEXT NOT NULL,\n adapter_key TEXT NOT NULL,\n runtime_mode TEXT NOT NULL DEFAULT 'full-access',\n status TEXT NOT NULL,\n last_seen_at TEXT NOT NULL,\n resume_cursor_json TEXT,\n runtime_payload_json TEXT\n )",
115460
115495
  "CREATE TABLE IF NOT EXISTS projection_projects (\n project_id TEXT PRIMARY KEY,\n title TEXT NOT NULL,\n workspace_root TEXT NOT NULL,\n scripts_json TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n deleted_at TEXT\n , default_model_selection_json TEXT, default_thread_env_mode TEXT, cmmd_registration_json TEXT)",
115461
- "CREATE TABLE IF NOT EXISTS projection_threads (\n thread_id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n title TEXT NOT NULL,\n branch TEXT,\n worktree_path TEXT,\n latest_turn_id TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n deleted_at TEXT\n , runtime_mode TEXT NOT NULL DEFAULT 'full-access', interaction_mode TEXT NOT NULL DEFAULT 'default', model_selection_json TEXT, archived_at TEXT, latest_user_message_at TEXT, pending_approval_count INTEGER NOT NULL DEFAULT 0, pending_user_input_count INTEGER NOT NULL DEFAULT 0, has_actionable_proposed_plan INTEGER NOT NULL DEFAULT 0, kind TEXT NOT NULL DEFAULT 'master', parent_thread_id TEXT, status TEXT NOT NULL DEFAULT 'idle', anchor_kind TEXT NOT NULL DEFAULT 'scratch', anchor_cmmd_id TEXT, worker_role TEXT DEFAULT NULL, goal TEXT, pending_auto_create_prompt_json TEXT, title_regeneration_json TEXT, rate_limit_status_json TEXT, linked_pull_request_json TEXT, settled_at TEXT, settled_override TEXT, work_session_id TEXT, work_session_bound_at TEXT)",
115496
+ "CREATE TABLE IF NOT EXISTS projection_threads (\n thread_id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n title TEXT NOT NULL,\n branch TEXT,\n worktree_path TEXT,\n latest_turn_id TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n deleted_at TEXT\n , runtime_mode TEXT NOT NULL DEFAULT 'full-access', interaction_mode TEXT NOT NULL DEFAULT 'default', model_selection_json TEXT, archived_at TEXT, latest_user_message_at TEXT, pending_approval_count INTEGER NOT NULL DEFAULT 0, pending_user_input_count INTEGER NOT NULL DEFAULT 0, has_actionable_proposed_plan INTEGER NOT NULL DEFAULT 0, kind TEXT NOT NULL DEFAULT 'master', parent_thread_id TEXT, status TEXT NOT NULL DEFAULT 'idle', anchor_kind TEXT NOT NULL DEFAULT 'scratch', anchor_cmmd_id TEXT, worker_role TEXT DEFAULT NULL, goal TEXT, pending_auto_create_prompt_json TEXT, title_regeneration_json TEXT, rate_limit_status_json TEXT, linked_pull_request_json TEXT, settled_at TEXT, settled_override TEXT, work_session_id TEXT, work_session_bound_at TEXT, wallet TEXT)",
115462
115497
  "CREATE TABLE IF NOT EXISTS projection_thread_messages (\n message_id TEXT PRIMARY KEY,\n thread_id TEXT NOT NULL,\n turn_id TEXT,\n role TEXT NOT NULL,\n text TEXT NOT NULL,\n is_streaming INTEGER NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n , attachments_json TEXT)",
115463
115498
  "CREATE TABLE IF NOT EXISTS projection_thread_activities (\n activity_id TEXT PRIMARY KEY,\n thread_id TEXT NOT NULL,\n turn_id TEXT,\n tone TEXT NOT NULL,\n kind TEXT NOT NULL,\n summary TEXT NOT NULL,\n payload_json TEXT NOT NULL,\n created_at TEXT NOT NULL\n , sequence INTEGER)",
115464
115499
  "CREATE TABLE IF NOT EXISTS projection_thread_sessions (\n thread_id TEXT PRIMARY KEY,\n status TEXT NOT NULL,\n provider_name TEXT,\n provider_session_id TEXT,\n provider_thread_id TEXT,\n active_turn_id TEXT,\n last_error TEXT,\n updated_at TEXT NOT NULL\n , runtime_mode TEXT NOT NULL DEFAULT 'full-access')",
@@ -115782,7 +115817,8 @@ const postgresUpgradeMigrations = new Map([
115782
115817
  ]],
115783
115818
  [77, [`ALTER TABLE projection_threads ADD COLUMN IF NOT EXISTS work_session_id TEXT`]],
115784
115819
  [78, [`ALTER TABLE projection_threads ADD COLUMN IF NOT EXISTS work_session_bound_at TEXT`]],
115785
- [79, [`ALTER TABLE command_access_tokens DROP COLUMN IF EXISTS refresh_token`]]
115820
+ [79, [`ALTER TABLE command_access_tokens DROP COLUMN IF EXISTS refresh_token`]],
115821
+ [80, [`ALTER TABLE projection_threads ADD COLUMN IF NOT EXISTS wallet TEXT`]]
115786
115822
  ]);
115787
115823
  function requirePostgresUpgradeStatements(version) {
115788
115824
  const statements = postgresUpgradeMigrations.get(version);
@@ -115808,15 +115844,15 @@ const runPostgresMigrations = fn$1("runPostgresMigrations")(function* () {
115808
115844
  ORDER BY version DESC
115809
115845
  LIMIT 1
115810
115846
  `)[0]?.version ?? 0;
115811
- if (currentVersion > 79) return yield* die$1(/* @__PURE__ */ new Error(`Forge Postgres schema ${currentVersion} is newer than server schema 79.`));
115847
+ if (currentVersion > 80) return yield* die$1(/* @__PURE__ */ new Error(`Forge Postgres schema ${currentVersion} is newer than server schema 80.`));
115812
115848
  if (currentVersion === 0) {
115813
115849
  for (const statement of postgresSchemaStatements) yield* sql.unsafe(statement);
115814
115850
  yield* sql`
115815
115851
  INSERT INTO forge_schema_migrations (version)
115816
- VALUES (${79})
115852
+ VALUES (${80})
115817
115853
  ON CONFLICT (version) DO NOTHING
115818
115854
  `;
115819
- } else for (let version = currentVersion + 1; version <= 79; version += 1) {
115855
+ } else for (let version = currentVersion + 1; version <= 80; version += 1) {
115820
115856
  const statements = yield* sync$1(() => requirePostgresUpgradeStatements(version));
115821
115857
  for (const statement of statements) yield* sql.unsafe(statement);
115822
115858
  yield* sql`
@@ -118644,6 +118680,21 @@ var _079_DropCommandRefreshToken_default = gen(function* () {
118644
118680
  yield* (yield* SqlClient)`ALTER TABLE command_access_tokens DROP COLUMN refresh_token`;
118645
118681
  });
118646
118682
  //#endregion
118683
+ //#region src/persistence/Migrations/080_ProjectionThreadWallet.ts
118684
+ /**
118685
+ * Stores the wallet the last CMMD kick named on a thread (CMMD#5917), so a
118686
+ * turn without one starts on it even after a server restart.
118687
+ */
118688
+ var _080_ProjectionThreadWallet_default = gen(function* () {
118689
+ const sql = yield* SqlClient;
118690
+ if (!(yield* sql`
118691
+ PRAGMA table_info(projection_threads)
118692
+ `).some((column) => column.name === "wallet")) yield* sql`
118693
+ ALTER TABLE projection_threads
118694
+ ADD COLUMN wallet TEXT
118695
+ `;
118696
+ });
118697
+ //#endregion
118647
118698
  //#region src/persistence/Migrations.ts
118648
118699
  /**
118649
118700
  * MigrationsLive - Migration runner with inline loader
@@ -119059,6 +119110,11 @@ const migrationEntries = [
119059
119110
  79,
119060
119111
  "DropCommandRefreshToken",
119061
119112
  _079_DropCommandRefreshToken_default
119113
+ ],
119114
+ [
119115
+ 80,
119116
+ "ProjectionThreadWallet",
119117
+ _080_ProjectionThreadWallet_default
119062
119118
  ]
119063
119119
  ];
119064
119120
  const makeMigrationLoader = (throughId) => fromRecord(Object.fromEntries(migrationEntries.filter(([id]) => throughId === void 0 || id <= throughId).map(([id, name, migration]) => [`${id}_${name}`, migration])));
@@ -152400,6 +152456,15 @@ function canIssueProviderEgressToken() {
152400
152456
  function canIssueApexProviderEgressToken() {
152401
152457
  return canIssueProviderEgressToken() || canRequestCmmdLocalUserProviderEgressToken();
152402
152458
  }
152459
+ /**
152460
+ * True on a CMMD cloud runtime that has everything the runtime mint route
152461
+ * needs: runtime mode, the control plane URL, the runtime id, a grant token,
152462
+ * and the provider proxy URL. `issueProviderEgressCredential` takes the
152463
+ * runtime mint path exactly when this holds.
152464
+ *
152465
+ * Exported for the Claude adapter, which mints Workspace Anthropic egress on
152466
+ * such a runtime for a turn stamped with the Workspace wallet (CMMD#5917).
152467
+ */
152403
152468
  function canIssueCmmdRuntimeProviderEgressToken() {
152404
152469
  return process.env.FORGE_CMMD_RUNTIME_MODE === "true" && Boolean(process.env.FORGE_COMMAND_APP_URL) && Boolean(process.env.FORGE_CMMD_RUNTIME_ID) && Boolean(runtimeGrantToken()) && Boolean(process.env.FORGE_PROVIDER_PROXY_URL);
152405
152470
  }
@@ -152977,7 +153042,7 @@ const CODEX_SKILLS_LIST_TIMEOUT_MS = 4e3;
152977
153042
  const CODEX_SUBAGENT_TOKEN_USAGE_METHOD = "forge/subagentTokenUsage/updated";
152978
153043
  const CODEX_VERSION_CHECK_TIMEOUT_MS = 15e3;
152979
153044
  const PROVIDER_EGRESS_TOKEN_REFRESH_MS = 1500 * 1e3;
152980
- const PROVIDER_EGRESS_TOKEN_REFRESH_DEFER_MS = 60 * 1e3;
153045
+ const PROVIDER_EGRESS_TOKEN_REFRESH_DEFER_MS$1 = 60 * 1e3;
152981
153046
  const INTERRUPT_REQUEST_TIMEOUT_MS = 2e3;
152982
153047
  const ANSI_ESCAPE_CHAR = String.fromCharCode(27);
152983
153048
  const ANSI_ESCAPE_REGEX = new RegExp(`${ANSI_ESCAPE_CHAR}\\[[0-9;]*m`, "g");
@@ -153799,7 +153864,7 @@ var CodexAppServerManager = class extends EventEmitter$1 {
153799
153864
  if (!context || context.stopping) return;
153800
153865
  if (context.session.activeTurnId || context.pending.size > 0) {
153801
153866
  this.emitLifecycleEvent(context, "session/tokenRefreshDeferred", "Workspace provider token refresh deferred until the active Codex turn finishes.");
153802
- this.scheduleProviderEgressTokenRefresh(context, PROVIDER_EGRESS_TOKEN_REFRESH_DEFER_MS);
153867
+ this.scheduleProviderEgressTokenRefresh(context, PROVIDER_EGRESS_TOKEN_REFRESH_DEFER_MS$1);
153803
153868
  return;
153804
153869
  }
153805
153870
  this.emitLifecycleEvent(context, "session/tokenRefreshRequired", "Workspace provider token is nearing expiry; restarting Codex session for recovery.");
@@ -192080,7 +192145,7 @@ var Vce = {
192080
192145
  function Ve() {
192081
192146
  return Vce;
192082
192147
  }
192083
- var Us = $U.homedir(), lk = $U.tmpdir(), { env: Vc } = process$1, Yce = (e) => {
192148
+ var Us = os.homedir(), lk = os.tmpdir(), { env: Vc } = process$1, Yce = (e) => {
192084
192149
  let t = path.join(Us, "Library");
192085
192150
  return {
192086
192151
  data: path.join(t, "Application Support", e),
@@ -202280,12 +202345,12 @@ function qZ(e, t) {
202280
202345
  }
202281
202346
  return n;
202282
202347
  }
202283
- var os$1 = "https://code.claude.com/docs/en", kKe = [
202348
+ var os$2 = "https://code.claude.com/docs/en", kKe = [
202284
202349
  {
202285
202350
  matches: (e) => e.path === "permissions.defaultMode" && e.code === "invalid_value",
202286
202351
  tip: {
202287
202352
  suggestion: "Valid modes: \"acceptEdits\" (ask before file changes), \"plan\" (analysis only), \"bypassPermissions\" (auto-accept all), or \"default\" (standard behavior)",
202288
- docLink: `${os$1}/iam#permission-modes`
202353
+ docLink: `${os$2}/iam#permission-modes`
202289
202354
  }
202290
202355
  },
202291
202356
  {
@@ -202300,7 +202365,7 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
202300
202365
  matches: (e) => e.path.startsWith("env.") && e.code === "invalid_type",
202301
202366
  tip: {
202302
202367
  suggestion: "Environment variables must be strings. Wrap numbers and booleans in quotes. Example: \"DEBUG\": \"true\", \"PORT\": \"3000\"",
202303
- docLink: `${os$1}/settings#environment-variables`
202368
+ docLink: `${os$2}/settings#environment-variables`
202304
202369
  }
202305
202370
  },
202306
202371
  {
@@ -202311,14 +202376,14 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
202311
202376
  matches: (e) => e.path.startsWith("hooks.") && e.code === "invalid_key",
202312
202377
  tip: {
202313
202378
  suggestion: "Not a recognized hook event. Common events: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, SessionEnd, Stop. Check spelling and capitalization.",
202314
- docLink: `${os$1}/hooks`
202379
+ docLink: `${os$2}/hooks`
202315
202380
  }
202316
202381
  },
202317
202382
  {
202318
202383
  matches: (e) => /\.hooks\.\d+\.command$/.test(e.path) && e.code === "invalid_type" && e.received === "undefined",
202319
202384
  tip: {
202320
202385
  suggestion: "Command hooks require `command`. For exec form (no shell), set `command` to the executable and `args` to its arguments: {\"type\": \"command\", \"command\": \"echo\", \"args\": [\"hi\"]}. For shell form, set `command` to the full shell string: {\"type\": \"command\", \"command\": \"echo hi\"}.",
202321
- docLink: `${os$1}/hooks#exec-form-and-shell-form`
202386
+ docLink: `${os$2}/hooks#exec-form-and-shell-form`
202322
202387
  }
202323
202388
  },
202324
202389
  {
@@ -202333,7 +202398,7 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
202333
202398
  matches: (e) => e.code === "unrecognized_keys",
202334
202399
  tip: {
202335
202400
  suggestion: "Check for typos or refer to the documentation for valid fields",
202336
- docLink: `${os$1}/settings`
202401
+ docLink: `${os$2}/settings`
202337
202402
  }
202338
202403
  },
202339
202404
  {
@@ -202348,13 +202413,13 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
202348
202413
  matches: (e) => e.path === "permissions.additionalDirectories" && e.code === "invalid_type",
202349
202414
  tip: {
202350
202415
  suggestion: "Must be an array of directory paths. Example: [\"~/projects\", \"/tmp/workspace\"]. You can also use --add-dir flag or /add-dir command",
202351
- docLink: `${os$1}/iam#working-directories`
202416
+ docLink: `${os$2}/iam#working-directories`
202352
202417
  }
202353
202418
  }
202354
202419
  ], AKe = {
202355
- permissions: `${os$1}/iam#configuring-permissions`,
202356
- env: `${os$1}/settings#environment-variables`,
202357
- hooks: `${os$1}/hooks`
202420
+ permissions: `${os$2}/iam#configuring-permissions`,
202421
+ env: `${os$2}/settings#environment-variables`,
202422
+ hooks: `${os$2}/hooks`
202358
202423
  };
202359
202424
  function GZ(e) {
202360
202425
  let t = kKe.find((r) => r.matches(e));
@@ -213972,6 +214037,48 @@ function hasConfiguredApexCredential(profiles) {
213972
214037
  }));
213973
214038
  }
213974
214039
  //#endregion
214040
+ //#region src/egress/providerEgressTokenRefresh.ts
214041
+ /**
214042
+ * How long to wait before restarting a session whose provider egress
214043
+ * credential is about to expire.
214044
+ *
214045
+ * CMMD-Center/CMMD#5917 review: the Workspace Anthropic egress token lives
214046
+ * one hour and is minted once, when a Claude session starts. The session
214047
+ * itself can run for many turns past that hour through its own prompt
214048
+ * queue, so without this the first turn after expiry fails with an opaque
214049
+ * 401 instead of an honest refusal. Restarting near expiry mints a fresh
214050
+ * token on the next turn instead, the same trade Codex already makes in
214051
+ * `codexAppServerManager.ts` (`scheduleProviderEgressTokenRefresh`).
214052
+ *
214053
+ * Kept in its own module so the delay math is testable without an Effect
214054
+ * runtime or a session map.
214055
+ */
214056
+ /** Restart this long before the token actually expires. */
214057
+ const PROVIDER_EGRESS_TOKEN_REFRESH_MARGIN_MS = 300 * 1e3;
214058
+ /**
214059
+ * Used when the credential carries no `expiresAt`, or one that fails to
214060
+ * parse. Conservative relative to the one-hour token life the review names,
214061
+ * so a missing timestamp fails toward an early, harmless restart rather than
214062
+ * toward never restarting at all.
214063
+ */
214064
+ const PROVIDER_EGRESS_TOKEN_REFRESH_FALLBACK_MS = 1500 * 1e3;
214065
+ /**
214066
+ * How long to wait before checking again when the refresh threshold arrives
214067
+ * mid-turn. Matches Codex's `PROVIDER_EGRESS_TOKEN_REFRESH_DEFER_MS`.
214068
+ */
214069
+ const PROVIDER_EGRESS_TOKEN_REFRESH_DEFER_MS = 60 * 1e3;
214070
+ /**
214071
+ * How long a session should wait, once idle, before restarting to mint a
214072
+ * fresh credential. Never negative: a credential that already expired, or
214073
+ * expires inside the margin, restarts immediately.
214074
+ */
214075
+ function providerEgressTokenRefreshDelayMs(expiresAt, nowMs) {
214076
+ if (!expiresAt) return PROVIDER_EGRESS_TOKEN_REFRESH_FALLBACK_MS;
214077
+ const expiresAtMs = Date.parse(expiresAt);
214078
+ if (Number.isNaN(expiresAtMs)) return PROVIDER_EGRESS_TOKEN_REFRESH_FALLBACK_MS;
214079
+ return Math.max(0, expiresAtMs - nowMs - PROVIDER_EGRESS_TOKEN_REFRESH_MARGIN_MS);
214080
+ }
214081
+ //#endregion
213975
214082
  //#region src/provider/claudeCredentialDirectory.ts
213976
214083
  /** Per-account credentials share the existing Claude transcript directory. */
213977
214084
  /** Repoints `.credentials.json` without moving the transcripts. */
@@ -216363,7 +216470,7 @@ function claudeForgeAttributionPrompt() {
216363
216470
  * turn, an API key is, so pointing the variable there would add a second source
216364
216471
  * of truth that a later reader has to rule out.
216365
216472
  */
216366
- function buildClaudeQueryEnv(baseProcessEnv, endpointProfile, claudeSettings, providerProxyCredential, credentialDirectory, selectedSubscription = false) {
216473
+ function buildClaudeQueryEnv(baseProcessEnv, endpointProfile, claudeSettings, providerProxyCredential, credentialDirectory, selectedSubscription = false, mintedEgressModel) {
216367
216474
  if (selectedSubscription) return claudeSubscriptionChildEnv(baseProcessEnv, credentialDirectory, true);
216368
216475
  const baseEnv = scrubForgeProviderChildEnvSecrets(baseProcessEnv);
216369
216476
  const effectiveBaseUrl = resolveClaudeQueryBaseUrl(endpointProfile, claudeSettings, providerProxyCredential);
@@ -216377,7 +216484,28 @@ function buildClaudeQueryEnv(baseProcessEnv, endpointProfile, claudeSettings, pr
216377
216484
  CLAUDE_CODE_MAX_RETRIES: "0",
216378
216485
  API_TIMEOUT_MS: "90000"
216379
216486
  } : {},
216380
- ...endpointProfile?.disableToolSearch === true ? { ENABLE_TOOL_SEARCH: "false" } : {}
216487
+ ...endpointProfile?.disableToolSearch === true ? { ENABLE_TOOL_SEARCH: "false" } : {},
216488
+ ...!endpointProfile && providerProxyCredential && mintedEgressModel ? claudeWorkspaceEgressModelPins(mintedEgressModel) : {}
216489
+ };
216490
+ }
216491
+ /**
216492
+ * CMMD's Workspace egress proxy only accepts the model(s) named on the mint
216493
+ * request that issued `providerProxyCredential`, and the mint above scopes to
216494
+ * one selected model (`forge-provider-egress.routes.ts` `modelScopeError`).
216495
+ * Left alone, Claude Code and its subagents still pick their own smaller
216496
+ * models for background and Explore-subagent calls, which fall outside that
216497
+ * scope and get refused. Pinning every one of those picks to the same model
216498
+ * the mint requested keeps the whole session inside it.
216499
+ *
216500
+ * Only the plain Anthropic egress branch gets these — never an
216501
+ * endpoint-profile turn (Apex / DeepSeek / Moonshot), whose upstream model
216502
+ * catalog and scoping this does not apply to.
216503
+ */
216504
+ function claudeWorkspaceEgressModelPins(model) {
216505
+ return {
216506
+ ANTHROPIC_SMALL_FAST_MODEL: model,
216507
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: model,
216508
+ CLAUDE_CODE_SUBAGENT_MODEL: model
216381
216509
  };
216382
216510
  }
216383
216511
  function resolveClaudeQueryBaseUrl(endpointProfile, claudeSettings, providerProxyCredential) {
@@ -216481,7 +216609,8 @@ function buildClaudeSessionContext(input) {
216481
216609
  lastThreadStartedId: void 0,
216482
216610
  stopped: false,
216483
216611
  currentApiModelId: input.effectiveApiModelId,
216484
- currentEffort: input.effectiveEffort
216612
+ currentEffort: input.effectiveEffort,
216613
+ tokenRefreshFiber: void 0
216485
216614
  };
216486
216615
  }
216487
216616
  function claudeSessionConfiguredConfig(input) {
@@ -216782,8 +216911,34 @@ function shouldUseProviderEgressProxy(profile) {
216782
216911
  const normalized = profile.baseUrl.toLowerCase();
216783
216912
  return normalized.includes("apex.cmmd.ai") || normalized.includes("deepseek") || normalized.includes("moonshot");
216784
216913
  }
216785
- function resolveClaudeProviderEgressProvider(profile) {
216914
+ /**
216915
+ * True for a plain Claude turn (no custom endpoint profile) stamped with the
216916
+ * Workspace wallet on a CMMD cloud runtime.
216917
+ *
216918
+ * That turn has to run through CMMD's metered Workspace egress, because CMMD
216919
+ * accepted the wallet choice and enforces it only at mint time and at the
216920
+ * proxy. The personal Claude login in the VM is never an acceptable stand-in,
216921
+ * so every path below refuses the turn rather than falling back to it
216922
+ * (CMMD#5917). Runtime mode alone decides "on a CMMD runtime": a runtime whose
216923
+ * mint settings are incomplete still counts, and is refused.
216924
+ */
216925
+ function isClaudeWorkspaceWalletTurnOnCmmdRuntime(profile, wallet) {
216926
+ return wallet === "workspace" && !profile?.baseUrl && process.env.FORGE_CMMD_RUNTIME_MODE === "true";
216927
+ }
216928
+ /**
216929
+ * Which egress lane, if any, a Claude session mints a proxy token for.
216930
+ *
216931
+ * - `apex`: a centrally managed Apex profile, whatever the wallet.
216932
+ * - `anthropic` for a Workspace-wallet turn on a CMMD runtime that can mint.
216933
+ * This is a narrow exception to `WORKSPACE_PROVIDER_ACCESS_DISABLED`, which
216934
+ * still governs every other plain Claude turn (CMMD#5917).
216935
+ * - `anthropic` through the local-user lane when the shared kill switch is
216936
+ * off. Unchanged, and never reached on a CMMD runtime.
216937
+ * - `null` otherwise, which leaves the turn on the personal login.
216938
+ */
216939
+ function resolveClaudeProviderEgressProvider(profile, wallet) {
216786
216940
  if (shouldUseProviderEgressProxy(profile)) return "apex";
216941
+ if (isClaudeWorkspaceWalletTurnOnCmmdRuntime(profile, wallet) && canIssueCmmdRuntimeProviderEgressToken()) return "anthropic";
216787
216942
  if (!profile?.baseUrl && false);
216788
216943
  return null;
216789
216944
  }
@@ -218404,6 +218559,9 @@ const makeClaudeAdapter = fn$1("makeClaudeAdapter")(function* (options) {
218404
218559
  const streamFiber = context.streamFiber;
218405
218560
  context.streamFiber = void 0;
218406
218561
  if (streamFiber && streamFiber.pollUnsafe() === void 0) yield* interrupt$4(streamFiber);
218562
+ const tokenRefreshFiber = context.tokenRefreshFiber;
218563
+ context.tokenRefreshFiber = void 0;
218564
+ if (tokenRefreshFiber && tokenRefreshFiber.pollUnsafe() === void 0) yield* interrupt$4(tokenRefreshFiber);
218407
218565
  try {
218408
218566
  context.query.close();
218409
218567
  selectedClaudeCredentialStore(serverConfig.baseDir).release(context.session.threadId);
@@ -218434,6 +218592,35 @@ const makeClaudeAdapter = fn$1("makeClaudeAdapter")(function* (options) {
218434
218592
  }
218435
218593
  sessions.delete(context.session.threadId);
218436
218594
  });
218595
+ /**
218596
+ * Restarts `threadId`'s session near its Workspace Anthropic egress
218597
+ * credential's expiry, once idle (CMMD-Center/CMMD#5917 review). Deferred
218598
+ * rather than run while a turn is active, the same trade
218599
+ * `scheduleProviderEgressTokenRefresh` makes for Codex in
218600
+ * `codexAppServerManager.ts`: interrupting mid-turn would trade a clean
218601
+ * 401 for a broken one.
218602
+ *
218603
+ * A known gap, same as Codex's: a single turn that runs past the
218604
+ * credential's actual expiry still fails mid-turn with a 401. This only
218605
+ * covers the idle-session case.
218606
+ */
218607
+ const scheduleWorkspaceEgressTokenRefresh = (context, credential, runFork) => {
218608
+ const threadId = context.session.threadId;
218609
+ context.tokenRefreshFiber = runFork(gen(function* () {
218610
+ let delayMs = providerEgressTokenRefreshDelayMs(credential.expiresAt, Date.now());
218611
+ while (true) {
218612
+ yield* sleep$4(delayMs);
218613
+ const current = sessions.get(threadId);
218614
+ if (!current || current !== context || current.stopped) return;
218615
+ if (current.turnState) {
218616
+ delayMs = PROVIDER_EGRESS_TOKEN_REFRESH_DEFER_MS;
218617
+ continue;
218618
+ }
218619
+ yield* stopSessionInternal(current, { emitExitEvent: true });
218620
+ return;
218621
+ }
218622
+ }));
218623
+ };
218437
218624
  const requireSession = (threadId) => {
218438
218625
  const context = sessions.get(threadId);
218439
218626
  if (!context) return fail(new ProviderAdapterSessionNotFoundError({
@@ -218628,19 +218815,46 @@ const makeClaudeAdapter = fn$1("makeClaudeAdapter")(function* (options) {
218628
218815
  });
218629
218816
  return (toolName, toolInput, callbackOptions) => runPromise(canUseToolEffect(toolName, toolInput, callbackOptions));
218630
218817
  };
218631
- const issueClaudeProviderProxyCredential = fn$1("issueClaudeProviderProxyCredential")(function* (endpointProfile, model, threadId) {
218632
- const provider = resolveClaudeProviderEgressProvider(endpointProfile);
218633
- if (!provider) return null;
218634
- return yield* issueProviderEgressCredential({
218818
+ /**
218819
+ * Mints the egress proxy credential this session runs on, or returns null
218820
+ * when the session runs on the personal login.
218821
+ *
218822
+ * A Workspace-wallet turn on a CMMD runtime never gets null: it either mints
218823
+ * Anthropic egress on a workspace_key receipt or fails here with
218824
+ * CLAUDE_WORKSPACE_EGRESS_REFUSAL, which
218825
+ * stops `startSession` before the child environment is built, so the
218826
+ * personal-login branch of `buildClaudeQueryEnv` is never reached for it.
218827
+ */
218828
+ const issueClaudeProviderProxyCredential = fn$1("issueClaudeProviderProxyCredential")(function* (endpointProfile, model, threadId, wallet) {
218829
+ const workspaceWalletTurn = isClaudeWorkspaceWalletTurnOnCmmdRuntime(endpointProfile, wallet);
218830
+ const provider = resolveClaudeProviderEgressProvider(endpointProfile, wallet);
218831
+ if (!provider) {
218832
+ if (workspaceWalletTurn) return yield* new ProviderAdapterProcessError({
218833
+ provider: PROVIDER$11,
218834
+ threadId,
218835
+ detail: `${CLAUDE_WORKSPACE_EGRESS_REFUSAL} This runtime is missing the CMMD settings it needs to request one.`
218836
+ });
218837
+ return null;
218838
+ }
218839
+ const credential = yield* issueProviderEgressCredential({
218635
218840
  provider,
218636
218841
  model,
218637
218842
  threadId
218638
- }).pipe(mapError((cause) => new ProviderAdapterProcessError({
218843
+ }).pipe(mapError((cause) => {
218844
+ const reason = toMessage(cause, "Failed to issue provider proxy token.");
218845
+ return new ProviderAdapterProcessError({
218846
+ provider: PROVIDER$11,
218847
+ threadId,
218848
+ detail: workspaceWalletTurn && provider === "anthropic" ? `${CLAUDE_WORKSPACE_EGRESS_REFUSAL} ${reason}` : reason,
218849
+ cause
218850
+ });
218851
+ }));
218852
+ if (workspaceWalletTurn && provider === "anthropic" && credential.deliveryReceipt?.identity.kind !== "workspace_key") return yield* new ProviderAdapterProcessError({
218639
218853
  provider: PROVIDER$11,
218640
218854
  threadId,
218641
- detail: toMessage(cause, "Failed to issue provider proxy token."),
218642
- cause
218643
- })));
218855
+ detail: `${CLAUDE_WORKSPACE_EGRESS_REFUSAL} CMMD issued a credential that is not a Workspace key.`
218856
+ });
218857
+ return credential;
218644
218858
  });
218645
218859
  const createClaudeQueryRuntime = fn$1("createClaudeQueryRuntime")(function* (prompt, queryOptions, threadId) {
218646
218860
  return yield* try_({
@@ -218755,6 +218969,12 @@ const makeClaudeAdapter = fn$1("makeClaudeAdapter")(function* (options) {
218755
218969
  claudeCredentialDirectory: credentialDirectoryDecision.outcome === "set" ? credentialDirectoryDecision.directory : null
218756
218970
  };
218757
218971
  });
218972
+ /**
218973
+ * Starts a Claude SDK session for a thread. The model access it runs on is
218974
+ * decided here, once: a selected account's credential, a minted egress proxy
218975
+ * credential, an endpoint profile, or the personal login. A Workspace-wallet
218976
+ * turn on a CMMD runtime is refused rather than given the personal login.
218977
+ */
218758
218978
  const startSession = fn$1("startSession")(function* (input) {
218759
218979
  const sessionProvider = yield* validateClaudeStartSessionProvider(input.provider);
218760
218980
  const startedAt = yield* nowIso;
@@ -218843,7 +219063,13 @@ const makeClaudeAdapter = fn$1("makeClaudeAdapter")(function* (options) {
218843
219063
  operation: "startSession",
218844
219064
  issue: "The selected Claude account cannot be used with a custom API endpoint. Choose a subscription model."
218845
219065
  });
218846
- const providerProxyCredential = selectedAccountIdentity !== null ? null : yield* issueClaudeProviderProxyCredential(modelConfig.endpointProfile, modelConfig.modelSlug ?? modelConfig.effectiveApiModelId ?? "unknown", threadId);
219066
+ if (selectedAccountIdentity !== null && isClaudeWorkspaceWalletTurnOnCmmdRuntime(modelConfig.endpointProfile, input.wallet)) return yield* new ProviderAdapterValidationError({
219067
+ provider: PROVIDER$11,
219068
+ operation: "startSession",
219069
+ issue: "This turn is billed to the Workspace wallet, so it cannot run on a selected personal Claude account. Clear the account choice, or start the task on your own wallet."
219070
+ });
219071
+ const mintedEgressModel = modelConfig.modelSlug ?? modelConfig.effectiveApiModelId ?? "unknown";
219072
+ const providerProxyCredential = selectedAccountIdentity !== null ? null : yield* issueClaudeProviderProxyCredential(modelConfig.endpointProfile, mintedEgressModel, threadId, input.wallet);
218847
219073
  const permissionMode = permissionModeForRuntimeMode(input.runtimeMode);
218848
219074
  const settings = claudeQuerySettings(modelConfig.thinking, modelConfig.fastMode);
218849
219075
  const workspacePreflight = input.cwd ? formatWorkspaceEnvironmentPreflightForAgent(runWorkspaceEnvironmentPreflight({ cwd: input.cwd })) : void 0;
@@ -218866,7 +219092,7 @@ const makeClaudeAdapter = fn$1("makeClaudeAdapter")(function* (options) {
218866
219092
  existingResumeSessionId,
218867
219093
  newSessionId,
218868
219094
  canUseTool,
218869
- env: buildClaudeQueryEnv(process.env, modelConfig.endpointProfile, claudeSettings, providerProxyCredential, claudeCredentialDirectory, selectedAccountIdentity !== null),
219095
+ env: buildClaudeQueryEnv(process.env, modelConfig.endpointProfile, claudeSettings, providerProxyCredential, claudeCredentialDirectory, selectedAccountIdentity !== null, mintedEgressModel),
218870
219096
  browserManager,
218871
219097
  threadId,
218872
219098
  browserToolEnvironmentId,
@@ -218919,6 +219145,7 @@ const makeClaudeAdapter = fn$1("makeClaudeAdapter")(function* (options) {
218919
219145
  })
218920
219146
  });
218921
219147
  attachClaudeStreamFiber(context$4, runFork);
219148
+ if (providerProxyCredential?.deliveryReceipt?.identity.kind === "workspace_key") scheduleWorkspaceEgressTokenRefresh(context$4, providerProxyCredential, runFork);
218922
219149
  return { ...session };
218923
219150
  }, (effect, input) => effect.pipe(onExit((exit) => sync$1(() => {
218924
219151
  if (exit._tag === "Failure") selectedClaudeCredentialStore(serverConfig.baseDir).release(input.threadId);
@@ -233284,6 +233511,11 @@ function toRuntimeStatus(session) {
233284
233511
  default: return "running";
233285
233512
  }
233286
233513
  }
233514
+ /**
233515
+ * The runtime payload persisted beside a session binding. The session directory
233516
+ * merges it shallowly into what is already stored, so a key left out here
233517
+ * (a later upsert with no wallet, say) keeps its earlier value.
233518
+ */
233287
233519
  function toRuntimePayloadFromSession(session, extra) {
233288
233520
  return {
233289
233521
  cwd: session.cwd ?? null,
@@ -233291,6 +233523,7 @@ function toRuntimePayloadFromSession(session, extra) {
233291
233523
  activeTurnId: session.activeTurnId ?? null,
233292
233524
  lastError: session.lastError ?? null,
233293
233525
  ...extra?.modelSelection !== void 0 ? { modelSelection: extra.modelSelection } : {},
233526
+ ...extra?.wallet !== void 0 ? { wallet: extra.wallet } : {},
233294
233527
  ...extra?.lastRuntimeEvent !== void 0 ? { lastRuntimeEvent: extra.lastRuntimeEvent } : {},
233295
233528
  ...extra?.lastRuntimeEventAt !== void 0 ? { lastRuntimeEventAt: extra.lastRuntimeEventAt } : {}
233296
233529
  };
@@ -233300,6 +233533,34 @@ function readPersistedModelSelection(runtimePayload) {
233300
233533
  const raw = "modelSelection" in runtimePayload ? runtimePayload.modelSelection : void 0;
233301
233534
  return is$1(ModelSelection)(raw) ? raw : void 0;
233302
233535
  }
233536
+ /**
233537
+ * The wallet the thread's provider session last started with, read back from
233538
+ * the persisted runtime payload (CMMD#5917).
233539
+ *
233540
+ * Only a CMMD kick names a wallet. Every other start (a person's follow-up
233541
+ * that changes the model, a recovery after the adapter lost the session)
233542
+ * reuses this one, so a thread billed to the Workspace wallet does not drop to
233543
+ * the personal login the first time its session restarts. Undefined when no
233544
+ * kick ever named one, which keeps today's behavior.
233545
+ */
233546
+ const isWorkSessionWallet = is$1(WorkSessionWallet);
233547
+ function readPersistedWallet(runtimePayload) {
233548
+ if (!runtimePayload || typeof runtimePayload !== "object" || Array.isArray(runtimePayload)) return;
233549
+ const raw = "wallet" in runtimePayload ? runtimePayload.wallet : void 0;
233550
+ return isWorkSessionWallet(raw) ? raw : void 0;
233551
+ }
233552
+ /**
233553
+ * The wallet a new session starts on: the one the kick named, else the one the
233554
+ * thread's session last ran with, whatever provider that was, because the
233555
+ * wallet belongs to the Work Session and not to the provider (CMMD#5917).
233556
+ */
233557
+ function resolveStartSessionWallet(requested, persistedBinding) {
233558
+ return requested ?? readPersistedWallet(persistedBinding?.runtimePayload);
233559
+ }
233560
+ /** `{ wallet }` when one is known, an empty object otherwise (exactOptionalPropertyTypes). */
233561
+ function walletField$1(wallet) {
233562
+ return wallet === void 0 ? {} : { wallet };
233563
+ }
233303
233564
  function readProviderAccountIdFromModelSelection(modelSelection) {
233304
233565
  if (!modelSelection) return void 0;
233305
233566
  switch (modelSelection.provider) {
@@ -233334,12 +233595,18 @@ const makeProviderService = fn$1("makeProviderService")(function* (options) {
233334
233595
  const withSessionLock = (threadId, effect) => get$5(sessionLocks, threadId).pipe(flatMap((lock) => lock.withPermit(effect)), scoped);
233335
233596
  const runtimeEventPubSub = yield* unbounded$1();
233336
233597
  const assertProviderExecutable = options?.assertProviderExecutable ?? (() => succeed(null));
233598
+ /**
233599
+ * Re-runs the readiness guard for an existing session before a turn or a
233600
+ * continuation, with the account and wallet the session was started on, and
233601
+ * refuses if the delivered identity drifted from the persisted one.
233602
+ */
233337
233603
  const assertCurrentProviderDelivery = fn$1("assertCurrentProviderDelivery")(function* (input) {
233338
233604
  const persistedBinding = getOrUndefined(yield* directory.getBinding(input.threadId));
233339
233605
  const providerAccountId = readPersistedProviderAccountId(persistedBinding?.runtimePayload);
233340
233606
  const currentBinding = yield* assertProviderExecutable({
233341
233607
  ...input,
233342
- ...selectedAccountGuardFields(providerAccountId)
233608
+ ...selectedAccountGuardFields(providerAccountId),
233609
+ ...walletField$1(readPersistedWallet(persistedBinding?.runtimePayload))
233343
233610
  });
233344
233611
  if (!currentBinding) return;
233345
233612
  if (!persistedBinding || persistedBinding.provider !== input.provider) return yield* toValidationError(input.operation, `Cannot verify the delivered provider identity for thread '${input.threadId}'.`);
@@ -233355,6 +233622,11 @@ const makeProviderService = fn$1("makeProviderService")(function* (options) {
233355
233622
  return yield* toValidationError(input.operation, `Thread '${input.threadId}' is bound to provider account '${input.persistedAccountId}' and cannot use provider account '${input.requestedAccountId}'.`);
233356
233623
  });
233357
233624
  const publishRuntimeEvent = (event) => succeed(event).pipe(tap((canonicalEvent) => canonicalEventLogger ? canonicalEventLogger.write(canonicalEvent, null) : void_$1), flatMap((canonicalEvent) => publish(runtimeEventPubSub, canonicalEvent)), asVoid);
233625
+ /**
233626
+ * Writes the thread's session binding. `extra` carries what only a start
233627
+ * knows, the model selection and the wallet, so a later runtime-event upsert
233628
+ * that omits them leaves the stored values in place.
233629
+ */
233358
233630
  const upsertSessionBinding = (session, threadId, extra) => directory.upsert({
233359
233631
  threadId,
233360
233632
  provider: session.provider,
@@ -233369,6 +233641,11 @@ const makeProviderService = fn$1("makeProviderService")(function* (options) {
233369
233641
  eventType: event.type
233370
233642
  }).pipe(andThen(publishRuntimeEvent(event)));
233371
233643
  yield* forEach(adapters, (adapter) => runForEach(adapter.streamEvents, processRuntimeEvent).pipe(forkScoped)).pipe(asVoid);
233644
+ /**
233645
+ * Restarts a session the adapter lost, from the persisted binding alone: cwd,
233646
+ * model selection, wallet and resume cursor. It has no read model, so what
233647
+ * the binding stored is all it can go on.
233648
+ */
233372
233649
  const recoverSessionForThread = fn$1("recoverSessionForThread")(function* (input) {
233373
233650
  yield* annotateCurrentSpan({
233374
233651
  "provider.operation": "recover-session",
@@ -233397,11 +233674,13 @@ const makeProviderService = fn$1("makeProviderService")(function* (options) {
233397
233674
  const persistedCwd = readPersistedCwd(input.binding.runtimePayload);
233398
233675
  const persistedModelSelection = readPersistedModelSelection(input.binding.runtimePayload);
233399
233676
  const persistedProviderAccountId = readProviderAccountIdFromModelSelection(persistedModelSelection);
233677
+ const persistedWallet = readPersistedWallet(input.binding.runtimePayload);
233400
233678
  const currentDeliveryBinding = yield* assertProviderExecutable({
233401
233679
  threadId: input.binding.threadId,
233402
233680
  provider: input.binding.provider,
233403
233681
  operation: input.operation,
233404
- ...selectedAccountGuardFields(persistedProviderAccountId)
233682
+ ...selectedAccountGuardFields(persistedProviderAccountId),
233683
+ ...walletField$1(persistedWallet)
233405
233684
  });
233406
233685
  const boundResumeCursor = yield* bindProviderDeliveryToResumeCursor({
233407
233686
  operation: input.operation,
@@ -233415,7 +233694,8 @@ const makeProviderService = fn$1("makeProviderService")(function* (options) {
233415
233694
  ...persistedCwd ? { cwd: persistedCwd } : {},
233416
233695
  ...persistedModelSelection ? { modelSelection: persistedModelSelection } : {},
233417
233696
  ...hasResumeCursor ? { resumeCursor: boundResumeCursor } : {},
233418
- runtimeMode: input.binding.runtimeMode ?? "full-access"
233697
+ runtimeMode: input.binding.runtimeMode ?? "full-access",
233698
+ ...walletField$1(persistedWallet)
233419
233699
  });
233420
233700
  if (resumed.provider !== adapter.provider) return yield* toValidationError(input.operation, `Adapter/provider mismatch while recovering thread '${input.binding.threadId}'. Expected '${adapter.provider}', received '${resumed.provider}'.`);
233421
233701
  yield* upsertSessionBinding(resumed, input.binding.threadId);
@@ -233487,6 +233767,11 @@ const makeProviderService = fn$1("makeProviderService")(function* (options) {
233487
233767
  isActive: true
233488
233768
  };
233489
233769
  });
233770
+ /**
233771
+ * Starts a provider session for a thread: decodes the input, resolves the
233772
+ * provider, guards account and delivery identity, resolves the wallet, then
233773
+ * persists the binding the adapter returns.
233774
+ */
233490
233775
  const startSession = fn$1("startSession")(function* (threadId, rawInput) {
233491
233776
  const parsed = yield* decodeInputOrValidationError({
233492
233777
  operation: "ProviderService.startSession",
@@ -233519,24 +233804,31 @@ const makeProviderService = fn$1("makeProviderService")(function* (options) {
233519
233804
  persistedAccountId: priorAccountId,
233520
233805
  requestedAccountId
233521
233806
  });
233807
+ const effectiveResumeCursor = input.resumeCursor ?? (persistedBinding?.provider === effectiveProvider ? persistedBinding.resumeCursor : void 0);
233808
+ const effectiveWallet = resolveStartSessionWallet(input.wallet, persistedBinding);
233522
233809
  const boundResumeCursor = yield* bindProviderDeliveryToResumeCursor({
233523
233810
  operation: "ProviderService.startSession",
233524
233811
  provider: effectiveProvider,
233525
- resumeCursor: input.resumeCursor ?? (persistedBinding?.provider === effectiveProvider ? persistedBinding.resumeCursor : void 0),
233812
+ resumeCursor: effectiveResumeCursor,
233526
233813
  currentBinding: yield* assertProviderExecutable({
233527
233814
  threadId,
233528
233815
  provider: effectiveProvider,
233529
233816
  operation: "ProviderService.startSession",
233530
- ...selectedAccountGuardFields(requestedAccountId)
233817
+ ...selectedAccountGuardFields(requestedAccountId),
233818
+ ...walletField$1(effectiveWallet)
233531
233819
  })
233532
233820
  });
233533
233821
  const session = yield* adapter.startSession({
233534
233822
  ...input,
233535
233823
  accountTransition: explicitProviderAccountTransition(priorAccountId, requestedAccountId),
233536
- ...boundResumeCursor !== void 0 ? { resumeCursor: boundResumeCursor } : {}
233824
+ ...boundResumeCursor !== void 0 ? { resumeCursor: boundResumeCursor } : {},
233825
+ ...walletField$1(effectiveWallet)
233537
233826
  });
233538
233827
  if (session.provider !== adapter.provider) return yield* toValidationError("ProviderService.startSession", `Adapter/provider mismatch: requested '${adapter.provider}', received '${session.provider}'.`);
233539
- yield* upsertSessionBinding(session, threadId, { modelSelection: input.modelSelection });
233828
+ yield* upsertSessionBinding(session, threadId, {
233829
+ modelSelection: input.modelSelection,
233830
+ ...walletField$1(effectiveWallet)
233831
+ });
233540
233832
  yield* analytics.record("provider.session.started", {
233541
233833
  provider: session.provider,
233542
233834
  runtimeMode: input.runtimeMode,
@@ -234337,8 +234629,13 @@ function makeClaudeRuntimeReadinessGuard(config, dependencies) {
234337
234629
  };
234338
234630
  return (input) => claudeReadinessGuardEffect(config, dependencies, resolved, input);
234339
234631
  }
234632
+ /**
234633
+ * One guard run: skip when the turn needs no delivered Claude credential,
234634
+ * prepare a selected account's credential when one is named, otherwise verify
234635
+ * the owner's native runtime generation against CMMD.
234636
+ */
234340
234637
  function claudeReadinessGuardEffect(config, dependencies, resolved, input) {
234341
- if (!requiresNativeClaudeReadiness(config, input.provider, input.providerAccountId)) return succeed(null);
234638
+ if (!requiresNativeClaudeReadiness(config, input.provider, input.providerAccountId, input.wallet)) return succeed(null);
234342
234639
  if (input.providerAccountId !== void 0) {
234343
234640
  const prepareSelectedCredential = dependencies.prepareSelectedCredential ?? makeClaudeSelectedCredentialPreparer(config, {
234344
234641
  resolveJwt: dependencies.resolveJwt,
@@ -234361,9 +234658,21 @@ function claudeReadinessGuardEffect(config, dependencies, resolved, input) {
234361
234658
  catch: (cause) => readinessValidationError(input.operation, cause)
234362
234659
  });
234363
234660
  }
234364
- function requiresNativeClaudeReadiness(config, provider, providerAccountId) {
234661
+ /**
234662
+ * Whether this turn runs on a Claude credential delivered into the VM, and so
234663
+ * has to prove that credential is the one CMMD applied before it runs.
234664
+ *
234665
+ * A turn billed to the Workspace wallet with no selected account does not: the
234666
+ * Claude adapter runs it on CMMD's metered egress and refuses it when CMMD
234667
+ * will not mint (CMMD#5917). Checking the owner's personal login there would
234668
+ * refuse a Workspace turn for a personal credential it never uses. A selected
234669
+ * account still goes through its own preparation, and the adapter then refuses
234670
+ * the Workspace-plus-account combination.
234671
+ */
234672
+ function requiresNativeClaudeReadiness(config, provider, providerAccountId, wallet) {
234365
234673
  if (provider !== "claudeAgent" || config.forgeCmmdRuntimeMode !== true) return false;
234366
- return providerAccountId !== void 0 || personalClaudeInVmEnabled();
234674
+ if (providerAccountId !== void 0) return true;
234675
+ return wallet !== "workspace" && personalClaudeInVmEnabled();
234367
234676
  }
234368
234677
  function resolveGuardAuthority(config, readSessionId, input) {
234369
234678
  const runtimeId = config.forgeCmmdRuntimeId?.trim();
@@ -270898,7 +271207,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
270898
271207
  var dgram = __require("dgram");
270899
271208
  var thunky = require_thunky();
270900
271209
  var events = __require("events");
270901
- var os = __require("os");
271210
+ var os$1 = __require("os");
270902
271211
  var noop = function() {};
270903
271212
  module.exports = function(opts) {
270904
271213
  if (!opts) opts = {};
@@ -271029,14 +271338,14 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
271029
271338
  return that;
271030
271339
  };
271031
271340
  function defaultInterface() {
271032
- var networks = os.networkInterfaces();
271341
+ var networks = os$1.networkInterfaces();
271033
271342
  var names = Object.keys(networks);
271034
271343
  for (var i = 0; i < names.length; i++) {
271035
271344
  var net = networks[names[i]];
271036
271345
  for (var j = 0; j < net.length; j++) {
271037
271346
  var iface = net[j];
271038
271347
  if (isIPv4(iface.family) && !iface.internal) {
271039
- if (os.platform() === "darwin" && names[i] === "en0") return iface.address;
271348
+ if (os$1.platform() === "darwin" && names[i] === "en0") return iface.address;
271040
271349
  return "0.0.0.0";
271041
271350
  }
271042
271351
  }
@@ -271044,7 +271353,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
271044
271353
  return "127.0.0.1";
271045
271354
  }
271046
271355
  function allInterfaces() {
271047
- var networks = os.networkInterfaces();
271356
+ var networks = os$1.networkInterfaces();
271048
271357
  var names = Object.keys(networks);
271049
271358
  var res = [];
271050
271359
  for (var i = 0; i < names.length; i++) {
@@ -288310,6 +288619,7 @@ const ProjectionThread = Struct({
288310
288619
  anchorCmmdId: NullOr(String$1).pipe(withDecodingDefault(succeed(null))),
288311
288620
  workSessionId: optionalKey(NullOr(String$1)),
288312
288621
  workSessionBoundAt: optionalKey(NullOr(String$1)),
288622
+ wallet: optionalKey(NullOr(WorkSessionWallet)),
288313
288623
  linkedPullRequest: optionalKey(NullOr(LinkedPullRequest)),
288314
288624
  status: ThreadStatus.pipe(withDecodingDefault(succeed("idle"))),
288315
288625
  workerRole: NullOr(WorkerRole).pipe(withDecodingDefault(succeed(null))),
@@ -292781,6 +293091,18 @@ function publicProviderFailureDetailFromCause(cause) {
292781
293091
  const error = squash(cause);
292782
293092
  return isProviderValidationError(error) ? publicProviderFailureDetailFromError(error) : publicProviderFailureDetail(pretty(cause));
292783
293093
  }
293094
+ /**
293095
+ * The wallet a session start asks for: the one on the turn-start event, which
293096
+ * the decider stamps at acceptance, else the one persisted on the thread row,
293097
+ * for older events and starts not driven by a turn (CMMD#5917). The decider writes the kick's
293098
+ * wallet to the thread before this reactor sees the turn, and the row
293099
+ * survives a restart, so a turn refused before any session start, or a
293100
+ * person's follow-up after a restart, still starts on the kick's wallet.
293101
+ * Undefined when no kick ever named one.
293102
+ */
293103
+ function resolveRequestedWallet(kickWallet, threadWallet) {
293104
+ return kickWallet ?? threadWallet ?? void 0;
293105
+ }
292784
293106
  function canReplaceThreadTitle(currentTitle, titleSeed) {
292785
293107
  const trimmedCurrentTitle = currentTitle.trim();
292786
293108
  if (trimmedCurrentTitle === DEFAULT_THREAD_TITLE) return true;
@@ -293101,6 +293423,16 @@ const ProviderCommandReactorLive = effect(ProviderCommandReactor, gen(function*
293101
293423
  * detect the mismatch and restart, dropping A's cached token (forge#3597).
293102
293424
  */
293103
293425
  const threadSessionWorkSessionIds = /* @__PURE__ */ new Map();
293426
+ /**
293427
+ * The wallet each LIVE provider session was started with, or null when the
293428
+ * start carried none (CMMD#5917).
293429
+ *
293430
+ * The Claude adapter reads the wallet once, at session start, to decide
293431
+ * whether the session runs on CMMD's Workspace egress or the personal
293432
+ * login. A kick naming a different wallet than the live session's has to
293433
+ * restart it, or the new wallet's turn runs on the old session's credential.
293434
+ */
293435
+ const threadSessionWallets = /* @__PURE__ */ new Map();
293104
293436
  const appendProviderFailureActivity = (input) => orchestrationEngine.dispatch({
293105
293437
  type: "thread.activity.append",
293106
293438
  commandId: serverCommandId$2("provider-failure-activity"),
@@ -293146,10 +293478,16 @@ const ProviderCommandReactorLive = effect(ProviderCommandReactor, gen(function*
293146
293478
  if (thread.anchorKind === "task" && project?.repositoryIdentity == null && !isGitWorkspace(cwd)) return "Forge created this task thread, but the project folder is not a Git repository yet. Import or link the repository before starting an agent turn.";
293147
293479
  return null;
293148
293480
  });
293481
+ /**
293482
+ * Returns the thread id of a live provider session for the thread, starting
293483
+ * one, or restarting the live one when its provider, model, account, Work
293484
+ * Session or wallet no longer matches what this turn asks for.
293485
+ */
293149
293486
  const ensureSessionForThread = fn$1("ensureSessionForThread")(function* (threadId, createdAt, options) {
293150
293487
  const readModel = yield* orchestrationEngine.getReadModel();
293151
293488
  const thread = readModel.threads.find((entry) => entry.id === threadId);
293152
293489
  if (!thread) return yield* die$1(/* @__PURE__ */ new Error(`Thread '${threadId}' was not found in read model.`));
293490
+ const requestedWallet = resolveRequestedWallet(options?.wallet, thread.wallet);
293153
293491
  const desiredRuntimeMode = thread.runtimeMode;
293154
293492
  const currentProvider = thread.session?.status !== "stopped" && isProviderKind(thread.session?.providerName) ? thread.session.providerName : void 0;
293155
293493
  const requestedModelSelection = options?.modelSelection;
@@ -293166,10 +293504,12 @@ const ProviderCommandReactorLive = effect(ProviderCommandReactor, gen(function*
293166
293504
  ...effectiveCwd ? { cwd: effectiveCwd } : {},
293167
293505
  modelSelection: desiredModelSelection,
293168
293506
  ...input?.resumeCursor !== void 0 ? { resumeCursor: input.resumeCursor } : {},
293169
- runtimeMode: desiredRuntimeMode
293507
+ runtimeMode: desiredRuntimeMode,
293508
+ ...requestedWallet !== void 0 ? { wallet: requestedWallet } : {}
293170
293509
  }), () => sync$1(() => {
293171
293510
  threadSessionAccountIds.set(threadId, readProviderAccountId(desiredModelSelection));
293172
293511
  threadSessionWorkSessionIds.set(threadId, thread.workSessionId ?? null);
293512
+ threadSessionWallets.set(threadId, requestedWallet ?? threadSessionWallets.get(threadId) ?? null);
293173
293513
  }));
293174
293514
  const bindSessionToThread = (session) => setThreadSession({
293175
293515
  threadId,
@@ -293219,7 +293559,15 @@ const ProviderCommandReactorLive = effect(ProviderCommandReactor, gen(function*
293219
293559
  const currentWorkSessionId = thread.workSessionId ?? null;
293220
293560
  const sessionWorkSessionId = threadSessionWorkSessionIds.get(threadId);
293221
293561
  const shouldRestartForWorkSessionChange = threadSessionWorkSessionIds.has(threadId) && sessionWorkSessionId !== currentWorkSessionId;
293222
- if (!runtimeModeChanged && !providerChanged && !shouldRestartForModelChange && !shouldRestartForModelSelectionChange && !shouldRestartForAccountChange && !shouldRestartForWorkSessionChange) return existingSessionThreadId;
293562
+ /**
293563
+ * A kick that names a wallet other than the one the live session started
293564
+ * with restarts it, so the Claude adapter re-decides its egress from the
293565
+ * new wallet (CMMD#5917). A live session this reactor did not start has
293566
+ * no recorded wallet and restarts too, which costs a resume and never
293567
+ * leaves a Workspace turn on a personal session.
293568
+ */
293569
+ const shouldRestartForWalletChange = requestedWallet !== void 0 && threadSessionWallets.get(threadId) !== requestedWallet;
293570
+ if (!runtimeModeChanged && !providerChanged && !shouldRestartForModelChange && !shouldRestartForModelSelectionChange && !shouldRestartForAccountChange && !shouldRestartForWorkSessionChange && !shouldRestartForWalletChange) return existingSessionThreadId;
293223
293571
  const resumeCursor = providerChanged || shouldRestartForModelChange ? void 0 : activeSession?.resumeCursor ?? void 0;
293224
293572
  yield* logInfo("provider command reactor restarting provider session", {
293225
293573
  threadId,
@@ -293235,9 +293583,10 @@ const ProviderCommandReactorLive = effect(ProviderCommandReactor, gen(function*
293235
293583
  shouldRestartForModelSelectionChange,
293236
293584
  shouldRestartForAccountChange,
293237
293585
  shouldRestartForWorkSessionChange,
293586
+ shouldRestartForWalletChange,
293238
293587
  hasResumeCursor: resumeCursor !== void 0
293239
293588
  });
293240
- if (shouldRestartForAccountChange || shouldRestartForWorkSessionChange || providerChanged) yield* providerService.stopSession({
293589
+ if (shouldRestartForAccountChange || shouldRestartForWorkSessionChange || shouldRestartForWalletChange || providerChanged) yield* providerService.stopSession({
293241
293590
  threadId,
293242
293591
  preserveResumeState: true
293243
293592
  });
@@ -293337,6 +293686,11 @@ const ProviderCommandReactorLive = effect(ProviderCommandReactor, gen(function*
293337
293686
  turnId: input.turnId,
293338
293687
  cause: pretty(cause)
293339
293688
  })), onInterrupt(() => releaseTurnStart(input.holdKey)), ensuring(closeTurnStartEventBuffer(input.holdKey, input.events)));
293689
+ /**
293690
+ * Ensures a session with the turn's model and wallet, then sends the turn.
293691
+ * A session-start failure (a refused Workspace egress mint, for one)
293692
+ * propagates to the caller, which records it on the thread.
293693
+ */
293340
293694
  const sendTurnForThread = fn$1("sendTurnForThread")(function* (input) {
293341
293695
  const thread = yield* resolveThread(input.threadId);
293342
293696
  if (!thread) return { _tag: "skipped" };
@@ -293351,7 +293705,10 @@ const ProviderCommandReactorLive = effect(ProviderCommandReactor, gen(function*
293351
293705
  });
293352
293706
  return { _tag: "skipped" };
293353
293707
  }
293354
- yield* ensureSessionForThread(input.threadId, input.createdAt, input.modelSelection !== void 0 ? { modelSelection: input.modelSelection } : {});
293708
+ yield* ensureSessionForThread(input.threadId, input.createdAt, {
293709
+ ...input.modelSelection !== void 0 ? { modelSelection: input.modelSelection } : {},
293710
+ ...input.wallet !== void 0 ? { wallet: input.wallet } : {}
293711
+ });
293355
293712
  if (input.modelSelection !== void 0) threadModelSelections.set(input.threadId, input.modelSelection);
293356
293713
  const cmmdTaskId = thread.anchorKind === "task" ? thread.anchorCmmdId : null;
293357
293714
  const cmmdCwd = resolveThreadWorkspaceCwd({
@@ -293563,6 +293920,11 @@ const ProviderCommandReactorLive = effect(ProviderCommandReactor, gen(function*
293563
293920
  ...result.title !== void 0 ? { title: result.title } : {}
293564
293921
  });
293565
293922
  });
293923
+ /**
293924
+ * Handles one `thread.turn-start-requested` event: validates the workspace,
293925
+ * forks first-turn title and branch generation, then sends the turn with the
293926
+ * event's model selection and wallet and records any failure on the thread.
293927
+ */
293566
293928
  const processTurnStartRequested = fn$1("processTurnStartRequested")(function* (event) {
293567
293929
  const key = turnStartKeyForEvent(event);
293568
293930
  if (yield* hasHandledTurnStartRecently(key)) return;
@@ -293626,7 +293988,8 @@ const ProviderCommandReactorLive = effect(ProviderCommandReactor, gen(function*
293626
293988
  ...message.attachments !== void 0 ? { attachments: message.attachments } : {},
293627
293989
  ...event.payload.modelSelection !== void 0 ? { modelSelection: event.payload.modelSelection } : {},
293628
293990
  interactionMode: event.payload.interactionMode,
293629
- createdAt: event.payload.createdAt
293991
+ createdAt: event.payload.createdAt,
293992
+ ...event.payload.wallet !== void 0 ? { wallet: event.payload.wallet } : {}
293630
293993
  }),
293631
293994
  close: closeTurnStartEventBuffer(turnStartHoldKey, turnStartEvents),
293632
293995
  onFailure: (cause) => appendProviderFailureActivity({
@@ -299777,7 +300140,7 @@ function resolveBuildCommitFromEnv(env) {
299777
300140
  * environment descriptor down instead of reporting an honest "unknown".
299778
300141
  */
299779
300142
  function readBakedBuildCommit() {
299780
- return "15aa06fedcdcf9e165622cf018e31ce724b98ef7";
300143
+ return "96d46d7493320e6f460e5d613e1ad7a2c6774761";
299781
300144
  }
299782
300145
  async function resolveServerBuildCommit(input) {
299783
300146
  if (isFullCommitSha(input.baked)) return input.baked;
@@ -303460,6 +303823,23 @@ function resolveThreadCommandAnchor(input) {
303460
303823
  anchorCmmdId: null
303461
303824
  };
303462
303825
  }
303826
+ /**
303827
+ * `{ wallet }` when a kick names a wallet other than the thread's, otherwise
303828
+ * null. Kept out of the decider body so its complexity budget does not grow
303829
+ * (CMMD#5917).
303830
+ */
303831
+ function turnWalletUpdate(current, requested) {
303832
+ return requested !== void 0 && requested !== current ? { wallet: requested } : null;
303833
+ }
303834
+ /**
303835
+ * `{ wallet }` for a turn-start event: the kick's wallet, else the thread's
303836
+ * wallet at acceptance, else nothing, which leaves an older-style event the
303837
+ * reactor falls back on thread state for (CMMD#5917).
303838
+ */
303839
+ function turnStartWallet(requested, current) {
303840
+ const wallet = requested ?? current ?? void 0;
303841
+ return wallet === void 0 ? {} : { wallet };
303842
+ }
303463
303843
  const decideOrchestrationCommand = fn$1("decideOrchestrationCommand")(function* ({ command, readModel }) {
303464
303844
  switch (command.type) {
303465
303845
  case "project.create":
@@ -303622,6 +304002,7 @@ const decideOrchestrationCommand = fn$1("decideOrchestrationCommand")(function*
303622
304002
  anchorCmmdId: anchor.anchorCmmdId,
303623
304003
  workSessionId: command.workSessionId ?? null,
303624
304004
  ...command.workSessionId != null ? { workSessionBoundAt: command.createdAt } : {},
304005
+ ...command.wallet !== void 0 ? { wallet: command.wallet } : {},
303625
304006
  goal: command.goal ?? null,
303626
304007
  linkedPullRequest: command.linkedPullRequest ?? null,
303627
304008
  kind,
@@ -303864,6 +304245,9 @@ const decideOrchestrationCommand = fn$1("decideOrchestrationCommand")(function*
303864
304245
  command,
303865
304246
  threadId: command.threadId
303866
304247
  });
304248
+ const isClientOriginTurnStart = command.workSessionId === void 0 || command.workSessionId === null;
304249
+ const threadHasWorkSession = targetThread.workSessionId !== void 0 && targetThread.workSessionId !== null;
304250
+ const authorizedWalletOverride = isClientOriginTurnStart && threadHasWorkSession ? void 0 : command.wallet;
303867
304251
  const nextAnchor = command.anchorKind !== void 0 || command.anchorCmmdId !== void 0 || command.cmmdTaskId !== void 0 ? resolveThreadCommandAnchor({
303868
304252
  anchorKind: command.anchorKind,
303869
304253
  anchorCmmdId: command.anchorCmmdId,
@@ -303924,6 +304308,7 @@ const decideOrchestrationCommand = fn$1("decideOrchestrationCommand")(function*
303924
304308
  runtimeMode: targetThread.runtimeMode,
303925
304309
  interactionMode: targetThread.interactionMode,
303926
304310
  ...sourceProposedPlan !== void 0 ? { sourceProposedPlan } : {},
304311
+ ...turnStartWallet(authorizedWalletOverride, targetThread.wallet),
303927
304312
  createdAt: command.createdAt
303928
304313
  }
303929
304314
  };
@@ -303937,7 +304322,8 @@ const decideOrchestrationCommand = fn$1("decideOrchestrationCommand")(function*
303937
304322
  });
303938
304323
  const shouldRebindWorkSession = command.workSessionId !== void 0 && command.workSessionId !== null && command.workSessionId !== targetThread.workSessionId;
303939
304324
  const shouldAdvanceBoundTimestamp = !shouldRebindWorkSession && command.workSessionId !== void 0 && command.workSessionId !== null && command.workSessionId === targetThread.workSessionId && (targetThread.workSessionBoundAt === null || targetThread.workSessionBoundAt === void 0 || command.createdAt > targetThread.workSessionBoundAt);
303940
- if (!shouldUpdateAnchor && !turnModelSelection && !shouldRebindWorkSession && !shouldAdvanceBoundTimestamp) return [userMessageEvent, turnStartRequestedEvent];
304325
+ const walletUpdate = turnWalletUpdate(targetThread.wallet, authorizedWalletOverride);
304326
+ if (!shouldUpdateAnchor && !turnModelSelection && !shouldRebindWorkSession && !shouldAdvanceBoundTimestamp && !walletUpdate) return [userMessageEvent, turnStartRequestedEvent];
303941
304327
  return [
303942
304328
  {
303943
304329
  ...withEventBase({
@@ -303956,6 +304342,7 @@ const decideOrchestrationCommand = fn$1("decideOrchestrationCommand")(function*
303956
304342
  workSessionId: command.workSessionId,
303957
304343
  workSessionBoundAt: command.createdAt
303958
304344
  } : shouldAdvanceBoundTimestamp ? { workSessionBoundAt: command.createdAt } : {},
304345
+ ...walletUpdate,
303959
304346
  updatedAt: command.createdAt
303960
304347
  }
303961
304348
  },
@@ -304527,6 +304914,7 @@ function projectEvent(model, event) {
304527
304914
  anchorCmmdId: payload.anchorCmmdId,
304528
304915
  workSessionId: payload.workSessionId ?? null,
304529
304916
  workSessionBoundAt: payload.workSessionBoundAt ?? null,
304917
+ wallet: payload.wallet ?? null,
304530
304918
  goal: payload.goal ?? null,
304531
304919
  linkedPullRequest: payload.linkedPullRequest ?? null,
304532
304920
  titleRegeneration: null,
@@ -304609,6 +304997,7 @@ function projectEvent(model, event) {
304609
304997
  ...payload.titleRegeneration !== void 0 ? { titleRegeneration: payload.titleRegeneration } : {},
304610
304998
  ...payload.workSessionId !== void 0 ? { workSessionId: payload.workSessionId } : {},
304611
304999
  ...payload.workSessionBoundAt !== void 0 ? { workSessionBoundAt: payload.workSessionBoundAt } : {},
305000
+ ...payload.wallet !== void 0 ? { wallet: payload.wallet } : {},
304612
305001
  updatedAt: payload.updatedAt
304613
305002
  })
304614
305003
  })));
@@ -305630,6 +306019,14 @@ const ProjectionThreadDbRow = ProjectionThread.mapFields(assign({
305630
306019
  rateLimitStatus: fromJsonString(ArraySchema(ThreadProviderRateLimitStatus)),
305631
306020
  linkedPullRequest: NullOr(fromJsonString(LinkedPullRequest))
305632
306021
  }));
306022
+ /**
306023
+ * The `wallet` column value: the row's wallet, or SQL null when it has none.
306024
+ * Module-level so the upsert's own complexity budget does not grow
306025
+ * (CMMD#5917).
306026
+ */
306027
+ function walletColumn(wallet) {
306028
+ return wallet ?? null;
306029
+ }
305633
306030
  const ProjectionThreadRepositoryLive = effect(ProjectionThreadRepository, gen(function* () {
305634
306031
  const sql = yield* SqlClient;
305635
306032
  const upsertProjectionThreadRow = void_({
@@ -305661,6 +306058,7 @@ const ProjectionThreadRepositoryLive = effect(ProjectionThreadRepository, gen(fu
305661
306058
  anchor_cmmd_id,
305662
306059
  work_session_id,
305663
306060
  work_session_bound_at,
306061
+ wallet,
305664
306062
  linked_pull_request_json,
305665
306063
  status,
305666
306064
  worker_role,
@@ -305695,6 +306093,7 @@ const ProjectionThreadRepositoryLive = effect(ProjectionThreadRepository, gen(fu
305695
306093
  ${row.anchorCmmdId},
305696
306094
  ${row.workSessionId ?? null},
305697
306095
  ${row.workSessionBoundAt ?? null},
306096
+ ${walletColumn(row.wallet)},
305698
306097
  ${row.linkedPullRequest == null ? null : JSON.stringify(row.linkedPullRequest)},
305699
306098
  ${row.status},
305700
306099
  ${row.workerRole},
@@ -305729,6 +306128,7 @@ const ProjectionThreadRepositoryLive = effect(ProjectionThreadRepository, gen(fu
305729
306128
  anchor_cmmd_id = excluded.anchor_cmmd_id,
305730
306129
  work_session_id = excluded.work_session_id,
305731
306130
  work_session_bound_at = excluded.work_session_bound_at,
306131
+ wallet = excluded.wallet,
305732
306132
  linked_pull_request_json = excluded.linked_pull_request_json,
305733
306133
  status = excluded.status,
305734
306134
  worker_role = excluded.worker_role,
@@ -305768,6 +306168,7 @@ const ProjectionThreadRepositoryLive = effect(ProjectionThreadRepository, gen(fu
305768
306168
  anchor_cmmd_id AS "anchorCmmdId",
305769
306169
  work_session_id AS "workSessionId",
305770
306170
  work_session_bound_at AS "workSessionBoundAt",
306171
+ wallet,
305771
306172
  linked_pull_request_json AS "linkedPullRequest",
305772
306173
  status,
305773
306174
  worker_role AS "workerRole",
@@ -305809,6 +306210,7 @@ const ProjectionThreadRepositoryLive = effect(ProjectionThreadRepository, gen(fu
305809
306210
  anchor_cmmd_id AS "anchorCmmdId",
305810
306211
  work_session_id AS "workSessionId",
305811
306212
  work_session_bound_at AS "workSessionBoundAt",
306213
+ wallet,
305812
306214
  linked_pull_request_json AS "linkedPullRequest",
305813
306215
  status,
305814
306216
  worker_role AS "workerRole",
@@ -305998,6 +306400,13 @@ function collectThreadUserInputAttachmentRelativePaths(threadId, events) {
305998
306400
  function projectedWorkSessionId(workSessionId) {
305999
306401
  return workSessionId ?? null;
306000
306402
  }
306403
+ /**
306404
+ * Coalesces an optional wallet to the persisted default, top-level for the
306405
+ * same complexity reason as `projectedWorkSessionId` (CMMD#5917).
306406
+ */
306407
+ function projectedWallet(wallet) {
306408
+ return wallet ?? null;
306409
+ }
306001
306410
  const runAttachmentSideEffects = fn$1("runAttachmentSideEffects")(function* (sideEffects) {
306002
306411
  const serverConfig = yield* service(ServerConfig);
306003
306412
  const fileSystem = yield* service(FileSystem);
@@ -306162,6 +306571,7 @@ const OrchestrationProjectionPipelineLive = effect(OrchestrationProjectionPipeli
306162
306571
  anchorCmmdId: event.payload.anchorCmmdId,
306163
306572
  workSessionId: projectedWorkSessionId(event.payload.workSessionId),
306164
306573
  workSessionBoundAt: event.payload.workSessionBoundAt ?? null,
306574
+ wallet: projectedWallet(event.payload.wallet),
306165
306575
  linkedPullRequest: event.payload.linkedPullRequest ?? null,
306166
306576
  status: event.payload.status,
306167
306577
  workerRole: event.payload.workerRole,
@@ -306201,6 +306611,7 @@ const OrchestrationProjectionPipelineLive = effect(OrchestrationProjectionPipeli
306201
306611
  anchorCmmdId: thread.anchorCmmdId,
306202
306612
  workSessionId: projectedWorkSessionId(thread.workSessionId),
306203
306613
  workSessionBoundAt: thread.workSessionBoundAt ?? null,
306614
+ wallet: projectedWallet(thread.wallet),
306204
306615
  linkedPullRequest: thread.linkedPullRequest ?? null,
306205
306616
  status: thread.status,
306206
306617
  workerRole: thread.workerRole,
@@ -306271,6 +306682,7 @@ const OrchestrationProjectionPipelineLive = effect(OrchestrationProjectionPipeli
306271
306682
  ...event.payload.titleRegeneration !== void 0 ? { titleRegeneration: event.payload.titleRegeneration } : {},
306272
306683
  ...event.payload.workSessionId !== void 0 ? { workSessionId: projectedWorkSessionId(event.payload.workSessionId) } : {},
306273
306684
  ...event.payload.workSessionBoundAt !== void 0 ? { workSessionBoundAt: event.payload.workSessionBoundAt } : {},
306685
+ ...event.payload.wallet !== void 0 ? { wallet: event.payload.wallet } : {},
306274
306686
  updatedAt: event.payload.updatedAt
306275
306687
  });
306276
306688
  return;
@@ -307286,6 +307698,13 @@ function workSessionIdField(workSessionId) {
307286
307698
  function workSessionBoundAtField(workSessionBoundAt) {
307287
307699
  return workSessionBoundAt !== void 0 ? { workSessionBoundAt } : {};
307288
307700
  }
307701
+ /**
307702
+ * `{ wallet }` when the row carries one, an empty object when absent. Mirrors
307703
+ * `workSessionIdField` so `exactOptionalPropertyTypes` is satisfied (CMMD#5917).
307704
+ */
307705
+ function walletField(wallet) {
307706
+ return wallet !== void 0 ? { wallet } : {};
307707
+ }
307289
307708
  const OrchestrationInfrastructureLayerLive = mergeAll(effect(ProjectionSnapshotQuery, gen(function* () {
307290
307709
  const sql = yield* SqlClient;
307291
307710
  const repositoryIdentityResolver = yield* RepositoryIdentityResolver;
@@ -307340,6 +307759,7 @@ const OrchestrationInfrastructureLayerLive = mergeAll(effect(ProjectionSnapshotQ
307340
307759
  anchor_cmmd_id AS "anchorCmmdId",
307341
307760
  work_session_id AS "workSessionId",
307342
307761
  work_session_bound_at AS "workSessionBoundAt",
307762
+ wallet,
307343
307763
  linked_pull_request_json AS "linkedPullRequest",
307344
307764
  status,
307345
307765
  worker_role AS "workerRole",
@@ -307380,6 +307800,7 @@ const OrchestrationInfrastructureLayerLive = mergeAll(effect(ProjectionSnapshotQ
307380
307800
  anchor_cmmd_id AS "anchorCmmdId",
307381
307801
  work_session_id AS "workSessionId",
307382
307802
  work_session_bound_at AS "workSessionBoundAt",
307803
+ wallet,
307383
307804
  linked_pull_request_json AS "linkedPullRequest",
307384
307805
  status,
307385
307806
  worker_role AS "workerRole",
@@ -307486,6 +307907,7 @@ const OrchestrationInfrastructureLayerLive = mergeAll(effect(ProjectionSnapshotQ
307486
307907
  anchor_cmmd_id AS "anchorCmmdId",
307487
307908
  work_session_id AS "workSessionId",
307488
307909
  work_session_bound_at AS "workSessionBoundAt",
307910
+ wallet,
307489
307911
  linked_pull_request_json AS "linkedPullRequest",
307490
307912
  status,
307491
307913
  worker_role AS "workerRole",
@@ -307820,6 +308242,7 @@ const OrchestrationInfrastructureLayerLive = mergeAll(effect(ProjectionSnapshotQ
307820
308242
  anchor_cmmd_id AS "anchorCmmdId",
307821
308243
  work_session_id AS "workSessionId",
307822
308244
  work_session_bound_at AS "workSessionBoundAt",
308245
+ wallet,
307823
308246
  linked_pull_request_json AS "linkedPullRequest",
307824
308247
  status,
307825
308248
  worker_role AS "workerRole",
@@ -308134,6 +308557,7 @@ const OrchestrationInfrastructureLayerLive = mergeAll(effect(ProjectionSnapshotQ
308134
308557
  anchorCmmdId: row.anchorCmmdId,
308135
308558
  ...workSessionIdField(row.workSessionId),
308136
308559
  ...workSessionBoundAtField(row.workSessionBoundAt),
308560
+ ...walletField(row.wallet),
308137
308561
  linkedPullRequest: row.linkedPullRequest,
308138
308562
  kind: row.kind,
308139
308563
  parentThreadId: row.parentThreadId,
@@ -308385,6 +308809,7 @@ const OrchestrationInfrastructureLayerLive = mergeAll(effect(ProjectionSnapshotQ
308385
308809
  anchorCmmdId: threadRow.value.anchorCmmdId,
308386
308810
  ...workSessionIdField(threadRow.value.workSessionId),
308387
308811
  ...workSessionBoundAtField(threadRow.value.workSessionBoundAt),
308812
+ ...walletField(threadRow.value.wallet),
308388
308813
  linkedPullRequest: threadRow.value.linkedPullRequest,
308389
308814
  kind: threadRow.value.kind,
308390
308815
  parentThreadId: threadRow.value.parentThreadId,
@@ -325243,7 +325668,7 @@ const connectLoginCommand = make$33("login", {
325243
325668
  })).json();
325244
325669
  },
325245
325670
  openBrowser: async (url) => {
325246
- const open = (await import("./open-2-reBrpv.mjs")).default;
325671
+ const open = (await import("./open-yHTUkd2Y.mjs")).default;
325247
325672
  await open(url);
325248
325673
  return true;
325249
325674
  },