@cmmd-center/forge 0.13.44 → 0.13.45
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 +111 -41
- package/dist/bin.mjs +150 -65
- package/dist/client/assets/{DiffPanel-BHAsKkKi.js → DiffPanel-Bn_XagA5.js} +2 -2
- package/dist/client/assets/{DiffPanel.logic-BdWiyvx0.js → DiffPanel.logic-BHJKg1bv.js} +2 -2
- package/dist/client/assets/{DiffPanelShell-Bobn6Clg.js → DiffPanelShell-DFspB3po.js} +3 -3
- package/dist/client/assets/{DiffWorkerPoolProvider-Z5jpxH96.js → DiffWorkerPoolProvider-QNjpRYlc.js} +2 -2
- package/dist/client/assets/{PullRequestCodePanel-GiNxYEaL.js → PullRequestCodePanel-AYQxo9Xg.js} +2 -2
- package/dist/client/assets/{Virtualizer-CuZEUMDS.js → Virtualizer-cy0aLqwi.js} +2 -2
- package/dist/client/assets/{index-BC6ONxVh.js → index-IBzz5pAu.js} +6 -6
- package/dist/client/index.html +4 -4
- 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/bin.cjs
CHANGED
|
@@ -66243,7 +66243,7 @@ function normalizeNumberish(value) {
|
|
|
66243
66243
|
}
|
|
66244
66244
|
//#endregion
|
|
66245
66245
|
//#region package.json
|
|
66246
|
-
var version$1 = "0.13.
|
|
66246
|
+
var version$1 = "0.13.45";
|
|
66247
66247
|
//#endregion
|
|
66248
66248
|
//#region src/sentry.ts
|
|
66249
66249
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -94509,7 +94509,7 @@ const prepareBootstrapWorktree = (input) => require_Schema$1.gen(function* () {
|
|
|
94509
94509
|
projectCwd: bootstrapWorktree.projectCwd
|
|
94510
94510
|
};
|
|
94511
94511
|
});
|
|
94512
|
-
const dispatchBootstrapTurnStart = (input, command) => require_Schema$1.gen(function* () {
|
|
94512
|
+
const dispatchBootstrapTurnStart$1 = (input, command) => require_Schema$1.gen(function* () {
|
|
94513
94513
|
const { orchestrationEngine, git, gitStatusBroadcaster, projectSetupScriptRunner } = input;
|
|
94514
94514
|
const bootstrap = command.bootstrap;
|
|
94515
94515
|
const { bootstrap: _bootstrap, ...finalTurnStartCommand } = command;
|
|
@@ -94659,6 +94659,48 @@ const dispatchBootstrapTurnStart = (input, command) => require_Schema$1.gen(func
|
|
|
94659
94659
|
})), command.threadId);
|
|
94660
94660
|
});
|
|
94661
94661
|
//#endregion
|
|
94662
|
+
//#region src/orchestration/Services/SpriteTaskHoldReactor.ts
|
|
94663
|
+
/**
|
|
94664
|
+
* SpriteTaskHoldReactor - keeps a Fly.io Sprite awake while a turn is running.
|
|
94665
|
+
*
|
|
94666
|
+
* Reacts to provider turn lifecycle events and holds the sprite's run open for
|
|
94667
|
+
* the duration of each turn. See `sprite/spriteTaskHold.ts` for the measurements
|
|
94668
|
+
* and the ordering rule this depends on.
|
|
94669
|
+
*
|
|
94670
|
+
* @module SpriteTaskHoldReactor
|
|
94671
|
+
*/
|
|
94672
|
+
/**
|
|
94673
|
+
* SpriteTaskHoldReactor - Service tag for the sprite task hold worker.
|
|
94674
|
+
*/
|
|
94675
|
+
var SpriteTaskHoldReactor = class extends require_Schema$1.Service()("forge/orchestration/Services/SpriteTaskHoldReactor") {};
|
|
94676
|
+
//#endregion
|
|
94677
|
+
//#region src/orchestration/bootstrapLaunch.ts
|
|
94678
|
+
/**
|
|
94679
|
+
* The entry point for launching a thread: a bootstrap turn start, held awake.
|
|
94680
|
+
*
|
|
94681
|
+
* A launch creates the thread, adds the worktree and starts the setup script before the first
|
|
94682
|
+
* provider event exists, so no turn hold covers it. On a sprite with nothing connected that
|
|
94683
|
+
* work advances at about 1.7% of wall clock (`sprite/spriteTaskHold.ts`). A person who sends a
|
|
94684
|
+
* first message and closes the tab would otherwise wait most of an hour for a one-minute
|
|
94685
|
+
* install.
|
|
94686
|
+
*
|
|
94687
|
+
* Callers import the dispatch from here. `bootstrapDispatch.ts` stays unaware of sprites.
|
|
94688
|
+
*/
|
|
94689
|
+
/**
|
|
94690
|
+
* Runs a launch with the sprite held awake. A launch that fails or is cancelled releases the
|
|
94691
|
+
* hold. One that succeeds keeps it: the reactor hands over to the turn's own hold when the turn
|
|
94692
|
+
* starts, and the hold's refresh budget ends it if the turn never does. Where no reactor is
|
|
94693
|
+
* wired the launch runs unchanged.
|
|
94694
|
+
*/
|
|
94695
|
+
const withLaunchHold = (threadId, launch) => require_Schema$1.gen(function* () {
|
|
94696
|
+
const reactor = yield* require_Schema$1.serviceOption(SpriteTaskHoldReactor);
|
|
94697
|
+
if (require_Schema$1.isNone(reactor)) return yield* launch;
|
|
94698
|
+
const release = () => reactor.value.releaseLaunch(threadId);
|
|
94699
|
+
return yield* require_Schema$1.uninterruptible(reactor.value.holdLaunch(threadId)).pipe(require_Schema$1.andThen(require_Schema$1.yieldNow), require_Schema$1.andThen(launch), require_Schema$1.onError(release));
|
|
94700
|
+
});
|
|
94701
|
+
/** `dispatchBootstrapTurnStart` from `bootstrapDispatch.ts`, with the launch held awake. */
|
|
94702
|
+
const dispatchBootstrapTurnStart = (input, command) => withLaunchHold(String(command.threadId), dispatchBootstrapTurnStart$1(input, command));
|
|
94703
|
+
//#endregion
|
|
94662
94704
|
//#region src/orchestration/Services/OrchestrationEngine.ts
|
|
94663
94705
|
/**
|
|
94664
94706
|
* OrchestrationEngineService - Service tag for orchestration engine access.
|
|
@@ -240999,8 +241041,13 @@ var SpriteTaskHoldManager = class {
|
|
|
240999
241041
|
activeTurnIds() {
|
|
241000
241042
|
return [...this.#holds.keys()];
|
|
241001
241043
|
}
|
|
241002
|
-
|
|
241044
|
+
/**
|
|
241045
|
+
* `maxRefreshes` bounds a hold that has no terminal event of its own, such as a launch
|
|
241046
|
+
* whose turn may never start. When the budget is spent the hold releases itself.
|
|
241047
|
+
*/
|
|
241048
|
+
async acquire(turnId, threadId = null, options = {}) {
|
|
241003
241049
|
if (this.#holds.has(turnId)) return;
|
|
241050
|
+
let refreshesLeft = options.maxRefreshes ?? Number.POSITIVE_INFINITY;
|
|
241004
241051
|
const name = spriteTaskHoldName(this.#config.namePrefix, turnId);
|
|
241005
241052
|
const hold = {
|
|
241006
241053
|
name,
|
|
@@ -241024,6 +241071,11 @@ var SpriteTaskHoldManager = class {
|
|
|
241024
241071
|
if (hold.released || this.#holds.get(turnId) !== hold) return;
|
|
241025
241072
|
hold.refresher = this.#timer.setInterval(() => {
|
|
241026
241073
|
if (hold.inFlight.size > 0) return;
|
|
241074
|
+
if (refreshesLeft <= 0) {
|
|
241075
|
+
if (this.#holds.get(turnId) === hold) this.release(turnId);
|
|
241076
|
+
return;
|
|
241077
|
+
}
|
|
241078
|
+
refreshesLeft -= 1;
|
|
241027
241079
|
const refresh = this.#transport.put(name, 300).catch((cause) => this.#onError(`failed to refresh sprite task hold for turn ${turnId}`, cause));
|
|
241028
241080
|
hold.inFlight.add(refresh);
|
|
241029
241081
|
refresh.finally(() => hold.inFlight.delete(refresh));
|
|
@@ -287087,21 +287139,6 @@ var ProviderRuntimeIngestionService = class extends require_Schema$1.Service()("
|
|
|
287087
287139
|
//#region src/orchestration/Services/PlanTaskCreationReactor.ts
|
|
287088
287140
|
var PlanTaskCreationReactor = class extends require_Schema$1.Service()("forge/orchestration/Services/PlanTaskCreationReactor") {};
|
|
287089
287141
|
//#endregion
|
|
287090
|
-
//#region src/orchestration/Services/SpriteTaskHoldReactor.ts
|
|
287091
|
-
/**
|
|
287092
|
-
* SpriteTaskHoldReactor - keeps a Fly.io Sprite awake while a turn is running.
|
|
287093
|
-
*
|
|
287094
|
-
* Reacts to provider turn lifecycle events and holds the sprite's run open for
|
|
287095
|
-
* the duration of each turn. See `sprite/spriteTaskHold.ts` for the measurements
|
|
287096
|
-
* and the ordering rule this depends on.
|
|
287097
|
-
*
|
|
287098
|
-
* @module SpriteTaskHoldReactor
|
|
287099
|
-
*/
|
|
287100
|
-
/**
|
|
287101
|
-
* SpriteTaskHoldReactor - Service tag for the sprite task hold worker.
|
|
287102
|
-
*/
|
|
287103
|
-
var SpriteTaskHoldReactor = class extends require_Schema$1.Service()("forge/orchestration/Services/SpriteTaskHoldReactor") {};
|
|
287104
|
-
//#endregion
|
|
287105
287142
|
//#region src/persistence/Services/ProjectionProjects.ts
|
|
287106
287143
|
/**
|
|
287107
287144
|
* ProjectionProjectRepository - Projection repository interface for projects.
|
|
@@ -293651,34 +293688,67 @@ const CheckpointReactorLive = require_Schema$1.effect(CheckpointReactor, make$7)
|
|
|
293651
293688
|
* it is provider-agnostic: codex, claude and every other adapter emit
|
|
293652
293689
|
* `turn.started` / `turn.completed` through `ProviderService.streamEvents`.
|
|
293653
293690
|
*/
|
|
293691
|
+
/**
|
|
293692
|
+
* A launch hold refreshes every 60 s, so this budget is about ten minutes. A launch whose turn
|
|
293693
|
+
* never starts, because the provider refused it or the process died first, has no event to
|
|
293694
|
+
* release it. The budget is what stops that hold from keeping the sprite billing.
|
|
293695
|
+
*/
|
|
293696
|
+
const LAUNCH_HOLD_MAX_REFRESHES = 10;
|
|
293697
|
+
/** The hold id of a thread's launch. One launch per thread, so the thread names it. */
|
|
293698
|
+
const launchHoldId = (threadId) => `launch-${threadId}`;
|
|
293654
293699
|
const make$6 = require_Schema$1.gen(function* () {
|
|
293655
293700
|
const providerService = yield* ProviderService;
|
|
293656
293701
|
const manager = makeSpriteTaskHoldManager(process.env, (message, cause) => {
|
|
293657
293702
|
require_Schema$1.runFork(require_Schema$1.logWarning(message, { cause: cause instanceof Error ? cause.message : cause }));
|
|
293658
293703
|
});
|
|
293704
|
+
const launchCallers = /* @__PURE__ */ new Map();
|
|
293705
|
+
const start = require_Schema$1.fn("start")(function* () {
|
|
293706
|
+
if (manager === null) return;
|
|
293707
|
+
yield* require_Schema$1.forkScoped(require_Path.runForEach(providerService.streamEvents, (event) => {
|
|
293708
|
+
if (event.type === "turn.started") {
|
|
293709
|
+
const turnId = event.turnId;
|
|
293710
|
+
if (turnId === void 0) return require_Schema$1.void_;
|
|
293711
|
+
return require_Schema$1.promise(async () => {
|
|
293712
|
+
await manager.acquire(String(turnId), String(event.threadId));
|
|
293713
|
+
launchCallers.delete(String(event.threadId));
|
|
293714
|
+
await manager.release(launchHoldId(String(event.threadId)));
|
|
293715
|
+
});
|
|
293716
|
+
}
|
|
293717
|
+
if (event.type === "turn.completed") {
|
|
293718
|
+
const turnId = event.turnId;
|
|
293719
|
+
if (turnId === void 0) return require_Schema$1.void_;
|
|
293720
|
+
return require_Schema$1.promise(() => manager.release(String(turnId)));
|
|
293721
|
+
}
|
|
293722
|
+
if (event.type === "turn.aborted") {
|
|
293723
|
+
const turnId = event.turnId;
|
|
293724
|
+
if (turnId === void 0) return require_Schema$1.void_;
|
|
293725
|
+
return require_Schema$1.promise(() => manager.release(String(turnId)));
|
|
293726
|
+
}
|
|
293727
|
+
if (event.type === "session.exited") {
|
|
293728
|
+
launchCallers.delete(String(event.threadId));
|
|
293729
|
+
return require_Schema$1.promise(() => manager.releaseThread(String(event.threadId)));
|
|
293730
|
+
}
|
|
293731
|
+
return require_Schema$1.void_;
|
|
293732
|
+
}));
|
|
293733
|
+
});
|
|
293734
|
+
/** Takes the launch hold for one more caller. The budget bounds a launch that never starts a turn. */
|
|
293735
|
+
const holdLaunch = (threadId) => require_Schema$1.promise(async () => {
|
|
293736
|
+
if (manager === null) return;
|
|
293737
|
+
launchCallers.set(threadId, (launchCallers.get(threadId) ?? 0) + 1);
|
|
293738
|
+
await manager.acquire(launchHoldId(threadId), threadId, { maxRefreshes: LAUNCH_HOLD_MAX_REFRESHES });
|
|
293739
|
+
});
|
|
293740
|
+
/** Lets one caller go. The hold itself is released when the last caller has let go. */
|
|
293741
|
+
const releaseLaunch = (threadId) => require_Schema$1.promise(async () => {
|
|
293742
|
+
if (manager === null) return;
|
|
293743
|
+
const remaining = (launchCallers.get(threadId) ?? 1) - 1;
|
|
293744
|
+
if (remaining > 0) return void launchCallers.set(threadId, remaining);
|
|
293745
|
+
launchCallers.delete(threadId);
|
|
293746
|
+
await manager.release(launchHoldId(threadId));
|
|
293747
|
+
});
|
|
293659
293748
|
return {
|
|
293660
|
-
start
|
|
293661
|
-
|
|
293662
|
-
|
|
293663
|
-
if (event.type === "turn.started") {
|
|
293664
|
-
const turnId = event.turnId;
|
|
293665
|
-
if (turnId === void 0) return require_Schema$1.void_;
|
|
293666
|
-
return require_Schema$1.promise(() => manager.acquire(String(turnId), String(event.threadId)));
|
|
293667
|
-
}
|
|
293668
|
-
if (event.type === "turn.completed") {
|
|
293669
|
-
const turnId = event.turnId;
|
|
293670
|
-
if (turnId === void 0) return require_Schema$1.void_;
|
|
293671
|
-
return require_Schema$1.promise(() => manager.release(String(turnId)));
|
|
293672
|
-
}
|
|
293673
|
-
if (event.type === "turn.aborted") {
|
|
293674
|
-
const turnId = event.turnId;
|
|
293675
|
-
if (turnId === void 0) return require_Schema$1.void_;
|
|
293676
|
-
return require_Schema$1.promise(() => manager.release(String(turnId)));
|
|
293677
|
-
}
|
|
293678
|
-
if (event.type === "session.exited") return require_Schema$1.promise(() => manager.releaseThread(String(event.threadId)));
|
|
293679
|
-
return require_Schema$1.void_;
|
|
293680
|
-
}));
|
|
293681
|
-
}),
|
|
293749
|
+
start,
|
|
293750
|
+
holdLaunch,
|
|
293751
|
+
releaseLaunch,
|
|
293682
293752
|
releaseAll: require_Schema$1.promise(() => manager === null ? Promise.resolve() : manager.releaseAll())
|
|
293683
293753
|
};
|
|
293684
293754
|
});
|
|
@@ -297824,7 +297894,7 @@ function resolveBuildCommitFromEnv(env) {
|
|
|
297824
297894
|
* environment descriptor down instead of reporting an honest "unknown".
|
|
297825
297895
|
*/
|
|
297826
297896
|
function readBakedBuildCommit() {
|
|
297827
|
-
return "
|
|
297897
|
+
return "8ada8bfccfb8a4b0827961f304821e7b11249865";
|
|
297828
297898
|
}
|
|
297829
297899
|
async function resolveServerBuildCommit(input) {
|
|
297830
297900
|
if (isFullCommitSha(input.baked)) return input.baked;
|
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";
|
|
@@ -50560,7 +50560,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
50560
50560
|
const min = forceColor || 0;
|
|
50561
50561
|
if (env.TERM === "dumb") return min;
|
|
50562
50562
|
if (process$1.platform === "win32") {
|
|
50563
|
-
const osRelease =
|
|
50563
|
+
const osRelease = os.release().split(".");
|
|
50564
50564
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
50565
50565
|
return 1;
|
|
50566
50566
|
}
|
|
@@ -53003,7 +53003,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
53003
53003
|
exports.processDetector = void 0;
|
|
53004
53004
|
const api_1 = (init_esm$1(), __toCommonJS(esm_exports$1));
|
|
53005
53005
|
const semconv_1 = require_semconv$1();
|
|
53006
|
-
const os$
|
|
53006
|
+
const os$4 = __require("os");
|
|
53007
53007
|
/**
|
|
53008
53008
|
* ProcessDetector will be used to detect the resources related current process running
|
|
53009
53009
|
* and being instrumented from the NodeJS Process module.
|
|
@@ -53025,7 +53025,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
53025
53025
|
};
|
|
53026
53026
|
if (process.argv.length > 1) attributes[semconv_1.ATTR_PROCESS_COMMAND] = process.argv[1];
|
|
53027
53027
|
try {
|
|
53028
|
-
const userInfo = os$
|
|
53028
|
+
const userInfo = os$4.userInfo();
|
|
53029
53029
|
attributes[semconv_1.ATTR_PROCESS_OWNER] = userInfo.username;
|
|
53030
53030
|
} catch (e) {
|
|
53031
53031
|
api_1.diag.debug(`error obtaining process owner: ${e}`);
|
|
@@ -65948,7 +65948,7 @@ function normalizeNumberish(value) {
|
|
|
65948
65948
|
}
|
|
65949
65949
|
//#endregion
|
|
65950
65950
|
//#region package.json
|
|
65951
|
-
var version$1 = "0.13.
|
|
65951
|
+
var version$1 = "0.13.45";
|
|
65952
65952
|
//#endregion
|
|
65953
65953
|
//#region src/sentry.ts
|
|
65954
65954
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -75830,7 +75830,7 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
75830
75830
|
var fs$6 = __require("fs");
|
|
75831
75831
|
var path$5 = __require("path");
|
|
75832
75832
|
var url$1 = __require("url");
|
|
75833
|
-
var os$
|
|
75833
|
+
var os$3 = __require("os");
|
|
75834
75834
|
var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
75835
75835
|
var vars = process.config && process.config.variables || {};
|
|
75836
75836
|
var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
|
|
@@ -75838,8 +75838,8 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
75838
75838
|
var abi = versions.modules;
|
|
75839
75839
|
if (versions.deno || process.isBun) abi = "unsupported";
|
|
75840
75840
|
var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
|
|
75841
|
-
var arch = process.env.npm_config_arch || os$
|
|
75842
|
-
var platform = process.env.npm_config_platform || os$
|
|
75841
|
+
var arch = process.env.npm_config_arch || os$3.arch();
|
|
75842
|
+
var platform = process.env.npm_config_platform || os$3.platform();
|
|
75843
75843
|
var libc = process.env.LIBC || (isMusl(platform) ? "musl" : "glibc");
|
|
75844
75844
|
var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || "";
|
|
75845
75845
|
var uv = (versions.uv || "").split(".")[0];
|
|
@@ -93527,7 +93527,7 @@ const launchDetached = (launch) => gen(function* () {
|
|
|
93527
93527
|
});
|
|
93528
93528
|
const OpenLive = effect(Open, gen(function* () {
|
|
93529
93529
|
const open = yield* tryPromise({
|
|
93530
|
-
try: () => import("./open-
|
|
93530
|
+
try: () => import("./open-yHTUkd2Y.mjs"),
|
|
93531
93531
|
catch: (cause) => new OpenError$1({
|
|
93532
93532
|
message: "failed to load browser opener",
|
|
93533
93533
|
cause
|
|
@@ -94146,7 +94146,7 @@ const prepareBootstrapWorktree = (input) => gen(function* () {
|
|
|
94146
94146
|
projectCwd: bootstrapWorktree.projectCwd
|
|
94147
94147
|
};
|
|
94148
94148
|
});
|
|
94149
|
-
const dispatchBootstrapTurnStart = (input, command) => gen(function* () {
|
|
94149
|
+
const dispatchBootstrapTurnStart$1 = (input, command) => gen(function* () {
|
|
94150
94150
|
const { orchestrationEngine, git, gitStatusBroadcaster, projectSetupScriptRunner } = input;
|
|
94151
94151
|
const bootstrap = command.bootstrap;
|
|
94152
94152
|
const { bootstrap: _bootstrap, ...finalTurnStartCommand } = command;
|
|
@@ -94296,6 +94296,48 @@ const dispatchBootstrapTurnStart = (input, command) => gen(function* () {
|
|
|
94296
94296
|
})), command.threadId);
|
|
94297
94297
|
});
|
|
94298
94298
|
//#endregion
|
|
94299
|
+
//#region src/orchestration/Services/SpriteTaskHoldReactor.ts
|
|
94300
|
+
/**
|
|
94301
|
+
* SpriteTaskHoldReactor - keeps a Fly.io Sprite awake while a turn is running.
|
|
94302
|
+
*
|
|
94303
|
+
* Reacts to provider turn lifecycle events and holds the sprite's run open for
|
|
94304
|
+
* the duration of each turn. See `sprite/spriteTaskHold.ts` for the measurements
|
|
94305
|
+
* and the ordering rule this depends on.
|
|
94306
|
+
*
|
|
94307
|
+
* @module SpriteTaskHoldReactor
|
|
94308
|
+
*/
|
|
94309
|
+
/**
|
|
94310
|
+
* SpriteTaskHoldReactor - Service tag for the sprite task hold worker.
|
|
94311
|
+
*/
|
|
94312
|
+
var SpriteTaskHoldReactor = class extends Service$1()("forge/orchestration/Services/SpriteTaskHoldReactor") {};
|
|
94313
|
+
//#endregion
|
|
94314
|
+
//#region src/orchestration/bootstrapLaunch.ts
|
|
94315
|
+
/**
|
|
94316
|
+
* The entry point for launching a thread: a bootstrap turn start, held awake.
|
|
94317
|
+
*
|
|
94318
|
+
* A launch creates the thread, adds the worktree and starts the setup script before the first
|
|
94319
|
+
* provider event exists, so no turn hold covers it. On a sprite with nothing connected that
|
|
94320
|
+
* work advances at about 1.7% of wall clock (`sprite/spriteTaskHold.ts`). A person who sends a
|
|
94321
|
+
* first message and closes the tab would otherwise wait most of an hour for a one-minute
|
|
94322
|
+
* install.
|
|
94323
|
+
*
|
|
94324
|
+
* Callers import the dispatch from here. `bootstrapDispatch.ts` stays unaware of sprites.
|
|
94325
|
+
*/
|
|
94326
|
+
/**
|
|
94327
|
+
* Runs a launch with the sprite held awake. A launch that fails or is cancelled releases the
|
|
94328
|
+
* hold. One that succeeds keeps it: the reactor hands over to the turn's own hold when the turn
|
|
94329
|
+
* starts, and the hold's refresh budget ends it if the turn never does. Where no reactor is
|
|
94330
|
+
* wired the launch runs unchanged.
|
|
94331
|
+
*/
|
|
94332
|
+
const withLaunchHold = (threadId, launch) => gen(function* () {
|
|
94333
|
+
const reactor = yield* serviceOption(SpriteTaskHoldReactor);
|
|
94334
|
+
if (isNone(reactor)) return yield* launch;
|
|
94335
|
+
const release = () => reactor.value.releaseLaunch(threadId);
|
|
94336
|
+
return yield* uninterruptible(reactor.value.holdLaunch(threadId)).pipe(andThen(yieldNow), andThen(launch), onError$1(release));
|
|
94337
|
+
});
|
|
94338
|
+
/** `dispatchBootstrapTurnStart` from `bootstrapDispatch.ts`, with the launch held awake. */
|
|
94339
|
+
const dispatchBootstrapTurnStart = (input, command) => withLaunchHold(String(command.threadId), dispatchBootstrapTurnStart$1(input, command));
|
|
94340
|
+
//#endregion
|
|
94299
94341
|
//#region src/orchestration/Services/OrchestrationEngine.ts
|
|
94300
94342
|
/**
|
|
94301
94343
|
* OrchestrationEngineService - Service tag for orchestration engine access.
|
|
@@ -191003,7 +191045,7 @@ var Vce = {
|
|
|
191003
191045
|
function Ve() {
|
|
191004
191046
|
return Vce;
|
|
191005
191047
|
}
|
|
191006
|
-
var Us =
|
|
191048
|
+
var Us = os.homedir(), lk = os.tmpdir(), { env: Vc } = process$1, Yce = (e) => {
|
|
191007
191049
|
let t = path.join(Us, "Library");
|
|
191008
191050
|
return {
|
|
191009
191051
|
data: path.join(t, "Application Support", e),
|
|
@@ -201203,12 +201245,12 @@ function qZ(e, t) {
|
|
|
201203
201245
|
}
|
|
201204
201246
|
return n;
|
|
201205
201247
|
}
|
|
201206
|
-
var os$
|
|
201248
|
+
var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
201207
201249
|
{
|
|
201208
201250
|
matches: (e) => e.path === "permissions.defaultMode" && e.code === "invalid_value",
|
|
201209
201251
|
tip: {
|
|
201210
201252
|
suggestion: "Valid modes: \"acceptEdits\" (ask before file changes), \"plan\" (analysis only), \"bypassPermissions\" (auto-accept all), or \"default\" (standard behavior)",
|
|
201211
|
-
docLink: `${os$
|
|
201253
|
+
docLink: `${os$2}/iam#permission-modes`
|
|
201212
201254
|
}
|
|
201213
201255
|
},
|
|
201214
201256
|
{
|
|
@@ -201223,7 +201265,7 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
|
|
|
201223
201265
|
matches: (e) => e.path.startsWith("env.") && e.code === "invalid_type",
|
|
201224
201266
|
tip: {
|
|
201225
201267
|
suggestion: "Environment variables must be strings. Wrap numbers and booleans in quotes. Example: \"DEBUG\": \"true\", \"PORT\": \"3000\"",
|
|
201226
|
-
docLink: `${os$
|
|
201268
|
+
docLink: `${os$2}/settings#environment-variables`
|
|
201227
201269
|
}
|
|
201228
201270
|
},
|
|
201229
201271
|
{
|
|
@@ -201234,14 +201276,14 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
|
|
|
201234
201276
|
matches: (e) => e.path.startsWith("hooks.") && e.code === "invalid_key",
|
|
201235
201277
|
tip: {
|
|
201236
201278
|
suggestion: "Not a recognized hook event. Common events: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, SessionEnd, Stop. Check spelling and capitalization.",
|
|
201237
|
-
docLink: `${os$
|
|
201279
|
+
docLink: `${os$2}/hooks`
|
|
201238
201280
|
}
|
|
201239
201281
|
},
|
|
201240
201282
|
{
|
|
201241
201283
|
matches: (e) => /\.hooks\.\d+\.command$/.test(e.path) && e.code === "invalid_type" && e.received === "undefined",
|
|
201242
201284
|
tip: {
|
|
201243
201285
|
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\"}.",
|
|
201244
|
-
docLink: `${os$
|
|
201286
|
+
docLink: `${os$2}/hooks#exec-form-and-shell-form`
|
|
201245
201287
|
}
|
|
201246
201288
|
},
|
|
201247
201289
|
{
|
|
@@ -201256,7 +201298,7 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
|
|
|
201256
201298
|
matches: (e) => e.code === "unrecognized_keys",
|
|
201257
201299
|
tip: {
|
|
201258
201300
|
suggestion: "Check for typos or refer to the documentation for valid fields",
|
|
201259
|
-
docLink: `${os$
|
|
201301
|
+
docLink: `${os$2}/settings`
|
|
201260
201302
|
}
|
|
201261
201303
|
},
|
|
201262
201304
|
{
|
|
@@ -201271,13 +201313,13 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
|
|
|
201271
201313
|
matches: (e) => e.path === "permissions.additionalDirectories" && e.code === "invalid_type",
|
|
201272
201314
|
tip: {
|
|
201273
201315
|
suggestion: "Must be an array of directory paths. Example: [\"~/projects\", \"/tmp/workspace\"]. You can also use --add-dir flag or /add-dir command",
|
|
201274
|
-
docLink: `${os$
|
|
201316
|
+
docLink: `${os$2}/iam#working-directories`
|
|
201275
201317
|
}
|
|
201276
201318
|
}
|
|
201277
201319
|
], AKe = {
|
|
201278
|
-
permissions: `${os$
|
|
201279
|
-
env: `${os$
|
|
201280
|
-
hooks: `${os$
|
|
201320
|
+
permissions: `${os$2}/iam#configuring-permissions`,
|
|
201321
|
+
env: `${os$2}/settings#environment-variables`,
|
|
201322
|
+
hooks: `${os$2}/hooks`
|
|
201281
201323
|
};
|
|
201282
201324
|
function GZ(e) {
|
|
201283
201325
|
let t = kKe.find((r) => r.matches(e));
|
|
@@ -240517,8 +240559,13 @@ var SpriteTaskHoldManager = class {
|
|
|
240517
240559
|
activeTurnIds() {
|
|
240518
240560
|
return [...this.#holds.keys()];
|
|
240519
240561
|
}
|
|
240520
|
-
|
|
240562
|
+
/**
|
|
240563
|
+
* `maxRefreshes` bounds a hold that has no terminal event of its own, such as a launch
|
|
240564
|
+
* whose turn may never start. When the budget is spent the hold releases itself.
|
|
240565
|
+
*/
|
|
240566
|
+
async acquire(turnId, threadId = null, options = {}) {
|
|
240521
240567
|
if (this.#holds.has(turnId)) return;
|
|
240568
|
+
let refreshesLeft = options.maxRefreshes ?? Number.POSITIVE_INFINITY;
|
|
240522
240569
|
const name = spriteTaskHoldName(this.#config.namePrefix, turnId);
|
|
240523
240570
|
const hold = {
|
|
240524
240571
|
name,
|
|
@@ -240542,6 +240589,11 @@ var SpriteTaskHoldManager = class {
|
|
|
240542
240589
|
if (hold.released || this.#holds.get(turnId) !== hold) return;
|
|
240543
240590
|
hold.refresher = this.#timer.setInterval(() => {
|
|
240544
240591
|
if (hold.inFlight.size > 0) return;
|
|
240592
|
+
if (refreshesLeft <= 0) {
|
|
240593
|
+
if (this.#holds.get(turnId) === hold) this.release(turnId);
|
|
240594
|
+
return;
|
|
240595
|
+
}
|
|
240596
|
+
refreshesLeft -= 1;
|
|
240545
240597
|
const refresh = this.#transport.put(name, 300).catch((cause) => this.#onError(`failed to refresh sprite task hold for turn ${turnId}`, cause));
|
|
240546
240598
|
hold.inFlight.add(refresh);
|
|
240547
240599
|
refresh.finally(() => hold.inFlight.delete(refresh));
|
|
@@ -269248,7 +269300,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
269248
269300
|
var dgram = __require("dgram");
|
|
269249
269301
|
var thunky = require_thunky();
|
|
269250
269302
|
var events = __require("events");
|
|
269251
|
-
var os = __require("os");
|
|
269303
|
+
var os$1 = __require("os");
|
|
269252
269304
|
var noop = function() {};
|
|
269253
269305
|
module.exports = function(opts) {
|
|
269254
269306
|
if (!opts) opts = {};
|
|
@@ -269379,14 +269431,14 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
269379
269431
|
return that;
|
|
269380
269432
|
};
|
|
269381
269433
|
function defaultInterface() {
|
|
269382
|
-
var networks = os.networkInterfaces();
|
|
269434
|
+
var networks = os$1.networkInterfaces();
|
|
269383
269435
|
var names = Object.keys(networks);
|
|
269384
269436
|
for (var i = 0; i < names.length; i++) {
|
|
269385
269437
|
var net = networks[names[i]];
|
|
269386
269438
|
for (var j = 0; j < net.length; j++) {
|
|
269387
269439
|
var iface = net[j];
|
|
269388
269440
|
if (isIPv4(iface.family) && !iface.internal) {
|
|
269389
|
-
if (os.platform() === "darwin" && names[i] === "en0") return iface.address;
|
|
269441
|
+
if (os$1.platform() === "darwin" && names[i] === "en0") return iface.address;
|
|
269390
269442
|
return "0.0.0.0";
|
|
269391
269443
|
}
|
|
269392
269444
|
}
|
|
@@ -269394,7 +269446,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
269394
269446
|
return "127.0.0.1";
|
|
269395
269447
|
}
|
|
269396
269448
|
function allInterfaces() {
|
|
269397
|
-
var networks = os.networkInterfaces();
|
|
269449
|
+
var networks = os$1.networkInterfaces();
|
|
269398
269450
|
var names = Object.keys(networks);
|
|
269399
269451
|
var res = [];
|
|
269400
269452
|
for (var i = 0; i < names.length; i++) {
|
|
@@ -286597,21 +286649,6 @@ var ProviderRuntimeIngestionService = class extends Service$1()("forge/orchestra
|
|
|
286597
286649
|
//#region src/orchestration/Services/PlanTaskCreationReactor.ts
|
|
286598
286650
|
var PlanTaskCreationReactor = class extends Service$1()("forge/orchestration/Services/PlanTaskCreationReactor") {};
|
|
286599
286651
|
//#endregion
|
|
286600
|
-
//#region src/orchestration/Services/SpriteTaskHoldReactor.ts
|
|
286601
|
-
/**
|
|
286602
|
-
* SpriteTaskHoldReactor - keeps a Fly.io Sprite awake while a turn is running.
|
|
286603
|
-
*
|
|
286604
|
-
* Reacts to provider turn lifecycle events and holds the sprite's run open for
|
|
286605
|
-
* the duration of each turn. See `sprite/spriteTaskHold.ts` for the measurements
|
|
286606
|
-
* and the ordering rule this depends on.
|
|
286607
|
-
*
|
|
286608
|
-
* @module SpriteTaskHoldReactor
|
|
286609
|
-
*/
|
|
286610
|
-
/**
|
|
286611
|
-
* SpriteTaskHoldReactor - Service tag for the sprite task hold worker.
|
|
286612
|
-
*/
|
|
286613
|
-
var SpriteTaskHoldReactor = class extends Service$1()("forge/orchestration/Services/SpriteTaskHoldReactor") {};
|
|
286614
|
-
//#endregion
|
|
286615
286652
|
//#region src/persistence/Services/ProjectionProjects.ts
|
|
286616
286653
|
/**
|
|
286617
286654
|
* ProjectionProjectRepository - Projection repository interface for projects.
|
|
@@ -293113,34 +293150,82 @@ const CheckpointReactorLive = effect(CheckpointReactor, gen(function* () {
|
|
|
293113
293150
|
drain: worker.drain
|
|
293114
293151
|
};
|
|
293115
293152
|
}));
|
|
293153
|
+
//#endregion
|
|
293154
|
+
//#region src/orchestration/Layers/SpriteTaskHoldReactor.ts
|
|
293155
|
+
/**
|
|
293156
|
+
* Holds the sprite awake for the duration of every agent turn.
|
|
293157
|
+
*
|
|
293158
|
+
* A sprite's cgroup freezes ~1s after the last inbound request, so a turn that
|
|
293159
|
+
* nobody is watching advances at ~1.7% of wall clock. A task hold restores it to
|
|
293160
|
+
* 100%. Measurements and the release-ordering rule live in
|
|
293161
|
+
* `sprite/spriteTaskHold.ts`; the platform contract is documented in
|
|
293162
|
+
* `docs/specs/2026-07-30-sprites-platform-ground-truth.md` §1.
|
|
293163
|
+
*
|
|
293164
|
+
* This subscribes to the same provider event stream CheckpointReactor uses, so
|
|
293165
|
+
* it is provider-agnostic: codex, claude and every other adapter emit
|
|
293166
|
+
* `turn.started` / `turn.completed` through `ProviderService.streamEvents`.
|
|
293167
|
+
*/
|
|
293168
|
+
/**
|
|
293169
|
+
* A launch hold refreshes every 60 s, so this budget is about ten minutes. A launch whose turn
|
|
293170
|
+
* never starts, because the provider refused it or the process died first, has no event to
|
|
293171
|
+
* release it. The budget is what stops that hold from keeping the sprite billing.
|
|
293172
|
+
*/
|
|
293173
|
+
const LAUNCH_HOLD_MAX_REFRESHES = 10;
|
|
293174
|
+
/** The hold id of a thread's launch. One launch per thread, so the thread names it. */
|
|
293175
|
+
const launchHoldId = (threadId) => `launch-${threadId}`;
|
|
293116
293176
|
const SpriteTaskHoldReactorLive = effect(SpriteTaskHoldReactor, gen(function* () {
|
|
293117
293177
|
const providerService = yield* ProviderService;
|
|
293118
293178
|
const manager = makeSpriteTaskHoldManager(process.env, (message, cause) => {
|
|
293119
293179
|
runFork(logWarning$1(message, { cause: cause instanceof Error ? cause.message : cause }));
|
|
293120
293180
|
});
|
|
293181
|
+
const launchCallers = /* @__PURE__ */ new Map();
|
|
293182
|
+
const start = fn$1("start")(function* () {
|
|
293183
|
+
if (manager === null) return;
|
|
293184
|
+
yield* forkScoped(runForEach(providerService.streamEvents, (event) => {
|
|
293185
|
+
if (event.type === "turn.started") {
|
|
293186
|
+
const turnId = event.turnId;
|
|
293187
|
+
if (turnId === void 0) return void_$1;
|
|
293188
|
+
return promise(async () => {
|
|
293189
|
+
await manager.acquire(String(turnId), String(event.threadId));
|
|
293190
|
+
launchCallers.delete(String(event.threadId));
|
|
293191
|
+
await manager.release(launchHoldId(String(event.threadId)));
|
|
293192
|
+
});
|
|
293193
|
+
}
|
|
293194
|
+
if (event.type === "turn.completed") {
|
|
293195
|
+
const turnId = event.turnId;
|
|
293196
|
+
if (turnId === void 0) return void_$1;
|
|
293197
|
+
return promise(() => manager.release(String(turnId)));
|
|
293198
|
+
}
|
|
293199
|
+
if (event.type === "turn.aborted") {
|
|
293200
|
+
const turnId = event.turnId;
|
|
293201
|
+
if (turnId === void 0) return void_$1;
|
|
293202
|
+
return promise(() => manager.release(String(turnId)));
|
|
293203
|
+
}
|
|
293204
|
+
if (event.type === "session.exited") {
|
|
293205
|
+
launchCallers.delete(String(event.threadId));
|
|
293206
|
+
return promise(() => manager.releaseThread(String(event.threadId)));
|
|
293207
|
+
}
|
|
293208
|
+
return void_$1;
|
|
293209
|
+
}));
|
|
293210
|
+
});
|
|
293211
|
+
/** Takes the launch hold for one more caller. The budget bounds a launch that never starts a turn. */
|
|
293212
|
+
const holdLaunch = (threadId) => promise(async () => {
|
|
293213
|
+
if (manager === null) return;
|
|
293214
|
+
launchCallers.set(threadId, (launchCallers.get(threadId) ?? 0) + 1);
|
|
293215
|
+
await manager.acquire(launchHoldId(threadId), threadId, { maxRefreshes: LAUNCH_HOLD_MAX_REFRESHES });
|
|
293216
|
+
});
|
|
293217
|
+
/** Lets one caller go. The hold itself is released when the last caller has let go. */
|
|
293218
|
+
const releaseLaunch = (threadId) => promise(async () => {
|
|
293219
|
+
if (manager === null) return;
|
|
293220
|
+
const remaining = (launchCallers.get(threadId) ?? 1) - 1;
|
|
293221
|
+
if (remaining > 0) return void launchCallers.set(threadId, remaining);
|
|
293222
|
+
launchCallers.delete(threadId);
|
|
293223
|
+
await manager.release(launchHoldId(threadId));
|
|
293224
|
+
});
|
|
293121
293225
|
return {
|
|
293122
|
-
start
|
|
293123
|
-
|
|
293124
|
-
|
|
293125
|
-
if (event.type === "turn.started") {
|
|
293126
|
-
const turnId = event.turnId;
|
|
293127
|
-
if (turnId === void 0) return void_$1;
|
|
293128
|
-
return promise(() => manager.acquire(String(turnId), String(event.threadId)));
|
|
293129
|
-
}
|
|
293130
|
-
if (event.type === "turn.completed") {
|
|
293131
|
-
const turnId = event.turnId;
|
|
293132
|
-
if (turnId === void 0) return void_$1;
|
|
293133
|
-
return promise(() => manager.release(String(turnId)));
|
|
293134
|
-
}
|
|
293135
|
-
if (event.type === "turn.aborted") {
|
|
293136
|
-
const turnId = event.turnId;
|
|
293137
|
-
if (turnId === void 0) return void_$1;
|
|
293138
|
-
return promise(() => manager.release(String(turnId)));
|
|
293139
|
-
}
|
|
293140
|
-
if (event.type === "session.exited") return promise(() => manager.releaseThread(String(event.threadId)));
|
|
293141
|
-
return void_$1;
|
|
293142
|
-
}));
|
|
293143
|
-
}),
|
|
293226
|
+
start,
|
|
293227
|
+
holdLaunch,
|
|
293228
|
+
releaseLaunch,
|
|
293144
293229
|
releaseAll: promise(() => manager === null ? Promise.resolve() : manager.releaseAll())
|
|
293145
293230
|
};
|
|
293146
293231
|
}));
|
|
@@ -297255,7 +297340,7 @@ function resolveBuildCommitFromEnv(env) {
|
|
|
297255
297340
|
* environment descriptor down instead of reporting an honest "unknown".
|
|
297256
297341
|
*/
|
|
297257
297342
|
function readBakedBuildCommit() {
|
|
297258
|
-
return "
|
|
297343
|
+
return "8ada8bfccfb8a4b0827961f304821e7b11249865";
|
|
297259
297344
|
}
|
|
297260
297345
|
async function resolveServerBuildCommit(input) {
|
|
297261
297346
|
if (isFullCommitSha(input.baked)) return input.baked;
|
|
@@ -321856,7 +321941,7 @@ const connectLoginCommand = make$34("login", {
|
|
|
321856
321941
|
})).json();
|
|
321857
321942
|
},
|
|
321858
321943
|
openBrowser: async (url) => {
|
|
321859
|
-
const open = (await import("./open-
|
|
321944
|
+
const open = (await import("./open-yHTUkd2Y.mjs")).default;
|
|
321860
321945
|
await open(url);
|
|
321861
321946
|
return true;
|
|
321862
321947
|
},
|