@schoolai/shipyard 3.14.0 → 3.15.0
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/capability-detector-worker.js +5 -5
- package/dist/{chunk-OX3UY44R.js → chunk-5PBWS7BB.js} +31 -42
- package/dist/chunk-5PBWS7BB.js.map +1 -0
- package/dist/{chunk-RCEAMZVG.js → chunk-6SK6FBYC.js} +2 -2
- package/dist/{chunk-M3WBYTB3.js → chunk-AXHG3QQA.js} +16 -1
- package/dist/chunk-AXHG3QQA.js.map +1 -0
- package/dist/{chunk-T3OTZ66B.js → chunk-B7WZUKYX.js} +219 -86
- package/dist/chunk-B7WZUKYX.js.map +1 -0
- package/dist/{chunk-BUAEJNUG.js → chunk-HPDRJ4VZ.js} +3 -3
- package/dist/{chunk-BUAEJNUG.js.map → chunk-HPDRJ4VZ.js.map} +1 -1
- package/dist/{chunk-WGS7ZW6N.js → chunk-L5FQEZ6Y.js} +3 -3
- package/dist/{chunk-KUPHN3ZN.js → chunk-RHHRJR3L.js} +2 -2
- package/dist/{chunk-3KE2VDKA.js → chunk-VKY7UXTP.js} +25 -3
- package/dist/chunk-VKY7UXTP.js.map +1 -0
- package/dist/{chunk-IWBDVGD2.js → chunk-VTALUCDB.js} +2 -2
- package/dist/cursor-runner.js +3 -3
- package/dist/electron-utility.js +2 -2
- package/dist/index.js +4 -4
- package/dist/{login-HRR3T4SZ.js → login-EYGYOEXL.js} +3 -3
- package/dist/{mcp-servers-GUA5WOHO.js → mcp-servers-DSOX243C.js} +8 -2
- package/dist/{plan-backfill-QNJUWOYP.js → plan-backfill-SMJEKTMM.js} +4 -4
- package/dist/{serve-25I4ML7R.js → serve-DAP6V7SY.js} +339 -147
- package/dist/{serve-25I4ML7R.js.map → serve-DAP6V7SY.js.map} +1 -1
- package/dist/{start-O2DXLW23.js → start-AX2ZK3AY.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-3KE2VDKA.js.map +0 -1
- package/dist/chunk-M3WBYTB3.js.map +0 -1
- package/dist/chunk-OX3UY44R.js.map +0 -1
- package/dist/chunk-T3OTZ66B.js.map +0 -1
- /package/dist/{chunk-RCEAMZVG.js.map → chunk-6SK6FBYC.js.map} +0 -0
- /package/dist/{chunk-WGS7ZW6N.js.map → chunk-L5FQEZ6Y.js.map} +0 -0
- /package/dist/{chunk-KUPHN3ZN.js.map → chunk-RHHRJR3L.js.map} +0 -0
- /package/dist/{chunk-IWBDVGD2.js.map → chunk-VTALUCDB.js.map} +0 -0
- /package/dist/{login-HRR3T4SZ.js.map → login-EYGYOEXL.js.map} +0 -0
- /package/dist/{mcp-servers-GUA5WOHO.js.map → mcp-servers-DSOX243C.js.map} +0 -0
- /package/dist/{plan-backfill-QNJUWOYP.js.map → plan-backfill-SMJEKTMM.js.map} +0 -0
- /package/dist/{start-O2DXLW23.js.map → start-AX2ZK3AY.js.map} +0 -0
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
guardedSubscribe,
|
|
13
13
|
makeInitialAttemptState,
|
|
14
14
|
shutdownFileWatcherGuard
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-VKY7UXTP.js";
|
|
16
16
|
import {
|
|
17
17
|
TRAILER_SCHEMA_VERSION,
|
|
18
18
|
appendTrailerToMessage,
|
|
@@ -39,13 +39,13 @@ import {
|
|
|
39
39
|
startPlanBackfillForDaemon,
|
|
40
40
|
sync,
|
|
41
41
|
validatePeerId
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-HPDRJ4VZ.js";
|
|
43
43
|
import {
|
|
44
44
|
loadAuthToken
|
|
45
45
|
} from "./chunk-TFWDJCUJ.js";
|
|
46
46
|
import {
|
|
47
47
|
getDaemonVersion
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-L5FQEZ6Y.js";
|
|
49
49
|
import {
|
|
50
50
|
collectPriorCrashDetail,
|
|
51
51
|
getRecentWasmPanicMessages
|
|
@@ -54,6 +54,7 @@ import "./chunk-UNGAIUEX.js";
|
|
|
54
54
|
import "./chunk-WW4UGZBY.js";
|
|
55
55
|
import {
|
|
56
56
|
CHARS_PER_TOKEN,
|
|
57
|
+
CODEX_BUNDLED_VERSION,
|
|
57
58
|
CURSOR_MODEL_CATALOG,
|
|
58
59
|
PROFILE_AUTH_ADAPTERS,
|
|
59
60
|
REDACTED_THINKING_PLACEHOLDER,
|
|
@@ -167,7 +168,7 @@ import {
|
|
|
167
168
|
translateWarningNotification,
|
|
168
169
|
unresolveReviewThread,
|
|
169
170
|
writeCursorApiKeyToVault
|
|
170
|
-
} from "./chunk-
|
|
171
|
+
} from "./chunk-5PBWS7BB.js";
|
|
171
172
|
import {
|
|
172
173
|
buildNodeSpawnEnv,
|
|
173
174
|
nodeSpawnEnvOverlay,
|
|
@@ -202,8 +203,10 @@ import {
|
|
|
202
203
|
redactArgs,
|
|
203
204
|
redactEnv,
|
|
204
205
|
resolveEnabledMcpServers,
|
|
205
|
-
resolveStdioEnv
|
|
206
|
-
|
|
206
|
+
resolveStdioEnv,
|
|
207
|
+
setTelemetrySink,
|
|
208
|
+
telemeter
|
|
209
|
+
} from "./chunk-B7WZUKYX.js";
|
|
207
210
|
import {
|
|
208
211
|
atomicWriteFile,
|
|
209
212
|
findProjectRoot,
|
|
@@ -226,7 +229,7 @@ import {
|
|
|
226
229
|
createAssetResolver,
|
|
227
230
|
toSdkContent,
|
|
228
231
|
toSdkPermissionMode
|
|
229
|
-
} from "./chunk-
|
|
232
|
+
} from "./chunk-6SK6FBYC.js";
|
|
230
233
|
import {
|
|
231
234
|
AGENT_IDS,
|
|
232
235
|
AGENT_SYSTEM_CLAUDE_CODE,
|
|
@@ -408,7 +411,7 @@ import {
|
|
|
408
411
|
unsafeAssertSourceId,
|
|
409
412
|
vizFileExtension,
|
|
410
413
|
withPreferredRuntimeAuthMethod
|
|
411
|
-
} from "./chunk-
|
|
414
|
+
} from "./chunk-VTALUCDB.js";
|
|
412
415
|
import {
|
|
413
416
|
AuthGitHubCallbackRequestSchema,
|
|
414
417
|
AuthGitHubCallbackResponseSchema,
|
|
@@ -448,13 +451,15 @@ import {
|
|
|
448
451
|
PublishCreateResponseSchema,
|
|
449
452
|
ROUTES,
|
|
450
453
|
TESTED_CLAUDE_CODE_VERSION,
|
|
454
|
+
TESTED_CODEX_VERSION,
|
|
451
455
|
TurnHealthResponseSchema,
|
|
452
456
|
ValidationErrorResponseSchema,
|
|
453
457
|
VaultKeyGetResponseSchema,
|
|
454
458
|
VaultKeyPutRequestSchema,
|
|
455
459
|
VaultKeyPutResponseSchema,
|
|
456
|
-
classifyClaudeCodeCompatibility
|
|
457
|
-
|
|
460
|
+
classifyClaudeCodeCompatibility,
|
|
461
|
+
classifyCodexCompatibility
|
|
462
|
+
} from "./chunk-AXHG3QQA.js";
|
|
458
463
|
import {
|
|
459
464
|
external_exports as external_exports2
|
|
460
465
|
} from "./chunk-EHQITHQX.js";
|
|
@@ -5764,7 +5769,7 @@ function nanoid(size = 21) {
|
|
|
5764
5769
|
}
|
|
5765
5770
|
|
|
5766
5771
|
// src/services/bootstrap/signaling.ts
|
|
5767
|
-
var DAEMON_NPM_VERSION = true ? "3.
|
|
5772
|
+
var DAEMON_NPM_VERSION = true ? "3.15.0" : "unknown";
|
|
5768
5773
|
function createDaemonSignaling(config) {
|
|
5769
5774
|
const agentId = config.agentId ?? nanoid();
|
|
5770
5775
|
function send(msg) {
|
|
@@ -7123,6 +7128,12 @@ function resolveSnapshotAwareLive(s2, sessionEntry, workspaceLive, inSnapshot) {
|
|
|
7123
7128
|
};
|
|
7124
7129
|
}
|
|
7125
7130
|
function buildWorkspaceRow(s2, live, transportEnabled, userEnabled) {
|
|
7131
|
+
const accountIssue = s2.source === "claudeai" && s2.authStatus === "unauthenticated" && s2.url === void 0 ? {
|
|
7132
|
+
errorType: "agent_signin_required",
|
|
7133
|
+
remediation: {
|
|
7134
|
+
message: "Re-authenticate with Claude to enable claude.ai connectors."
|
|
7135
|
+
}
|
|
7136
|
+
} : null;
|
|
7126
7137
|
return {
|
|
7127
7138
|
name: s2.name,
|
|
7128
7139
|
canonicalId: canonicalMcpServerKey(s2),
|
|
@@ -7139,6 +7150,8 @@ function buildWorkspaceRow(s2, live, transportEnabled, userEnabled) {
|
|
|
7139
7150
|
...live?.toolCount !== void 0 ? { toolCount: live.toolCount } : {},
|
|
7140
7151
|
...live?.errorType !== void 0 ? { errorType: live.errorType } : {},
|
|
7141
7152
|
...live?.remediation !== void 0 ? { remediation: live.remediation } : {},
|
|
7153
|
+
...accountIssue?.errorType !== void 0 ? { errorType: accountIssue.errorType } : {},
|
|
7154
|
+
...accountIssue?.remediation !== void 0 ? { remediation: accountIssue.remediation } : {},
|
|
7142
7155
|
...s2.sources !== void 0 ? { sources: s2.sources } : {}
|
|
7143
7156
|
};
|
|
7144
7157
|
}
|
|
@@ -8017,7 +8030,7 @@ function searchViaRipgrep(query3, jsonlPaths, signal) {
|
|
|
8017
8030
|
};
|
|
8018
8031
|
rl.on("line", (line) => {
|
|
8019
8032
|
const parsed = parseRgJsonLine(line);
|
|
8020
|
-
if (
|
|
8033
|
+
if (parsed?.type !== "match") return;
|
|
8021
8034
|
if (!isRgMatchData(parsed.data)) return;
|
|
8022
8035
|
const data = parsed.data;
|
|
8023
8036
|
const sessionId = extractSessionIdFromPath(data.path.text);
|
|
@@ -8792,7 +8805,7 @@ function parseRipgrepOutput(stdout, maxResults) {
|
|
|
8792
8805
|
for (const raw of stdout.split("\n")) {
|
|
8793
8806
|
if (raw.length === 0) continue;
|
|
8794
8807
|
const parsed = parseRgJsonLine2(raw);
|
|
8795
|
-
if (
|
|
8808
|
+
if (parsed?.type !== "match") continue;
|
|
8796
8809
|
if (!isRgMatchData2(parsed.data)) continue;
|
|
8797
8810
|
const [firstSub] = parsed.data.submatches;
|
|
8798
8811
|
if (!firstSub) continue;
|
|
@@ -13393,7 +13406,7 @@ var WorktreeMachineRunner = class {
|
|
|
13393
13406
|
}
|
|
13394
13407
|
#runValidate(_input, key) {
|
|
13395
13408
|
const entry = this.#entries.get(key);
|
|
13396
|
-
if (
|
|
13409
|
+
if (entry?.state.phase !== "validating") return;
|
|
13397
13410
|
const result = this.#deps.io.validateInputs(entry.state.input);
|
|
13398
13411
|
if (!result.ok) {
|
|
13399
13412
|
this.dispatch({ type: "validation_failed", error: result.error, reason: result.reason }, key);
|
|
@@ -13450,7 +13463,7 @@ var WorktreeMachineRunner = class {
|
|
|
13450
13463
|
}
|
|
13451
13464
|
#clearSetupTimeout(key) {
|
|
13452
13465
|
const entry = this.#entries.get(key);
|
|
13453
|
-
if (!entry
|
|
13466
|
+
if (!entry?.setupTimer) return;
|
|
13454
13467
|
this.#clearTimeoutFn(entry.setupTimer);
|
|
13455
13468
|
entry.setupTimer = null;
|
|
13456
13469
|
}
|
|
@@ -13775,81 +13788,6 @@ function flattenControlChannel(v2) {
|
|
|
13775
13788
|
};
|
|
13776
13789
|
}
|
|
13777
13790
|
|
|
13778
|
-
// src/services/metrics/telemeter.ts
|
|
13779
|
-
var TELEMETERED_EVENT_NAMES = [
|
|
13780
|
-
"run_stall_timeout",
|
|
13781
|
-
"request_task_state_replay_failed",
|
|
13782
|
-
"loro_recovery_failed",
|
|
13783
|
-
"mcp_server_connect_failed",
|
|
13784
|
-
"mcp_server_needs_auth",
|
|
13785
|
-
"mcp_reconnect_failed",
|
|
13786
|
-
"mcp_reconnect_terminal",
|
|
13787
|
-
"mcp_reconnect_terminal_unsupported",
|
|
13788
|
-
"mcp_reauth_failed",
|
|
13789
|
-
"mcp_adopted_set_failed",
|
|
13790
|
-
"mcp_push_failed",
|
|
13791
|
-
"harness_mcp_registration_failed",
|
|
13792
|
-
"codex_auth_divergence_detected",
|
|
13793
|
-
"cursor_auth_divergence_detected",
|
|
13794
|
-
/**
|
|
13795
|
-
* A Codex remote-compact cycle failed with a 401 "Missing bearer" error —
|
|
13796
|
-
* the app-server lost its in-memory token during refresh-token rotation.
|
|
13797
|
-
* Emitted once per compact attempt (not per retry) so fleet dashboards can
|
|
13798
|
-
* surface the storm rate without log amplification.
|
|
13799
|
-
*/
|
|
13800
|
-
"codex_compact_auth_failure",
|
|
13801
|
-
"event_loop_stall",
|
|
13802
|
-
"machine_sleep_artifact",
|
|
13803
|
-
/**
|
|
13804
|
-
* Per-process memory from the Electron main process (`app.getAppMetrics()`).
|
|
13805
|
-
* The only source of true per-process RSS for the renderer/GPU/utility — JS
|
|
13806
|
-
* heap (browser_metrics_sample) is capped ~4GB and cannot reveal a 50GB
|
|
13807
|
-
* process. Forwarded to D1 by the daemon so runaway RAM is localizable
|
|
13808
|
-
* fleet-wide to the offending Electron process.
|
|
13809
|
-
*/
|
|
13810
|
-
"electron_app_metrics",
|
|
13811
|
-
/** Electron main cleared a wedged Squirrel.Mac staged install on launch. */
|
|
13812
|
-
"squirrel_install_stuck_recovered",
|
|
13813
|
-
/**
|
|
13814
|
-
* An ALO control-channel entry exhausted its maxDeliver retry budget
|
|
13815
|
-
* without receiving an ack. Payload: { streamId, attempts, channel: 'control' }.
|
|
13816
|
-
* Emitted via the `onDeadLetter` callback in control-channel-wiring.ts.
|
|
13817
|
-
* Complements the `alo_resend_exhausted` ERROR log event emitted by the
|
|
13818
|
-
* shell itself; this telemetry path routes it to D1 for fleet-wide
|
|
13819
|
-
* observability so silent resend exhaustion is detectable in aggregate.
|
|
13820
|
-
*/
|
|
13821
|
-
"alo_resend_exhausted",
|
|
13822
|
-
/**
|
|
13823
|
-
* An ALO control-channel shell reaped itself as an orphan — no truncating
|
|
13824
|
-
* ack landed for `orphanThresholdMs` (5 min) while its retry buffer was
|
|
13825
|
-
* non-empty, so the WHOLE buffer of unacked control messages was discarded.
|
|
13826
|
-
* This is the bulk-loss sibling of `alo_resend_exhausted` (one entry): a
|
|
13827
|
-
* reap can drop dozens of messages at once. Payload:
|
|
13828
|
-
* { streamId, discardedCount, msSinceLastAck, attempts, channel: 'control' }.
|
|
13829
|
-
* Emitted via the `onOrphanReaped` callback in control-channel-wiring.ts;
|
|
13830
|
-
* the shell also emits a matching ERROR log. Routed to D1 so silent
|
|
13831
|
-
* reconnect-time loss is detectable fleet-wide.
|
|
13832
|
-
*/
|
|
13833
|
-
"alo_shell_orphan_reaped",
|
|
13834
|
-
/**
|
|
13835
|
-
* A `task_index_snapshot` envelope serialized past the control-channel
|
|
13836
|
-
* high-water even after byte-bounded pagination — i.e. a single slim entry
|
|
13837
|
-
* alone exceeds the cap (a page is guaranteed >=1 entry for forward
|
|
13838
|
-
* progress). The control channel may drop it whole (`channel_send_dropped`).
|
|
13839
|
-
* Payload: { bytes, taskCount, limitBytes }. Surfaces the pathological
|
|
13840
|
-
* oversized-record case the byte budget cannot otherwise bound.
|
|
13841
|
-
*/
|
|
13842
|
-
"task_index_snapshot_oversized"
|
|
13843
|
-
];
|
|
13844
|
-
var TELEMETERED_EVENTS = new Set(TELEMETERED_EVENT_NAMES);
|
|
13845
|
-
var sink = null;
|
|
13846
|
-
function setTelemetrySink(fn) {
|
|
13847
|
-
sink = fn;
|
|
13848
|
-
}
|
|
13849
|
-
function telemeter(event, payload) {
|
|
13850
|
-
sink?.(event, payload);
|
|
13851
|
-
}
|
|
13852
|
-
|
|
13853
13791
|
// src/services/channels/auth/agent-auth-verifier.ts
|
|
13854
13792
|
var AUTH_CONVERGENCE_RUNTIMES = /* @__PURE__ */ new Set(["codex", "cursor", "claude-code"]);
|
|
13855
13793
|
function isAuthConvergenceRuntime(runtimeId) {
|
|
@@ -17095,7 +17033,7 @@ async function refreshPluginCapabilities(daemon, tokenStore) {
|
|
|
17095
17033
|
const userSettings = await daemon.userSettingsStore.getSettings();
|
|
17096
17034
|
const [updatedMarketplace, updatedMcp, updatedSkills] = await Promise.all([
|
|
17097
17035
|
detectMarketplacePlugins(daemon.capabilities.marketplacePlugins),
|
|
17098
|
-
import("./mcp-servers-
|
|
17036
|
+
import("./mcp-servers-DSOX243C.js").then(
|
|
17099
17037
|
(m2) => m2.detectMCPServers(
|
|
17100
17038
|
daemon.capabilities.environments,
|
|
17101
17039
|
tokenStore,
|
|
@@ -17144,6 +17082,17 @@ function runPluginOp(pluginName, marketplace, action, ctx) {
|
|
|
17144
17082
|
return;
|
|
17145
17083
|
}
|
|
17146
17084
|
logAdapter({ event: `plugin_cc_${action}_requested`, pluginName, marketplace });
|
|
17085
|
+
const claudeBinary = resolveClaudeBinaryPath(logAdapter);
|
|
17086
|
+
if (!claudeBinary) {
|
|
17087
|
+
handler.sendControl({
|
|
17088
|
+
type: action === "install" ? "plugin_cc_install_status" : "plugin_cc_uninstall_status",
|
|
17089
|
+
pluginName,
|
|
17090
|
+
marketplace,
|
|
17091
|
+
status: "error",
|
|
17092
|
+
error: "Claude Code binary not found. Reinstall Shipyard or set CLAUDE_CODE_PATH."
|
|
17093
|
+
});
|
|
17094
|
+
return;
|
|
17095
|
+
}
|
|
17147
17096
|
inFlightPluginOps.add(fullId);
|
|
17148
17097
|
if (action === "install") {
|
|
17149
17098
|
handler.sendControl({
|
|
@@ -17160,7 +17109,7 @@ function runPluginOp(pluginName, marketplace, action, ctx) {
|
|
|
17160
17109
|
status: "uninstalling"
|
|
17161
17110
|
});
|
|
17162
17111
|
}
|
|
17163
|
-
execFile8(
|
|
17112
|
+
execFile8(claudeBinary, ["plugin", action, fullId], { timeout: 6e4 }).then(async () => {
|
|
17164
17113
|
logAdapter({ event: `plugin_cc_${action}_completed`, pluginName, marketplace });
|
|
17165
17114
|
if (action === "install") {
|
|
17166
17115
|
handler.sendControl({
|
|
@@ -19233,6 +19182,10 @@ function handleLoginExit(exitCode, output, ctx) {
|
|
|
19233
19182
|
output,
|
|
19234
19183
|
reason: classification.kind
|
|
19235
19184
|
});
|
|
19185
|
+
telemeter("anthropic_login_failed", {
|
|
19186
|
+
exitCode,
|
|
19187
|
+
method: ctx.method ?? "default"
|
|
19188
|
+
});
|
|
19236
19189
|
ctx.sendStatus({
|
|
19237
19190
|
type: "anthropic_login_status",
|
|
19238
19191
|
requestId: ctx.requestId,
|
|
@@ -30199,6 +30152,14 @@ function handleMessageChannel(opts) {
|
|
|
30199
30152
|
};
|
|
30200
30153
|
}
|
|
30201
30154
|
|
|
30155
|
+
// src/services/collab/connection-lifecycle.ts
|
|
30156
|
+
function decideStaleSignal(entry, incoming) {
|
|
30157
|
+
if (!entry) return { action: "drop" };
|
|
30158
|
+
if (entry.generationId === incoming.generationId) return { action: "apply" };
|
|
30159
|
+
if (entry.lastState === "new") return { action: "reoffer", generationId: entry.generationId };
|
|
30160
|
+
return { action: "drop" };
|
|
30161
|
+
}
|
|
30162
|
+
|
|
30202
30163
|
// src/services/peer-manager.ts
|
|
30203
30164
|
function routeDataChannel(label) {
|
|
30204
30165
|
if (label === LORO_SYNC_LABEL) {
|
|
@@ -30404,12 +30365,6 @@ function installControlGuard(dc, label, machineId, log, logAdapter, dcBufferedSa
|
|
|
30404
30365
|
var HANDSHAKE_TIMEOUT_MS = 3e4;
|
|
30405
30366
|
function noopLogAdapter(_entry) {
|
|
30406
30367
|
}
|
|
30407
|
-
function decideStaleSignal(entry, incoming) {
|
|
30408
|
-
if (!entry) return { action: "drop" };
|
|
30409
|
-
if (entry.generationId === incoming.generationId) return { action: "apply" };
|
|
30410
|
-
if (entry.lastState === "new") return { action: "reoffer", generationId: entry.generationId };
|
|
30411
|
-
return { action: "drop" };
|
|
30412
|
-
}
|
|
30413
30368
|
var DISCONNECT_WATCHDOG_MS = 5e3;
|
|
30414
30369
|
var REOFFER_THROTTLE_MS = 1e3;
|
|
30415
30370
|
function createPeerManager(config) {
|
|
@@ -32799,7 +32754,7 @@ function filterEntriesToPorts(entries, cwdByPid, workspaceRoot) {
|
|
|
32799
32754
|
if (seenPorts.has(entry.port)) continue;
|
|
32800
32755
|
if (IGNORED_COMMANDS.has(entry.command.toLowerCase())) continue;
|
|
32801
32756
|
const cwd = cwdByPid.get(entry.pid);
|
|
32802
|
-
if (!cwd
|
|
32757
|
+
if (!cwd?.startsWith(workspaceRoot)) continue;
|
|
32803
32758
|
const framework = detectFramework2(entry.command);
|
|
32804
32759
|
const isDevRuntime = /^(node|python|ruby|bun|deno)$/i.test(entry.command);
|
|
32805
32760
|
if (!framework && !isDevRuntime) continue;
|
|
@@ -35321,6 +35276,15 @@ function makeBinarySender(dc, guarded) {
|
|
|
35321
35276
|
}
|
|
35322
35277
|
};
|
|
35323
35278
|
}
|
|
35279
|
+
function sendLoadedPluginPanelsToCollabPeer(dc, loadedPluginsRef) {
|
|
35280
|
+
if (loadedPluginsRef.current.length === 0) return;
|
|
35281
|
+
if (dc.readyState !== "open") return;
|
|
35282
|
+
const msg = {
|
|
35283
|
+
type: "plugin_panels_updated",
|
|
35284
|
+
plugins: loadedPluginsRef.current
|
|
35285
|
+
};
|
|
35286
|
+
dc.send(JSON.stringify(msg));
|
|
35287
|
+
}
|
|
35324
35288
|
function buildCollabRoomManager(deps) {
|
|
35325
35289
|
const {
|
|
35326
35290
|
peerRoleRegistry,
|
|
@@ -35435,12 +35399,7 @@ function buildCollabRoomManager(deps) {
|
|
|
35435
35399
|
housekeepingBarrier,
|
|
35436
35400
|
skillResolutionService: daemon.skillResolution
|
|
35437
35401
|
});
|
|
35438
|
-
|
|
35439
|
-
daemon.taskManager.broadcastControl({
|
|
35440
|
-
type: "plugin_panels_updated",
|
|
35441
|
-
plugins: loadedPluginsRef.current
|
|
35442
|
-
});
|
|
35443
|
-
}
|
|
35402
|
+
sendLoadedPluginPanelsToCollabPeer(narrow(rawChannel), loadedPluginsRef);
|
|
35444
35403
|
},
|
|
35445
35404
|
onTaskMessageChannel: (machineId, rawChannel, taskId) => {
|
|
35446
35405
|
if (!isTaskMessageChannelAllowed(taskId, collabTaskId)) {
|
|
@@ -36888,7 +36847,7 @@ function buildOutgoingMessage(report) {
|
|
|
36888
36847
|
...report.previousVersion ? { previousVersion: report.previousVersion } : {}
|
|
36889
36848
|
};
|
|
36890
36849
|
}
|
|
36891
|
-
function wireUpdateStatusForwarding(report,
|
|
36850
|
+
function wireUpdateStatusForwarding(report, sink, onMessage, log) {
|
|
36892
36851
|
if (!report) return;
|
|
36893
36852
|
let sent = false;
|
|
36894
36853
|
let unsub = null;
|
|
@@ -36896,7 +36855,7 @@ function wireUpdateStatusForwarding(report, sink2, onMessage, log) {
|
|
|
36896
36855
|
if (sent) return;
|
|
36897
36856
|
if (msg.type !== "authenticated") return;
|
|
36898
36857
|
try {
|
|
36899
|
-
|
|
36858
|
+
sink.send(buildOutgoingMessage(report));
|
|
36900
36859
|
} catch (err3) {
|
|
36901
36860
|
log?.warn({ err: err3 }, "update-status forward failed; will retry on next authenticated");
|
|
36902
36861
|
return;
|
|
@@ -53350,7 +53309,7 @@ var McpCoordinator = class {
|
|
|
53350
53309
|
if (snap.state !== "disabled") continue;
|
|
53351
53310
|
if (this.#disabledNames.has(snap.name)) continue;
|
|
53352
53311
|
const resolved = this.#resolvedByName.get(snap.name);
|
|
53353
|
-
if (
|
|
53312
|
+
if (resolved?.transport !== "stdio") continue;
|
|
53354
53313
|
this.#deps.log({ event: "mcp_stdio_adoption_recovery", serverName: snap.name });
|
|
53355
53314
|
this.#registry.dispatch(snap.name, { type: "enable", config: resolved });
|
|
53356
53315
|
}
|
|
@@ -55223,7 +55182,7 @@ async function handleProxyHttpRequest(opts) {
|
|
|
55223
55182
|
return;
|
|
55224
55183
|
}
|
|
55225
55184
|
const authHeader = opts.req.headers.authorization;
|
|
55226
|
-
if (!authHeader
|
|
55185
|
+
if (!authHeader?.toLowerCase().startsWith("bearer ")) {
|
|
55227
55186
|
await respondProxyError(
|
|
55228
55187
|
opts.req,
|
|
55229
55188
|
opts.res,
|
|
@@ -55822,7 +55781,7 @@ async function buildMcpCoordinator(input) {
|
|
|
55822
55781
|
resolveServerUrl: (name) => {
|
|
55823
55782
|
const caps = input.getCapabilities();
|
|
55824
55783
|
const server = caps?.mcpServers?.find((s2) => s2.name === name);
|
|
55825
|
-
if (!server
|
|
55784
|
+
if (!server?.url) return null;
|
|
55826
55785
|
const out = { url: server.url };
|
|
55827
55786
|
if (server.oauth?.callbackPort !== void 0 && server.oauth.callbackPort > 0) {
|
|
55828
55787
|
out.callbackPort = server.oauth.callbackPort;
|
|
@@ -55942,6 +55901,13 @@ var DEFAULT_THRESHOLD_MS = 250;
|
|
|
55942
55901
|
var DEFAULT_INTERVAL_MS4 = 100;
|
|
55943
55902
|
var MACHINE_SLEEP_ARTIFACT_LAG_MS = 6e4;
|
|
55944
55903
|
var ATTRIBUTION_EPSILON_MS = 100;
|
|
55904
|
+
var lastMachineSleepArtifactAtMs = 0;
|
|
55905
|
+
function markMachineSleepArtifact(atMs) {
|
|
55906
|
+
lastMachineSleepArtifactAtMs = atMs;
|
|
55907
|
+
}
|
|
55908
|
+
function didMachineSleepArtifactOccurSince(sinceMs) {
|
|
55909
|
+
return lastMachineSleepArtifactAtMs > sinceMs;
|
|
55910
|
+
}
|
|
55945
55911
|
var EventLoopWatchdog = class {
|
|
55946
55912
|
#log;
|
|
55947
55913
|
#thresholdMs;
|
|
@@ -56005,6 +55971,7 @@ var EventLoopWatchdog = class {
|
|
|
56005
55971
|
...cause.attributedLabel !== void 0 && { attributedLabel: cause.attributedLabel }
|
|
56006
55972
|
};
|
|
56007
55973
|
if (lag > MACHINE_SLEEP_ARTIFACT_LAG_MS) {
|
|
55974
|
+
markMachineSleepArtifact(now);
|
|
56008
55975
|
this.#log({ event: "machine_sleep_artifact", ...payload });
|
|
56009
55976
|
telemeter("machine_sleep_artifact", payload);
|
|
56010
55977
|
return;
|
|
@@ -56072,12 +56039,14 @@ var HealthMetrics = class {
|
|
|
56072
56039
|
};
|
|
56073
56040
|
hist.reset();
|
|
56074
56041
|
const nowMs = Date.now();
|
|
56042
|
+
const windowStartMs = this.#lastCpuSampleAtMs;
|
|
56075
56043
|
const cpuDelta = process.cpuUsage(this.#lastCpuUsage ?? void 0);
|
|
56076
56044
|
const cpu = {
|
|
56077
56045
|
userMs: cpuDelta.user / 1e3,
|
|
56078
56046
|
systemMs: cpuDelta.system / 1e3,
|
|
56079
|
-
windowMs:
|
|
56047
|
+
windowMs: windowStartMs > 0 ? nowMs - windowStartMs : 0
|
|
56080
56048
|
};
|
|
56049
|
+
const postSleepArtifact = windowStartMs > 0 && (didMachineSleepArtifactOccurSince(windowStartMs) || cpu.windowMs - this.#intervalMs > MACHINE_SLEEP_ARTIFACT_LAG_MS);
|
|
56081
56050
|
this.#lastCpuUsage = process.cpuUsage();
|
|
56082
56051
|
this.#lastCpuSampleAtMs = nowMs;
|
|
56083
56052
|
return {
|
|
@@ -56098,7 +56067,8 @@ var HealthMetrics = class {
|
|
|
56098
56067
|
canvas: this.#canvasDocsCache.cachedDocCount
|
|
56099
56068
|
},
|
|
56100
56069
|
eventLoop,
|
|
56101
|
-
cpu
|
|
56070
|
+
cpu,
|
|
56071
|
+
postSleepArtifact
|
|
56102
56072
|
};
|
|
56103
56073
|
}
|
|
56104
56074
|
#emitSnapshot() {
|
|
@@ -56124,6 +56094,7 @@ var HealthMetrics = class {
|
|
|
56124
56094
|
cpuUserMs: snap.cpu.userMs,
|
|
56125
56095
|
cpuSystemMs: snap.cpu.systemMs,
|
|
56126
56096
|
cpuWindowMs: snap.cpu.windowMs,
|
|
56097
|
+
...snap.postSleepArtifact && { postSleepArtifact: true },
|
|
56127
56098
|
windowEpoch
|
|
56128
56099
|
});
|
|
56129
56100
|
this.#metricsCollector.capture("health_snapshot", {
|
|
@@ -56137,7 +56108,8 @@ var HealthMetrics = class {
|
|
|
56137
56108
|
loroCanvasDocCount: snap.loroDocs.canvas,
|
|
56138
56109
|
eventLoopP99Ms: snap.eventLoop.p99,
|
|
56139
56110
|
cpuUserMs: snap.cpu.userMs,
|
|
56140
|
-
cpuSystemMs: snap.cpu.systemMs
|
|
56111
|
+
cpuSystemMs: snap.cpu.systemMs,
|
|
56112
|
+
...snap.postSleepArtifact && { postSleepArtifact: true }
|
|
56141
56113
|
});
|
|
56142
56114
|
}
|
|
56143
56115
|
};
|
|
@@ -60090,7 +60062,7 @@ var ScheduleEvaluator = class {
|
|
|
60090
60062
|
}
|
|
60091
60063
|
async #fireSchedule(schedule) {
|
|
60092
60064
|
const freshSchedule = await this.#deps.loadSchedule(schedule.id);
|
|
60093
|
-
if (!freshSchedule
|
|
60065
|
+
if (!freshSchedule?.enabled) {
|
|
60094
60066
|
this.#deps.log({
|
|
60095
60067
|
event: "schedule_fire_skipped",
|
|
60096
60068
|
scheduleId: schedule.id,
|
|
@@ -61801,8 +61773,8 @@ var CodexAppServerClient = class {
|
|
|
61801
61773
|
*
|
|
61802
61774
|
* Calling again replaces the previous sink. Pass `null` to deregister.
|
|
61803
61775
|
*/
|
|
61804
|
-
registerAccountSink(
|
|
61805
|
-
this.#accountSink =
|
|
61776
|
+
registerAccountSink(sink) {
|
|
61777
|
+
this.#accountSink = sink;
|
|
61806
61778
|
}
|
|
61807
61779
|
/**
|
|
61808
61780
|
* Register the MCP server set to be sent on the next `thread/start` call.
|
|
@@ -62350,16 +62322,16 @@ var CodexAppServerClient = class {
|
|
|
62350
62322
|
if (threadId === null) return false;
|
|
62351
62323
|
if (!this.#compactThreads.has(threadId)) return false;
|
|
62352
62324
|
if (method === CodexNotifications.error) {
|
|
62353
|
-
const
|
|
62354
|
-
if (!
|
|
62325
|
+
const sink2 = this.#threadScopedSinks(params).onError;
|
|
62326
|
+
if (!sink2) return false;
|
|
62355
62327
|
this.#compactThreads.delete(threadId);
|
|
62356
|
-
|
|
62328
|
+
sink2(params);
|
|
62357
62329
|
return true;
|
|
62358
62330
|
}
|
|
62359
62331
|
if (!isContextCompactionItemNotification(method, params)) return false;
|
|
62360
|
-
const
|
|
62361
|
-
if (!
|
|
62362
|
-
|
|
62332
|
+
const sink = this.#threadScopedSinks(params).onUnregisteredTurnEvent;
|
|
62333
|
+
if (!sink) return false;
|
|
62334
|
+
sink({ method, params });
|
|
62363
62335
|
if (method === CodexNotifications.itemCompleted) {
|
|
62364
62336
|
this.#compactThreads.delete(threadId);
|
|
62365
62337
|
}
|
|
@@ -65398,6 +65370,35 @@ function isCodexResumeThreadNotFound(err3) {
|
|
|
65398
65370
|
}
|
|
65399
65371
|
|
|
65400
65372
|
// src/services/session/codex-subprocess-facade.ts
|
|
65373
|
+
function detectedCodexVersionForLog(input) {
|
|
65374
|
+
const { detectedCodexVersion, compatibility } = input;
|
|
65375
|
+
switch (compatibility.status) {
|
|
65376
|
+
case "compatible":
|
|
65377
|
+
return detectedCodexVersion ?? null;
|
|
65378
|
+
case "untested":
|
|
65379
|
+
return compatibility.detected;
|
|
65380
|
+
case "unknown":
|
|
65381
|
+
return detectedCodexVersion ?? null;
|
|
65382
|
+
default: {
|
|
65383
|
+
const _exhaustive = compatibility;
|
|
65384
|
+
return _exhaustive;
|
|
65385
|
+
}
|
|
65386
|
+
}
|
|
65387
|
+
}
|
|
65388
|
+
function formatCodexSpawnFailureMessage(input) {
|
|
65389
|
+
const { detail, compatibility } = input;
|
|
65390
|
+
switch (compatibility.status) {
|
|
65391
|
+
case "compatible":
|
|
65392
|
+
case "unknown":
|
|
65393
|
+
return `Codex spawn failed: ${detail}`;
|
|
65394
|
+
case "untested":
|
|
65395
|
+
return `Codex spawn failed: codex version mismatch; update Shipyard bundled Codex (detected ${compatibility.detected}, tested ${compatibility.tested}). Original error: ${detail}`;
|
|
65396
|
+
default: {
|
|
65397
|
+
const _exhaustive = compatibility;
|
|
65398
|
+
return _exhaustive;
|
|
65399
|
+
}
|
|
65400
|
+
}
|
|
65401
|
+
}
|
|
65401
65402
|
function createCodexSubprocessFacade(options, log) {
|
|
65402
65403
|
const pending = [];
|
|
65403
65404
|
let inner = null;
|
|
@@ -65483,9 +65484,28 @@ function createCodexSubprocessFacade(options, log) {
|
|
|
65483
65484
|
drainOnto(subprocess);
|
|
65484
65485
|
} catch (err3) {
|
|
65485
65486
|
const msg = err3 instanceof Error ? err3.message : String(err3);
|
|
65486
|
-
|
|
65487
|
+
const detectedCodexVersion = options.spawnArgs.codexVersion;
|
|
65488
|
+
const compatibility = classifyCodexCompatibility(detectedCodexVersion);
|
|
65489
|
+
const detectedForLog = detectedCodexVersionForLog({ detectedCodexVersion, compatibility });
|
|
65490
|
+
log({
|
|
65491
|
+
event: "codex_spawn_failed",
|
|
65492
|
+
detail: msg,
|
|
65493
|
+
codexVersionCompatibility: compatibility.status,
|
|
65494
|
+
detectedCodexVersion: detectedForLog,
|
|
65495
|
+
testedCodexVersion: TESTED_CODEX_VERSION,
|
|
65496
|
+
hint: compatibility.status === "untested" ? "codex version mismatch; update Shipyard bundled Codex" : null
|
|
65497
|
+
});
|
|
65498
|
+
telemeter("codex_spawn_failed", {
|
|
65499
|
+
errorName: err3 instanceof Error ? err3.name : "NonErrorThrown",
|
|
65500
|
+
codexVersionCompatibility: compatibility.status,
|
|
65501
|
+
detectedCodexVersion: detectedForLog,
|
|
65502
|
+
testedCodexVersion: TESTED_CODEX_VERSION
|
|
65503
|
+
});
|
|
65487
65504
|
spawnFailed = true;
|
|
65488
|
-
options.onEvent({
|
|
65505
|
+
options.onEvent({
|
|
65506
|
+
type: "sdk_error",
|
|
65507
|
+
error: formatCodexSpawnFailureMessage({ detail: msg, compatibility })
|
|
65508
|
+
});
|
|
65489
65509
|
options.onEvent({ type: "subprocess_died", exitCode: 1 });
|
|
65490
65510
|
}
|
|
65491
65511
|
})();
|
|
@@ -66037,7 +66057,7 @@ async function createHarnessHttpServer(opts = {}) {
|
|
|
66037
66057
|
return;
|
|
66038
66058
|
}
|
|
66039
66059
|
const authHeader = req.headers.authorization;
|
|
66040
|
-
if (!authHeader
|
|
66060
|
+
if (!authHeader?.toLowerCase().startsWith("bearer ")) {
|
|
66041
66061
|
await rejectAuth(req, res, 401, JSON_RPC_ERROR_UNAUTHORIZED, "unauthorized");
|
|
66042
66062
|
return;
|
|
66043
66063
|
}
|
|
@@ -66208,6 +66228,7 @@ function buildCodexSpawnArgs(args) {
|
|
|
66208
66228
|
});
|
|
66209
66229
|
return {
|
|
66210
66230
|
binary: spawn15.binary,
|
|
66231
|
+
...args.codexVersion !== void 0 ? { codexVersion: args.codexVersion } : {},
|
|
66211
66232
|
argv: spawn15.argv,
|
|
66212
66233
|
...spawn15.env !== void 0 ? { env: spawn15.env } : {},
|
|
66213
66234
|
stripEnv: args.stripEnv
|
|
@@ -66380,13 +66401,18 @@ function createCodexFacadeSubsystem(d) {
|
|
|
66380
66401
|
unregisterCodexFacade
|
|
66381
66402
|
});
|
|
66382
66403
|
const codexFacadesByTaskId = /* @__PURE__ */ new Map();
|
|
66404
|
+
async function resolveRequiredCodexBinary() {
|
|
66405
|
+
const binary = await codexProfile.spawn.binaryResolver();
|
|
66406
|
+
if (binary === null) throw new Error("Codex binary not resolved");
|
|
66407
|
+
return binary;
|
|
66408
|
+
}
|
|
66383
66409
|
const codexEngineRef = { current: null };
|
|
66384
66410
|
function getOrCreateCodexEngine() {
|
|
66385
66411
|
const existing = codexEngineRef.current;
|
|
66386
66412
|
if (existing !== null && !existing.isDisposed) return existing;
|
|
66387
66413
|
const engine = new CodexEngineSingleton({
|
|
66388
66414
|
resolveSpawnConfig: async () => {
|
|
66389
|
-
const binaryPath = await
|
|
66415
|
+
const binaryPath = await resolveRequiredCodexBinary();
|
|
66390
66416
|
const spawn15 = rewriteElectronNodeScriptSpawn({
|
|
66391
66417
|
binary: binaryPath,
|
|
66392
66418
|
argv: ["app-server"]
|
|
@@ -66457,7 +66483,7 @@ function createCodexFacadeSubsystem(d) {
|
|
|
66457
66483
|
state.pending.length = 0;
|
|
66458
66484
|
}
|
|
66459
66485
|
async function initCodexInner(state, input) {
|
|
66460
|
-
const binary = await
|
|
66486
|
+
const binary = await resolveRequiredCodexBinary();
|
|
66461
66487
|
const spawnCtx = {
|
|
66462
66488
|
taskId: input.args.taskId,
|
|
66463
66489
|
cwd: input.args.cwd,
|
|
@@ -66469,7 +66495,13 @@ function createCodexFacadeSubsystem(d) {
|
|
|
66469
66495
|
const argv = codexProfile.spawn.args(spawnCtx);
|
|
66470
66496
|
const envInject = codexProfile.spawn.envInject(spawnCtx);
|
|
66471
66497
|
const stripEnv = codexProfile.spawn.envStrip;
|
|
66472
|
-
const spawnArgs = buildCodexSpawnArgs({
|
|
66498
|
+
const spawnArgs = buildCodexSpawnArgs({
|
|
66499
|
+
binary,
|
|
66500
|
+
codexVersion: CODEX_BUNDLED_VERSION,
|
|
66501
|
+
argv,
|
|
66502
|
+
env: envInject,
|
|
66503
|
+
stripEnv
|
|
66504
|
+
});
|
|
66473
66505
|
const harnessReg = await input.harnessHttp.registerTask(
|
|
66474
66506
|
buildHarnessRegisterCtx({
|
|
66475
66507
|
taskId: input.args.taskId,
|
|
@@ -78858,10 +78890,10 @@ var ThreadStreamDeltaForwarder = class {
|
|
|
78858
78890
|
#sinks = /* @__PURE__ */ new Set();
|
|
78859
78891
|
#inFlight = [];
|
|
78860
78892
|
#disposed = false;
|
|
78861
|
-
addSink(
|
|
78862
|
-
this.#sinks.add(
|
|
78893
|
+
addSink(sink) {
|
|
78894
|
+
this.#sinks.add(sink);
|
|
78863
78895
|
return () => {
|
|
78864
|
-
this.#sinks.delete(
|
|
78896
|
+
this.#sinks.delete(sink);
|
|
78865
78897
|
};
|
|
78866
78898
|
}
|
|
78867
78899
|
/** Shape a stream_delta event, buffer it for replay, and fan it out to sinks. */
|
|
@@ -78909,9 +78941,9 @@ var ThreadStreamDeltaForwarder = class {
|
|
|
78909
78941
|
this.#inFlight = [];
|
|
78910
78942
|
}
|
|
78911
78943
|
#fanOut(msg) {
|
|
78912
|
-
for (const
|
|
78944
|
+
for (const sink of this.#sinks) {
|
|
78913
78945
|
try {
|
|
78914
|
-
|
|
78946
|
+
sink(msg);
|
|
78915
78947
|
} catch {
|
|
78916
78948
|
}
|
|
78917
78949
|
}
|
|
@@ -79439,8 +79471,8 @@ var Thread = class {
|
|
|
79439
79471
|
denyAllPendingPermissions(reason) {
|
|
79440
79472
|
this.#permissionHandler.denyAllPending(reason);
|
|
79441
79473
|
}
|
|
79442
|
-
addStreamDeltaSink(
|
|
79443
|
-
return this.#streamDelta.addSink(
|
|
79474
|
+
addStreamDeltaSink(sink) {
|
|
79475
|
+
return this.#streamDelta.addSink(sink);
|
|
79444
79476
|
}
|
|
79445
79477
|
getInFlightStreamDeltas() {
|
|
79446
79478
|
return this.#streamDelta.getInFlight();
|
|
@@ -81184,6 +81216,132 @@ ${diff}
|
|
|
81184
81216
|
}
|
|
81185
81217
|
}
|
|
81186
81218
|
|
|
81219
|
+
// src/services/plan-backfill/plan-storage-recovery.ts
|
|
81220
|
+
var PLAN_STORAGE_RECOVERY_MAX_ATTEMPTS = 4;
|
|
81221
|
+
var BASE_BACKOFF_MS = 750;
|
|
81222
|
+
var MAX_BACKOFF_MS = 6e3;
|
|
81223
|
+
function planStorageRecoveryBackoffMs(attempt) {
|
|
81224
|
+
return Math.min(BASE_BACKOFF_MS * 2 ** Math.max(0, attempt - 1), MAX_BACKOFF_MS);
|
|
81225
|
+
}
|
|
81226
|
+
function decidePlanStorageRecovery(state) {
|
|
81227
|
+
switch (state.outcome) {
|
|
81228
|
+
case "has-content":
|
|
81229
|
+
case "rebuilt":
|
|
81230
|
+
return { kind: "recovered" };
|
|
81231
|
+
case "no-source":
|
|
81232
|
+
return { kind: "exhausted" };
|
|
81233
|
+
case "storage-error":
|
|
81234
|
+
case "failed":
|
|
81235
|
+
return state.attempts >= state.maxAttempts ? { kind: "give_up" } : { kind: "retry" };
|
|
81236
|
+
default: {
|
|
81237
|
+
const _exhaustive = state.outcome;
|
|
81238
|
+
void _exhaustive;
|
|
81239
|
+
return { kind: "give_up" };
|
|
81240
|
+
}
|
|
81241
|
+
}
|
|
81242
|
+
}
|
|
81243
|
+
|
|
81244
|
+
// src/services/plan/plan-storage-recovery-controller.ts
|
|
81245
|
+
function defaultScheduleStorageRecovery(fn, delayMs) {
|
|
81246
|
+
const timer = setTimeout(fn, delayMs);
|
|
81247
|
+
return () => clearTimeout(timer);
|
|
81248
|
+
}
|
|
81249
|
+
var PlanStorageRecoveryController = class {
|
|
81250
|
+
#deps;
|
|
81251
|
+
/**
|
|
81252
|
+
* One-shot guard: true while a cycle is scheduled or running, so repeated
|
|
81253
|
+
* empty replays (reconnects, several viewers requesting state) cannot start
|
|
81254
|
+
* overlapping evict-and-reload loops against the live doc.
|
|
81255
|
+
*/
|
|
81256
|
+
#inFlight = false;
|
|
81257
|
+
/** Cancel handle for the pending attempt's deferred timer; null when none armed. */
|
|
81258
|
+
#cancel = null;
|
|
81259
|
+
constructor(deps) {
|
|
81260
|
+
this.#deps = deps;
|
|
81261
|
+
}
|
|
81262
|
+
/** Begin a recovery cycle for `detection`. No-op if disposed or already running. */
|
|
81263
|
+
schedule(detection) {
|
|
81264
|
+
if (this.#deps.isDisposed() || this.#inFlight) return;
|
|
81265
|
+
this.#inFlight = true;
|
|
81266
|
+
this.#deps.log({ event: "plan_storage_recovery_scheduled", taskId: this.#deps.taskId });
|
|
81267
|
+
this.#scheduleAttempt(detection, 1);
|
|
81268
|
+
}
|
|
81269
|
+
/** Cancel any pending attempt and clear the one-shot guard (dispose/rewind). */
|
|
81270
|
+
cancel() {
|
|
81271
|
+
this.#cancel?.();
|
|
81272
|
+
this.#cancel = null;
|
|
81273
|
+
this.#inFlight = false;
|
|
81274
|
+
}
|
|
81275
|
+
#scheduleAttempt(detection, attempt) {
|
|
81276
|
+
const fire = () => {
|
|
81277
|
+
this.#cancel = null;
|
|
81278
|
+
if (this.#deps.isDisposed()) {
|
|
81279
|
+
this.#inFlight = false;
|
|
81280
|
+
return;
|
|
81281
|
+
}
|
|
81282
|
+
this.#deps.enqueueAsync(() => this.#runAttempt(detection, attempt));
|
|
81283
|
+
};
|
|
81284
|
+
const schedule = this.#deps.scheduleStorageRecovery ?? defaultScheduleStorageRecovery;
|
|
81285
|
+
this.#cancel = schedule(fire, planStorageRecoveryBackoffMs(attempt));
|
|
81286
|
+
}
|
|
81287
|
+
async #runAttempt(detection, attempt) {
|
|
81288
|
+
if (this.#deps.isDisposed() || !this.#inFlight) return;
|
|
81289
|
+
const evicted = await this.#deps.planRepo.invalidate(this.#deps.taskId);
|
|
81290
|
+
if (!evicted) {
|
|
81291
|
+
this.#deps.log({
|
|
81292
|
+
event: "plan_storage_recovery_evict_blocked",
|
|
81293
|
+
taskId: this.#deps.taskId,
|
|
81294
|
+
attempt
|
|
81295
|
+
});
|
|
81296
|
+
}
|
|
81297
|
+
if (this.#deps.isDisposed() || !this.#inFlight) return;
|
|
81298
|
+
const outcome = await ensurePlanDocRebuilt({
|
|
81299
|
+
taskId: this.#deps.taskId,
|
|
81300
|
+
planRepo: this.#deps.planRepo,
|
|
81301
|
+
taskRecord: { lastPlanDetection: { filePath: detection.filePath } },
|
|
81302
|
+
dataDir: this.#deps.dataDir,
|
|
81303
|
+
shipyardHome: getShipyardHome(),
|
|
81304
|
+
log: this.#deps.log
|
|
81305
|
+
});
|
|
81306
|
+
if (this.#deps.isDisposed() || !this.#inFlight) return;
|
|
81307
|
+
const action = decidePlanStorageRecovery({
|
|
81308
|
+
outcome: outcome.kind,
|
|
81309
|
+
attempts: attempt,
|
|
81310
|
+
maxAttempts: PLAN_STORAGE_RECOVERY_MAX_ATTEMPTS
|
|
81311
|
+
});
|
|
81312
|
+
switch (action.kind) {
|
|
81313
|
+
case "recovered":
|
|
81314
|
+
this.#inFlight = false;
|
|
81315
|
+
this.#deps.log({
|
|
81316
|
+
event: "plan_storage_recovery_succeeded",
|
|
81317
|
+
taskId: this.#deps.taskId,
|
|
81318
|
+
attempt
|
|
81319
|
+
});
|
|
81320
|
+
this.#deps.reEmitPlanDetected(detection);
|
|
81321
|
+
return;
|
|
81322
|
+
case "retry":
|
|
81323
|
+
this.#scheduleAttempt(detection, attempt + 1);
|
|
81324
|
+
return;
|
|
81325
|
+
case "exhausted":
|
|
81326
|
+
case "give_up":
|
|
81327
|
+
this.#inFlight = false;
|
|
81328
|
+
this.#deps.log({
|
|
81329
|
+
event: "plan_storage_recovery_gave_up",
|
|
81330
|
+
taskId: this.#deps.taskId,
|
|
81331
|
+
attempt,
|
|
81332
|
+
reason: action.kind
|
|
81333
|
+
});
|
|
81334
|
+
return;
|
|
81335
|
+
default: {
|
|
81336
|
+
const _exhaustive = action;
|
|
81337
|
+
void _exhaustive;
|
|
81338
|
+
this.#inFlight = false;
|
|
81339
|
+
return;
|
|
81340
|
+
}
|
|
81341
|
+
}
|
|
81342
|
+
}
|
|
81343
|
+
};
|
|
81344
|
+
|
|
81187
81345
|
// src/services/plan/plan-handler.ts
|
|
81188
81346
|
var PLAN_PUBLISHED_DENY_MESSAGE = `Your plan has been published to the Shipyard canvas for collaborative review. Reviewers can comment, edit, and approve your plan in real-time. You will receive feedback as <${XML_TAGS.COMMENT}> children of the <plan> resource and plan edits as <${XML_TAGS.PLAN_UPDATE}> diffs. Wait for <${XML_TAGS.PLAN_REVIEW} decision="approve"> before calling ExitPlanMode again.`;
|
|
81189
81347
|
var PLAN_STILL_UNDER_REVIEW_MESSAGE = `Your plan is still under review. Wait for <${XML_TAGS.PLAN_REVIEW} decision="approve"> before calling ExitPlanMode again.`;
|
|
@@ -81250,8 +81408,23 @@ var PlanHandler = class {
|
|
|
81250
81408
|
* single chained promise here suffices.
|
|
81251
81409
|
*/
|
|
81252
81410
|
#codexPlanQueue = Promise.resolve();
|
|
81411
|
+
/**
|
|
81412
|
+
* #4770 storage-error recovery loop (evict + reload + re-emit). Owns its own
|
|
81413
|
+
* one-shot/timer state; cancelled on dispose/rewind. See the controller.
|
|
81414
|
+
*/
|
|
81415
|
+
#storageRecovery;
|
|
81253
81416
|
constructor(deps) {
|
|
81254
81417
|
this.#deps = deps;
|
|
81418
|
+
this.#storageRecovery = new PlanStorageRecoveryController({
|
|
81419
|
+
taskId: deps.taskId,
|
|
81420
|
+
planRepo: deps.planRepo,
|
|
81421
|
+
dataDir: deps.dataDir,
|
|
81422
|
+
isDisposed: deps.isDisposed,
|
|
81423
|
+
enqueueAsync: deps.enqueueAsync,
|
|
81424
|
+
log: deps.log,
|
|
81425
|
+
reEmitPlanDetected: (detection) => this.#reEmitPlanDetected(detection),
|
|
81426
|
+
scheduleStorageRecovery: deps.scheduleStorageRecovery
|
|
81427
|
+
});
|
|
81255
81428
|
if (deps.initialPlanDetection) {
|
|
81256
81429
|
this.#lastPlanDetection = deps.initialPlanDetection;
|
|
81257
81430
|
this.#lastPersistedPlanDetection = deps.initialPlanDetection;
|
|
@@ -81666,7 +81839,24 @@ var PlanHandler = class {
|
|
|
81666
81839
|
shipyardHome: getShipyardHome(),
|
|
81667
81840
|
log: this.#deps.log
|
|
81668
81841
|
});
|
|
81669
|
-
if (
|
|
81842
|
+
if (this.#deps.isDisposed()) return;
|
|
81843
|
+
if (outcome.kind === "storage-error") {
|
|
81844
|
+
this.#storageRecovery.schedule(detection);
|
|
81845
|
+
return;
|
|
81846
|
+
}
|
|
81847
|
+
if (outcome.kind !== "rebuilt") return;
|
|
81848
|
+
this.#reEmitPlanDetected(detection);
|
|
81849
|
+
}
|
|
81850
|
+
/**
|
|
81851
|
+
* Re-broadcast `plan_detected` carrying the plan doc's CURRENT markdown via
|
|
81852
|
+
* the durable path (current sender, else the persist queue) rather than a
|
|
81853
|
+
* captured per-peer `send`, so the populated state reaches every browser —
|
|
81854
|
+
* owner and collab viewers (`plan_detected` is collab-whitelisted) — even if
|
|
81855
|
+
* the original requester reconnected meanwhile. No-op when the doc is still
|
|
81856
|
+
* empty, so a failed recovery never emits a misleading empty re-detection.
|
|
81857
|
+
*/
|
|
81858
|
+
#reEmitPlanDetected(detection) {
|
|
81859
|
+
if (this.#deps.isDisposed()) return;
|
|
81670
81860
|
const markdown = this.#deps.planRepo.getContent(this.#deps.taskId);
|
|
81671
81861
|
if (markdown.trim() === "") return;
|
|
81672
81862
|
const msg = this.#buildPlanDetectedReplay(detection, markdown);
|
|
@@ -81715,6 +81905,7 @@ var PlanHandler = class {
|
|
|
81715
81905
|
this.#createdPlanFiles.clear();
|
|
81716
81906
|
this.#proactiveToolUseId = null;
|
|
81717
81907
|
this.#detectionInFlight = false;
|
|
81908
|
+
this.#storageRecovery.cancel();
|
|
81718
81909
|
void this.#planFileBridge?.dispose();
|
|
81719
81910
|
this.#planFileBridge = null;
|
|
81720
81911
|
}
|
|
@@ -81722,6 +81913,7 @@ var PlanHandler = class {
|
|
|
81722
81913
|
this.#approvalReceived = false;
|
|
81723
81914
|
this.#planPublished = false;
|
|
81724
81915
|
this.#stopPlanWatch();
|
|
81916
|
+
this.#storageRecovery.cancel();
|
|
81725
81917
|
void this.#planFileBridge?.dispose();
|
|
81726
81918
|
this.#planFileBridge = null;
|
|
81727
81919
|
this.#processedPlanToolUseIds.clear();
|
|
@@ -85866,7 +86058,7 @@ function maybeEmitCursorWindowOccupancy(ctx, event) {
|
|
|
85866
86058
|
handleAutoCompactionSnapshot(ctx, synthetic, resolved.windowTokens, resolved.source === "held");
|
|
85867
86059
|
}
|
|
85868
86060
|
function priorOccupancyFromTurnStats(prior) {
|
|
85869
|
-
if (
|
|
86061
|
+
if (prior?.type !== "turn_stats") return null;
|
|
85870
86062
|
const used = prior.liveContextTokens ?? 0;
|
|
85871
86063
|
const priorWindow = prior.contextWindow ?? 0;
|
|
85872
86064
|
if (used <= 0 || priorWindow <= 0) return null;
|
|
@@ -86782,7 +86974,7 @@ var RoiTracker = class {
|
|
|
86782
86974
|
function syntheticResourceUri(msg) {
|
|
86783
86975
|
if (!msg.isSynthetic || msg.content.length !== 1) return null;
|
|
86784
86976
|
const block = msg.content[0];
|
|
86785
|
-
if (
|
|
86977
|
+
if (block?.type !== "resource") return null;
|
|
86786
86978
|
if (!("uri" in block.resource)) return null;
|
|
86787
86979
|
return block.resource.uri;
|
|
86788
86980
|
}
|
|
@@ -86790,7 +86982,7 @@ function seedPushedEverFromHistory(msgs, pushManager) {
|
|
|
86790
86982
|
const seeded = /* @__PURE__ */ new Set();
|
|
86791
86983
|
for (const msg of msgs) {
|
|
86792
86984
|
const uri = syntheticResourceUri(msg);
|
|
86793
|
-
if (!uri
|
|
86985
|
+
if (!uri?.startsWith("shipyard://")) continue;
|
|
86794
86986
|
if (seeded.has(uri)) continue;
|
|
86795
86987
|
seeded.add(uri);
|
|
86796
86988
|
pushManager.seedSessionPushed(uri);
|
|
@@ -88183,7 +88375,7 @@ var StructuredTaskTracker = class {
|
|
|
88183
88375
|
const overlay = this.#currentOverlay ?? DEFAULT_TASK_OVERLAY;
|
|
88184
88376
|
const merged = applyOverlayToMap(this.#structuredTasks, overlay);
|
|
88185
88377
|
const item = merged.get(itemId);
|
|
88186
|
-
if (
|
|
88378
|
+
if (item?.status !== "in_progress") return;
|
|
88187
88379
|
const caps = this.#resolveEffectiveCaps(itemId, item);
|
|
88188
88380
|
this.#maybeFireItemActivated(itemId, caps);
|
|
88189
88381
|
}
|
|
@@ -91104,8 +91296,8 @@ var Task = class {
|
|
|
91104
91296
|
thread.clearControlChannelSend();
|
|
91105
91297
|
}
|
|
91106
91298
|
}
|
|
91107
|
-
addStreamDeltaSink(
|
|
91108
|
-
return this.#getPrimary().addStreamDeltaSink(
|
|
91299
|
+
addStreamDeltaSink(sink) {
|
|
91300
|
+
return this.#getPrimary().addStreamDeltaSink(sink);
|
|
91109
91301
|
}
|
|
91110
91302
|
getInFlightStreamDeltas() {
|
|
91111
91303
|
return this.#getPrimary().getInFlightStreamDeltas();
|
|
@@ -94970,7 +95162,7 @@ function extractTaskSnapshotDigest(ctx) {
|
|
|
94970
95162
|
return JSON.stringify(parts);
|
|
94971
95163
|
}
|
|
94972
95164
|
function summarizePrState(payload) {
|
|
94973
|
-
if (!payload
|
|
95165
|
+
if (!payload?.currentBranchPR) {
|
|
94974
95166
|
return { prState: null, ci: null, reviewers: null, mergeable: null };
|
|
94975
95167
|
}
|
|
94976
95168
|
const pr = payload.currentBranchPR;
|
|
@@ -95029,7 +95221,7 @@ function findPendingAskQuestion(notifications) {
|
|
|
95029
95221
|
function findLastAssistantPreview(messages) {
|
|
95030
95222
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
95031
95223
|
const m2 = messages[i];
|
|
95032
|
-
if (
|
|
95224
|
+
if (m2?.senderKind !== "agent") continue;
|
|
95033
95225
|
const text = collectAgentText(m2);
|
|
95034
95226
|
if (!text) continue;
|
|
95035
95227
|
return previewSlice(text);
|
|
@@ -97708,8 +97900,8 @@ async function createDaemon(deps) {
|
|
|
97708
97900
|
throw err3;
|
|
97709
97901
|
}
|
|
97710
97902
|
},
|
|
97711
|
-
wireUpdateStatusForwarding: (
|
|
97712
|
-
wireUpdateStatusForwarding(pendingUpdateReport,
|
|
97903
|
+
wireUpdateStatusForwarding: (sink, onMessage) => {
|
|
97904
|
+
wireUpdateStatusForwarding(pendingUpdateReport, sink, onMessage);
|
|
97713
97905
|
pendingUpdateReport = null;
|
|
97714
97906
|
},
|
|
97715
97907
|
findVizBySlug: (slug) => {
|
|
@@ -100994,4 +101186,4 @@ export {
|
|
|
100994
101186
|
decideWorkspaceScope,
|
|
100995
101187
|
serve
|
|
100996
101188
|
};
|
|
100997
|
-
//# sourceMappingURL=serve-
|
|
101189
|
+
//# sourceMappingURL=serve-DAP6V7SY.js.map
|