@schoolai/shipyard 3.1.1 → 3.2.0-rc.20260416.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/{chunk-ERKQ6CBC.js → chunk-2RV2XXAI.js} +2 -2
- package/dist/{chunk-ERKQ6CBC.js.map → chunk-2RV2XXAI.js.map} +1 -1
- package/dist/{chunk-WHHNOYQE.js → chunk-CF6ARE53.js} +2 -2
- package/dist/index.js +3 -3
- package/dist/{login-VMDYGKB7.js → login-44ILKKPG.js} +3 -3
- package/dist/{serve-HDRZ2CU6.js → serve-ZD5RISIM.js} +478 -223
- package/dist/serve-ZD5RISIM.js.map +1 -0
- package/dist/{start-63XQAT6J.js → start-XAUXSUYV.js} +4 -4
- package/package.json +1 -1
- package/dist/serve-HDRZ2CU6.js.map +0 -1
- /package/dist/{chunk-WHHNOYQE.js.map → chunk-CF6ARE53.js.map} +0 -0
- /package/dist/{login-VMDYGKB7.js.map → login-44ILKKPG.js.map} +0 -0
- /package/dist/{start-63XQAT6J.js.map → start-XAUXSUYV.js.map} +0 -0
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
VaultKeyPutRequestSchema,
|
|
38
38
|
VaultKeyPutResponseSchema,
|
|
39
39
|
classifyClaudeCodeCompatibility
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-2RV2XXAI.js";
|
|
41
41
|
import {
|
|
42
42
|
loadAuthToken
|
|
43
43
|
} from "./chunk-IHSXN66C.js";
|
|
@@ -24345,7 +24345,8 @@ var DiffHunkAnnotationSchema = BaseCommentZodSchema.extend({
|
|
|
24345
24345
|
lineNumber: external_exports.number(),
|
|
24346
24346
|
lineContent: external_exports.string(),
|
|
24347
24347
|
lineContentHash: external_exports.string(),
|
|
24348
|
-
side: external_exports.enum(["original", "modified"])
|
|
24348
|
+
side: external_exports.enum(["original", "modified"]),
|
|
24349
|
+
diffScope: external_exports.enum(["working-tree", "branch", "last-turn", "pr"]).optional()
|
|
24349
24350
|
});
|
|
24350
24351
|
var PreviewElementAnnotationSchema = BaseCommentZodSchema.extend({
|
|
24351
24352
|
annotationType: external_exports.literal("preview-element"),
|
|
@@ -24590,6 +24591,7 @@ var CrdtCompactor = class {
|
|
|
24590
24591
|
};
|
|
24591
24592
|
var PLAN_EPOCH = 3;
|
|
24592
24593
|
var CANVAS_EPOCH = 2;
|
|
24594
|
+
var OBSOLETE_PREFIXES = /* @__PURE__ */ new Set(["typing", "task-view"]);
|
|
24593
24595
|
var DOCUMENT_PREFIXES = ["plan", "canvas"];
|
|
24594
24596
|
var PREFIX_SET = new Set(DOCUMENT_PREFIXES);
|
|
24595
24597
|
function isDocumentPrefix(value) {
|
|
@@ -26709,6 +26711,17 @@ var BrowserToFileIOMessageSchema = external_exports.discriminatedUnion("type", [
|
|
|
26709
26711
|
external_exports.object({
|
|
26710
26712
|
type: external_exports.literal("git_ls_files"),
|
|
26711
26713
|
requestId: external_exports.string()
|
|
26714
|
+
}),
|
|
26715
|
+
external_exports.object({
|
|
26716
|
+
type: external_exports.literal("git_branch_diff_files"),
|
|
26717
|
+
requestId: external_exports.string(),
|
|
26718
|
+
baseRef: external_exports.string().optional()
|
|
26719
|
+
}),
|
|
26720
|
+
external_exports.object({
|
|
26721
|
+
type: external_exports.literal("git_branch_diff_file"),
|
|
26722
|
+
requestId: external_exports.string(),
|
|
26723
|
+
path: external_exports.string(),
|
|
26724
|
+
mergeBase: external_exports.string()
|
|
26712
26725
|
})
|
|
26713
26726
|
]);
|
|
26714
26727
|
var FileChangeSchema = external_exports.object({
|
|
@@ -26770,6 +26783,19 @@ var DaemonToFileIOMessageSchema = external_exports.discriminatedUnion("type", [
|
|
|
26770
26783
|
requestId: external_exports.string(),
|
|
26771
26784
|
files: external_exports.array(external_exports.string())
|
|
26772
26785
|
}),
|
|
26786
|
+
external_exports.object({
|
|
26787
|
+
type: external_exports.literal("git_branch_diff_files_result"),
|
|
26788
|
+
requestId: external_exports.string(),
|
|
26789
|
+
files: external_exports.array(CheckpointFileEntrySchema),
|
|
26790
|
+
mergeBase: external_exports.string(),
|
|
26791
|
+
baseRef: external_exports.string()
|
|
26792
|
+
}),
|
|
26793
|
+
external_exports.object({
|
|
26794
|
+
type: external_exports.literal("git_branch_diff_file_result"),
|
|
26795
|
+
requestId: external_exports.string(),
|
|
26796
|
+
originalContent: external_exports.string(),
|
|
26797
|
+
modifiedContent: external_exports.string()
|
|
26798
|
+
}),
|
|
26773
26799
|
external_exports.object({ type: external_exports.literal("error"), requestId: external_exports.string(), error: external_exports.string() }),
|
|
26774
26800
|
external_exports.object({
|
|
26775
26801
|
type: external_exports.literal("checkpoint_ready"),
|
|
@@ -28754,6 +28780,35 @@ async function rerunChecks(cwd, prNumber) {
|
|
|
28754
28780
|
}
|
|
28755
28781
|
}
|
|
28756
28782
|
|
|
28783
|
+
// src/shared/capabilities/git-diff.ts
|
|
28784
|
+
async function getDefaultBranch(cwd) {
|
|
28785
|
+
try {
|
|
28786
|
+
const ref = await runWithTimeout(
|
|
28787
|
+
"git",
|
|
28788
|
+
["symbolic-ref", "refs/remotes/origin/HEAD", "--short"],
|
|
28789
|
+
cwd,
|
|
28790
|
+
TIMEOUT_MS
|
|
28791
|
+
);
|
|
28792
|
+
return ref || null;
|
|
28793
|
+
} catch {
|
|
28794
|
+
}
|
|
28795
|
+
for (const candidate of ["origin/main", "origin/master"]) {
|
|
28796
|
+
try {
|
|
28797
|
+
await runWithTimeout("git", ["rev-parse", "--verify", candidate], cwd, TIMEOUT_MS);
|
|
28798
|
+
return candidate;
|
|
28799
|
+
} catch {
|
|
28800
|
+
}
|
|
28801
|
+
}
|
|
28802
|
+
return null;
|
|
28803
|
+
}
|
|
28804
|
+
async function getMergeBase(cwd, baseBranch) {
|
|
28805
|
+
try {
|
|
28806
|
+
return await runWithTimeout("git", ["merge-base", baseBranch, "HEAD"], cwd, TIMEOUT_MS);
|
|
28807
|
+
} catch {
|
|
28808
|
+
return null;
|
|
28809
|
+
}
|
|
28810
|
+
}
|
|
28811
|
+
|
|
28757
28812
|
// src/shared/capabilities/index.ts
|
|
28758
28813
|
var AutoModeConfigSchema = external_exports.object({
|
|
28759
28814
|
cachedGrowthBookFeatures: external_exports.object({ tengu_auto_mode_config: external_exports.object({ enabled: external_exports.string() }) }).passthrough()
|
|
@@ -29215,6 +29270,28 @@ function narrow(value) {
|
|
|
29215
29270
|
import { unlinkSync } from "fs";
|
|
29216
29271
|
import { readFile as readFile5, unlink as unlink2, writeFile as writeFile3 } from "fs/promises";
|
|
29217
29272
|
import { join as join8 } from "path";
|
|
29273
|
+
|
|
29274
|
+
// src/services/bootstrap/classify-uncaught-error.ts
|
|
29275
|
+
function classifyUncaughtError(error2) {
|
|
29276
|
+
if (!(error2 instanceof Error)) return "fatal";
|
|
29277
|
+
const code2 = "code" in error2 && typeof error2.code === "string" ? error2.code : void 0;
|
|
29278
|
+
const msg = error2.message;
|
|
29279
|
+
if (code2 === "EPIPE" || code2 === "ECONNRESET" || code2 === "ECONNABORTED" || code2 === "ECONNREFUSED" || code2 === "ERR_STREAM_DESTROYED") {
|
|
29280
|
+
return "recoverable";
|
|
29281
|
+
}
|
|
29282
|
+
if (msg.includes("can't add channel") && msg.includes("stopped")) {
|
|
29283
|
+
return "recoverable";
|
|
29284
|
+
}
|
|
29285
|
+
if (msg.includes("RTCDataChannel.readyState is not")) {
|
|
29286
|
+
return "recoverable";
|
|
29287
|
+
}
|
|
29288
|
+
if (msg.includes("ProcessTransport is not ready")) {
|
|
29289
|
+
return "recoverable";
|
|
29290
|
+
}
|
|
29291
|
+
return "fatal";
|
|
29292
|
+
}
|
|
29293
|
+
|
|
29294
|
+
// src/services/bootstrap/lifecycle.ts
|
|
29218
29295
|
function isProcessAlive(pid) {
|
|
29219
29296
|
try {
|
|
29220
29297
|
process.kill(pid, 0);
|
|
@@ -29244,7 +29321,12 @@ var LifecycleManager = class {
|
|
|
29244
29321
|
process.on("SIGTERM", termHandler);
|
|
29245
29322
|
process.on("SIGINT", intHandler);
|
|
29246
29323
|
const exceptionHandler = (error2) => {
|
|
29247
|
-
|
|
29324
|
+
const severity = classifyUncaughtError(error2);
|
|
29325
|
+
if (severity === "recoverable") {
|
|
29326
|
+
this.#log.warn({ err: error2 }, "Recoverable uncaught exception \u2014 absorbed");
|
|
29327
|
+
return;
|
|
29328
|
+
}
|
|
29329
|
+
this.#log.error({ err: error2 }, "Fatal uncaught exception \u2014 initiating shutdown");
|
|
29248
29330
|
void this.#shutdown("uncaughtException");
|
|
29249
29331
|
};
|
|
29250
29332
|
const rejectionHandler = (reason) => {
|
|
@@ -29588,7 +29670,7 @@ function nanoid(size2 = 21) {
|
|
|
29588
29670
|
}
|
|
29589
29671
|
|
|
29590
29672
|
// src/services/bootstrap/signaling.ts
|
|
29591
|
-
var DAEMON_NPM_VERSION = true ? "3.
|
|
29673
|
+
var DAEMON_NPM_VERSION = true ? "3.2.0" : "unknown";
|
|
29592
29674
|
function createDaemonSignaling(config2) {
|
|
29593
29675
|
const agentId = config2.agentId ?? nanoid();
|
|
29594
29676
|
function send(msg) {
|
|
@@ -29743,6 +29825,7 @@ function handleBrowserPreviewChannel(port, send, sendBinary, log, options) {
|
|
|
29743
29825
|
const requestTimeoutMs = options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
29744
29826
|
const activeRequests = /* @__PURE__ */ new Map();
|
|
29745
29827
|
const cookieJar = /* @__PURE__ */ new Map();
|
|
29828
|
+
const previewPrefix = `/__preview/url/${encodeURIComponent(`http://localhost:${port}`)}/`;
|
|
29746
29829
|
function respond(msg) {
|
|
29747
29830
|
send(JSON.stringify(msg));
|
|
29748
29831
|
}
|
|
@@ -29896,7 +29979,7 @@ function handleBrowserPreviewChannel(port, send, sendBinary, log, options) {
|
|
|
29896
29979
|
res.on("data", (chunk) => chunks.push(chunk));
|
|
29897
29980
|
res.on("end", () => {
|
|
29898
29981
|
const rawJs = Buffer.concat(chunks).toString("utf-8");
|
|
29899
|
-
const rewritten = rewriteJsImportPaths(rawJs);
|
|
29982
|
+
const rewritten = rewriteJsImportPaths(rawJs, previewPrefix);
|
|
29900
29983
|
const body = new TextEncoder().encode(rewritten);
|
|
29901
29984
|
headers["content-length"] = String(body.byteLength);
|
|
29902
29985
|
respond({
|
|
@@ -30019,8 +30102,9 @@ function injectBaseHref(html, origin) {
|
|
|
30019
30102
|
function rewriteRootRelativePaths(html) {
|
|
30020
30103
|
return html.replace(/((?:src|href|action)\s*=\s*["'])\/(?!\/)/gi, "$1./");
|
|
30021
30104
|
}
|
|
30022
|
-
function rewriteJsImportPaths(js) {
|
|
30023
|
-
|
|
30105
|
+
function rewriteJsImportPaths(js, previewPrefix) {
|
|
30106
|
+
const replacement = previewPrefix ?? "./";
|
|
30107
|
+
return js.replace(/((?:from|import)\s*\(\s*["'])\/(?!\/)/g, `$1${replacement}`).replace(/(from\s+["'])\/(?!\/)/g, `$1${replacement}`);
|
|
30024
30108
|
}
|
|
30025
30109
|
function handleBrowserPreviewUrlChannel(send, sendBinary, log, options) {
|
|
30026
30110
|
const requestTimeoutMs = options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
@@ -30113,7 +30197,10 @@ function handleBrowserPreviewUrlChannel(send, sendBinary, log, options) {
|
|
|
30113
30197
|
injectBaseHref(new TextDecoder().decode(rawBody), targetUrl.origin)
|
|
30114
30198
|
);
|
|
30115
30199
|
} else if (isJs) {
|
|
30116
|
-
|
|
30200
|
+
const urlPrefix = `/__preview/url/${encodeURIComponent(targetUrl.origin)}/`;
|
|
30201
|
+
body = new TextEncoder().encode(
|
|
30202
|
+
rewriteJsImportPaths(new TextDecoder().decode(rawBody), urlPrefix)
|
|
30203
|
+
);
|
|
30117
30204
|
} else {
|
|
30118
30205
|
body = rawBody;
|
|
30119
30206
|
}
|
|
@@ -32301,8 +32388,7 @@ async function sweepStaleTasks(taskStateStore, taskManager, log) {
|
|
|
32301
32388
|
const noBroadcast = { broadcast: false };
|
|
32302
32389
|
for (const action of actions) {
|
|
32303
32390
|
if (action.kind === "mark_input_required") {
|
|
32304
|
-
await taskStateStore.
|
|
32305
|
-
await taskStateStore.acknowledge(action.taskId, noBroadcast);
|
|
32391
|
+
await taskStateStore.sweepToInputRequired(action.taskId, noBroadcast);
|
|
32306
32392
|
log({
|
|
32307
32393
|
event: "stale_task_swept",
|
|
32308
32394
|
taskId: action.taskId,
|
|
@@ -43227,6 +43313,11 @@ Use \`add_comment\` to annotate your work and respond to reviewer feedback. Use
|
|
|
43227
43313
|
|
|
43228
43314
|
You can **create** comments on diff and plan surfaces only (\`mode: "diff"\` and \`mode: "plan"\`). You can **reply** to comments on all 5 surfaces. Preview and canvas comments are user-originated feedback on your running app or visualizations \u2014 respond by replying to acknowledge and acting on the feedback.
|
|
43229
43315
|
|
|
43316
|
+
**Diff scope** \u2014 \`diff\` surface comments may include a \`diff-scope\` attribute indicating which view the comment was made on:
|
|
43317
|
+
- \`working-tree\` \u2014 uncommitted changes (your latest edits, like \`git diff\`)
|
|
43318
|
+
- \`branch\` \u2014 full branch diff vs base branch (all commits + uncommitted, like \`git diff main...HEAD\`)
|
|
43319
|
+
- \`last-turn\` \u2014 changes from a specific agent turn
|
|
43320
|
+
|
|
43230
43321
|
**When publishing plans** \u2014 \`mode: "plan"\` for non-obvious design decisions, anchored to specific plan text.
|
|
43231
43322
|
|
|
43232
43323
|
**Periodically during long tasks** \u2014 \`list_comments\` to catch missed feedback, especially after context loss.
|
|
@@ -75126,8 +75217,10 @@ function deriveArtifact(annotation, taskId) {
|
|
|
75126
75217
|
}
|
|
75127
75218
|
function surfaceAttrs(annotation) {
|
|
75128
75219
|
switch (annotation.annotationType) {
|
|
75129
|
-
case "diff-hunk":
|
|
75130
|
-
|
|
75220
|
+
case "diff-hunk": {
|
|
75221
|
+
const scopeAttr = annotation.diffScope ? ` diff-scope="${escapeXmlAttr(annotation.diffScope)}"` : "";
|
|
75222
|
+
return ` file="${escapeXmlAttr(annotation.filePath)}" line="${annotation.lineNumber}"${scopeAttr}`;
|
|
75223
|
+
}
|
|
75131
75224
|
case "plan-text":
|
|
75132
75225
|
return annotation.anchorText ? ` anchor="${escapeXmlAttr(annotation.anchorText)}"` : "";
|
|
75133
75226
|
case "preview-element":
|
|
@@ -76776,8 +76869,6 @@ ${conversationReplay}` : conversationReplay;
|
|
|
76776
76869
|
});
|
|
76777
76870
|
this.#ownSessionId = null;
|
|
76778
76871
|
this.#effectiveSpawnMode = { kind: "fresh" };
|
|
76779
|
-
this.#config.sessionPersistence.clear(this.#config.channelId).catch(() => {
|
|
76780
|
-
});
|
|
76781
76872
|
}
|
|
76782
76873
|
if (this.#tryForkFailedRetry(error2)) return;
|
|
76783
76874
|
if (this.#tryStaleResumeRetry(error2)) return;
|
|
@@ -79671,7 +79762,7 @@ var SideThreadRegistry = class {
|
|
|
79671
79762
|
};
|
|
79672
79763
|
},
|
|
79673
79764
|
onSubprocessEvent: (event) => {
|
|
79674
|
-
if (event.type === "turn_complete") {
|
|
79765
|
+
if (event.type === "turn_complete" || event.type === "sdk_error" || event.type === "subprocess_died") {
|
|
79675
79766
|
this.#deps.onThreadTurnComplete(params.threadId);
|
|
79676
79767
|
}
|
|
79677
79768
|
}
|
|
@@ -80354,7 +80445,7 @@ var StructuredTaskTracker = class {
|
|
|
80354
80445
|
* Attach a file watcher for CC task files. Called after init_received
|
|
80355
80446
|
* when we know the CC session ID, or immediately for resumed sessions.
|
|
80356
80447
|
*/
|
|
80357
|
-
attachFileWatcher(sessionId) {
|
|
80448
|
+
attachFileWatcher(sessionId, options) {
|
|
80358
80449
|
if (this.#ccTaskWatcherDispose) {
|
|
80359
80450
|
this.#deps.log({
|
|
80360
80451
|
event: "file_watcher_already_attached",
|
|
@@ -80365,17 +80456,17 @@ var StructuredTaskTracker = class {
|
|
|
80365
80456
|
}
|
|
80366
80457
|
const watcher = createCCTaskFileWatcher(sessionId, this.#deps.log);
|
|
80367
80458
|
this.#ccTaskFileWriter = createCCTaskFileWriter(watcher.dir, this.#deps.log);
|
|
80368
|
-
this.#initFileWatcher(watcher);
|
|
80459
|
+
this.#initFileWatcher(watcher, options);
|
|
80369
80460
|
if (this.#currentOverlay) {
|
|
80370
|
-
this.#flushStructuredTasks();
|
|
80461
|
+
this.#flushStructuredTasks(options);
|
|
80371
80462
|
}
|
|
80372
80463
|
}
|
|
80373
80464
|
/**
|
|
80374
80465
|
* Apply an overlay on top of CC tasks. Stores the overlay and re-flushes.
|
|
80375
80466
|
*/
|
|
80376
|
-
applyOverlay(overlay) {
|
|
80467
|
+
applyOverlay(overlay, options) {
|
|
80377
80468
|
this.#currentOverlay = overlay;
|
|
80378
|
-
this.#flushStructuredTasks();
|
|
80469
|
+
this.#flushStructuredTasks(options);
|
|
80379
80470
|
}
|
|
80380
80471
|
processStructuredTaskEvents(content) {
|
|
80381
80472
|
const events = extractStructuredTaskEvents(content);
|
|
@@ -80500,11 +80591,11 @@ var StructuredTaskTracker = class {
|
|
|
80500
80591
|
applyDepEdgeAdditions(merged, overlay.depEdges);
|
|
80501
80592
|
return merged;
|
|
80502
80593
|
}
|
|
80503
|
-
#flushStructuredTasks() {
|
|
80594
|
+
#flushStructuredTasks(options) {
|
|
80504
80595
|
const overlay = this.#currentOverlay ?? DEFAULT_TASK_OVERLAY;
|
|
80505
80596
|
const merged = this.#applyOverlayToMap(this.#structuredTasks, overlay);
|
|
80506
80597
|
const todoProgress = this.#computeTodoProgress(merged);
|
|
80507
|
-
this.#deps.updateStructuredTasks(Object.fromEntries(merged), todoProgress);
|
|
80598
|
+
this.#deps.updateStructuredTasks(Object.fromEntries(merged), todoProgress, options);
|
|
80508
80599
|
if (!this.#suppressWriteThrough) {
|
|
80509
80600
|
this.#ccTaskFileWriter?.writeMergedTasks(merged);
|
|
80510
80601
|
}
|
|
@@ -80525,9 +80616,12 @@ var StructuredTaskTracker = class {
|
|
|
80525
80616
|
currentActivity
|
|
80526
80617
|
};
|
|
80527
80618
|
}
|
|
80528
|
-
#initFileWatcher(watcher) {
|
|
80619
|
+
#initFileWatcher(watcher, initOptions) {
|
|
80620
|
+
let isFirstRead = !!initOptions?.preserveUpdatedAt;
|
|
80529
80621
|
this.#ccTaskWatcherDispose = watcher.watch((tasks) => {
|
|
80530
|
-
|
|
80622
|
+
const opts = isFirstRead ? initOptions : void 0;
|
|
80623
|
+
isFirstRead = false;
|
|
80624
|
+
this.#reconcileFromDisk(tasks, opts);
|
|
80531
80625
|
});
|
|
80532
80626
|
}
|
|
80533
80627
|
/**
|
|
@@ -80537,7 +80631,7 @@ var StructuredTaskTracker = class {
|
|
|
80537
80631
|
* - Remove tasks that were previously from disk but are now gone
|
|
80538
80632
|
* - Re-flush with overlay applied
|
|
80539
80633
|
*/
|
|
80540
|
-
#reconcileFromDisk(ccTasks) {
|
|
80634
|
+
#reconcileFromDisk(ccTasks, options) {
|
|
80541
80635
|
const currentDiskIds = /* @__PURE__ */ new Set();
|
|
80542
80636
|
for (const file of ccTasks) {
|
|
80543
80637
|
currentDiskIds.add(file.id);
|
|
@@ -80558,7 +80652,7 @@ var StructuredTaskTracker = class {
|
|
|
80558
80652
|
}
|
|
80559
80653
|
this.#suppressWriteThrough = true;
|
|
80560
80654
|
try {
|
|
80561
|
-
this.#flushStructuredTasks();
|
|
80655
|
+
this.#flushStructuredTasks(options);
|
|
80562
80656
|
} finally {
|
|
80563
80657
|
this.#suppressWriteThrough = false;
|
|
80564
80658
|
}
|
|
@@ -81296,7 +81390,9 @@ var Task = class _Task {
|
|
|
81296
81390
|
log: deps.log
|
|
81297
81391
|
});
|
|
81298
81392
|
if (deps.existingSessionId) {
|
|
81299
|
-
this.#structuredTaskTracker.attachFileWatcher(deps.existingSessionId
|
|
81393
|
+
this.#structuredTaskTracker.attachFileWatcher(deps.existingSessionId, {
|
|
81394
|
+
preserveUpdatedAt: true
|
|
81395
|
+
});
|
|
81300
81396
|
}
|
|
81301
81397
|
this.#subagentManager = new SubagentManager({
|
|
81302
81398
|
taskId: deps.taskId,
|
|
@@ -82424,6 +82520,8 @@ Use this context to maintain continuity. You have already done this work \u2014
|
|
|
82424
82520
|
}
|
|
82425
82521
|
}
|
|
82426
82522
|
#handleSdkError(event) {
|
|
82523
|
+
this.#collabQueue.onTurnComplete();
|
|
82524
|
+
this.#pushManager.onTurnEnd();
|
|
82427
82525
|
this.#deps.metricsCollector.capture("agent_error", {
|
|
82428
82526
|
taskId: this.#deps.taskId,
|
|
82429
82527
|
errorType: event.errorSubtype ?? "sdk_error",
|
|
@@ -82443,6 +82541,8 @@ Use this context to maintain continuity. You have already done this work \u2014
|
|
|
82443
82541
|
}
|
|
82444
82542
|
}
|
|
82445
82543
|
#handleSubprocessDied() {
|
|
82544
|
+
this.#collabQueue.onTurnComplete();
|
|
82545
|
+
this.#pushManager.onTurnEnd();
|
|
82446
82546
|
this.#mcpPoller.stop();
|
|
82447
82547
|
if (this.#lastTurnResult != null) {
|
|
82448
82548
|
this.#costBaseline = {
|
|
@@ -82524,8 +82624,8 @@ Use this context to maintain continuity. You have already done this work \u2014
|
|
|
82524
82624
|
}
|
|
82525
82625
|
}
|
|
82526
82626
|
}
|
|
82527
|
-
applyOverlay(overlay) {
|
|
82528
|
-
this.#structuredTaskTracker.applyOverlay(overlay);
|
|
82627
|
+
applyOverlay(overlay, options) {
|
|
82628
|
+
this.#structuredTaskTracker.applyOverlay(overlay, options);
|
|
82529
82629
|
}
|
|
82530
82630
|
/** ---------------------------------------------------------------- */
|
|
82531
82631
|
/** Resource resolution */
|
|
@@ -83202,7 +83302,8 @@ var TaskManager = class {
|
|
|
83202
83302
|
this.#tasks.set(taskId, { taskId, channelId, cwd, mode, orchestrator });
|
|
83203
83303
|
this.#flushPendingStreamSubs(taskId, orchestrator);
|
|
83204
83304
|
this.#deps.taskStateStore.getTask(taskId).then((record) => {
|
|
83205
|
-
if (record?.taskOverlay)
|
|
83305
|
+
if (record?.taskOverlay)
|
|
83306
|
+
orchestrator.applyOverlay(record.taskOverlay, { preserveUpdatedAt: true });
|
|
83206
83307
|
}).catch((err) => {
|
|
83207
83308
|
this.#deps.log({
|
|
83208
83309
|
event: "overlay_restore_failed",
|
|
@@ -83244,10 +83345,27 @@ var TaskManager = class {
|
|
|
83244
83345
|
getTaskMode(taskId) {
|
|
83245
83346
|
return this.#tasks.get(taskId)?.mode ?? "task";
|
|
83246
83347
|
}
|
|
83247
|
-
handleUserMessage(taskId, content, settings, cwd, participantId, senderDisplayName) {
|
|
83248
|
-
|
|
83348
|
+
async handleUserMessage(taskId, content, settings, cwd, participantId, senderDisplayName) {
|
|
83349
|
+
let task = this.#tasks.get(taskId);
|
|
83249
83350
|
if (!task) {
|
|
83250
|
-
|
|
83351
|
+
const record = await this.#deps.taskStateStore.getTask(taskId);
|
|
83352
|
+
if (!record) {
|
|
83353
|
+
throw new Error(`No orchestrator for task ${taskId}`);
|
|
83354
|
+
}
|
|
83355
|
+
this.restoreOrchestrator(taskId, record.channelId, {
|
|
83356
|
+
initialState: "cold_idle",
|
|
83357
|
+
cwd: record.cwd,
|
|
83358
|
+
mode: record.mode,
|
|
83359
|
+
costBaseline: {
|
|
83360
|
+
totalCostUsd: record.totalCostUsd,
|
|
83361
|
+
totalOutputTokens: record.totalOutputTokens
|
|
83362
|
+
}
|
|
83363
|
+
});
|
|
83364
|
+
task = this.#tasks.get(taskId);
|
|
83365
|
+
if (!task) {
|
|
83366
|
+
throw new Error(`Failed to restore orchestrator for task ${taskId}`);
|
|
83367
|
+
}
|
|
83368
|
+
this.#deps.log({ event: "task_lazy_restored", taskId, channelId: record.channelId });
|
|
83251
83369
|
}
|
|
83252
83370
|
if (cwd && cwd !== task.cwd) {
|
|
83253
83371
|
task.cwd = cwd;
|
|
@@ -83567,8 +83685,13 @@ var TaskManager = class {
|
|
|
83567
83685
|
});
|
|
83568
83686
|
});
|
|
83569
83687
|
},
|
|
83570
|
-
updateStructuredTasks: (tasks, todoProgress) => {
|
|
83571
|
-
this.#deps.taskStateStore.updateStructuredTasks(
|
|
83688
|
+
updateStructuredTasks: (tasks, todoProgress, options) => {
|
|
83689
|
+
this.#deps.taskStateStore.updateStructuredTasks(
|
|
83690
|
+
taskId,
|
|
83691
|
+
tasks,
|
|
83692
|
+
todoProgress,
|
|
83693
|
+
options ? { preserveUpdatedAt: options.preserveUpdatedAt } : void 0
|
|
83694
|
+
).catch((err) => {
|
|
83572
83695
|
this.#deps.log({
|
|
83573
83696
|
event: "task_state_store_structured_tasks_failed",
|
|
83574
83697
|
taskId,
|
|
@@ -83715,52 +83838,29 @@ function buildTaskStateStore(dataDir) {
|
|
|
83715
83838
|
});
|
|
83716
83839
|
},
|
|
83717
83840
|
async updateTaskStatus(taskId, status, options) {
|
|
83718
|
-
|
|
83719
|
-
if (!task) return;
|
|
83720
|
-
pushBroadcast(options);
|
|
83721
|
-
await store.set(taskId, applyStatusTransition(task, status, Date.now()));
|
|
83841
|
+
await safeUpdate(taskId, (task) => applyStatusTransition(task, status, Date.now()), options);
|
|
83722
83842
|
},
|
|
83723
83843
|
async updateTitle(taskId, title, options) {
|
|
83724
|
-
|
|
83725
|
-
if (!task) return;
|
|
83726
|
-
pushBroadcast(options);
|
|
83727
|
-
await store.set(taskId, {
|
|
83728
|
-
...task,
|
|
83729
|
-
title,
|
|
83730
|
-
updatedAt: Date.now()
|
|
83731
|
-
});
|
|
83844
|
+
await safeUpdate(taskId, (task) => ({ ...task, title, updatedAt: Date.now() }), options);
|
|
83732
83845
|
},
|
|
83733
83846
|
async updateCwd(taskId, cwd, options) {
|
|
83734
|
-
|
|
83735
|
-
if (!task) return;
|
|
83736
|
-
pushBroadcast(options);
|
|
83737
|
-
await store.set(taskId, {
|
|
83738
|
-
...task,
|
|
83739
|
-
cwd,
|
|
83740
|
-
updatedAt: Date.now()
|
|
83741
|
-
});
|
|
83847
|
+
await safeUpdate(taskId, (task) => ({ ...task, cwd, updatedAt: Date.now() }), options);
|
|
83742
83848
|
},
|
|
83743
83849
|
async updateMode(taskId, mode, options) {
|
|
83744
|
-
|
|
83745
|
-
if (!task) return;
|
|
83746
|
-
pushBroadcast(options);
|
|
83747
|
-
await store.set(taskId, {
|
|
83748
|
-
...task,
|
|
83749
|
-
mode,
|
|
83750
|
-
updatedAt: Date.now()
|
|
83751
|
-
});
|
|
83850
|
+
await safeUpdate(taskId, (task) => ({ ...task, mode, updatedAt: Date.now() }), options);
|
|
83752
83851
|
},
|
|
83753
83852
|
async updateTodoProgress(taskId, progress, options) {
|
|
83754
|
-
|
|
83755
|
-
|
|
83756
|
-
|
|
83757
|
-
|
|
83758
|
-
|
|
83759
|
-
|
|
83760
|
-
|
|
83761
|
-
|
|
83762
|
-
|
|
83763
|
-
|
|
83853
|
+
await safeUpdate(
|
|
83854
|
+
taskId,
|
|
83855
|
+
(task) => ({
|
|
83856
|
+
...task,
|
|
83857
|
+
todoCompleted: progress.todoCompleted,
|
|
83858
|
+
todoTotal: progress.todoTotal,
|
|
83859
|
+
currentActivity: progress.currentActivity,
|
|
83860
|
+
updatedAt: Date.now()
|
|
83861
|
+
}),
|
|
83862
|
+
options
|
|
83863
|
+
);
|
|
83764
83864
|
},
|
|
83765
83865
|
async acknowledge(taskId, options) {
|
|
83766
83866
|
await safeUpdate(taskId, (task) => ({ ...task, acknowledgedAt: Date.now() }), options);
|
|
@@ -83769,39 +83869,42 @@ function buildTaskStateStore(dataDir) {
|
|
|
83769
83869
|
await safeUpdate(taskId, (task) => ({ ...task, pinned: !task.pinned }), options);
|
|
83770
83870
|
},
|
|
83771
83871
|
async updateStructuredTasks(taskId, tasks, todoProgress, options) {
|
|
83772
|
-
|
|
83773
|
-
|
|
83774
|
-
|
|
83775
|
-
|
|
83776
|
-
|
|
83777
|
-
|
|
83778
|
-
|
|
83779
|
-
|
|
83780
|
-
|
|
83781
|
-
|
|
83782
|
-
|
|
83783
|
-
|
|
83784
|
-
|
|
83872
|
+
await safeUpdate(
|
|
83873
|
+
taskId,
|
|
83874
|
+
(task) => ({
|
|
83875
|
+
...task,
|
|
83876
|
+
structuredTasks: tasks,
|
|
83877
|
+
...todoProgress && {
|
|
83878
|
+
todoCompleted: todoProgress.todoCompleted,
|
|
83879
|
+
todoTotal: todoProgress.todoTotal,
|
|
83880
|
+
currentActivity: todoProgress.currentActivity
|
|
83881
|
+
},
|
|
83882
|
+
updatedAt: options?.preserveUpdatedAt ? task.updatedAt : Date.now()
|
|
83883
|
+
}),
|
|
83884
|
+
options
|
|
83885
|
+
);
|
|
83785
83886
|
},
|
|
83786
83887
|
async updateTaskOverlay(taskId, overlay, options) {
|
|
83787
|
-
|
|
83788
|
-
|
|
83789
|
-
|
|
83790
|
-
|
|
83791
|
-
|
|
83792
|
-
|
|
83793
|
-
|
|
83794
|
-
|
|
83888
|
+
await safeUpdate(
|
|
83889
|
+
taskId,
|
|
83890
|
+
(task) => ({
|
|
83891
|
+
...task,
|
|
83892
|
+
taskOverlay: overlay,
|
|
83893
|
+
updatedAt: options?.preserveUpdatedAt ? task.updatedAt : Date.now()
|
|
83894
|
+
}),
|
|
83895
|
+
options
|
|
83896
|
+
);
|
|
83795
83897
|
},
|
|
83796
83898
|
async updateComposerSettings(taskId, settings, options) {
|
|
83797
|
-
|
|
83798
|
-
|
|
83799
|
-
|
|
83800
|
-
|
|
83801
|
-
|
|
83802
|
-
|
|
83803
|
-
|
|
83804
|
-
|
|
83899
|
+
await safeUpdate(
|
|
83900
|
+
taskId,
|
|
83901
|
+
(task) => ({
|
|
83902
|
+
...task,
|
|
83903
|
+
composerSettings: { ...task.composerSettings, ...settings },
|
|
83904
|
+
updatedAt: Date.now()
|
|
83905
|
+
}),
|
|
83906
|
+
options
|
|
83907
|
+
);
|
|
83805
83908
|
},
|
|
83806
83909
|
async updateCostStats(taskId, stats, options) {
|
|
83807
83910
|
await safeUpdate(
|
|
@@ -83827,12 +83930,27 @@ function buildTaskStateStore(dataDir) {
|
|
|
83827
83930
|
options
|
|
83828
83931
|
);
|
|
83829
83932
|
},
|
|
83933
|
+
async sweepToInputRequired(taskId, options) {
|
|
83934
|
+
await safeUpdate(
|
|
83935
|
+
taskId,
|
|
83936
|
+
(task) => ({
|
|
83937
|
+
...task,
|
|
83938
|
+
status: "input_required",
|
|
83939
|
+
taskStartedAt: null
|
|
83940
|
+
}),
|
|
83941
|
+
options
|
|
83942
|
+
);
|
|
83943
|
+
},
|
|
83830
83944
|
async getTask(taskId) {
|
|
83831
83945
|
return store.get(taskId);
|
|
83832
83946
|
},
|
|
83833
83947
|
async listTasks() {
|
|
83834
83948
|
return store.list();
|
|
83835
83949
|
},
|
|
83950
|
+
async listTasksWithVersion() {
|
|
83951
|
+
const tasks = await store.list();
|
|
83952
|
+
return { tasks, version: _version };
|
|
83953
|
+
},
|
|
83836
83954
|
subscribe(listener) {
|
|
83837
83955
|
taskListeners.add(listener);
|
|
83838
83956
|
return () => {
|
|
@@ -84145,13 +84263,15 @@ ${additionalSystemPrompt}` : basePrompt;
|
|
|
84145
84263
|
async function detectInitialCapabilities(tokenStore, settings) {
|
|
84146
84264
|
return detectCapabilities(tokenStore, settings.preferredAnthropicAuth ?? void 0);
|
|
84147
84265
|
}
|
|
84148
|
-
function applyProxyFiltering(merged, proxyRef,
|
|
84149
|
-
|
|
84266
|
+
function applyProxyFiltering(merged, proxyRef, disabledNames) {
|
|
84267
|
+
const proxy = proxyRef.current;
|
|
84268
|
+
if (!proxy) return;
|
|
84269
|
+
for (const name of proxy.getAllManagedNames()) {
|
|
84150
84270
|
if (name in merged) {
|
|
84151
84271
|
delete merged[name];
|
|
84152
84272
|
}
|
|
84153
84273
|
}
|
|
84154
|
-
const freshConfigs =
|
|
84274
|
+
const freshConfigs = proxy.getServerConfigs();
|
|
84155
84275
|
for (const [name, config2] of freshConfigs) {
|
|
84156
84276
|
if (!disabledNames.has(name)) {
|
|
84157
84277
|
merged[name] = config2;
|
|
@@ -84180,7 +84300,7 @@ function collectProxyEndpoints(capabilitiesRef, claudeAiToken) {
|
|
|
84180
84300
|
}
|
|
84181
84301
|
return endpoints;
|
|
84182
84302
|
}
|
|
84183
|
-
async function initializeProxyServer(deps, capabilitiesRef,
|
|
84303
|
+
async function initializeProxyServer(deps, capabilitiesRef, onReauthComplete) {
|
|
84184
84304
|
const claudeAiToken = await readAnthropicOAuthToken();
|
|
84185
84305
|
const proxyEndpoints = collectProxyEndpoints(capabilitiesRef, claudeAiToken ?? void 0);
|
|
84186
84306
|
if (proxyEndpoints.size === 0) return { proxyServer: null };
|
|
@@ -84192,11 +84312,14 @@ async function initializeProxyServer(deps, capabilitiesRef, proxyManagedNames, o
|
|
|
84192
84312
|
});
|
|
84193
84313
|
try {
|
|
84194
84314
|
await proxy.initialize(proxyEndpoints);
|
|
84195
|
-
|
|
84315
|
+
const connectedNames = proxy.getServerNames();
|
|
84316
|
+
const allNames = [...proxyEndpoints.keys()];
|
|
84196
84317
|
deps.log({
|
|
84197
84318
|
event: "mcp_proxy_initialized",
|
|
84198
84319
|
serverCount: proxyEndpoints.size,
|
|
84199
|
-
|
|
84320
|
+
connectedCount: connectedNames.length,
|
|
84321
|
+
connectedNames,
|
|
84322
|
+
failedNames: allNames.filter((n) => !connectedNames.includes(n))
|
|
84200
84323
|
});
|
|
84201
84324
|
return { proxyServer: proxy };
|
|
84202
84325
|
} catch (err) {
|
|
@@ -84409,7 +84532,6 @@ async function createDaemon(deps) {
|
|
|
84409
84532
|
initialContent
|
|
84410
84533
|
);
|
|
84411
84534
|
}
|
|
84412
|
-
const proxyManagedNames = /* @__PURE__ */ new Set();
|
|
84413
84535
|
const resolveMcpServers = () => {
|
|
84414
84536
|
if (isVanillaAgentMode()) return void 0;
|
|
84415
84537
|
const userServers = resolveUserMcpServers(capabilitiesRef.current, deps.tokenStore);
|
|
@@ -84417,9 +84539,11 @@ async function createDaemon(deps) {
|
|
|
84417
84539
|
capabilitiesRef.current?.mcpServers?.filter((s2) => !s2.enabled).map((s2) => s2.name) ?? []
|
|
84418
84540
|
);
|
|
84419
84541
|
const pluginServers = resolvePluginMcpServersMap(deps.tokenStore, deps.log, disabledNames);
|
|
84420
|
-
|
|
84542
|
+
const proxyManagedNames = proxyRef.current?.getAllManagedNames() ?? [];
|
|
84543
|
+
if (!userServers && pluginServers.size === 0 && proxyManagedNames.length === 0)
|
|
84544
|
+
return void 0;
|
|
84421
84545
|
const merged = mergePluginAndUserServers(pluginServers, userServers, deps.log);
|
|
84422
|
-
applyProxyFiltering(merged, proxyRef,
|
|
84546
|
+
applyProxyFiltering(merged, proxyRef, disabledNames);
|
|
84423
84547
|
deps.log({
|
|
84424
84548
|
event: "resolve_mcp_servers",
|
|
84425
84549
|
capabilityServerCount: capabilitiesRef.current?.mcpServers?.length ?? 0,
|
|
@@ -84427,7 +84551,7 @@ async function createDaemon(deps) {
|
|
|
84427
84551
|
userServerCount: userServers ? Object.keys(userServers).length : 0,
|
|
84428
84552
|
userServerNames: userServers ? Object.keys(userServers) : [],
|
|
84429
84553
|
pluginServerCount: pluginServers.size,
|
|
84430
|
-
proxyManaged:
|
|
84554
|
+
proxyManaged: proxyManagedNames,
|
|
84431
84555
|
mergedCount: Object.keys(merged).length,
|
|
84432
84556
|
mergedNames: Object.keys(merged)
|
|
84433
84557
|
});
|
|
@@ -84493,7 +84617,13 @@ async function createDaemon(deps) {
|
|
|
84493
84617
|
taskManager.createTask(params);
|
|
84494
84618
|
},
|
|
84495
84619
|
sendMessage: (taskId, content, settings, cwd) => {
|
|
84496
|
-
taskManager.handleUserMessage(taskId, content, settings, cwd)
|
|
84620
|
+
taskManager.handleUserMessage(taskId, content, settings, cwd).catch((err) => {
|
|
84621
|
+
deps.log({
|
|
84622
|
+
event: "schedule_send_message_error",
|
|
84623
|
+
taskId,
|
|
84624
|
+
error: err instanceof Error ? err.message : String(err)
|
|
84625
|
+
});
|
|
84626
|
+
});
|
|
84497
84627
|
},
|
|
84498
84628
|
getRunningScheduleIds: async () => {
|
|
84499
84629
|
const running = /* @__PURE__ */ new Set();
|
|
@@ -84652,7 +84782,6 @@ async function createDaemon(deps) {
|
|
|
84652
84782
|
const { proxyServer } = await initializeProxyServer(
|
|
84653
84783
|
deps,
|
|
84654
84784
|
capabilitiesRef,
|
|
84655
|
-
proxyManagedNames,
|
|
84656
84785
|
() => oauthStateStore.invalidate()
|
|
84657
84786
|
);
|
|
84658
84787
|
proxyRef.current = proxyServer;
|
|
@@ -87109,7 +87238,10 @@ function wireControlChannel(rawChannel, daemon, logAdapter, deps) {
|
|
|
87109
87238
|
if (resolved) {
|
|
87110
87239
|
const without = { ...resolved };
|
|
87111
87240
|
delete without[serverName];
|
|
87112
|
-
daemon.preWarmManager.updateMcpServers(without).then(() => daemon.preWarmManager.updateMcpServers(resolved)).then(() =>
|
|
87241
|
+
daemon.preWarmManager.updateMcpServers(without).then(() => daemon.preWarmManager.updateMcpServers(resolved)).then(() => {
|
|
87242
|
+
daemon.taskManager.reconnectMcpServer(serverName);
|
|
87243
|
+
daemon.taskManager.triggerFastMcpPolling();
|
|
87244
|
+
}).catch((err) => {
|
|
87113
87245
|
logAdapter({
|
|
87114
87246
|
event: `${eventName}_reconnect_failed`,
|
|
87115
87247
|
serverName,
|
|
@@ -87328,12 +87460,11 @@ function wireControlChannel(rawChannel, daemon, logAdapter, deps) {
|
|
|
87328
87460
|
});
|
|
87329
87461
|
},
|
|
87330
87462
|
onRequestTaskIndex: () => {
|
|
87331
|
-
|
|
87332
|
-
daemon.taskStateStore.listTasks().then((tasks) => {
|
|
87463
|
+
daemon.taskStateStore.listTasksWithVersion().then(({ tasks, version }) => {
|
|
87333
87464
|
controlHandler.sendControl({
|
|
87334
87465
|
type: "task_index_snapshot",
|
|
87335
87466
|
tasks,
|
|
87336
|
-
version
|
|
87467
|
+
version
|
|
87337
87468
|
});
|
|
87338
87469
|
}).catch((err) => {
|
|
87339
87470
|
logAdapter({
|
|
@@ -87547,19 +87678,6 @@ function wireControlChannel(rawChannel, daemon, logAdapter, deps) {
|
|
|
87547
87678
|
}
|
|
87548
87679
|
};
|
|
87549
87680
|
pushMcpStatus(5);
|
|
87550
|
-
const initialSnapshotVersion = daemon.taskStateStore.version;
|
|
87551
|
-
daemon.taskStateStore.listTasks().then((tasks) => {
|
|
87552
|
-
controlHandler.sendControl({
|
|
87553
|
-
type: "task_index_snapshot",
|
|
87554
|
-
tasks,
|
|
87555
|
-
version: initialSnapshotVersion
|
|
87556
|
-
});
|
|
87557
|
-
}).catch((err) => {
|
|
87558
|
-
logAdapter({
|
|
87559
|
-
event: "task_index_initial_push_failed",
|
|
87560
|
-
error: err instanceof Error ? err.message : String(err)
|
|
87561
|
-
});
|
|
87562
|
-
});
|
|
87563
87681
|
daemon.userSettingsStore.getSettings().then((settings) => {
|
|
87564
87682
|
controlHandler.sendControl({ type: "user_settings_snapshot", settings });
|
|
87565
87683
|
}).catch((err) => {
|
|
@@ -87661,7 +87779,7 @@ function handleMessageChannel(opts) {
|
|
|
87661
87779
|
}
|
|
87662
87780
|
return result.data;
|
|
87663
87781
|
}
|
|
87664
|
-
function handleSendMessage2(msg) {
|
|
87782
|
+
async function handleSendMessage2(msg) {
|
|
87665
87783
|
try {
|
|
87666
87784
|
const settings = {
|
|
87667
87785
|
model: msg.model,
|
|
@@ -87672,7 +87790,7 @@ function handleMessageChannel(opts) {
|
|
|
87672
87790
|
if (opts.onUserMessage) {
|
|
87673
87791
|
opts.onUserMessage(msg.content, settings, msg.cwd, participantId, senderDisplayName);
|
|
87674
87792
|
} else {
|
|
87675
|
-
taskManager.handleUserMessage(
|
|
87793
|
+
await taskManager.handleUserMessage(
|
|
87676
87794
|
taskId,
|
|
87677
87795
|
msg.content,
|
|
87678
87796
|
settings,
|
|
@@ -87755,7 +87873,7 @@ function handleMessageChannel(opts) {
|
|
|
87755
87873
|
}
|
|
87756
87874
|
switch (msg.type) {
|
|
87757
87875
|
case "send_message":
|
|
87758
|
-
handleSendMessage2(msg);
|
|
87876
|
+
void handleSendMessage2(msg);
|
|
87759
87877
|
break;
|
|
87760
87878
|
case "stop":
|
|
87761
87879
|
if (opts.onStop) opts.onStop();
|
|
@@ -88186,7 +88304,9 @@ function buildCollabPermissions(registry) {
|
|
|
88186
88304
|
return {
|
|
88187
88305
|
visibility: isAllowed,
|
|
88188
88306
|
mutability: isAllowed,
|
|
88189
|
-
creation(
|
|
88307
|
+
creation(docId, peer) {
|
|
88308
|
+
const colonIdx = docId.indexOf(":");
|
|
88309
|
+
if (colonIdx > 0 && OBSOLETE_PREFIXES.has(docId.slice(0, colonIdx))) return false;
|
|
88190
88310
|
if (peer.channelKind === "storage") return true;
|
|
88191
88311
|
if (peer.peerType === "service") return true;
|
|
88192
88312
|
const entry = findEntry(registry, peer);
|
|
@@ -88259,15 +88379,15 @@ var LEGACY_PREFIXES = [
|
|
|
88259
88379
|
"diff-review",
|
|
88260
88380
|
"preview-annotation"
|
|
88261
88381
|
];
|
|
88262
|
-
var OBSOLETE_PREFIXES = /* @__PURE__ */ new Set(["typing", "task-view"]);
|
|
88263
88382
|
function isLegacyDocId(decoded) {
|
|
88264
88383
|
if (decoded.startsWith("v2:")) return true;
|
|
88265
88384
|
return LEGACY_PREFIXES.some((prefix) => decoded.startsWith(`${prefix}:`));
|
|
88266
88385
|
}
|
|
88267
88386
|
function shouldPrune(decoded, currentEpoch) {
|
|
88387
|
+
const firstColon = decoded.indexOf(":");
|
|
88388
|
+
if (firstColon > 0 && OBSOLETE_PREFIXES.has(decoded.slice(0, firstColon))) return true;
|
|
88268
88389
|
const parsed = parseDocumentId(decoded);
|
|
88269
88390
|
if (!parsed) return isLegacyDocId(decoded);
|
|
88270
|
-
if (OBSOLETE_PREFIXES.has(parsed.prefix)) return true;
|
|
88271
88391
|
return parsed.epoch < currentEpoch;
|
|
88272
88392
|
}
|
|
88273
88393
|
async function pruneOldEpochData(dataDir, currentEpoch, log) {
|
|
@@ -88445,6 +88565,12 @@ function handleFileIOChannel(initialCwd, send, log, deps) {
|
|
|
88445
88565
|
case "git_ls_files":
|
|
88446
88566
|
handleGitLsFiles(msg.requestId);
|
|
88447
88567
|
break;
|
|
88568
|
+
case "git_branch_diff_files":
|
|
88569
|
+
handleGitBranchDiffFiles(msg.requestId, msg.baseRef);
|
|
88570
|
+
break;
|
|
88571
|
+
case "git_branch_diff_file":
|
|
88572
|
+
handleGitBranchDiffFile(msg.requestId, msg.path, msg.mergeBase);
|
|
88573
|
+
break;
|
|
88448
88574
|
default:
|
|
88449
88575
|
assertNever(msg);
|
|
88450
88576
|
}
|
|
@@ -88546,6 +88672,79 @@ function handleFileIOChannel(initialCwd, send, log, deps) {
|
|
|
88546
88672
|
respondError(requestId, formatError(err));
|
|
88547
88673
|
}
|
|
88548
88674
|
}
|
|
88675
|
+
async function handleGitBranchDiffFiles(requestId, baseRefOverride) {
|
|
88676
|
+
try {
|
|
88677
|
+
const baseRef = baseRefOverride ?? await getDefaultBranch(cwd);
|
|
88678
|
+
if (!baseRef) {
|
|
88679
|
+
respond({
|
|
88680
|
+
type: "git_branch_diff_files_result",
|
|
88681
|
+
requestId,
|
|
88682
|
+
files: [],
|
|
88683
|
+
mergeBase: "",
|
|
88684
|
+
baseRef: ""
|
|
88685
|
+
});
|
|
88686
|
+
return;
|
|
88687
|
+
}
|
|
88688
|
+
const mergeBase = await getMergeBase(cwd, baseRef);
|
|
88689
|
+
if (!mergeBase) {
|
|
88690
|
+
respond({
|
|
88691
|
+
type: "git_branch_diff_files_result",
|
|
88692
|
+
requestId,
|
|
88693
|
+
files: [],
|
|
88694
|
+
mergeBase: "",
|
|
88695
|
+
baseRef
|
|
88696
|
+
});
|
|
88697
|
+
return;
|
|
88698
|
+
}
|
|
88699
|
+
const { stdout } = await execFileAsync3(
|
|
88700
|
+
"git",
|
|
88701
|
+
["diff", "--name-status", `${mergeBase}..HEAD`],
|
|
88702
|
+
{ cwd, maxBuffer: 10 * 1024 * 1024 }
|
|
88703
|
+
);
|
|
88704
|
+
const files = stdout.split("\n").filter(Boolean).map((line) => {
|
|
88705
|
+
const parts = line.split(" ");
|
|
88706
|
+
const statusCode = parts[0] ?? "";
|
|
88707
|
+
const filePath = parts[1] ?? "";
|
|
88708
|
+
let status;
|
|
88709
|
+
if (statusCode === "A") {
|
|
88710
|
+
status = "added";
|
|
88711
|
+
} else if (statusCode === "D") {
|
|
88712
|
+
status = "deleted";
|
|
88713
|
+
} else {
|
|
88714
|
+
status = "modified";
|
|
88715
|
+
}
|
|
88716
|
+
return { path: filePath, status, insertions: 0, deletions: 0 };
|
|
88717
|
+
});
|
|
88718
|
+
respond({
|
|
88719
|
+
type: "git_branch_diff_files_result",
|
|
88720
|
+
requestId,
|
|
88721
|
+
files,
|
|
88722
|
+
mergeBase,
|
|
88723
|
+
baseRef
|
|
88724
|
+
});
|
|
88725
|
+
} catch (err) {
|
|
88726
|
+
respondError(requestId, formatError(err));
|
|
88727
|
+
}
|
|
88728
|
+
}
|
|
88729
|
+
async function handleGitBranchDiffFile(requestId, filePath, mergeBase) {
|
|
88730
|
+
try {
|
|
88731
|
+
const originalContent = await readGitObject(`${mergeBase}:${filePath}`) ?? "";
|
|
88732
|
+
let modifiedContent;
|
|
88733
|
+
try {
|
|
88734
|
+
modifiedContent = await readFile25(resolve(cwd, filePath), "utf-8");
|
|
88735
|
+
} catch {
|
|
88736
|
+
modifiedContent = "";
|
|
88737
|
+
}
|
|
88738
|
+
respond({
|
|
88739
|
+
type: "git_branch_diff_file_result",
|
|
88740
|
+
requestId,
|
|
88741
|
+
originalContent,
|
|
88742
|
+
modifiedContent
|
|
88743
|
+
});
|
|
88744
|
+
} catch (err) {
|
|
88745
|
+
respondError(requestId, formatError(err));
|
|
88746
|
+
}
|
|
88747
|
+
}
|
|
88549
88748
|
async function handleGitDiffFile(requestId, safeRelPath, absPath, cached) {
|
|
88550
88749
|
try {
|
|
88551
88750
|
let originalContent = "";
|
|
@@ -89030,6 +89229,9 @@ function handleLSPChannel(cwd, send, log) {
|
|
|
89030
89229
|
exited = true;
|
|
89031
89230
|
child = null;
|
|
89032
89231
|
});
|
|
89232
|
+
proc.stdin?.on("error", (err) => {
|
|
89233
|
+
log({ event: "lsp_stdin_error", error: err.message });
|
|
89234
|
+
});
|
|
89033
89235
|
log({ event: "lsp_spawned", pid: proc.pid });
|
|
89034
89236
|
return proc;
|
|
89035
89237
|
}
|
|
@@ -89066,8 +89268,13 @@ function handleLSPChannel(cwd, send, log) {
|
|
|
89066
89268
|
const header = `Content-Length: ${Buffer.byteLength(data)}\r
|
|
89067
89269
|
\r
|
|
89068
89270
|
`;
|
|
89069
|
-
|
|
89070
|
-
|
|
89271
|
+
try {
|
|
89272
|
+
child.stdin?.write(header);
|
|
89273
|
+
child.stdin?.write(data);
|
|
89274
|
+
} catch {
|
|
89275
|
+
log({ event: "lsp_write_failed", exited });
|
|
89276
|
+
child = null;
|
|
89277
|
+
}
|
|
89071
89278
|
}
|
|
89072
89279
|
function dispose() {
|
|
89073
89280
|
disposed = true;
|
|
@@ -89248,84 +89455,94 @@ function createPeerManager(config2) {
|
|
|
89248
89455
|
return factoryPromise;
|
|
89249
89456
|
}
|
|
89250
89457
|
function handleDataChannel(machineId, event) {
|
|
89251
|
-
|
|
89252
|
-
|
|
89253
|
-
|
|
89254
|
-
|
|
89255
|
-
|
|
89256
|
-
|
|
89257
|
-
|
|
89258
|
-
|
|
89259
|
-
|
|
89260
|
-
|
|
89261
|
-
|
|
89262
|
-
|
|
89263
|
-
|
|
89264
|
-
|
|
89265
|
-
|
|
89266
|
-
|
|
89267
|
-
|
|
89268
|
-
|
|
89269
|
-
|
|
89270
|
-
|
|
89271
|
-
|
|
89272
|
-
|
|
89273
|
-
|
|
89274
|
-
|
|
89275
|
-
|
|
89276
|
-
|
|
89277
|
-
|
|
89278
|
-
|
|
89279
|
-
|
|
89280
|
-
|
|
89281
|
-
|
|
89282
|
-
|
|
89283
|
-
|
|
89284
|
-
|
|
89285
|
-
|
|
89286
|
-
|
|
89287
|
-
|
|
89288
|
-
|
|
89289
|
-
|
|
89290
|
-
|
|
89291
|
-
|
|
89292
|
-
|
|
89293
|
-
|
|
89294
|
-
|
|
89295
|
-
|
|
89296
|
-
|
|
89297
|
-
|
|
89298
|
-
|
|
89299
|
-
|
|
89300
|
-
|
|
89301
|
-
|
|
89302
|
-
|
|
89303
|
-
|
|
89304
|
-
|
|
89305
|
-
|
|
89306
|
-
|
|
89307
|
-
|
|
89308
|
-
|
|
89309
|
-
|
|
89310
|
-
|
|
89311
|
-
|
|
89312
|
-
|
|
89313
|
-
|
|
89314
|
-
|
|
89315
|
-
|
|
89316
|
-
|
|
89317
|
-
|
|
89318
|
-
|
|
89319
|
-
|
|
89320
|
-
|
|
89321
|
-
|
|
89322
|
-
|
|
89323
|
-
|
|
89324
|
-
|
|
89325
|
-
|
|
89458
|
+
try {
|
|
89459
|
+
config2.onPeerDataChannel?.(machineId);
|
|
89460
|
+
const channel = event.channel;
|
|
89461
|
+
const label = channel.label ?? "";
|
|
89462
|
+
const route = routeDataChannel(label);
|
|
89463
|
+
switch (route.kind) {
|
|
89464
|
+
case "thread_messages": {
|
|
89465
|
+
config2.log.debug(
|
|
89466
|
+
{ machineId, taskId: route.taskId, threadId: route.threadId },
|
|
89467
|
+
"Thread messages data channel received"
|
|
89468
|
+
);
|
|
89469
|
+
config2.onThreadMessageChannel?.(machineId, event.channel, route.taskId, route.threadId);
|
|
89470
|
+
return;
|
|
89471
|
+
}
|
|
89472
|
+
case "task_messages": {
|
|
89473
|
+
config2.log.debug(
|
|
89474
|
+
{ machineId, taskId: route.taskId },
|
|
89475
|
+
"Task messages data channel received"
|
|
89476
|
+
);
|
|
89477
|
+
config2.onTaskMessageChannel?.(machineId, event.channel, route.taskId);
|
|
89478
|
+
return;
|
|
89479
|
+
}
|
|
89480
|
+
case "daemon_control": {
|
|
89481
|
+
config2.log.info({ machineId }, "Daemon control data channel received");
|
|
89482
|
+
config2.onControlChannel?.(machineId, event.channel);
|
|
89483
|
+
return;
|
|
89484
|
+
}
|
|
89485
|
+
case "loro_sync": {
|
|
89486
|
+
config2.log.info({ machineId }, "Loro sync data channel received");
|
|
89487
|
+
const rawChannel = event.channel;
|
|
89488
|
+
guardLoroChannelSend(rawChannel, config2.log);
|
|
89489
|
+
config2.webrtcAdapter.attachDataChannel(
|
|
89490
|
+
machineIdToPeerId(machineId),
|
|
89491
|
+
event.channel
|
|
89492
|
+
);
|
|
89493
|
+
return;
|
|
89494
|
+
}
|
|
89495
|
+
case "file_io": {
|
|
89496
|
+
config2.log.debug({ machineId, id: route.id }, "File I/O data channel received");
|
|
89497
|
+
config2.onFileIOChannel?.(machineId, event.channel, route.id);
|
|
89498
|
+
return;
|
|
89499
|
+
}
|
|
89500
|
+
case "lsp": {
|
|
89501
|
+
config2.log.debug({ machineId, id: route.id }, "LSP data channel received");
|
|
89502
|
+
config2.onLSPChannel?.(machineId, event.channel, route.id);
|
|
89503
|
+
return;
|
|
89504
|
+
}
|
|
89505
|
+
case "browser_preview": {
|
|
89506
|
+
config2.log.debug(
|
|
89507
|
+
{ machineId, port: route.port },
|
|
89508
|
+
"Browser preview data channel received"
|
|
89509
|
+
);
|
|
89510
|
+
config2.onBrowserPreviewChannel?.(machineId, event.channel, route.port);
|
|
89511
|
+
return;
|
|
89512
|
+
}
|
|
89513
|
+
case "browser_preview_url": {
|
|
89514
|
+
config2.log.debug({ machineId }, "Browser preview URL data channel received");
|
|
89515
|
+
config2.onBrowserPreviewUrlChannel?.(machineId, event.channel);
|
|
89516
|
+
return;
|
|
89517
|
+
}
|
|
89518
|
+
case "terminal": {
|
|
89519
|
+
config2.log.debug(
|
|
89520
|
+
{ machineId, taskId: route.taskId, terminalId: route.terminalId },
|
|
89521
|
+
"Terminal data channel received"
|
|
89522
|
+
);
|
|
89523
|
+
config2.onTerminalChannel?.(machineId, event.channel, route.taskId, route.terminalId);
|
|
89524
|
+
return;
|
|
89525
|
+
}
|
|
89526
|
+
case "asset_transfer": {
|
|
89527
|
+
config2.log.debug({ machineId }, "Asset transfer data channel received");
|
|
89528
|
+
config2.onAssetTransferChannel?.(machineId, event.channel);
|
|
89529
|
+
return;
|
|
89530
|
+
}
|
|
89531
|
+
case "unknown": {
|
|
89532
|
+
config2.log.warn(
|
|
89533
|
+
{ machineId, label: route.label },
|
|
89534
|
+
"Ignoring unrecognized data channel label"
|
|
89535
|
+
);
|
|
89536
|
+
return;
|
|
89537
|
+
}
|
|
89538
|
+
default:
|
|
89539
|
+
assertNever3(route);
|
|
89326
89540
|
}
|
|
89327
|
-
|
|
89328
|
-
|
|
89541
|
+
} catch (err) {
|
|
89542
|
+
config2.log.warn(
|
|
89543
|
+
{ machineId, err: err instanceof Error ? err.message : String(err) },
|
|
89544
|
+
"Data channel routing failed (peer connection likely closing)"
|
|
89545
|
+
);
|
|
89329
89546
|
}
|
|
89330
89547
|
}
|
|
89331
89548
|
function setupPeerHandlers(machineId, pc) {
|
|
@@ -89347,6 +89564,7 @@ function createPeerManager(config2) {
|
|
|
89347
89564
|
if (state === "failed" || state === "closed") {
|
|
89348
89565
|
config2.webrtcAdapter.detachDataChannel(machineIdToPeerId(machineId));
|
|
89349
89566
|
peers.delete(machineId);
|
|
89567
|
+
pc.onconnectionstatechange = null;
|
|
89350
89568
|
pc.close();
|
|
89351
89569
|
}
|
|
89352
89570
|
};
|
|
@@ -89402,7 +89620,20 @@ function createPeerManager(config2) {
|
|
|
89402
89620
|
if (!pc.createOffer) {
|
|
89403
89621
|
throw new Error("PeerConnection does not support createOffer");
|
|
89404
89622
|
}
|
|
89405
|
-
|
|
89623
|
+
let channel;
|
|
89624
|
+
try {
|
|
89625
|
+
channel = pc.createDataChannel(LORO_SYNC_LABEL, { ordered: true });
|
|
89626
|
+
} catch (err) {
|
|
89627
|
+
config2.log.warn(
|
|
89628
|
+
{ targetMachineId, err: String(err) },
|
|
89629
|
+
"createDataChannel failed (connection likely closing)"
|
|
89630
|
+
);
|
|
89631
|
+
pendingCreates.delete(targetMachineId);
|
|
89632
|
+
peers.delete(targetMachineId);
|
|
89633
|
+
pc.onconnectionstatechange = null;
|
|
89634
|
+
pc.close();
|
|
89635
|
+
throw err;
|
|
89636
|
+
}
|
|
89406
89637
|
const rawChannel = channel;
|
|
89407
89638
|
guardLoroChannelSend(rawChannel, config2.log);
|
|
89408
89639
|
rawChannel.onopen = () => {
|
|
@@ -89461,6 +89692,7 @@ function createPeerManager(config2) {
|
|
|
89461
89692
|
const pc = peers.get(targetId);
|
|
89462
89693
|
if (pc) {
|
|
89463
89694
|
config2.webrtcAdapter.detachDataChannel(machineIdToPeerId(targetId));
|
|
89695
|
+
pc.onconnectionstatechange = null;
|
|
89464
89696
|
pc.close();
|
|
89465
89697
|
peers.delete(targetId);
|
|
89466
89698
|
}
|
|
@@ -89468,6 +89700,7 @@ function createPeerManager(config2) {
|
|
|
89468
89700
|
destroy() {
|
|
89469
89701
|
for (const [machineId, pc] of peers) {
|
|
89470
89702
|
config2.webrtcAdapter.detachDataChannel(machineIdToPeerId(machineId));
|
|
89703
|
+
pc.onconnectionstatechange = null;
|
|
89471
89704
|
pc.close();
|
|
89472
89705
|
}
|
|
89473
89706
|
peers.clear();
|
|
@@ -91478,7 +91711,16 @@ function attachConversationHandler(daemon, dc, channelId, params, log, attempts)
|
|
|
91478
91711
|
const handlerOpts = {
|
|
91479
91712
|
taskId,
|
|
91480
91713
|
channelId,
|
|
91481
|
-
send: (data) =>
|
|
91714
|
+
send: (data) => {
|
|
91715
|
+
try {
|
|
91716
|
+
dc.send(data);
|
|
91717
|
+
} catch (err) {
|
|
91718
|
+
log({
|
|
91719
|
+
event: "message_channel_send_failed",
|
|
91720
|
+
error: err instanceof Error ? err.message : String(err)
|
|
91721
|
+
});
|
|
91722
|
+
}
|
|
91723
|
+
},
|
|
91482
91724
|
taskManager: daemon.taskManager,
|
|
91483
91725
|
store: daemon.store,
|
|
91484
91726
|
log,
|
|
@@ -91602,7 +91844,16 @@ function wireThreadErrorFallback(daemon, dc, taskId, threadId, channelId, log) {
|
|
|
91602
91844
|
const handler = handleMessageChannel({
|
|
91603
91845
|
taskId,
|
|
91604
91846
|
channelId,
|
|
91605
|
-
send: (data) =>
|
|
91847
|
+
send: (data) => {
|
|
91848
|
+
try {
|
|
91849
|
+
dc.send(data);
|
|
91850
|
+
} catch (err) {
|
|
91851
|
+
log({
|
|
91852
|
+
event: "message_channel_send_failed",
|
|
91853
|
+
error: err instanceof Error ? err.message : String(err)
|
|
91854
|
+
});
|
|
91855
|
+
}
|
|
91856
|
+
},
|
|
91606
91857
|
taskManager: daemon.taskManager,
|
|
91607
91858
|
store: daemon.store,
|
|
91608
91859
|
log,
|
|
@@ -91647,15 +91898,19 @@ function routeSignalingMessage(peerManager, signalingHandle, log) {
|
|
|
91647
91898
|
switch (msg.type) {
|
|
91648
91899
|
case "webrtc-offer":
|
|
91649
91900
|
if (msg.fromMachineId)
|
|
91650
|
-
peerManager?.handleOffer(msg.fromMachineId, toSDPDescription(msg.offer))
|
|
91901
|
+
peerManager?.handleOffer(msg.fromMachineId, toSDPDescription(msg.offer)).catch(
|
|
91902
|
+
(err) => log.error({ event: "webrtc_offer_failed", error: String(err) })
|
|
91903
|
+
);
|
|
91651
91904
|
break;
|
|
91652
91905
|
case "webrtc-answer":
|
|
91653
91906
|
if (msg.fromMachineId)
|
|
91654
|
-
peerManager?.handleAnswer(msg.fromMachineId, toSDPDescription(msg.answer))
|
|
91907
|
+
peerManager?.handleAnswer(msg.fromMachineId, toSDPDescription(msg.answer)).catch(
|
|
91908
|
+
(err) => log.error({ event: "webrtc_answer_failed", error: String(err) })
|
|
91909
|
+
);
|
|
91655
91910
|
break;
|
|
91656
91911
|
case "webrtc-ice":
|
|
91657
91912
|
if (msg.fromMachineId)
|
|
91658
|
-
peerManager?.handleIce(msg.fromMachineId, toICECandidate(msg.candidate));
|
|
91913
|
+
peerManager?.handleIce(msg.fromMachineId, toICECandidate(msg.candidate)).catch((err) => log.error({ event: "webrtc_ice_failed", error: String(err) }));
|
|
91659
91914
|
break;
|
|
91660
91915
|
case "ice-servers":
|
|
91661
91916
|
peerManager?.updateIceServers(msg.iceServers);
|
|
@@ -91696,4 +91951,4 @@ export {
|
|
|
91696
91951
|
classifyLogLevel,
|
|
91697
91952
|
serve
|
|
91698
91953
|
};
|
|
91699
|
-
//# sourceMappingURL=serve-
|
|
91954
|
+
//# sourceMappingURL=serve-ZD5RISIM.js.map
|