@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.
- package/dist/bin.cjs +467 -42
- package/dist/bin.mjs +491 -66
- package/dist/client/assets/{CanvasPanel-BZ55yFCm.js → CanvasPanel-56JpVM3f.js} +2 -2
- package/dist/client/assets/{DiffPanel-jTwdJQlt.js → DiffPanel-DaqlmpHv.js} +2 -2
- package/dist/client/assets/{DiffPanel.logic-DukK-hlH.js → DiffPanel.logic-CNeDuJXV.js} +2 -2
- package/dist/client/assets/{DiffWorkerPoolProvider-BxK3crqQ.js → DiffWorkerPoolProvider-7AKbLYH_.js} +2 -2
- package/dist/client/assets/{PullRequestCodePanel-D9vLGRM9.js → PullRequestCodePanel-uQGOOGFF.js} +2 -2
- package/dist/client/assets/{ThemeEditorPanel-Bgrpa0cR.js → ThemeEditorPanel-BdgROB68.js} +2 -2
- package/dist/client/assets/{Virtualizer-pdZw7YnL.js → Virtualizer-CX04hq93.js} +2 -2
- package/dist/client/assets/{WorkerPoolContext-DfkvYwPY.js → WorkerPoolContext-CWbxmZMK.js} +2 -2
- package/dist/client/assets/{cmmdAuthRedirect-B_Ad6N4c.js → cmmdAuthRedirect-Cpw3QgrC.js} +2 -2
- package/dist/client/assets/cmmdForgeRuntimeListResource-CX0wIrGL.js +1008 -0
- package/dist/client/assets/{currentForgeWorkspaceStore-B3v2VP9w.js → currentForgeWorkspaceStore-CBTn8tE8.js} +2 -2
- package/dist/client/assets/{dialog-DMVibvkf.js → dialog-BSwJ44Xn.js} +2 -2
- package/dist/client/assets/{index-z4eYDXxq.js → index-d3qvIP59.js} +104 -104
- package/dist/client/assets/{popover-DZpHoNco.js → popover-ZNCjh9sJ.js} +2 -2
- package/dist/client/assets/{scroll-area-dh4WduWB.js → scroll-area-By2Wg8Aw.js} +2 -2
- package/dist/client/assets/{sidebarV2CustomSnoozeDialog-DsUlSvAq.js → sidebarV2CustomSnoozeDialog-B_dtRwFZ.js} +2 -2
- package/dist/client/assets/src-e9jwz4Nc.js +3 -0
- package/dist/client/assets/{switch-Bt0PG_99.js → switch-opCmyrUy.js} +2 -2
- package/dist/client/assets/{themePalette-rKk-Jh5K.js → themePalette-DchQFoHe.js} +2 -2
- package/dist/client/assets/{toggle-CM3FO84q.js → toggle-CGX6qKVS.js} +2 -2
- package/dist/client/assets/{toggle-group-sUSKwOOz.js → toggle-group-BRN0oZh2.js} +2 -2
- package/dist/client/assets/{tooltip-DHkQTarv.js → tooltip-Bh_PspOm.js} +2 -2
- package/dist/client/assets/{utils-B9FLzOgF.js → utils-MX9zGa4a.js} +2 -2
- package/dist/client/index.html +18 -18
- package/dist/forge-build.json +1 -1
- package/dist/{open-2-reBrpv.mjs → open-yHTUkd2Y.mjs} +3 -3
- package/package.json +1 -1
- package/dist/client/assets/cmmdForgeRuntimeListResource-6ppYDui_.js +0 -1008
- 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
|
|
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 =
|
|
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$
|
|
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$
|
|
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.
|
|
66142
|
+
var version$1 = "0.13.136";
|
|
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$
|
|
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$
|
|
75894
|
-
var platform = process.env.npm_config_platform || os$
|
|
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-
|
|
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 >
|
|
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 (${
|
|
115852
|
+
VALUES (${80})
|
|
115817
115853
|
ON CONFLICT (version) DO NOTHING
|
|
115818
115854
|
`;
|
|
115819
|
-
} else for (let version = currentVersion + 1; version <=
|
|
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 =
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
202416
|
+
docLink: `${os$2}/iam#working-directories`
|
|
202352
202417
|
}
|
|
202353
202418
|
}
|
|
202354
202419
|
], AKe = {
|
|
202355
|
-
permissions: `${os$
|
|
202356
|
-
env: `${os$
|
|
202357
|
-
hooks: `${os$
|
|
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
|
-
|
|
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
|
-
|
|
218632
|
-
|
|
218633
|
-
|
|
218634
|
-
|
|
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) =>
|
|
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:
|
|
218642
|
-
|
|
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
|
-
|
|
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:
|
|
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, {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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 "
|
|
300143
|
+
return "5716c4b70da370f76d24ac48e65aafc1819dd6c1";
|
|
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
|
-
|
|
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-
|
|
325671
|
+
const open = (await import("./open-yHTUkd2Y.mjs")).default;
|
|
325247
325672
|
await open(url);
|
|
325248
325673
|
return true;
|
|
325249
325674
|
},
|