@schoolai/shipyard 3.4.0-nightly.20260430.0 → 3.4.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/index.js CHANGED
@@ -111,7 +111,7 @@ async function handleSubcommand() {
111
111
  return true;
112
112
  }
113
113
  if (subcommand === "start") {
114
- const { startCommand } = await import("./start-LMIPVOCM.js");
114
+ const { startCommand } = await import("./start-6AQMLAOX.js");
115
115
  await startCommand();
116
116
  return true;
117
117
  }
@@ -128,7 +128,7 @@ async function main() {
128
128
  const args = parseCliArgs();
129
129
  if (args.serve) {
130
130
  await loadAuthFromConfig(env);
131
- const { serve } = await import("./serve-TUBBJN36.js");
131
+ const { serve } = await import("./serve-QENWMCVP.js");
132
132
  return serve({ isDev: env.SHIPYARD_DEV });
133
133
  }
134
134
  logger.error("Use `shipyard start` to run the daemon. Use --help for usage.");
@@ -24152,9 +24152,9 @@ var MarkdownSerializerState = class {
24152
24152
  /**
24153
24153
  Get the markdown string for a given opening or closing mark.
24154
24154
  */
24155
- markString(mark, open3, parent, index) {
24155
+ markString(mark, open2, parent, index) {
24156
24156
  let info = this.getMark(mark.type.name);
24157
- let value = open3 ? info.open : info.close;
24157
+ let value = open2 ? info.open : info.close;
24158
24158
  return typeof value == "string" ? value : value(this, mark, parent, index);
24159
24159
  }
24160
24160
  /**
@@ -69406,8 +69406,8 @@ var Fitter = class {
69406
69406
  this.frontier.push({ type, match: type.contentMatch });
69407
69407
  }
69408
69408
  closeFrontierNode() {
69409
- let open3 = this.frontier.pop();
69410
- let add2 = open3.match.fillBefore(Fragment.empty, true);
69409
+ let open2 = this.frontier.pop();
69410
+ let add2 = open2.match.fillBefore(Fragment.empty, true);
69411
69411
  if (add2.childCount)
69412
69412
  this.placed = addToFragment(this.placed, this.frontier.length, add2);
69413
69413
  }
@@ -69440,8 +69440,8 @@ function closeNodeStart(node, openStart, openEnd) {
69440
69440
  }
69441
69441
  return node.copy(frag);
69442
69442
  }
69443
- function contentAfterFits($to, depth, type, match2, open3) {
69444
- let node = $to.node(depth), index = open3 ? $to.indexAfter(depth) : $to.index(depth);
69443
+ function contentAfterFits($to, depth, type, match2, open2) {
69444
+ let node = $to.node(depth), index = open2 ? $to.indexAfter(depth) : $to.index(depth);
69445
69445
  if (index == node.childCount && !type.compatibleContent(node.type))
69446
69446
  return null;
69447
69447
  let fit = match2.fillBefore(node.content, true, index);
@@ -92602,13 +92602,13 @@ function parseTaskNotificationXml(content) {
92602
92602
  return { type: "background_agent_result", taskId, result };
92603
92603
  }
92604
92604
  function extractXmlTag(xml, tag) {
92605
- const open3 = `<${tag}>`;
92605
+ const open2 = `<${tag}>`;
92606
92606
  const close2 = `</${tag}>`;
92607
- const start = xml.indexOf(open3);
92607
+ const start = xml.indexOf(open2);
92608
92608
  if (start === -1) return null;
92609
- const end = xml.indexOf(close2, start + open3.length);
92609
+ const end = xml.indexOf(close2, start + open2.length);
92610
92610
  if (end === -1) return null;
92611
- return xml.slice(start + open3.length, end);
92611
+ return xml.slice(start + open2.length, end);
92612
92612
  }
92613
92613
  function classifyMessage(message, log) {
92614
92614
  switch (message.type) {
@@ -101790,7 +101790,7 @@ function buildCredentialsVaultStore(filePath) {
101790
101790
  }
101791
101791
 
101792
101792
  // src/services/storage/jsonl-conversation-store.ts
101793
- import { appendFile as appendFile3, mkdir as mkdir18, open, readFile as readFile34, rename as rename17, stat as stat14, writeFile as writeFile24 } from "fs/promises";
101793
+ import { appendFile as appendFile3, mkdir as mkdir18, readFile as readFile34, rename as rename17, stat as stat14, writeFile as writeFile24 } from "fs/promises";
101794
101794
  import { join as join46 } from "path";
101795
101795
  var StoredMessageSchema = MessageSchema.omit({ seqNo: true, channelId: true });
101796
101796
  function logPerf(entry) {
@@ -101811,21 +101811,6 @@ function buildJsonlConversationStore(dataDir) {
101811
101811
  async function ensureDir() {
101812
101812
  await mkdir18(channelsDir, { recursive: true });
101813
101813
  }
101814
- function parseJsonlBlob(raw, channelId) {
101815
- const lines = raw.split("\n");
101816
- if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
101817
- const messages = [];
101818
- for (let seqNo = 0; seqNo < lines.length; seqNo++) {
101819
- const line = lines[seqNo];
101820
- if (!line) continue;
101821
- try {
101822
- const parsed = StoredMessageSchema.parse(JSON.parse(line));
101823
- messages.push({ ...parsed, seqNo, channelId });
101824
- } catch {
101825
- }
101826
- }
101827
- return messages;
101828
- }
101829
101814
  async function readLines(channelId) {
101830
101815
  const startedAt = Date.now();
101831
101816
  logPerf({ event: "perf_jsonl_read_start", channelId });
@@ -101833,146 +101818,44 @@ function buildJsonlConversationStore(dataDir) {
101833
101818
  try {
101834
101819
  raw = await readFile34(channelPath(channelId), "utf-8");
101835
101820
  } catch (err) {
101836
- if (!isEnoent(err)) throw err;
101837
- logPerf({
101838
- event: "perf_jsonl_read_done",
101839
- channelId,
101840
- bytes: 0,
101841
- linesParsed: 0,
101842
- durationMs: Date.now() - startedAt
101843
- });
101844
- return [];
101845
- }
101846
- const messages = parseJsonlBlob(raw, channelId);
101847
- logPerf({
101848
- event: "perf_jsonl_read_done",
101849
- channelId,
101850
- bytes: Buffer.byteLength(raw, "utf-8"),
101851
- linesParsed: messages.length,
101852
- durationMs: Date.now() - startedAt
101853
- });
101854
- return messages;
101855
- }
101856
- async function countLinesInFile(path2) {
101857
- let fh;
101858
- try {
101859
- fh = await open(path2, "r");
101860
- } catch (err) {
101861
- if (isEnoent(err)) return 0;
101862
- throw err;
101863
- }
101864
- try {
101865
- const s2 = await fh.stat();
101866
- return await countNewlinesInRange(fh, 0, s2.size);
101867
- } finally {
101868
- await fh.close();
101869
- }
101870
- }
101871
- async function readBackwardChunks(fh, fileSize, targetNewlines) {
101872
- const CHUNK = 64 * 1024;
101873
- const chunks = [];
101874
- let newlines = 0;
101875
- let cursor = fileSize;
101876
- while (cursor > 0 && newlines <= targetNewlines) {
101877
- const readLen = Math.min(CHUNK, cursor);
101878
- const nextStart = cursor - readLen;
101879
- const buf = Buffer.allocUnsafe(readLen);
101880
- const { bytesRead } = await fh.read(buf, 0, readLen, nextStart);
101881
- const slice2 = bytesRead === readLen ? buf : buf.subarray(0, bytesRead);
101882
- for (let i = 0; i < slice2.length; i++) {
101883
- if (slice2[i] === 10) newlines++;
101884
- }
101885
- chunks.unshift(slice2);
101886
- cursor = nextStart;
101887
- }
101888
- return { chunks, newlines, startByte: cursor };
101889
- }
101890
- async function countNewlinesInRange(fh, start, end) {
101891
- if (start >= end) return 0;
101892
- const CHUNK = 64 * 1024;
101893
- const buf = Buffer.allocUnsafe(CHUNK);
101894
- let count = 0;
101895
- let pos = start;
101896
- while (pos < end) {
101897
- const readLen = Math.min(CHUNK, end - pos);
101898
- const { bytesRead } = await fh.read(buf, 0, readLen, pos);
101899
- for (let i = 0; i < bytesRead; i++) {
101900
- if (buf[i] === 10) count++;
101821
+ if (isEnoent(err)) {
101822
+ logPerf({
101823
+ event: "perf_jsonl_read_done",
101824
+ channelId,
101825
+ bytes: 0,
101826
+ linesParsed: 0,
101827
+ durationMs: Date.now() - startedAt
101828
+ });
101829
+ return [];
101901
101830
  }
101902
- pos += bytesRead;
101831
+ throw err;
101903
101832
  }
101904
- return count;
101905
- }
101906
- function extractTailLines(chunks, chunkedFromOffset, limit) {
101907
- const raw = Buffer.concat(chunks).toString("utf-8");
101908
- let lines = raw.split("\n");
101909
- if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
101910
- if (chunkedFromOffset > 0 && lines.length > 0) lines = lines.slice(1);
101911
- return lines.length <= limit ? lines : lines.slice(-limit);
101912
- }
101913
- function parseTailLines(lines, startSeqNo, channelId) {
101833
+ const lines = raw.split("\n").filter((line) => line.length > 0);
101914
101834
  const messages = [];
101835
+ let seqNo = 0;
101915
101836
  for (let i = 0; i < lines.length; i++) {
101916
101837
  const line = lines[i];
101917
101838
  if (!line) continue;
101918
101839
  try {
101919
101840
  const parsed = StoredMessageSchema.parse(JSON.parse(line));
101920
- messages.push({ ...parsed, seqNo: startSeqNo + i, channelId });
101841
+ messages.push({
101842
+ ...parsed,
101843
+ seqNo,
101844
+ channelId
101845
+ });
101846
+ seqNo++;
101921
101847
  } catch {
101922
- return null;
101923
101848
  }
101924
101849
  }
101850
+ logPerf({
101851
+ event: "perf_jsonl_read_done",
101852
+ channelId,
101853
+ bytes: Buffer.byteLength(raw, "utf-8"),
101854
+ linesParsed: messages.length,
101855
+ durationMs: Date.now() - startedAt
101856
+ });
101925
101857
  return messages;
101926
101858
  }
101927
- async function streamTailFromDisk(channelId, fileSize, limit) {
101928
- let fh;
101929
- try {
101930
- fh = await open(channelPath(channelId), "r");
101931
- } catch (err) {
101932
- if (isEnoent(err)) return { messages: [], totalLines: 0 };
101933
- throw err;
101934
- }
101935
- try {
101936
- const tail = await readBackwardChunks(fh, fileSize, limit);
101937
- const prefixNewlines = await countNewlinesInRange(fh, 0, tail.startByte);
101938
- const tailLines = extractTailLines(tail.chunks, tail.startByte, limit);
101939
- const totalLines = prefixNewlines + tail.newlines;
101940
- const startSeqNo = totalLines - tailLines.length;
101941
- const messages = parseTailLines(tailLines, startSeqNo, channelId);
101942
- if (messages === null) return null;
101943
- return { messages, totalLines };
101944
- } finally {
101945
- await fh.close();
101946
- }
101947
- }
101948
- async function statFreshness(path2) {
101949
- try {
101950
- const s2 = await stat14(path2);
101951
- return { size: s2.size, mtimeMs: s2.mtimeMs };
101952
- } catch (err) {
101953
- if (isEnoent(err)) return null;
101954
- throw err;
101955
- }
101956
- }
101957
- function readTailFromCache(channelId, limit, fileStat) {
101958
- const hit = readCache.get(channelId);
101959
- if (!hit || hit.size !== fileStat.size || hit.mtimeMs !== fileStat.mtimeMs) return null;
101960
- const tail = hit.messages.length <= limit ? [...hit.messages] : hit.messages.slice(-limit);
101961
- return { messages: tail, totalLines: hit.messages.length };
101962
- }
101963
- async function readTail(channelId, limit) {
101964
- if (limit <= 0) return { messages: [], totalLines: 0 };
101965
- const fileStat = await statFreshness(channelPath(channelId));
101966
- if (fileStat === null || fileStat.size === 0) return { messages: [], totalLines: 0 };
101967
- const cached2 = readTailFromCache(channelId, limit, fileStat);
101968
- if (cached2 !== null) return cached2;
101969
- if (fileStat.size <= 256 * 1024) {
101970
- const all = await readLinesCached(channelId);
101971
- const tail = all.length <= limit ? all : all.slice(-limit);
101972
- return { messages: tail, totalLines: all.length };
101973
- }
101974
- return streamTailFromDisk(channelId, fileStat.size, limit);
101975
- }
101976
101859
  async function readLinesCached(channelId) {
101977
101860
  const path2 = channelPath(channelId);
101978
101861
  let fileStat = null;
@@ -101995,22 +101878,14 @@ function buildJsonlConversationStore(dataDir) {
101995
101878
  });
101996
101879
  return [...fresh];
101997
101880
  }
101998
- function pushIntoLiveCache(channelId, appended, fileStat) {
101999
- const liveHit = readCache.get(channelId);
102000
- if (!liveHit) return;
102001
- const lastSeqNo = liveHit.messages[liveHit.messages.length - 1]?.seqNo ?? -1;
102002
- const incoming = Array.isArray(appended) ? appended : [appended];
102003
- for (const m2 of incoming) {
102004
- if (m2.seqNo > lastSeqNo) liveHit.messages.push(m2);
102005
- }
102006
- liveHit.size = fileStat.size;
102007
- liveHit.mtimeMs = fileStat.mtimeMs;
102008
- }
102009
101881
  async function refreshCacheAfterAppend(channelId, appended) {
102010
- if (!readCache.get(channelId)) return;
101882
+ const hit = readCache.get(channelId);
101883
+ if (!hit) return;
102011
101884
  try {
102012
101885
  const s2 = await stat14(channelPath(channelId));
102013
- pushIntoLiveCache(channelId, appended, { size: s2.size, mtimeMs: s2.mtimeMs });
101886
+ hit.messages.push(appended);
101887
+ hit.size = s2.size;
101888
+ hit.mtimeMs = s2.mtimeMs;
102014
101889
  } catch (err) {
102015
101890
  if (isEnoent(err)) {
102016
101891
  readCache.delete(channelId);
@@ -102057,14 +101932,15 @@ function buildJsonlConversationStore(dataDir) {
102057
101932
  if (!found2) return null;
102058
101933
  return { kind: "duplicate", seqNo: found2.seqNo, dedupKey: `fp:${fingerprint}` };
102059
101934
  }
102060
- function classifyDedupResult(existing, message, nextSeqNo, dedupWindowMs, now) {
101935
+ function classifyDedupResult(existing, message, currentSeq, dedupWindowMs, now) {
102061
101936
  const byCorr = decideDedupByCorrelation(existing, message);
102062
101937
  if (byCorr) return byCorr;
102063
101938
  const bySdk = decideDedupBySdkUuid(existing, message);
102064
101939
  if (bySdk) return bySdk;
102065
101940
  const byFp = decideDedupByFingerprint(existing, message, dedupWindowMs, now);
102066
101941
  if (byFp) return byFp;
102067
- return { kind: "append", seqNo: nextSeqNo };
101942
+ const seqNo = currentSeq !== void 0 ? currentSeq + 1 : existing.length;
101943
+ return { kind: "append", seqNo };
102068
101944
  }
102069
101945
  return {
102070
101946
  async appendMessage(message) {
@@ -102082,18 +101958,15 @@ function buildJsonlConversationStore(dataDir) {
102082
101958
  if (currentSeq !== void 0) {
102083
101959
  seqNo = currentSeq + 1;
102084
101960
  } else {
102085
- seqNo = await countLinesInFile(channelPath(message.channelId));
101961
+ const existing = await readLines(message.channelId);
101962
+ seqNo = existing.length;
102086
101963
  }
102087
101964
  seqCounters.set(message.channelId, seqNo);
102088
101965
  const { channelId: _channelId, ...rest } = message;
102089
101966
  const line = JSON.stringify(rest);
102090
101967
  await appendFile3(channelPath(message.channelId), `${line}
102091
101968
  `, "utf-8");
102092
- await refreshCacheAfterAppend(message.channelId, {
102093
- ...rest,
102094
- channelId: message.channelId,
102095
- seqNo
102096
- });
101969
+ readCache.delete(message.channelId);
102097
101970
  resolveSeqNo(seqNo);
102098
101971
  }).catch((err) => {
102099
101972
  readCache.delete(message.channelId);
@@ -102127,24 +102000,22 @@ function buildJsonlConversationStore(dataDir) {
102127
102000
  if (currentSeq !== void 0) {
102128
102001
  startSeqNo = currentSeq + 1;
102129
102002
  } else {
102130
- startSeqNo = await countLinesInFile(channelPath(channelId));
102003
+ const existing = await readLines(channelId);
102004
+ startSeqNo = existing.length;
102131
102005
  }
102132
102006
  const seqNos = [];
102133
102007
  const lines = [];
102134
- const cacheUpdates = [];
102135
102008
  for (let i = 0; i < messages.length; i++) {
102136
102009
  const msg = messages[i];
102137
102010
  if (!msg) continue;
102138
- const seqNo = startSeqNo + i;
102139
- seqNos.push(seqNo);
102011
+ seqNos.push(startSeqNo + i);
102140
102012
  const { channelId: _cid, ...rest } = msg;
102141
102013
  lines.push(JSON.stringify(rest));
102142
- cacheUpdates.push({ ...rest, channelId, seqNo });
102143
102014
  }
102144
102015
  await appendFile3(channelPath(channelId), `${lines.join("\n")}
102145
102016
  `, "utf-8");
102146
102017
  seqCounters.set(channelId, startSeqNo + messages.length - 1);
102147
- await refreshCacheAfterAppend(channelId, cacheUpdates);
102018
+ readCache.delete(channelId);
102148
102019
  resolveSeqNos(seqNos);
102149
102020
  }).catch((err) => {
102150
102021
  readCache.delete(channelId);
@@ -102166,11 +102037,10 @@ function buildJsonlConversationStore(dataDir) {
102166
102037
  await ensureDir();
102167
102038
  const existing = await readLinesCached(message.channelId);
102168
102039
  const currentSeq = seqCounters.get(message.channelId);
102169
- const nextSeqNo = currentSeq !== void 0 ? currentSeq + 1 : await countLinesInFile(channelPath(message.channelId));
102170
102040
  const decision = classifyDedupResult(
102171
102041
  existing,
102172
102042
  message,
102173
- nextSeqNo,
102043
+ currentSeq,
102174
102044
  DEDUP_WINDOW_MS,
102175
102045
  Date.now()
102176
102046
  );
@@ -102272,16 +102142,6 @@ function buildJsonlConversationStore(dataDir) {
102272
102142
  };
102273
102143
  },
102274
102144
  async getMessagesBefore(channelId, beforeSeqNo, limit) {
102275
- if (limit <= 0) return { messages: [], hasMore: false };
102276
- if (beforeSeqNo === Number.POSITIVE_INFINITY) {
102277
- const tail = await readTail(channelId, limit);
102278
- if (tail !== null) {
102279
- return {
102280
- messages: tail.messages,
102281
- hasMore: tail.totalLines > tail.messages.length
102282
- };
102283
- }
102284
- }
102285
102145
  const all = await readLinesCached(channelId);
102286
102146
  if (beforeSeqNo === Number.POSITIVE_INFINITY && all.length <= limit) {
102287
102147
  return { messages: all, hasMore: false };
@@ -110594,7 +110454,7 @@ var StructuredTaskTracker = class {
110594
110454
 
110595
110455
  // src/services/task/subagent-transcript-watcher.ts
110596
110456
  import { unwatchFile, watchFile } from "fs";
110597
- import { open as open2 } from "fs/promises";
110457
+ import { open } from "fs/promises";
110598
110458
  import { homedir as homedir9 } from "os";
110599
110459
  import { join as join56 } from "path";
110600
110460
  function computeTranscriptPath(cwd, sessionId, taskId) {
@@ -110775,7 +110635,7 @@ var SubagentTranscriptWatcher = class {
110775
110635
  async #readNewData() {
110776
110636
  let fh = null;
110777
110637
  try {
110778
- fh = await open2(this.#config.transcriptPath, "r");
110638
+ fh = await open(this.#config.transcriptPath, "r");
110779
110639
  const stat15 = await fh.stat();
110780
110640
  if (stat15.size <= this.#bytesRead) return;
110781
110641
  const bytesToRead = stat15.size - this.#bytesRead;
@@ -118359,8 +118219,8 @@ function wireAutoOpenBrowser(connection, signalingClient, authToken, signalingUr
118359
118219
  const webUrl = getWebAppUrl(signalingUrl);
118360
118220
  const url = `${webUrl}?bcode=${encodeURIComponent(code2)}`;
118361
118221
  log.info({ url: webUrl }, "Opening browser");
118362
- const open3 = await import("./open-OYFTLGDC.js");
118363
- await open3.default(url);
118222
+ const open2 = await import("./open-OYFTLGDC.js");
118223
+ await open2.default(url);
118364
118224
  }).catch((err) => {
118365
118225
  log.warn(
118366
118226
  { error: err instanceof Error ? err.message : String(err) },
@@ -119555,4 +119415,4 @@ export {
119555
119415
  decideWorkspaceScope,
119556
119416
  serve
119557
119417
  };
119558
- //# sourceMappingURL=serve-TUBBJN36.js.map
119418
+ //# sourceMappingURL=serve-QENWMCVP.js.map