@schoolai/shipyard 3.3.0 → 3.3.1-nightly.20260425.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-UWBX6UGC.js → chunk-SDMIFWEZ.js} +3 -3
- package/dist/chunk-SDMIFWEZ.js.map +1 -0
- package/dist/{chunk-OHIIVBEZ.js → chunk-UEHXOJGL.js} +2 -2
- package/dist/index.js +3 -3
- package/dist/{login-N43V35KE.js → login-DD23VPPF.js} +3 -3
- package/dist/{serve-QLYUK5XN.js → serve-ULDOVKX7.js} +624 -263
- package/dist/{serve-QLYUK5XN.js.map → serve-ULDOVKX7.js.map} +1 -1
- package/dist/{start-NVYMND3X.js → start-TWML63JK.js} +4 -4
- package/package.json +5 -2
- package/dist/chunk-UWBX6UGC.js.map +0 -1
- /package/dist/{chunk-OHIIVBEZ.js.map → chunk-UEHXOJGL.js.map} +0 -0
- /package/dist/{login-N43V35KE.js.map → login-DD23VPPF.js.map} +0 -0
- /package/dist/{start-NVYMND3X.js.map → start-TWML63JK.js.map} +0 -0
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
VaultKeyPutRequestSchema,
|
|
54
54
|
VaultKeyPutResponseSchema,
|
|
55
55
|
classifyClaudeCodeCompatibility
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-SDMIFWEZ.js";
|
|
57
57
|
import "./chunk-EHQITHQX.js";
|
|
58
58
|
import {
|
|
59
59
|
loadAuthToken
|
|
@@ -14592,7 +14592,7 @@ function parseWorktreeListOutput(output, repoPath) {
|
|
|
14592
14592
|
// src/shared/capabilities/index.ts
|
|
14593
14593
|
import { readFile as readFile3 } from "fs/promises";
|
|
14594
14594
|
import { homedir as homedir2 } from "os";
|
|
14595
|
-
import { join as
|
|
14595
|
+
import { join as join6 } from "path";
|
|
14596
14596
|
|
|
14597
14597
|
// src/shared/capabilities/agents.ts
|
|
14598
14598
|
async function detectAgentProviders() {
|
|
@@ -14850,7 +14850,6 @@ async function detectMarketplacePlugins() {
|
|
|
14850
14850
|
// src/shared/capabilities/effort-probe.ts
|
|
14851
14851
|
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
14852
14852
|
import { createRequire } from "module";
|
|
14853
|
-
import { dirname as dirname3, join as join6 } from "path";
|
|
14854
14853
|
|
|
14855
14854
|
// ../../packages/loro-schema/dist/index.js
|
|
14856
14855
|
import { LoroDoc as LoroDoc4 } from "loro-crdt";
|
|
@@ -28056,8 +28055,7 @@ var RequestPublishShape = external_exports.object({
|
|
|
28056
28055
|
external_exports.object({
|
|
28057
28056
|
kind: external_exports.literal("previewPort"),
|
|
28058
28057
|
previewPort: external_exports.number().int().positive().max(65535),
|
|
28059
|
-
canvasElementId: external_exports.string().optional()
|
|
28060
|
-
projectRoot: external_exports.string().optional()
|
|
28058
|
+
canvasElementId: external_exports.string().optional()
|
|
28061
28059
|
})
|
|
28062
28060
|
]),
|
|
28063
28061
|
ttl: external_exports.enum(["24h", "7d", "30d"]),
|
|
@@ -28106,6 +28104,20 @@ var PublishedArtifactsStateShape = external_exports.object({
|
|
|
28106
28104
|
taskId: external_exports.string(),
|
|
28107
28105
|
entries: external_exports.array(PublishedArtifactRecordShape)
|
|
28108
28106
|
});
|
|
28107
|
+
var PreviewElementStateShape = external_exports.object({
|
|
28108
|
+
elementId: external_exports.string().min(1),
|
|
28109
|
+
ownerUserId: external_exports.string(),
|
|
28110
|
+
port: external_exports.number().int().positive().optional(),
|
|
28111
|
+
url: external_exports.string().optional(),
|
|
28112
|
+
proxyPort: external_exports.number().int().positive().optional(),
|
|
28113
|
+
initialPath: external_exports.string().optional(),
|
|
28114
|
+
projectRoot: external_exports.string().optional()
|
|
28115
|
+
});
|
|
28116
|
+
var PreviewElementsStateShape = external_exports.object({
|
|
28117
|
+
type: external_exports.literal("preview_elements_state"),
|
|
28118
|
+
taskId: external_exports.string(),
|
|
28119
|
+
entries: external_exports.array(PreviewElementStateShape)
|
|
28120
|
+
});
|
|
28109
28121
|
var BrowserToDaemonControlMessageSchema = external_exports.discriminatedUnion("type", [
|
|
28110
28122
|
external_exports.object({
|
|
28111
28123
|
type: external_exports.literal("permission_response"),
|
|
@@ -28451,6 +28463,7 @@ var RateLimitInfoSchema = external_exports.object({
|
|
|
28451
28463
|
"org_service_level_disabled",
|
|
28452
28464
|
"org_service_zero_credit_limit",
|
|
28453
28465
|
"no_limits_configured",
|
|
28466
|
+
"fetch_error",
|
|
28454
28467
|
"unknown"
|
|
28455
28468
|
]).optional(),
|
|
28456
28469
|
isUsingOverage: external_exports.boolean().optional(),
|
|
@@ -28938,7 +28951,8 @@ var DaemonToBrowserControlMessageSchema = external_exports.discriminatedUnion("t
|
|
|
28938
28951
|
}),
|
|
28939
28952
|
PublishProgressShape,
|
|
28940
28953
|
PublishResultShape,
|
|
28941
|
-
PublishedArtifactsStateShape
|
|
28954
|
+
PublishedArtifactsStateShape,
|
|
28955
|
+
PreviewElementsStateShape
|
|
28942
28956
|
]);
|
|
28943
28957
|
var TASK_MESSAGES_PREFIX = "task-messages:";
|
|
28944
28958
|
var DAEMON_CONTROL_LABEL = "daemon-control";
|
|
@@ -29319,8 +29333,7 @@ var PublishTargetSchema = external_exports.discriminatedUnion("kind", [
|
|
|
29319
29333
|
external_exports.object({
|
|
29320
29334
|
kind: external_exports.literal("previewPort"),
|
|
29321
29335
|
previewPort: external_exports.number().int().positive().max(65535),
|
|
29322
|
-
canvasElementId: external_exports.string().optional()
|
|
29323
|
-
projectRoot: external_exports.string().optional()
|
|
29336
|
+
canvasElementId: external_exports.string().optional()
|
|
29324
29337
|
})
|
|
29325
29338
|
]);
|
|
29326
29339
|
var PublishInputSchema = external_exports.object({
|
|
@@ -30319,21 +30332,27 @@ function isReasoningEffort(value) {
|
|
|
30319
30332
|
}
|
|
30320
30333
|
function probeCli() {
|
|
30321
30334
|
try {
|
|
30322
|
-
const
|
|
30323
|
-
|
|
30324
|
-
|
|
30325
|
-
|
|
30335
|
+
const binaryPath = resolveBundledClaudeBinary();
|
|
30336
|
+
if (!binaryPath || !existsSync2(binaryPath)) {
|
|
30337
|
+
logger.warn(
|
|
30338
|
+
{ binaryPath },
|
|
30339
|
+
"bundled Claude Code binary not found; using conservative effort set"
|
|
30340
|
+
);
|
|
30341
|
+
return { supported: CONSERVATIVE_FALLBACK, source: "fallback" };
|
|
30342
|
+
}
|
|
30343
|
+
const slice2 = readEffortDescriptionFromBinary(binaryPath);
|
|
30344
|
+
if (slice2 === null) {
|
|
30326
30345
|
logger.warn(
|
|
30327
|
-
{
|
|
30328
|
-
"
|
|
30346
|
+
{ binaryPath },
|
|
30347
|
+
"effort description not found in bundled binary; using conservative effort set"
|
|
30329
30348
|
);
|
|
30330
30349
|
return { supported: CONSERVATIVE_FALLBACK, source: "fallback" };
|
|
30331
30350
|
}
|
|
30332
|
-
const parsed = parseEffortsFromCliText(
|
|
30351
|
+
const parsed = parseEffortsFromCliText(slice2);
|
|
30333
30352
|
if (!parsed) {
|
|
30334
30353
|
logger.warn(
|
|
30335
|
-
{
|
|
30336
|
-
"could not parse effort tokens from bundled
|
|
30354
|
+
{ binaryPath },
|
|
30355
|
+
"could not parse effort tokens from bundled binary; using conservative effort set"
|
|
30337
30356
|
);
|
|
30338
30357
|
return { supported: CONSERVATIVE_FALLBACK, source: "fallback" };
|
|
30339
30358
|
}
|
|
@@ -30343,6 +30362,32 @@ function probeCli() {
|
|
|
30343
30362
|
return { supported: CONSERVATIVE_FALLBACK, source: "fallback" };
|
|
30344
30363
|
}
|
|
30345
30364
|
}
|
|
30365
|
+
function resolveBundledClaudeBinary() {
|
|
30366
|
+
const req = createRequire(import.meta.url);
|
|
30367
|
+
const sdkMain = req.resolve("@anthropic-ai/claude-agent-sdk");
|
|
30368
|
+
const sdkReq = createRequire(sdkMain);
|
|
30369
|
+
const ext2 = process.platform === "win32" ? ".exe" : "";
|
|
30370
|
+
const candidates = process.platform === "linux" ? [
|
|
30371
|
+
`@anthropic-ai/claude-agent-sdk-linux-${process.arch}-musl`,
|
|
30372
|
+
`@anthropic-ai/claude-agent-sdk-linux-${process.arch}`
|
|
30373
|
+
] : [`@anthropic-ai/claude-agent-sdk-${process.platform}-${process.arch}`];
|
|
30374
|
+
for (const pkg of candidates) {
|
|
30375
|
+
try {
|
|
30376
|
+
return sdkReq.resolve(`${pkg}/claude${ext2}`);
|
|
30377
|
+
} catch (err) {
|
|
30378
|
+
logger.debug({ pkg, err }, "platform claude binary candidate not resolvable");
|
|
30379
|
+
}
|
|
30380
|
+
}
|
|
30381
|
+
return null;
|
|
30382
|
+
}
|
|
30383
|
+
function readEffortDescriptionFromBinary(binaryPath) {
|
|
30384
|
+
const buf = readFileSync(binaryPath);
|
|
30385
|
+
const needle = Buffer.from("Effort level for the current session");
|
|
30386
|
+
const idx = buf.indexOf(needle);
|
|
30387
|
+
if (idx === -1) return null;
|
|
30388
|
+
const end = Math.min(idx + 200, buf.length);
|
|
30389
|
+
return buf.toString("utf-8", idx, end);
|
|
30390
|
+
}
|
|
30346
30391
|
|
|
30347
30392
|
// src/shared/capabilities/models.ts
|
|
30348
30393
|
async function detectModels() {
|
|
@@ -31139,7 +31184,7 @@ var AutoModeConfigSchema = external_exports.object({
|
|
|
31139
31184
|
}).passthrough();
|
|
31140
31185
|
async function detectAutoModeEnabled() {
|
|
31141
31186
|
try {
|
|
31142
|
-
const claudeConfig = await readFile3(
|
|
31187
|
+
const claudeConfig = await readFile3(join6(homedir2(), ".claude.json"), "utf-8");
|
|
31143
31188
|
const result = AutoModeConfigSchema.safeParse(JSON.parse(claudeConfig));
|
|
31144
31189
|
return result.success && result.data.cachedGrowthBookFeatures.tengu_auto_mode_config.enabled === "enabled";
|
|
31145
31190
|
} catch {
|
|
@@ -31208,7 +31253,7 @@ async function detectCapabilitiesWithInitialRetry(tokenStore, methodHint, lastKn
|
|
|
31208
31253
|
|
|
31209
31254
|
// src/shared/file-storage-adapter.ts
|
|
31210
31255
|
import { access, mkdir as mkdir2, readdir as readdir3, readFile as readFile4, rename as rename2, unlink as unlink2, writeFile as writeFile2 } from "fs/promises";
|
|
31211
|
-
import { dirname as
|
|
31256
|
+
import { dirname as dirname3, join as join7, sep } from "path";
|
|
31212
31257
|
var FileStorageAdapter = class _FileStorageAdapter extends StorageAdapter {
|
|
31213
31258
|
#dataDir;
|
|
31214
31259
|
constructor(dataDir) {
|
|
@@ -31226,7 +31271,7 @@ var FileStorageAdapter = class _FileStorageAdapter extends StorageAdapter {
|
|
|
31226
31271
|
}
|
|
31227
31272
|
async save(key, data) {
|
|
31228
31273
|
const filePath = this.#keyToPath(key);
|
|
31229
|
-
const dir =
|
|
31274
|
+
const dir = dirname3(filePath);
|
|
31230
31275
|
await mkdir2(dir, { recursive: true, mode: 448 });
|
|
31231
31276
|
const tmpPath = `${filePath}.tmp`;
|
|
31232
31277
|
await writeFile2(tmpPath, data, { mode: 384 });
|
|
@@ -31268,7 +31313,7 @@ var FileStorageAdapter = class _FileStorageAdapter extends StorageAdapter {
|
|
|
31268
31313
|
* docId is the first key segment (e.g. "canvas:<taskId>:<epoch>").
|
|
31269
31314
|
*/
|
|
31270
31315
|
async hasDoc(docId) {
|
|
31271
|
-
const dirPath =
|
|
31316
|
+
const dirPath = join7(this.#dataDir, encodeURIComponent(docId));
|
|
31272
31317
|
try {
|
|
31273
31318
|
await access(dirPath);
|
|
31274
31319
|
return true;
|
|
@@ -31282,7 +31327,7 @@ var FileStorageAdapter = class _FileStorageAdapter extends StorageAdapter {
|
|
|
31282
31327
|
}
|
|
31283
31328
|
#keyToPath(key) {
|
|
31284
31329
|
const sanitized = key.map((part) => encodeURIComponent(part));
|
|
31285
|
-
return
|
|
31330
|
+
return join7(this.#dataDir, ...sanitized);
|
|
31286
31331
|
}
|
|
31287
31332
|
#pathToKey(filePath) {
|
|
31288
31333
|
const relative5 = filePath.slice(this.#dataDir.length + 1);
|
|
@@ -31300,7 +31345,7 @@ var FileStorageAdapter = class _FileStorageAdapter extends StorageAdapter {
|
|
|
31300
31345
|
return;
|
|
31301
31346
|
}
|
|
31302
31347
|
for (const entry of entries) {
|
|
31303
|
-
const fullPath =
|
|
31348
|
+
const fullPath = join7(dir, entry.name);
|
|
31304
31349
|
if (entry.isDirectory()) {
|
|
31305
31350
|
await this.#walkDir(fullPath, keyPrefix, results);
|
|
31306
31351
|
} else if (entry.isFile() && !entry.name.endsWith(".tmp")) {
|
|
@@ -31478,7 +31523,7 @@ var KeepAwakeManager = class {
|
|
|
31478
31523
|
// src/shared/mcp/token-store.ts
|
|
31479
31524
|
import { readFileSync as readFileSync2, statSync } from "fs";
|
|
31480
31525
|
import { readFile as readFile5, rename as rename3, stat as stat3, writeFile as writeFile3 } from "fs/promises";
|
|
31481
|
-
import { join as
|
|
31526
|
+
import { join as join8 } from "path";
|
|
31482
31527
|
var TOKEN_FILE = "mcp-tokens.json";
|
|
31483
31528
|
var REFRESH_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
31484
31529
|
var MCPTokenStore = class {
|
|
@@ -31496,7 +31541,7 @@ var MCPTokenStore = class {
|
|
|
31496
31541
|
this.#onChange = cb;
|
|
31497
31542
|
}
|
|
31498
31543
|
#filePath() {
|
|
31499
|
-
return
|
|
31544
|
+
return join8(this.#shipyardHome, TOKEN_FILE);
|
|
31500
31545
|
}
|
|
31501
31546
|
/** Read mtime from disk. Returns -1 if file does not exist. */
|
|
31502
31547
|
#readMtimeMs() {
|
|
@@ -31608,7 +31653,7 @@ var MCPTokenStore = class {
|
|
|
31608
31653
|
// src/services/bootstrap/lifecycle.ts
|
|
31609
31654
|
import { unlinkSync } from "fs";
|
|
31610
31655
|
import { readFile as readFile6, unlink as unlink3, writeFile as writeFile4 } from "fs/promises";
|
|
31611
|
-
import { join as
|
|
31656
|
+
import { join as join9 } from "path";
|
|
31612
31657
|
|
|
31613
31658
|
// src/services/bootstrap/classify-uncaught-error.ts
|
|
31614
31659
|
function classifyUncaughtError(error2) {
|
|
@@ -31742,7 +31787,7 @@ var LifecycleManager = class {
|
|
|
31742
31787
|
this.#removePidFileSync();
|
|
31743
31788
|
}
|
|
31744
31789
|
async acquirePidFile(shipyardHome) {
|
|
31745
|
-
const pidFilePath =
|
|
31790
|
+
const pidFilePath = join9(shipyardHome, "daemon.pid");
|
|
31746
31791
|
try {
|
|
31747
31792
|
const existing = await readFile6(pidFilePath, "utf-8");
|
|
31748
31793
|
const raw = existing.trim();
|
|
@@ -31939,10 +31984,10 @@ var LifecycleManager = class {
|
|
|
31939
31984
|
// src/services/bootstrap/load-or-create-peer-id.ts
|
|
31940
31985
|
import { randomUUID } from "crypto";
|
|
31941
31986
|
import { mkdir as mkdir3, readFile as readFile7, rename as rename4, writeFile as writeFile5 } from "fs/promises";
|
|
31942
|
-
import { dirname as
|
|
31987
|
+
import { dirname as dirname4, join as join10 } from "path";
|
|
31943
31988
|
var PEER_ID_FILE = "daemon-peer-id";
|
|
31944
31989
|
async function loadOrCreateDaemonPeerId(shipyardDataDir) {
|
|
31945
|
-
const target =
|
|
31990
|
+
const target = join10(shipyardDataDir, PEER_ID_FILE);
|
|
31946
31991
|
const existing = await readExistingPeerId(target);
|
|
31947
31992
|
if (existing !== null) return existing;
|
|
31948
31993
|
const peerId = generatePeerId();
|
|
@@ -31967,7 +32012,7 @@ async function readExistingPeerId(target) {
|
|
|
31967
32012
|
return candidate;
|
|
31968
32013
|
}
|
|
31969
32014
|
async function writePeerIdAtomic(target, peerId) {
|
|
31970
|
-
await mkdir3(
|
|
32015
|
+
await mkdir3(dirname4(target), { recursive: true });
|
|
31971
32016
|
const tmp = `${target}.${randomUUID()}.tmp`;
|
|
31972
32017
|
await writeFile5(tmp, peerId, "utf-8");
|
|
31973
32018
|
await rename4(tmp, target);
|
|
@@ -31975,10 +32020,10 @@ async function writePeerIdAtomic(target, peerId) {
|
|
|
31975
32020
|
|
|
31976
32021
|
// src/services/bootstrap/pid-tracking.ts
|
|
31977
32022
|
import { readFile as readFile8, writeFile as writeFile6 } from "fs/promises";
|
|
31978
|
-
import { join as
|
|
32023
|
+
import { join as join11 } from "path";
|
|
31979
32024
|
var PID_FILE = "children.pid";
|
|
31980
32025
|
function buildPidTracker(shipyardHome) {
|
|
31981
|
-
const filePath =
|
|
32026
|
+
const filePath = join11(shipyardHome, PID_FILE);
|
|
31982
32027
|
let queue = Promise.resolve();
|
|
31983
32028
|
function enqueue(fn) {
|
|
31984
32029
|
const next = queue.then(fn);
|
|
@@ -32061,7 +32106,7 @@ function buildReloadDocsFromStorage(repoRef, log) {
|
|
|
32061
32106
|
// src/services/bootstrap/signaling.ts
|
|
32062
32107
|
import { mkdirSync, readFileSync as readFileSync3, writeFileSync } from "fs";
|
|
32063
32108
|
import { hostname } from "os";
|
|
32064
|
-
import { dirname as
|
|
32109
|
+
import { dirname as dirname5, join as join12 } from "path";
|
|
32065
32110
|
|
|
32066
32111
|
// ../../node_modules/.pnpm/nanoid@5.1.6/node_modules/nanoid/index.js
|
|
32067
32112
|
import { webcrypto as crypto2 } from "crypto";
|
|
@@ -32094,7 +32139,7 @@ function nanoid(size2 = 21) {
|
|
|
32094
32139
|
}
|
|
32095
32140
|
|
|
32096
32141
|
// src/services/bootstrap/signaling.ts
|
|
32097
|
-
var DAEMON_NPM_VERSION = true ? "3.3.
|
|
32142
|
+
var DAEMON_NPM_VERSION = true ? "3.3.1" : "unknown";
|
|
32098
32143
|
function createDaemonSignaling(config2) {
|
|
32099
32144
|
const agentId = config2.agentId ?? nanoid();
|
|
32100
32145
|
function send(msg) {
|
|
@@ -32123,7 +32168,7 @@ function createDaemonSignaling(config2) {
|
|
|
32123
32168
|
};
|
|
32124
32169
|
}
|
|
32125
32170
|
function getOrCreateAgentId(shipyardHome) {
|
|
32126
|
-
const filePath =
|
|
32171
|
+
const filePath = join12(shipyardHome, "agent-id");
|
|
32127
32172
|
try {
|
|
32128
32173
|
const existing = readFileSync3(filePath, "utf-8").trim();
|
|
32129
32174
|
if (existing) return existing;
|
|
@@ -32131,7 +32176,7 @@ function getOrCreateAgentId(shipyardHome) {
|
|
|
32131
32176
|
}
|
|
32132
32177
|
const id = crypto.randomUUID();
|
|
32133
32178
|
try {
|
|
32134
|
-
mkdirSync(
|
|
32179
|
+
mkdirSync(dirname5(filePath), { recursive: true });
|
|
32135
32180
|
writeFileSync(filePath, id, { mode: 384 });
|
|
32136
32181
|
} catch {
|
|
32137
32182
|
}
|
|
@@ -32339,7 +32384,7 @@ function createPeerRoleRegistry() {
|
|
|
32339
32384
|
|
|
32340
32385
|
// src/services/epoch-pruning.ts
|
|
32341
32386
|
import { readdir as readdir4, rm } from "fs/promises";
|
|
32342
|
-
import { join as
|
|
32387
|
+
import { join as join13 } from "path";
|
|
32343
32388
|
var LEGACY_PREFIXES = [
|
|
32344
32389
|
"task-meta",
|
|
32345
32390
|
"task-conv",
|
|
@@ -32379,7 +32424,7 @@ async function pruneOldEpochData(dataDir, currentEpoch, log) {
|
|
|
32379
32424
|
}
|
|
32380
32425
|
if (!shouldPrune(decoded, currentEpoch)) continue;
|
|
32381
32426
|
removals.push(
|
|
32382
|
-
rm(
|
|
32427
|
+
rm(join13(dataDir, entry.name), { recursive: true }).then(() => {
|
|
32383
32428
|
pruned++;
|
|
32384
32429
|
}).catch((err) => {
|
|
32385
32430
|
log({
|
|
@@ -34385,7 +34430,7 @@ function onConnection(ws, deps, peers) {
|
|
|
34385
34430
|
|
|
34386
34431
|
// src/services/local-direct/local-direct-token.ts
|
|
34387
34432
|
import { chmod, mkdir as mkdir4, rename as rename5, rm as rm2, writeFile as writeFile7 } from "fs/promises";
|
|
34388
|
-
import { dirname as
|
|
34433
|
+
import { dirname as dirname6, join as join14 } from "path";
|
|
34389
34434
|
var ADVERTISEMENT_FILE = "local-direct.json";
|
|
34390
34435
|
var ADVERTISEMENT_MODE = 384;
|
|
34391
34436
|
var ADVERTISEMENT_DIR_MODE = 448;
|
|
@@ -34394,11 +34439,11 @@ function generateLocalDirectToken() {
|
|
|
34394
34439
|
return nanoid(TOKEN_LENGTH);
|
|
34395
34440
|
}
|
|
34396
34441
|
function advertisementPath(shipyardHome) {
|
|
34397
|
-
return
|
|
34442
|
+
return join14(shipyardHome, "data", ADVERTISEMENT_FILE);
|
|
34398
34443
|
}
|
|
34399
34444
|
async function writeAdvertisement(shipyardHome, ad) {
|
|
34400
34445
|
const target = advertisementPath(shipyardHome);
|
|
34401
|
-
const dir =
|
|
34446
|
+
const dir = dirname6(target);
|
|
34402
34447
|
await mkdir4(dir, { recursive: true, mode: ADVERTISEMENT_DIR_MODE });
|
|
34403
34448
|
try {
|
|
34404
34449
|
await chmod(dir, ADVERTISEMENT_DIR_MODE);
|
|
@@ -34523,7 +34568,7 @@ function createMetricsCollector(workerUrl, authToken, telemetryEnabled) {
|
|
|
34523
34568
|
// src/services/plugins/plugin-file-watcher.ts
|
|
34524
34569
|
import { existsSync as existsSync3, watch } from "fs";
|
|
34525
34570
|
import { readdir as readdir5, readFile as readFile9, stat as stat4 } from "fs/promises";
|
|
34526
|
-
import { join as
|
|
34571
|
+
import { join as join15 } from "path";
|
|
34527
34572
|
import { pathToFileURL } from "url";
|
|
34528
34573
|
|
|
34529
34574
|
// src/shared/plugins/plugin-registry.ts
|
|
@@ -34624,7 +34669,7 @@ var PluginFileWatcher = class {
|
|
|
34624
34669
|
}
|
|
34625
34670
|
const loaded = [];
|
|
34626
34671
|
for (const entry of entries) {
|
|
34627
|
-
const pluginDir =
|
|
34672
|
+
const pluginDir = join15(dir, entry);
|
|
34628
34673
|
let stats;
|
|
34629
34674
|
try {
|
|
34630
34675
|
stats = await stat4(pluginDir);
|
|
@@ -34639,7 +34684,7 @@ var PluginFileWatcher = class {
|
|
|
34639
34684
|
this.#reconcile(loaded);
|
|
34640
34685
|
}
|
|
34641
34686
|
async #loadPlugin(id, pluginDir) {
|
|
34642
|
-
const manifestPath =
|
|
34687
|
+
const manifestPath = join15(pluginDir, "plugin.json");
|
|
34643
34688
|
let manifestRaw;
|
|
34644
34689
|
try {
|
|
34645
34690
|
manifestRaw = await readFile9(manifestPath, "utf-8");
|
|
@@ -34666,7 +34711,7 @@ var PluginFileWatcher = class {
|
|
|
34666
34711
|
}
|
|
34667
34712
|
const manifest = parsed.data;
|
|
34668
34713
|
let template = "";
|
|
34669
|
-
const templatePath =
|
|
34714
|
+
const templatePath = join15(pluginDir, "template.html");
|
|
34670
34715
|
try {
|
|
34671
34716
|
template = await readFile9(templatePath, "utf-8");
|
|
34672
34717
|
} catch {
|
|
@@ -34681,7 +34726,7 @@ var PluginFileWatcher = class {
|
|
|
34681
34726
|
};
|
|
34682
34727
|
}
|
|
34683
34728
|
async #loadAndRegisterHandler(id, pluginDir, title) {
|
|
34684
|
-
const handlerPath =
|
|
34729
|
+
const handlerPath = join15(pluginDir, "handler.mjs");
|
|
34685
34730
|
let handlerFn;
|
|
34686
34731
|
try {
|
|
34687
34732
|
const handlerStat = await stat4(handlerPath);
|
|
@@ -35348,7 +35393,7 @@ function handlePluginAuthRequest(pluginId, sendControl, deps, logAdapter) {
|
|
|
35348
35393
|
// src/services/port-detection.ts
|
|
35349
35394
|
import { execFile as execFile3 } from "child_process";
|
|
35350
35395
|
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
35351
|
-
import { dirname as
|
|
35396
|
+
import { dirname as dirname7, join as join16 } from "path";
|
|
35352
35397
|
import { promisify as promisify2 } from "util";
|
|
35353
35398
|
var execFileAsync = promisify2(execFile3);
|
|
35354
35399
|
var EXEC_TIMEOUT_MS2 = 5e3;
|
|
@@ -35463,7 +35508,7 @@ function hasStringName(val) {
|
|
|
35463
35508
|
function resolveProjectRoot(cwd) {
|
|
35464
35509
|
let dir = cwd;
|
|
35465
35510
|
while (true) {
|
|
35466
|
-
const candidate =
|
|
35511
|
+
const candidate = join16(dir, "package.json");
|
|
35467
35512
|
if (existsSync4(candidate)) {
|
|
35468
35513
|
let packageName;
|
|
35469
35514
|
try {
|
|
@@ -35476,7 +35521,7 @@ function resolveProjectRoot(cwd) {
|
|
|
35476
35521
|
}
|
|
35477
35522
|
return { projectRoot: dir, packageName };
|
|
35478
35523
|
}
|
|
35479
|
-
const parent =
|
|
35524
|
+
const parent = dirname7(dir);
|
|
35480
35525
|
if (parent === dir) {
|
|
35481
35526
|
return {};
|
|
35482
35527
|
}
|
|
@@ -35573,6 +35618,175 @@ async function getCwdByPid(pids) {
|
|
|
35573
35618
|
}
|
|
35574
35619
|
}
|
|
35575
35620
|
|
|
35621
|
+
// src/services/preview/preview-state-store.ts
|
|
35622
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
35623
|
+
import {
|
|
35624
|
+
mkdirSync as mkdirSync2,
|
|
35625
|
+
readdirSync,
|
|
35626
|
+
readFileSync as readFileSync5,
|
|
35627
|
+
renameSync,
|
|
35628
|
+
unlinkSync as unlinkSync2,
|
|
35629
|
+
writeFileSync as writeFileSync2
|
|
35630
|
+
} from "fs";
|
|
35631
|
+
import { join as join17 } from "path";
|
|
35632
|
+
function isEnoent2(err) {
|
|
35633
|
+
return err instanceof Error && Reflect.get(err, "code") === "ENOENT";
|
|
35634
|
+
}
|
|
35635
|
+
function atomicWriteSync(filePath, content) {
|
|
35636
|
+
const tmpPath = `${filePath}.${randomUUID2()}.tmp`;
|
|
35637
|
+
writeFileSync2(tmpPath, content, "utf-8");
|
|
35638
|
+
renameSync(tmpPath, filePath);
|
|
35639
|
+
}
|
|
35640
|
+
function recordFilePath(rootDir, taskId, elementId) {
|
|
35641
|
+
return join17(rootDir, taskId, `${elementId}.json`);
|
|
35642
|
+
}
|
|
35643
|
+
function parseRecord(filePath, logger2) {
|
|
35644
|
+
let raw;
|
|
35645
|
+
try {
|
|
35646
|
+
raw = readFileSync5(filePath, "utf-8");
|
|
35647
|
+
} catch {
|
|
35648
|
+
return null;
|
|
35649
|
+
}
|
|
35650
|
+
let obj;
|
|
35651
|
+
try {
|
|
35652
|
+
obj = JSON.parse(raw);
|
|
35653
|
+
} catch {
|
|
35654
|
+
logger2.warn({ filePath }, "preview_state_store: invalid JSON, skipping");
|
|
35655
|
+
return null;
|
|
35656
|
+
}
|
|
35657
|
+
const result = PreviewElementStateShape.safeParse(obj);
|
|
35658
|
+
if (!result.success) {
|
|
35659
|
+
logger2.warn(
|
|
35660
|
+
{ filePath, issues: result.error.issues },
|
|
35661
|
+
"preview_state_store: schema validation failed, skipping"
|
|
35662
|
+
);
|
|
35663
|
+
return null;
|
|
35664
|
+
}
|
|
35665
|
+
return result.data;
|
|
35666
|
+
}
|
|
35667
|
+
function createPreviewStateStore(opts) {
|
|
35668
|
+
const { rootDir, logger: logger2 } = opts;
|
|
35669
|
+
const registry = /* @__PURE__ */ new Map();
|
|
35670
|
+
let sendFn = null;
|
|
35671
|
+
mkdirSync2(rootDir, { recursive: true });
|
|
35672
|
+
function getTaskMap(taskId) {
|
|
35673
|
+
let taskMap = registry.get(taskId);
|
|
35674
|
+
if (!taskMap) {
|
|
35675
|
+
taskMap = /* @__PURE__ */ new Map();
|
|
35676
|
+
registry.set(taskId, taskMap);
|
|
35677
|
+
}
|
|
35678
|
+
return taskMap;
|
|
35679
|
+
}
|
|
35680
|
+
function scanTaskDir(taskId) {
|
|
35681
|
+
const taskPath = join17(rootDir, taskId);
|
|
35682
|
+
let files;
|
|
35683
|
+
try {
|
|
35684
|
+
files = readdirSync(taskPath);
|
|
35685
|
+
} catch {
|
|
35686
|
+
return;
|
|
35687
|
+
}
|
|
35688
|
+
for (const file of files) {
|
|
35689
|
+
if (!file.endsWith(".json")) continue;
|
|
35690
|
+
const record = parseRecord(join17(taskPath, file), logger2);
|
|
35691
|
+
if (record) getTaskMap(taskId).set(record.elementId, record);
|
|
35692
|
+
}
|
|
35693
|
+
}
|
|
35694
|
+
function scanRootDir() {
|
|
35695
|
+
let taskDirs;
|
|
35696
|
+
try {
|
|
35697
|
+
taskDirs = readdirSync(rootDir);
|
|
35698
|
+
} catch {
|
|
35699
|
+
return;
|
|
35700
|
+
}
|
|
35701
|
+
for (const taskId of taskDirs) {
|
|
35702
|
+
scanTaskDir(taskId);
|
|
35703
|
+
}
|
|
35704
|
+
}
|
|
35705
|
+
scanRootDir();
|
|
35706
|
+
function broadcastTask(taskId) {
|
|
35707
|
+
if (!sendFn) return;
|
|
35708
|
+
const taskMap = registry.get(taskId);
|
|
35709
|
+
const entries = taskMap ? [...taskMap.values()] : [];
|
|
35710
|
+
entries.sort((a, b2) => a.elementId < b2.elementId ? -1 : a.elementId > b2.elementId ? 1 : 0);
|
|
35711
|
+
sendFn({ type: "preview_elements_state", taskId, entries });
|
|
35712
|
+
}
|
|
35713
|
+
function writeToDisk(taskId, state) {
|
|
35714
|
+
const filePath = recordFilePath(rootDir, taskId, state.elementId);
|
|
35715
|
+
try {
|
|
35716
|
+
mkdirSync2(join17(rootDir, taskId), { recursive: true });
|
|
35717
|
+
atomicWriteSync(filePath, JSON.stringify(state, null, 2));
|
|
35718
|
+
} catch (err) {
|
|
35719
|
+
logger2.warn(
|
|
35720
|
+
{
|
|
35721
|
+
taskId,
|
|
35722
|
+
elementId: state.elementId,
|
|
35723
|
+
err: err instanceof Error ? err.message : String(err)
|
|
35724
|
+
},
|
|
35725
|
+
"preview_state_store: putState disk write failed"
|
|
35726
|
+
);
|
|
35727
|
+
}
|
|
35728
|
+
}
|
|
35729
|
+
function removeFromDisk(taskId, elementId) {
|
|
35730
|
+
const filePath = recordFilePath(rootDir, taskId, elementId);
|
|
35731
|
+
try {
|
|
35732
|
+
unlinkSync2(filePath);
|
|
35733
|
+
} catch (err) {
|
|
35734
|
+
if (!isEnoent2(err)) {
|
|
35735
|
+
logger2.warn(
|
|
35736
|
+
{ taskId, elementId, err: err instanceof Error ? err.message : String(err) },
|
|
35737
|
+
"preview_state_store: deleteByElementId disk unlink failed"
|
|
35738
|
+
);
|
|
35739
|
+
}
|
|
35740
|
+
}
|
|
35741
|
+
}
|
|
35742
|
+
return {
|
|
35743
|
+
getByElementId(taskId, elementId) {
|
|
35744
|
+
return registry.get(taskId)?.get(elementId);
|
|
35745
|
+
},
|
|
35746
|
+
findByProjectRoot(taskId, projectRoot) {
|
|
35747
|
+
const taskMap = registry.get(taskId);
|
|
35748
|
+
if (!taskMap) return void 0;
|
|
35749
|
+
for (const state of taskMap.values()) {
|
|
35750
|
+
if (state.projectRoot === projectRoot) return state;
|
|
35751
|
+
}
|
|
35752
|
+
return void 0;
|
|
35753
|
+
},
|
|
35754
|
+
putState(taskId, state) {
|
|
35755
|
+
writeToDisk(taskId, state);
|
|
35756
|
+
const taskMap = getTaskMap(taskId);
|
|
35757
|
+
taskMap.set(state.elementId, state);
|
|
35758
|
+
broadcastTask(taskId);
|
|
35759
|
+
},
|
|
35760
|
+
deleteByElementId(taskId, elementId) {
|
|
35761
|
+
const taskMap = registry.get(taskId);
|
|
35762
|
+
if (!taskMap) return;
|
|
35763
|
+
const existed = taskMap.has(elementId);
|
|
35764
|
+
if (!existed) return;
|
|
35765
|
+
removeFromDisk(taskId, elementId);
|
|
35766
|
+
taskMap.delete(elementId);
|
|
35767
|
+
if (taskMap.size === 0) registry.delete(taskId);
|
|
35768
|
+
broadcastTask(taskId);
|
|
35769
|
+
},
|
|
35770
|
+
listByTask(taskId) {
|
|
35771
|
+
const taskMap = registry.get(taskId);
|
|
35772
|
+
if (!taskMap) return [];
|
|
35773
|
+
const entries = [...taskMap.values()];
|
|
35774
|
+
entries.sort((a, b2) => a.elementId < b2.elementId ? -1 : a.elementId > b2.elementId ? 1 : 0);
|
|
35775
|
+
return entries;
|
|
35776
|
+
},
|
|
35777
|
+
setSendControlMessage(fn) {
|
|
35778
|
+
sendFn = fn;
|
|
35779
|
+
},
|
|
35780
|
+
broadcast(taskId) {
|
|
35781
|
+
broadcastTask(taskId);
|
|
35782
|
+
},
|
|
35783
|
+
dispose() {
|
|
35784
|
+
registry.clear();
|
|
35785
|
+
sendFn = null;
|
|
35786
|
+
}
|
|
35787
|
+
};
|
|
35788
|
+
}
|
|
35789
|
+
|
|
35576
35790
|
// src/services/preview-proxy.ts
|
|
35577
35791
|
import http2 from "http";
|
|
35578
35792
|
|
|
@@ -36449,30 +36663,30 @@ function createPreviewProxy(config2) {
|
|
|
36449
36663
|
}
|
|
36450
36664
|
|
|
36451
36665
|
// src/services/publish/published-artifact-store.ts
|
|
36452
|
-
import { createHash, randomUUID as
|
|
36453
|
-
import { mkdirSync as
|
|
36666
|
+
import { createHash, randomUUID as randomUUID3 } from "crypto";
|
|
36667
|
+
import { mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync6, watch as watch2 } from "fs";
|
|
36454
36668
|
import { mkdir as mkdir5, readFile as readFile10, rename as rename6, unlink as unlink4, writeFile as writeFile8 } from "fs/promises";
|
|
36455
|
-
import { dirname as
|
|
36669
|
+
import { dirname as dirname8, join as join18, relative as relative2 } from "path";
|
|
36456
36670
|
var DEBOUNCE_MS2 = 200;
|
|
36457
36671
|
function bindMapKey(bindKind, bindKey) {
|
|
36458
36672
|
return `${bindKind}:${bindKey}`;
|
|
36459
36673
|
}
|
|
36460
|
-
function
|
|
36674
|
+
function recordFilePath2(rootDir, taskId, bindKind, bindKey) {
|
|
36461
36675
|
return join18(rootDir, taskId, bindKind, `${bindKey}.json`);
|
|
36462
36676
|
}
|
|
36463
36677
|
function sha256Hex(input) {
|
|
36464
36678
|
return createHash("sha256").update(input, "utf-8").digest("hex");
|
|
36465
36679
|
}
|
|
36466
36680
|
async function atomicWrite(filePath, content) {
|
|
36467
|
-
await mkdir5(
|
|
36468
|
-
const tmpPath = `${filePath}.${
|
|
36681
|
+
await mkdir5(dirname8(filePath), { recursive: true });
|
|
36682
|
+
const tmpPath = `${filePath}.${randomUUID3()}.tmp`;
|
|
36469
36683
|
await writeFile8(tmpPath, content, "utf-8");
|
|
36470
36684
|
await rename6(tmpPath, filePath);
|
|
36471
36685
|
}
|
|
36472
|
-
function
|
|
36686
|
+
function parseRecord2(filePath, logger2) {
|
|
36473
36687
|
let raw;
|
|
36474
36688
|
try {
|
|
36475
|
-
raw =
|
|
36689
|
+
raw = readFileSync6(filePath, "utf-8");
|
|
36476
36690
|
} catch {
|
|
36477
36691
|
return null;
|
|
36478
36692
|
}
|
|
@@ -36493,7 +36707,7 @@ function parseRecord(filePath, logger2) {
|
|
|
36493
36707
|
}
|
|
36494
36708
|
return result.data;
|
|
36495
36709
|
}
|
|
36496
|
-
function
|
|
36710
|
+
function isEnoent3(err) {
|
|
36497
36711
|
return err instanceof Error && Reflect.get(err, "code") === "ENOENT";
|
|
36498
36712
|
}
|
|
36499
36713
|
function createPublishedArtifactStore(opts) {
|
|
@@ -36504,17 +36718,17 @@ function createPublishedArtifactStore(opts) {
|
|
|
36504
36718
|
const ownWrites = /* @__PURE__ */ new Set();
|
|
36505
36719
|
let watcher = null;
|
|
36506
36720
|
let disposed = false;
|
|
36507
|
-
|
|
36721
|
+
mkdirSync3(rootDir, { recursive: true });
|
|
36508
36722
|
function scanKindDir(taskId, kindPath) {
|
|
36509
36723
|
let files;
|
|
36510
36724
|
try {
|
|
36511
|
-
files =
|
|
36725
|
+
files = readdirSync2(kindPath);
|
|
36512
36726
|
} catch {
|
|
36513
36727
|
return;
|
|
36514
36728
|
}
|
|
36515
36729
|
for (const file of files) {
|
|
36516
36730
|
if (!file.endsWith(".json")) continue;
|
|
36517
|
-
const record =
|
|
36731
|
+
const record = parseRecord2(join18(kindPath, file), logger2);
|
|
36518
36732
|
if (record) inMemorySet(taskId, record);
|
|
36519
36733
|
}
|
|
36520
36734
|
}
|
|
@@ -36522,7 +36736,7 @@ function createPublishedArtifactStore(opts) {
|
|
|
36522
36736
|
const taskPath = join18(rootDir, taskId);
|
|
36523
36737
|
let kindDirs;
|
|
36524
36738
|
try {
|
|
36525
|
-
kindDirs =
|
|
36739
|
+
kindDirs = readdirSync2(taskPath);
|
|
36526
36740
|
} catch {
|
|
36527
36741
|
return;
|
|
36528
36742
|
}
|
|
@@ -36534,7 +36748,7 @@ function createPublishedArtifactStore(opts) {
|
|
|
36534
36748
|
function scanRootDir() {
|
|
36535
36749
|
let taskDirs;
|
|
36536
36750
|
try {
|
|
36537
|
-
taskDirs =
|
|
36751
|
+
taskDirs = readdirSync2(rootDir);
|
|
36538
36752
|
} catch {
|
|
36539
36753
|
return;
|
|
36540
36754
|
}
|
|
@@ -36658,7 +36872,7 @@ function createPublishedArtifactStore(opts) {
|
|
|
36658
36872
|
return entries;
|
|
36659
36873
|
},
|
|
36660
36874
|
async putBinding(taskId, record) {
|
|
36661
|
-
const filePath =
|
|
36875
|
+
const filePath = recordFilePath2(rootDir, taskId, record.bindKind, record.bindKey);
|
|
36662
36876
|
ownWrites.add(filePath);
|
|
36663
36877
|
try {
|
|
36664
36878
|
await atomicWrite(filePath, JSON.stringify(record, null, 2));
|
|
@@ -36670,12 +36884,12 @@ function createPublishedArtifactStore(opts) {
|
|
|
36670
36884
|
broadcastTask(taskId);
|
|
36671
36885
|
},
|
|
36672
36886
|
async deleteBinding(taskId, bindKind, bindKey) {
|
|
36673
|
-
const filePath =
|
|
36887
|
+
const filePath = recordFilePath2(rootDir, taskId, bindKind, bindKey);
|
|
36674
36888
|
ownWrites.add(filePath);
|
|
36675
36889
|
try {
|
|
36676
36890
|
await unlink4(filePath);
|
|
36677
36891
|
} catch (err) {
|
|
36678
|
-
if (!
|
|
36892
|
+
if (!isEnoent3(err)) {
|
|
36679
36893
|
ownWrites.delete(filePath);
|
|
36680
36894
|
throw err;
|
|
36681
36895
|
}
|
|
@@ -37878,44 +38092,51 @@ async function storePreviewArtifact(input, bindKey, resolvedProjectRoot, existin
|
|
|
37878
38092
|
expiresAt: result.expiresAt,
|
|
37879
38093
|
ttl: input.ttl,
|
|
37880
38094
|
lastSize: files.reduce((sum, f2) => sum + f2.content.length, 0),
|
|
37881
|
-
projectRoot: resolvedProjectRoot
|
|
38095
|
+
projectRoot: resolvedProjectRoot,
|
|
37882
38096
|
canvasElementId: input.target.kind === "previewPort" ? input.target.canvasElementId : void 0
|
|
37883
38097
|
};
|
|
37884
38098
|
await input.publishedArtifactStore.putBinding(input.taskId, newRecord);
|
|
37885
38099
|
}
|
|
38100
|
+
function resolvePreviewProjectRoot(input, target) {
|
|
38101
|
+
const canvasElementId = target.canvasElementId;
|
|
38102
|
+
const storeEntry = canvasElementId && input.previewStateStore ? input.previewStateStore.getByElementId(input.taskId, canvasElementId) ?? null : null;
|
|
38103
|
+
const storeProjectRoot = storeEntry?.projectRoot ?? null;
|
|
38104
|
+
const detectedPortMatch = input.getDetectedPorts().find((p2) => p2.port === target.previewPort);
|
|
38105
|
+
const detectedProjectRoot = detectedPortMatch?.projectRoot ?? null;
|
|
38106
|
+
const resolvedProjectRoot = storeProjectRoot ?? detectedProjectRoot ?? null;
|
|
38107
|
+
const resolvedFrom = storeProjectRoot ? "store" : detectedProjectRoot ? "detected_ports" : "none";
|
|
38108
|
+
return { resolvedProjectRoot, resolvedFrom, storeProjectRoot, detectedProjectRoot };
|
|
38109
|
+
}
|
|
37886
38110
|
async function runPublishPreviewPort(input, ctx) {
|
|
37887
38111
|
if (input.target.kind !== "previewPort") {
|
|
37888
38112
|
return { ok: false, phase: "failed", error: "Internal error: wrong target kind" };
|
|
37889
38113
|
}
|
|
37890
|
-
const
|
|
37891
|
-
const
|
|
37892
|
-
const
|
|
37893
|
-
const resolvedProjectRoot =
|
|
37894
|
-
const bindKey = resolvedProjectRoot !== null ? sha256Hex(resolvedProjectRoot) : null;
|
|
37895
|
-
const existing = bindKey !== null ? input.publishedArtifactStore?.getBinding(input.taskId, "preview", bindKey) ?? null : null;
|
|
37896
|
-
const buildRoot = resolvedProjectRoot ?? input.projectRoot;
|
|
38114
|
+
const target = input.target;
|
|
38115
|
+
const canvasElementId = target.canvasElementId;
|
|
38116
|
+
const resolution = resolvePreviewProjectRoot(input, target);
|
|
38117
|
+
const { resolvedProjectRoot } = resolution;
|
|
37897
38118
|
ctx.log?.({
|
|
37898
38119
|
event: "publish_preview_resolved",
|
|
37899
|
-
|
|
37900
|
-
|
|
38120
|
+
canvasElementId: canvasElementId ?? null,
|
|
38121
|
+
previewPort: target.previewPort,
|
|
38122
|
+
storeProjectRoot: resolution.storeProjectRoot,
|
|
38123
|
+
detectedPortProjectRoot: resolution.detectedProjectRoot,
|
|
37901
38124
|
resolvedProjectRoot,
|
|
37902
|
-
|
|
38125
|
+
resolvedFrom: resolution.resolvedFrom
|
|
37903
38126
|
});
|
|
37904
|
-
|
|
38127
|
+
if (!resolvedProjectRoot) {
|
|
38128
|
+
const error2 = canvasElementId ? `Preview element has no resolvable projectRoot \u2014 was \`present({projectRoot})\` called? (canvasElementId: ${canvasElementId})` : "Preview publish requires a canvasElementId. The browser must send the stable canvas element id so the daemon can resolve projectRoot from the preview state store.";
|
|
38129
|
+
ctx.onProgress("failed", error2);
|
|
38130
|
+
return { ok: false, phase: "detecting_framework", error: error2 };
|
|
38131
|
+
}
|
|
38132
|
+
const bindKey = sha256Hex(resolvedProjectRoot);
|
|
38133
|
+
const existing = input.publishedArtifactStore?.getBinding(input.taskId, "preview", bindKey) ?? null;
|
|
38134
|
+
const built = await detectAndBuild(resolvedProjectRoot, ctx);
|
|
37905
38135
|
if (!built.ok) return built.outcome;
|
|
37906
38136
|
ctx.onProgress("uploading");
|
|
37907
38137
|
try {
|
|
37908
38138
|
const result = await uploadPreviewFiles(input, built.framework, built.files, existing);
|
|
37909
|
-
|
|
37910
|
-
await storePreviewArtifact(
|
|
37911
|
-
input,
|
|
37912
|
-
bindKey,
|
|
37913
|
-
resolvedProjectRoot,
|
|
37914
|
-
existing,
|
|
37915
|
-
result,
|
|
37916
|
-
built.files
|
|
37917
|
-
);
|
|
37918
|
-
}
|
|
38139
|
+
await storePreviewArtifact(input, bindKey, resolvedProjectRoot, existing, result, built.files);
|
|
37919
38140
|
ctx.onProgress("completed");
|
|
37920
38141
|
return { ok: true, id: result.id, url: result.url, expiresAt: result.expiresAt };
|
|
37921
38142
|
} catch (err) {
|
|
@@ -37966,6 +38187,7 @@ function createPublishTools(ctx) {
|
|
|
37966
38187
|
taskId: ctx.taskId.current,
|
|
37967
38188
|
vizWatcher: ctx.vizWatcher,
|
|
37968
38189
|
publishedArtifactStore: ctx.publishedArtifactStore,
|
|
38190
|
+
previewStateStore: ctx.previewStateStore,
|
|
37969
38191
|
getDetectedPorts: ctx.getDetectedPorts
|
|
37970
38192
|
},
|
|
37971
38193
|
{ onProgress: () => {
|
|
@@ -38068,6 +38290,7 @@ async function handlePublishRequest(params) {
|
|
|
38068
38290
|
taskId: params.taskId,
|
|
38069
38291
|
vizWatcher: params.vizWatcher,
|
|
38070
38292
|
publishedArtifactStore: params.publishedArtifactStore,
|
|
38293
|
+
previewStateStore: params.previewStateStore,
|
|
38071
38294
|
getDetectedPorts: params.getDetectedPorts
|
|
38072
38295
|
},
|
|
38073
38296
|
{ onProgress: emitProgress, ...params.log !== void 0 && { log: params.log } }
|
|
@@ -39178,38 +39401,22 @@ async function rehydrateCollabQueues(persistence, taskManager, log) {
|
|
|
39178
39401
|
})
|
|
39179
39402
|
);
|
|
39180
39403
|
}
|
|
39181
|
-
function
|
|
39182
|
-
return
|
|
39183
|
-
}
|
|
39184
|
-
function collectOwnedPreviews(canvasRepo, taskId, selfUserId) {
|
|
39185
|
-
try {
|
|
39186
|
-
const elements = canvasRepo.getElements(taskId);
|
|
39187
|
-
const ports = [];
|
|
39188
|
-
for (const el of elements) {
|
|
39189
|
-
if (el.data.type !== "preview") continue;
|
|
39190
|
-
const data = isPreviewData(el.data.data) ? el.data.data : null;
|
|
39191
|
-
if (!data || data.ownerUserId !== selfUserId) continue;
|
|
39192
|
-
if (typeof data.port === "number") ports.push(data.port);
|
|
39193
|
-
}
|
|
39194
|
-
return ports;
|
|
39195
|
-
} catch {
|
|
39196
|
-
return [];
|
|
39197
|
-
}
|
|
39404
|
+
function collectOwnedPreviews(_canvasRepo, _taskId, _selfUserId) {
|
|
39405
|
+
return [];
|
|
39198
39406
|
}
|
|
39199
39407
|
async function rehydrateCanvasPreviews(canvasRepo, previewProxy, selfUserId, taskStateStore, log) {
|
|
39200
39408
|
const tasks = await taskStateStore.listTasks();
|
|
39201
39409
|
const refs = [];
|
|
39202
39410
|
for (const taskId of Object.keys(tasks)) {
|
|
39203
39411
|
if (!await canvasRepo.hasLocalDoc(taskId)) continue;
|
|
39204
|
-
for (const
|
|
39205
|
-
refs.push(
|
|
39412
|
+
for (const ref of collectOwnedPreviews(canvasRepo, taskId, selfUserId)) {
|
|
39413
|
+
refs.push(ref);
|
|
39206
39414
|
}
|
|
39207
39415
|
}
|
|
39208
39416
|
const warmedTaskIds = /* @__PURE__ */ new Set();
|
|
39209
39417
|
for (const { taskId, port } of refs) {
|
|
39210
39418
|
try {
|
|
39211
|
-
|
|
39212
|
-
await reconcileProxyPortInCanvas(canvasRepo, taskId, port, newProxyPort);
|
|
39419
|
+
await previewProxy.acquire(port);
|
|
39213
39420
|
warmedTaskIds.add(taskId);
|
|
39214
39421
|
log({ event: "canvas_preview_warmed", taskId, port });
|
|
39215
39422
|
} catch (err) {
|
|
@@ -39223,19 +39430,6 @@ async function rehydrateCanvasPreviews(canvasRepo, previewProxy, selfUserId, tas
|
|
|
39223
39430
|
}
|
|
39224
39431
|
return Array.from(warmedTaskIds);
|
|
39225
39432
|
}
|
|
39226
|
-
async function reconcileProxyPortInCanvas(canvasRepo, taskId, upstreamPort, newProxyPort) {
|
|
39227
|
-
if (!await canvasRepo.hasLocalDoc(taskId)) return;
|
|
39228
|
-
for (const el of canvasRepo.getElements(taskId)) {
|
|
39229
|
-
if (el.data.type !== "preview") continue;
|
|
39230
|
-
const rec = el.data.data;
|
|
39231
|
-
if (!isPreviewData(rec)) continue;
|
|
39232
|
-
if (rec.port !== upstreamPort) continue;
|
|
39233
|
-
if (rec.proxyPort === newProxyPort) continue;
|
|
39234
|
-
canvasRepo.updateElement(taskId, el.id, {
|
|
39235
|
-
data: { ...rec, proxyPort: newProxyPort }
|
|
39236
|
-
});
|
|
39237
|
-
}
|
|
39238
|
-
}
|
|
39239
39433
|
async function migratePinnedToFavoriteTasks(taskStateStore, userSettingsStore, log) {
|
|
39240
39434
|
const settings = await userSettingsStore.getSettings();
|
|
39241
39435
|
if (settings.favoriteTasks.length > 0) return;
|
|
@@ -39245,6 +39439,77 @@ async function migratePinnedToFavoriteTasks(taskStateStore, userSettingsStore, l
|
|
|
39245
39439
|
await userSettingsStore.updateSetting("favoriteTasks", pinnedIds);
|
|
39246
39440
|
log({ event: "pinned_to_favorites_migrated", count: pinnedIds.length });
|
|
39247
39441
|
}
|
|
39442
|
+
function isObjectRecord(v2) {
|
|
39443
|
+
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
|
|
39444
|
+
}
|
|
39445
|
+
function extractLegacyPreviewState(elementId, rawData) {
|
|
39446
|
+
if (!isObjectRecord(rawData)) return null;
|
|
39447
|
+
const ownerUserId = typeof rawData.ownerUserId === "string" && rawData.ownerUserId.length > 0 ? rawData.ownerUserId : null;
|
|
39448
|
+
if (!ownerUserId) return null;
|
|
39449
|
+
const state = { elementId, ownerUserId };
|
|
39450
|
+
let hasLegacyField = false;
|
|
39451
|
+
if (typeof rawData.port === "number" && Number.isInteger(rawData.port) && rawData.port > 0) {
|
|
39452
|
+
state.port = rawData.port;
|
|
39453
|
+
hasLegacyField = true;
|
|
39454
|
+
}
|
|
39455
|
+
if (typeof rawData.url === "string" && rawData.url.length > 0) {
|
|
39456
|
+
state.url = rawData.url;
|
|
39457
|
+
hasLegacyField = true;
|
|
39458
|
+
}
|
|
39459
|
+
if (typeof rawData.proxyPort === "number" && Number.isInteger(rawData.proxyPort) && rawData.proxyPort > 0) {
|
|
39460
|
+
state.proxyPort = rawData.proxyPort;
|
|
39461
|
+
hasLegacyField = true;
|
|
39462
|
+
}
|
|
39463
|
+
if (typeof rawData.initialPath === "string" && rawData.initialPath.length > 0) {
|
|
39464
|
+
state.initialPath = rawData.initialPath;
|
|
39465
|
+
hasLegacyField = true;
|
|
39466
|
+
}
|
|
39467
|
+
if (typeof rawData.projectRoot === "string" && rawData.projectRoot.length > 0) {
|
|
39468
|
+
state.projectRoot = rawData.projectRoot;
|
|
39469
|
+
hasLegacyField = true;
|
|
39470
|
+
}
|
|
39471
|
+
return hasLegacyField ? state : null;
|
|
39472
|
+
}
|
|
39473
|
+
function migrateLegacyPreviewDataForTask(taskId, canvasRepo, store, log) {
|
|
39474
|
+
let seededCount = 0;
|
|
39475
|
+
const elements = canvasRepo.getElements(taskId);
|
|
39476
|
+
for (const el of elements) {
|
|
39477
|
+
if (el.data.type !== "preview") continue;
|
|
39478
|
+
const elementId = String(el.id);
|
|
39479
|
+
if (store.getByElementId(taskId, elementId)) continue;
|
|
39480
|
+
const legacy = extractLegacyPreviewState(elementId, el.data.data);
|
|
39481
|
+
if (!legacy) continue;
|
|
39482
|
+
store.putState(taskId, legacy);
|
|
39483
|
+
seededCount += 1;
|
|
39484
|
+
log({
|
|
39485
|
+
event: "preview_legacy_migrated",
|
|
39486
|
+
taskId,
|
|
39487
|
+
elementId,
|
|
39488
|
+
port: legacy.port,
|
|
39489
|
+
projectRoot: legacy.projectRoot
|
|
39490
|
+
});
|
|
39491
|
+
}
|
|
39492
|
+
return seededCount;
|
|
39493
|
+
}
|
|
39494
|
+
async function migrateLegacyPreviewData(canvasRepo, previewStateStore, taskStateStore, log) {
|
|
39495
|
+
const tasks = await taskStateStore.listTasks();
|
|
39496
|
+
let totalSeeded = 0;
|
|
39497
|
+
for (const taskId of Object.keys(tasks)) {
|
|
39498
|
+
if (!await canvasRepo.hasLocalDoc(taskId)) continue;
|
|
39499
|
+
try {
|
|
39500
|
+
totalSeeded += migrateLegacyPreviewDataForTask(taskId, canvasRepo, previewStateStore, log);
|
|
39501
|
+
} catch (err) {
|
|
39502
|
+
log({
|
|
39503
|
+
event: "preview_legacy_migrate_task_failed",
|
|
39504
|
+
taskId,
|
|
39505
|
+
error: err instanceof Error ? err.message : String(err)
|
|
39506
|
+
});
|
|
39507
|
+
}
|
|
39508
|
+
}
|
|
39509
|
+
if (totalSeeded > 0) {
|
|
39510
|
+
log({ event: "preview_legacy_migrate_complete", seededCount: totalSeeded });
|
|
39511
|
+
}
|
|
39512
|
+
}
|
|
39248
39513
|
async function sweepStaleTasks(taskStateStore, taskManager, log) {
|
|
39249
39514
|
const tasks = await taskStateStore.listTasks();
|
|
39250
39515
|
const actions = planStaleSweep(tasks, (id) => taskManager.isRunning(id));
|
|
@@ -39372,7 +39637,7 @@ function assertNever3(value) {
|
|
|
39372
39637
|
|
|
39373
39638
|
// src/services/bootstrap/self-update-lock.ts
|
|
39374
39639
|
import { mkdir as mkdir7, readFile as readFile16, stat as stat5, unlink as unlink6, writeFile as writeFile11 } from "fs/promises";
|
|
39375
|
-
import { dirname as
|
|
39640
|
+
import { dirname as dirname9, join as join24 } from "path";
|
|
39376
39641
|
var LOCK_FILENAME = ".lock";
|
|
39377
39642
|
var STALE_LOCK_MS = 10 * 60 * 1e3;
|
|
39378
39643
|
var LockFileSchema = external_exports.object({
|
|
@@ -39464,7 +39729,7 @@ async function resolveEexist(shipyardHome, path2, ownerPid, now, isProcessAlive2
|
|
|
39464
39729
|
}
|
|
39465
39730
|
async function tryAcquireLockExclusive(shipyardHome, pid, now, isProcessAlive2) {
|
|
39466
39731
|
const path2 = lockPath(shipyardHome);
|
|
39467
|
-
await mkdir7(
|
|
39732
|
+
await mkdir7(dirname9(path2), { recursive: true });
|
|
39468
39733
|
const body = JSON.stringify({ pid, startedAt: now() });
|
|
39469
39734
|
while (true) {
|
|
39470
39735
|
try {
|
|
@@ -40025,7 +40290,7 @@ function createCanvasResourceResolver(deps) {
|
|
|
40025
40290
|
|
|
40026
40291
|
// src/services/credentials/vault-key-manager.ts
|
|
40027
40292
|
import { mkdir as mkdir8, readFile as readFile17, writeFile as writeFile12 } from "fs/promises";
|
|
40028
|
-
import { dirname as
|
|
40293
|
+
import { dirname as dirname10, join as join26 } from "path";
|
|
40029
40294
|
|
|
40030
40295
|
// src/services/credentials/vault-crypto.ts
|
|
40031
40296
|
async function generateVaultKey() {
|
|
@@ -40111,12 +40376,12 @@ async function resolveMachineId(shipyardHome) {
|
|
|
40111
40376
|
} catch {
|
|
40112
40377
|
}
|
|
40113
40378
|
const id = globalThis.crypto.randomUUID();
|
|
40114
|
-
await mkdir8(
|
|
40379
|
+
await mkdir8(dirname10(idPath), { recursive: true });
|
|
40115
40380
|
await writeFile12(idPath, id, { encoding: "utf-8", mode: 384 });
|
|
40116
40381
|
return id;
|
|
40117
40382
|
}
|
|
40118
40383
|
async function saveKeyLocally(keyPath, key) {
|
|
40119
|
-
await mkdir8(
|
|
40384
|
+
await mkdir8(dirname10(keyPath), { recursive: true });
|
|
40120
40385
|
await writeFile12(keyPath, key, { encoding: "utf-8", mode: 384 });
|
|
40121
40386
|
}
|
|
40122
40387
|
|
|
@@ -40814,7 +41079,7 @@ function createGitCheckpointService() {
|
|
|
40814
41079
|
import { createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
|
|
40815
41080
|
|
|
40816
41081
|
// src/services/harness/comment-server.ts
|
|
40817
|
-
import { randomUUID as
|
|
41082
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
40818
41083
|
import { access as access2, readFile as readFile20 } from "fs/promises";
|
|
40819
41084
|
import { join as join29, relative as relative3 } from "path";
|
|
40820
41085
|
var TOOL_DESCRIPTION = [
|
|
@@ -40933,7 +41198,7 @@ function resolveShortCommentId(annotations, input) {
|
|
|
40933
41198
|
}
|
|
40934
41199
|
function buildReplyAnnotation(parent, body) {
|
|
40935
41200
|
const base3 = {
|
|
40936
|
-
commentId:
|
|
41201
|
+
commentId: randomUUID4(),
|
|
40937
41202
|
body,
|
|
40938
41203
|
authorName: "Claude Code",
|
|
40939
41204
|
authorKind: "agent",
|
|
@@ -41235,7 +41500,7 @@ async function handleReplyComment(ctx, parentCommentId, comment2) {
|
|
|
41235
41500
|
async function handlePlanComment(ctx, anchorText, comment2) {
|
|
41236
41501
|
const annotation = {
|
|
41237
41502
|
annotationType: "plan-text",
|
|
41238
|
-
commentId:
|
|
41503
|
+
commentId: randomUUID4(),
|
|
41239
41504
|
anchorText,
|
|
41240
41505
|
anchorContext: null,
|
|
41241
41506
|
body: comment2,
|
|
@@ -41285,7 +41550,7 @@ async function handleDiffComment(ctx, filePath, lineNumber, comment2) {
|
|
|
41285
41550
|
const lineContentHash = lineContent ? djb2Hash(lineContent) : "";
|
|
41286
41551
|
const annotation = {
|
|
41287
41552
|
annotationType: "diff-hunk",
|
|
41288
|
-
commentId:
|
|
41553
|
+
commentId: randomUUID4(),
|
|
41289
41554
|
filePath: normalizedPath,
|
|
41290
41555
|
lineNumber,
|
|
41291
41556
|
lineContent,
|
|
@@ -41977,7 +42242,7 @@ var PresentPortSchema = external_exports.object({
|
|
|
41977
42242
|
width: external_exports.number().int().positive().optional().describe("Canvas only."),
|
|
41978
42243
|
height: external_exports.number().int().positive().optional().describe("Canvas only."),
|
|
41979
42244
|
projectRoot: external_exports.string().optional().describe(
|
|
41980
|
-
"Absolute path to the dev server's package.json directory.
|
|
42245
|
+
"Absolute path to the dev server's package.json directory. Binds this preview to a stable app identity. Restarting your dev server on a new port (or a fresh `present` call) with the same projectRoot will reuse the same canvas element \u2014 no duplicate frames, and the published URL is stable across port restarts. Without projectRoot, every port change creates a new element."
|
|
41981
42246
|
)
|
|
41982
42247
|
});
|
|
41983
42248
|
var PresentUrlSchema = external_exports.object({
|
|
@@ -42006,7 +42271,7 @@ var PresentToolInputShape = {
|
|
|
42006
42271
|
height: external_exports.number().int().positive().optional().describe("Canvas only; ignored elsewhere."),
|
|
42007
42272
|
initialPath: external_exports.string().optional().describe('SPA route for source="port" on canvas (e.g. "/settings").'),
|
|
42008
42273
|
projectRoot: external_exports.string().optional().describe(
|
|
42009
|
-
`Absolute path to the dev server's package.json dir (source="port" only).
|
|
42274
|
+
`Absolute path to the dev server's package.json dir (source="port" only). Binds this preview to a stable app identity. Restarting your dev server on a new port with the same projectRoot will reuse the same canvas element \u2014 no duplicate frames, and the published URL is stable across port restarts. Without projectRoot, every port change creates a new element.`
|
|
42010
42275
|
),
|
|
42011
42276
|
force: external_exports.boolean().optional().describe("Re-apply an already-placed slug to canvas after editing. Slug+canvas only.")
|
|
42012
42277
|
};
|
|
@@ -51285,6 +51550,7 @@ function createHarnessMcpServer(ctx) {
|
|
|
51285
51550
|
projectRoot: ctx.projectRoot,
|
|
51286
51551
|
previewProxy: ctx.previewProxy,
|
|
51287
51552
|
publishedArtifactStore: ctx.publishedArtifactStore,
|
|
51553
|
+
previewStateStore: ctx.previewStateStore,
|
|
51288
51554
|
getDetectedPorts: ctx.getDetectedPorts
|
|
51289
51555
|
};
|
|
51290
51556
|
const server = createSdkMcpServer({
|
|
@@ -51307,37 +51573,53 @@ function createHarnessMcpServer(ctx) {
|
|
|
51307
51573
|
}
|
|
51308
51574
|
|
|
51309
51575
|
// src/services/harness/visualization-file-watcher.ts
|
|
51310
|
-
import { randomUUID as
|
|
51576
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
51311
51577
|
import { watch as watch3 } from "fs";
|
|
51312
51578
|
import { mkdir as mkdir10, readFile as readFile22, rename as rename9, writeFile as writeFile15 } from "fs/promises";
|
|
51313
|
-
import { dirname as
|
|
51579
|
+
import { dirname as dirname11, join as join31 } from "path";
|
|
51314
51580
|
var PREVIEW_DEFAULT_W = 1200;
|
|
51315
51581
|
var PREVIEW_DEFAULT_H = 800;
|
|
51316
51582
|
function previewDataToLoroValue(data) {
|
|
51317
|
-
|
|
51318
|
-
if (data.port !== void 0) out.port = data.port;
|
|
51319
|
-
if (data.url !== void 0) out.url = data.url;
|
|
51320
|
-
if (data.proxyPort !== void 0) out.proxyPort = data.proxyPort;
|
|
51321
|
-
if (data.initialPath !== void 0) out.initialPath = data.initialPath;
|
|
51322
|
-
return out;
|
|
51583
|
+
return { ownerUserId: data.ownerUserId };
|
|
51323
51584
|
}
|
|
51324
|
-
function
|
|
51585
|
+
function isObjectRecord2(v2) {
|
|
51325
51586
|
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
|
|
51326
51587
|
}
|
|
51327
51588
|
function extractPreviewData(raw) {
|
|
51328
|
-
if (!
|
|
51589
|
+
if (!isObjectRecord2(raw)) return null;
|
|
51329
51590
|
const out = {};
|
|
51330
|
-
if (typeof raw.port === "number") out.port = raw.port;
|
|
51331
|
-
if (typeof raw.url === "string") out.url = raw.url;
|
|
51332
|
-
if (typeof raw.proxyPort === "number") out.proxyPort = raw.proxyPort;
|
|
51333
51591
|
if (typeof raw.ownerUserId === "string") out.ownerUserId = raw.ownerUserId;
|
|
51334
|
-
|
|
51592
|
+
return out;
|
|
51593
|
+
}
|
|
51594
|
+
function buildPreviewState(elementId, params, ownerUserId, existing) {
|
|
51595
|
+
const state = { elementId, ownerUserId };
|
|
51596
|
+
const port = params.port ?? existing?.port;
|
|
51597
|
+
if (port !== void 0) state.port = port;
|
|
51598
|
+
const url = params.url ?? existing?.url;
|
|
51599
|
+
if (url !== void 0) state.url = url;
|
|
51600
|
+
const proxyPort = params.proxyPort ?? existing?.proxyPort;
|
|
51601
|
+
if (proxyPort !== void 0) state.proxyPort = proxyPort;
|
|
51602
|
+
const initialPath = params.initialPath ?? existing?.initialPath;
|
|
51603
|
+
if (initialPath !== void 0) state.initialPath = initialPath;
|
|
51604
|
+
const projectRoot = params.projectRoot ?? existing?.projectRoot;
|
|
51605
|
+
if (typeof projectRoot === "string" && projectRoot.length > 0) state.projectRoot = projectRoot;
|
|
51606
|
+
return state;
|
|
51607
|
+
}
|
|
51608
|
+
function mergedPreviewData(data, state) {
|
|
51609
|
+
const out = {
|
|
51610
|
+
ownerUserId: data.ownerUserId
|
|
51611
|
+
};
|
|
51612
|
+
if (state.port !== void 0) out.port = state.port;
|
|
51613
|
+
if (state.url !== void 0) out.url = state.url;
|
|
51614
|
+
if (state.proxyPort !== void 0) out.proxyPort = state.proxyPort;
|
|
51615
|
+
if (state.initialPath !== void 0) out.initialPath = state.initialPath;
|
|
51616
|
+
if (state.projectRoot !== void 0) out.projectRoot = state.projectRoot;
|
|
51335
51617
|
return out;
|
|
51336
51618
|
}
|
|
51337
51619
|
var DEBOUNCE_MS3 = 200;
|
|
51338
51620
|
async function atomicWrite2(filePath, content) {
|
|
51339
|
-
await mkdir10(
|
|
51340
|
-
const tmpPath = `${filePath}.${
|
|
51621
|
+
await mkdir10(dirname11(filePath), { recursive: true });
|
|
51622
|
+
const tmpPath = `${filePath}.${randomUUID5()}.tmp`;
|
|
51341
51623
|
await writeFile15(tmpPath, content, "utf-8");
|
|
51342
51624
|
await rename9(tmpPath, filePath);
|
|
51343
51625
|
}
|
|
@@ -51506,7 +51788,7 @@ var VisualizationFileWatcher = class {
|
|
|
51506
51788
|
if (this.#disposed) return;
|
|
51507
51789
|
if (this.#watchedFiles.has(filePath)) return;
|
|
51508
51790
|
this.#watchedFiles.add(filePath);
|
|
51509
|
-
const dirPath =
|
|
51791
|
+
const dirPath = dirname11(filePath);
|
|
51510
51792
|
const existing = this.#dirWatchers.get(dirPath);
|
|
51511
51793
|
if (existing) {
|
|
51512
51794
|
existing.refCount += 1;
|
|
@@ -51546,7 +51828,7 @@ var VisualizationFileWatcher = class {
|
|
|
51546
51828
|
}
|
|
51547
51829
|
#stopFileWatch(filePath) {
|
|
51548
51830
|
if (!this.#watchedFiles.delete(filePath)) return;
|
|
51549
|
-
const dirPath =
|
|
51831
|
+
const dirPath = dirname11(filePath);
|
|
51550
51832
|
const entry = this.#dirWatchers.get(dirPath);
|
|
51551
51833
|
if (entry) {
|
|
51552
51834
|
entry.refCount -= 1;
|
|
@@ -51564,39 +51846,56 @@ var VisualizationFileWatcher = class {
|
|
|
51564
51846
|
/**
|
|
51565
51847
|
* Idempotent create-or-update of a preview canvas element.
|
|
51566
51848
|
*
|
|
51567
|
-
*
|
|
51568
|
-
*
|
|
51569
|
-
*
|
|
51849
|
+
* Dedupe order (pointer-only CRDT, PROTOCOL_VERSION 36):
|
|
51850
|
+
* 1. If params has `projectRoot` AND `previewStateStore` already has
|
|
51851
|
+
* an entry with a matching `projectRoot` → update that entry's
|
|
51852
|
+
* port / url / proxyPort in place (same elementId, no new canvas
|
|
51853
|
+
* element). This is the port-swap upsert: Vite restarts on a new
|
|
51854
|
+
* port, daemon calls `present({projectRoot})` again, and the
|
|
51855
|
+
* existing element's iframe URL flips — no duplicates.
|
|
51856
|
+
* 2. Else if the CRDT has a `preview` element with matching
|
|
51857
|
+
* `ownerUserId` AND the store has an entry with matching port —
|
|
51858
|
+
* update that entry. This covers the legacy / no-projectRoot path
|
|
51859
|
+
* where dedupe keys off the live port alone.
|
|
51860
|
+
* 3. Else create a new canvas element (pointer-only) + a new store
|
|
51861
|
+
* entry carrying the mutable state.
|
|
51862
|
+
*
|
|
51863
|
+
* In every case, the store is written with the element's projectRoot
|
|
51864
|
+
* (if known) so the publish pipeline can look it up by elementId.
|
|
51570
51865
|
*
|
|
51571
|
-
*
|
|
51572
|
-
*
|
|
51573
|
-
* race the lookup. (loro-crdt mutations are synchronous via `change()`.)
|
|
51866
|
+
* loro-crdt mutations are synchronous via `change()`, so the
|
|
51867
|
+
* check+write against the CRDT cannot race a concurrent caller.
|
|
51574
51868
|
*/
|
|
51575
51869
|
createOrUpdatePreviewElement(params) {
|
|
51576
51870
|
const data = this.registry.planPreviewElement(params);
|
|
51577
51871
|
const loroData = previewDataToLoroValue(data);
|
|
51872
|
+
const store = this.#deps.previewStateStore ?? null;
|
|
51873
|
+
if (store && params.projectRoot !== void 0 && params.projectRoot.length > 0) {
|
|
51874
|
+
const existing = store.findByProjectRoot(params.taskId, params.projectRoot);
|
|
51875
|
+
if (existing) {
|
|
51876
|
+
const elementId2 = existing.elementId;
|
|
51877
|
+
const mergedState = buildPreviewState(elementId2, params, data.ownerUserId, existing);
|
|
51878
|
+
store.putState(params.taskId, mergedState);
|
|
51879
|
+
return {
|
|
51880
|
+
kind: "updated",
|
|
51881
|
+
elementId: elementId2,
|
|
51882
|
+
data: mergedPreviewData(data, mergedState)
|
|
51883
|
+
};
|
|
51884
|
+
}
|
|
51885
|
+
}
|
|
51578
51886
|
const existingElements = this.#deps.canvasRepo.getElements(params.taskId);
|
|
51579
|
-
const
|
|
51580
|
-
|
|
51581
|
-
const
|
|
51582
|
-
|
|
51583
|
-
|
|
51584
|
-
|
|
51585
|
-
|
|
51586
|
-
|
|
51587
|
-
|
|
51588
|
-
|
|
51589
|
-
|
|
51590
|
-
|
|
51591
|
-
const existing = extractPreviewData(match2.data.data);
|
|
51592
|
-
if (existing?.projectRoot) {
|
|
51593
|
-
return { ...data, projectRoot: existing.projectRoot };
|
|
51594
|
-
}
|
|
51595
|
-
return data;
|
|
51596
|
-
})();
|
|
51597
|
-
const preservedLoroData = previewDataToLoroValue(preservedData);
|
|
51598
|
-
this.#deps.canvasRepo.updateElement(params.taskId, matchTreeId, { data: preservedLoroData });
|
|
51599
|
-
return { kind: "updated", elementId: `${match2.id}`, data: preservedData };
|
|
51887
|
+
const legacyMatch = store ? this.#findLegacyPreviewMatch(existingElements, params, data.ownerUserId) : null;
|
|
51888
|
+
if (legacyMatch && store) {
|
|
51889
|
+
const matchTreeId = legacyMatch.id;
|
|
51890
|
+
const elementId2 = `${matchTreeId}`;
|
|
51891
|
+
const existingState = store.getByElementId(params.taskId, elementId2);
|
|
51892
|
+
const mergedState = buildPreviewState(elementId2, params, data.ownerUserId, existingState);
|
|
51893
|
+
store.putState(params.taskId, mergedState);
|
|
51894
|
+
return {
|
|
51895
|
+
kind: "updated",
|
|
51896
|
+
elementId: elementId2,
|
|
51897
|
+
data: mergedPreviewData(data, mergedState)
|
|
51898
|
+
};
|
|
51600
51899
|
}
|
|
51601
51900
|
const positionable = existingElements.map((el) => ({
|
|
51602
51901
|
x: el.data.x,
|
|
@@ -51616,7 +51915,26 @@ var VisualizationFileWatcher = class {
|
|
|
51616
51915
|
zIndex: position.zIndex,
|
|
51617
51916
|
data: loroData
|
|
51618
51917
|
});
|
|
51619
|
-
|
|
51918
|
+
const elementId = `${nodeId}`;
|
|
51919
|
+
if (store) {
|
|
51920
|
+
const freshState = buildPreviewState(elementId, params, data.ownerUserId, void 0);
|
|
51921
|
+
store.putState(params.taskId, freshState);
|
|
51922
|
+
}
|
|
51923
|
+
return { kind: "created", elementId, data };
|
|
51924
|
+
}
|
|
51925
|
+
#findLegacyPreviewMatch(existingElements, params, ownerUserId) {
|
|
51926
|
+
const store = this.#deps.previewStateStore;
|
|
51927
|
+
if (!store) return null;
|
|
51928
|
+
for (const el of existingElements) {
|
|
51929
|
+
if (el.data.type !== "preview") continue;
|
|
51930
|
+
const elData = extractPreviewData(el.data.data);
|
|
51931
|
+
if (!elData || elData.ownerUserId !== ownerUserId) continue;
|
|
51932
|
+
const state = store.getByElementId(params.taskId, `${el.id}`);
|
|
51933
|
+
if (!state) continue;
|
|
51934
|
+
if (params.port !== void 0 && state.port === params.port) return el;
|
|
51935
|
+
if (params.url !== void 0 && state.url === params.url) return el;
|
|
51936
|
+
}
|
|
51937
|
+
return null;
|
|
51620
51938
|
}
|
|
51621
51939
|
async #createCanvasElement(effect) {
|
|
51622
51940
|
const existingElements = this.#deps.canvasRepo.getElements(effect.taskId);
|
|
@@ -51757,17 +52075,7 @@ var VisualizationRegistry = class {
|
|
|
51757
52075
|
* idempotency key derived from `{taskId, port || url}`.
|
|
51758
52076
|
*/
|
|
51759
52077
|
planPreviewElement(params) {
|
|
51760
|
-
|
|
51761
|
-
ownerUserId: params.ownerUserId
|
|
51762
|
-
};
|
|
51763
|
-
if (params.port !== void 0) data.port = params.port;
|
|
51764
|
-
if (params.url !== void 0) data.url = params.url;
|
|
51765
|
-
if (params.proxyPort !== void 0) data.proxyPort = params.proxyPort;
|
|
51766
|
-
if (params.initialPath !== void 0) data.initialPath = params.initialPath;
|
|
51767
|
-
if (typeof params.projectRoot === "string" && params.projectRoot.length > 0) {
|
|
51768
|
-
data.projectRoot = params.projectRoot;
|
|
51769
|
-
}
|
|
51770
|
-
return data;
|
|
52078
|
+
return { ownerUserId: params.ownerUserId };
|
|
51771
52079
|
}
|
|
51772
52080
|
/**
|
|
51773
52081
|
* Force-refresh the canvas element for a presented visualization, regardless
|
|
@@ -75398,7 +75706,7 @@ var ScheduleEvaluator = class {
|
|
|
75398
75706
|
};
|
|
75399
75707
|
|
|
75400
75708
|
// src/services/serve-factory-helpers.ts
|
|
75401
|
-
import { existsSync as existsSync6, readdirSync as
|
|
75709
|
+
import { existsSync as existsSync6, readdirSync as readdirSync3, readFileSync as readFileSync7 } from "fs";
|
|
75402
75710
|
import { homedir as homedir3 } from "os";
|
|
75403
75711
|
import { join as join34 } from "path";
|
|
75404
75712
|
|
|
@@ -77978,7 +78286,7 @@ function rehydrateVizRegistry(registry, vizWatcher, resolvedTaskId, vizDir, log)
|
|
|
77978
78286
|
const registryPath = join34(vizDir, resolvedTaskId, "registry.json");
|
|
77979
78287
|
if (!existsSync6(registryPath)) return Promise.resolve();
|
|
77980
78288
|
try {
|
|
77981
|
-
const raw =
|
|
78289
|
+
const raw = readFileSync7(registryPath, "utf-8");
|
|
77982
78290
|
const parsed = PersistedVisualizationRegistrySchema.safeParse(JSON.parse(raw));
|
|
77983
78291
|
if (parsed.success) {
|
|
77984
78292
|
const effects = registry.rehydrate(resolvedTaskId, parsed.data);
|
|
@@ -78003,7 +78311,7 @@ function rehydrateVizRegistry(registry, vizWatcher, resolvedTaskId, vizDir, log)
|
|
|
78003
78311
|
}
|
|
78004
78312
|
function prehydrateAllVizWatchers(vizDir, getOrCreateVizWatcher) {
|
|
78005
78313
|
try {
|
|
78006
|
-
for (const entry of
|
|
78314
|
+
for (const entry of readdirSync3(vizDir, { withFileTypes: true })) {
|
|
78007
78315
|
if (entry.isDirectory() && existsSync6(join34(vizDir, entry.name, "registry.json"))) {
|
|
78008
78316
|
getOrCreateVizWatcher(entry.name);
|
|
78009
78317
|
}
|
|
@@ -78729,7 +79037,7 @@ function resolveModelFamily(model) {
|
|
|
78729
79037
|
if (model.includes("haiku")) return "haiku";
|
|
78730
79038
|
return "sonnet";
|
|
78731
79039
|
}
|
|
78732
|
-
var CC_VERSION = "2.1.
|
|
79040
|
+
var CC_VERSION = "2.1.120";
|
|
78733
79041
|
var BILLING_HEADER_PREFIX = `x-anthropic-billing-header: cc_version=${CC_VERSION}; cc_entrypoint=sdk-ts;`;
|
|
78734
79042
|
function buildConversationSystemPrompt(model) {
|
|
78735
79043
|
const family = resolveModelFamily(model);
|
|
@@ -78825,7 +79133,7 @@ async function resolveDirectApiCredentials(method) {
|
|
|
78825
79133
|
}
|
|
78826
79134
|
|
|
78827
79135
|
// src/services/session/direct-api-subprocess.ts
|
|
78828
|
-
import { randomUUID as
|
|
79136
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
78829
79137
|
|
|
78830
79138
|
// ../../node_modules/.pnpm/@anthropic-ai+sdk@0.90.0_zod@4.3.6/node_modules/@anthropic-ai/sdk/internal/tslib.mjs
|
|
78831
79139
|
function __classPrivateFieldSet(receiver, state, value, kind, f2) {
|
|
@@ -84994,7 +85302,7 @@ var DirectApiSubprocess = class _DirectApiSubprocess {
|
|
|
84994
85302
|
const allToolNames = [...SERVER_SIDE_TOOLS.map((t) => t.name), ...tools.map((t) => t.name)];
|
|
84995
85303
|
onEvent({
|
|
84996
85304
|
type: "init_received",
|
|
84997
|
-
sessionId: `direct-api-${
|
|
85305
|
+
sessionId: `direct-api-${randomUUID6()}`,
|
|
84998
85306
|
metadata: {
|
|
84999
85307
|
tools: allToolNames,
|
|
85000
85308
|
skills: [],
|
|
@@ -85347,8 +85655,7 @@ async function handlePublish(ctx, input) {
|
|
|
85347
85655
|
previewPort: target.previewPort,
|
|
85348
85656
|
...target.canvasElementId !== void 0 && {
|
|
85349
85657
|
canvasElementId: target.canvasElementId
|
|
85350
|
-
}
|
|
85351
|
-
...target.projectRoot !== void 0 && { projectRoot: target.projectRoot }
|
|
85658
|
+
}
|
|
85352
85659
|
} : { kind: "canvasElementId", canvasElementId: target.canvasElementId };
|
|
85353
85660
|
const outcome = await runPublish(
|
|
85354
85661
|
{
|
|
@@ -85361,6 +85668,7 @@ async function handlePublish(ctx, input) {
|
|
|
85361
85668
|
taskId: ctx.taskId,
|
|
85362
85669
|
vizWatcher: ctx.vizWatcher,
|
|
85363
85670
|
publishedArtifactStore: ctx.publishedArtifactStore,
|
|
85671
|
+
previewStateStore: ctx.previewStateStore,
|
|
85364
85672
|
getDetectedPorts: ctx.getDetectedPorts
|
|
85365
85673
|
},
|
|
85366
85674
|
{ onProgress: () => {
|
|
@@ -85680,7 +85988,7 @@ function createShipyardResolver() {
|
|
|
85680
85988
|
|
|
85681
85989
|
// src/services/storage/annotation-store.ts
|
|
85682
85990
|
import { mkdir as mkdir11, readFile as readFile25, rename as rename10, writeFile as writeFile16 } from "fs/promises";
|
|
85683
|
-
import { dirname as
|
|
85991
|
+
import { dirname as dirname12, join as join35 } from "path";
|
|
85684
85992
|
var LegacyBaseFields = external_exports.object({
|
|
85685
85993
|
commentId: external_exports.string(),
|
|
85686
85994
|
body: external_exports.string(),
|
|
@@ -85732,7 +86040,7 @@ function buildAnnotationStore(dataDir) {
|
|
|
85732
86040
|
}
|
|
85733
86041
|
async function atomicWrite4(taskId, data) {
|
|
85734
86042
|
const fp = filePath(taskId);
|
|
85735
|
-
await mkdir11(
|
|
86043
|
+
await mkdir11(dirname12(fp), { recursive: true });
|
|
85736
86044
|
const tmpPath = `${fp}.tmp`;
|
|
85737
86045
|
await writeFile16(tmpPath, JSON.stringify(data, null, 2), "utf-8");
|
|
85738
86046
|
await rename10(tmpPath, fp);
|
|
@@ -86102,7 +86410,7 @@ async function seedBuiltInTemplates(store, builtIns, dismissed) {
|
|
|
86102
86410
|
|
|
86103
86411
|
// src/services/storage/credentials-vault-store.ts
|
|
86104
86412
|
import { mkdir as mkdir13, readFile as readFile27, rename as rename12, writeFile as writeFile18 } from "fs/promises";
|
|
86105
|
-
import { dirname as
|
|
86413
|
+
import { dirname as dirname13 } from "path";
|
|
86106
86414
|
function buildCredentialsVaultStore(filePath) {
|
|
86107
86415
|
let cache2 = null;
|
|
86108
86416
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -86116,7 +86424,7 @@ function buildCredentialsVaultStore(filePath) {
|
|
|
86116
86424
|
}
|
|
86117
86425
|
}
|
|
86118
86426
|
async function ensureDir() {
|
|
86119
|
-
await mkdir13(
|
|
86427
|
+
await mkdir13(dirname13(filePath), { recursive: true });
|
|
86120
86428
|
}
|
|
86121
86429
|
async function readStore() {
|
|
86122
86430
|
if (cache2) return cache2;
|
|
@@ -86646,9 +86954,9 @@ function buildObservableConversationStore(inner) {
|
|
|
86646
86954
|
}
|
|
86647
86955
|
|
|
86648
86956
|
// src/services/storage/projects-store.ts
|
|
86649
|
-
import { randomUUID as
|
|
86957
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
86650
86958
|
import { mkdir as mkdir15, readFile as readFile29, rename as rename14, writeFile as writeFile20 } from "fs/promises";
|
|
86651
|
-
import { dirname as
|
|
86959
|
+
import { dirname as dirname14 } from "path";
|
|
86652
86960
|
var ProjectsArraySchema = external_exports.array(ProjectSchema);
|
|
86653
86961
|
function buildProjectsStore(filePath) {
|
|
86654
86962
|
let cache2 = null;
|
|
@@ -86663,7 +86971,7 @@ function buildProjectsStore(filePath) {
|
|
|
86663
86971
|
}
|
|
86664
86972
|
}
|
|
86665
86973
|
async function ensureDir() {
|
|
86666
|
-
await mkdir15(
|
|
86974
|
+
await mkdir15(dirname14(filePath), { recursive: true });
|
|
86667
86975
|
}
|
|
86668
86976
|
async function readStore() {
|
|
86669
86977
|
if (cache2) return cache2;
|
|
@@ -86723,7 +87031,7 @@ function buildProjectsStore(filePath) {
|
|
|
86723
87031
|
const current2 = await readStore();
|
|
86724
87032
|
const nextOrder = current2.length === 0 ? 0 : Math.max(...current2.map((p2) => p2.order)) + 1;
|
|
86725
87033
|
const project = {
|
|
86726
|
-
id:
|
|
87034
|
+
id: randomUUID7(),
|
|
86727
87035
|
name,
|
|
86728
87036
|
order: nextOrder,
|
|
86729
87037
|
createdAt: Date.now(),
|
|
@@ -86787,7 +87095,7 @@ function buildProjectsStore(filePath) {
|
|
|
86787
87095
|
|
|
86788
87096
|
// src/services/storage/rate-limit-store.ts
|
|
86789
87097
|
import { mkdir as mkdir16, readFile as readFile30, rename as rename15, writeFile as writeFile21 } from "fs/promises";
|
|
86790
|
-
import { dirname as
|
|
87098
|
+
import { dirname as dirname15, join as join38 } from "path";
|
|
86791
87099
|
var RATE_LIMIT_STORE_VERSION = 2;
|
|
86792
87100
|
var RateLimitRecordSchema = external_exports.object({
|
|
86793
87101
|
info: RateLimitInfoSchema,
|
|
@@ -86969,7 +87277,7 @@ function migrateV1toV2(v1) {
|
|
|
86969
87277
|
return { schemaVersion: RATE_LIMIT_STORE_VERSION, records };
|
|
86970
87278
|
}
|
|
86971
87279
|
async function atomicWrite3(filePath, data) {
|
|
86972
|
-
await mkdir16(
|
|
87280
|
+
await mkdir16(dirname15(filePath), { recursive: true });
|
|
86973
87281
|
const tmpPath = `${filePath}.tmp`;
|
|
86974
87282
|
await writeFile21(tmpPath, JSON.stringify(data, null, 2), "utf-8");
|
|
86975
87283
|
await rename15(tmpPath, filePath);
|
|
@@ -86980,7 +87288,7 @@ import { join as join39 } from "path";
|
|
|
86980
87288
|
|
|
86981
87289
|
// src/services/storage/json-document-store.ts
|
|
86982
87290
|
import { mkdir as mkdir17, readFile as readFile31, rename as rename16, writeFile as writeFile22 } from "fs/promises";
|
|
86983
|
-
import { dirname as
|
|
87291
|
+
import { dirname as dirname16 } from "path";
|
|
86984
87292
|
function buildJsonDocumentStore(opts) {
|
|
86985
87293
|
const { filePath, recordSchema, currentVersion, migrate } = opts;
|
|
86986
87294
|
let cache2 = null;
|
|
@@ -86995,7 +87303,7 @@ function buildJsonDocumentStore(opts) {
|
|
|
86995
87303
|
}
|
|
86996
87304
|
}
|
|
86997
87305
|
async function ensureDir() {
|
|
86998
|
-
await mkdir17(
|
|
87306
|
+
await mkdir17(dirname16(filePath), { recursive: true });
|
|
86999
87307
|
}
|
|
87000
87308
|
async function readStore() {
|
|
87001
87309
|
if (cache2) return cache2;
|
|
@@ -87231,7 +87539,7 @@ function buildTemplateStore(dataDir) {
|
|
|
87231
87539
|
|
|
87232
87540
|
// src/services/storage/user-settings-store.ts
|
|
87233
87541
|
import { mkdir as mkdir19, readFile as readFile33, rename as rename18, writeFile as writeFile24 } from "fs/promises";
|
|
87234
|
-
import { dirname as
|
|
87542
|
+
import { dirname as dirname17 } from "path";
|
|
87235
87543
|
function buildUserSettingsStore(filePath) {
|
|
87236
87544
|
let cache2 = null;
|
|
87237
87545
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -87245,7 +87553,7 @@ function buildUserSettingsStore(filePath) {
|
|
|
87245
87553
|
}
|
|
87246
87554
|
}
|
|
87247
87555
|
async function ensureDir() {
|
|
87248
|
-
await mkdir19(
|
|
87556
|
+
await mkdir19(dirname17(filePath), { recursive: true });
|
|
87249
87557
|
}
|
|
87250
87558
|
async function readStore() {
|
|
87251
87559
|
if (cache2) return cache2;
|
|
@@ -87336,7 +87644,7 @@ function buildUserSettingsStore(filePath) {
|
|
|
87336
87644
|
}
|
|
87337
87645
|
|
|
87338
87646
|
// src/services/task/orchestrator/task.ts
|
|
87339
|
-
import { randomUUID as
|
|
87647
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
87340
87648
|
import { join as join50 } from "path";
|
|
87341
87649
|
|
|
87342
87650
|
// src/services/event-batching.ts
|
|
@@ -90190,13 +90498,13 @@ function skipForMainChannel(content) {
|
|
|
90190
90498
|
}
|
|
90191
90499
|
|
|
90192
90500
|
// src/services/plan/plan-handler.ts
|
|
90193
|
-
import { existsSync as existsSync8, readdirSync as
|
|
90501
|
+
import { existsSync as existsSync8, readdirSync as readdirSync4, statSync as statSync2 } from "fs";
|
|
90194
90502
|
import { readFile as readFile35 } from "fs/promises";
|
|
90195
90503
|
import { homedir as homedir5 } from "os";
|
|
90196
90504
|
import { join as join44 } from "path";
|
|
90197
90505
|
|
|
90198
90506
|
// src/services/plan/plan-file-bridge.ts
|
|
90199
|
-
import { createHash as createHash3, randomUUID as
|
|
90507
|
+
import { createHash as createHash3, randomUUID as randomUUID8 } from "crypto";
|
|
90200
90508
|
import { existsSync as existsSync7, watch as watch4 } from "fs";
|
|
90201
90509
|
import { readFile as readFile34, rename as rename19, writeFile as writeFile25 } from "fs/promises";
|
|
90202
90510
|
import { homedir as homedir4 } from "os";
|
|
@@ -90461,7 +90769,7 @@ var PlanFileBridge = class _PlanFileBridge {
|
|
|
90461
90769
|
const content = this.#config.planRepo.getContent(this.#config.taskId);
|
|
90462
90770
|
const hash = contentHash(content);
|
|
90463
90771
|
if (hash === this.#lastWrittenHash) return;
|
|
90464
|
-
const tmpPath = `${this.#filePath}.${
|
|
90772
|
+
const tmpPath = `${this.#filePath}.${randomUUID8()}.tmp`;
|
|
90465
90773
|
await writeFile25(tmpPath, content, "utf-8");
|
|
90466
90774
|
await rename19(tmpPath, this.#filePath);
|
|
90467
90775
|
this.#lastWrittenHash = hash;
|
|
@@ -91214,7 +91522,7 @@ var PlanHandler = class {
|
|
|
91214
91522
|
const plansDir = join44(homedir5(), ".claude", "plans");
|
|
91215
91523
|
if (!existsSync8(plansDir)) return null;
|
|
91216
91524
|
try {
|
|
91217
|
-
const files =
|
|
91525
|
+
const files = readdirSync4(plansDir).filter((f2) => f2.endsWith(".md")).map((f2) => ({
|
|
91218
91526
|
path: join44(plansDir, f2),
|
|
91219
91527
|
mtime: statSync2(join44(plansDir, f2)).mtimeMs
|
|
91220
91528
|
})).sort((a, b2) => b2.mtime - a.mtime);
|
|
@@ -91833,14 +92141,14 @@ function planPostCompactPending(input) {
|
|
|
91833
92141
|
}
|
|
91834
92142
|
|
|
91835
92143
|
// src/services/task/compaction-snapshot.ts
|
|
91836
|
-
import { randomUUID as
|
|
92144
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
91837
92145
|
import { homedir as homedir6 } from "os";
|
|
91838
92146
|
import { join as pathJoin } from "path";
|
|
91839
92147
|
function resolveArchiveAbsolutePath(channelId) {
|
|
91840
92148
|
return pathJoin(homedir6(), ".shipyard", "data", "channels", `${channelId}.jsonl`);
|
|
91841
92149
|
}
|
|
91842
92150
|
function planCompactionSnapshot(input) {
|
|
91843
|
-
const threadId =
|
|
92151
|
+
const threadId = randomUUID9();
|
|
91844
92152
|
const channelId = buildThreadChannelId(input.taskId, threadId);
|
|
91845
92153
|
const compactionCount = input.messages.filter(
|
|
91846
92154
|
(m2) => m2.content.some((b2) => b2.type === "compaction_boundary")
|
|
@@ -91877,7 +92185,7 @@ function planCompactionSnapshot(input) {
|
|
|
91877
92185
|
stats
|
|
91878
92186
|
};
|
|
91879
92187
|
const boundaryMessage = {
|
|
91880
|
-
messageId:
|
|
92188
|
+
messageId: randomUUID9(),
|
|
91881
92189
|
channelId: input.channelId,
|
|
91882
92190
|
participantId: input.humanParticipantId,
|
|
91883
92191
|
senderKind: "human",
|
|
@@ -92757,7 +93065,7 @@ var RewindCheckpointHandler = class {
|
|
|
92757
93065
|
|
|
92758
93066
|
// src/services/task/side-thread-registry.ts
|
|
92759
93067
|
import { mkdir as mkdir20, readFile as readFile36, rename as rename20, writeFile as writeFile26 } from "fs/promises";
|
|
92760
|
-
import { dirname as
|
|
93068
|
+
import { dirname as dirname18, join as join45 } from "path";
|
|
92761
93069
|
var ThreadFileSchema = external_exports.object({
|
|
92762
93070
|
threads: external_exports.record(external_exports.string(), ThreadMetadataSchema)
|
|
92763
93071
|
});
|
|
@@ -93118,7 +93426,7 @@ var SideThreadRegistry = class {
|
|
|
93118
93426
|
threads[threadId] = entry.metadata;
|
|
93119
93427
|
}
|
|
93120
93428
|
const filePath = this.#filePath();
|
|
93121
|
-
await mkdir20(
|
|
93429
|
+
await mkdir20(dirname18(filePath), { recursive: true });
|
|
93122
93430
|
const tmpPath = `${filePath}.tmp`;
|
|
93123
93431
|
await writeFile26(tmpPath, JSON.stringify({ threads }, null, 2), "utf-8");
|
|
93124
93432
|
await rename20(tmpPath, filePath);
|
|
@@ -93533,7 +93841,7 @@ async function resolveResources(ctx, content, history2, excludeUris) {
|
|
|
93533
93841
|
import { watch as watch5 } from "fs";
|
|
93534
93842
|
import { readdir as readdir10, readFile as readFile37 } from "fs/promises";
|
|
93535
93843
|
import { homedir as homedir7 } from "os";
|
|
93536
|
-
import { basename as basename5, dirname as
|
|
93844
|
+
import { basename as basename5, dirname as dirname19, join as join46 } from "path";
|
|
93537
93845
|
var VALID_STATUSES2 = /* @__PURE__ */ new Set(["pending", "in_progress", "completed"]);
|
|
93538
93846
|
function sanitize(id) {
|
|
93539
93847
|
return id.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
@@ -93586,7 +93894,7 @@ function createCCTaskFileWatcher(listId, log) {
|
|
|
93586
93894
|
let debounceTimer = null;
|
|
93587
93895
|
const DEBOUNCE_MS4 = 200;
|
|
93588
93896
|
const targetDirName = basename5(dir);
|
|
93589
|
-
const parentDir =
|
|
93897
|
+
const parentDir = dirname19(dir);
|
|
93590
93898
|
function scheduleRead() {
|
|
93591
93899
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
93592
93900
|
debounceTimer = setTimeout(() => {
|
|
@@ -96285,7 +96593,7 @@ var Task = class {
|
|
|
96285
96593
|
instructions
|
|
96286
96594
|
});
|
|
96287
96595
|
const archiveMessages = plan.messagesToCopy.map((msg) => ({
|
|
96288
|
-
messageId:
|
|
96596
|
+
messageId: randomUUID10(),
|
|
96289
96597
|
channelId: plan.threadMetadata.channelId,
|
|
96290
96598
|
participantId: msg.participantId,
|
|
96291
96599
|
senderKind: msg.senderKind,
|
|
@@ -100444,7 +100752,7 @@ function buildThemeStore(dataDir) {
|
|
|
100444
100752
|
// src/services/themes/vscode-scanner.ts
|
|
100445
100753
|
import { readdir as readdir13, readFile as readFile39, stat as stat11 } from "fs/promises";
|
|
100446
100754
|
import { homedir as homedir9 } from "os";
|
|
100447
|
-
import { dirname as
|
|
100755
|
+
import { dirname as dirname20, join as join53, normalize as normalize5, resolve as resolve2 } from "path";
|
|
100448
100756
|
var VSCodeThemeEntrySchema2 = external_exports.object({
|
|
100449
100757
|
extensionId: external_exports.string(),
|
|
100450
100758
|
name: external_exports.string(),
|
|
@@ -100599,7 +100907,7 @@ async function readVSCodeThemeWithIncludes(absolutePath) {
|
|
|
100599
100907
|
const obj = await readObject(canonical);
|
|
100600
100908
|
const include = typeof obj.include === "string" ? obj.include : null;
|
|
100601
100909
|
if (!include) return obj;
|
|
100602
|
-
const basePath = resolve2(
|
|
100910
|
+
const basePath = resolve2(dirname20(canonical), include);
|
|
100603
100911
|
const base3 = await walk(basePath, depth + 1);
|
|
100604
100912
|
return mergeThemeObjects(base3, obj);
|
|
100605
100913
|
};
|
|
@@ -100912,7 +101220,8 @@ async function createDaemon(deps) {
|
|
|
100912
101220
|
const watcher = new VisualizationFileWatcher(registry, {
|
|
100913
101221
|
canvasRepo,
|
|
100914
101222
|
vizDir,
|
|
100915
|
-
log: deps.log
|
|
101223
|
+
log: deps.log,
|
|
101224
|
+
previewStateStore: deps.previewStateStore ?? null
|
|
100916
101225
|
});
|
|
100917
101226
|
watcher.setSendControlMessage((msg) => taskManager.broadcastControl(msg));
|
|
100918
101227
|
watcher.setRehydrationPromise(
|
|
@@ -100937,26 +101246,25 @@ async function createDaemon(deps) {
|
|
|
100937
101246
|
}
|
|
100938
101247
|
const trackedPreviewPorts = /* @__PURE__ */ new Map();
|
|
100939
101248
|
const previewLifecycleSubs = /* @__PURE__ */ new Map();
|
|
100940
|
-
function
|
|
100941
|
-
if (!isRecord4(dataField)) return
|
|
100942
|
-
|
|
100943
|
-
const port = dataField.port;
|
|
100944
|
-
return typeof port === "number" ? port : void 0;
|
|
101249
|
+
function isLocalPreviewElement(dataField, selfUserId) {
|
|
101250
|
+
if (!isRecord4(dataField)) return false;
|
|
101251
|
+
return dataField.ownerUserId === selfUserId;
|
|
100945
101252
|
}
|
|
100946
101253
|
function collectLocalPreviewPorts(taskId) {
|
|
100947
101254
|
const current2 = /* @__PURE__ */ new Map();
|
|
101255
|
+
const store2 = deps.previewStateStore ?? null;
|
|
101256
|
+
if (!store2) return current2;
|
|
100948
101257
|
for (const el of canvasRepo.getElements(taskId)) {
|
|
100949
101258
|
if (el.data.type !== "preview") continue;
|
|
100950
|
-
|
|
100951
|
-
|
|
101259
|
+
if (!isLocalPreviewElement(el.data.data, deps.auth.userId)) continue;
|
|
101260
|
+
const state = store2.getByElementId(taskId, String(el.id));
|
|
101261
|
+
const port = state?.port;
|
|
101262
|
+
if (typeof port === "number") current2.set(String(el.id), port);
|
|
100952
101263
|
}
|
|
100953
101264
|
return current2;
|
|
100954
101265
|
}
|
|
100955
|
-
function
|
|
100956
|
-
const
|
|
100957
|
-
const tracked = trackedPreviewPorts.get(taskId) ?? /* @__PURE__ */ new Map();
|
|
100958
|
-
trackedPreviewPorts.set(taskId, current2);
|
|
100959
|
-
for (const [elementId, port] of tracked) {
|
|
101266
|
+
function releaseRemovedProxyRefs(previous, current2) {
|
|
101267
|
+
for (const [elementId, port] of previous) {
|
|
100960
101268
|
const stillPresent = current2.get(elementId);
|
|
100961
101269
|
if (stillPresent === void 0 || stillPresent !== port) {
|
|
100962
101270
|
deps.previewProxy.release(port).catch(() => {
|
|
@@ -100964,6 +101272,22 @@ async function createDaemon(deps) {
|
|
|
100964
101272
|
}
|
|
100965
101273
|
}
|
|
100966
101274
|
}
|
|
101275
|
+
function sweepOrphanedPreviewState(taskId, liveElementIds) {
|
|
101276
|
+
const store2 = deps.previewStateStore ?? null;
|
|
101277
|
+
if (!store2) return;
|
|
101278
|
+
for (const state of store2.listByTask(taskId)) {
|
|
101279
|
+
if (liveElementIds.has(state.elementId)) continue;
|
|
101280
|
+
const el = canvasRepo.getElements(taskId).find((e) => String(e.id) === state.elementId);
|
|
101281
|
+
if (!el) store2.deleteByElementId(taskId, state.elementId);
|
|
101282
|
+
}
|
|
101283
|
+
}
|
|
101284
|
+
function reconcilePreviewRefs(taskId) {
|
|
101285
|
+
const current2 = collectLocalPreviewPorts(taskId);
|
|
101286
|
+
const tracked = trackedPreviewPorts.get(taskId) ?? /* @__PURE__ */ new Map();
|
|
101287
|
+
trackedPreviewPorts.set(taskId, current2);
|
|
101288
|
+
releaseRemovedProxyRefs(tracked, current2);
|
|
101289
|
+
sweepOrphanedPreviewState(taskId, new Set(current2.keys()));
|
|
101290
|
+
}
|
|
100967
101291
|
function ensurePreviewLifecycleTracking(taskId) {
|
|
100968
101292
|
if (previewLifecycleSubs.has(taskId)) return;
|
|
100969
101293
|
const unsub = canvasRepo.subscribe(
|
|
@@ -101003,6 +101327,7 @@ async function createDaemon(deps) {
|
|
|
101003
101327
|
getAuthToken: () => deps.auth.token,
|
|
101004
101328
|
projectRoot: cwd ?? deps.workspaceRoot,
|
|
101005
101329
|
publishedArtifactStore: deps.publishedArtifactStore ?? null,
|
|
101330
|
+
previewStateStore: deps.previewStateStore ?? null,
|
|
101006
101331
|
getDetectedPorts: deps.getDetectedPorts ?? (() => [])
|
|
101007
101332
|
});
|
|
101008
101333
|
const options = buildSpawnOptions({
|
|
@@ -101042,6 +101367,7 @@ async function createDaemon(deps) {
|
|
|
101042
101367
|
getAuthToken: () => deps.auth.token,
|
|
101043
101368
|
projectRoot,
|
|
101044
101369
|
publishedArtifactStore: deps.publishedArtifactStore ?? null,
|
|
101370
|
+
previewStateStore: deps.previewStateStore ?? null,
|
|
101045
101371
|
getDetectedPorts: deps.getDetectedPorts ?? (() => [])
|
|
101046
101372
|
});
|
|
101047
101373
|
deps.log({ event: "conversation_backend", backend: "direct-api", model, taskId });
|
|
@@ -101334,6 +101660,9 @@ async function createDaemon(deps) {
|
|
|
101334
101660
|
await sweepStaleTasks(taskStateStore, taskManager, deps.log);
|
|
101335
101661
|
await migratePinnedToFavoriteTasks(taskStateStore, userSettingsStore, deps.log);
|
|
101336
101662
|
await rehydrateCollabQueues(collabQueuePersistence, taskManager, deps.log);
|
|
101663
|
+
if (deps.previewStateStore) {
|
|
101664
|
+
await migrateLegacyPreviewData(canvasRepo, deps.previewStateStore, taskStateStore, deps.log);
|
|
101665
|
+
}
|
|
101337
101666
|
const warmedPreviewTasks = await rehydrateCanvasPreviews(
|
|
101338
101667
|
canvasRepo,
|
|
101339
101668
|
deps.previewProxy,
|
|
@@ -101931,6 +102260,14 @@ function filterOutboundForCollab(msg, collabTaskId, getTaskSync) {
|
|
|
101931
102260
|
case "background_agent_update":
|
|
101932
102261
|
case "viz_content":
|
|
101933
102262
|
case "viz_content_batch":
|
|
102263
|
+
/**
|
|
102264
|
+
* published_artifacts_state and preview_elements_state are per-task
|
|
102265
|
+
* but visible to all collaborators so the chip + iframe on each
|
|
102266
|
+
* canvas element reflect the same reality for everyone. Same rule
|
|
102267
|
+
* as the other task-scoped messages: match taskId or drop.
|
|
102268
|
+
*/
|
|
102269
|
+
case "published_artifacts_state":
|
|
102270
|
+
case "preview_elements_state":
|
|
101934
102271
|
if ("taskId" in msg && msg.taskId !== collabTaskId) return null;
|
|
101935
102272
|
return msg;
|
|
101936
102273
|
/** Preview: collab peers need port detection and preview targets */
|
|
@@ -101956,13 +102293,6 @@ function filterOutboundForCollab(msg, collabTaskId, getTaskSync) {
|
|
|
101956
102293
|
case "publish_progress":
|
|
101957
102294
|
case "publish_result":
|
|
101958
102295
|
return null;
|
|
101959
|
-
/**
|
|
101960
|
-
* published_artifacts_state is per-task but visible to all collaborators
|
|
101961
|
-
* so the chip on each element reflects the same reality for everyone.
|
|
101962
|
-
* Filter by taskId so a peer only sees state for tasks they participate in.
|
|
101963
|
-
*/
|
|
101964
|
-
case "published_artifacts_state":
|
|
101965
|
-
return msg.taskId === collabTaskId ? msg : null;
|
|
101966
102296
|
/** Exhaustiveness check: compile error if a new type is unhandled */
|
|
101967
102297
|
default: {
|
|
101968
102298
|
const _exhaustive = msg;
|
|
@@ -102516,7 +102846,7 @@ import { readdir as readdir14 } from "fs/promises";
|
|
|
102516
102846
|
import { execFile as execFile8, spawn as spawn5 } from "child_process";
|
|
102517
102847
|
import { closeSync, openSync } from "fs";
|
|
102518
102848
|
import { access as access3, chmod as chmod2, constants, mkdir as mkdir24, writeFile as writeFile30 } from "fs/promises";
|
|
102519
|
-
import { dirname as
|
|
102849
|
+
import { dirname as dirname21, isAbsolute as isAbsolute2, join as join55 } from "path";
|
|
102520
102850
|
var GIT_TIMEOUT_MS = 3e4;
|
|
102521
102851
|
var MAX_BUFFER = 10 * 1024 * 1024;
|
|
102522
102852
|
var BASE_REF_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9/_.-]*$/;
|
|
@@ -102779,7 +103109,7 @@ async function removeWorktree(worktreePath) {
|
|
|
102779
103109
|
if (!worktreePath.includes("-wt/")) {
|
|
102780
103110
|
throw new Error("worktreePath must be under a -wt/ parent directory");
|
|
102781
103111
|
}
|
|
102782
|
-
await runGit(["worktree", "remove", worktreePath],
|
|
103112
|
+
await runGit(["worktree", "remove", worktreePath], dirname21(worktreePath));
|
|
102783
103113
|
}
|
|
102784
103114
|
|
|
102785
103115
|
// src/services/channels/control-channel-infra-handlers.ts
|
|
@@ -103274,7 +103604,7 @@ function runPluginOp(pluginName, marketplace, action, ctx) {
|
|
|
103274
103604
|
}
|
|
103275
103605
|
|
|
103276
103606
|
// src/services/channels/read-recent-logs.ts
|
|
103277
|
-
import { createReadStream, readdirSync as
|
|
103607
|
+
import { createReadStream, readdirSync as readdirSync5 } from "fs";
|
|
103278
103608
|
import { join as join56 } from "path";
|
|
103279
103609
|
import { createInterface } from "readline";
|
|
103280
103610
|
var MAX_BYTES = 5e4;
|
|
@@ -103332,7 +103662,7 @@ async function readRecentLogs(logDir, windowMinutes, maxBytes = MAX_BYTES) {
|
|
|
103332
103662
|
function discoverLogFiles(logDir) {
|
|
103333
103663
|
let entries;
|
|
103334
103664
|
try {
|
|
103335
|
-
entries =
|
|
103665
|
+
entries = readdirSync5(logDir);
|
|
103336
103666
|
} catch {
|
|
103337
103667
|
return [];
|
|
103338
103668
|
}
|
|
@@ -104919,6 +105249,7 @@ function wireControlChannel(rawChannel, daemon, logAdapter, deps) {
|
|
|
104919
105249
|
}
|
|
104920
105250
|
};
|
|
104921
105251
|
const publishedArtifactStore = deps.publishedArtifactStore;
|
|
105252
|
+
const previewStateStore = deps.previewStateStore;
|
|
104922
105253
|
const getDetectedPorts = deps.getDetectedPorts;
|
|
104923
105254
|
handlePublishRequest({
|
|
104924
105255
|
correlationId,
|
|
@@ -104931,6 +105262,7 @@ function wireControlChannel(rawChannel, daemon, logAdapter, deps) {
|
|
|
104931
105262
|
projectRoot: wsRoot,
|
|
104932
105263
|
vizWatcher,
|
|
104933
105264
|
publishedArtifactStore,
|
|
105265
|
+
previewStateStore,
|
|
104934
105266
|
getDetectedPorts,
|
|
104935
105267
|
sendControl: wrappedSendControl,
|
|
104936
105268
|
log: (entry) => {
|
|
@@ -105150,6 +105482,24 @@ function wireControlChannel(rawChannel, daemon, logAdapter, deps) {
|
|
|
105150
105482
|
});
|
|
105151
105483
|
});
|
|
105152
105484
|
}
|
|
105485
|
+
if (deps?.previewStateStore) {
|
|
105486
|
+
const previewStore = deps.previewStateStore;
|
|
105487
|
+
daemon.taskStateStore.listTasks().then((tasks) => {
|
|
105488
|
+
for (const taskId of Object.keys(tasks)) {
|
|
105489
|
+
const entries = previewStore.listByTask(taskId);
|
|
105490
|
+
controlHandler.sendControl({
|
|
105491
|
+
type: "preview_elements_state",
|
|
105492
|
+
taskId,
|
|
105493
|
+
entries
|
|
105494
|
+
});
|
|
105495
|
+
}
|
|
105496
|
+
}).catch((err) => {
|
|
105497
|
+
logAdapter({
|
|
105498
|
+
event: "preview_elements_initial_push_failed",
|
|
105499
|
+
error: err instanceof Error ? err.message : String(err)
|
|
105500
|
+
});
|
|
105501
|
+
});
|
|
105502
|
+
}
|
|
105153
105503
|
const userSettingsUnsub = daemon.userSettingsStore.subscribe((settings) => {
|
|
105154
105504
|
controlHandler.sendControl({ type: "user_settings_updated", settings });
|
|
105155
105505
|
});
|
|
@@ -105684,7 +106034,7 @@ import { promisify as promisify7 } from "util";
|
|
|
105684
106034
|
|
|
105685
106035
|
// src/shared/file-io-path-safety.ts
|
|
105686
106036
|
import { realpath } from "fs/promises";
|
|
105687
|
-
import { basename as basename6, dirname as
|
|
106037
|
+
import { basename as basename6, dirname as dirname22, join as join57, normalize as normalize6 } from "path";
|
|
105688
106038
|
async function safeAbsolutePath(userPath, isHidden2, allowedHiddenNames) {
|
|
105689
106039
|
const normalized = prepareAbsolutePath(userPath, isHidden2, allowedHiddenNames);
|
|
105690
106040
|
if (normalized === null) return null;
|
|
@@ -105706,13 +106056,13 @@ async function canonicalizeOrRecombine(path2) {
|
|
|
105706
106056
|
try {
|
|
105707
106057
|
return await realpath(path2);
|
|
105708
106058
|
} catch (err) {
|
|
105709
|
-
if (!
|
|
105710
|
-
const parentCanonical = await realpath(
|
|
106059
|
+
if (!isEnoent4(err)) return null;
|
|
106060
|
+
const parentCanonical = await realpath(dirname22(path2)).catch(() => null);
|
|
105711
106061
|
if (parentCanonical === null) return null;
|
|
105712
106062
|
return join57(parentCanonical, basename6(path2));
|
|
105713
106063
|
}
|
|
105714
106064
|
}
|
|
105715
|
-
function
|
|
106065
|
+
function isEnoent4(err) {
|
|
105716
106066
|
return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
|
|
105717
106067
|
}
|
|
105718
106068
|
function checkSegmentsAllowed(path2, isHidden2, allowedHiddenNames) {
|
|
@@ -107022,13 +107372,13 @@ function wireThreadErrorFallback(daemon, dc, taskId, threadId, channelId, log) {
|
|
|
107022
107372
|
// src/shared/pty-manager.ts
|
|
107023
107373
|
import { accessSync, chmodSync, constants as constants2 } from "fs";
|
|
107024
107374
|
import { createRequire as createRequire4 } from "module";
|
|
107025
|
-
import { dirname as
|
|
107375
|
+
import { dirname as dirname23, resolve as resolve4 } from "path";
|
|
107026
107376
|
import * as pty from "node-pty";
|
|
107027
107377
|
function ensureSpawnHelperExecutable() {
|
|
107028
107378
|
if (globalThis.process.platform === "win32") return;
|
|
107029
107379
|
try {
|
|
107030
107380
|
const req = createRequire4(import.meta.url);
|
|
107031
|
-
const nodePtyDir =
|
|
107381
|
+
const nodePtyDir = dirname23(req.resolve("node-pty/package.json"));
|
|
107032
107382
|
const spawnHelper = resolve4(
|
|
107033
107383
|
nodePtyDir,
|
|
107034
107384
|
"prebuilds",
|
|
@@ -107487,8 +107837,9 @@ function buildCollabRoomManager(deps) {
|
|
|
107487
107837
|
configStore: pluginConfigStore,
|
|
107488
107838
|
previewProxy,
|
|
107489
107839
|
presencePool: presencePoolRef,
|
|
107490
|
-
/** Collab peers cannot publish — null
|
|
107840
|
+
/** Collab peers cannot publish — null stores enforce read-only access. */
|
|
107491
107841
|
publishedArtifactStore: null,
|
|
107842
|
+
previewStateStore: null,
|
|
107492
107843
|
getDetectedPorts: () => []
|
|
107493
107844
|
});
|
|
107494
107845
|
if (loadedPluginsRef.current.length > 0) {
|
|
@@ -107770,7 +108121,7 @@ function buildCollabRoomManager(deps) {
|
|
|
107770
108121
|
import { execSync } from "child_process";
|
|
107771
108122
|
import { existsSync as existsSync9 } from "fs";
|
|
107772
108123
|
import { createRequire as createRequire5 } from "module";
|
|
107773
|
-
import { dirname as
|
|
108124
|
+
import { dirname as dirname24, join as join59 } from "path";
|
|
107774
108125
|
|
|
107775
108126
|
// src/services/bootstrap/self-update.ts
|
|
107776
108127
|
import { execFile as execFile11, spawn as spawn9 } from "child_process";
|
|
@@ -108433,7 +108784,7 @@ function resolveClaudeCodePath(log) {
|
|
|
108433
108784
|
try {
|
|
108434
108785
|
const req = createRequire5(import.meta.url);
|
|
108435
108786
|
const sdkMain = req.resolve("@anthropic-ai/claude-agent-sdk");
|
|
108436
|
-
const p2 = join59(
|
|
108787
|
+
const p2 = join59(dirname24(sdkMain), "cli.js");
|
|
108437
108788
|
if (existsSync9(p2)) return ok("sdk_bundled", p2);
|
|
108438
108789
|
} catch {
|
|
108439
108790
|
}
|
|
@@ -108697,7 +109048,8 @@ function buildSharedChannelCallbacks(deps) {
|
|
|
108697
109048
|
terminalPtys,
|
|
108698
109049
|
signalingHandle,
|
|
108699
109050
|
sessionServerUrl,
|
|
108700
|
-
publishedArtifactStore
|
|
109051
|
+
publishedArtifactStore,
|
|
109052
|
+
previewStateStore
|
|
108701
109053
|
} = deps;
|
|
108702
109054
|
return {
|
|
108703
109055
|
onPeerDataChannel: (machineId) => {
|
|
@@ -108720,6 +109072,7 @@ function buildSharedChannelCallbacks(deps) {
|
|
|
108720
109072
|
sessionServerUrl,
|
|
108721
109073
|
getAuthToken: () => auth3.token,
|
|
108722
109074
|
publishedArtifactStore,
|
|
109075
|
+
previewStateStore,
|
|
108723
109076
|
getDetectedPorts: () => detectedPortsRef.current
|
|
108724
109077
|
});
|
|
108725
109078
|
portDetectorRef.current?.resend();
|
|
@@ -109133,6 +109486,10 @@ async function serve(options = {}) {
|
|
|
109133
109486
|
rootDir: join62(dataDir, "published"),
|
|
109134
109487
|
logger: log
|
|
109135
109488
|
});
|
|
109489
|
+
const previewStateStore = createPreviewStateStore({
|
|
109490
|
+
rootDir: join62(dataDir, "preview-state"),
|
|
109491
|
+
logger: log
|
|
109492
|
+
});
|
|
109136
109493
|
const daemon = await createDaemon({
|
|
109137
109494
|
shipyardHome,
|
|
109138
109495
|
dataDir,
|
|
@@ -109152,10 +109509,12 @@ async function serve(options = {}) {
|
|
|
109152
109509
|
previewProxy,
|
|
109153
109510
|
sessionServerUrl,
|
|
109154
109511
|
publishedArtifactStore,
|
|
109512
|
+
previewStateStore,
|
|
109155
109513
|
getDetectedPorts: () => detectedPortsRef.current
|
|
109156
109514
|
});
|
|
109157
109515
|
daemon.healthMetrics.start();
|
|
109158
109516
|
publishedArtifactStore.setSendControlMessage((msg) => daemon.taskManager.broadcastControl(msg));
|
|
109517
|
+
previewStateStore.setSendControlMessage((msg) => daemon.taskManager.broadcastControl(msg));
|
|
109159
109518
|
const pluginsDir = join62(shipyardHome, "plugins");
|
|
109160
109519
|
await mkdir28(pluginsDir, { recursive: true });
|
|
109161
109520
|
let loadedPlugins = [];
|
|
@@ -109287,7 +109646,8 @@ async function serve(options = {}) {
|
|
|
109287
109646
|
fileWatcherPool,
|
|
109288
109647
|
terminalPtys,
|
|
109289
109648
|
sessionServerUrl,
|
|
109290
|
-
publishedArtifactStore
|
|
109649
|
+
publishedArtifactStore,
|
|
109650
|
+
previewStateStore
|
|
109291
109651
|
} : null;
|
|
109292
109652
|
const peerManager = peerSetupDeps ? buildPeerManager(peerSetupDeps) : null;
|
|
109293
109653
|
if (peerSetupDeps && !localDirectRef.current) {
|
|
@@ -109400,6 +109760,7 @@ async function serve(options = {}) {
|
|
|
109400
109760
|
log.info("Graceful shutdown initiated");
|
|
109401
109761
|
portDetector.dispose();
|
|
109402
109762
|
publishedArtifactStore.dispose();
|
|
109763
|
+
previewStateStore.dispose();
|
|
109403
109764
|
await previewProxy.stop();
|
|
109404
109765
|
pluginFileWatcher.dispose();
|
|
109405
109766
|
await fileWatcherPool.dispose();
|
|
@@ -109436,4 +109797,4 @@ export {
|
|
|
109436
109797
|
_testing,
|
|
109437
109798
|
serve
|
|
109438
109799
|
};
|
|
109439
|
-
//# sourceMappingURL=serve-
|
|
109800
|
+
//# sourceMappingURL=serve-ULDOVKX7.js.map
|