@cmmd-center/forge 0.10.4 → 0.10.6
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 +106 -37
- package/dist/bin.mjs +129 -60
- package/dist/client/assets/{CanvasPanel-BYsK8tAq.js → CanvasPanel-Dr4I7MnM.js} +2 -2
- package/dist/client/assets/{CompositeItem-khilqBJh.js → CompositeItem-Cj6_oAlz.js} +2 -2
- package/dist/client/assets/{DiffPanel-CrG7-Qe5.js → DiffPanel-njtnlFro.js} +3 -3
- package/dist/client/assets/{DiffPanel.logic--xX71t7M.js → DiffPanel.logic-BiWRNb4k.js} +2 -2
- package/dist/client/assets/{DiffPanelShell-CSeG4SSQ.js → DiffPanelShell-AKUK0L-g.js} +33 -33
- package/dist/client/assets/{DiffWorkerPoolProvider-C1s-wxqS.js → DiffWorkerPoolProvider-DWrja16U.js} +51 -51
- package/dist/client/assets/PullRequestCodePanel-CAaq9dk8.js +5 -0
- package/dist/client/assets/{Virtualizer-BaEpKPBi.js → Virtualizer-BXpiamky.js} +2 -2
- package/dist/client/assets/{canvasStateStore-CVTcDwc2.js → canvasStateStore-DncdOQ4J.js} +2 -2
- package/dist/client/assets/{cmmdAuthRedirect-B6WFFIw6.js → cmmdAuthRedirect-DWiMDVzN.js} +2 -2
- package/dist/client/assets/index-DBIIL0ML.js +151 -0
- package/dist/client/assets/index-T36rURmx.css +1 -0
- package/dist/client/assets/src-CtyKlVph.js +3 -0
- package/dist/client/assets/{toggle-DnYrc2U3.js → toggle-pTm2fPLg.js} +2 -2
- package/dist/client/assets/{useTriggerFocusGuards-CVcUEajo.js → useTriggerFocusGuards-B4Ejoaox.js} +2 -2
- package/dist/client/index.html +11 -11
- package/dist/forge-build.json +1 -1
- package/dist/{open-FIgTDosf.mjs → open-D8mGyWmt.mjs} +3 -3
- package/package.json +1 -1
- package/dist/client/assets/PullRequestCodePanel-CDmYMNEt.js +0 -5
- package/dist/client/assets/index-DB-C-45R.css +0 -1
- package/dist/client/assets/index-zQmFiQS7.js +0 -151
- package/dist/client/assets/src-BSCF6BY3.js +0 -3
package/dist/bin.mjs
CHANGED
|
@@ -22,7 +22,7 @@ import { createCipheriv, createDecipheriv, createHash, createHmac, createPublicK
|
|
|
22
22
|
import * as FS$1 from "node:fs";
|
|
23
23
|
import fs, { accessSync, chmodSync, constants, createReadStream, existsSync, mkdirSync, mkdtempSync, promises, readFile, readFileSync, readdir, readdirSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
24
24
|
import * as NodeOS from "node:os";
|
|
25
|
-
import
|
|
25
|
+
import $U, { homedir, networkInterfaces, tmpdir } from "node:os";
|
|
26
26
|
import * as Path$1 from "node:path";
|
|
27
27
|
import path, { basename, delimiter, dirname, extname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
|
|
28
28
|
import { pathToFileURL } from "node:url";
|
|
@@ -16520,7 +16520,7 @@ function makeNetServiceShape(createServer = Net.createServer) {
|
|
|
16520
16520
|
}
|
|
16521
16521
|
//#endregion
|
|
16522
16522
|
//#region ../../packages/shared/src/releaseInfo.generated.ts
|
|
16523
|
-
const FORGE_RELEASE_VERSION = "0.10.
|
|
16523
|
+
const FORGE_RELEASE_VERSION = "0.10.4";
|
|
16524
16524
|
//#endregion
|
|
16525
16525
|
//#region ../../packages/shared/src/hostProcess.ts
|
|
16526
16526
|
/**
|
|
@@ -18157,6 +18157,7 @@ const ExecutionEnvironmentDescriptor = Struct({
|
|
|
18157
18157
|
platform: ExecutionEnvironmentPlatform,
|
|
18158
18158
|
serverVersion: TrimmedNonEmptyString,
|
|
18159
18159
|
buildCommit: optional$4(TrimmedNonEmptyString),
|
|
18160
|
+
deviceRuntimeId: optional$4(TrimmedNonEmptyString),
|
|
18160
18161
|
capabilities: ExecutionEnvironmentCapabilities
|
|
18161
18162
|
});
|
|
18162
18163
|
Literals([
|
|
@@ -21906,6 +21907,7 @@ const DEFAULT_CLIENT_SETTINGS = decodeSync(Struct({
|
|
|
21906
21907
|
confirmThreadArchive: Boolean$1.pipe(withDecodingDefault(succeed(true))),
|
|
21907
21908
|
confirmThreadDelete: Boolean$1.pipe(withDecodingDefault(succeed(true))),
|
|
21908
21909
|
showInteractionModeToggle: Boolean$1.pipe(withDecodingDefault(succeed(false))),
|
|
21910
|
+
composerCollapseOnBlur: Boolean$1.pipe(withDecodingDefault(succeed(true))),
|
|
21909
21911
|
diffWordWrap: Boolean$1.pipe(withDecodingDefault(succeed(true))),
|
|
21910
21912
|
previewAutoOpen: Boolean$1.pipe(withDecodingDefault(succeed(false))),
|
|
21911
21913
|
previewRememberLastUrl: Boolean$1.pipe(withDecodingDefault(succeed(true))),
|
|
@@ -49730,7 +49732,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
49730
49732
|
const min = forceColor || 0;
|
|
49731
49733
|
if (env.TERM === "dumb") return min;
|
|
49732
49734
|
if (process$1.platform === "win32") {
|
|
49733
|
-
const osRelease =
|
|
49735
|
+
const osRelease = $U.release().split(".");
|
|
49734
49736
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
49735
49737
|
return 1;
|
|
49736
49738
|
}
|
|
@@ -52173,7 +52175,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
52173
52175
|
exports.processDetector = void 0;
|
|
52174
52176
|
const api_1 = (init_esm$1(), __toCommonJS(esm_exports$1));
|
|
52175
52177
|
const semconv_1 = require_semconv$1();
|
|
52176
|
-
const os$
|
|
52178
|
+
const os$3 = __require("os");
|
|
52177
52179
|
/**
|
|
52178
52180
|
* ProcessDetector will be used to detect the resources related current process running
|
|
52179
52181
|
* and being instrumented from the NodeJS Process module.
|
|
@@ -52195,7 +52197,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
52195
52197
|
};
|
|
52196
52198
|
if (process.argv.length > 1) attributes[semconv_1.ATTR_PROCESS_COMMAND] = process.argv[1];
|
|
52197
52199
|
try {
|
|
52198
|
-
const userInfo = os$
|
|
52200
|
+
const userInfo = os$3.userInfo();
|
|
52199
52201
|
attributes[semconv_1.ATTR_PROCESS_OWNER] = userInfo.username;
|
|
52200
52202
|
} catch (e) {
|
|
52201
52203
|
api_1.diag.debug(`error obtaining process owner: ${e}`);
|
|
@@ -65118,7 +65120,7 @@ function normalizeNumberish(value) {
|
|
|
65118
65120
|
}
|
|
65119
65121
|
//#endregion
|
|
65120
65122
|
//#region package.json
|
|
65121
|
-
var version$1 = "0.10.
|
|
65123
|
+
var version$1 = "0.10.6";
|
|
65122
65124
|
//#endregion
|
|
65123
65125
|
//#region src/sentry.ts
|
|
65124
65126
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -67886,6 +67888,15 @@ function parsePersistedServerObservabilitySettings(raw) {
|
|
|
67886
67888
|
* @module ServerConfig
|
|
67887
67889
|
*/
|
|
67888
67890
|
const DEFAULT_PORT = 13773;
|
|
67891
|
+
/**
|
|
67892
|
+
* Where a managed cloud runtime keeps the user's checkouts when
|
|
67893
|
+
* FORGE_CLOUD_PROJECTS_ROOT is not set. CMMD seeds every sprite checkout under
|
|
67894
|
+
* /projects (forge-guest-layout.ts on the CMMD side) and passes that value in
|
|
67895
|
+
* the Service env, so this default only matters for a server started without
|
|
67896
|
+
* it. It used to be a path under the Fly-era mounted volume; on a sprite the
|
|
67897
|
+
* two repos disagreed and every local-checkout turn was refused (FOR-36484).
|
|
67898
|
+
*/
|
|
67899
|
+
const DEFAULT_CLOUD_PROJECTS_ROOT = "/projects";
|
|
67889
67900
|
const RuntimeMode = Literals(["web", "desktop"]);
|
|
67890
67901
|
Literals(["browser", "headless"]);
|
|
67891
67902
|
const deriveServerPaths = fn$1(function* (baseDir, _devUrl, _mode) {
|
|
@@ -68011,7 +68022,7 @@ var ServerConfig = class ServerConfig extends Service$1()("forge/config/ServerCo
|
|
|
68011
68022
|
forgeCodexHomePath: void 0,
|
|
68012
68023
|
forgeClaudeConfigPath: void 0,
|
|
68013
68024
|
forgeApexBaseUrl: void 0,
|
|
68014
|
-
cloudProjectsRoot:
|
|
68025
|
+
cloudProjectsRoot: DEFAULT_CLOUD_PROJECTS_ROOT,
|
|
68015
68026
|
...overrides
|
|
68016
68027
|
};
|
|
68017
68028
|
}));
|
|
@@ -73756,7 +73767,7 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
73756
73767
|
var fs$6 = __require("fs");
|
|
73757
73768
|
var path$5 = __require("path");
|
|
73758
73769
|
var url$1 = __require("url");
|
|
73759
|
-
var os$
|
|
73770
|
+
var os$2 = __require("os");
|
|
73760
73771
|
var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
73761
73772
|
var vars = process.config && process.config.variables || {};
|
|
73762
73773
|
var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
|
|
@@ -73764,8 +73775,8 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
73764
73775
|
var abi = versions.modules;
|
|
73765
73776
|
if (versions.deno || process.isBun) abi = "unsupported";
|
|
73766
73777
|
var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
|
|
73767
|
-
var arch = process.env.npm_config_arch || os$
|
|
73768
|
-
var platform = process.env.npm_config_platform || os$
|
|
73778
|
+
var arch = process.env.npm_config_arch || os$2.arch();
|
|
73779
|
+
var platform = process.env.npm_config_platform || os$2.platform();
|
|
73769
73780
|
var libc = process.env.LIBC || (isMusl(platform) ? "musl" : "glibc");
|
|
73770
73781
|
var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || "";
|
|
73771
73782
|
var uv = (versions.uv || "").split(".")[0];
|
|
@@ -91423,7 +91434,7 @@ const launchDetached = (launch) => gen(function* () {
|
|
|
91423
91434
|
});
|
|
91424
91435
|
const OpenLive = effect(Open, gen(function* () {
|
|
91425
91436
|
const open = yield* tryPromise({
|
|
91426
|
-
try: () => import("./open-
|
|
91437
|
+
try: () => import("./open-D8mGyWmt.mjs"),
|
|
91427
91438
|
catch: (cause) => new OpenError$1({
|
|
91428
91439
|
message: "failed to load browser opener",
|
|
91429
91440
|
cause
|
|
@@ -97136,7 +97147,7 @@ const resolveAutoBootstrapWelcomeTargets = gen(function* () {
|
|
|
97136
97147
|
/**
|
|
97137
97148
|
* Cloud-mode project recovery — runs only on cloud execution runtimes.
|
|
97138
97149
|
* Scans `cloudProjectsRoot` (default
|
|
97139
|
-
* /
|
|
97150
|
+
* /projects) for git-repo subdirectories and registers any not yet in
|
|
97140
97151
|
* the orchestration engine. This is the cloud-mode replacement for the
|
|
97141
97152
|
* gated `autoBootstrapProjectFromCwd` path: managed runtimes whose volume
|
|
97142
97153
|
* already holds cloned repos surface them in the sidebar after restart.
|
|
@@ -149395,13 +149406,40 @@ var CodexAppServerManager = class extends EventEmitter$1 {
|
|
|
149395
149406
|
if (!providerConversationId) return;
|
|
149396
149407
|
return context.collabReceiverTurns.get(providerConversationId);
|
|
149397
149408
|
}
|
|
149409
|
+
/**
|
|
149410
|
+
* The child threads one thread item says the turn spawned.
|
|
149411
|
+
*
|
|
149412
|
+
* Two item shapes name a child, and which one arrives depends on the Codex
|
|
149413
|
+
* build. `CollabAgentToolCallThreadItem` lists `receiverThreadIds`, which
|
|
149414
|
+
* "in case of spawn operation ... corresponds to the newly spawned agent".
|
|
149415
|
+
* `SubAgentActivityThreadItem` names a single `agentThreadId` and is what a
|
|
149416
|
+
* `spawn_agent` call reports on codex-cli 0.152/0.153: measured on the
|
|
149417
|
+
* packaged desktop on 2026-09-06, the spawn arrived as `SubAgentActivity`
|
|
149418
|
+
* (`kind: started`) and the only collab tool call that followed was the
|
|
149419
|
+
* `wait`, whose `receiverThreadIds` was empty. Reading only the collab item
|
|
149420
|
+
* left the child unmapped, so its spend was published as a second turn row
|
|
149421
|
+
* under the child's own turn id instead of a subagent row under the parent's.
|
|
149422
|
+
*
|
|
149423
|
+
* `SubAgentActivityThreadItem` has no `model` field, so a `completed` report
|
|
149424
|
+
* for a child a collab call already named must not blank the model out; the
|
|
149425
|
+
* caller's `model ?? known` merge is what keeps it.
|
|
149426
|
+
*/
|
|
149427
|
+
readSpawnedThreadIds(item, itemType) {
|
|
149428
|
+
if (itemType === "subAgentActivity") {
|
|
149429
|
+
const agentThreadId = this.readString(item, "agentThreadId");
|
|
149430
|
+
return agentThreadId ? [agentThreadId] : [];
|
|
149431
|
+
}
|
|
149432
|
+
if (itemType !== "collabAgentToolCall") return [];
|
|
149433
|
+
return this.readArray(item, "receiverThreadIds")?.map((value) => typeof value === "string" ? value : null).filter((value) => value !== null) ?? [];
|
|
149434
|
+
}
|
|
149398
149435
|
rememberCollabReceiverTurns(context, params, parentTurnId) {
|
|
149399
149436
|
if (!parentTurnId) return;
|
|
149400
149437
|
const payload = this.readObject(params);
|
|
149401
149438
|
const item = this.readObject(payload, "item") ?? payload;
|
|
149402
|
-
|
|
149439
|
+
const itemType = this.readString(item, "type") ?? this.readString(item, "kind");
|
|
149440
|
+
const receiverThreadIds = this.readSpawnedThreadIds(item, itemType);
|
|
149441
|
+
if (receiverThreadIds.length === 0) return;
|
|
149403
149442
|
const model = this.readString(item, "model");
|
|
149404
|
-
const receiverThreadIds = this.readArray(item, "receiverThreadIds")?.map((value) => typeof value === "string" ? value : null).filter((value) => value !== null) ?? [];
|
|
149405
149443
|
for (const receiverThreadId of receiverThreadIds) {
|
|
149406
149444
|
const known = context.collabReceiverTurns.get(receiverThreadId)?.model;
|
|
149407
149445
|
const resolved = model ?? known;
|
|
@@ -149417,8 +149455,8 @@ var CodexAppServerManager = class extends EventEmitter$1 {
|
|
|
149417
149455
|
* Codex reports a child thread's tokens on the parent's own connection:
|
|
149418
149456
|
* `ThreadTokenUsageUpdatedNotification` requires `threadId` and `turnId` and
|
|
149419
149457
|
* names the child thread for a child, and `Thread.parentThreadId` is "only
|
|
149420
|
-
* set if this thread is a subagent" (codex 0.
|
|
149421
|
-
* schema). Every other child notification is suppressed so it cannot replace
|
|
149458
|
+
* set if this thread is a subagent" (still true of the codex-cli 0.153
|
|
149459
|
+
* app-server protocol schema). Every other child notification is suppressed so it cannot replace
|
|
149422
149460
|
* the parent turn; this one is not, because the tokens belong on the ledger.
|
|
149423
149461
|
* The method is Forge's own rather than the protocol's, because the payload
|
|
149424
149462
|
* carries what the Usage row needs rather than what the notification held.
|
|
@@ -187273,7 +187311,7 @@ var Vce = {
|
|
|
187273
187311
|
function Ve() {
|
|
187274
187312
|
return Vce;
|
|
187275
187313
|
}
|
|
187276
|
-
var Us =
|
|
187314
|
+
var Us = $U.homedir(), lk = $U.tmpdir(), { env: Vc } = process$1, Yce = (e) => {
|
|
187277
187315
|
let t = path.join(Us, "Library");
|
|
187278
187316
|
return {
|
|
187279
187317
|
data: path.join(t, "Application Support", e),
|
|
@@ -197473,12 +197511,12 @@ function qZ(e, t) {
|
|
|
197473
197511
|
}
|
|
197474
197512
|
return n;
|
|
197475
197513
|
}
|
|
197476
|
-
var os$
|
|
197514
|
+
var os$1 = "https://code.claude.com/docs/en", kKe = [
|
|
197477
197515
|
{
|
|
197478
197516
|
matches: (e) => e.path === "permissions.defaultMode" && e.code === "invalid_value",
|
|
197479
197517
|
tip: {
|
|
197480
197518
|
suggestion: "Valid modes: \"acceptEdits\" (ask before file changes), \"plan\" (analysis only), \"bypassPermissions\" (auto-accept all), or \"default\" (standard behavior)",
|
|
197481
|
-
docLink: `${os$
|
|
197519
|
+
docLink: `${os$1}/iam#permission-modes`
|
|
197482
197520
|
}
|
|
197483
197521
|
},
|
|
197484
197522
|
{
|
|
@@ -197493,7 +197531,7 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
197493
197531
|
matches: (e) => e.path.startsWith("env.") && e.code === "invalid_type",
|
|
197494
197532
|
tip: {
|
|
197495
197533
|
suggestion: "Environment variables must be strings. Wrap numbers and booleans in quotes. Example: \"DEBUG\": \"true\", \"PORT\": \"3000\"",
|
|
197496
|
-
docLink: `${os$
|
|
197534
|
+
docLink: `${os$1}/settings#environment-variables`
|
|
197497
197535
|
}
|
|
197498
197536
|
},
|
|
197499
197537
|
{
|
|
@@ -197504,14 +197542,14 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
197504
197542
|
matches: (e) => e.path.startsWith("hooks.") && e.code === "invalid_key",
|
|
197505
197543
|
tip: {
|
|
197506
197544
|
suggestion: "Not a recognized hook event. Common events: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, SessionEnd, Stop. Check spelling and capitalization.",
|
|
197507
|
-
docLink: `${os$
|
|
197545
|
+
docLink: `${os$1}/hooks`
|
|
197508
197546
|
}
|
|
197509
197547
|
},
|
|
197510
197548
|
{
|
|
197511
197549
|
matches: (e) => /\.hooks\.\d+\.command$/.test(e.path) && e.code === "invalid_type" && e.received === "undefined",
|
|
197512
197550
|
tip: {
|
|
197513
197551
|
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\"}.",
|
|
197514
|
-
docLink: `${os$
|
|
197552
|
+
docLink: `${os$1}/hooks#exec-form-and-shell-form`
|
|
197515
197553
|
}
|
|
197516
197554
|
},
|
|
197517
197555
|
{
|
|
@@ -197526,7 +197564,7 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
197526
197564
|
matches: (e) => e.code === "unrecognized_keys",
|
|
197527
197565
|
tip: {
|
|
197528
197566
|
suggestion: "Check for typos or refer to the documentation for valid fields",
|
|
197529
|
-
docLink: `${os$
|
|
197567
|
+
docLink: `${os$1}/settings`
|
|
197530
197568
|
}
|
|
197531
197569
|
},
|
|
197532
197570
|
{
|
|
@@ -197541,13 +197579,13 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
197541
197579
|
matches: (e) => e.path === "permissions.additionalDirectories" && e.code === "invalid_type",
|
|
197542
197580
|
tip: {
|
|
197543
197581
|
suggestion: "Must be an array of directory paths. Example: [\"~/projects\", \"/tmp/workspace\"]. You can also use --add-dir flag or /add-dir command",
|
|
197544
|
-
docLink: `${os$
|
|
197582
|
+
docLink: `${os$1}/iam#working-directories`
|
|
197545
197583
|
}
|
|
197546
197584
|
}
|
|
197547
197585
|
], AKe = {
|
|
197548
|
-
permissions: `${os$
|
|
197549
|
-
env: `${os$
|
|
197550
|
-
hooks: `${os$
|
|
197586
|
+
permissions: `${os$1}/iam#configuring-permissions`,
|
|
197587
|
+
env: `${os$1}/settings#environment-variables`,
|
|
197588
|
+
hooks: `${os$1}/hooks`
|
|
197551
197589
|
};
|
|
197552
197590
|
function GZ(e) {
|
|
197553
197591
|
let t = kKe.find((r) => r.matches(e));
|
|
@@ -207214,11 +207252,14 @@ function mapCodexThreadTokenUsageEvent(event, canonicalThreadId, payload) {
|
|
|
207214
207252
|
*
|
|
207215
207253
|
* The source is the live app-server protocol, not a rollout read: Codex sends
|
|
207216
207254
|
* `thread/tokenUsage/updated` for a child thread on the parent's own
|
|
207217
|
-
* connection (
|
|
207218
|
-
* `
|
|
207219
|
-
*
|
|
207220
|
-
*
|
|
207221
|
-
*
|
|
207255
|
+
* connection (`ThreadTokenUsageUpdatedNotification` requires `threadId` and
|
|
207256
|
+
* `turnId`, and `Thread.parentThreadId` is set only for a subagent), and
|
|
207257
|
+
* `codexAppServerManager` already tracked those child threads to route their
|
|
207258
|
+
* notifications onto the parent turn. It learns a child from whichever item
|
|
207259
|
+
* the running Codex build uses to announce a spawn: the
|
|
207260
|
+
* `receiverThreadIds` of a `CollabAgentToolCallThreadItem`, which also names
|
|
207261
|
+
* the spawned agent's `model`, or the `agentThreadId` of a
|
|
207262
|
+
* `SubAgentActivityThreadItem`, which names no model.
|
|
207222
207263
|
*
|
|
207223
207264
|
* The row carries no context-meter snapshot and no `turnUsage`: the parent's
|
|
207224
207265
|
* own row is never re-summed with its children. It carries the call's delta
|
|
@@ -208100,7 +208141,8 @@ const CODE_BY_UPSTREAM_REASON$1 = {
|
|
|
208100
208141
|
credential_expired_refreshing: "CREDENTIAL_EXPIRED_REFRESHING",
|
|
208101
208142
|
credential_reconnect_required: "CREDENTIAL_RECONNECT_REQUIRED",
|
|
208102
208143
|
credential_not_connected: "CREDENTIAL_RECONNECT_REQUIRED",
|
|
208103
|
-
credential_generation_not_applied: "CREDENTIAL_GENERATION_NOT_APPLIED"
|
|
208144
|
+
credential_generation_not_applied: "CREDENTIAL_GENERATION_NOT_APPLIED",
|
|
208145
|
+
runtime_unavailable: "RUNTIME_UNAVAILABLE"
|
|
208104
208146
|
};
|
|
208105
208147
|
const CLAUDE_NATIVE_CREDENTIAL_UNUSABLE_COPY = "The delivered Claude credential is unavailable or unusable in this runtime.";
|
|
208106
208148
|
/**
|
|
@@ -208163,10 +208205,17 @@ function claudeNativeCredentialUnusableMessage() {
|
|
|
208163
208205
|
* CMMD writes this marker when it activates a personal Claude subscription
|
|
208164
208206
|
* inside a running sprite. Activation always happens after boot, so a
|
|
208165
208207
|
* boot-time env var alone cannot reflect it (FOR-36249).
|
|
208208
|
+
*
|
|
208209
|
+
* CMMD names the file in the Service env (FORGE_PERSONAL_CLAUDE_MARKER_PATH).
|
|
208210
|
+
* Without that, the marker sits directly under FORGE_HOME, which is the same
|
|
208211
|
+
* guest home CMMD derives every sprite path from. A server with neither has no
|
|
208212
|
+
* sprite home to look in, and a desktop never has a marker, so it reads none.
|
|
208166
208213
|
*/
|
|
208167
|
-
const
|
|
208214
|
+
const PERSONAL_CLAUDE_IN_VM_MARKER_NAME = ".forge-personal-claude-in-vm";
|
|
208168
208215
|
function markerPath(env) {
|
|
208169
|
-
|
|
208216
|
+
if (env.FORGE_PERSONAL_CLAUDE_MARKER_PATH) return env.FORGE_PERSONAL_CLAUDE_MARKER_PATH;
|
|
208217
|
+
if (env.FORGE_HOME) return join(env.FORGE_HOME, PERSONAL_CLAUDE_IN_VM_MARKER_NAME);
|
|
208218
|
+
return null;
|
|
208170
208219
|
}
|
|
208171
208220
|
/**
|
|
208172
208221
|
* True when this runtime should offer the personal Claude subscription lane.
|
|
@@ -208179,8 +208228,10 @@ function markerPath(env) {
|
|
|
208179
208228
|
*/
|
|
208180
208229
|
function personalClaudeInVmEnabled(env = process.env) {
|
|
208181
208230
|
if (env.FORGE_PERSONAL_CLAUDE_IN_VM === "true") return true;
|
|
208231
|
+
const marker = markerPath(env);
|
|
208232
|
+
if (!marker) return false;
|
|
208182
208233
|
try {
|
|
208183
|
-
return existsSync(
|
|
208234
|
+
return existsSync(marker);
|
|
208184
208235
|
} catch {
|
|
208185
208236
|
return false;
|
|
208186
208237
|
}
|
|
@@ -226760,7 +226811,8 @@ const CLAUDE_READINESS_COPY = {
|
|
|
226760
226811
|
failed: "Claude native runtime setup could not be applied. Reconnect Claude in Settings.",
|
|
226761
226812
|
invalid: "Claude native runtime readiness is no longer valid. Reconnect Claude in Settings.",
|
|
226762
226813
|
unavailable: "Claude native runtime readiness could not be verified.",
|
|
226763
|
-
generationMismatch: "Claude native runtime generation does not match CMMD readiness."
|
|
226814
|
+
generationMismatch: "Claude native runtime generation does not match CMMD readiness.",
|
|
226815
|
+
environmentUnavailable: "This Environment is not running, so Claude cannot run on it. Restart the Environment, then try again."
|
|
226764
226816
|
};
|
|
226765
226817
|
var ClaudeRuntimeReadinessError = class extends Error {
|
|
226766
226818
|
constructor(safeIssue, retryable = false, retryProfile = "default") {
|
|
@@ -226830,6 +226882,7 @@ async function withReadinessRetry(attempt) {
|
|
|
226830
226882
|
*/
|
|
226831
226883
|
function readinessReasonIssue(readiness) {
|
|
226832
226884
|
const code = claudeReadinessReasonCode(readiness.reason);
|
|
226885
|
+
if (code === "RUNTIME_UNAVAILABLE") return CLAUDE_READINESS_COPY.environmentUnavailable;
|
|
226833
226886
|
if (code === "CREDENTIAL_RECONNECT_REQUIRED") return CLAUDE_READINESS_COPY.invalid;
|
|
226834
226887
|
if (code === "CREDENTIAL_GENERATION_NOT_APPLIED") return CLAUDE_READINESS_COPY.applying;
|
|
226835
226888
|
if (code !== "CREDENTIAL_EXPIRED_REFRESHING") return null;
|
|
@@ -226840,6 +226893,10 @@ function readinessReasonIssue(readiness) {
|
|
|
226840
226893
|
function isCredentialRefreshInFlight(readiness) {
|
|
226841
226894
|
return claudeReadinessReasonCode(readiness.reason) === "CREDENTIAL_EXPIRED_REFRESHING";
|
|
226842
226895
|
}
|
|
226896
|
+
/** True when CMMD says the runtime itself cannot take a delivery (CMMD-36473). */
|
|
226897
|
+
function isRuntimeUnavailable(readiness) {
|
|
226898
|
+
return claudeReadinessReasonCode(readiness.reason) === "RUNTIME_UNAVAILABLE";
|
|
226899
|
+
}
|
|
226843
226900
|
function readinessFailureIssue(readiness) {
|
|
226844
226901
|
const reasonIssue = readinessReasonIssue(readiness);
|
|
226845
226902
|
if (reasonIssue !== null) return reasonIssue;
|
|
@@ -226879,11 +226936,12 @@ function verifiedClaudeDeliveryBinding(readiness, authority) {
|
|
|
226879
226936
|
function appliedClaudeGeneration(readiness) {
|
|
226880
226937
|
if (readiness.connected !== true || readiness.deliveryStatus !== "applied" || readiness.nativeExecutable !== true || typeof readiness.generationId !== "string" || readiness.generationId.trim().length === 0) {
|
|
226881
226938
|
const refreshing = isCredentialRefreshInFlight(readiness);
|
|
226882
|
-
|
|
226939
|
+
const retryable = !isRuntimeUnavailable(readiness) && (refreshing || [
|
|
226883
226940
|
"pending",
|
|
226884
226941
|
"claimed",
|
|
226885
226942
|
"activating"
|
|
226886
|
-
].includes(readiness.deliveryStatus)
|
|
226943
|
+
].includes(readiness.deliveryStatus));
|
|
226944
|
+
throw new ClaudeRuntimeReadinessError(readinessFailureIssue(readiness), retryable, refreshing ? "credentialRefresh" : "default");
|
|
226887
226945
|
}
|
|
226888
226946
|
return readiness.generationId;
|
|
226889
226947
|
}
|
|
@@ -228037,15 +228095,15 @@ const collectOutput = fn$1("collectOutput")(function* (input, stream, maxOutputB
|
|
|
228037
228095
|
/**
|
|
228038
228096
|
* Adds a `safe.directory` exception to a git child environment.
|
|
228039
228097
|
*
|
|
228040
|
-
* Forge runs git against workspaces on a mounted volume (
|
|
228041
|
-
* Fly). A volume mount replaces the build-time ownership of its mountpoint, so a
|
|
228098
|
+
* Forge runs git against workspaces on a mounted volume (`<cloudProjectsRoot>/...`
|
|
228099
|
+
* on Fly). A volume mount replaces the build-time ownership of its mountpoint, so a
|
|
228042
228100
|
* repository there can be owned by a uid other than the server's, and git then
|
|
228043
228101
|
* refuses EVERY command against it with "detected dubious ownership" — the
|
|
228044
228102
|
* FORGE-2T failure in `CheckpointStore.captureCheckpoint`.
|
|
228045
228103
|
*
|
|
228046
228104
|
* The exception has to be `*`, verified against git 2.43:
|
|
228047
228105
|
* - git compares `safe.directory` entries literally, so a prefix such as
|
|
228048
|
-
* `/
|
|
228106
|
+
* `/projects/*` does not match the repository at all.
|
|
228049
228107
|
* - the value must name the DISCOVERED REPOSITORY ROOT, which is an ancestor of
|
|
228050
228108
|
* `cwd` whenever a command runs from a subdirectory. Resolving that root means
|
|
228051
228109
|
* asking git, which is the command being refused.
|
|
@@ -262514,7 +262572,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
262514
262572
|
var dgram = __require("dgram");
|
|
262515
262573
|
var thunky = require_thunky();
|
|
262516
262574
|
var events = __require("events");
|
|
262517
|
-
var os
|
|
262575
|
+
var os = __require("os");
|
|
262518
262576
|
var noop = function() {};
|
|
262519
262577
|
module.exports = function(opts) {
|
|
262520
262578
|
if (!opts) opts = {};
|
|
@@ -262645,14 +262703,14 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
262645
262703
|
return that;
|
|
262646
262704
|
};
|
|
262647
262705
|
function defaultInterface() {
|
|
262648
|
-
var networks = os
|
|
262706
|
+
var networks = os.networkInterfaces();
|
|
262649
262707
|
var names = Object.keys(networks);
|
|
262650
262708
|
for (var i = 0; i < names.length; i++) {
|
|
262651
262709
|
var net = networks[names[i]];
|
|
262652
262710
|
for (var j = 0; j < net.length; j++) {
|
|
262653
262711
|
var iface = net[j];
|
|
262654
262712
|
if (isIPv4(iface.family) && !iface.internal) {
|
|
262655
|
-
if (os
|
|
262713
|
+
if (os.platform() === "darwin" && names[i] === "en0") return iface.address;
|
|
262656
262714
|
return "0.0.0.0";
|
|
262657
262715
|
}
|
|
262658
262716
|
}
|
|
@@ -262660,7 +262718,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
262660
262718
|
return "127.0.0.1";
|
|
262661
262719
|
}
|
|
262662
262720
|
function allInterfaces() {
|
|
262663
|
-
var networks = os
|
|
262721
|
+
var networks = os.networkInterfaces();
|
|
262664
262722
|
var names = Object.keys(networks);
|
|
262665
262723
|
var res = [];
|
|
262666
262724
|
for (var i = 0; i < names.length; i++) {
|
|
@@ -290889,7 +290947,7 @@ const ServerLoggerLive = gen(function* () {
|
|
|
290889
290947
|
* Observed live on a Forge Cloud sprite (2026-07-25): the browser opens
|
|
290890
290948
|
* `wss://<sprite>.sprites.app/ws?routeKey=…&runtimeTicket=<JWT>`, and the HTTP
|
|
290891
290949
|
* instrumentation records `url.full` / `url.query` verbatim. The ticket then
|
|
290892
|
-
* lands in
|
|
290950
|
+
* lands in `<FORGE_HOME>/userdata/logs/server.trace.ndjson` at mode 644 — readable by
|
|
290893
290951
|
* the same user the agent runs as — and the URL also crosses fly.io's edge,
|
|
290894
290952
|
* where infrastructure we do not control may log it.
|
|
290895
290953
|
*
|
|
@@ -291181,7 +291239,7 @@ function resolveBuildCommitFromEnv(env) {
|
|
|
291181
291239
|
* environment descriptor down instead of reporting an honest "unknown".
|
|
291182
291240
|
*/
|
|
291183
291241
|
function readBakedBuildCommit() {
|
|
291184
|
-
return "
|
|
291242
|
+
return "5f0060a9696edd41f61f06cbf24450a5994fed33";
|
|
291185
291243
|
}
|
|
291186
291244
|
async function resolveServerBuildCommit(input) {
|
|
291187
291245
|
if (isFullCommitSha(input.baked)) return input.baked;
|
|
@@ -291270,6 +291328,25 @@ function runtimeTopology(serverConfig) {
|
|
|
291270
291328
|
if (serverConfig.mode === "desktop") return "desktop-local";
|
|
291271
291329
|
return "local-web";
|
|
291272
291330
|
}
|
|
291331
|
+
/**
|
|
291332
|
+
* The CMMD device runtime id to publish on this server's descriptor.
|
|
291333
|
+
*
|
|
291334
|
+
* A client cannot work this out for itself. Its only other source is page
|
|
291335
|
+
* storage, which holds this machine's id when the page runs inside the desktop
|
|
291336
|
+
* shell and a freshly minted browser id otherwise, so opening the same local
|
|
291337
|
+
* server at `127.0.0.1` in Safari made the desktop look like a remote runtime
|
|
291338
|
+
* (FOR-36439). The server was told the id at boot, so the server says it.
|
|
291339
|
+
*
|
|
291340
|
+
* The cloud shell is excluded on purpose. It is a control plane, not an
|
|
291341
|
+
* execution runtime, and its own provider list is empty; publishing a runtime
|
|
291342
|
+
* id there would let the SPA resolve some target as "the server I am talking
|
|
291343
|
+
* to" and read models off a surface that runs nothing. Everything else with no
|
|
291344
|
+
* registration (dev checkouts, plain `forge serve`) already answers undefined.
|
|
291345
|
+
*/
|
|
291346
|
+
function resolveDescriptorDeviceRuntimeId(config) {
|
|
291347
|
+
if (config.forgeCloudShellMode === true) return void 0;
|
|
291348
|
+
return resolveRuntimeReplicationRuntimeId(config);
|
|
291349
|
+
}
|
|
291273
291350
|
function executionEnvironmentCapabilities(serverConfig) {
|
|
291274
291351
|
const isCloudShell = serverConfig.forgeCloudShellMode === true;
|
|
291275
291352
|
const isRuntime = serverConfig.forgeCmmdRuntimeMode === true && !isCloudShell;
|
|
@@ -291343,6 +291420,7 @@ const ServerEnvironmentLive = effect(ServerEnvironment, fn$1("makeServerEnvironm
|
|
|
291343
291420
|
env: process.env,
|
|
291344
291421
|
readGitCommit: resolveForgeGitCommit
|
|
291345
291422
|
}));
|
|
291423
|
+
const deviceRuntimeId = resolveDescriptorDeviceRuntimeId(serverConfig);
|
|
291346
291424
|
const buildDescriptor = gen(function* () {
|
|
291347
291425
|
const displayNameOverride = yield* get$5(displayNameOverrideRef);
|
|
291348
291426
|
const os = platformOs();
|
|
@@ -291355,6 +291433,7 @@ const ServerEnvironmentLive = effect(ServerEnvironment, fn$1("makeServerEnvironm
|
|
|
291355
291433
|
},
|
|
291356
291434
|
serverVersion: version$1,
|
|
291357
291435
|
...buildCommit !== void 0 ? { buildCommit } : {},
|
|
291436
|
+
...deviceRuntimeId !== void 0 ? { deviceRuntimeId } : {},
|
|
291358
291437
|
capabilities: {
|
|
291359
291438
|
...executionEnvironmentCapabilities(serverConfig),
|
|
291360
291439
|
posthogPublicKey: posthog.posthogPublicKey,
|
|
@@ -299149,16 +299228,6 @@ function describeDispatchCause(cause) {
|
|
|
299149
299228
|
if (deepest === void 0 || deepest.length <= DISPATCH_CAUSE_DETAIL_LIMIT) return deepest;
|
|
299150
299229
|
return `${deepest.slice(0, DISPATCH_CAUSE_DETAIL_LIMIT)}...`;
|
|
299151
299230
|
}
|
|
299152
|
-
/**
|
|
299153
|
-
* Where automation-created projects live when the caller does not say.
|
|
299154
|
-
*
|
|
299155
|
-
* This is the documented default of the `cloudProjectsRoot` setting
|
|
299156
|
-
* (FORGE_CLOUD_PROJECTS_ROOT, see cli.ts) and exists only for direct callers
|
|
299157
|
-
* such as tests. Every HTTP route passes the CONFIGURED value instead: reading
|
|
299158
|
-
* the default here is what made a runtime configured with any other root create
|
|
299159
|
-
* its automation projects in a directory nothing else read.
|
|
299160
|
-
*/
|
|
299161
|
-
const DEFAULT_CLOUD_PROJECTS_ROOT = "/data/Projects";
|
|
299162
299231
|
const respondToOrchestrationHttpError = (error) => gen(function* () {
|
|
299163
299232
|
if (error._tag === "OrchestrationGetSnapshotError") {
|
|
299164
299233
|
yield* logError("orchestration http route failed", {
|
|
@@ -314070,7 +314139,7 @@ const resolveServerConfig = (flags, cliLogLevel, options) => gen(function* () {
|
|
|
314070
314139
|
forgeCodexHomePath: env.forgeCodexHomePath,
|
|
314071
314140
|
forgeClaudeConfigPath: env.forgeClaudeConfigPath,
|
|
314072
314141
|
forgeApexBaseUrl: env.forgeApexBaseUrl,
|
|
314073
|
-
cloudProjectsRoot: env.cloudProjectsRoot ?? "/
|
|
314142
|
+
cloudProjectsRoot: env.cloudProjectsRoot ?? "/projects"
|
|
314074
314143
|
};
|
|
314075
314144
|
if (config.forgeCloudShellMode === true && (!config.forgeCloudOwnerAssertionPublicKey?.trim() || !config.forgeCloudOwnerAssertionKeyId?.trim())) return yield* die$1(/* @__PURE__ */ new Error("FORGE_CMMD_CLOUD_OWNER_ASSERTION_PUBLIC_KEY and FORGE_CMMD_CLOUD_OWNER_ASSERTION_KEY_ID are required in cloud-shell mode; runtime ticket keys are not accepted for Cloud owner assertions."));
|
|
314076
314145
|
if (config.forgeCloudShellMode === true && !isEd25519PublicKey(config.forgeCloudOwnerAssertionPublicKey ?? "")) return yield* die$1(/* @__PURE__ */ new Error("FORGE_CMMD_CLOUD_OWNER_ASSERTION_PUBLIC_KEY must be a valid Ed25519 public key in cloud-shell mode."));
|
|
@@ -314488,7 +314557,7 @@ const connectLoginCommand = make$34("login", {
|
|
|
314488
314557
|
})).json();
|
|
314489
314558
|
},
|
|
314490
314559
|
openBrowser: async (url) => {
|
|
314491
|
-
const open = (await import("./open-
|
|
314560
|
+
const open = (await import("./open-D8mGyWmt.mjs")).default;
|
|
314492
314561
|
await open(url);
|
|
314493
314562
|
return true;
|
|
314494
314563
|
},
|