@cmmd-center/forge 0.9.9-rc.1 → 0.9.9-rc.2
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 +94 -4
- package/dist/bin.mjs +118 -28
- package/dist/{open-D8mGyWmt.mjs → open-FIgTDosf.mjs} +3 -3
- package/package.json +1 -1
package/dist/bin.cjs
CHANGED
|
@@ -64277,7 +64277,7 @@ function normalizeNumberish(value) {
|
|
|
64277
64277
|
}
|
|
64278
64278
|
//#endregion
|
|
64279
64279
|
//#region package.json
|
|
64280
|
-
var version$1 = "0.9.9-rc.
|
|
64280
|
+
var version$1 = "0.9.9-rc.2";
|
|
64281
64281
|
//#endregion
|
|
64282
64282
|
//#region src/sentry.ts
|
|
64283
64283
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -92088,6 +92088,31 @@ function describeHydrationOutcome(outcome) {
|
|
|
92088
92088
|
};
|
|
92089
92089
|
}
|
|
92090
92090
|
//#endregion
|
|
92091
|
+
//#region src/runtimeReplication/replicaThreadQuarantine.ts
|
|
92092
|
+
/**
|
|
92093
|
+
* Which replica threads hydration should stop retrying.
|
|
92094
|
+
*
|
|
92095
|
+
* A thread that fails its identity or generation check was recorded against a
|
|
92096
|
+
* runtime that no longer exists. Nothing about a later boot changes that, and
|
|
92097
|
+
* because a failed thread is never inserted it never becomes "known", so the
|
|
92098
|
+
* next boot fetches and fails it again. Measured on a production sprite: 24
|
|
92099
|
+
* such threads retried on every one of three boots.
|
|
92100
|
+
*
|
|
92101
|
+
* Quarantine is deliberately NARROW. Only a permanent failure qualifies. A
|
|
92102
|
+
* thread that merely disappeared may come back, and a project that does not
|
|
92103
|
+
* resolve to an active workspace starts resolving the moment that project is
|
|
92104
|
+
* imported. Quarantining either would turn a recoverable gap into a permanent
|
|
92105
|
+
* one, which is worse than the retry it saves.
|
|
92106
|
+
*/
|
|
92107
|
+
/** The one failure that a later boot can never turn into a success. */
|
|
92108
|
+
const PERMANENT_FAILURE = "failed identity or generation checks";
|
|
92109
|
+
function isQuarantinedReplicaThread(quarantined, threadId) {
|
|
92110
|
+
return quarantined.has(threadId);
|
|
92111
|
+
}
|
|
92112
|
+
function shouldQuarantineReplicaThread(detail) {
|
|
92113
|
+
return detail.includes(PERMANENT_FAILURE);
|
|
92114
|
+
}
|
|
92115
|
+
//#endregion
|
|
92091
92116
|
//#region src/runtimeReplication/replicaHydrationIdentity.ts
|
|
92092
92117
|
function stableReplicaDigest(...values) {
|
|
92093
92118
|
return node_crypto.createHash("sha256").update(values.join("\0")).digest("base64url");
|
|
@@ -92467,6 +92492,10 @@ const prepareReplicaSummary = require_Schema$1.fn("prepareReplicaSummary")(funct
|
|
|
92467
92492
|
state.skippedExisting += 1;
|
|
92468
92493
|
return;
|
|
92469
92494
|
}
|
|
92495
|
+
if (isQuarantinedReplicaThread(state.quarantinedThreadIds, summary.threadId)) {
|
|
92496
|
+
state.skippedQuarantined += 1;
|
|
92497
|
+
return;
|
|
92498
|
+
}
|
|
92470
92499
|
const localResolution = yield* resolveLocalReplicaProjects(state, index, summary, dependencies);
|
|
92471
92500
|
const localProjects = localResolution.projects;
|
|
92472
92501
|
if (localProjects.length !== 1) return yield* replicaHydrationFailure("replica project '" + summary.projectId + "' does not resolve to one active workspace");
|
|
@@ -92507,13 +92536,18 @@ const prepareReplicaSummary = require_Schema$1.fn("prepareReplicaSummary")(funct
|
|
|
92507
92536
|
* repeated cursor) stay fatal on purpose: those mean the index itself cannot be
|
|
92508
92537
|
* trusted, so continuing would hydrate an unknown mixture.
|
|
92509
92538
|
*/
|
|
92510
|
-
function skipUnhydratableThread(operation, threadId, state) {
|
|
92539
|
+
function skipUnhydratableThread(operation, threadId, state, dependencies) {
|
|
92511
92540
|
return operation.pipe(require_Schema$1.catchTag("RuntimeReplicaHydrationError", (error) => require_Schema$1.gen(function* () {
|
|
92512
92541
|
state.unhydratableThreadIds.push(threadId);
|
|
92513
92542
|
yield* require_Schema$1.logWarning("skipped a thread that could not be hydrated", {
|
|
92514
92543
|
threadId,
|
|
92515
92544
|
detail: error.detail
|
|
92516
92545
|
});
|
|
92546
|
+
if (!shouldQuarantineReplicaThread(error.detail)) return;
|
|
92547
|
+
yield* dependencies.quarantineThread({
|
|
92548
|
+
threadId,
|
|
92549
|
+
detail: error.detail
|
|
92550
|
+
}).pipe(require_Schema$1.ignore);
|
|
92517
92551
|
})));
|
|
92518
92552
|
}
|
|
92519
92553
|
const applyPreparedReplica = require_Schema$1.fn("applyPreparedReplica")(function* (expectedRuntimeId, prepared, state, dependencies) {
|
|
@@ -92541,7 +92575,7 @@ function prepareReplicaPages(expectedRuntimeId, cursor, state, dependencies) {
|
|
|
92541
92575
|
if (index === null) return;
|
|
92542
92576
|
if (state.runtimeIdentity === null) state.runtimeIdentity = index.runtime;
|
|
92543
92577
|
else if (!replicaRuntimeMatches(state.runtimeIdentity, index.runtime)) return yield* replicaHydrationFailure("index runtime identity changed between pages");
|
|
92544
|
-
yield* require_Schema$1.forEach(index.threads, (summary) => skipUnhydratableThread(prepareReplicaSummary(expectedRuntimeId, index, summary, state, dependencies), summary.threadId, state), {
|
|
92578
|
+
yield* require_Schema$1.forEach(index.threads, (summary) => skipUnhydratableThread(prepareReplicaSummary(expectedRuntimeId, index, summary, state, dependencies), summary.threadId, state, dependencies), {
|
|
92545
92579
|
concurrency: 1,
|
|
92546
92580
|
discard: true
|
|
92547
92581
|
});
|
|
@@ -92562,16 +92596,19 @@ const hydrateRuntimeReplica = require_Schema$1.fn("hydrateRuntimeReplica")(funct
|
|
|
92562
92596
|
runtimeIdentity: null,
|
|
92563
92597
|
hydrated: 0,
|
|
92564
92598
|
skippedExisting: 0,
|
|
92599
|
+
skippedQuarantined: 0,
|
|
92600
|
+
quarantinedThreadIds: yield* dependencies.readQuarantinedThreadIds().pipe(require_Schema$1.orElseSucceed(() => /* @__PURE__ */ new Set())),
|
|
92565
92601
|
unhydratableThreadIds: []
|
|
92566
92602
|
};
|
|
92567
92603
|
yield* prepareReplicaPages(input.expectedRuntimeId, void 0, state, dependencies);
|
|
92568
|
-
yield* require_Schema$1.forEach(state.prepared, (prepared) => skipUnhydratableThread(applyPreparedReplica(input.expectedRuntimeId, prepared, state, dependencies), prepared.summary.threadId, state), {
|
|
92604
|
+
yield* require_Schema$1.forEach(state.prepared, (prepared) => skipUnhydratableThread(applyPreparedReplica(input.expectedRuntimeId, prepared, state, dependencies), prepared.summary.threadId, state, dependencies), {
|
|
92569
92605
|
concurrency: 1,
|
|
92570
92606
|
discard: true
|
|
92571
92607
|
});
|
|
92572
92608
|
const outcome = {
|
|
92573
92609
|
hydrated: state.hydrated,
|
|
92574
92610
|
skippedExisting: state.skippedExisting,
|
|
92611
|
+
skippedQuarantined: state.skippedQuarantined,
|
|
92575
92612
|
skippedUnhydratable: state.unhydratableThreadIds.length,
|
|
92576
92613
|
unhydratableThreadIds: [...state.unhydratableThreadIds]
|
|
92577
92614
|
};
|
|
@@ -92626,6 +92663,29 @@ async function requestReplicaRead(input, fetchImpl = fetch) {
|
|
|
92626
92663
|
}
|
|
92627
92664
|
}
|
|
92628
92665
|
//#endregion
|
|
92666
|
+
//#region src/runtimeReplication/replicaThreadQuarantineStore.ts
|
|
92667
|
+
/**
|
|
92668
|
+
* Durable record of replica threads that can never hydrate.
|
|
92669
|
+
*
|
|
92670
|
+
* Lives on the guest rather than in CMMD's replica because CMMD exposes no
|
|
92671
|
+
* write surface for it. That bounds what this can fix: it stops one Environment
|
|
92672
|
+
* re-fetching known-dead threads on every boot, and it does NOT remove the rows
|
|
92673
|
+
* from durable history, so a fresh Environment pays the cost once again.
|
|
92674
|
+
*/
|
|
92675
|
+
const makeReplicaThreadQuarantineStore = require_Schema$1.gen(function* () {
|
|
92676
|
+
const sql = yield* require_SqlError.SqlClient;
|
|
92677
|
+
const readQuarantinedThreadIds = () => sql`SELECT thread_id FROM replica_thread_quarantine`.pipe(require_Schema$1.map((rows) => new Set(rows.map((row) => row.thread_id))), require_Schema$1.mapError((cause) => replicaHydrationFailure("quarantine read failed", cause)));
|
|
92678
|
+
const quarantineThread = (input) => sql`
|
|
92679
|
+
INSERT INTO replica_thread_quarantine (thread_id, detail, quarantined_at)
|
|
92680
|
+
VALUES (${input.threadId}, ${input.detail}, ${(/* @__PURE__ */ new Date()).toISOString()})
|
|
92681
|
+
ON CONFLICT (thread_id) DO NOTHING
|
|
92682
|
+
`.pipe(require_Schema$1.asVoid, require_Schema$1.mapError((cause) => replicaHydrationFailure("quarantine write failed", cause)));
|
|
92683
|
+
return {
|
|
92684
|
+
readQuarantinedThreadIds,
|
|
92685
|
+
quarantineThread
|
|
92686
|
+
};
|
|
92687
|
+
});
|
|
92688
|
+
//#endregion
|
|
92629
92689
|
//#region src/runtimeReplication/replicaHydrationCloud.ts
|
|
92630
92690
|
const REPLICA_INDEX_PAGE_SIZE = 100;
|
|
92631
92691
|
const registerCloudRuntimeForReplicaHydration = require_Schema$1.gen(function* () {
|
|
@@ -92662,6 +92722,7 @@ const hydrateCloudRuntimeReplica = require_Schema$1.gen(function* () {
|
|
|
92662
92722
|
}),
|
|
92663
92723
|
catch: (cause) => replicaHydrationFailure("runtime replica read failed", cause)
|
|
92664
92724
|
});
|
|
92725
|
+
const quarantine = yield* makeReplicaThreadQuarantineStore;
|
|
92665
92726
|
const dependencies = {
|
|
92666
92727
|
dispatch: (command) => engine.dispatch(command).pipe(require_Schema$1.mapError((cause) => replicaHydrationFailure("orchestration dispatch failed", cause))),
|
|
92667
92728
|
getReadModel: engine.getReadModel,
|
|
@@ -92669,6 +92730,8 @@ const hydrateCloudRuntimeReplica = require_Schema$1.gen(function* () {
|
|
|
92669
92730
|
readThread: ({ threadId }) => request({ threadId }),
|
|
92670
92731
|
restoreThreadCursor: (input) => outbox.restoreThreadCursor(input).pipe(require_Schema$1.mapError((cause) => replicaHydrationFailure("cursor restore failed", cause))),
|
|
92671
92732
|
resolveProjectRepositoryFullName: (workspaceRoot) => repositoryIdentityResolver.resolve(workspaceRoot).pipe(require_Schema$1.map((identity) => identity?.owner && identity.name ? `${identity.owner}/${identity.name}` : null), require_Schema$1.mapError((cause) => replicaHydrationFailure("repository identity resolution failed", cause))),
|
|
92733
|
+
readQuarantinedThreadIds: quarantine.readQuarantinedThreadIds,
|
|
92734
|
+
quarantineThread: quarantine.quarantineThread,
|
|
92672
92735
|
now: () => (/* @__PURE__ */ new Date()).toISOString()
|
|
92673
92736
|
};
|
|
92674
92737
|
return yield* hydrateRuntimeReplica({ expectedRuntimeId: grant.runtimeId }, dependencies);
|
|
@@ -109937,6 +110000,28 @@ var _072_ProjectDefaultThreadEnvMode_default = require_Schema$1.gen(function* ()
|
|
|
109937
110000
|
`;
|
|
109938
110001
|
});
|
|
109939
110002
|
//#endregion
|
|
110003
|
+
//#region src/persistence/Migrations/073_ReplicaThreadQuarantine.ts
|
|
110004
|
+
/**
|
|
110005
|
+
* Threads that can never hydrate, so hydration stops retrying them.
|
|
110006
|
+
*
|
|
110007
|
+
* A thread recorded against a destroyed runtime fails its identity or
|
|
110008
|
+
* generation check forever. It is never inserted, so it never becomes "known",
|
|
110009
|
+
* so the next boot fetches and fails it again. Measured on a production sprite:
|
|
110010
|
+
* 24 such threads, retried on every one of three boots.
|
|
110011
|
+
*
|
|
110012
|
+
* Keyed by thread alone, not by runtime: the whole point is that the runtime
|
|
110013
|
+
* that recorded the row is gone.
|
|
110014
|
+
*/
|
|
110015
|
+
var _073_ReplicaThreadQuarantine_default = require_Schema$1.gen(function* () {
|
|
110016
|
+
yield* (yield* require_SqlError.SqlClient)`
|
|
110017
|
+
CREATE TABLE IF NOT EXISTS replica_thread_quarantine (
|
|
110018
|
+
thread_id TEXT NOT NULL PRIMARY KEY,
|
|
110019
|
+
detail TEXT NOT NULL,
|
|
110020
|
+
quarantined_at TEXT NOT NULL
|
|
110021
|
+
)
|
|
110022
|
+
`;
|
|
110023
|
+
});
|
|
110024
|
+
//#endregion
|
|
109940
110025
|
//#region src/persistence/Migrations.ts
|
|
109941
110026
|
/**
|
|
109942
110027
|
* MigrationsLive - Migration runner with inline loader
|
|
@@ -110317,6 +110402,11 @@ const migrationEntries = [
|
|
|
110317
110402
|
72,
|
|
110318
110403
|
"ProjectDefaultThreadEnvMode",
|
|
110319
110404
|
_072_ProjectDefaultThreadEnvMode_default
|
|
110405
|
+
],
|
|
110406
|
+
[
|
|
110407
|
+
73,
|
|
110408
|
+
"ReplicaThreadQuarantine",
|
|
110409
|
+
_073_ReplicaThreadQuarantine_default
|
|
110320
110410
|
]
|
|
110321
110411
|
];
|
|
110322
110412
|
const makeMigrationLoader = (throughId) => fromRecord(Object.fromEntries(migrationEntries.filter(([id]) => throughId === void 0 || id <= throughId).map(([id, name, migration]) => [`${id}_${name}`, migration])));
|
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 os, { 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";
|
|
@@ -48656,7 +48656,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
48656
48656
|
const min = forceColor || 0;
|
|
48657
48657
|
if (env.TERM === "dumb") return min;
|
|
48658
48658
|
if (process$1.platform === "win32") {
|
|
48659
|
-
const osRelease =
|
|
48659
|
+
const osRelease = os.release().split(".");
|
|
48660
48660
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
48661
48661
|
return 1;
|
|
48662
48662
|
}
|
|
@@ -51099,7 +51099,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
51099
51099
|
exports.processDetector = void 0;
|
|
51100
51100
|
const api_1 = (init_esm$1(), __toCommonJS(esm_exports$1));
|
|
51101
51101
|
const semconv_1 = require_semconv$1();
|
|
51102
|
-
const os$
|
|
51102
|
+
const os$4 = __require("os");
|
|
51103
51103
|
/**
|
|
51104
51104
|
* ProcessDetector will be used to detect the resources related current process running
|
|
51105
51105
|
* and being instrumented from the NodeJS Process module.
|
|
@@ -51121,7 +51121,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
51121
51121
|
};
|
|
51122
51122
|
if (process.argv.length > 1) attributes[semconv_1.ATTR_PROCESS_COMMAND] = process.argv[1];
|
|
51123
51123
|
try {
|
|
51124
|
-
const userInfo = os$
|
|
51124
|
+
const userInfo = os$4.userInfo();
|
|
51125
51125
|
attributes[semconv_1.ATTR_PROCESS_OWNER] = userInfo.username;
|
|
51126
51126
|
} catch (e) {
|
|
51127
51127
|
api_1.diag.debug(`error obtaining process owner: ${e}`);
|
|
@@ -64044,7 +64044,7 @@ function normalizeNumberish(value) {
|
|
|
64044
64044
|
}
|
|
64045
64045
|
//#endregion
|
|
64046
64046
|
//#region package.json
|
|
64047
|
-
var version$1 = "0.9.9-rc.
|
|
64047
|
+
var version$1 = "0.9.9-rc.2";
|
|
64048
64048
|
//#endregion
|
|
64049
64049
|
//#region src/sentry.ts
|
|
64050
64050
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -72623,7 +72623,7 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
72623
72623
|
var fs$6 = __require("fs");
|
|
72624
72624
|
var path$5 = __require("path");
|
|
72625
72625
|
var url$1 = __require("url");
|
|
72626
|
-
var os$
|
|
72626
|
+
var os$3 = __require("os");
|
|
72627
72627
|
var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
72628
72628
|
var vars = process.config && process.config.variables || {};
|
|
72629
72629
|
var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
|
|
@@ -72631,8 +72631,8 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
72631
72631
|
var abi = versions.modules;
|
|
72632
72632
|
if (versions.deno || process.isBun) abi = "unsupported";
|
|
72633
72633
|
var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
|
|
72634
|
-
var arch = process.env.npm_config_arch || os$
|
|
72635
|
-
var platform = process.env.npm_config_platform || os$
|
|
72634
|
+
var arch = process.env.npm_config_arch || os$3.arch();
|
|
72635
|
+
var platform = process.env.npm_config_platform || os$3.platform();
|
|
72636
72636
|
var libc = process.env.LIBC || (isMusl(platform) ? "musl" : "glibc");
|
|
72637
72637
|
var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || "";
|
|
72638
72638
|
var uv = (versions.uv || "").split(".")[0];
|
|
@@ -90267,7 +90267,7 @@ const launchDetached = (launch) => gen(function* () {
|
|
|
90267
90267
|
});
|
|
90268
90268
|
const OpenLive = effect(Open, gen(function* () {
|
|
90269
90269
|
const open = yield* tryPromise({
|
|
90270
|
-
try: () => import("./open-
|
|
90270
|
+
try: () => import("./open-FIgTDosf.mjs"),
|
|
90271
90271
|
catch: (cause) => new OpenError$1({
|
|
90272
90272
|
message: "failed to load browser opener",
|
|
90273
90273
|
cause
|
|
@@ -91787,6 +91787,31 @@ function describeHydrationOutcome(outcome) {
|
|
|
91787
91787
|
};
|
|
91788
91788
|
}
|
|
91789
91789
|
//#endregion
|
|
91790
|
+
//#region src/runtimeReplication/replicaThreadQuarantine.ts
|
|
91791
|
+
/**
|
|
91792
|
+
* Which replica threads hydration should stop retrying.
|
|
91793
|
+
*
|
|
91794
|
+
* A thread that fails its identity or generation check was recorded against a
|
|
91795
|
+
* runtime that no longer exists. Nothing about a later boot changes that, and
|
|
91796
|
+
* because a failed thread is never inserted it never becomes "known", so the
|
|
91797
|
+
* next boot fetches and fails it again. Measured on a production sprite: 24
|
|
91798
|
+
* such threads retried on every one of three boots.
|
|
91799
|
+
*
|
|
91800
|
+
* Quarantine is deliberately NARROW. Only a permanent failure qualifies. A
|
|
91801
|
+
* thread that merely disappeared may come back, and a project that does not
|
|
91802
|
+
* resolve to an active workspace starts resolving the moment that project is
|
|
91803
|
+
* imported. Quarantining either would turn a recoverable gap into a permanent
|
|
91804
|
+
* one, which is worse than the retry it saves.
|
|
91805
|
+
*/
|
|
91806
|
+
/** The one failure that a later boot can never turn into a success. */
|
|
91807
|
+
const PERMANENT_FAILURE = "failed identity or generation checks";
|
|
91808
|
+
function isQuarantinedReplicaThread(quarantined, threadId) {
|
|
91809
|
+
return quarantined.has(threadId);
|
|
91810
|
+
}
|
|
91811
|
+
function shouldQuarantineReplicaThread(detail) {
|
|
91812
|
+
return detail.includes(PERMANENT_FAILURE);
|
|
91813
|
+
}
|
|
91814
|
+
//#endregion
|
|
91790
91815
|
//#region src/runtimeReplication/replicaHydrationIdentity.ts
|
|
91791
91816
|
function stableReplicaDigest(...values) {
|
|
91792
91817
|
return Crypto.createHash("sha256").update(values.join("\0")).digest("base64url");
|
|
@@ -92166,6 +92191,10 @@ const prepareReplicaSummary = fn$1("prepareReplicaSummary")(function* (expectedR
|
|
|
92166
92191
|
state.skippedExisting += 1;
|
|
92167
92192
|
return;
|
|
92168
92193
|
}
|
|
92194
|
+
if (isQuarantinedReplicaThread(state.quarantinedThreadIds, summary.threadId)) {
|
|
92195
|
+
state.skippedQuarantined += 1;
|
|
92196
|
+
return;
|
|
92197
|
+
}
|
|
92169
92198
|
const localResolution = yield* resolveLocalReplicaProjects(state, index, summary, dependencies);
|
|
92170
92199
|
const localProjects = localResolution.projects;
|
|
92171
92200
|
if (localProjects.length !== 1) return yield* replicaHydrationFailure("replica project '" + summary.projectId + "' does not resolve to one active workspace");
|
|
@@ -92206,13 +92235,18 @@ const prepareReplicaSummary = fn$1("prepareReplicaSummary")(function* (expectedR
|
|
|
92206
92235
|
* repeated cursor) stay fatal on purpose: those mean the index itself cannot be
|
|
92207
92236
|
* trusted, so continuing would hydrate an unknown mixture.
|
|
92208
92237
|
*/
|
|
92209
|
-
function skipUnhydratableThread(operation, threadId, state) {
|
|
92238
|
+
function skipUnhydratableThread(operation, threadId, state, dependencies) {
|
|
92210
92239
|
return operation.pipe(catchTag("RuntimeReplicaHydrationError", (error) => gen(function* () {
|
|
92211
92240
|
state.unhydratableThreadIds.push(threadId);
|
|
92212
92241
|
yield* logWarning$1("skipped a thread that could not be hydrated", {
|
|
92213
92242
|
threadId,
|
|
92214
92243
|
detail: error.detail
|
|
92215
92244
|
});
|
|
92245
|
+
if (!shouldQuarantineReplicaThread(error.detail)) return;
|
|
92246
|
+
yield* dependencies.quarantineThread({
|
|
92247
|
+
threadId,
|
|
92248
|
+
detail: error.detail
|
|
92249
|
+
}).pipe(ignore);
|
|
92216
92250
|
})));
|
|
92217
92251
|
}
|
|
92218
92252
|
const applyPreparedReplica = fn$1("applyPreparedReplica")(function* (expectedRuntimeId, prepared, state, dependencies) {
|
|
@@ -92240,7 +92274,7 @@ function prepareReplicaPages(expectedRuntimeId, cursor, state, dependencies) {
|
|
|
92240
92274
|
if (index === null) return;
|
|
92241
92275
|
if (state.runtimeIdentity === null) state.runtimeIdentity = index.runtime;
|
|
92242
92276
|
else if (!replicaRuntimeMatches(state.runtimeIdentity, index.runtime)) return yield* replicaHydrationFailure("index runtime identity changed between pages");
|
|
92243
|
-
yield* forEach(index.threads, (summary) => skipUnhydratableThread(prepareReplicaSummary(expectedRuntimeId, index, summary, state, dependencies), summary.threadId, state), {
|
|
92277
|
+
yield* forEach(index.threads, (summary) => skipUnhydratableThread(prepareReplicaSummary(expectedRuntimeId, index, summary, state, dependencies), summary.threadId, state, dependencies), {
|
|
92244
92278
|
concurrency: 1,
|
|
92245
92279
|
discard: true
|
|
92246
92280
|
});
|
|
@@ -92261,16 +92295,19 @@ const hydrateRuntimeReplica = fn$1("hydrateRuntimeReplica")(function* (input, de
|
|
|
92261
92295
|
runtimeIdentity: null,
|
|
92262
92296
|
hydrated: 0,
|
|
92263
92297
|
skippedExisting: 0,
|
|
92298
|
+
skippedQuarantined: 0,
|
|
92299
|
+
quarantinedThreadIds: yield* dependencies.readQuarantinedThreadIds().pipe(orElseSucceed(() => /* @__PURE__ */ new Set())),
|
|
92264
92300
|
unhydratableThreadIds: []
|
|
92265
92301
|
};
|
|
92266
92302
|
yield* prepareReplicaPages(input.expectedRuntimeId, void 0, state, dependencies);
|
|
92267
|
-
yield* forEach(state.prepared, (prepared) => skipUnhydratableThread(applyPreparedReplica(input.expectedRuntimeId, prepared, state, dependencies), prepared.summary.threadId, state), {
|
|
92303
|
+
yield* forEach(state.prepared, (prepared) => skipUnhydratableThread(applyPreparedReplica(input.expectedRuntimeId, prepared, state, dependencies), prepared.summary.threadId, state, dependencies), {
|
|
92268
92304
|
concurrency: 1,
|
|
92269
92305
|
discard: true
|
|
92270
92306
|
});
|
|
92271
92307
|
const outcome = {
|
|
92272
92308
|
hydrated: state.hydrated,
|
|
92273
92309
|
skippedExisting: state.skippedExisting,
|
|
92310
|
+
skippedQuarantined: state.skippedQuarantined,
|
|
92274
92311
|
skippedUnhydratable: state.unhydratableThreadIds.length,
|
|
92275
92312
|
unhydratableThreadIds: [...state.unhydratableThreadIds]
|
|
92276
92313
|
};
|
|
@@ -92325,6 +92362,29 @@ async function requestReplicaRead(input, fetchImpl = fetch) {
|
|
|
92325
92362
|
}
|
|
92326
92363
|
}
|
|
92327
92364
|
//#endregion
|
|
92365
|
+
//#region src/runtimeReplication/replicaThreadQuarantineStore.ts
|
|
92366
|
+
/**
|
|
92367
|
+
* Durable record of replica threads that can never hydrate.
|
|
92368
|
+
*
|
|
92369
|
+
* Lives on the guest rather than in CMMD's replica because CMMD exposes no
|
|
92370
|
+
* write surface for it. That bounds what this can fix: it stops one Environment
|
|
92371
|
+
* re-fetching known-dead threads on every boot, and it does NOT remove the rows
|
|
92372
|
+
* from durable history, so a fresh Environment pays the cost once again.
|
|
92373
|
+
*/
|
|
92374
|
+
const makeReplicaThreadQuarantineStore = gen(function* () {
|
|
92375
|
+
const sql = yield* SqlClient;
|
|
92376
|
+
const readQuarantinedThreadIds = () => sql`SELECT thread_id FROM replica_thread_quarantine`.pipe(map$3((rows) => new Set(rows.map((row) => row.thread_id))), mapError((cause) => replicaHydrationFailure("quarantine read failed", cause)));
|
|
92377
|
+
const quarantineThread = (input) => sql`
|
|
92378
|
+
INSERT INTO replica_thread_quarantine (thread_id, detail, quarantined_at)
|
|
92379
|
+
VALUES (${input.threadId}, ${input.detail}, ${(/* @__PURE__ */ new Date()).toISOString()})
|
|
92380
|
+
ON CONFLICT (thread_id) DO NOTHING
|
|
92381
|
+
`.pipe(asVoid, mapError((cause) => replicaHydrationFailure("quarantine write failed", cause)));
|
|
92382
|
+
return {
|
|
92383
|
+
readQuarantinedThreadIds,
|
|
92384
|
+
quarantineThread
|
|
92385
|
+
};
|
|
92386
|
+
});
|
|
92387
|
+
//#endregion
|
|
92328
92388
|
//#region src/runtimeReplication/replicaHydrationCloud.ts
|
|
92329
92389
|
const REPLICA_INDEX_PAGE_SIZE = 100;
|
|
92330
92390
|
const registerCloudRuntimeForReplicaHydration = gen(function* () {
|
|
@@ -92361,6 +92421,7 @@ const hydrateCloudRuntimeReplica = gen(function* () {
|
|
|
92361
92421
|
}),
|
|
92362
92422
|
catch: (cause) => replicaHydrationFailure("runtime replica read failed", cause)
|
|
92363
92423
|
});
|
|
92424
|
+
const quarantine = yield* makeReplicaThreadQuarantineStore;
|
|
92364
92425
|
const dependencies = {
|
|
92365
92426
|
dispatch: (command) => engine.dispatch(command).pipe(mapError((cause) => replicaHydrationFailure("orchestration dispatch failed", cause))),
|
|
92366
92427
|
getReadModel: engine.getReadModel,
|
|
@@ -92368,6 +92429,8 @@ const hydrateCloudRuntimeReplica = gen(function* () {
|
|
|
92368
92429
|
readThread: ({ threadId }) => request({ threadId }),
|
|
92369
92430
|
restoreThreadCursor: (input) => outbox.restoreThreadCursor(input).pipe(mapError((cause) => replicaHydrationFailure("cursor restore failed", cause))),
|
|
92370
92431
|
resolveProjectRepositoryFullName: (workspaceRoot) => repositoryIdentityResolver.resolve(workspaceRoot).pipe(map$3((identity) => identity?.owner && identity.name ? `${identity.owner}/${identity.name}` : null), mapError((cause) => replicaHydrationFailure("repository identity resolution failed", cause))),
|
|
92432
|
+
readQuarantinedThreadIds: quarantine.readQuarantinedThreadIds,
|
|
92433
|
+
quarantineThread: quarantine.quarantineThread,
|
|
92371
92434
|
now: () => (/* @__PURE__ */ new Date()).toISOString()
|
|
92372
92435
|
};
|
|
92373
92436
|
return yield* hydrateRuntimeReplica({ expectedRuntimeId: grant.runtimeId }, dependencies);
|
|
@@ -109614,6 +109677,28 @@ var _072_ProjectDefaultThreadEnvMode_default = gen(function* () {
|
|
|
109614
109677
|
`;
|
|
109615
109678
|
});
|
|
109616
109679
|
//#endregion
|
|
109680
|
+
//#region src/persistence/Migrations/073_ReplicaThreadQuarantine.ts
|
|
109681
|
+
/**
|
|
109682
|
+
* Threads that can never hydrate, so hydration stops retrying them.
|
|
109683
|
+
*
|
|
109684
|
+
* A thread recorded against a destroyed runtime fails its identity or
|
|
109685
|
+
* generation check forever. It is never inserted, so it never becomes "known",
|
|
109686
|
+
* so the next boot fetches and fails it again. Measured on a production sprite:
|
|
109687
|
+
* 24 such threads, retried on every one of three boots.
|
|
109688
|
+
*
|
|
109689
|
+
* Keyed by thread alone, not by runtime: the whole point is that the runtime
|
|
109690
|
+
* that recorded the row is gone.
|
|
109691
|
+
*/
|
|
109692
|
+
var _073_ReplicaThreadQuarantine_default = gen(function* () {
|
|
109693
|
+
yield* (yield* SqlClient)`
|
|
109694
|
+
CREATE TABLE IF NOT EXISTS replica_thread_quarantine (
|
|
109695
|
+
thread_id TEXT NOT NULL PRIMARY KEY,
|
|
109696
|
+
detail TEXT NOT NULL,
|
|
109697
|
+
quarantined_at TEXT NOT NULL
|
|
109698
|
+
)
|
|
109699
|
+
`;
|
|
109700
|
+
});
|
|
109701
|
+
//#endregion
|
|
109617
109702
|
//#region src/persistence/Migrations.ts
|
|
109618
109703
|
/**
|
|
109619
109704
|
* MigrationsLive - Migration runner with inline loader
|
|
@@ -109994,6 +110079,11 @@ const migrationEntries = [
|
|
|
109994
110079
|
72,
|
|
109995
110080
|
"ProjectDefaultThreadEnvMode",
|
|
109996
110081
|
_072_ProjectDefaultThreadEnvMode_default
|
|
110082
|
+
],
|
|
110083
|
+
[
|
|
110084
|
+
73,
|
|
110085
|
+
"ReplicaThreadQuarantine",
|
|
110086
|
+
_073_ReplicaThreadQuarantine_default
|
|
109997
110087
|
]
|
|
109998
110088
|
];
|
|
109999
110089
|
const makeMigrationLoader = (throughId) => fromRecord(Object.fromEntries(migrationEntries.filter(([id]) => throughId === void 0 || id <= throughId).map(([id, name, migration]) => [`${id}_${name}`, migration])));
|
|
@@ -182748,7 +182838,7 @@ var Vce = {
|
|
|
182748
182838
|
function Ve() {
|
|
182749
182839
|
return Vce;
|
|
182750
182840
|
}
|
|
182751
|
-
var Us =
|
|
182841
|
+
var Us = os.homedir(), lk = os.tmpdir(), { env: Vc } = process$1, Yce = (e) => {
|
|
182752
182842
|
let t = path.join(Us, "Library");
|
|
182753
182843
|
return {
|
|
182754
182844
|
data: path.join(t, "Application Support", e),
|
|
@@ -192948,12 +193038,12 @@ function qZ(e, t) {
|
|
|
192948
193038
|
}
|
|
192949
193039
|
return n;
|
|
192950
193040
|
}
|
|
192951
|
-
var os$
|
|
193041
|
+
var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
192952
193042
|
{
|
|
192953
193043
|
matches: (e) => e.path === "permissions.defaultMode" && e.code === "invalid_value",
|
|
192954
193044
|
tip: {
|
|
192955
193045
|
suggestion: "Valid modes: \"acceptEdits\" (ask before file changes), \"plan\" (analysis only), \"bypassPermissions\" (auto-accept all), or \"default\" (standard behavior)",
|
|
192956
|
-
docLink: `${os$
|
|
193046
|
+
docLink: `${os$2}/iam#permission-modes`
|
|
192957
193047
|
}
|
|
192958
193048
|
},
|
|
192959
193049
|
{
|
|
@@ -192968,7 +193058,7 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
|
|
|
192968
193058
|
matches: (e) => e.path.startsWith("env.") && e.code === "invalid_type",
|
|
192969
193059
|
tip: {
|
|
192970
193060
|
suggestion: "Environment variables must be strings. Wrap numbers and booleans in quotes. Example: \"DEBUG\": \"true\", \"PORT\": \"3000\"",
|
|
192971
|
-
docLink: `${os$
|
|
193061
|
+
docLink: `${os$2}/settings#environment-variables`
|
|
192972
193062
|
}
|
|
192973
193063
|
},
|
|
192974
193064
|
{
|
|
@@ -192979,14 +193069,14 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
|
|
|
192979
193069
|
matches: (e) => e.path.startsWith("hooks.") && e.code === "invalid_key",
|
|
192980
193070
|
tip: {
|
|
192981
193071
|
suggestion: "Not a recognized hook event. Common events: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, SessionEnd, Stop. Check spelling and capitalization.",
|
|
192982
|
-
docLink: `${os$
|
|
193072
|
+
docLink: `${os$2}/hooks`
|
|
192983
193073
|
}
|
|
192984
193074
|
},
|
|
192985
193075
|
{
|
|
192986
193076
|
matches: (e) => /\.hooks\.\d+\.command$/.test(e.path) && e.code === "invalid_type" && e.received === "undefined",
|
|
192987
193077
|
tip: {
|
|
192988
193078
|
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\"}.",
|
|
192989
|
-
docLink: `${os$
|
|
193079
|
+
docLink: `${os$2}/hooks#exec-form-and-shell-form`
|
|
192990
193080
|
}
|
|
192991
193081
|
},
|
|
192992
193082
|
{
|
|
@@ -193001,7 +193091,7 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
|
|
|
193001
193091
|
matches: (e) => e.code === "unrecognized_keys",
|
|
193002
193092
|
tip: {
|
|
193003
193093
|
suggestion: "Check for typos or refer to the documentation for valid fields",
|
|
193004
|
-
docLink: `${os$
|
|
193094
|
+
docLink: `${os$2}/settings`
|
|
193005
193095
|
}
|
|
193006
193096
|
},
|
|
193007
193097
|
{
|
|
@@ -193016,13 +193106,13 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
|
|
|
193016
193106
|
matches: (e) => e.path === "permissions.additionalDirectories" && e.code === "invalid_type",
|
|
193017
193107
|
tip: {
|
|
193018
193108
|
suggestion: "Must be an array of directory paths. Example: [\"~/projects\", \"/tmp/workspace\"]. You can also use --add-dir flag or /add-dir command",
|
|
193019
|
-
docLink: `${os$
|
|
193109
|
+
docLink: `${os$2}/iam#working-directories`
|
|
193020
193110
|
}
|
|
193021
193111
|
}
|
|
193022
193112
|
], AKe = {
|
|
193023
|
-
permissions: `${os$
|
|
193024
|
-
env: `${os$
|
|
193025
|
-
hooks: `${os$
|
|
193113
|
+
permissions: `${os$2}/iam#configuring-permissions`,
|
|
193114
|
+
env: `${os$2}/settings#environment-variables`,
|
|
193115
|
+
hooks: `${os$2}/hooks`
|
|
193026
193116
|
};
|
|
193027
193117
|
function GZ(e) {
|
|
193028
193118
|
let t = kKe.find((r) => r.matches(e));
|
|
@@ -257167,7 +257257,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
257167
257257
|
var dgram = __require("dgram");
|
|
257168
257258
|
var thunky = require_thunky();
|
|
257169
257259
|
var events = __require("events");
|
|
257170
|
-
var os = __require("os");
|
|
257260
|
+
var os$1 = __require("os");
|
|
257171
257261
|
var noop = function() {};
|
|
257172
257262
|
module.exports = function(opts) {
|
|
257173
257263
|
if (!opts) opts = {};
|
|
@@ -257298,14 +257388,14 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
257298
257388
|
return that;
|
|
257299
257389
|
};
|
|
257300
257390
|
function defaultInterface() {
|
|
257301
|
-
var networks = os.networkInterfaces();
|
|
257391
|
+
var networks = os$1.networkInterfaces();
|
|
257302
257392
|
var names = Object.keys(networks);
|
|
257303
257393
|
for (var i = 0; i < names.length; i++) {
|
|
257304
257394
|
var net = networks[names[i]];
|
|
257305
257395
|
for (var j = 0; j < net.length; j++) {
|
|
257306
257396
|
var iface = net[j];
|
|
257307
257397
|
if (isIPv4(iface.family) && !iface.internal) {
|
|
257308
|
-
if (os.platform() === "darwin" && names[i] === "en0") return iface.address;
|
|
257398
|
+
if (os$1.platform() === "darwin" && names[i] === "en0") return iface.address;
|
|
257309
257399
|
return "0.0.0.0";
|
|
257310
257400
|
}
|
|
257311
257401
|
}
|
|
@@ -257313,7 +257403,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
257313
257403
|
return "127.0.0.1";
|
|
257314
257404
|
}
|
|
257315
257405
|
function allInterfaces() {
|
|
257316
|
-
var networks = os.networkInterfaces();
|
|
257406
|
+
var networks = os$1.networkInterfaces();
|
|
257317
257407
|
var names = Object.keys(networks);
|
|
257318
257408
|
var res = [];
|
|
257319
257409
|
for (var i = 0; i < names.length; i++) {
|
|
@@ -308149,7 +308239,7 @@ const connectLoginCommand = make$32("login", {
|
|
|
308149
308239
|
})).json();
|
|
308150
308240
|
},
|
|
308151
308241
|
openBrowser: async (url) => {
|
|
308152
|
-
const open = (await import("./open-
|
|
308242
|
+
const open = (await import("./open-FIgTDosf.mjs")).default;
|
|
308153
308243
|
await open(url);
|
|
308154
308244
|
return true;
|
|
308155
308245
|
},
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import childProcess, { execFile } from "node:child_process";
|
|
4
4
|
import fs from "node:fs";
|
|
5
|
-
import
|
|
5
|
+
import os from "node:os";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import process from "node:process";
|
|
@@ -49,7 +49,7 @@ function isInsideContainer() {
|
|
|
49
49
|
//#region ../../node_modules/.bun/is-wsl@3.1.1/node_modules/is-wsl/index.js
|
|
50
50
|
const isWsl = () => {
|
|
51
51
|
if (process.platform !== "linux") return false;
|
|
52
|
-
if (
|
|
52
|
+
if (os.release().toLowerCase().includes("microsoft")) {
|
|
53
53
|
if (isInsideContainer()) return false;
|
|
54
54
|
return true;
|
|
55
55
|
}
|
|
@@ -589,4 +589,4 @@ defineLazyProperty(apps, "safari", () => detectPlatformBinary({ darwin: "Safari"
|
|
|
589
589
|
//#endregion
|
|
590
590
|
export { apps, open as default, openApp };
|
|
591
591
|
|
|
592
|
-
//# sourceMappingURL=open-
|
|
592
|
+
//# sourceMappingURL=open-FIgTDosf.mjs.map
|