@cmmd-center/forge 0.13.134 → 0.13.136

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 (31) 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-jTwdJQlt.js → DiffPanel-DaqlmpHv.js} +2 -2
  5. package/dist/client/assets/{DiffPanel.logic-DukK-hlH.js → DiffPanel.logic-CNeDuJXV.js} +2 -2
  6. package/dist/client/assets/{DiffWorkerPoolProvider-BxK3crqQ.js → DiffWorkerPoolProvider-7AKbLYH_.js} +2 -2
  7. package/dist/client/assets/{PullRequestCodePanel-D9vLGRM9.js → PullRequestCodePanel-uQGOOGFF.js} +2 -2
  8. package/dist/client/assets/{ThemeEditorPanel-Bgrpa0cR.js → ThemeEditorPanel-BdgROB68.js} +2 -2
  9. package/dist/client/assets/{Virtualizer-pdZw7YnL.js → Virtualizer-CX04hq93.js} +2 -2
  10. package/dist/client/assets/{WorkerPoolContext-DfkvYwPY.js → WorkerPoolContext-CWbxmZMK.js} +2 -2
  11. package/dist/client/assets/{cmmdAuthRedirect-B_Ad6N4c.js → cmmdAuthRedirect-Cpw3QgrC.js} +2 -2
  12. package/dist/client/assets/cmmdForgeRuntimeListResource-CX0wIrGL.js +1008 -0
  13. package/dist/client/assets/{currentForgeWorkspaceStore-B3v2VP9w.js → currentForgeWorkspaceStore-CBTn8tE8.js} +2 -2
  14. package/dist/client/assets/{dialog-DMVibvkf.js → dialog-BSwJ44Xn.js} +2 -2
  15. package/dist/client/assets/{index-z4eYDXxq.js → index-d3qvIP59.js} +104 -104
  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-6ppYDui_.js +0 -1008
  31. package/dist/client/assets/src-DpAPOFgC.js +0 -3
package/dist/bin.cjs CHANGED
@@ -17489,6 +17489,22 @@ const RuntimeMode$1 = require_Schema$1.Literals([
17489
17489
  "full-access"
17490
17490
  ]);
17491
17491
  const DEFAULT_RUNTIME_MODE$2 = "full-access";
17492
+ /**
17493
+ * Which wallet pays for a CMMD Work Session's provider usage. The values
17494
+ * match CMMD's `forgeWorkSessionWallets` in `shared/schema/forge-work-sessions.ts`.
17495
+ *
17496
+ * CMMD stamps it on the kick `thread.turn.start` (CMMD#5917). An absent value
17497
+ * means the turn carries no wallet claim, which Forge treats the way it
17498
+ * treated every turn before the field existed: on the personal login. On a
17499
+ * CMMD cloud runtime a `workspace` Claude turn must run through CMMD's metered
17500
+ * egress and is refused if CMMD will not mint for it. It never falls back to
17501
+ * the personal login in the VM.
17502
+ */
17503
+ const WorkSessionWallet = require_Schema$1.Literals([
17504
+ "personal",
17505
+ "workspace",
17506
+ "byok"
17507
+ ]);
17492
17508
  const ProviderInteractionMode = require_Schema$1.Literals(["default", "plan"]);
17493
17509
  const DEFAULT_PROVIDER_INTERACTION_MODE = "default";
17494
17510
  const ProviderRequestKind = require_Schema$1.Literals([
@@ -17847,6 +17863,7 @@ const OrchestrationThread = require_Schema$1.Struct({
17847
17863
  workerRole: require_Schema$1.NullOr(WorkerRole).pipe(require_Schema$1.withDecodingDefault(require_Schema$1.succeed(null))),
17848
17864
  workSessionId: require_Schema$1.optionalKey(require_Schema$1.NullOr(require_Schema$1.String)),
17849
17865
  workSessionBoundAt: require_Schema$1.optionalKey(require_Schema$1.NullOr(require_Schema$1.String)),
17866
+ wallet: require_Schema$1.optionalKey(require_Schema$1.NullOr(WorkSessionWallet)),
17850
17867
  pendingAutoCreatePrompt: require_Schema$1.optional(require_Schema$1.NullOr(AutoCreateTaskPrompt)).pipe(require_Schema$1.withDecodingDefault(require_Schema$1.succeed(null))),
17851
17868
  goal: require_Schema$1.NullOr(TrimmedNonEmptyString).pipe(require_Schema$1.withDecodingDefault(require_Schema$1.succeed(null))),
17852
17869
  titleRegeneration: require_Schema$1.NullOr(ThreadTitleRegeneration).pipe(require_Schema$1.withDecodingDefault(require_Schema$1.succeed(null))),
@@ -18025,6 +18042,7 @@ const ThreadCreateCommand = require_Schema$1.Struct({
18025
18042
  anchorKind: require_Schema$1.optional(CmmdAnchorKind),
18026
18043
  anchorCmmdId: require_Schema$1.optional(require_Schema$1.NullOr(require_Schema$1.String)),
18027
18044
  workSessionId: require_Schema$1.optional(require_Schema$1.NullOr(CommandWorkSessionId)),
18045
+ wallet: require_Schema$1.optional(WorkSessionWallet),
18028
18046
  goal: require_Schema$1.optional(require_Schema$1.NullOr(TrimmedNonEmptyString)),
18029
18047
  linkedPullRequest: require_Schema$1.optional(require_Schema$1.NullOr(LinkedPullRequest)),
18030
18048
  kind: require_Schema$1.optional(ThreadKind),
@@ -18135,7 +18153,8 @@ const ThreadTurnStartCommand = require_Schema$1.Struct({
18135
18153
  kind: require_Schema$1.optional(ThreadKind),
18136
18154
  parentThreadId: require_Schema$1.optional(require_Schema$1.NullOr(ThreadId)),
18137
18155
  createdAt: IsoDateTime,
18138
- workSessionId: require_Schema$1.optional(require_Schema$1.NullOr(CommandWorkSessionId))
18156
+ workSessionId: require_Schema$1.optional(require_Schema$1.NullOr(CommandWorkSessionId)),
18157
+ wallet: require_Schema$1.optional(WorkSessionWallet)
18139
18158
  });
18140
18159
  const ClientThreadTurnStartCommand = require_Schema$1.Struct({
18141
18160
  type: require_Schema$1.Literal("thread.turn.start"),
@@ -18159,7 +18178,8 @@ const ClientThreadTurnStartCommand = require_Schema$1.Struct({
18159
18178
  kind: require_Schema$1.optional(ThreadKind),
18160
18179
  parentThreadId: require_Schema$1.optional(require_Schema$1.NullOr(ThreadId)),
18161
18180
  createdAt: IsoDateTime,
18162
- workSessionId: require_Schema$1.optional(require_Schema$1.NullOr(CommandWorkSessionId))
18181
+ workSessionId: require_Schema$1.optional(require_Schema$1.NullOr(CommandWorkSessionId)),
18182
+ wallet: require_Schema$1.optional(WorkSessionWallet)
18163
18183
  });
18164
18184
  const ThreadTurnInterruptCommand = require_Schema$1.Struct({
18165
18185
  type: require_Schema$1.Literal("thread.turn.interrupt"),
@@ -18457,6 +18477,7 @@ const ThreadCreatedPayload$1 = require_Schema$1.Struct({
18457
18477
  anchorCmmdId: require_Schema$1.NullOr(require_Schema$1.String).pipe(require_Schema$1.withDecodingDefault(require_Schema$1.succeed(null))),
18458
18478
  workSessionId: require_Schema$1.optionalKey(require_Schema$1.NullOr(require_Schema$1.String)),
18459
18479
  workSessionBoundAt: require_Schema$1.optionalKey(require_Schema$1.NullOr(require_Schema$1.String)),
18480
+ wallet: require_Schema$1.optionalKey(require_Schema$1.NullOr(WorkSessionWallet)),
18460
18481
  goal: require_Schema$1.optionalKey(require_Schema$1.NullOr(TrimmedNonEmptyString)),
18461
18482
  linkedPullRequest: require_Schema$1.optionalKey(require_Schema$1.NullOr(LinkedPullRequest)),
18462
18483
  kind: ThreadKind.pipe(require_Schema$1.withDecodingDefault(require_Schema$1.succeed("master"))),
@@ -18500,6 +18521,7 @@ const ThreadMetaUpdatedPayload$1 = require_Schema$1.Struct({
18500
18521
  workerRole: require_Schema$1.optional(require_Schema$1.NullOr(WorkerRole)),
18501
18522
  workSessionId: require_Schema$1.optional(require_Schema$1.NullOr(require_Schema$1.String)),
18502
18523
  workSessionBoundAt: require_Schema$1.optional(require_Schema$1.String),
18524
+ wallet: require_Schema$1.optional(WorkSessionWallet),
18503
18525
  goal: require_Schema$1.optional(require_Schema$1.NullOr(TrimmedNonEmptyString)),
18504
18526
  linkedPullRequest: require_Schema$1.optional(require_Schema$1.NullOr(LinkedPullRequest)),
18505
18527
  regenerateTitle: require_Schema$1.optional(require_Schema$1.Literal(true)),
@@ -18536,6 +18558,7 @@ const ThreadTurnStartRequestedPayload = require_Schema$1.Struct({
18536
18558
  runtimeMode: RuntimeMode$1.pipe(require_Schema$1.withDecodingDefault(require_Schema$1.succeed(DEFAULT_RUNTIME_MODE$2))),
18537
18559
  interactionMode: ProviderInteractionMode.pipe(require_Schema$1.withDecodingDefault(require_Schema$1.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
18538
18560
  sourceProposedPlan: require_Schema$1.optional(SourceProposedPlanReference),
18561
+ wallet: require_Schema$1.optional(WorkSessionWallet),
18539
18562
  createdAt: IsoDateTime
18540
18563
  });
18541
18564
  const ThreadTurnInterruptRequestedPayload = require_Schema$1.Struct({
@@ -21051,7 +21074,8 @@ const ProviderSessionStartInput = require_Schema$1.Struct({
21051
21074
  resumeCursor: require_Schema$1.optional(require_Schema$1.Unknown),
21052
21075
  approvalPolicy: require_Schema$1.optional(ProviderApprovalPolicy),
21053
21076
  sandboxMode: require_Schema$1.optional(ProviderSandboxMode),
21054
- runtimeMode: RuntimeMode$1
21077
+ runtimeMode: RuntimeMode$1,
21078
+ wallet: require_Schema$1.optional(WorkSessionWallet)
21055
21079
  });
21056
21080
  const ProviderSendTurnInput = require_Schema$1.Struct({
21057
21081
  threadId: ThreadId,
@@ -66407,7 +66431,7 @@ function normalizeNumberish(value) {
66407
66431
  }
66408
66432
  //#endregion
66409
66433
  //#region package.json
66410
- var version$1 = "0.13.134";
66434
+ var version$1 = "0.13.136";
66411
66435
  //#endregion
66412
66436
  //#region src/sentry.ts
66413
66437
  const SERVER_APP_NAME = "forge-server";
@@ -98208,6 +98232,16 @@ const PUBLIC_PROVIDER_LEAK_PATTERNS = [
98208
98232
  /https?:\/\/[^\s'"<>)]*(?:apex|deepseek|moonshot|kimi)[^\s'"<>)]*/i
98209
98233
  ];
98210
98234
  const DEFAULT_PUBLIC_PROVIDER_ERROR = "CMMD is temporarily unavailable. Check the workspace AI connection and retry.";
98235
+ /**
98236
+ * The sentence a Workspace-wallet Claude turn fails with on a CMMD runtime when
98237
+ * CMMD will not mint its egress token (CMMD#5917). The Claude adapter opens its
98238
+ * refusal with it, and `categorizePublicProviderError` returns it unchanged, so
98239
+ * the refusal still reads as a refusal when a production stack forces the
98240
+ * failure detail through sanitization. Anything else would read as an outage
98241
+ * and invite a retry on the personal login.
98242
+ */
98243
+ 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.";
98244
+ const CLAUDE_WORKSPACE_EGRESS_REFUSAL_LOWER = CLAUDE_WORKSPACE_EGRESS_REFUSAL.toLowerCase();
98211
98245
  function isProviderRateOrQuotaError(message) {
98212
98246
  if (!message) return false;
98213
98247
  const normalized = message.toLowerCase();
@@ -98231,6 +98265,7 @@ function providerLifecycleOrAccountCopy(message) {
98231
98265
  function categorizePublicProviderError(message) {
98232
98266
  if (!message) return null;
98233
98267
  const m = message.toLowerCase();
98268
+ if (m.includes(CLAUDE_WORKSPACE_EGRESS_REFUSAL_LOWER)) return CLAUDE_WORKSPACE_EGRESS_REFUSAL;
98234
98269
  const lifecycleOrAccountCopy = providerLifecycleOrAccountCopy(m);
98235
98270
  if (lifecycleOrAccountCopy !== null) return lifecycleOrAccountCopy;
98236
98271
  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.";
@@ -115871,7 +115906,7 @@ const postgresSchemaStatements = [
115871
115906
  "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 )",
115872
115907
  "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 )",
115873
115908
  "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)",
115874
- "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)",
115909
+ "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)",
115875
115910
  "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)",
115876
115911
  "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)",
115877
115912
  "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')",
@@ -116195,7 +116230,8 @@ const postgresUpgradeMigrations = new Map([
116195
116230
  ]],
116196
116231
  [77, [`ALTER TABLE projection_threads ADD COLUMN IF NOT EXISTS work_session_id TEXT`]],
116197
116232
  [78, [`ALTER TABLE projection_threads ADD COLUMN IF NOT EXISTS work_session_bound_at TEXT`]],
116198
- [79, [`ALTER TABLE command_access_tokens DROP COLUMN IF EXISTS refresh_token`]]
116233
+ [79, [`ALTER TABLE command_access_tokens DROP COLUMN IF EXISTS refresh_token`]],
116234
+ [80, [`ALTER TABLE projection_threads ADD COLUMN IF NOT EXISTS wallet TEXT`]]
116199
116235
  ]);
116200
116236
  function requirePostgresUpgradeStatements(version) {
116201
116237
  const statements = postgresUpgradeMigrations.get(version);
@@ -116221,15 +116257,15 @@ const runPostgresMigrations = require_Schema$1.fn("runPostgresMigrations")(funct
116221
116257
  ORDER BY version DESC
116222
116258
  LIMIT 1
116223
116259
  `)[0]?.version ?? 0;
116224
- if (currentVersion > 79) return yield* require_Schema$1.die(/* @__PURE__ */ new Error(`Forge Postgres schema ${currentVersion} is newer than server schema 79.`));
116260
+ if (currentVersion > 80) return yield* require_Schema$1.die(/* @__PURE__ */ new Error(`Forge Postgres schema ${currentVersion} is newer than server schema 80.`));
116225
116261
  if (currentVersion === 0) {
116226
116262
  for (const statement of postgresSchemaStatements) yield* sql.unsafe(statement);
116227
116263
  yield* sql`
116228
116264
  INSERT INTO forge_schema_migrations (version)
116229
- VALUES (${79})
116265
+ VALUES (${80})
116230
116266
  ON CONFLICT (version) DO NOTHING
116231
116267
  `;
116232
- } else for (let version = currentVersion + 1; version <= 79; version += 1) {
116268
+ } else for (let version = currentVersion + 1; version <= 80; version += 1) {
116233
116269
  const statements = yield* require_Schema$1.sync(() => requirePostgresUpgradeStatements(version));
116234
116270
  for (const statement of statements) yield* sql.unsafe(statement);
116235
116271
  yield* sql`
@@ -119058,6 +119094,21 @@ var _079_DropCommandRefreshToken_default = require_Schema$1.gen(function* () {
119058
119094
  yield* (yield* require_SqlError.SqlClient)`ALTER TABLE command_access_tokens DROP COLUMN refresh_token`;
119059
119095
  });
119060
119096
  //#endregion
119097
+ //#region src/persistence/Migrations/080_ProjectionThreadWallet.ts
119098
+ /**
119099
+ * Stores the wallet the last CMMD kick named on a thread (CMMD#5917), so a
119100
+ * turn without one starts on it even after a server restart.
119101
+ */
119102
+ var _080_ProjectionThreadWallet_default = require_Schema$1.gen(function* () {
119103
+ const sql = yield* require_SqlError.SqlClient;
119104
+ if (!(yield* sql`
119105
+ PRAGMA table_info(projection_threads)
119106
+ `).some((column) => column.name === "wallet")) yield* sql`
119107
+ ALTER TABLE projection_threads
119108
+ ADD COLUMN wallet TEXT
119109
+ `;
119110
+ });
119111
+ //#endregion
119061
119112
  //#region src/persistence/Migrations.ts
119062
119113
  /**
119063
119114
  * MigrationsLive - Migration runner with inline loader
@@ -119473,6 +119524,11 @@ const migrationEntries = [
119473
119524
  79,
119474
119525
  "DropCommandRefreshToken",
119475
119526
  _079_DropCommandRefreshToken_default
119527
+ ],
119528
+ [
119529
+ 80,
119530
+ "ProjectionThreadWallet",
119531
+ _080_ProjectionThreadWallet_default
119476
119532
  ]
119477
119533
  ];
119478
119534
  const makeMigrationLoader = (throughId) => fromRecord(Object.fromEntries(migrationEntries.filter(([id]) => throughId === void 0 || id <= throughId).map(([id, name, migration]) => [`${id}_${name}`, migration])));
@@ -152823,6 +152879,15 @@ function canIssueProviderEgressToken() {
152823
152879
  function canIssueApexProviderEgressToken() {
152824
152880
  return canIssueProviderEgressToken() || canRequestCmmdLocalUserProviderEgressToken();
152825
152881
  }
152882
+ /**
152883
+ * True on a CMMD cloud runtime that has everything the runtime mint route
152884
+ * needs: runtime mode, the control plane URL, the runtime id, a grant token,
152885
+ * and the provider proxy URL. `issueProviderEgressCredential` takes the
152886
+ * runtime mint path exactly when this holds.
152887
+ *
152888
+ * Exported for the Claude adapter, which mints Workspace Anthropic egress on
152889
+ * such a runtime for a turn stamped with the Workspace wallet (CMMD#5917).
152890
+ */
152826
152891
  function canIssueCmmdRuntimeProviderEgressToken() {
152827
152892
  return process.env.FORGE_CMMD_RUNTIME_MODE === "true" && Boolean(process.env.FORGE_COMMAND_APP_URL) && Boolean(process.env.FORGE_CMMD_RUNTIME_ID) && Boolean(require_runtimeControlAuthority.runtimeGrantToken()) && Boolean(process.env.FORGE_PROVIDER_PROXY_URL);
152828
152893
  }
@@ -153400,7 +153465,7 @@ const CODEX_SKILLS_LIST_TIMEOUT_MS = 4e3;
153400
153465
  const CODEX_SUBAGENT_TOKEN_USAGE_METHOD = "forge/subagentTokenUsage/updated";
153401
153466
  const CODEX_VERSION_CHECK_TIMEOUT_MS = 15e3;
153402
153467
  const PROVIDER_EGRESS_TOKEN_REFRESH_MS = 1500 * 1e3;
153403
- const PROVIDER_EGRESS_TOKEN_REFRESH_DEFER_MS = 60 * 1e3;
153468
+ const PROVIDER_EGRESS_TOKEN_REFRESH_DEFER_MS$1 = 60 * 1e3;
153404
153469
  const INTERRUPT_REQUEST_TIMEOUT_MS = 2e3;
153405
153470
  const ANSI_ESCAPE_CHAR = String.fromCharCode(27);
153406
153471
  const ANSI_ESCAPE_REGEX = new RegExp(`${ANSI_ESCAPE_CHAR}\\[[0-9;]*m`, "g");
@@ -154222,7 +154287,7 @@ var CodexAppServerManager = class extends node_events.EventEmitter {
154222
154287
  if (!context || context.stopping) return;
154223
154288
  if (context.session.activeTurnId || context.pending.size > 0) {
154224
154289
  this.emitLifecycleEvent(context, "session/tokenRefreshDeferred", "Workspace provider token refresh deferred until the active Codex turn finishes.");
154225
- this.scheduleProviderEgressTokenRefresh(context, PROVIDER_EGRESS_TOKEN_REFRESH_DEFER_MS);
154290
+ this.scheduleProviderEgressTokenRefresh(context, PROVIDER_EGRESS_TOKEN_REFRESH_DEFER_MS$1);
154226
154291
  return;
154227
154292
  }
154228
154293
  this.emitLifecycleEvent(context, "session/tokenRefreshRequired", "Workspace provider token is nearing expiry; restarting Codex session for recovery.");
@@ -214400,6 +214465,48 @@ function hasConfiguredApexCredential(profiles) {
214400
214465
  }));
214401
214466
  }
214402
214467
  //#endregion
214468
+ //#region src/egress/providerEgressTokenRefresh.ts
214469
+ /**
214470
+ * How long to wait before restarting a session whose provider egress
214471
+ * credential is about to expire.
214472
+ *
214473
+ * CMMD-Center/CMMD#5917 review: the Workspace Anthropic egress token lives
214474
+ * one hour and is minted once, when a Claude session starts. The session
214475
+ * itself can run for many turns past that hour through its own prompt
214476
+ * queue, so without this the first turn after expiry fails with an opaque
214477
+ * 401 instead of an honest refusal. Restarting near expiry mints a fresh
214478
+ * token on the next turn instead, the same trade Codex already makes in
214479
+ * `codexAppServerManager.ts` (`scheduleProviderEgressTokenRefresh`).
214480
+ *
214481
+ * Kept in its own module so the delay math is testable without an Effect
214482
+ * runtime or a session map.
214483
+ */
214484
+ /** Restart this long before the token actually expires. */
214485
+ const PROVIDER_EGRESS_TOKEN_REFRESH_MARGIN_MS = 300 * 1e3;
214486
+ /**
214487
+ * Used when the credential carries no `expiresAt`, or one that fails to
214488
+ * parse. Conservative relative to the one-hour token life the review names,
214489
+ * so a missing timestamp fails toward an early, harmless restart rather than
214490
+ * toward never restarting at all.
214491
+ */
214492
+ const PROVIDER_EGRESS_TOKEN_REFRESH_FALLBACK_MS = 1500 * 1e3;
214493
+ /**
214494
+ * How long to wait before checking again when the refresh threshold arrives
214495
+ * mid-turn. Matches Codex's `PROVIDER_EGRESS_TOKEN_REFRESH_DEFER_MS`.
214496
+ */
214497
+ const PROVIDER_EGRESS_TOKEN_REFRESH_DEFER_MS = 60 * 1e3;
214498
+ /**
214499
+ * How long a session should wait, once idle, before restarting to mint a
214500
+ * fresh credential. Never negative: a credential that already expired, or
214501
+ * expires inside the margin, restarts immediately.
214502
+ */
214503
+ function providerEgressTokenRefreshDelayMs(expiresAt, nowMs) {
214504
+ if (!expiresAt) return PROVIDER_EGRESS_TOKEN_REFRESH_FALLBACK_MS;
214505
+ const expiresAtMs = Date.parse(expiresAt);
214506
+ if (Number.isNaN(expiresAtMs)) return PROVIDER_EGRESS_TOKEN_REFRESH_FALLBACK_MS;
214507
+ return Math.max(0, expiresAtMs - nowMs - PROVIDER_EGRESS_TOKEN_REFRESH_MARGIN_MS);
214508
+ }
214509
+ //#endregion
214403
214510
  //#region src/provider/claudeCredentialDirectory.ts
214404
214511
  /** Per-account credentials share the existing Claude transcript directory. */
214405
214512
  /** Repoints `.credentials.json` without moving the transcripts. */
@@ -216794,7 +216901,7 @@ function claudeForgeAttributionPrompt() {
216794
216901
  * turn, an API key is, so pointing the variable there would add a second source
216795
216902
  * of truth that a later reader has to rule out.
216796
216903
  */
216797
- function buildClaudeQueryEnv(baseProcessEnv, endpointProfile, claudeSettings, providerProxyCredential, credentialDirectory, selectedSubscription = false) {
216904
+ function buildClaudeQueryEnv(baseProcessEnv, endpointProfile, claudeSettings, providerProxyCredential, credentialDirectory, selectedSubscription = false, mintedEgressModel) {
216798
216905
  if (selectedSubscription) return claudeSubscriptionChildEnv(baseProcessEnv, credentialDirectory, true);
216799
216906
  const baseEnv = scrubForgeProviderChildEnvSecrets(baseProcessEnv);
216800
216907
  const effectiveBaseUrl = resolveClaudeQueryBaseUrl(endpointProfile, claudeSettings, providerProxyCredential);
@@ -216808,7 +216915,28 @@ function buildClaudeQueryEnv(baseProcessEnv, endpointProfile, claudeSettings, pr
216808
216915
  CLAUDE_CODE_MAX_RETRIES: "0",
216809
216916
  API_TIMEOUT_MS: "90000"
216810
216917
  } : {},
216811
- ...endpointProfile?.disableToolSearch === true ? { ENABLE_TOOL_SEARCH: "false" } : {}
216918
+ ...endpointProfile?.disableToolSearch === true ? { ENABLE_TOOL_SEARCH: "false" } : {},
216919
+ ...!endpointProfile && providerProxyCredential && mintedEgressModel ? claudeWorkspaceEgressModelPins(mintedEgressModel) : {}
216920
+ };
216921
+ }
216922
+ /**
216923
+ * CMMD's Workspace egress proxy only accepts the model(s) named on the mint
216924
+ * request that issued `providerProxyCredential`, and the mint above scopes to
216925
+ * one selected model (`forge-provider-egress.routes.ts` `modelScopeError`).
216926
+ * Left alone, Claude Code and its subagents still pick their own smaller
216927
+ * models for background and Explore-subagent calls, which fall outside that
216928
+ * scope and get refused. Pinning every one of those picks to the same model
216929
+ * the mint requested keeps the whole session inside it.
216930
+ *
216931
+ * Only the plain Anthropic egress branch gets these — never an
216932
+ * endpoint-profile turn (Apex / DeepSeek / Moonshot), whose upstream model
216933
+ * catalog and scoping this does not apply to.
216934
+ */
216935
+ function claudeWorkspaceEgressModelPins(model) {
216936
+ return {
216937
+ ANTHROPIC_SMALL_FAST_MODEL: model,
216938
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: model,
216939
+ CLAUDE_CODE_SUBAGENT_MODEL: model
216812
216940
  };
216813
216941
  }
216814
216942
  function resolveClaudeQueryBaseUrl(endpointProfile, claudeSettings, providerProxyCredential) {
@@ -216912,7 +217040,8 @@ function buildClaudeSessionContext(input) {
216912
217040
  lastThreadStartedId: void 0,
216913
217041
  stopped: false,
216914
217042
  currentApiModelId: input.effectiveApiModelId,
216915
- currentEffort: input.effectiveEffort
217043
+ currentEffort: input.effectiveEffort,
217044
+ tokenRefreshFiber: void 0
216916
217045
  };
216917
217046
  }
216918
217047
  function claudeSessionConfiguredConfig(input) {
@@ -217213,8 +217342,34 @@ function shouldUseProviderEgressProxy(profile) {
217213
217342
  const normalized = profile.baseUrl.toLowerCase();
217214
217343
  return normalized.includes("apex.cmmd.ai") || normalized.includes("deepseek") || normalized.includes("moonshot");
217215
217344
  }
217216
- function resolveClaudeProviderEgressProvider(profile) {
217345
+ /**
217346
+ * True for a plain Claude turn (no custom endpoint profile) stamped with the
217347
+ * Workspace wallet on a CMMD cloud runtime.
217348
+ *
217349
+ * That turn has to run through CMMD's metered Workspace egress, because CMMD
217350
+ * accepted the wallet choice and enforces it only at mint time and at the
217351
+ * proxy. The personal Claude login in the VM is never an acceptable stand-in,
217352
+ * so every path below refuses the turn rather than falling back to it
217353
+ * (CMMD#5917). Runtime mode alone decides "on a CMMD runtime": a runtime whose
217354
+ * mint settings are incomplete still counts, and is refused.
217355
+ */
217356
+ function isClaudeWorkspaceWalletTurnOnCmmdRuntime(profile, wallet) {
217357
+ return wallet === "workspace" && !profile?.baseUrl && process.env.FORGE_CMMD_RUNTIME_MODE === "true";
217358
+ }
217359
+ /**
217360
+ * Which egress lane, if any, a Claude session mints a proxy token for.
217361
+ *
217362
+ * - `apex`: a centrally managed Apex profile, whatever the wallet.
217363
+ * - `anthropic` for a Workspace-wallet turn on a CMMD runtime that can mint.
217364
+ * This is a narrow exception to `WORKSPACE_PROVIDER_ACCESS_DISABLED`, which
217365
+ * still governs every other plain Claude turn (CMMD#5917).
217366
+ * - `anthropic` through the local-user lane when the shared kill switch is
217367
+ * off. Unchanged, and never reached on a CMMD runtime.
217368
+ * - `null` otherwise, which leaves the turn on the personal login.
217369
+ */
217370
+ function resolveClaudeProviderEgressProvider(profile, wallet) {
217217
217371
  if (shouldUseProviderEgressProxy(profile)) return "apex";
217372
+ if (isClaudeWorkspaceWalletTurnOnCmmdRuntime(profile, wallet) && canIssueCmmdRuntimeProviderEgressToken()) return "anthropic";
217218
217373
  if (!profile?.baseUrl && false);
217219
217374
  return null;
217220
217375
  }
@@ -218836,6 +218991,9 @@ const makeClaudeAdapter = require_Schema$1.fn("makeClaudeAdapter")(function* (op
218836
218991
  const streamFiber = context.streamFiber;
218837
218992
  context.streamFiber = void 0;
218838
218993
  if (streamFiber && streamFiber.pollUnsafe() === void 0) yield* require_Path.interrupt(streamFiber);
218994
+ const tokenRefreshFiber = context.tokenRefreshFiber;
218995
+ context.tokenRefreshFiber = void 0;
218996
+ if (tokenRefreshFiber && tokenRefreshFiber.pollUnsafe() === void 0) yield* require_Path.interrupt(tokenRefreshFiber);
218839
218997
  try {
218840
218998
  context.query.close();
218841
218999
  selectedClaudeCredentialStore(serverConfig.baseDir).release(context.session.threadId);
@@ -218866,6 +219024,35 @@ const makeClaudeAdapter = require_Schema$1.fn("makeClaudeAdapter")(function* (op
218866
219024
  }
218867
219025
  sessions.delete(context.session.threadId);
218868
219026
  });
219027
+ /**
219028
+ * Restarts `threadId`'s session near its Workspace Anthropic egress
219029
+ * credential's expiry, once idle (CMMD-Center/CMMD#5917 review). Deferred
219030
+ * rather than run while a turn is active, the same trade
219031
+ * `scheduleProviderEgressTokenRefresh` makes for Codex in
219032
+ * `codexAppServerManager.ts`: interrupting mid-turn would trade a clean
219033
+ * 401 for a broken one.
219034
+ *
219035
+ * A known gap, same as Codex's: a single turn that runs past the
219036
+ * credential's actual expiry still fails mid-turn with a 401. This only
219037
+ * covers the idle-session case.
219038
+ */
219039
+ const scheduleWorkspaceEgressTokenRefresh = (context, credential, runFork) => {
219040
+ const threadId = context.session.threadId;
219041
+ context.tokenRefreshFiber = runFork(require_Schema$1.gen(function* () {
219042
+ let delayMs = providerEgressTokenRefreshDelayMs(credential.expiresAt, Date.now());
219043
+ while (true) {
219044
+ yield* require_Schema$1.sleep(delayMs);
219045
+ const current = sessions.get(threadId);
219046
+ if (!current || current !== context || current.stopped) return;
219047
+ if (current.turnState) {
219048
+ delayMs = PROVIDER_EGRESS_TOKEN_REFRESH_DEFER_MS;
219049
+ continue;
219050
+ }
219051
+ yield* stopSessionInternal(current, { emitExitEvent: true });
219052
+ return;
219053
+ }
219054
+ }));
219055
+ };
218869
219056
  const requireSession = (threadId) => {
218870
219057
  const context = sessions.get(threadId);
218871
219058
  if (!context) return require_Schema$1.fail(new ProviderAdapterSessionNotFoundError({
@@ -219060,19 +219247,46 @@ const makeClaudeAdapter = require_Schema$1.fn("makeClaudeAdapter")(function* (op
219060
219247
  });
219061
219248
  return (toolName, toolInput, callbackOptions) => runPromise(canUseToolEffect(toolName, toolInput, callbackOptions));
219062
219249
  };
219063
- const issueClaudeProviderProxyCredential = require_Schema$1.fn("issueClaudeProviderProxyCredential")(function* (endpointProfile, model, threadId) {
219064
- const provider = resolveClaudeProviderEgressProvider(endpointProfile);
219065
- if (!provider) return null;
219066
- return yield* issueProviderEgressCredential({
219250
+ /**
219251
+ * Mints the egress proxy credential this session runs on, or returns null
219252
+ * when the session runs on the personal login.
219253
+ *
219254
+ * A Workspace-wallet turn on a CMMD runtime never gets null: it either mints
219255
+ * Anthropic egress on a workspace_key receipt or fails here with
219256
+ * CLAUDE_WORKSPACE_EGRESS_REFUSAL, which
219257
+ * stops `startSession` before the child environment is built, so the
219258
+ * personal-login branch of `buildClaudeQueryEnv` is never reached for it.
219259
+ */
219260
+ const issueClaudeProviderProxyCredential = require_Schema$1.fn("issueClaudeProviderProxyCredential")(function* (endpointProfile, model, threadId, wallet) {
219261
+ const workspaceWalletTurn = isClaudeWorkspaceWalletTurnOnCmmdRuntime(endpointProfile, wallet);
219262
+ const provider = resolveClaudeProviderEgressProvider(endpointProfile, wallet);
219263
+ if (!provider) {
219264
+ if (workspaceWalletTurn) return yield* new ProviderAdapterProcessError({
219265
+ provider: PROVIDER$11,
219266
+ threadId,
219267
+ detail: `${CLAUDE_WORKSPACE_EGRESS_REFUSAL} This runtime is missing the CMMD settings it needs to request one.`
219268
+ });
219269
+ return null;
219270
+ }
219271
+ const credential = yield* issueProviderEgressCredential({
219067
219272
  provider,
219068
219273
  model,
219069
219274
  threadId
219070
- }).pipe(require_Schema$1.mapError((cause) => new ProviderAdapterProcessError({
219275
+ }).pipe(require_Schema$1.mapError((cause) => {
219276
+ const reason = toMessage(cause, "Failed to issue provider proxy token.");
219277
+ return new ProviderAdapterProcessError({
219278
+ provider: PROVIDER$11,
219279
+ threadId,
219280
+ detail: workspaceWalletTurn && provider === "anthropic" ? `${CLAUDE_WORKSPACE_EGRESS_REFUSAL} ${reason}` : reason,
219281
+ cause
219282
+ });
219283
+ }));
219284
+ if (workspaceWalletTurn && provider === "anthropic" && credential.deliveryReceipt?.identity.kind !== "workspace_key") return yield* new ProviderAdapterProcessError({
219071
219285
  provider: PROVIDER$11,
219072
219286
  threadId,
219073
- detail: toMessage(cause, "Failed to issue provider proxy token."),
219074
- cause
219075
- })));
219287
+ detail: `${CLAUDE_WORKSPACE_EGRESS_REFUSAL} CMMD issued a credential that is not a Workspace key.`
219288
+ });
219289
+ return credential;
219076
219290
  });
219077
219291
  const createClaudeQueryRuntime = require_Schema$1.fn("createClaudeQueryRuntime")(function* (prompt, queryOptions, threadId) {
219078
219292
  return yield* require_Schema$1.try_({
@@ -219187,6 +219401,12 @@ const makeClaudeAdapter = require_Schema$1.fn("makeClaudeAdapter")(function* (op
219187
219401
  claudeCredentialDirectory: credentialDirectoryDecision.outcome === "set" ? credentialDirectoryDecision.directory : null
219188
219402
  };
219189
219403
  });
219404
+ /**
219405
+ * Starts a Claude SDK session for a thread. The model access it runs on is
219406
+ * decided here, once: a selected account's credential, a minted egress proxy
219407
+ * credential, an endpoint profile, or the personal login. A Workspace-wallet
219408
+ * turn on a CMMD runtime is refused rather than given the personal login.
219409
+ */
219190
219410
  const startSession = require_Schema$1.fn("startSession")(function* (input) {
219191
219411
  const sessionProvider = yield* validateClaudeStartSessionProvider(input.provider);
219192
219412
  const startedAt = yield* nowIso;
@@ -219275,7 +219495,13 @@ const makeClaudeAdapter = require_Schema$1.fn("makeClaudeAdapter")(function* (op
219275
219495
  operation: "startSession",
219276
219496
  issue: "The selected Claude account cannot be used with a custom API endpoint. Choose a subscription model."
219277
219497
  });
219278
- const providerProxyCredential = selectedAccountIdentity !== null ? null : yield* issueClaudeProviderProxyCredential(modelConfig.endpointProfile, modelConfig.modelSlug ?? modelConfig.effectiveApiModelId ?? "unknown", threadId);
219498
+ if (selectedAccountIdentity !== null && isClaudeWorkspaceWalletTurnOnCmmdRuntime(modelConfig.endpointProfile, input.wallet)) return yield* new ProviderAdapterValidationError({
219499
+ provider: PROVIDER$11,
219500
+ operation: "startSession",
219501
+ 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."
219502
+ });
219503
+ const mintedEgressModel = modelConfig.modelSlug ?? modelConfig.effectiveApiModelId ?? "unknown";
219504
+ const providerProxyCredential = selectedAccountIdentity !== null ? null : yield* issueClaudeProviderProxyCredential(modelConfig.endpointProfile, mintedEgressModel, threadId, input.wallet);
219279
219505
  const permissionMode = permissionModeForRuntimeMode(input.runtimeMode);
219280
219506
  const settings = claudeQuerySettings(modelConfig.thinking, modelConfig.fastMode);
219281
219507
  const workspacePreflight = input.cwd ? formatWorkspaceEnvironmentPreflightForAgent(runWorkspaceEnvironmentPreflight({ cwd: input.cwd })) : void 0;
@@ -219298,7 +219524,7 @@ const makeClaudeAdapter = require_Schema$1.fn("makeClaudeAdapter")(function* (op
219298
219524
  existingResumeSessionId,
219299
219525
  newSessionId,
219300
219526
  canUseTool,
219301
- env: buildClaudeQueryEnv(process.env, modelConfig.endpointProfile, claudeSettings, providerProxyCredential, claudeCredentialDirectory, selectedAccountIdentity !== null),
219527
+ env: buildClaudeQueryEnv(process.env, modelConfig.endpointProfile, claudeSettings, providerProxyCredential, claudeCredentialDirectory, selectedAccountIdentity !== null, mintedEgressModel),
219302
219528
  browserManager,
219303
219529
  threadId,
219304
219530
  browserToolEnvironmentId,
@@ -219351,6 +219577,7 @@ const makeClaudeAdapter = require_Schema$1.fn("makeClaudeAdapter")(function* (op
219351
219577
  })
219352
219578
  });
219353
219579
  attachClaudeStreamFiber(context$4, runFork);
219580
+ if (providerProxyCredential?.deliveryReceipt?.identity.kind === "workspace_key") scheduleWorkspaceEgressTokenRefresh(context$4, providerProxyCredential, runFork);
219354
219581
  return { ...session };
219355
219582
  }, (effect, input) => effect.pipe(require_Schema$1.onExit((exit) => require_Schema$1.sync(() => {
219356
219583
  if (exit._tag === "Failure") selectedClaudeCredentialStore(serverConfig.baseDir).release(input.threadId);
@@ -233743,6 +233970,11 @@ function toRuntimeStatus(session) {
233743
233970
  default: return "running";
233744
233971
  }
233745
233972
  }
233973
+ /**
233974
+ * The runtime payload persisted beside a session binding. The session directory
233975
+ * merges it shallowly into what is already stored, so a key left out here
233976
+ * (a later upsert with no wallet, say) keeps its earlier value.
233977
+ */
233746
233978
  function toRuntimePayloadFromSession(session, extra) {
233747
233979
  return {
233748
233980
  cwd: session.cwd ?? null,
@@ -233750,6 +233982,7 @@ function toRuntimePayloadFromSession(session, extra) {
233750
233982
  activeTurnId: session.activeTurnId ?? null,
233751
233983
  lastError: session.lastError ?? null,
233752
233984
  ...extra?.modelSelection !== void 0 ? { modelSelection: extra.modelSelection } : {},
233985
+ ...extra?.wallet !== void 0 ? { wallet: extra.wallet } : {},
233753
233986
  ...extra?.lastRuntimeEvent !== void 0 ? { lastRuntimeEvent: extra.lastRuntimeEvent } : {},
233754
233987
  ...extra?.lastRuntimeEventAt !== void 0 ? { lastRuntimeEventAt: extra.lastRuntimeEventAt } : {}
233755
233988
  };
@@ -233759,6 +233992,34 @@ function readPersistedModelSelection(runtimePayload) {
233759
233992
  const raw = "modelSelection" in runtimePayload ? runtimePayload.modelSelection : void 0;
233760
233993
  return require_Schema$1.is(ModelSelection)(raw) ? raw : void 0;
233761
233994
  }
233995
+ /**
233996
+ * The wallet the thread's provider session last started with, read back from
233997
+ * the persisted runtime payload (CMMD#5917).
233998
+ *
233999
+ * Only a CMMD kick names a wallet. Every other start (a person's follow-up
234000
+ * that changes the model, a recovery after the adapter lost the session)
234001
+ * reuses this one, so a thread billed to the Workspace wallet does not drop to
234002
+ * the personal login the first time its session restarts. Undefined when no
234003
+ * kick ever named one, which keeps today's behavior.
234004
+ */
234005
+ const isWorkSessionWallet = require_Schema$1.is(WorkSessionWallet);
234006
+ function readPersistedWallet(runtimePayload) {
234007
+ if (!runtimePayload || typeof runtimePayload !== "object" || Array.isArray(runtimePayload)) return;
234008
+ const raw = "wallet" in runtimePayload ? runtimePayload.wallet : void 0;
234009
+ return isWorkSessionWallet(raw) ? raw : void 0;
234010
+ }
234011
+ /**
234012
+ * The wallet a new session starts on: the one the kick named, else the one the
234013
+ * thread's session last ran with, whatever provider that was, because the
234014
+ * wallet belongs to the Work Session and not to the provider (CMMD#5917).
234015
+ */
234016
+ function resolveStartSessionWallet(requested, persistedBinding) {
234017
+ return requested ?? readPersistedWallet(persistedBinding?.runtimePayload);
234018
+ }
234019
+ /** `{ wallet }` when one is known, an empty object otherwise (exactOptionalPropertyTypes). */
234020
+ function walletField$1(wallet) {
234021
+ return wallet === void 0 ? {} : { wallet };
234022
+ }
233762
234023
  function readProviderAccountIdFromModelSelection(modelSelection) {
233763
234024
  if (!modelSelection) return void 0;
233764
234025
  switch (modelSelection.provider) {
@@ -233793,12 +234054,18 @@ const makeProviderService = require_Schema$1.fn("makeProviderService")(function*
233793
234054
  const withSessionLock = (threadId, effect) => require_Path.get$1(sessionLocks, threadId).pipe(require_Schema$1.flatMap((lock) => lock.withPermit(effect)), require_Schema$1.scoped);
233794
234055
  const runtimeEventPubSub = yield* require_Path.unbounded$1();
233795
234056
  const assertProviderExecutable = options?.assertProviderExecutable ?? (() => require_Schema$1.succeed(null));
234057
+ /**
234058
+ * Re-runs the readiness guard for an existing session before a turn or a
234059
+ * continuation, with the account and wallet the session was started on, and
234060
+ * refuses if the delivered identity drifted from the persisted one.
234061
+ */
233796
234062
  const assertCurrentProviderDelivery = require_Schema$1.fn("assertCurrentProviderDelivery")(function* (input) {
233797
234063
  const persistedBinding = require_Schema$1.getOrUndefined$1(yield* directory.getBinding(input.threadId));
233798
234064
  const providerAccountId = readPersistedProviderAccountId(persistedBinding?.runtimePayload);
233799
234065
  const currentBinding = yield* assertProviderExecutable({
233800
234066
  ...input,
233801
- ...selectedAccountGuardFields(providerAccountId)
234067
+ ...selectedAccountGuardFields(providerAccountId),
234068
+ ...walletField$1(readPersistedWallet(persistedBinding?.runtimePayload))
233802
234069
  });
233803
234070
  if (!currentBinding) return;
233804
234071
  if (!persistedBinding || persistedBinding.provider !== input.provider) return yield* toValidationError(input.operation, `Cannot verify the delivered provider identity for thread '${input.threadId}'.`);
@@ -233814,6 +234081,11 @@ const makeProviderService = require_Schema$1.fn("makeProviderService")(function*
233814
234081
  return yield* toValidationError(input.operation, `Thread '${input.threadId}' is bound to provider account '${input.persistedAccountId}' and cannot use provider account '${input.requestedAccountId}'.`);
233815
234082
  });
233816
234083
  const publishRuntimeEvent = (event) => require_Schema$1.succeed(event).pipe(require_Schema$1.tap((canonicalEvent) => canonicalEventLogger ? canonicalEventLogger.write(canonicalEvent, null) : require_Schema$1.void_), require_Schema$1.flatMap((canonicalEvent) => require_Path.publish(runtimeEventPubSub, canonicalEvent)), require_Schema$1.asVoid);
234084
+ /**
234085
+ * Writes the thread's session binding. `extra` carries what only a start
234086
+ * knows, the model selection and the wallet, so a later runtime-event upsert
234087
+ * that omits them leaves the stored values in place.
234088
+ */
233817
234089
  const upsertSessionBinding = (session, threadId, extra) => directory.upsert({
233818
234090
  threadId,
233819
234091
  provider: session.provider,
@@ -233829,6 +234101,11 @@ const makeProviderService = require_Schema$1.fn("makeProviderService")(function*
233829
234101
  eventType: event.type
233830
234102
  }).pipe(require_Schema$1.andThen(publishRuntimeEvent(event)));
233831
234103
  yield* require_Schema$1.forEach(adapters, (adapter) => require_Path.runForEach(adapter.streamEvents, processRuntimeEvent).pipe(require_Schema$1.forkScoped)).pipe(require_Schema$1.asVoid);
234104
+ /**
234105
+ * Restarts a session the adapter lost, from the persisted binding alone: cwd,
234106
+ * model selection, wallet and resume cursor. It has no read model, so what
234107
+ * the binding stored is all it can go on.
234108
+ */
233832
234109
  const recoverSessionForThread = require_Schema$1.fn("recoverSessionForThread")(function* (input) {
233833
234110
  yield* require_Schema$1.annotateCurrentSpan({
233834
234111
  "provider.operation": "recover-session",
@@ -233857,11 +234134,13 @@ const makeProviderService = require_Schema$1.fn("makeProviderService")(function*
233857
234134
  const persistedCwd = readPersistedCwd(input.binding.runtimePayload);
233858
234135
  const persistedModelSelection = readPersistedModelSelection(input.binding.runtimePayload);
233859
234136
  const persistedProviderAccountId = readProviderAccountIdFromModelSelection(persistedModelSelection);
234137
+ const persistedWallet = readPersistedWallet(input.binding.runtimePayload);
233860
234138
  const currentDeliveryBinding = yield* assertProviderExecutable({
233861
234139
  threadId: input.binding.threadId,
233862
234140
  provider: input.binding.provider,
233863
234141
  operation: input.operation,
233864
- ...selectedAccountGuardFields(persistedProviderAccountId)
234142
+ ...selectedAccountGuardFields(persistedProviderAccountId),
234143
+ ...walletField$1(persistedWallet)
233865
234144
  });
233866
234145
  const boundResumeCursor = yield* bindProviderDeliveryToResumeCursor({
233867
234146
  operation: input.operation,
@@ -233875,7 +234154,8 @@ const makeProviderService = require_Schema$1.fn("makeProviderService")(function*
233875
234154
  ...persistedCwd ? { cwd: persistedCwd } : {},
233876
234155
  ...persistedModelSelection ? { modelSelection: persistedModelSelection } : {},
233877
234156
  ...hasResumeCursor ? { resumeCursor: boundResumeCursor } : {},
233878
- runtimeMode: input.binding.runtimeMode ?? "full-access"
234157
+ runtimeMode: input.binding.runtimeMode ?? "full-access",
234158
+ ...walletField$1(persistedWallet)
233879
234159
  });
233880
234160
  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}'.`);
233881
234161
  yield* upsertSessionBinding(resumed, input.binding.threadId);
@@ -233948,6 +234228,11 @@ const makeProviderService = require_Schema$1.fn("makeProviderService")(function*
233948
234228
  isActive: true
233949
234229
  };
233950
234230
  });
234231
+ /**
234232
+ * Starts a provider session for a thread: decodes the input, resolves the
234233
+ * provider, guards account and delivery identity, resolves the wallet, then
234234
+ * persists the binding the adapter returns.
234235
+ */
233951
234236
  const startSession = require_Schema$1.fn("startSession")(function* (threadId, rawInput) {
233952
234237
  const parsed = yield* decodeInputOrValidationError({
233953
234238
  operation: "ProviderService.startSession",
@@ -233980,24 +234265,31 @@ const makeProviderService = require_Schema$1.fn("makeProviderService")(function*
233980
234265
  persistedAccountId: priorAccountId,
233981
234266
  requestedAccountId
233982
234267
  });
234268
+ const effectiveResumeCursor = input.resumeCursor ?? (persistedBinding?.provider === effectiveProvider ? persistedBinding.resumeCursor : void 0);
234269
+ const effectiveWallet = resolveStartSessionWallet(input.wallet, persistedBinding);
233983
234270
  const boundResumeCursor = yield* bindProviderDeliveryToResumeCursor({
233984
234271
  operation: "ProviderService.startSession",
233985
234272
  provider: effectiveProvider,
233986
- resumeCursor: input.resumeCursor ?? (persistedBinding?.provider === effectiveProvider ? persistedBinding.resumeCursor : void 0),
234273
+ resumeCursor: effectiveResumeCursor,
233987
234274
  currentBinding: yield* assertProviderExecutable({
233988
234275
  threadId,
233989
234276
  provider: effectiveProvider,
233990
234277
  operation: "ProviderService.startSession",
233991
- ...selectedAccountGuardFields(requestedAccountId)
234278
+ ...selectedAccountGuardFields(requestedAccountId),
234279
+ ...walletField$1(effectiveWallet)
233992
234280
  })
233993
234281
  });
233994
234282
  const session = yield* adapter.startSession({
233995
234283
  ...input,
233996
234284
  accountTransition: explicitProviderAccountTransition(priorAccountId, requestedAccountId),
233997
- ...boundResumeCursor !== void 0 ? { resumeCursor: boundResumeCursor } : {}
234285
+ ...boundResumeCursor !== void 0 ? { resumeCursor: boundResumeCursor } : {},
234286
+ ...walletField$1(effectiveWallet)
233998
234287
  });
233999
234288
  if (session.provider !== adapter.provider) return yield* toValidationError("ProviderService.startSession", `Adapter/provider mismatch: requested '${adapter.provider}', received '${session.provider}'.`);
234000
- yield* upsertSessionBinding(session, threadId, { modelSelection: input.modelSelection });
234289
+ yield* upsertSessionBinding(session, threadId, {
234290
+ modelSelection: input.modelSelection,
234291
+ ...walletField$1(effectiveWallet)
234292
+ });
234001
234293
  yield* analytics.record("provider.session.started", {
234002
234294
  provider: session.provider,
234003
234295
  runtimeMode: input.runtimeMode,
@@ -234799,8 +235091,13 @@ function makeClaudeRuntimeReadinessGuard(config, dependencies) {
234799
235091
  };
234800
235092
  return (input) => claudeReadinessGuardEffect(config, dependencies, resolved, input);
234801
235093
  }
235094
+ /**
235095
+ * One guard run: skip when the turn needs no delivered Claude credential,
235096
+ * prepare a selected account's credential when one is named, otherwise verify
235097
+ * the owner's native runtime generation against CMMD.
235098
+ */
234802
235099
  function claudeReadinessGuardEffect(config, dependencies, resolved, input) {
234803
- if (!requiresNativeClaudeReadiness(config, input.provider, input.providerAccountId)) return require_Schema$1.succeed(null);
235100
+ if (!requiresNativeClaudeReadiness(config, input.provider, input.providerAccountId, input.wallet)) return require_Schema$1.succeed(null);
234804
235101
  if (input.providerAccountId !== void 0) {
234805
235102
  const prepareSelectedCredential = dependencies.prepareSelectedCredential ?? makeClaudeSelectedCredentialPreparer(config, {
234806
235103
  resolveJwt: dependencies.resolveJwt,
@@ -234823,9 +235120,21 @@ function claudeReadinessGuardEffect(config, dependencies, resolved, input) {
234823
235120
  catch: (cause) => readinessValidationError(input.operation, cause)
234824
235121
  });
234825
235122
  }
234826
- function requiresNativeClaudeReadiness(config, provider, providerAccountId) {
235123
+ /**
235124
+ * Whether this turn runs on a Claude credential delivered into the VM, and so
235125
+ * has to prove that credential is the one CMMD applied before it runs.
235126
+ *
235127
+ * A turn billed to the Workspace wallet with no selected account does not: the
235128
+ * Claude adapter runs it on CMMD's metered egress and refuses it when CMMD
235129
+ * will not mint (CMMD#5917). Checking the owner's personal login there would
235130
+ * refuse a Workspace turn for a personal credential it never uses. A selected
235131
+ * account still goes through its own preparation, and the adapter then refuses
235132
+ * the Workspace-plus-account combination.
235133
+ */
235134
+ function requiresNativeClaudeReadiness(config, provider, providerAccountId, wallet) {
234827
235135
  if (provider !== "claudeAgent" || config.forgeCmmdRuntimeMode !== true) return false;
234828
- return providerAccountId !== void 0 || personalClaudeInVmEnabled();
235136
+ if (providerAccountId !== void 0) return true;
235137
+ return wallet !== "workspace" && personalClaudeInVmEnabled();
234829
235138
  }
234830
235139
  function resolveGuardAuthority(config, readSessionId, input) {
234831
235140
  const runtimeId = config.forgeCmmdRuntimeId?.trim();
@@ -288800,6 +289109,7 @@ const ProjectionThread = require_Schema$1.Struct({
288800
289109
  anchorCmmdId: require_Schema$1.NullOr(require_Schema$1.String).pipe(require_Schema$1.withDecodingDefault(require_Schema$1.succeed(null))),
288801
289110
  workSessionId: require_Schema$1.optionalKey(require_Schema$1.NullOr(require_Schema$1.String)),
288802
289111
  workSessionBoundAt: require_Schema$1.optionalKey(require_Schema$1.NullOr(require_Schema$1.String)),
289112
+ wallet: require_Schema$1.optionalKey(require_Schema$1.NullOr(WorkSessionWallet)),
288803
289113
  linkedPullRequest: require_Schema$1.optionalKey(require_Schema$1.NullOr(LinkedPullRequest)),
288804
289114
  status: ThreadStatus.pipe(require_Schema$1.withDecodingDefault(require_Schema$1.succeed("idle"))),
288805
289115
  workerRole: require_Schema$1.NullOr(WorkerRole).pipe(require_Schema$1.withDecodingDefault(require_Schema$1.succeed(null))),
@@ -293301,6 +293611,18 @@ function publicProviderFailureDetailFromCause(cause) {
293301
293611
  const error = require_Schema$1.squash(cause);
293302
293612
  return isProviderValidationError(error) ? publicProviderFailureDetailFromError(error) : publicProviderFailureDetail(require_Schema$1.pretty(cause));
293303
293613
  }
293614
+ /**
293615
+ * The wallet a session start asks for: the one on the turn-start event, which
293616
+ * the decider stamps at acceptance, else the one persisted on the thread row,
293617
+ * for older events and starts not driven by a turn (CMMD#5917). The decider writes the kick's
293618
+ * wallet to the thread before this reactor sees the turn, and the row
293619
+ * survives a restart, so a turn refused before any session start, or a
293620
+ * person's follow-up after a restart, still starts on the kick's wallet.
293621
+ * Undefined when no kick ever named one.
293622
+ */
293623
+ function resolveRequestedWallet(kickWallet, threadWallet) {
293624
+ return kickWallet ?? threadWallet ?? void 0;
293625
+ }
293304
293626
  function canReplaceThreadTitle(currentTitle, titleSeed) {
293305
293627
  const trimmedCurrentTitle = currentTitle.trim();
293306
293628
  if (trimmedCurrentTitle === DEFAULT_THREAD_TITLE) return true;
@@ -293621,6 +293943,16 @@ const make$7 = require_Schema$1.gen(function* () {
293621
293943
  * detect the mismatch and restart, dropping A's cached token (forge#3597).
293622
293944
  */
293623
293945
  const threadSessionWorkSessionIds = /* @__PURE__ */ new Map();
293946
+ /**
293947
+ * The wallet each LIVE provider session was started with, or null when the
293948
+ * start carried none (CMMD#5917).
293949
+ *
293950
+ * The Claude adapter reads the wallet once, at session start, to decide
293951
+ * whether the session runs on CMMD's Workspace egress or the personal
293952
+ * login. A kick naming a different wallet than the live session's has to
293953
+ * restart it, or the new wallet's turn runs on the old session's credential.
293954
+ */
293955
+ const threadSessionWallets = /* @__PURE__ */ new Map();
293624
293956
  const appendProviderFailureActivity = (input) => orchestrationEngine.dispatch({
293625
293957
  type: "thread.activity.append",
293626
293958
  commandId: serverCommandId$2("provider-failure-activity"),
@@ -293666,10 +293998,16 @@ const make$7 = require_Schema$1.gen(function* () {
293666
293998
  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.";
293667
293999
  return null;
293668
294000
  });
294001
+ /**
294002
+ * Returns the thread id of a live provider session for the thread, starting
294003
+ * one, or restarting the live one when its provider, model, account, Work
294004
+ * Session or wallet no longer matches what this turn asks for.
294005
+ */
293669
294006
  const ensureSessionForThread = require_Schema$1.fn("ensureSessionForThread")(function* (threadId, createdAt, options) {
293670
294007
  const readModel = yield* orchestrationEngine.getReadModel();
293671
294008
  const thread = readModel.threads.find((entry) => entry.id === threadId);
293672
294009
  if (!thread) return yield* require_Schema$1.die(/* @__PURE__ */ new Error(`Thread '${threadId}' was not found in read model.`));
294010
+ const requestedWallet = resolveRequestedWallet(options?.wallet, thread.wallet);
293673
294011
  const desiredRuntimeMode = thread.runtimeMode;
293674
294012
  const currentProvider = thread.session?.status !== "stopped" && isProviderKind(thread.session?.providerName) ? thread.session.providerName : void 0;
293675
294013
  const requestedModelSelection = options?.modelSelection;
@@ -293686,10 +294024,12 @@ const make$7 = require_Schema$1.gen(function* () {
293686
294024
  ...effectiveCwd ? { cwd: effectiveCwd } : {},
293687
294025
  modelSelection: desiredModelSelection,
293688
294026
  ...input?.resumeCursor !== void 0 ? { resumeCursor: input.resumeCursor } : {},
293689
- runtimeMode: desiredRuntimeMode
294027
+ runtimeMode: desiredRuntimeMode,
294028
+ ...requestedWallet !== void 0 ? { wallet: requestedWallet } : {}
293690
294029
  }), () => require_Schema$1.sync(() => {
293691
294030
  threadSessionAccountIds.set(threadId, readProviderAccountId(desiredModelSelection));
293692
294031
  threadSessionWorkSessionIds.set(threadId, thread.workSessionId ?? null);
294032
+ threadSessionWallets.set(threadId, requestedWallet ?? threadSessionWallets.get(threadId) ?? null);
293693
294033
  }));
293694
294034
  const bindSessionToThread = (session) => setThreadSession({
293695
294035
  threadId,
@@ -293739,7 +294079,15 @@ const make$7 = require_Schema$1.gen(function* () {
293739
294079
  const currentWorkSessionId = thread.workSessionId ?? null;
293740
294080
  const sessionWorkSessionId = threadSessionWorkSessionIds.get(threadId);
293741
294081
  const shouldRestartForWorkSessionChange = threadSessionWorkSessionIds.has(threadId) && sessionWorkSessionId !== currentWorkSessionId;
293742
- if (!runtimeModeChanged && !providerChanged && !shouldRestartForModelChange && !shouldRestartForModelSelectionChange && !shouldRestartForAccountChange && !shouldRestartForWorkSessionChange) return existingSessionThreadId;
294082
+ /**
294083
+ * A kick that names a wallet other than the one the live session started
294084
+ * with restarts it, so the Claude adapter re-decides its egress from the
294085
+ * new wallet (CMMD#5917). A live session this reactor did not start has
294086
+ * no recorded wallet and restarts too, which costs a resume and never
294087
+ * leaves a Workspace turn on a personal session.
294088
+ */
294089
+ const shouldRestartForWalletChange = requestedWallet !== void 0 && threadSessionWallets.get(threadId) !== requestedWallet;
294090
+ if (!runtimeModeChanged && !providerChanged && !shouldRestartForModelChange && !shouldRestartForModelSelectionChange && !shouldRestartForAccountChange && !shouldRestartForWorkSessionChange && !shouldRestartForWalletChange) return existingSessionThreadId;
293743
294091
  const resumeCursor = providerChanged || shouldRestartForModelChange ? void 0 : activeSession?.resumeCursor ?? void 0;
293744
294092
  yield* require_Schema$1.logInfo("provider command reactor restarting provider session", {
293745
294093
  threadId,
@@ -293755,9 +294103,10 @@ const make$7 = require_Schema$1.gen(function* () {
293755
294103
  shouldRestartForModelSelectionChange,
293756
294104
  shouldRestartForAccountChange,
293757
294105
  shouldRestartForWorkSessionChange,
294106
+ shouldRestartForWalletChange,
293758
294107
  hasResumeCursor: resumeCursor !== void 0
293759
294108
  });
293760
- if (shouldRestartForAccountChange || shouldRestartForWorkSessionChange || providerChanged) yield* providerService.stopSession({
294109
+ if (shouldRestartForAccountChange || shouldRestartForWorkSessionChange || shouldRestartForWalletChange || providerChanged) yield* providerService.stopSession({
293761
294110
  threadId,
293762
294111
  preserveResumeState: true
293763
294112
  });
@@ -293857,6 +294206,11 @@ const make$7 = require_Schema$1.gen(function* () {
293857
294206
  turnId: input.turnId,
293858
294207
  cause: require_Schema$1.pretty(cause)
293859
294208
  })), require_Schema$1.onInterrupt(() => releaseTurnStart(input.holdKey)), require_Schema$1.ensuring(closeTurnStartEventBuffer(input.holdKey, input.events)));
294209
+ /**
294210
+ * Ensures a session with the turn's model and wallet, then sends the turn.
294211
+ * A session-start failure (a refused Workspace egress mint, for one)
294212
+ * propagates to the caller, which records it on the thread.
294213
+ */
293860
294214
  const sendTurnForThread = require_Schema$1.fn("sendTurnForThread")(function* (input) {
293861
294215
  const thread = yield* resolveThread(input.threadId);
293862
294216
  if (!thread) return { _tag: "skipped" };
@@ -293871,7 +294225,10 @@ const make$7 = require_Schema$1.gen(function* () {
293871
294225
  });
293872
294226
  return { _tag: "skipped" };
293873
294227
  }
293874
- yield* ensureSessionForThread(input.threadId, input.createdAt, input.modelSelection !== void 0 ? { modelSelection: input.modelSelection } : {});
294228
+ yield* ensureSessionForThread(input.threadId, input.createdAt, {
294229
+ ...input.modelSelection !== void 0 ? { modelSelection: input.modelSelection } : {},
294230
+ ...input.wallet !== void 0 ? { wallet: input.wallet } : {}
294231
+ });
293875
294232
  if (input.modelSelection !== void 0) threadModelSelections.set(input.threadId, input.modelSelection);
293876
294233
  const cmmdTaskId = thread.anchorKind === "task" ? thread.anchorCmmdId : null;
293877
294234
  const cmmdCwd = resolveThreadWorkspaceCwd({
@@ -294084,6 +294441,11 @@ const make$7 = require_Schema$1.gen(function* () {
294084
294441
  ...result.title !== void 0 ? { title: result.title } : {}
294085
294442
  });
294086
294443
  });
294444
+ /**
294445
+ * Handles one `thread.turn-start-requested` event: validates the workspace,
294446
+ * forks first-turn title and branch generation, then sends the turn with the
294447
+ * event's model selection and wallet and records any failure on the thread.
294448
+ */
294087
294449
  const processTurnStartRequested = require_Schema$1.fn("processTurnStartRequested")(function* (event) {
294088
294450
  const key = turnStartKeyForEvent(event);
294089
294451
  if (yield* hasHandledTurnStartRecently(key)) return;
@@ -294147,7 +294509,8 @@ const make$7 = require_Schema$1.gen(function* () {
294147
294509
  ...message.attachments !== void 0 ? { attachments: message.attachments } : {},
294148
294510
  ...event.payload.modelSelection !== void 0 ? { modelSelection: event.payload.modelSelection } : {},
294149
294511
  interactionMode: event.payload.interactionMode,
294150
- createdAt: event.payload.createdAt
294512
+ createdAt: event.payload.createdAt,
294513
+ ...event.payload.wallet !== void 0 ? { wallet: event.payload.wallet } : {}
294151
294514
  }),
294152
294515
  close: closeTurnStartEventBuffer(turnStartHoldKey, turnStartEvents),
294153
294516
  onFailure: (cause) => appendProviderFailureActivity({
@@ -300333,7 +300696,7 @@ function resolveBuildCommitFromEnv(env) {
300333
300696
  * environment descriptor down instead of reporting an honest "unknown".
300334
300697
  */
300335
300698
  function readBakedBuildCommit() {
300336
- return "ba1d9d7ef5237a6a7d52a06b10c4d15f8cff00b8";
300699
+ return "5716c4b70da370f76d24ac48e65aafc1819dd6c1";
300337
300700
  }
300338
300701
  async function resolveServerBuildCommit(input) {
300339
300702
  if (isFullCommitSha(input.baked)) return input.baked;
@@ -304036,6 +304399,23 @@ function resolveThreadCommandAnchor(input) {
304036
304399
  anchorCmmdId: null
304037
304400
  };
304038
304401
  }
304402
+ /**
304403
+ * `{ wallet }` when a kick names a wallet other than the thread's, otherwise
304404
+ * null. Kept out of the decider body so its complexity budget does not grow
304405
+ * (CMMD#5917).
304406
+ */
304407
+ function turnWalletUpdate(current, requested) {
304408
+ return requested !== void 0 && requested !== current ? { wallet: requested } : null;
304409
+ }
304410
+ /**
304411
+ * `{ wallet }` for a turn-start event: the kick's wallet, else the thread's
304412
+ * wallet at acceptance, else nothing, which leaves an older-style event the
304413
+ * reactor falls back on thread state for (CMMD#5917).
304414
+ */
304415
+ function turnStartWallet(requested, current) {
304416
+ const wallet = requested ?? current ?? void 0;
304417
+ return wallet === void 0 ? {} : { wallet };
304418
+ }
304039
304419
  const decideOrchestrationCommand = require_Schema$1.fn("decideOrchestrationCommand")(function* ({ command, readModel }) {
304040
304420
  switch (command.type) {
304041
304421
  case "project.create":
@@ -304198,6 +304578,7 @@ const decideOrchestrationCommand = require_Schema$1.fn("decideOrchestrationComma
304198
304578
  anchorCmmdId: anchor.anchorCmmdId,
304199
304579
  workSessionId: command.workSessionId ?? null,
304200
304580
  ...command.workSessionId != null ? { workSessionBoundAt: command.createdAt } : {},
304581
+ ...command.wallet !== void 0 ? { wallet: command.wallet } : {},
304201
304582
  goal: command.goal ?? null,
304202
304583
  linkedPullRequest: command.linkedPullRequest ?? null,
304203
304584
  kind,
@@ -304440,6 +304821,9 @@ const decideOrchestrationCommand = require_Schema$1.fn("decideOrchestrationComma
304440
304821
  command,
304441
304822
  threadId: command.threadId
304442
304823
  });
304824
+ const isClientOriginTurnStart = command.workSessionId === void 0 || command.workSessionId === null;
304825
+ const threadHasWorkSession = targetThread.workSessionId !== void 0 && targetThread.workSessionId !== null;
304826
+ const authorizedWalletOverride = isClientOriginTurnStart && threadHasWorkSession ? void 0 : command.wallet;
304443
304827
  const nextAnchor = command.anchorKind !== void 0 || command.anchorCmmdId !== void 0 || command.cmmdTaskId !== void 0 ? resolveThreadCommandAnchor({
304444
304828
  anchorKind: command.anchorKind,
304445
304829
  anchorCmmdId: command.anchorCmmdId,
@@ -304500,6 +304884,7 @@ const decideOrchestrationCommand = require_Schema$1.fn("decideOrchestrationComma
304500
304884
  runtimeMode: targetThread.runtimeMode,
304501
304885
  interactionMode: targetThread.interactionMode,
304502
304886
  ...sourceProposedPlan !== void 0 ? { sourceProposedPlan } : {},
304887
+ ...turnStartWallet(authorizedWalletOverride, targetThread.wallet),
304503
304888
  createdAt: command.createdAt
304504
304889
  }
304505
304890
  };
@@ -304513,7 +304898,8 @@ const decideOrchestrationCommand = require_Schema$1.fn("decideOrchestrationComma
304513
304898
  });
304514
304899
  const shouldRebindWorkSession = command.workSessionId !== void 0 && command.workSessionId !== null && command.workSessionId !== targetThread.workSessionId;
304515
304900
  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);
304516
- if (!shouldUpdateAnchor && !turnModelSelection && !shouldRebindWorkSession && !shouldAdvanceBoundTimestamp) return [userMessageEvent, turnStartRequestedEvent];
304901
+ const walletUpdate = turnWalletUpdate(targetThread.wallet, authorizedWalletOverride);
304902
+ if (!shouldUpdateAnchor && !turnModelSelection && !shouldRebindWorkSession && !shouldAdvanceBoundTimestamp && !walletUpdate) return [userMessageEvent, turnStartRequestedEvent];
304517
304903
  return [
304518
304904
  {
304519
304905
  ...withEventBase({
@@ -304532,6 +304918,7 @@ const decideOrchestrationCommand = require_Schema$1.fn("decideOrchestrationComma
304532
304918
  workSessionId: command.workSessionId,
304533
304919
  workSessionBoundAt: command.createdAt
304534
304920
  } : shouldAdvanceBoundTimestamp ? { workSessionBoundAt: command.createdAt } : {},
304921
+ ...walletUpdate,
304535
304922
  updatedAt: command.createdAt
304536
304923
  }
304537
304924
  },
@@ -305103,6 +305490,7 @@ function projectEvent(model, event) {
305103
305490
  anchorCmmdId: payload.anchorCmmdId,
305104
305491
  workSessionId: payload.workSessionId ?? null,
305105
305492
  workSessionBoundAt: payload.workSessionBoundAt ?? null,
305493
+ wallet: payload.wallet ?? null,
305106
305494
  goal: payload.goal ?? null,
305107
305495
  linkedPullRequest: payload.linkedPullRequest ?? null,
305108
305496
  titleRegeneration: null,
@@ -305185,6 +305573,7 @@ function projectEvent(model, event) {
305185
305573
  ...payload.titleRegeneration !== void 0 ? { titleRegeneration: payload.titleRegeneration } : {},
305186
305574
  ...payload.workSessionId !== void 0 ? { workSessionId: payload.workSessionId } : {},
305187
305575
  ...payload.workSessionBoundAt !== void 0 ? { workSessionBoundAt: payload.workSessionBoundAt } : {},
305576
+ ...payload.wallet !== void 0 ? { wallet: payload.wallet } : {},
305188
305577
  updatedAt: payload.updatedAt
305189
305578
  })
305190
305579
  })));
@@ -306220,6 +306609,14 @@ const ProjectionThreadDbRow = ProjectionThread.mapFields(require_Schema$1.assign
306220
306609
  rateLimitStatus: require_Schema$1.fromJsonString(require_Schema$1.ArraySchema(ThreadProviderRateLimitStatus)),
306221
306610
  linkedPullRequest: require_Schema$1.NullOr(require_Schema$1.fromJsonString(LinkedPullRequest))
306222
306611
  }));
306612
+ /**
306613
+ * The `wallet` column value: the row's wallet, or SQL null when it has none.
306614
+ * Module-level so the upsert's own complexity budget does not grow
306615
+ * (CMMD#5917).
306616
+ */
306617
+ function walletColumn(wallet) {
306618
+ return wallet ?? null;
306619
+ }
306223
306620
  const makeProjectionThreadRepository = require_Schema$1.gen(function* () {
306224
306621
  const sql = yield* require_SqlError.SqlClient;
306225
306622
  const upsertProjectionThreadRow = void_({
@@ -306251,6 +306648,7 @@ const makeProjectionThreadRepository = require_Schema$1.gen(function* () {
306251
306648
  anchor_cmmd_id,
306252
306649
  work_session_id,
306253
306650
  work_session_bound_at,
306651
+ wallet,
306254
306652
  linked_pull_request_json,
306255
306653
  status,
306256
306654
  worker_role,
@@ -306285,6 +306683,7 @@ const makeProjectionThreadRepository = require_Schema$1.gen(function* () {
306285
306683
  ${row.anchorCmmdId},
306286
306684
  ${row.workSessionId ?? null},
306287
306685
  ${row.workSessionBoundAt ?? null},
306686
+ ${walletColumn(row.wallet)},
306288
306687
  ${row.linkedPullRequest == null ? null : JSON.stringify(row.linkedPullRequest)},
306289
306688
  ${row.status},
306290
306689
  ${row.workerRole},
@@ -306319,6 +306718,7 @@ const makeProjectionThreadRepository = require_Schema$1.gen(function* () {
306319
306718
  anchor_cmmd_id = excluded.anchor_cmmd_id,
306320
306719
  work_session_id = excluded.work_session_id,
306321
306720
  work_session_bound_at = excluded.work_session_bound_at,
306721
+ wallet = excluded.wallet,
306322
306722
  linked_pull_request_json = excluded.linked_pull_request_json,
306323
306723
  status = excluded.status,
306324
306724
  worker_role = excluded.worker_role,
@@ -306358,6 +306758,7 @@ const makeProjectionThreadRepository = require_Schema$1.gen(function* () {
306358
306758
  anchor_cmmd_id AS "anchorCmmdId",
306359
306759
  work_session_id AS "workSessionId",
306360
306760
  work_session_bound_at AS "workSessionBoundAt",
306761
+ wallet,
306361
306762
  linked_pull_request_json AS "linkedPullRequest",
306362
306763
  status,
306363
306764
  worker_role AS "workerRole",
@@ -306399,6 +306800,7 @@ const makeProjectionThreadRepository = require_Schema$1.gen(function* () {
306399
306800
  anchor_cmmd_id AS "anchorCmmdId",
306400
306801
  work_session_id AS "workSessionId",
306401
306802
  work_session_bound_at AS "workSessionBoundAt",
306803
+ wallet,
306402
306804
  linked_pull_request_json AS "linkedPullRequest",
306403
306805
  status,
306404
306806
  worker_role AS "workerRole",
@@ -306589,6 +306991,13 @@ function collectThreadUserInputAttachmentRelativePaths(threadId, events) {
306589
306991
  function projectedWorkSessionId(workSessionId) {
306590
306992
  return workSessionId ?? null;
306591
306993
  }
306994
+ /**
306995
+ * Coalesces an optional wallet to the persisted default, top-level for the
306996
+ * same complexity reason as `projectedWorkSessionId` (CMMD#5917).
306997
+ */
306998
+ function projectedWallet(wallet) {
306999
+ return wallet ?? null;
307000
+ }
306592
307001
  const runAttachmentSideEffects = require_Schema$1.fn("runAttachmentSideEffects")(function* (sideEffects) {
306593
307002
  const serverConfig = yield* require_Schema$1.service(ServerConfig);
306594
307003
  const fileSystem = yield* require_Schema$1.service(require_Path.FileSystem);
@@ -306756,6 +307165,7 @@ const makeOrchestrationProjectionPipeline = require_Schema$1.fn("makeOrchestrati
306756
307165
  anchorCmmdId: event.payload.anchorCmmdId,
306757
307166
  workSessionId: projectedWorkSessionId(event.payload.workSessionId),
306758
307167
  workSessionBoundAt: event.payload.workSessionBoundAt ?? null,
307168
+ wallet: projectedWallet(event.payload.wallet),
306759
307169
  linkedPullRequest: event.payload.linkedPullRequest ?? null,
306760
307170
  status: event.payload.status,
306761
307171
  workerRole: event.payload.workerRole,
@@ -306796,6 +307206,7 @@ const makeOrchestrationProjectionPipeline = require_Schema$1.fn("makeOrchestrati
306796
307206
  anchorCmmdId: thread.anchorCmmdId,
306797
307207
  workSessionId: projectedWorkSessionId(thread.workSessionId),
306798
307208
  workSessionBoundAt: thread.workSessionBoundAt ?? null,
307209
+ wallet: projectedWallet(thread.wallet),
306799
307210
  linkedPullRequest: thread.linkedPullRequest ?? null,
306800
307211
  status: thread.status,
306801
307212
  workerRole: thread.workerRole,
@@ -306866,6 +307277,7 @@ const makeOrchestrationProjectionPipeline = require_Schema$1.fn("makeOrchestrati
306866
307277
  ...event.payload.titleRegeneration !== void 0 ? { titleRegeneration: event.payload.titleRegeneration } : {},
306867
307278
  ...event.payload.workSessionId !== void 0 ? { workSessionId: projectedWorkSessionId(event.payload.workSessionId) } : {},
306868
307279
  ...event.payload.workSessionBoundAt !== void 0 ? { workSessionBoundAt: event.payload.workSessionBoundAt } : {},
307280
+ ...event.payload.wallet !== void 0 ? { wallet: event.payload.wallet } : {},
306869
307281
  updatedAt: event.payload.updatedAt
306870
307282
  });
306871
307283
  return;
@@ -307883,6 +308295,13 @@ function workSessionIdField(workSessionId) {
307883
308295
  function workSessionBoundAtField(workSessionBoundAt) {
307884
308296
  return workSessionBoundAt !== void 0 ? { workSessionBoundAt } : {};
307885
308297
  }
308298
+ /**
308299
+ * `{ wallet }` when the row carries one, an empty object when absent. Mirrors
308300
+ * `workSessionIdField` so `exactOptionalPropertyTypes` is satisfied (CMMD#5917).
308301
+ */
308302
+ function walletField(wallet) {
308303
+ return wallet !== void 0 ? { wallet } : {};
308304
+ }
307886
308305
  const makeProjectionSnapshotQuery = require_Schema$1.gen(function* () {
307887
308306
  const sql = yield* require_SqlError.SqlClient;
307888
308307
  const repositoryIdentityResolver = yield* RepositoryIdentityResolver;
@@ -307937,6 +308356,7 @@ const makeProjectionSnapshotQuery = require_Schema$1.gen(function* () {
307937
308356
  anchor_cmmd_id AS "anchorCmmdId",
307938
308357
  work_session_id AS "workSessionId",
307939
308358
  work_session_bound_at AS "workSessionBoundAt",
308359
+ wallet,
307940
308360
  linked_pull_request_json AS "linkedPullRequest",
307941
308361
  status,
307942
308362
  worker_role AS "workerRole",
@@ -307977,6 +308397,7 @@ const makeProjectionSnapshotQuery = require_Schema$1.gen(function* () {
307977
308397
  anchor_cmmd_id AS "anchorCmmdId",
307978
308398
  work_session_id AS "workSessionId",
307979
308399
  work_session_bound_at AS "workSessionBoundAt",
308400
+ wallet,
307980
308401
  linked_pull_request_json AS "linkedPullRequest",
307981
308402
  status,
307982
308403
  worker_role AS "workerRole",
@@ -308083,6 +308504,7 @@ const makeProjectionSnapshotQuery = require_Schema$1.gen(function* () {
308083
308504
  anchor_cmmd_id AS "anchorCmmdId",
308084
308505
  work_session_id AS "workSessionId",
308085
308506
  work_session_bound_at AS "workSessionBoundAt",
308507
+ wallet,
308086
308508
  linked_pull_request_json AS "linkedPullRequest",
308087
308509
  status,
308088
308510
  worker_role AS "workerRole",
@@ -308417,6 +308839,7 @@ const makeProjectionSnapshotQuery = require_Schema$1.gen(function* () {
308417
308839
  anchor_cmmd_id AS "anchorCmmdId",
308418
308840
  work_session_id AS "workSessionId",
308419
308841
  work_session_bound_at AS "workSessionBoundAt",
308842
+ wallet,
308420
308843
  linked_pull_request_json AS "linkedPullRequest",
308421
308844
  status,
308422
308845
  worker_role AS "workerRole",
@@ -308731,6 +309154,7 @@ const makeProjectionSnapshotQuery = require_Schema$1.gen(function* () {
308731
309154
  anchorCmmdId: row.anchorCmmdId,
308732
309155
  ...workSessionIdField(row.workSessionId),
308733
309156
  ...workSessionBoundAtField(row.workSessionBoundAt),
309157
+ ...walletField(row.wallet),
308734
309158
  linkedPullRequest: row.linkedPullRequest,
308735
309159
  kind: row.kind,
308736
309160
  parentThreadId: row.parentThreadId,
@@ -308982,6 +309406,7 @@ const makeProjectionSnapshotQuery = require_Schema$1.gen(function* () {
308982
309406
  anchorCmmdId: threadRow.value.anchorCmmdId,
308983
309407
  ...workSessionIdField(threadRow.value.workSessionId),
308984
309408
  ...workSessionBoundAtField(threadRow.value.workSessionBoundAt),
309409
+ ...walletField(threadRow.value.wallet),
308985
309410
  linkedPullRequest: threadRow.value.linkedPullRequest,
308986
309411
  kind: threadRow.value.kind,
308987
309412
  parentThreadId: threadRow.value.parentThreadId,