pi-crew 0.9.55 → 0.9.56

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.mjs CHANGED
@@ -1896,14 +1896,14 @@ function errorPathFromValidation(error) {
1896
1896
  function validateConfigWithWarnings(raw) {
1897
1897
  if (!Value2.Check(PiTeamsConfigSchema, raw)) {
1898
1898
  return [...Value2.Errors(PiTeamsConfigSchema, raw)].map((error) => {
1899
- const path86 = errorPathFromValidation(error);
1899
+ const path87 = errorPathFromValidation(error);
1900
1900
  const message = error.message ?? "invalid value";
1901
1901
  if (error.keyword === "additionalProperties") {
1902
- const offendingKey = path86.split("/").pop() ?? path86;
1902
+ const offendingKey = path87.split("/").pop() ?? path87;
1903
1903
  const suggestion = suggestConfigKey(offendingKey, KNOWN_TOP_LEVEL_KEYS);
1904
- if (suggestion) return `${path86}: ${message} (did you mean '${suggestion}'?)`;
1904
+ if (suggestion) return `${path87}: ${message} (did you mean '${suggestion}'?)`;
1905
1905
  }
1906
- return `${path86}: ${message}`;
1906
+ return `${path87}: ${message}`;
1907
1907
  });
1908
1908
  }
1909
1909
  return [];
@@ -3841,16 +3841,16 @@ function parseGenericGitUrl(url) {
3841
3841
  const { repo: repoWithoutRef, ref } = splitRef(url);
3842
3842
  let repo = repoWithoutRef;
3843
3843
  let host = "";
3844
- let path86 = "";
3844
+ let path87 = "";
3845
3845
  const scpLikeMatch = repoWithoutRef.match(/^git@([^:]+):(.+)$/);
3846
3846
  if (scpLikeMatch) {
3847
3847
  host = scpLikeMatch[1] ?? "";
3848
- path86 = scpLikeMatch[2] ?? "";
3848
+ path87 = scpLikeMatch[2] ?? "";
3849
3849
  } else if (repoWithoutRef.startsWith("https://") || repoWithoutRef.startsWith("http://") || repoWithoutRef.startsWith("ssh://") || repoWithoutRef.startsWith("git://")) {
3850
3850
  try {
3851
3851
  const parsed = new URL(repoWithoutRef);
3852
3852
  host = parsed.hostname;
3853
- path86 = parsed.pathname.replace(/^\/+/, "");
3853
+ path87 = parsed.pathname.replace(/^\/+/, "");
3854
3854
  } catch {
3855
3855
  return null;
3856
3856
  }
@@ -3860,13 +3860,13 @@ function parseGenericGitUrl(url) {
3860
3860
  return null;
3861
3861
  }
3862
3862
  host = repoWithoutRef.slice(0, slashIndex);
3863
- path86 = repoWithoutRef.slice(slashIndex + 1);
3863
+ path87 = repoWithoutRef.slice(slashIndex + 1);
3864
3864
  if (!host.includes(".") && host !== "localhost") {
3865
3865
  return null;
3866
3866
  }
3867
3867
  repo = `https://${repoWithoutRef}`;
3868
3868
  }
3869
- const normalizedPath = path86.replace(/\.git$/, "").replace(/^\/+/, "");
3869
+ const normalizedPath = path87.replace(/\.git$/, "").replace(/^\/+/, "");
3870
3870
  if (!host || !normalizedPath || normalizedPath.split("/").length < 2) {
3871
3871
  return null;
3872
3872
  }
@@ -4207,10 +4207,10 @@ function readWorkflowDir(dir, source) {
4207
4207
  }
4208
4208
  function parseDynamicWorkflowFile(filePath, source) {
4209
4209
  try {
4210
- const basename17 = path11.basename(filePath, ".dwf.ts");
4210
+ const basename18 = path11.basename(filePath, ".dwf.ts");
4211
4211
  return {
4212
- name: basename17,
4213
- description: `Dynamic workflow script (${basename17}.dwf.ts).`,
4212
+ name: basename18,
4213
+ description: `Dynamic workflow script (${basename18}.dwf.ts).`,
4214
4214
  source,
4215
4215
  filePath,
4216
4216
  steps: [],
@@ -5928,7 +5928,18 @@ function isRecord(value) {
5928
5928
  return false;
5929
5929
  return true;
5930
5930
  }
5931
+ function mayContainSecret(value) {
5932
+ for (const m of SECRET_MARKERS_CASE_SENSITIVE) {
5933
+ if (value.includes(m)) return true;
5934
+ }
5935
+ const lower = value.toLowerCase();
5936
+ for (const m of SECRET_MARKERS_LOWER) {
5937
+ if (lower.includes(m)) return true;
5938
+ }
5939
+ return false;
5940
+ }
5931
5941
  function redactSecretString(value) {
5942
+ if (!mayContainSecret(value)) return value;
5932
5943
  let result4 = value;
5933
5944
  if (result4.length <= 2e6) {
5934
5945
  const beginMarkerCount = result4.split("-----BEGIN").length - 1;
@@ -6009,7 +6020,7 @@ function redactJsonLine(line4) {
6009
6020
  return redactSecretString(line4);
6010
6021
  }
6011
6022
  }
6012
- var PEM_PRIVATE_KEY_PATTERN, TOKEN_COUNT_KEYS, JWT_PATTERN, GITHUB_PAT_PATTERN, AWS_ACCESS_KEY_PATTERN, SLACK_TOKEN_PATTERN, GOOGLE_API_KEY_PATTERN, STRIPE_KEY_PATTERN, AUTH_HEADER_BOUNDARY_CHARS;
6023
+ var PEM_PRIVATE_KEY_PATTERN, TOKEN_COUNT_KEYS, JWT_PATTERN, GITHUB_PAT_PATTERN, AWS_ACCESS_KEY_PATTERN, SLACK_TOKEN_PATTERN, GOOGLE_API_KEY_PATTERN, STRIPE_KEY_PATTERN, AUTH_HEADER_BOUNDARY_CHARS, SECRET_MARKERS_CASE_SENSITIVE, SECRET_MARKERS_LOWER;
6013
6024
  var init_redaction = __esm({
6014
6025
  "src/utils/redaction.ts"() {
6015
6026
  "use strict";
@@ -6032,6 +6043,22 @@ var init_redaction = __esm({
6032
6043
  GOOGLE_API_KEY_PATTERN = /(?<![A-Za-z0-9_-])AIza[0-9A-Za-z_-]{35}(?![0-9A-Za-z_-])/g;
6033
6044
  STRIPE_KEY_PATTERN = /(?<![A-Za-z0-9_])sk_live_[0-9a-zA-Z]{24}(?![0-9a-zA-Z])/g;
6034
6045
  AUTH_HEADER_BOUNDARY_CHARS = /* @__PURE__ */ new Set([" ", ",", "{", "[", '"', "\r", "\n", "-", " "]);
6046
+ SECRET_MARKERS_CASE_SENSITIVE = [
6047
+ "-----BEGIN",
6048
+ "eyJ",
6049
+ "AKIA",
6050
+ "AIza",
6051
+ "sk_live_",
6052
+ "xox",
6053
+ // GitHub PAT prefixes (gh[pousr]_) — exact, not the over-broad "gh" which
6054
+ // matched "though"/"highlight"/"might" and defeated the pre-filter skip.
6055
+ "ghp_",
6056
+ "gho_",
6057
+ "ghu_",
6058
+ "ghs_",
6059
+ "ghr_"
6060
+ ];
6061
+ SECRET_MARKERS_LOWER = ["bearer", "authorization", "token", "api", "key", "password", "passwd", "secret", "credential", "private"];
6035
6062
  }
6036
6063
  });
6037
6064
 
@@ -6130,12 +6157,6 @@ function clearHardKillTimer(pid) {
6130
6157
  childHardKillTimers.delete(pid);
6131
6158
  }
6132
6159
  }
6133
- function appendBoundedTail(current, chunk, maxBytes = MAX_CAPTURE_BYTES) {
6134
- return new TailCaptureStage({
6135
- maxBytes,
6136
- marker: `[pi-crew captured output truncated to last ${Math.round(maxBytes / 1024)} KiB]`
6137
- }).apply(current + chunk);
6138
- }
6139
6160
  function spawnTaskkillSafe(pid) {
6140
6161
  try {
6141
6162
  const taskkillChild = spawn("taskkill", ["/pid", String(pid), "/t", "/f"], {
@@ -7036,6 +7057,15 @@ function compactChildPiEvent(event) {
7036
7057
  stopReason: record.stopReason
7037
7058
  };
7038
7059
  }
7060
+ if (record.type === "supervisor_contact" || record.type === "crew_supervisor_contact") {
7061
+ return {
7062
+ type: record.type,
7063
+ taskId: record.taskId,
7064
+ reason: record.reason,
7065
+ message: record.message,
7066
+ data: record.data
7067
+ };
7068
+ }
7039
7069
  return record.type ? { type: record.type } : void 0;
7040
7070
  }
7041
7071
  function displayTextFromCompactEvent(event) {
@@ -7198,6 +7228,67 @@ var init_child_pi_streams = __esm({
7198
7228
  }
7199
7229
  });
7200
7230
 
7231
+ // src/runtime/compact-stages/bounded-tail.ts
7232
+ function defaultMarker(maxBytes) {
7233
+ return `[pi-crew captured output truncated to last ${Math.round(maxBytes / 1024)} KiB]`;
7234
+ }
7235
+ var DEFAULT_MAX_BYTES, BoundedTail;
7236
+ var init_bounded_tail = __esm({
7237
+ "src/runtime/compact-stages/bounded-tail.ts"() {
7238
+ "use strict";
7239
+ init_defaults();
7240
+ DEFAULT_MAX_BYTES = DEFAULT_CHILD_PI.maxCaptureBytes;
7241
+ BoundedTail = class {
7242
+ #maxBytes;
7243
+ #marker;
7244
+ #segs = [];
7245
+ #bytes = 0;
7246
+ #dropped = false;
7247
+ #cached;
7248
+ #dirty = false;
7249
+ constructor(maxBytes = DEFAULT_MAX_BYTES, marker) {
7250
+ if (!(maxBytes > 0)) throw new Error(`BoundedTail: maxBytes must be > 0, got ${maxBytes}`);
7251
+ this.#maxBytes = maxBytes;
7252
+ this.#marker = marker ?? defaultMarker(maxBytes);
7253
+ }
7254
+ /** Append a chunk. O(chunk) amortized; never scans the full buffer. */
7255
+ push(chunk) {
7256
+ if (!chunk) return this;
7257
+ this.#segs.push(chunk);
7258
+ this.#bytes += Buffer.byteLength(chunk, "utf-8");
7259
+ while (this.#bytes > this.#maxBytes && this.#segs.length > 1) {
7260
+ const dropped = this.#segs.shift();
7261
+ this.#bytes -= Buffer.byteLength(dropped, "utf-8");
7262
+ this.#dropped = true;
7263
+ }
7264
+ this.#dirty = true;
7265
+ return this;
7266
+ }
7267
+ /** Materialize the bounded string. Computed at most once per push; cached otherwise. */
7268
+ value() {
7269
+ if (!this.#dirty && this.#cached !== void 0) return this.#cached;
7270
+ const body = this.#segs.join("");
7271
+ const result4 = this.#bound(body);
7272
+ this.#cached = result4;
7273
+ this.#dirty = false;
7274
+ return result4;
7275
+ }
7276
+ /** Byte-exact bound with marker parity vs the old TailCaptureStage path. */
7277
+ #bound(body) {
7278
+ if (Buffer.byteLength(body, "utf-8") <= this.#maxBytes) {
7279
+ return this.#dropped ? `${this.#marker}
7280
+ ${body}` : body;
7281
+ }
7282
+ const buf = Buffer.from(body, "utf-8");
7283
+ let start = Math.max(0, buf.length - this.#maxBytes);
7284
+ while (start < buf.length && (buf[start] & 192) === 128) start++;
7285
+ return `${this.#marker}
7286
+ ${buf.subarray(start).toString("utf-8")}`;
7287
+ }
7288
+ };
7289
+ }
7290
+ });
7291
+
7201
7292
  // src/runtime/crash-classification.ts
7202
7293
  function detectNativePanic(stderrSnippet) {
7203
7294
  if (!stderrSnippet) return null;
@@ -7585,8 +7676,8 @@ ${JSON.stringify({ type: "message_end", usage: { input: 10, output: 5, cost: 1e-
7585
7676
  ts: (/* @__PURE__ */ new Date()).toISOString()
7586
7677
  });
7587
7678
  }
7588
- let stdout = "";
7589
- let stderr = "";
7679
+ const stdoutTail = new BoundedTail();
7680
+ const stderrTail = new BoundedTail();
7590
7681
  let settled = false;
7591
7682
  let childExited = false;
7592
7683
  let postExitGuardCleanup;
@@ -7644,6 +7735,7 @@ ${JSON.stringify({ type: "message_end", usage: { input: 10, output: 5, cost: 1e-
7644
7735
  if (noResponseTimer) clearTimeout(noResponseTimer);
7645
7736
  noResponseTimer = setTimeout(() => {
7646
7737
  responseTimeoutHit = true;
7738
+ const stderr = stderrTail.value();
7647
7739
  const timeoutStderr = redactStderrExcerpt(stderr, 1024);
7648
7740
  input.onLifecycleEvent?.({
7649
7741
  type: "response_timeout",
@@ -7671,8 +7763,8 @@ ${JSON.stringify({ type: "message_end", usage: { input: 10, output: 5, cost: 1e-
7671
7763
  const timeoutErr = `Child Pi produced no new output for ${responseTimeoutMs}ms; killed but did not exit within ${SAFETY_SETTLE_MS}ms (possible zombie).`;
7672
7764
  void settle({
7673
7765
  exitCode: null,
7674
- stdout,
7675
- stderr,
7766
+ stdout: stdoutTail.value(),
7767
+ stderr: stderrTail.value(),
7676
7768
  error: timeoutErr,
7677
7769
  exitStatus: {
7678
7770
  exitCode: null,
@@ -7700,7 +7792,7 @@ ${JSON.stringify({ type: "message_end", usage: { input: 10, output: 5, cost: 1e-
7700
7792
  ...input,
7701
7793
  onStdoutLine: (line4) => {
7702
7794
  if (!steeringController.isHardAbortInitiated()) restartNoResponseTimer();
7703
- stdout = appendBoundedTail(stdout, `${line4}
7795
+ stdoutTail.push(`${line4}
7704
7796
  `);
7705
7797
  input.onStdoutLine?.(line4);
7706
7798
  },
@@ -7957,9 +8049,11 @@ ${JSON.stringify({ type: "message_end", usage: { input: 10, output: 5, cost: 1e-
7957
8049
  });
7958
8050
  child.stderr?.on("data", (chunk) => {
7959
8051
  if (!steeringController.isHardAbortInitiated()) restartNoResponseTimer();
7960
- stderr = appendBoundedTail(stderr, chunk.toString("utf-8"));
8052
+ stderrTail.push(chunk.toString("utf-8"));
7961
8053
  });
7962
8054
  child.on("error", (error) => {
8055
+ const stdout = stdoutTail.value();
8056
+ const stderr = stderrTail.value();
7963
8057
  const processError = new Error(
7964
8058
  `Child Pi process error: ${error.message}. Stderr: ${redactStderrExcerpt(stderr, 500) || "(none)"}`
7965
8059
  );
@@ -7998,6 +8092,7 @@ ${JSON.stringify({ type: "message_end", usage: { input: 10, output: 5, cost: 1e-
7998
8092
  });
7999
8093
  });
8000
8094
  child.on("exit", (code, signal) => {
8095
+ const stderr = stderrTail.value();
8001
8096
  if (child.pid) {
8002
8097
  unregisterActiveChild(child.pid);
8003
8098
  clearHardKillTimer(child.pid);
@@ -8045,6 +8140,8 @@ ${JSON.stringify({ type: "message_end", usage: { input: 10, output: 5, cost: 1e-
8045
8140
  }
8046
8141
  });
8047
8142
  child.on("close", (exitCode) => {
8143
+ const stdout = stdoutTail.value();
8144
+ const stderr = stderrTail.value();
8048
8145
  if (child.pid) {
8049
8146
  unregisterActiveChild(child.pid);
8050
8147
  clearHardKillTimer(child.pid);
@@ -8125,6 +8222,7 @@ var init_child_pi = __esm({
8125
8222
  init_child_pi_spawn();
8126
8223
  init_child_pi_steering();
8127
8224
  init_child_pi_streams();
8225
+ init_bounded_tail();
8128
8226
  init_child_pi_kill();
8129
8227
  init_child_pi_spawn();
8130
8228
  init_child_pi_streams();
@@ -8307,14 +8405,28 @@ function safeAgentTaskId(taskId) {
8307
8405
  function agentStateDir(manifest, taskId) {
8308
8406
  return path19.join(agentsRoot(manifest), safeAgentTaskId(taskId));
8309
8407
  }
8408
+ function bumpAgentPathCache() {
8409
+ if (ensuredAgentDirs.size > AGENT_PATH_CACHE_MAX) {
8410
+ const oldest = ensuredAgentDirs.keys().next().value;
8411
+ if (oldest !== void 0) ensuredAgentDirs.delete(oldest);
8412
+ }
8413
+ if (resolvedAgentFiles.size > AGENT_PATH_CACHE_MAX) {
8414
+ const oldest = resolvedAgentFiles.keys().next().value;
8415
+ if (oldest !== void 0) resolvedAgentFiles.delete(oldest);
8416
+ }
8417
+ }
8310
8418
  function ensureAgentStateDir(manifest, taskId) {
8311
8419
  const root = agentsRoot(manifest);
8420
+ const dir = agentStateDir(manifest, taskId);
8421
+ const cachedDir = ensuredAgentDirs.get(dir);
8422
+ if (cachedDir !== void 0) return cachedDir;
8312
8423
  fs22.mkdirSync(root, { recursive: true });
8313
8424
  if (fs22.lstatSync(root).isSymbolicLink()) throw new Error(`Invalid agents root: ${root}`);
8314
- const dir = agentStateDir(manifest, taskId);
8315
8425
  fs22.mkdirSync(dir, { recursive: true });
8316
8426
  if (fs22.lstatSync(dir).isSymbolicLink()) throw new Error(`Invalid agent state directory: ${dir}`);
8317
8427
  resolveRealContainedPath(root, path19.basename(dir));
8428
+ ensuredAgentDirs.set(dir, dir);
8429
+ bumpAgentPathCache();
8318
8430
  return dir;
8319
8431
  }
8320
8432
  function safeExistingAgentFile(manifest, taskId, fileName) {
@@ -8324,8 +8436,15 @@ function safeExistingAgentFile(manifest, taskId, fileName) {
8324
8436
  return resolveRealContainedPath(agentsRoot(manifest), path19.join(safeAgentTaskId(taskId), fileName));
8325
8437
  }
8326
8438
  function agentStateFile(manifest, taskId, fileName) {
8439
+ const dir = agentStateDir(manifest, taskId);
8440
+ const cacheKey2 = `${dir}\0${fileName}`;
8441
+ const cached = resolvedAgentFiles.get(cacheKey2);
8442
+ if (cached !== void 0) return cached;
8327
8443
  ensureAgentStateDir(manifest, taskId);
8328
- return safeExistingAgentFile(manifest, taskId, fileName);
8444
+ const resolved = safeExistingAgentFile(manifest, taskId, fileName);
8445
+ resolvedAgentFiles.set(cacheKey2, resolved);
8446
+ bumpAgentPathCache();
8447
+ return resolved;
8329
8448
  }
8330
8449
  function agentStatusPath(manifest, taskId) {
8331
8450
  return path19.join(agentStateDir(manifest, taskId), "status.json");
@@ -8486,6 +8605,7 @@ async function readCrewAgentsAsync(manifest) {
8486
8605
  return inFlight;
8487
8606
  }
8488
8607
  function saveCrewAgents(manifest, records) {
8608
+ flushPendingAgentWrites();
8489
8609
  withAgentsLock(manifest, () => {
8490
8610
  fs22.mkdirSync(manifest.stateRoot, { recursive: true });
8491
8611
  const filePath = agentsPath(manifest);
@@ -8560,6 +8680,9 @@ function writeCrewAgentStatusCoalesced(manifest, record) {
8560
8680
  durability: "best-effort"
8561
8681
  });
8562
8682
  }
8683
+ function flushPendingAgentWrites() {
8684
+ flushPendingAtomicWrites();
8685
+ }
8563
8686
  function readCrewAgentStatus(manifest, taskOrAgentId) {
8564
8687
  try {
8565
8688
  return readJsonFile(safeExistingAgentFile(manifest, taskOrAgentId, "status.json"));
@@ -8739,7 +8862,7 @@ function recordFromTask(manifest, task, runtime) {
8739
8862
  error: task.error
8740
8863
  };
8741
8864
  }
8742
- var AGENT_READER_TTL_MS, ASYNC_AGENT_READER_CACHE_MAX_ENTRIES, AGENTS_LOCK_STALE_MS, asyncAgentReaderCache, TERMINAL_AGENT_STATUSES, AGENT_COALESCE_MS, agentEventSeqCache, AGENT_EVENT_SEQ_CACHE_MAX_ENTRIES, AGENT_EVENT_SEQ_SIDECAR;
8865
+ var ensuredAgentDirs, resolvedAgentFiles, AGENT_PATH_CACHE_MAX, AGENT_READER_TTL_MS, ASYNC_AGENT_READER_CACHE_MAX_ENTRIES, AGENTS_LOCK_STALE_MS, asyncAgentReaderCache, TERMINAL_AGENT_STATUSES, AGENT_COALESCE_MS, agentEventSeqCache, AGENT_EVENT_SEQ_CACHE_MAX_ENTRIES, AGENT_EVENT_SEQ_SIDECAR;
8743
8866
  var init_crew_agent_records = __esm({
8744
8867
  "src/runtime/crew-agent-records.ts"() {
8745
8868
  "use strict";
@@ -8750,6 +8873,9 @@ var init_crew_agent_records = __esm({
8750
8873
  init_safe_paths();
8751
8874
  init_sleep();
8752
8875
  init_crew_agent_runtime();
8876
+ ensuredAgentDirs = /* @__PURE__ */ new Map();
8877
+ resolvedAgentFiles = /* @__PURE__ */ new Map();
8878
+ AGENT_PATH_CACHE_MAX = 512;
8753
8879
  AGENT_READER_TTL_MS = 200;
8754
8880
  ASYNC_AGENT_READER_CACHE_MAX_ENTRIES = 128;
8755
8881
  AGENTS_LOCK_STALE_MS = 3e4;
@@ -8843,13 +8969,13 @@ var init_errors = __esm({
8843
8969
  }
8844
8970
  };
8845
8971
  errors = {
8846
- fileRead(path86, source) {
8847
- return new CrewError(ErrorCode.FileReadError, `Failed to read ${path86}: ${source.code?.toLowerCase() ?? "unknown"}`).withContext(
8972
+ fileRead(path87, source) {
8973
+ return new CrewError(ErrorCode.FileReadError, `Failed to read ${path87}: ${source.code?.toLowerCase() ?? "unknown"}`).withContext(
8848
8974
  "file system read operation"
8849
8975
  );
8850
8976
  },
8851
- fileWrite(path86, source) {
8852
- return new CrewError(ErrorCode.FileWriteError, `Failed to write ${path86}: ${source.code?.toLowerCase() ?? "unknown"}`).withContext(
8977
+ fileWrite(path87, source) {
8978
+ return new CrewError(ErrorCode.FileWriteError, `Failed to write ${path87}: ${source.code?.toLowerCase() ?? "unknown"}`).withContext(
8853
8979
  "file system write operation"
8854
8980
  );
8855
8981
  },
@@ -8919,6 +9045,88 @@ var init_errors = __esm({
8919
9045
  }
8920
9046
  });
8921
9047
 
9048
+ // src/utils/task-name-generator.ts
9049
+ var init_task_name_generator = __esm({
9050
+ "src/utils/task-name-generator.ts"() {
9051
+ "use strict";
9052
+ }
9053
+ });
9054
+
9055
+ // src/utils/ids.ts
9056
+ import { randomBytes } from "node:crypto";
9057
+ function createRunId(prefix = "team") {
9058
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
9059
+ const suffix = randomBytes(8).toString("hex");
9060
+ return `${prefix}_${stamp}_${suffix}`;
9061
+ }
9062
+ function createTaskId(stepId, index) {
9063
+ const normalized = stepId.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "task";
9064
+ return `${String(index + 1).padStart(2, "0")}_${normalized}`;
9065
+ }
9066
+ var init_ids = __esm({
9067
+ "src/utils/ids.ts"() {
9068
+ "use strict";
9069
+ init_task_name_generator();
9070
+ }
9071
+ });
9072
+
9073
+ // src/state/contracts.ts
9074
+ function isTeamRunStatus(value) {
9075
+ return typeof value === "string" && TEAM_RUN_STATUSES.includes(value);
9076
+ }
9077
+ function isTeamTaskStatus(value) {
9078
+ return typeof value === "string" && TEAM_TASK_STATUSES.includes(value);
9079
+ }
9080
+ function canTransitionRunStatus(from, to) {
9081
+ return from === to || (TEAM_RUN_STATUS_TRANSITIONS[from]?.includes(to) ?? false);
9082
+ }
9083
+ function canTransitionTaskStatus(from, to) {
9084
+ return from === to || (TEAM_TASK_STATUS_TRANSITIONS[from]?.includes(to) ?? false);
9085
+ }
9086
+ var TEAM_RUN_STATUSES, TEAM_TASK_STATUSES, TEAM_TERMINAL_TASK_STATUSES, TEAM_RUN_STATUS_TRANSITIONS, TEAM_TASK_STATUS_TRANSITIONS;
9087
+ var init_contracts = __esm({
9088
+ "src/state/contracts.ts"() {
9089
+ "use strict";
9090
+ TEAM_RUN_STATUSES = ["queued", "planning", "running", "blocked", "completed", "failed", "cancelled"];
9091
+ TEAM_TASK_STATUSES = [
9092
+ "queued",
9093
+ "running",
9094
+ "waiting",
9095
+ "completed",
9096
+ "failed",
9097
+ "cancelled",
9098
+ "skipped",
9099
+ "needs_attention"
9100
+ ];
9101
+ TEAM_TERMINAL_TASK_STATUSES = /* @__PURE__ */ new Set([
9102
+ "completed",
9103
+ "failed",
9104
+ "cancelled",
9105
+ "skipped",
9106
+ "needs_attention"
9107
+ ]);
9108
+ TEAM_RUN_STATUS_TRANSITIONS = {
9109
+ queued: ["planning", "running", "cancelled", "failed"],
9110
+ planning: ["running", "blocked", "cancelled", "failed"],
9111
+ running: ["blocked", "completed", "failed", "cancelled"],
9112
+ blocked: ["running", "cancelled", "failed"],
9113
+ completed: ["running", "cancelled"],
9114
+ failed: ["running", "cancelled"],
9115
+ cancelled: ["running"]
9116
+ };
9117
+ TEAM_TASK_STATUS_TRANSITIONS = {
9118
+ queued: ["running", "cancelled", "skipped", "failed"],
9119
+ running: ["completed", "failed", "cancelled", "queued", "waiting"],
9120
+ waiting: ["running", "queued", "completed", "failed", "cancelled"],
9121
+ completed: ["queued"],
9122
+ failed: ["queued", "cancelled"],
9123
+ cancelled: ["queued"],
9124
+ skipped: ["queued", "cancelled"],
9125
+ needs_attention: ["queued", "running"]
9126
+ };
9127
+ }
9128
+ });
9129
+
8922
9130
  // src/ui/run-event-bus.ts
8923
9131
  function classifyEventChannel(type) {
8924
9132
  if (WORKER_PROGRESS_TYPES.has(type)) return "worker:progress";
@@ -9343,6 +9551,7 @@ var init_incremental_reader = __esm({
9343
9551
 
9344
9552
  // src/state/event-log-rotation.ts
9345
9553
  import * as fs24 from "node:fs";
9554
+ import * as path20 from "node:path";
9346
9555
  function resolveConfig(config) {
9347
9556
  return { ...DEFAULT_ROTATION_CONFIG, ...config };
9348
9557
  }
@@ -9443,6 +9652,26 @@ function bumpGenerationUnlocked(eventsPath) {
9443
9652
  }
9444
9653
  return next;
9445
9654
  }
9655
+ function sweepOldArchives(eventsPath, now = Date.now()) {
9656
+ const dir = path20.dirname(eventsPath);
9657
+ const base = path20.basename(eventsPath);
9658
+ let entries;
9659
+ try {
9660
+ entries = fs24.readdirSync(dir);
9661
+ } catch {
9662
+ return;
9663
+ }
9664
+ const cutoff = now - ARCHIVE_RETENTION_DAYS * 24 * 60 * 60 * 1e3;
9665
+ for (const name of entries) {
9666
+ if (!name.startsWith(`${base}.`) || !name.endsWith(".archive.jsonl")) continue;
9667
+ const archivePath = path20.join(dir, name);
9668
+ try {
9669
+ if (fs24.statSync(archivePath).mtimeMs < cutoff) fs24.unlinkSync(archivePath);
9670
+ } catch (error) {
9671
+ logInternalError("event-log.archive-sweep", error, `archivePath=${archivePath}`, "debug");
9672
+ }
9673
+ }
9674
+ }
9446
9675
  function rotateEventLogUnlocked(eventsPath) {
9447
9676
  if (!fs24.existsSync(eventsPath)) return false;
9448
9677
  try {
@@ -9456,13 +9685,14 @@ function rotateEventLogUnlocked(eventsPath) {
9456
9685
  fs24.copyFileSync(eventsPath, archivePath);
9457
9686
  atomicWriteFile(eventsPath, "");
9458
9687
  bumpGenerationUnlocked(eventsPath);
9688
+ sweepOldArchives(eventsPath);
9459
9689
  return true;
9460
9690
  } catch (error) {
9461
9691
  logInternalError("event-log.rotate", error, `eventsPath=${eventsPath}`);
9462
9692
  return false;
9463
9693
  }
9464
9694
  }
9465
- var DEFAULT_ROTATION_CONFIG, AVG_BYTES_PER_EVENT;
9695
+ var DEFAULT_ROTATION_CONFIG, AVG_BYTES_PER_EVENT, ARCHIVE_RETENTION_DAYS;
9466
9696
  var init_event_log_rotation = __esm({
9467
9697
  "src/state/event-log-rotation.ts"() {
9468
9698
  "use strict";
@@ -9478,6 +9708,7 @@ var init_event_log_rotation = __esm({
9478
9708
  compactToCount: 1e3
9479
9709
  };
9480
9710
  AVG_BYTES_PER_EVENT = 80;
9711
+ ARCHIVE_RETENTION_DAYS = 7;
9481
9712
  }
9482
9713
  });
9483
9714
 
@@ -9505,15 +9736,26 @@ __export(event_log_exports, {
9505
9736
  resetEventLogMode: () => resetEventLogMode,
9506
9737
  scanSequence: () => scanSequence,
9507
9738
  sequencePath: () => sequencePath,
9739
+ tickAppendCounter: () => tickAppendCounter,
9508
9740
  withEventLogLockSync: () => withEventLogLockSync
9509
9741
  });
9510
9742
  import { createHash as createHash2 } from "node:crypto";
9511
9743
  import * as fs25 from "node:fs";
9512
- import * as path20 from "node:path";
9744
+ import * as path21 from "node:path";
9745
+ function tickAppendCounter(eventsPath, inc = 1) {
9746
+ const prev = appendCounters.get(eventsPath) ?? 0;
9747
+ const next = prev + inc;
9748
+ appendCounters.set(eventsPath, next);
9749
+ if (appendCounters.size > APPEND_COUNTER_MAX_ENTRIES) {
9750
+ const oldest = appendCounters.keys().next().value;
9751
+ if (oldest !== void 0) appendCounters.delete(oldest);
9752
+ }
9753
+ return Math.floor(next / 100) > Math.floor(prev / 100);
9754
+ }
9513
9755
  function withEventLogLockSync(eventsPath, fn, options) {
9514
- fs25.mkdirSync(path20.dirname(eventsPath), { recursive: true });
9756
+ fs25.mkdirSync(path21.dirname(eventsPath), { recursive: true });
9515
9757
  const lockDir = `${eventsPath}.mkdirlock`;
9516
- const pidFile = path20.join(lockDir, "pid");
9758
+ const pidFile = path21.join(lockDir, "pid");
9517
9759
  const start = Date.now();
9518
9760
  const timeout = options?.timeoutMs ?? 5e3;
9519
9761
  const staleMs = options?.staleMs ?? 1e4;
@@ -9664,7 +9906,7 @@ function nextSequence(eventsPath) {
9664
9906
  }
9665
9907
  function persistSequence(eventsPath, seq) {
9666
9908
  try {
9667
- atomicWriteFile(sequencePath(eventsPath), String(seq));
9909
+ atomicWriteFile(sequencePath(eventsPath), String(seq), { durability: "best-effort" });
9668
9910
  } catch (error) {
9669
9911
  logInternalError("event-log.persist-sequence-file", error, `eventsPath=${eventsPath}`);
9670
9912
  }
@@ -9731,9 +9973,9 @@ async function withEventLogLockAsync(eventsPath, fn, options) {
9731
9973
  () => void 0
9732
9974
  );
9733
9975
  const next = prev.then(async () => {
9734
- await fs25.promises.mkdir(path20.dirname(eventsPath), { recursive: true });
9976
+ await fs25.promises.mkdir(path21.dirname(eventsPath), { recursive: true });
9735
9977
  const lockDir = `${eventsPath}.alock`;
9736
- const pidFile = path20.join(lockDir, "pid");
9978
+ const pidFile = path21.join(lockDir, "pid");
9737
9979
  const timeout = options?.timeoutMs ?? 5e3;
9738
9980
  const staleMs = options?.staleMs ?? 1e4;
9739
9981
  const start = Date.now();
@@ -9742,7 +9984,7 @@ async function withEventLogLockAsync(eventsPath, fn, options) {
9742
9984
  try {
9743
9985
  await fs25.promises.mkdir(lockDir);
9744
9986
  try {
9745
- atomicWriteFile(pidFile, String(process.pid));
9987
+ atomicWriteFile(pidFile, String(process.pid), { durability: "best-effort" });
9746
9988
  } catch {
9747
9989
  }
9748
9990
  acquired = true;
@@ -9893,17 +10135,19 @@ async function appendEventAsync(eventsPath, event) {
9893
10135
  const line4 = JSON.stringify(redactSecrets(fullEvent)) + "\n";
9894
10136
  if (isWorkerAtomicWriterEnabled()) {
9895
10137
  await appendFileViaWorker(eventsPath, line4);
9896
- const fd = await fs25.promises.open(eventsPath, "r+");
9897
- try {
9898
- await fd.sync();
9899
- } finally {
9900
- await fd.close();
10138
+ if (isTerminal) {
10139
+ const fd = await fs25.promises.open(eventsPath, "r+");
10140
+ try {
10141
+ await fd.sync();
10142
+ } finally {
10143
+ await fd.close();
10144
+ }
9901
10145
  }
9902
10146
  } else {
9903
10147
  const fd = await fs25.promises.open(eventsPath, "a");
9904
10148
  try {
9905
10149
  await fd.appendFile(line4, "utf-8");
9906
- await fd.sync();
10150
+ if (isTerminal) await fd.sync();
9907
10151
  try {
9908
10152
  postAppendStat = await fd.stat();
9909
10153
  } catch {
@@ -9916,7 +10160,7 @@ async function appendEventAsync(eventsPath, event) {
9916
10160
  persistSequence(eventsPath, seq);
9917
10161
  }
9918
10162
  let compactedAfterAppend = false;
9919
- if (appendCounter % 100 === 0 && needsRotation(eventsPath)) {
10163
+ if (tickAppendCounter(eventsPath) && needsRotation(eventsPath)) {
9920
10164
  compactedAfterAppend = true;
9921
10165
  try {
9922
10166
  const prepared = prepareCompaction(eventsPath);
@@ -9959,7 +10203,7 @@ async function appendEventAsync(eventsPath, event) {
9959
10203
  };
9960
10204
  const prev = asyncQueues.get(queueKey) ?? Promise.resolve();
9961
10205
  const next = prev.then(async () => {
9962
- await fs25.promises.mkdir(path20.dirname(eventsPath), { recursive: true });
10206
+ await fs25.promises.mkdir(path21.dirname(eventsPath), { recursive: true });
9963
10207
  return withEventLogLockAsync(eventsPath, doAppendUnderLock);
9964
10208
  });
9965
10209
  const tail = next.then(
@@ -9981,7 +10225,8 @@ async function appendEventAsync(eventsPath, event) {
9981
10225
  }
9982
10226
  async function appendEventBatchInsideLock(eventsPath, queue) {
9983
10227
  if (queue.length === 0) return;
9984
- fs25.mkdirSync(path20.dirname(eventsPath), { recursive: true });
10228
+ tickAppendCounter(eventsPath, queue.length);
10229
+ fs25.mkdirSync(path21.dirname(eventsPath), { recursive: true });
9985
10230
  try {
9986
10231
  if (fs25.existsSync(eventsPath)) {
9987
10232
  const stat2 = fs25.statSync(eventsPath);
@@ -10076,7 +10321,7 @@ async function appendEventBatchInsideLock(eventsPath, queue) {
10076
10321
  for (const { item, fullEvent } of finalized) item.resolve(fullEvent);
10077
10322
  }
10078
10323
  function appendEventInsideLock(eventsPath, event) {
10079
- fs25.mkdirSync(path20.dirname(eventsPath), { recursive: true });
10324
+ fs25.mkdirSync(path21.dirname(eventsPath), { recursive: true });
10080
10325
  const baseMetadata = event.metadata;
10081
10326
  const explicitSeq = baseMetadata?.seq;
10082
10327
  const seq = explicitSeq ?? reserveSequence(eventsPath);
@@ -10165,8 +10410,7 @@ function appendEventInsideLock(eventsPath, event) {
10165
10410
  logInternalError("event-log.persist-sequence", error, `eventsPath=${eventsPath}`);
10166
10411
  }
10167
10412
  }
10168
- appendCounter++;
10169
- if (appendCounter % 100 === 0 && needsRotation(eventsPath)) {
10413
+ if (tickAppendCounter(eventsPath) && needsRotation(eventsPath)) {
10170
10414
  try {
10171
10415
  const prepared = prepareCompaction(eventsPath);
10172
10416
  if (prepared) applyCompactionUnlocked(eventsPath, prepared);
@@ -10329,7 +10573,7 @@ function dedupeTerminalEvents(events) {
10329
10573
  }
10330
10574
  return output;
10331
10575
  }
10332
- var TERMINAL_EVENT_TYPES, MAX_EVENTS_BYTES, sequenceCache, MAX_SEQUENCE_CACHE_ENTRIES, appendCounter, overflowCounter, MAX_SEQUENCE_CACHE_ENTRIES_VALUE, seqCounters, asyncQueues, asyncLocks, bufferedQueues, bufferedTimers, DEFAULT_BUFFER_MS;
10576
+ var TERMINAL_EVENT_TYPES, MAX_EVENTS_BYTES, sequenceCache, MAX_SEQUENCE_CACHE_ENTRIES, appendCounters, APPEND_COUNTER_MAX_ENTRIES, overflowCounter, MAX_SEQUENCE_CACHE_ENTRIES_VALUE, seqCounters, asyncQueues, asyncLocks, bufferedQueues, bufferedTimers, DEFAULT_BUFFER_MS;
10333
10577
  var init_event_log = __esm({
10334
10578
  "src/state/event-log.ts"() {
10335
10579
  "use strict";
@@ -10347,7 +10591,8 @@ var init_event_log = __esm({
10347
10591
  MAX_EVENTS_BYTES = 50 * 1024 * 1024;
10348
10592
  sequenceCache = /* @__PURE__ */ new Map();
10349
10593
  MAX_SEQUENCE_CACHE_ENTRIES = 256;
10350
- appendCounter = 0;
10594
+ appendCounters = /* @__PURE__ */ new Map();
10595
+ APPEND_COUNTER_MAX_ENTRIES = 256;
10351
10596
  overflowCounter = 0;
10352
10597
  MAX_SEQUENCE_CACHE_ENTRIES_VALUE = MAX_SEQUENCE_CACHE_ENTRIES;
10353
10598
  seqCounters = /* @__PURE__ */ new Map();
@@ -10384,88 +10629,6 @@ var init_event_log = __esm({
10384
10629
  }
10385
10630
  });
10386
10631
 
10387
- // src/utils/task-name-generator.ts
10388
- var init_task_name_generator = __esm({
10389
- "src/utils/task-name-generator.ts"() {
10390
- "use strict";
10391
- }
10392
- });
10393
-
10394
- // src/utils/ids.ts
10395
- import { randomBytes } from "node:crypto";
10396
- function createRunId(prefix = "team") {
10397
- const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
10398
- const suffix = randomBytes(8).toString("hex");
10399
- return `${prefix}_${stamp}_${suffix}`;
10400
- }
10401
- function createTaskId(stepId, index) {
10402
- const normalized = stepId.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "task";
10403
- return `${String(index + 1).padStart(2, "0")}_${normalized}`;
10404
- }
10405
- var init_ids = __esm({
10406
- "src/utils/ids.ts"() {
10407
- "use strict";
10408
- init_task_name_generator();
10409
- }
10410
- });
10411
-
10412
- // src/state/contracts.ts
10413
- function isTeamRunStatus(value) {
10414
- return typeof value === "string" && TEAM_RUN_STATUSES.includes(value);
10415
- }
10416
- function isTeamTaskStatus(value) {
10417
- return typeof value === "string" && TEAM_TASK_STATUSES.includes(value);
10418
- }
10419
- function canTransitionRunStatus(from, to) {
10420
- return from === to || (TEAM_RUN_STATUS_TRANSITIONS[from]?.includes(to) ?? false);
10421
- }
10422
- function canTransitionTaskStatus(from, to) {
10423
- return from === to || (TEAM_TASK_STATUS_TRANSITIONS[from]?.includes(to) ?? false);
10424
- }
10425
- var TEAM_RUN_STATUSES, TEAM_TASK_STATUSES, TEAM_TERMINAL_TASK_STATUSES, TEAM_RUN_STATUS_TRANSITIONS, TEAM_TASK_STATUS_TRANSITIONS;
10426
- var init_contracts = __esm({
10427
- "src/state/contracts.ts"() {
10428
- "use strict";
10429
- TEAM_RUN_STATUSES = ["queued", "planning", "running", "blocked", "completed", "failed", "cancelled"];
10430
- TEAM_TASK_STATUSES = [
10431
- "queued",
10432
- "running",
10433
- "waiting",
10434
- "completed",
10435
- "failed",
10436
- "cancelled",
10437
- "skipped",
10438
- "needs_attention"
10439
- ];
10440
- TEAM_TERMINAL_TASK_STATUSES = /* @__PURE__ */ new Set([
10441
- "completed",
10442
- "failed",
10443
- "cancelled",
10444
- "skipped",
10445
- "needs_attention"
10446
- ]);
10447
- TEAM_RUN_STATUS_TRANSITIONS = {
10448
- queued: ["planning", "running", "cancelled", "failed"],
10449
- planning: ["running", "blocked", "cancelled", "failed"],
10450
- running: ["blocked", "completed", "failed", "cancelled"],
10451
- blocked: ["running", "cancelled", "failed"],
10452
- completed: ["running", "cancelled"],
10453
- failed: ["running", "cancelled"],
10454
- cancelled: ["running"]
10455
- };
10456
- TEAM_TASK_STATUS_TRANSITIONS = {
10457
- queued: ["running", "cancelled", "skipped", "failed"],
10458
- running: ["completed", "failed", "cancelled", "queued", "waiting"],
10459
- waiting: ["running", "queued", "completed", "failed", "cancelled"],
10460
- completed: ["queued"],
10461
- failed: ["queued", "cancelled"],
10462
- cancelled: ["queued"],
10463
- skipped: ["queued", "cancelled"],
10464
- needs_attention: ["queued", "running"]
10465
- };
10466
- }
10467
- });
10468
-
10469
10632
  // src/state/types.ts
10470
10633
  var CURRENT_SCHEMA_VERSION;
10471
10634
  var init_types = __esm({
@@ -10499,7 +10662,7 @@ __export(state_store_exports, {
10499
10662
  });
10500
10663
  import * as fs26 from "node:fs";
10501
10664
  import * as fsp from "node:fs/promises";
10502
- import * as path21 from "node:path";
10665
+ import * as path22 from "node:path";
10503
10666
  function statManifestWithWindowsRetry(manifestPath) {
10504
10667
  if (process.platform !== "win32") return fs26.statSync(manifestPath);
10505
10668
  const retryable = /* @__PURE__ */ new Set(["ENOENT", "EPERM", "EBUSY", "EAGAIN"]);
@@ -10562,20 +10725,29 @@ function scopeBaseRoot(cwd) {
10562
10725
  }
10563
10726
  function resolveRunStateRoot(cwd, runId) {
10564
10727
  assertSafePathId("runId", runId);
10565
- const runsRoot = path21.join(scopeBaseRoot(cwd), DEFAULT_PATHS.state.runsSubdir);
10728
+ const key = `${cwd}\0${runId}`;
10729
+ const now = Date.now();
10730
+ const cached = runStateRootCache.get(key);
10731
+ if (cached && cached.expiresAt > now) return cached.root;
10732
+ const runsRoot = path22.join(scopeBaseRoot(cwd), DEFAULT_PATHS.state.runsSubdir);
10566
10733
  const scopedPath = resolveContainedRelativePath(runsRoot, runId, "runId");
10567
10734
  try {
10568
10735
  resolveRealContainedPath(runsRoot, runId);
10569
10736
  } catch {
10570
10737
  return void 0;
10571
10738
  }
10739
+ if (runStateRootCache.size >= RUN_STATE_ROOT_CACHE_MAX) {
10740
+ const oldest = runStateRootCache.keys().next().value;
10741
+ if (oldest !== void 0) runStateRootCache.delete(oldest);
10742
+ }
10743
+ runStateRootCache.set(key, { root: scopedPath, expiresAt: now + RUN_STATE_ROOT_TTL_MS });
10572
10744
  return scopedPath;
10573
10745
  }
10574
10746
  function validateRunManifestPaths(cwd, runId, manifest, stateRoot, tasksPath) {
10575
10747
  if (!manifest.status || typeof manifest.status !== "string") return false;
10576
- if (manifest.runId !== runId || manifest.stateRoot !== stateRoot || manifest.tasksPath !== tasksPath || manifest.eventsPath !== path21.join(stateRoot, "events.jsonl"))
10748
+ if (manifest.runId !== runId || manifest.stateRoot !== stateRoot || manifest.tasksPath !== tasksPath || manifest.eventsPath !== path22.join(stateRoot, "events.jsonl"))
10577
10749
  return false;
10578
- const artifactsParent = path21.join(scopeBaseRoot(cwd), DEFAULT_PATHS.state.artifactsSubdir);
10750
+ const artifactsParent = path22.join(scopeBaseRoot(cwd), DEFAULT_PATHS.state.artifactsSubdir);
10579
10751
  const expectedArtifactsRoot = resolveContainedRelativePath(artifactsParent, runId, "runId");
10580
10752
  if (manifest.artifactsRoot !== expectedArtifactsRoot) return false;
10581
10753
  if (fs26.existsSync(expectedArtifactsRoot)) {
@@ -10596,15 +10768,15 @@ function createRunPaths(cwd, runId = createRunId()) {
10596
10768
  }
10597
10769
  assertSafePathId("runId", runId);
10598
10770
  const baseRoot = scopeBaseRoot(cwd);
10599
- const stateRoot = resolveContainedRelativePath(path21.join(baseRoot, DEFAULT_PATHS.state.runsSubdir), runId, "runId");
10600
- const artifactsRoot = resolveContainedRelativePath(path21.join(baseRoot, DEFAULT_PATHS.state.artifactsSubdir), runId, "runId");
10771
+ const stateRoot = resolveContainedRelativePath(path22.join(baseRoot, DEFAULT_PATHS.state.runsSubdir), runId, "runId");
10772
+ const artifactsRoot = resolveContainedRelativePath(path22.join(baseRoot, DEFAULT_PATHS.state.artifactsSubdir), runId, "runId");
10601
10773
  return {
10602
10774
  runId,
10603
10775
  stateRoot,
10604
10776
  artifactsRoot,
10605
- manifestPath: path21.join(stateRoot, DEFAULT_PATHS.state.manifestFile),
10606
- tasksPath: path21.join(stateRoot, DEFAULT_PATHS.state.tasksFile),
10607
- eventsPath: path21.join(stateRoot, DEFAULT_PATHS.state.eventsFile)
10777
+ manifestPath: path22.join(stateRoot, DEFAULT_PATHS.state.manifestFile),
10778
+ tasksPath: path22.join(stateRoot, DEFAULT_PATHS.state.tasksFile),
10779
+ eventsPath: path22.join(stateRoot, DEFAULT_PATHS.state.eventsFile)
10608
10780
  };
10609
10781
  }
10610
10782
  function createTasksFromWorkflow(runId, workflow, team, cwd) {
@@ -10700,7 +10872,7 @@ function saveRunManifest(manifest) {
10700
10872
  const cachedTasksMtimeMs = cachedBeforeInvalidate?.tasksMtimeMs ?? 0;
10701
10873
  const cachedTasksSize = cachedBeforeInvalidate?.tasksSize ?? 0;
10702
10874
  invalidateRunCache(manifest.stateRoot);
10703
- const manifestPath = path21.join(manifest.stateRoot, "manifest.json");
10875
+ const manifestPath = path22.join(manifest.stateRoot, "manifest.json");
10704
10876
  atomicWriteJson(manifestPath, manifest);
10705
10877
  const manifestStat = fs26.statSync(manifestPath);
10706
10878
  setManifestCache(manifest.stateRoot, {
@@ -10718,7 +10890,7 @@ async function saveRunManifestAsync(manifest) {
10718
10890
  const cachedTasksMtimeMs = cachedBeforeInvalidate?.tasksMtimeMs ?? 0;
10719
10891
  const cachedTasksSize = cachedBeforeInvalidate?.tasksSize ?? 0;
10720
10892
  invalidateRunCache(manifest.stateRoot);
10721
- const manifestPath = path21.join(manifest.stateRoot, "manifest.json");
10893
+ const manifestPath = path22.join(manifest.stateRoot, "manifest.json");
10722
10894
  await atomicWriteJsonAsync(manifestPath, manifest);
10723
10895
  let manifestStat;
10724
10896
  try {
@@ -10745,7 +10917,7 @@ function saveRunTasks(manifest, tasks) {
10745
10917
  return;
10746
10918
  }
10747
10919
  atomicWriteJson(manifest.tasksPath, tasks);
10748
- const manifestPath = path21.join(manifest.stateRoot, "manifest.json");
10920
+ const manifestPath = path22.join(manifest.stateRoot, "manifest.json");
10749
10921
  let manifestStat;
10750
10922
  let tasksStat;
10751
10923
  try {
@@ -10795,7 +10967,7 @@ function saveManifestAndTasksAtomicSync(manifest, tasks) {
10795
10967
  try {
10796
10968
  withRunLockSync(manifest, () => {
10797
10969
  invalidateRunCache(manifest.stateRoot);
10798
- atomicWriteJson(path21.join(manifest.stateRoot, "manifest.json"), manifest);
10970
+ atomicWriteJson(path22.join(manifest.stateRoot, "manifest.json"), manifest);
10799
10971
  manifestWritten = true;
10800
10972
  atomicWriteJson(manifest.tasksPath, tasks);
10801
10973
  tasksWritten = true;
@@ -10895,8 +11067,8 @@ async function readJsonFileAsync(filePath) {
10895
11067
  function loadRunManifestById(cwd, runId) {
10896
11068
  const stateRoot = resolveRunStateRoot(cwd, runId);
10897
11069
  if (!stateRoot) return void 0;
10898
- const manifestPath = path21.join(stateRoot, "manifest.json");
10899
- const tasksPath = path21.join(stateRoot, "tasks.json");
11070
+ const manifestPath = path22.join(stateRoot, "manifest.json");
11071
+ const tasksPath = path22.join(stateRoot, "tasks.json");
10900
11072
  let manifestStat;
10901
11073
  try {
10902
11074
  manifestStat = statManifestWithWindowsRetry(manifestPath);
@@ -10963,8 +11135,8 @@ function loadRunManifestById(cwd, runId) {
10963
11135
  async function loadRunManifestByIdAsync(cwd, runId) {
10964
11136
  const stateRoot = resolveRunStateRoot(cwd, runId);
10965
11137
  if (!stateRoot) return void 0;
10966
- const manifestPath = path21.join(stateRoot, "manifest.json");
10967
- const tasksPath = path21.join(stateRoot, "tasks.json");
11138
+ const manifestPath = path22.join(stateRoot, "manifest.json");
11139
+ const tasksPath = path22.join(stateRoot, "tasks.json");
10968
11140
  let manifestStat;
10969
11141
  try {
10970
11142
  manifestStat = await fs26.promises.stat(manifestPath);
@@ -11031,7 +11203,7 @@ async function loadRunManifestByIdAsync(cwd, runId) {
11031
11203
  });
11032
11204
  return { manifest, tasks: tasks ?? [] };
11033
11205
  }
11034
- var manifestCacheGeneration, MANIFEST_CACHE_TTL_MS, LOAD_MANIFEST_RETRY_LIMIT, manifestCache, MANIFEST_CACHE_TTL_MS_VALUE;
11206
+ var manifestCacheGeneration, MANIFEST_CACHE_TTL_MS, LOAD_MANIFEST_RETRY_LIMIT, manifestCache, MANIFEST_CACHE_TTL_MS_VALUE, runStateRootCache, RUN_STATE_ROOT_TTL_MS, RUN_STATE_ROOT_CACHE_MAX;
11035
11207
  var init_state_store = __esm({
11036
11208
  "src/state/state-store.ts"() {
11037
11209
  "use strict";
@@ -11053,6 +11225,9 @@ var init_state_store = __esm({
11053
11225
  LOAD_MANIFEST_RETRY_LIMIT = 5;
11054
11226
  manifestCache = /* @__PURE__ */ new Map();
11055
11227
  MANIFEST_CACHE_TTL_MS_VALUE = MANIFEST_CACHE_TTL_MS;
11228
+ runStateRootCache = /* @__PURE__ */ new Map();
11229
+ RUN_STATE_ROOT_TTL_MS = 1e4;
11230
+ RUN_STATE_ROOT_CACHE_MAX = 256;
11056
11231
  }
11057
11232
  });
11058
11233
 
@@ -11280,7 +11455,7 @@ var init_recovery_recipes = __esm({
11280
11455
 
11281
11456
  // src/runtime/diagnostic-export.ts
11282
11457
  import * as fs27 from "node:fs";
11283
- import * as path22 from "node:path";
11458
+ import * as path23 from "node:path";
11284
11459
  function envRedacted() {
11285
11460
  const output = {};
11286
11461
  for (const [key, value] of Object.entries(process.env)) {
@@ -11317,7 +11492,7 @@ async function exportDiagnostic(ctx, runId, options = {}) {
11317
11492
  if (!loaded) throw new Error(`Run '${runId}' not found.`);
11318
11493
  const exportedAt = (/* @__PURE__ */ new Date()).toISOString();
11319
11494
  const safeTimestamp = exportedAt.replace(/[:.]/g, "-");
11320
- const recentEvents = readEvents(loaded.manifest.eventsPath).slice(-200);
11495
+ const recentEvents = readJsonlTail(loaded.manifest.eventsPath, 256 * 1024).items.slice(-200);
11321
11496
  const metricsSnapshot = options.registry?.snapshot();
11322
11497
  const taskDiagnostics = {};
11323
11498
  const terminalEvidence = {};
@@ -11362,9 +11537,9 @@ async function exportDiagnostic(ctx, runId, options = {}) {
11362
11537
  runMailboxUnread: snapshot.mailbox,
11363
11538
  recoveryLedger
11364
11539
  };
11365
- const dir = path22.join(loaded.manifest.artifactsRoot, "diagnostic");
11540
+ const dir = path23.join(loaded.manifest.artifactsRoot, "diagnostic");
11366
11541
  fs27.mkdirSync(dir, { recursive: true });
11367
- const filePath = path22.join(dir, `diagnostic-${safeTimestamp}.json`);
11542
+ const filePath = path23.join(dir, `diagnostic-${safeTimestamp}.json`);
11368
11543
  atomicWriteFile(filePath, `${JSON.stringify(report, null, 2)}
11369
11544
  `);
11370
11545
  return { path: filePath, report };
@@ -11374,7 +11549,7 @@ function listRecentDiagnostic(dir, windowMs, now = Date.now()) {
11374
11549
  if (!fs27.existsSync(dir)) return void 0;
11375
11550
  return fs27.readdirSync(dir).filter((file) => file.startsWith("diagnostic-") && file.endsWith(".json")).map((file) => ({
11376
11551
  file,
11377
- mtimeMs: fs27.statSync(path22.join(dir, file)).mtimeMs
11552
+ mtimeMs: fs27.statSync(path23.join(dir, file)).mtimeMs
11378
11553
  })).filter((entry) => now - entry.mtimeMs < windowMs).sort((a, b) => b.mtimeMs - a.mtimeMs)[0]?.file;
11379
11554
  } catch {
11380
11555
  return void 0;
@@ -11385,9 +11560,9 @@ var init_diagnostic_export = __esm({
11385
11560
  "src/runtime/diagnostic-export.ts"() {
11386
11561
  "use strict";
11387
11562
  init_atomic_write();
11388
- init_event_log();
11389
11563
  init_state_store();
11390
11564
  init_heartbeat_aggregator();
11565
+ init_incremental_reader();
11391
11566
  init_redaction();
11392
11567
  init_crew_agent_records();
11393
11568
  init_recovery_recipes();
@@ -11798,7 +11973,7 @@ var init_tool_result = __esm({
11798
11973
  // src/state/artifact-store.ts
11799
11974
  import { createHash as createHash3 } from "node:crypto";
11800
11975
  import * as fs28 from "node:fs";
11801
- import * as path23 from "node:path";
11976
+ import * as path24 from "node:path";
11802
11977
  function hashContent(content) {
11803
11978
  return createHash3("sha256").update(content).digest("hex");
11804
11979
  }
@@ -11814,7 +11989,7 @@ function nowMs2() {
11814
11989
  }
11815
11990
  function readMarkerMtime(artifactsRoot, markerFile) {
11816
11991
  try {
11817
- return fs28.statSync(path23.join(artifactsRoot, markerFile)).mtimeMs;
11992
+ return fs28.statSync(path24.join(artifactsRoot, markerFile)).mtimeMs;
11818
11993
  } catch {
11819
11994
  return void 0;
11820
11995
  }
@@ -11826,7 +12001,7 @@ function shouldCleanup(artifactsRoot, markerFile, scanGraceMs) {
11826
12001
  }
11827
12002
  function writeCleanupMarker(artifactsRoot, markerFile) {
11828
12003
  fs28.mkdirSync(artifactsRoot, { recursive: true });
11829
- atomicWriteFile(path23.join(artifactsRoot, markerFile), String(nowMs2()));
12004
+ atomicWriteFile(path24.join(artifactsRoot, markerFile), String(nowMs2()));
11830
12005
  }
11831
12006
  function cleanupOldArtifacts(artifactsRoot, options) {
11832
12007
  if (!fs28.existsSync(artifactsRoot)) return;
@@ -11843,7 +12018,7 @@ function cleanupOldArtifacts(artifactsRoot, options) {
11843
12018
  for (const entry of entries) {
11844
12019
  if (entry.name === markerFile) continue;
11845
12020
  if (entry.isSymbolicLink()) continue;
11846
- const target = path23.join(artifactsRoot, entry.name);
12021
+ const target = path24.join(artifactsRoot, entry.name);
11847
12022
  try {
11848
12023
  const stat2 = fs28.statSync(target);
11849
12024
  if (stat2.mtimeMs >= cutoff) continue;
@@ -11868,7 +12043,7 @@ function resolveInside(baseDir, relativePath) {
11868
12043
  if (err2.code !== "ENOENT") throw err2;
11869
12044
  }
11870
12045
  const normalizedRelativePath = relativePath.replaceAll("\\", "/").replace(/^\.\/+/, "");
11871
- if (!normalizedRelativePath || normalizedRelativePath.split("/").some((segment) => segment === "..") || path23.isAbsolute(normalizedRelativePath)) {
12046
+ if (!normalizedRelativePath || normalizedRelativePath.split("/").some((segment) => segment === "..") || path24.isAbsolute(normalizedRelativePath)) {
11872
12047
  throw new Error(`Invalid artifact path: ${relativePath}`);
11873
12048
  }
11874
12049
  return resolveRealContainedPath(baseDir, normalizedRelativePath);
@@ -11879,8 +12054,8 @@ function writeArtifact(artifactsRoot, options) {
11879
12054
  throw new Error(`Artifacts root is a symbolic link \u2014 not allowed: ${artifactsRoot}`);
11880
12055
  }
11881
12056
  const filePath = resolveInside(artifactsRoot, options.relativePath);
11882
- fs28.mkdirSync(path23.dirname(filePath), { recursive: true });
11883
- resolveRealContainedPath(artifactsRoot, path23.dirname(filePath));
12057
+ fs28.mkdirSync(path24.dirname(filePath), { recursive: true });
12058
+ resolveRealContainedPath(artifactsRoot, path24.dirname(filePath));
11884
12059
  let content = options.content;
11885
12060
  const trimmed = content.trim();
11886
12061
  if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
@@ -11919,7 +12094,7 @@ var init_artifact_store = __esm({
11919
12094
 
11920
12095
  // src/state/mailbox.ts
11921
12096
  import * as fs29 from "node:fs";
11922
- import * as path24 from "node:path";
12097
+ import * as path25 from "node:path";
11923
12098
  function registerMailboxAppendObserver(fn) {
11924
12099
  mailboxAppendObservers.add(fn);
11925
12100
  return () => {
@@ -11939,7 +12114,7 @@ function notifyMailboxAppended(message) {
11939
12114
  });
11940
12115
  }
11941
12116
  function mailboxDir(manifest) {
11942
- return path24.join(manifest.stateRoot, "mailbox");
12117
+ return path25.join(manifest.stateRoot, "mailbox");
11943
12118
  }
11944
12119
  function safeMailboxDir(manifest, create = false) {
11945
12120
  const dir = mailboxDir(manifest);
@@ -11949,8 +12124,8 @@ function safeMailboxDir(manifest, create = false) {
11949
12124
  } catch (error) {
11950
12125
  if (process.platform === "win32" && error.code === "EPERM") {
11951
12126
  try {
11952
- const realDir = fs29.realpathSync(path24.dirname(dir));
11953
- const correctedDir = path24.join(realDir, path24.basename(dir));
12127
+ const realDir = fs29.realpathSync(path25.dirname(dir));
12128
+ const correctedDir = path25.join(realDir, path25.basename(dir));
11954
12129
  fs29.mkdirSync(correctedDir, { recursive: true });
11955
12130
  } catch {
11956
12131
  throw error;
@@ -11962,18 +12137,18 @@ function safeMailboxDir(manifest, create = false) {
11962
12137
  }
11963
12138
  if (!fs29.existsSync(dir)) {
11964
12139
  if (create) throw new Error(`Mailbox directory creation failed: ${dir}`);
11965
- return path24.join(dir);
12140
+ return path25.join(dir);
11966
12141
  }
11967
12142
  if (fs29.lstatSync(dir).isSymbolicLink()) throw new Error(`Invalid mailbox directory: ${dir}`);
11968
12143
  return dir;
11969
12144
  }
11970
12145
  function safeTaskId(taskId) {
11971
- if (!/^[\w.-]+$/.test(taskId) || taskId.includes("..") || path24.isAbsolute(taskId))
12146
+ if (!/^[\w.-]+$/.test(taskId) || taskId.includes("..") || path25.isAbsolute(taskId))
11972
12147
  throw new Error(`Invalid mailbox task id: ${taskId}`);
11973
12148
  return taskId;
11974
12149
  }
11975
12150
  function safeMailboxTasksRoot(manifest, create = false) {
11976
- const root = path24.join(safeMailboxDir(manifest, create), "tasks");
12151
+ const root = path25.join(safeMailboxDir(manifest, create), "tasks");
11977
12152
  if (create) fs29.mkdirSync(root, { recursive: true });
11978
12153
  if (!fs29.existsSync(root)) return root;
11979
12154
  if (fs29.lstatSync(root).isSymbolicLink()) throw new Error(`Invalid mailbox tasks directory: ${root}`);
@@ -11982,9 +12157,9 @@ function safeMailboxTasksRoot(manifest, create = false) {
11982
12157
  function taskMailboxDir(manifest, taskId, create = false) {
11983
12158
  const tasksRoot = safeMailboxTasksRoot(manifest, create);
11984
12159
  const normalizedTaskId = safeTaskId(taskId);
11985
- const resolved = path24.resolve(tasksRoot, normalizedTaskId);
11986
- const relative9 = path24.relative(tasksRoot, resolved);
11987
- if (relative9.startsWith("..") || path24.isAbsolute(relative9)) throw new Error(`Invalid mailbox task id: ${taskId}`);
12160
+ const resolved = path25.resolve(tasksRoot, normalizedTaskId);
12161
+ const relative9 = path25.relative(tasksRoot, resolved);
12162
+ if (relative9.startsWith("..") || path25.isAbsolute(relative9)) throw new Error(`Invalid mailbox task id: ${taskId}`);
11988
12163
  if (create) fs29.mkdirSync(resolved, { recursive: true });
11989
12164
  if (fs29.existsSync(resolved) && fs29.lstatSync(resolved).isSymbolicLink()) throw new Error(`Invalid mailbox task directory: ${resolved}`);
11990
12165
  return resolved;
@@ -11996,15 +12171,15 @@ function safeMailboxFile(filePath, parentDir) {
11996
12171
  }
11997
12172
  function mailboxFile(manifest, direction, taskId, create = false) {
11998
12173
  const parent = taskId ? taskMailboxDir(manifest, taskId, create) : safeMailboxDir(manifest, create);
11999
- return safeMailboxFile(path24.join(parent, `${direction}.jsonl`), parent);
12174
+ return safeMailboxFile(path25.join(parent, `${direction}.jsonl`), parent);
12000
12175
  }
12001
12176
  function deliveryFile(manifest, create = false) {
12002
12177
  try {
12003
12178
  const parent = safeMailboxDir(manifest, create);
12004
- return safeMailboxFile(path24.join(parent, "delivery.json"), parent);
12179
+ return safeMailboxFile(path25.join(parent, "delivery.json"), parent);
12005
12180
  } catch (err2) {
12006
12181
  if (err2.code === "ENOENT") {
12007
- return path24.join(mailboxDir(manifest), "delivery.json");
12182
+ return path25.join(mailboxDir(manifest), "delivery.json");
12008
12183
  }
12009
12184
  throw err2;
12010
12185
  }
@@ -12014,13 +12189,13 @@ function ensureRunMailbox(manifest) {
12014
12189
  for (const direction of ["inbox", "outbox"]) {
12015
12190
  const filePath = mailboxFile(manifest, direction, void 0, true);
12016
12191
  if (!fs29.existsSync(filePath)) {
12017
- fs29.mkdirSync(path24.dirname(filePath), { recursive: true });
12192
+ fs29.mkdirSync(path25.dirname(filePath), { recursive: true });
12018
12193
  atomicWriteFile(filePath, "");
12019
12194
  }
12020
12195
  }
12021
12196
  const delivery = deliveryFile(manifest, true);
12022
12197
  if (!fs29.existsSync(delivery)) {
12023
- fs29.mkdirSync(path24.dirname(delivery), { recursive: true });
12198
+ fs29.mkdirSync(path25.dirname(delivery), { recursive: true });
12024
12199
  atomicWriteFile(delivery, `${JSON.stringify({ messages: {}, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)}
12025
12200
  `);
12026
12201
  }
@@ -12095,11 +12270,11 @@ function safeReadMailboxFile(filePath, direction) {
12095
12270
  if (!fs29.existsSync(filePath)) return [];
12096
12271
  const messages = readMailboxFile(filePath, direction);
12097
12272
  try {
12098
- const dir = path24.dirname(filePath);
12099
- const base = path24.basename(filePath);
12273
+ const dir = path25.dirname(filePath);
12274
+ const base = path25.basename(filePath);
12100
12275
  for (const entry of fs29.readdirSync(dir)) {
12101
12276
  if (!entry.startsWith(`${base}.`) || !entry.endsWith(".archive.jsonl")) continue;
12102
- const archivePath = path24.join(dir, entry);
12277
+ const archivePath = path25.join(dir, entry);
12103
12278
  messages.push(...readMailboxFile(archivePath, direction));
12104
12279
  }
12105
12280
  } catch {
@@ -12124,12 +12299,12 @@ function rotateMailboxFileIfNeeded(filePath, thresholdBytes = MAILBOX_ARCHIVE_TH
12124
12299
  }
12125
12300
  function pruneOldMailboxArchives(mailboxFilePath) {
12126
12301
  try {
12127
- const dir = path24.dirname(mailboxFilePath);
12128
- const base = path24.basename(mailboxFilePath);
12302
+ const dir = path25.dirname(mailboxFilePath);
12303
+ const base = path25.basename(mailboxFilePath);
12129
12304
  const archives = fs29.readdirSync(dir).filter((f) => f.startsWith(base) && f.includes(".archive.jsonl")).sort();
12130
12305
  const excess = archives.length - DEFAULT_MAILBOX.maxArchivesPerDirection;
12131
12306
  for (let i = 0; i < excess; i += 1) {
12132
- fs29.rmSync(path24.join(dir, archives[i]), { force: true });
12307
+ fs29.rmSync(path25.join(dir, archives[i]), { force: true });
12133
12308
  }
12134
12309
  } catch (error) {
12135
12310
  logInternalError("mailbox.prune", error, mailboxFilePath);
@@ -12828,9 +13003,9 @@ var init_context = __esm({
12828
13003
 
12829
13004
  // src/runtime/async-marker.ts
12830
13005
  import * as fs30 from "node:fs";
12831
- import * as path25 from "node:path";
13006
+ import * as path26 from "node:path";
12832
13007
  function asyncStartMarkerPath(manifest) {
12833
- return path25.join(manifest.stateRoot, "async.pid");
13008
+ return path26.join(manifest.stateRoot, "async.pid");
12834
13009
  }
12835
13010
  function hasAsyncStartMarker(manifest) {
12836
13011
  try {
@@ -12948,7 +13123,7 @@ var init_process_status = __esm({
12948
13123
 
12949
13124
  // src/runtime/run-tracker.ts
12950
13125
  import * as fs31 from "node:fs";
12951
- import * as path26 from "node:path";
13126
+ import * as path27 from "node:path";
12952
13127
  function registerRunPromise(runId) {
12953
13128
  let resolve23;
12954
13129
  let reject;
@@ -12996,7 +13171,7 @@ async function waitForRun(runId, cwd, options = {}) {
12996
13171
  let attempt = 0;
12997
13172
  while (Date.now() < deadline) {
12998
13173
  if (attempt === 0) {
12999
- const runDir = path26.join(projectCrewRoot(cwd), "state", "runs", runId);
13174
+ const runDir = path27.join(projectCrewRoot(cwd), "state", "runs", runId);
13000
13175
  if (!fs31.existsSync(runDir)) {
13001
13176
  throw new Error(`Run ${runId} not found. No run directory at ${runDir}`);
13002
13177
  }
@@ -13148,15 +13323,15 @@ var init_crew_hooks = __esm({
13148
13323
 
13149
13324
  // src/runtime/skill-effectiveness.ts
13150
13325
  import { existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync21, writeFileSync as writeFileSync5 } from "node:fs";
13151
- import { dirname as dirname14, join as join26 } from "node:path";
13326
+ import { dirname as dirname15, join as join27 } from "node:path";
13152
13327
  function getSkillMetricsPath(cwd, runId) {
13153
- return join26(projectCrewRoot(cwd), `state/runs/${runId}/skill-metrics.jsonl`);
13328
+ return join27(projectCrewRoot(cwd), `state/runs/${runId}/skill-metrics.jsonl`);
13154
13329
  }
13155
13330
  function getSkillActivationsPath(cwd, runId) {
13156
- return join26(projectCrewRoot(cwd), `state/runs/${runId}/skill-activations.jsonl`);
13331
+ return join27(projectCrewRoot(cwd), `state/runs/${runId}/skill-activations.jsonl`);
13157
13332
  }
13158
13333
  function ensureSkillMetricsDir(cwd, runId) {
13159
- const dir = dirname14(getSkillMetricsPath(cwd, runId));
13334
+ const dir = dirname15(getSkillMetricsPath(cwd, runId));
13160
13335
  if (!existsSync22(dir)) {
13161
13336
  mkdirSync14(dir, { recursive: true });
13162
13337
  }
@@ -13200,17 +13375,17 @@ function confidenceToThreshold(confidence) {
13200
13375
  }
13201
13376
  function recordSkillActivation(cwd, activation) {
13202
13377
  ensureSkillMetricsDir(cwd, activation.runId);
13203
- const path86 = getSkillActivationsPath(cwd, activation.runId);
13378
+ const path87 = getSkillActivationsPath(cwd, activation.runId);
13204
13379
  const line4 = JSON.stringify(activation) + "\n";
13205
- writeFileSync5(path86, line4, { flag: "a", encoding: "utf-8" });
13380
+ writeFileSync5(path87, line4, { flag: "a", encoding: "utf-8" });
13206
13381
  return activation;
13207
13382
  }
13208
13383
  function getSkillActivations(cwd, runId) {
13209
- const path86 = getSkillActivationsPath(cwd, runId);
13210
- if (!existsSync22(path86)) {
13384
+ const path87 = getSkillActivationsPath(cwd, runId);
13385
+ if (!existsSync22(path87)) {
13211
13386
  return [];
13212
13387
  }
13213
- const content = readFileSync21(path86, "utf-8");
13388
+ const content = readFileSync21(path87, "utf-8");
13214
13389
  if (!content.trim()) {
13215
13390
  return [];
13216
13391
  }
@@ -13389,7 +13564,7 @@ __export(skill_instructions_exports, {
13389
13564
  resolveTaskSkillNames: () => resolveTaskSkillNames
13390
13565
  });
13391
13566
  import * as fs32 from "node:fs";
13392
- import * as path27 from "node:path";
13567
+ import * as path28 from "node:path";
13393
13568
  import { fileURLToPath as fileURLToPath4 } from "node:url";
13394
13569
  import * as os9 from "node:os";
13395
13570
  function isValidSkillName(name) {
@@ -13441,18 +13616,18 @@ function candidateSkillDirs(cwd) {
13441
13616
  // F6 (v0.7.9): same five roots as discover-skills, in the same precedence
13442
13617
  // order. The first hit wins, so a project `.pi/skills/foo/SKILL.md`
13443
13618
  // overrides both the bundled `foo` and any legacy `<cwd>/skills/foo`.
13444
- { root: path27.resolve(cwd, ".pi", "skills"), source: "project-pi" },
13619
+ { root: path28.resolve(cwd, ".pi", "skills"), source: "project-pi" },
13445
13620
  {
13446
- root: path27.resolve(cwd, ".agents", "skills"),
13621
+ root: path28.resolve(cwd, ".agents", "skills"),
13447
13622
  source: "project-agents"
13448
13623
  },
13449
- { root: path27.resolve(cwd, "skills"), source: "project" },
13450
- { root: path27.join(getAgentDir(), "skills"), source: "user-pi" },
13624
+ { root: path28.resolve(cwd, "skills"), source: "project" },
13625
+ { root: path28.join(getAgentDir(), "skills"), source: "user-pi" },
13451
13626
  {
13452
- root: path27.join(os9.homedir(), ".agents", "skills"),
13627
+ root: path28.join(os9.homedir(), ".agents", "skills"),
13453
13628
  source: "user-agents"
13454
13629
  },
13455
- { root: path27.join(os9.homedir(), ".pi", "skills"), source: "user-pi" }
13630
+ { root: path28.join(os9.homedir(), ".pi", "skills"), source: "user-pi" }
13456
13631
  ];
13457
13632
  }
13458
13633
  function rememberSkill(key, value) {
@@ -13498,7 +13673,7 @@ function cachedSkillFresh(value) {
13498
13673
  }
13499
13674
  function readSkillMarkdown(cwd, name) {
13500
13675
  if (!isValidSkillName(name)) return void 0;
13501
- const cacheKey2 = `${path27.resolve(cwd)}:${name}`;
13676
+ const cacheKey2 = `${path28.resolve(cwd)}:${name}`;
13502
13677
  const cached = skillReadCache.get(cacheKey2);
13503
13678
  if (cached && cachedSkillFresh(cached)) {
13504
13679
  skillCacheStats.hits++;
@@ -13509,7 +13684,7 @@ function readSkillMarkdown(cwd, name) {
13509
13684
  skillCacheStats.currentSize = skillReadCache.size;
13510
13685
  for (const entry of candidateSkillDirs(cwd)) {
13511
13686
  try {
13512
- const relative9 = path27.join(name, "SKILL.md");
13687
+ const relative9 = path28.join(name, "SKILL.md");
13513
13688
  const contained = resolveRealContainedPath(entry.root, relative9);
13514
13689
  if (!fs32.existsSync(contained)) continue;
13515
13690
  if (fs32.lstatSync(contained).isSymbolicLink()) continue;
@@ -13584,7 +13759,7 @@ Skill '${safeName}' was selected but no SKILL.md file was found. Continue with t
13584
13759
  if (!pushSection(missing)) omittedCount += 1;
13585
13760
  continue;
13586
13761
  }
13587
- skillPaths.push(path27.dirname(loaded.path));
13762
+ skillPaths.push(path28.dirname(loaded.path));
13588
13763
  const description = frontmatterDescription(loaded.content);
13589
13764
  const source = loaded.source === "project" ? `project:skills/${safeName}` : `package:skills/${safeName}`;
13590
13765
  const weighted = weightedSkills?.find((w) => w.skillId === name);
@@ -13599,7 +13774,7 @@ Skill '${safeName}' was selected but no SKILL.md file was found. Continue with t
13599
13774
  // spec "small instruction + large local reference" pattern, e.g.
13600
13775
  // effective-html's `references/html-effectiveness/`) leave the agent
13601
13776
  // guessing the skill dir. No behavior change for corpus-less skills.
13602
- `Path: ${path27.dirname(loaded.path)}`
13777
+ `Path: ${path28.dirname(loaded.path)}`
13603
13778
  ].filter(Boolean).join("\n");
13604
13779
  const rawContent = loaded.compacted;
13605
13780
  const wrappedContent = `<!-- skill: ${safeName} -->
@@ -13643,7 +13818,7 @@ var init_skill_instructions = __esm({
13643
13818
  init_safe_paths();
13644
13819
  init_skill_effectiveness();
13645
13820
  init_peer_dep();
13646
- PACKAGE_SKILLS_DIR = path27.resolve(path27.dirname(fileURLToPath4(import.meta.url)), "..", "..", "skills");
13821
+ PACKAGE_SKILLS_DIR = path28.resolve(path28.dirname(fileURLToPath4(import.meta.url)), "..", "..", "skills");
13647
13822
  MAX_SKILL_CHARS = 1500;
13648
13823
  MAX_TOTAL_CHARS = 6e3;
13649
13824
  MAX_SKILL_NAME_CHARS = 80;
@@ -14422,17 +14597,17 @@ var require_visit = __commonJS({
14422
14597
  visit.BREAK = BREAK;
14423
14598
  visit.SKIP = SKIP;
14424
14599
  visit.REMOVE = REMOVE;
14425
- function visit_(key, node, visitor, path86) {
14426
- const ctrl = callVisitor(key, node, visitor, path86);
14600
+ function visit_(key, node, visitor, path87) {
14601
+ const ctrl = callVisitor(key, node, visitor, path87);
14427
14602
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
14428
- replaceNode(key, path86, ctrl);
14429
- return visit_(key, ctrl, visitor, path86);
14603
+ replaceNode(key, path87, ctrl);
14604
+ return visit_(key, ctrl, visitor, path87);
14430
14605
  }
14431
14606
  if (typeof ctrl !== "symbol") {
14432
14607
  if (identity.isCollection(node)) {
14433
- path86 = Object.freeze(path86.concat(node));
14608
+ path87 = Object.freeze(path87.concat(node));
14434
14609
  for (let i = 0; i < node.items.length; ++i) {
14435
- const ci = visit_(i, node.items[i], visitor, path86);
14610
+ const ci = visit_(i, node.items[i], visitor, path87);
14436
14611
  if (typeof ci === "number")
14437
14612
  i = ci - 1;
14438
14613
  else if (ci === BREAK)
@@ -14443,13 +14618,13 @@ var require_visit = __commonJS({
14443
14618
  }
14444
14619
  }
14445
14620
  } else if (identity.isPair(node)) {
14446
- path86 = Object.freeze(path86.concat(node));
14447
- const ck = visit_("key", node.key, visitor, path86);
14621
+ path87 = Object.freeze(path87.concat(node));
14622
+ const ck = visit_("key", node.key, visitor, path87);
14448
14623
  if (ck === BREAK)
14449
14624
  return BREAK;
14450
14625
  else if (ck === REMOVE)
14451
14626
  node.key = null;
14452
- const cv = visit_("value", node.value, visitor, path86);
14627
+ const cv = visit_("value", node.value, visitor, path87);
14453
14628
  if (cv === BREAK)
14454
14629
  return BREAK;
14455
14630
  else if (cv === REMOVE)
@@ -14470,17 +14645,17 @@ var require_visit = __commonJS({
14470
14645
  visitAsync.BREAK = BREAK;
14471
14646
  visitAsync.SKIP = SKIP;
14472
14647
  visitAsync.REMOVE = REMOVE;
14473
- async function visitAsync_(key, node, visitor, path86) {
14474
- const ctrl = await callVisitor(key, node, visitor, path86);
14648
+ async function visitAsync_(key, node, visitor, path87) {
14649
+ const ctrl = await callVisitor(key, node, visitor, path87);
14475
14650
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
14476
- replaceNode(key, path86, ctrl);
14477
- return visitAsync_(key, ctrl, visitor, path86);
14651
+ replaceNode(key, path87, ctrl);
14652
+ return visitAsync_(key, ctrl, visitor, path87);
14478
14653
  }
14479
14654
  if (typeof ctrl !== "symbol") {
14480
14655
  if (identity.isCollection(node)) {
14481
- path86 = Object.freeze(path86.concat(node));
14656
+ path87 = Object.freeze(path87.concat(node));
14482
14657
  for (let i = 0; i < node.items.length; ++i) {
14483
- const ci = await visitAsync_(i, node.items[i], visitor, path86);
14658
+ const ci = await visitAsync_(i, node.items[i], visitor, path87);
14484
14659
  if (typeof ci === "number")
14485
14660
  i = ci - 1;
14486
14661
  else if (ci === BREAK)
@@ -14491,13 +14666,13 @@ var require_visit = __commonJS({
14491
14666
  }
14492
14667
  }
14493
14668
  } else if (identity.isPair(node)) {
14494
- path86 = Object.freeze(path86.concat(node));
14495
- const ck = await visitAsync_("key", node.key, visitor, path86);
14669
+ path87 = Object.freeze(path87.concat(node));
14670
+ const ck = await visitAsync_("key", node.key, visitor, path87);
14496
14671
  if (ck === BREAK)
14497
14672
  return BREAK;
14498
14673
  else if (ck === REMOVE)
14499
14674
  node.key = null;
14500
- const cv = await visitAsync_("value", node.value, visitor, path86);
14675
+ const cv = await visitAsync_("value", node.value, visitor, path87);
14501
14676
  if (cv === BREAK)
14502
14677
  return BREAK;
14503
14678
  else if (cv === REMOVE)
@@ -14524,23 +14699,23 @@ var require_visit = __commonJS({
14524
14699
  }
14525
14700
  return visitor;
14526
14701
  }
14527
- function callVisitor(key, node, visitor, path86) {
14702
+ function callVisitor(key, node, visitor, path87) {
14528
14703
  if (typeof visitor === "function")
14529
- return visitor(key, node, path86);
14704
+ return visitor(key, node, path87);
14530
14705
  if (identity.isMap(node))
14531
- return visitor.Map?.(key, node, path86);
14706
+ return visitor.Map?.(key, node, path87);
14532
14707
  if (identity.isSeq(node))
14533
- return visitor.Seq?.(key, node, path86);
14708
+ return visitor.Seq?.(key, node, path87);
14534
14709
  if (identity.isPair(node))
14535
- return visitor.Pair?.(key, node, path86);
14710
+ return visitor.Pair?.(key, node, path87);
14536
14711
  if (identity.isScalar(node))
14537
- return visitor.Scalar?.(key, node, path86);
14712
+ return visitor.Scalar?.(key, node, path87);
14538
14713
  if (identity.isAlias(node))
14539
- return visitor.Alias?.(key, node, path86);
14714
+ return visitor.Alias?.(key, node, path87);
14540
14715
  return void 0;
14541
14716
  }
14542
- function replaceNode(key, path86, node) {
14543
- const parent = path86[path86.length - 1];
14717
+ function replaceNode(key, path87, node) {
14718
+ const parent = path87[path87.length - 1];
14544
14719
  if (identity.isCollection(parent)) {
14545
14720
  parent.items[key] = node;
14546
14721
  } else if (identity.isPair(parent)) {
@@ -15150,10 +15325,10 @@ var require_Collection = __commonJS({
15150
15325
  var createNode = require_createNode();
15151
15326
  var identity = require_identity();
15152
15327
  var Node = require_Node();
15153
- function collectionFromPath(schema, path86, value) {
15328
+ function collectionFromPath(schema, path87, value) {
15154
15329
  let v = value;
15155
- for (let i = path86.length - 1; i >= 0; --i) {
15156
- const k = path86[i];
15330
+ for (let i = path87.length - 1; i >= 0; --i) {
15331
+ const k = path87[i];
15157
15332
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
15158
15333
  const a = [];
15159
15334
  a[k] = v;
@@ -15172,7 +15347,7 @@ var require_Collection = __commonJS({
15172
15347
  sourceObjects: /* @__PURE__ */ new Map()
15173
15348
  });
15174
15349
  }
15175
- var isEmptyPath = (path86) => path86 == null || typeof path86 === "object" && !!path86[Symbol.iterator]().next().done;
15350
+ var isEmptyPath = (path87) => path87 == null || typeof path87 === "object" && !!path87[Symbol.iterator]().next().done;
15176
15351
  var Collection = class extends Node.NodeBase {
15177
15352
  constructor(type, schema) {
15178
15353
  super(type);
@@ -15202,11 +15377,11 @@ var require_Collection = __commonJS({
15202
15377
  * be a Pair instance or a `{ key, value }` object, which may not have a key
15203
15378
  * that already exists in the map.
15204
15379
  */
15205
- addIn(path86, value) {
15206
- if (isEmptyPath(path86))
15380
+ addIn(path87, value) {
15381
+ if (isEmptyPath(path87))
15207
15382
  this.add(value);
15208
15383
  else {
15209
- const [key, ...rest] = path86;
15384
+ const [key, ...rest] = path87;
15210
15385
  const node = this.get(key, true);
15211
15386
  if (identity.isCollection(node))
15212
15387
  node.addIn(rest, value);
@@ -15220,8 +15395,8 @@ var require_Collection = __commonJS({
15220
15395
  * Removes a value from the collection.
15221
15396
  * @returns `true` if the item was found and removed.
15222
15397
  */
15223
- deleteIn(path86) {
15224
- const [key, ...rest] = path86;
15398
+ deleteIn(path87) {
15399
+ const [key, ...rest] = path87;
15225
15400
  if (rest.length === 0)
15226
15401
  return this.delete(key);
15227
15402
  const node = this.get(key, true);
@@ -15235,8 +15410,8 @@ var require_Collection = __commonJS({
15235
15410
  * scalar values from their surrounding node; to disable set `keepScalar` to
15236
15411
  * `true` (collections are always returned intact).
15237
15412
  */
15238
- getIn(path86, keepScalar) {
15239
- const [key, ...rest] = path86;
15413
+ getIn(path87, keepScalar) {
15414
+ const [key, ...rest] = path87;
15240
15415
  const node = this.get(key, true);
15241
15416
  if (rest.length === 0)
15242
15417
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -15254,8 +15429,8 @@ var require_Collection = __commonJS({
15254
15429
  /**
15255
15430
  * Checks if the collection includes a value with the key `key`.
15256
15431
  */
15257
- hasIn(path86) {
15258
- const [key, ...rest] = path86;
15432
+ hasIn(path87) {
15433
+ const [key, ...rest] = path87;
15259
15434
  if (rest.length === 0)
15260
15435
  return this.has(key);
15261
15436
  const node = this.get(key, true);
@@ -15265,8 +15440,8 @@ var require_Collection = __commonJS({
15265
15440
  * Sets a value in this collection. For `!!set`, `value` needs to be a
15266
15441
  * boolean to add/remove the item from the set.
15267
15442
  */
15268
- setIn(path86, value) {
15269
- const [key, ...rest] = path86;
15443
+ setIn(path87, value) {
15444
+ const [key, ...rest] = path87;
15270
15445
  if (rest.length === 0) {
15271
15446
  this.set(key, value);
15272
15447
  } else {
@@ -17781,9 +17956,9 @@ var require_Document = __commonJS({
17781
17956
  this.contents.add(value);
17782
17957
  }
17783
17958
  /** Adds a value to the document. */
17784
- addIn(path86, value) {
17959
+ addIn(path87, value) {
17785
17960
  if (assertCollection(this.contents))
17786
- this.contents.addIn(path86, value);
17961
+ this.contents.addIn(path87, value);
17787
17962
  }
17788
17963
  /**
17789
17964
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -17858,14 +18033,14 @@ var require_Document = __commonJS({
17858
18033
  * Removes a value from the document.
17859
18034
  * @returns `true` if the item was found and removed.
17860
18035
  */
17861
- deleteIn(path86) {
17862
- if (Collection.isEmptyPath(path86)) {
18036
+ deleteIn(path87) {
18037
+ if (Collection.isEmptyPath(path87)) {
17863
18038
  if (this.contents == null)
17864
18039
  return false;
17865
18040
  this.contents = null;
17866
18041
  return true;
17867
18042
  }
17868
- return assertCollection(this.contents) ? this.contents.deleteIn(path86) : false;
18043
+ return assertCollection(this.contents) ? this.contents.deleteIn(path87) : false;
17869
18044
  }
17870
18045
  /**
17871
18046
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -17880,10 +18055,10 @@ var require_Document = __commonJS({
17880
18055
  * scalar values from their surrounding node; to disable set `keepScalar` to
17881
18056
  * `true` (collections are always returned intact).
17882
18057
  */
17883
- getIn(path86, keepScalar) {
17884
- if (Collection.isEmptyPath(path86))
18058
+ getIn(path87, keepScalar) {
18059
+ if (Collection.isEmptyPath(path87))
17885
18060
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
17886
- return identity.isCollection(this.contents) ? this.contents.getIn(path86, keepScalar) : void 0;
18061
+ return identity.isCollection(this.contents) ? this.contents.getIn(path87, keepScalar) : void 0;
17887
18062
  }
17888
18063
  /**
17889
18064
  * Checks if the document includes a value with the key `key`.
@@ -17894,10 +18069,10 @@ var require_Document = __commonJS({
17894
18069
  /**
17895
18070
  * Checks if the document includes a value at `path`.
17896
18071
  */
17897
- hasIn(path86) {
17898
- if (Collection.isEmptyPath(path86))
18072
+ hasIn(path87) {
18073
+ if (Collection.isEmptyPath(path87))
17899
18074
  return this.contents !== void 0;
17900
- return identity.isCollection(this.contents) ? this.contents.hasIn(path86) : false;
18075
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path87) : false;
17901
18076
  }
17902
18077
  /**
17903
18078
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -17914,13 +18089,13 @@ var require_Document = __commonJS({
17914
18089
  * Sets a value in this document. For `!!set`, `value` needs to be a
17915
18090
  * boolean to add/remove the item from the set.
17916
18091
  */
17917
- setIn(path86, value) {
17918
- if (Collection.isEmptyPath(path86)) {
18092
+ setIn(path87, value) {
18093
+ if (Collection.isEmptyPath(path87)) {
17919
18094
  this.contents = value;
17920
18095
  } else if (this.contents == null) {
17921
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path86), value);
18096
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path87), value);
17922
18097
  } else if (assertCollection(this.contents)) {
17923
- this.contents.setIn(path86, value);
18098
+ this.contents.setIn(path87, value);
17924
18099
  }
17925
18100
  }
17926
18101
  /**
@@ -19880,9 +20055,9 @@ var require_cst_visit = __commonJS({
19880
20055
  visit.BREAK = BREAK;
19881
20056
  visit.SKIP = SKIP;
19882
20057
  visit.REMOVE = REMOVE;
19883
- visit.itemAtPath = (cst, path86) => {
20058
+ visit.itemAtPath = (cst, path87) => {
19884
20059
  let item = cst;
19885
- for (const [field, index] of path86) {
20060
+ for (const [field, index] of path87) {
19886
20061
  const tok = item?.[field];
19887
20062
  if (tok && "items" in tok) {
19888
20063
  item = tok.items[index];
@@ -19891,23 +20066,23 @@ var require_cst_visit = __commonJS({
19891
20066
  }
19892
20067
  return item;
19893
20068
  };
19894
- visit.parentCollection = (cst, path86) => {
19895
- const parent = visit.itemAtPath(cst, path86.slice(0, -1));
19896
- const field = path86[path86.length - 1][0];
20069
+ visit.parentCollection = (cst, path87) => {
20070
+ const parent = visit.itemAtPath(cst, path87.slice(0, -1));
20071
+ const field = path87[path87.length - 1][0];
19897
20072
  const coll = parent?.[field];
19898
20073
  if (coll && "items" in coll)
19899
20074
  return coll;
19900
20075
  throw new Error("Parent collection not found");
19901
20076
  };
19902
- function _visit(path86, item, visitor) {
19903
- let ctrl = visitor(item, path86);
20077
+ function _visit(path87, item, visitor) {
20078
+ let ctrl = visitor(item, path87);
19904
20079
  if (typeof ctrl === "symbol")
19905
20080
  return ctrl;
19906
20081
  for (const field of ["key", "value"]) {
19907
20082
  const token = item[field];
19908
20083
  if (token && "items" in token) {
19909
20084
  for (let i = 0; i < token.items.length; ++i) {
19910
- const ci = _visit(Object.freeze(path86.concat([[field, i]])), token.items[i], visitor);
20085
+ const ci = _visit(Object.freeze(path87.concat([[field, i]])), token.items[i], visitor);
19911
20086
  if (typeof ci === "number")
19912
20087
  i = ci - 1;
19913
20088
  else if (ci === BREAK)
@@ -19918,10 +20093,10 @@ var require_cst_visit = __commonJS({
19918
20093
  }
19919
20094
  }
19920
20095
  if (typeof ctrl === "function" && field === "key")
19921
- ctrl = ctrl(item, path86);
20096
+ ctrl = ctrl(item, path87);
19922
20097
  }
19923
20098
  }
19924
- return typeof ctrl === "function" ? ctrl(item, path86) : ctrl;
20099
+ return typeof ctrl === "function" ? ctrl(item, path87) : ctrl;
19925
20100
  }
19926
20101
  exports.visit = visit;
19927
20102
  }
@@ -21674,7 +21849,7 @@ var require_dist = __commonJS({
21674
21849
 
21675
21850
  // src/skills/validate.ts
21676
21851
  import * as fs34 from "node:fs";
21677
- import * as path28 from "node:path";
21852
+ import * as path29 from "node:path";
21678
21853
  function parseSkillFrontmatter(content) {
21679
21854
  const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
21680
21855
  if (!match) return { ok: true, data: {} };
@@ -21695,16 +21870,16 @@ function parseSkillFrontmatter(content) {
21695
21870
  };
21696
21871
  }
21697
21872
  }
21698
- function hard(path86, field, reason) {
21699
- return { path: path86, field, reason, severity: "error" };
21873
+ function hard(path87, field, reason) {
21874
+ return { path: path87, field, reason, severity: "error" };
21700
21875
  }
21701
- function warn(path86, field, reason) {
21702
- return { path: path86, field, reason, severity: "warn" };
21876
+ function warn(path87, field, reason) {
21877
+ return { path: path87, field, reason, severity: "warn" };
21703
21878
  }
21704
21879
  function validateSkillFrontmatter(skillDir) {
21705
21880
  const errors2 = [];
21706
- const skillMdPath = path28.join(skillDir, "SKILL.md");
21707
- const derivedName = path28.basename(skillDir);
21881
+ const skillMdPath = path29.join(skillDir, "SKILL.md");
21882
+ const derivedName = path29.basename(skillDir);
21708
21883
  let content;
21709
21884
  try {
21710
21885
  content = fs34.readFileSync(skillMdPath, "utf-8");
@@ -21841,23 +22016,23 @@ var init_validate = __esm({
21841
22016
  // src/skills/discover-skills.ts
21842
22017
  import * as fs35 from "node:fs";
21843
22018
  import * as os10 from "node:os";
21844
- import * as path29 from "node:path";
22019
+ import * as path30 from "node:path";
21845
22020
  import { fileURLToPath as fileURLToPath5 } from "node:url";
21846
22021
  function listSkillDirs(cwd) {
21847
22022
  return [
21848
22023
  { root: PACKAGE_SKILLS_DIR2, source: "package" },
21849
- { root: path29.resolve(cwd, ".pi", "skills"), source: "project-pi" },
22024
+ { root: path30.resolve(cwd, ".pi", "skills"), source: "project-pi" },
21850
22025
  {
21851
- root: path29.resolve(cwd, ".agents", "skills"),
22026
+ root: path30.resolve(cwd, ".agents", "skills"),
21852
22027
  source: "project-agents"
21853
22028
  },
21854
- { root: path29.resolve(cwd, "skills"), source: "project" },
21855
- { root: path29.join(getAgentDir(), "skills"), source: "user-pi" },
22029
+ { root: path30.resolve(cwd, "skills"), source: "project" },
22030
+ { root: path30.join(getAgentDir(), "skills"), source: "user-pi" },
21856
22031
  {
21857
- root: path29.join(os10.homedir(), ".agents", "skills"),
22032
+ root: path30.join(os10.homedir(), ".agents", "skills"),
21858
22033
  source: "user-agents"
21859
22034
  },
21860
- { root: path29.join(os10.homedir(), ".pi", "skills"), source: "user-pi" }
22035
+ { root: path30.join(os10.homedir(), ".pi", "skills"), source: "user-pi" }
21861
22036
  ];
21862
22037
  }
21863
22038
  function readDescription(content) {
@@ -21889,13 +22064,13 @@ function discoverSkills(cwd) {
21889
22064
  })) {
21890
22065
  if (!entry.isDirectory()) continue;
21891
22066
  if (!isSafePathId(entry.name)) continue;
21892
- const skillDirPath = path29.join(dir.root, entry.name);
22067
+ const skillDirPath = path30.join(dir.root, entry.name);
21893
22068
  try {
21894
22069
  if (fs35.lstatSync(skillDirPath).isSymbolicLink()) continue;
21895
22070
  } catch {
21896
22071
  continue;
21897
22072
  }
21898
- const skillMdRelative = path29.join(entry.name, "SKILL.md");
22073
+ const skillMdRelative = path30.join(entry.name, "SKILL.md");
21899
22074
  let skillMdPath;
21900
22075
  try {
21901
22076
  skillMdPath = resolveContainedPath(dir.root, skillMdRelative);
@@ -21921,7 +22096,7 @@ function discoverSkills(cwd) {
21921
22096
  description = desc;
21922
22097
  if (parseError) {
21923
22098
  diagnostics.push({
21924
- path: path29.dirname(skillMdPath),
22099
+ path: path30.dirname(skillMdPath),
21925
22100
  field: "frontmatter",
21926
22101
  reason: parseError,
21927
22102
  severity: "error"
@@ -21943,7 +22118,7 @@ function discoverSkills(cwd) {
21943
22118
  }
21944
22119
  const filtered = [];
21945
22120
  for (const skill of results) {
21946
- const validation = validateSkillFrontmatter(path29.dirname(skill.path));
22121
+ const validation = validateSkillFrontmatter(path30.dirname(skill.path));
21947
22122
  if (validation.ok) {
21948
22123
  filtered.push(skill);
21949
22124
  } else {
@@ -21962,7 +22137,7 @@ var init_discover_skills = __esm({
21962
22137
  init_internal_error();
21963
22138
  init_safe_paths();
21964
22139
  init_validate();
21965
- PACKAGE_SKILLS_DIR2 = path29.resolve(path29.dirname(fileURLToPath5(import.meta.url)), "..", "..", "skills");
22140
+ PACKAGE_SKILLS_DIR2 = path30.resolve(path30.dirname(fileURLToPath5(import.meta.url)), "..", "..", "skills");
21966
22141
  CACHE_TTL_MS = 3e4;
21967
22142
  cache = null;
21968
22143
  lastDiagnostics = [];
@@ -22070,9 +22245,9 @@ var init_capability_inventory = __esm({
22070
22245
 
22071
22246
  // src/runtime/foreground-control.ts
22072
22247
  import * as fs36 from "node:fs";
22073
- import * as path30 from "node:path";
22248
+ import * as path31 from "node:path";
22074
22249
  function foregroundControlPath(manifest) {
22075
- return path30.join(manifest.stateRoot, "foreground-control.json");
22250
+ return path31.join(manifest.stateRoot, "foreground-control.json");
22076
22251
  }
22077
22252
  function readLastRequest(controlPath) {
22078
22253
  if (!fs36.existsSync(controlPath)) return void 0;
@@ -22101,7 +22276,7 @@ function readForegroundControlStatus(manifest, tasks) {
22101
22276
  function writeForegroundInterruptRequest(manifest, reason = "User requested foreground interrupt.") {
22102
22277
  const controlPath = foregroundControlPath(manifest);
22103
22278
  const lockDir = `${controlPath}.lock`;
22104
- const pidFile = path30.join(lockDir, "pid");
22279
+ const pidFile = path31.join(lockDir, "pid");
22105
22280
  let requests = [];
22106
22281
  const acquireLock = () => {
22107
22282
  const timeout = 5e3;
@@ -22194,7 +22369,7 @@ function writeForegroundInterruptRequest(manifest, reason = "User requested fore
22194
22369
  reason,
22195
22370
  acknowledged: false
22196
22371
  };
22197
- fs36.mkdirSync(path30.dirname(controlPath), { recursive: true });
22372
+ fs36.mkdirSync(path31.dirname(controlPath), { recursive: true });
22198
22373
  atomicWriteFile(controlPath, `${JSON.stringify({ requests: [...requests, request] }, null, 2)}
22199
22374
  `);
22200
22375
  appendEvent(manifest.eventsPath, {
@@ -23387,7 +23562,7 @@ var init_model_scope = __esm({
23387
23562
  // src/runtime/model-fallback.ts
23388
23563
  import * as fs38 from "node:fs";
23389
23564
  import * as os11 from "node:os";
23390
- import * as path31 from "node:path";
23565
+ import * as path32 from "node:path";
23391
23566
  function modelInfoFromUnknown(value) {
23392
23567
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
23393
23568
  const record = value;
@@ -23429,10 +23604,10 @@ function piAgentDir() {
23429
23604
  const envDir = process.env.PI_CODING_AGENT_DIR?.trim();
23430
23605
  if (envDir) {
23431
23606
  if (envDir === "~") return os11.homedir();
23432
- if (envDir.startsWith("~/")) return path31.join(os11.homedir(), envDir.slice(2));
23607
+ if (envDir.startsWith("~/")) return path32.join(os11.homedir(), envDir.slice(2));
23433
23608
  return envDir;
23434
23609
  }
23435
- return path31.join(os11.homedir(), ".pi", "agent");
23610
+ return path32.join(os11.homedir(), ".pi", "agent");
23436
23611
  }
23437
23612
  function settingsModelInfo(settings) {
23438
23613
  if (typeof settings?.defaultProvider !== "string" || typeof settings.defaultModel !== "string") return void 0;
@@ -23463,8 +23638,8 @@ function modelsJsonInfos(modelsJson) {
23463
23638
  }
23464
23639
  function configuredModelInfosFromPiConfig(cwd) {
23465
23640
  const agentDir = piAgentDir();
23466
- const globalSettings = readJsonObject(path31.join(agentDir, "settings.json"));
23467
- const projectSettings = cwd ? readJsonObject(path31.join(cwd, ".pi", "settings.json")) : void 0;
23641
+ const globalSettings = readJsonObject(path32.join(agentDir, "settings.json"));
23642
+ const projectSettings = cwd ? readJsonObject(path32.join(cwd, ".pi", "settings.json")) : void 0;
23468
23643
  const effectiveSettings = {
23469
23644
  ...globalSettings ?? {},
23470
23645
  ...projectSettings ?? {}
@@ -23472,7 +23647,7 @@ function configuredModelInfosFromPiConfig(cwd) {
23472
23647
  const defaultModel = settingsModelInfo(effectiveSettings);
23473
23648
  return uniqueModelInfos([
23474
23649
  ...defaultModel ? [defaultModel] : [],
23475
- ...modelsJsonInfos(readJsonObject(path31.join(agentDir, "models.json")))
23650
+ ...modelsJsonInfos(readJsonObject(path32.join(agentDir, "models.json")))
23476
23651
  ]);
23477
23652
  }
23478
23653
  function splitThinkingSuffix(model) {
@@ -23677,9 +23852,9 @@ var init_sensitive_paths = __esm({
23677
23852
 
23678
23853
  // src/runtime/sidechain-output.ts
23679
23854
  import * as fs39 from "node:fs";
23680
- import * as path32 from "node:path";
23855
+ import * as path33 from "node:path";
23681
23856
  function writeSidechainEntry(filePath, entry) {
23682
- fs39.mkdirSync(path32.dirname(filePath), { recursive: true });
23857
+ fs39.mkdirSync(path33.dirname(filePath), { recursive: true });
23683
23858
  fs39.appendFileSync(
23684
23859
  filePath,
23685
23860
  `${JSON.stringify(redactSecrets({ isSidechain: true, timestamp: (/* @__PURE__ */ new Date()).toISOString(), ...entry }))}
@@ -23689,7 +23864,7 @@ function writeSidechainEntry(filePath, entry) {
23689
23864
  }
23690
23865
  function sidechainOutputPath(stateRoot, taskId) {
23691
23866
  if (!isSafePathId(taskId)) throw new Error(`Invalid taskId: ${taskId}`);
23692
- return path32.join(stateRoot, "agents", taskId, "sidechain.output.jsonl");
23867
+ return path33.join(stateRoot, "agents", taskId, "sidechain.output.jsonl");
23693
23868
  }
23694
23869
  function eventToSidechainType(event) {
23695
23870
  if (!event || typeof event !== "object" || Array.isArray(event)) return void 0;
@@ -23708,12 +23883,12 @@ var init_sidechain_output = __esm({
23708
23883
 
23709
23884
  // src/runtime/streaming-output.ts
23710
23885
  import * as fs40 from "node:fs";
23711
- import * as path33 from "node:path";
23886
+ import * as path34 from "node:path";
23712
23887
  function createStreamingOutput(manifest, taskId) {
23713
23888
  if (!isSafePathId(taskId)) throw new Error(`Invalid taskId: ${taskId}`);
23714
- const outputDir = path33.join(manifest.artifactsRoot, "streaming");
23889
+ const outputDir = path34.join(manifest.artifactsRoot, "streaming");
23715
23890
  fs40.mkdirSync(outputDir, { recursive: true });
23716
- const outputPath = path33.join(outputDir, `${taskId}.md`);
23891
+ const outputPath = path34.join(outputDir, `${taskId}.md`);
23717
23892
  let buffer = "";
23718
23893
  let closed = false;
23719
23894
  return {
@@ -27008,8 +27183,8 @@ var require_utils = __commonJS({
27008
27183
  }
27009
27184
  return ind;
27010
27185
  }
27011
- function removeDotSegments(path86) {
27012
- let input = path86;
27186
+ function removeDotSegments(path87) {
27187
+ let input = path87;
27013
27188
  const output = [];
27014
27189
  let nextSlash = -1;
27015
27190
  let len = 0;
@@ -27261,8 +27436,8 @@ var require_schemes = __commonJS({
27261
27436
  wsComponent.secure = void 0;
27262
27437
  }
27263
27438
  if (wsComponent.resourceName) {
27264
- const [path86, query] = wsComponent.resourceName.split("?");
27265
- wsComponent.path = path86 && path86 !== "/" ? path86 : void 0;
27439
+ const [path87, query] = wsComponent.resourceName.split("?");
27440
+ wsComponent.path = path87 && path87 !== "/" ? path87 : void 0;
27266
27441
  wsComponent.query = query;
27267
27442
  wsComponent.resourceName = void 0;
27268
27443
  }
@@ -30496,7 +30671,7 @@ var init_yield_handler = __esm({
30496
30671
 
30497
30672
  // src/runtime/live-session-runtime.ts
30498
30673
  import * as fs41 from "node:fs";
30499
- import * as path34 from "node:path";
30674
+ import * as path35 from "node:path";
30500
30675
  function loadLiveSessionModule() {
30501
30676
  if (!liveSessionModulePromise) {
30502
30677
  liveSessionModulePromise = import("@earendil-works/pi-coding-agent");
@@ -30509,7 +30684,7 @@ function appendTranscript2(filePath, event) {
30509
30684
  }
30510
30685
  async function appendTranscriptAsync(filePath, event) {
30511
30686
  try {
30512
- await fs41.promises.mkdir(path34.dirname(filePath), { recursive: true });
30687
+ await fs41.promises.mkdir(path35.dirname(filePath), { recursive: true });
30513
30688
  const content = `${JSON.stringify(redactSecrets(event))}
30514
30689
  `;
30515
30690
  await fs41.promises.appendFile(filePath, content, "utf-8");
@@ -33167,7 +33342,7 @@ var init_scheduler = __esm({
33167
33342
  // src/runtime/settings-store.ts
33168
33343
  import * as fs43 from "node:fs";
33169
33344
  import { homedir as homedir8 } from "node:os";
33170
- import * as path35 from "node:path";
33345
+ import * as path36 from "node:path";
33171
33346
  function validateScheduledJob(job) {
33172
33347
  if (!job || typeof job !== "object") return false;
33173
33348
  const obj = job;
@@ -33201,10 +33376,10 @@ function sanitizeSettings(raw) {
33201
33376
  return out;
33202
33377
  }
33203
33378
  function globalPath() {
33204
- return path35.join(homedir8(), ".pi", "crew-settings.json");
33379
+ return path36.join(homedir8(), ".pi", "crew-settings.json");
33205
33380
  }
33206
33381
  function projectPath(cwd) {
33207
- return path35.join(cwd, ".pi", "crew-settings.json");
33382
+ return path36.join(cwd, ".pi", "crew-settings.json");
33208
33383
  }
33209
33384
  function readSettingsFile(filePath) {
33210
33385
  if (!fs43.existsSync(filePath)) return {};
@@ -33223,7 +33398,7 @@ function loadCrewSettings(cwd = process.cwd()) {
33223
33398
  }
33224
33399
  function updateCrewSettings(cwd, mutator) {
33225
33400
  const p = projectPath(cwd);
33226
- fs43.mkdirSync(path35.dirname(p), { recursive: true });
33401
+ fs43.mkdirSync(path36.dirname(p), { recursive: true });
33227
33402
  return withFileLockSync(p, () => {
33228
33403
  const fresh = loadCrewSettings(cwd);
33229
33404
  const next = mutator(fresh);
@@ -34108,11 +34283,11 @@ function resolveSchemaKey(schema, key) {
34108
34283
  childSchema: childSchemas[0]
34109
34284
  };
34110
34285
  }
34111
- function findUnknownConfigKeyPaths(value, schema, depth = 0, path86 = []) {
34286
+ function findUnknownConfigKeyPaths(value, schema, depth = 0, path87 = []) {
34112
34287
  if (!isRecord2(value) || depth > MAX_CONFIG_KEY_DEPTH) return [];
34113
34288
  const unknownPaths = [];
34114
34289
  for (const [key, childValue] of Object.entries(value)) {
34115
- const childPath = [...path86, key];
34290
+ const childPath = [...path87, key];
34116
34291
  const resolution = resolveSchemaKey(schema, key);
34117
34292
  if (!resolution.allowed) {
34118
34293
  unknownPaths.push(childPath);
@@ -34124,8 +34299,8 @@ function findUnknownConfigKeyPaths(value, schema, depth = 0, path86 = []) {
34124
34299
  }
34125
34300
  return unknownPaths;
34126
34301
  }
34127
- function isAgentOverrideKeyPath(path86) {
34128
- return path86.length === 4 && path86[0] === "agents" && path86[1] === "overrides";
34302
+ function isAgentOverrideKeyPath(path87) {
34303
+ return path87.length === 4 && path87[0] === "agents" && path87[1] === "overrides";
34129
34304
  }
34130
34305
  function extractConfigReferences(config) {
34131
34306
  const agents = /* @__PURE__ */ new Set();
@@ -34415,7 +34590,7 @@ var init_zombie_scanner = __esm({
34415
34590
 
34416
34591
  // src/schema/team-tool-schema.ts
34417
34592
  import { Type as Type5 } from "@sinclair/typebox";
34418
- var SkillOverride, FreeformConfig, sharedFields, ACTION_DESCRIPTION, runActions, statusActions, controlActions, manageActions, automateActions, RunDomainParams, StatusDomainParams, ControlDomainParams, ManageDomainParams, AutomateDomainParams, TeamToolParams;
34593
+ var SkillOverride, FreeformConfig, sharedFields, ACTION_DESCRIPTION, runActions, statusActions, controlActions, manageActions, automateActions, RunDomainParams, StatusDomainParams, ControlDomainParams, ManageDomainParams, AutomateDomainParams, allActionLiterals, TeamToolParams;
34419
34594
  var init_team_tool_schema = __esm({
34420
34595
  "src/schema/team-tool-schema.ts"() {
34421
34596
  "use strict";
@@ -34717,13 +34892,16 @@ var init_team_tool_schema = __esm({
34717
34892
  ControlDomainParams = Type5.Object({ action: controlActions, ...sharedFields }, { additionalProperties: true });
34718
34893
  ManageDomainParams = Type5.Object({ action: manageActions, ...sharedFields }, { additionalProperties: true });
34719
34894
  AutomateDomainParams = Type5.Object({ action: automateActions, ...sharedFields }, { additionalProperties: true });
34720
- TeamToolParams = Type5.Union([
34721
- RunDomainParams,
34722
- StatusDomainParams,
34723
- ControlDomainParams,
34724
- ManageDomainParams,
34725
- AutomateDomainParams
34726
- ]);
34895
+ allActionLiterals = [runActions, statusActions, controlActions, manageActions, automateActions].flatMap(
34896
+ (set) => set.anyOf ?? []
34897
+ );
34898
+ TeamToolParams = Type5.Object(
34899
+ {
34900
+ action: Type5.Optional(Type5.Union(allActionLiterals, { description: ACTION_DESCRIPTION })),
34901
+ ...sharedFields
34902
+ },
34903
+ { additionalProperties: true }
34904
+ );
34727
34905
  }
34728
34906
  });
34729
34907
 
@@ -34877,7 +35055,7 @@ var init_validate_resources = __esm({
34877
35055
  // src/extension/team-tool/doctor.ts
34878
35056
  import { execFileSync as execFileSync2, spawnSync } from "node:child_process";
34879
35057
  import * as fs45 from "node:fs";
34880
- import * as path36 from "node:path";
35058
+ import * as path37 from "node:path";
34881
35059
  function firstOutputLine(stdout, stderr) {
34882
35060
  const output = `${stdout ?? ""}
34883
35061
  ${stderr ?? ""}`.trim();
@@ -35038,12 +35216,12 @@ function buildTeamDoctorReport(input) {
35038
35216
  {
35039
35217
  label: "project state root",
35040
35218
  ok: true,
35041
- detail: path36.join(projectCrewRoot(input.cwd), DEFAULT_PATHS.state.runsSubdir)
35219
+ detail: path37.join(projectCrewRoot(input.cwd), DEFAULT_PATHS.state.runsSubdir)
35042
35220
  },
35043
35221
  {
35044
35222
  label: "artifacts root",
35045
35223
  ok: true,
35046
- detail: path36.join(projectCrewRoot(input.cwd), DEFAULT_PATHS.state.artifactsSubdir)
35224
+ detail: path37.join(projectCrewRoot(input.cwd), DEFAULT_PATHS.state.artifactsSubdir)
35047
35225
  }
35048
35226
  ];
35049
35227
  }),
@@ -35347,7 +35525,7 @@ var init_markers = __esm({
35347
35525
  // src/worktree/cleanup.ts
35348
35526
  import { execFileSync as execFileSync3 } from "node:child_process";
35349
35527
  import * as fs47 from "node:fs";
35350
- import * as path37 from "node:path";
35528
+ import * as path38 from "node:path";
35351
35529
  function sanitizeBranchPart(value) {
35352
35530
  return value.toLowerCase().replace(/[^a-z0-9._/-]+/g, "-").replace(/^-+|-+$/g, "") || "task";
35353
35531
  }
@@ -35391,7 +35569,7 @@ function captureDiff(worktreePath) {
35391
35569
  }
35392
35570
  function cleanupRunWorktrees(manifest, options = {}) {
35393
35571
  const sanitizedRunId = manifest.runId.replace(/[^a-zA-Z0-9._-]/g, "-").replace(/^-+|-+$/g, "") || "run";
35394
- const worktreeRoot = path37.join(projectCrewRoot(manifest.cwd), DEFAULT_PATHS.state.worktreesSubdir, sanitizedRunId);
35572
+ const worktreeRoot = path38.join(projectCrewRoot(manifest.cwd), DEFAULT_PATHS.state.worktreesSubdir, sanitizedRunId);
35395
35573
  const result4 = {
35396
35574
  removed: [],
35397
35575
  preserved: [],
@@ -35404,7 +35582,7 @@ function cleanupRunWorktrees(manifest, options = {}) {
35404
35582
  if (options.signal?.aborted) break;
35405
35583
  if (!entry.isDirectory()) continue;
35406
35584
  if (options.signal?.aborted) break;
35407
- const worktreePath = path37.join(worktreeRoot, entry.name);
35585
+ const worktreePath = path38.join(worktreeRoot, entry.name);
35408
35586
  if (options.signal?.aborted) break;
35409
35587
  const dirty = isDirty(worktreePath);
35410
35588
  const branchName = `pi-crew/${manifest.runId}/${sanitizeBranchPart(entry.name)}`;
@@ -35624,15 +35802,15 @@ var init_cleanup = __esm({
35624
35802
 
35625
35803
  // src/extension/import-index.ts
35626
35804
  import * as fs48 from "node:fs";
35627
- import * as path38 from "node:path";
35805
+ import * as path39 from "node:path";
35628
35806
  function readEntry(root, scope, runId) {
35629
35807
  if (!isSafePathId(runId)) return void 0;
35630
35808
  let bundlePath;
35631
35809
  let summaryPath;
35632
35810
  try {
35633
35811
  const entryRoot = resolveRealContainedPath(root, runId);
35634
- bundlePath = resolveRealContainedPath(root, path38.join(runId, "run-export.json"));
35635
- summaryPath = path38.join(entryRoot, "README.md");
35812
+ bundlePath = resolveRealContainedPath(root, path39.join(runId, "run-export.json"));
35813
+ summaryPath = path39.join(entryRoot, "README.md");
35636
35814
  } catch {
35637
35815
  return void 0;
35638
35816
  }
@@ -35659,15 +35837,15 @@ function collect(root, scope) {
35659
35837
  if (!fs48.existsSync(root)) return [];
35660
35838
  try {
35661
35839
  if (fs48.lstatSync(root).isSymbolicLink()) return [];
35662
- resolveRealContainedPath(path38.dirname(root), path38.basename(root));
35840
+ resolveRealContainedPath(path39.dirname(root), path39.basename(root));
35663
35841
  } catch {
35664
35842
  return [];
35665
35843
  }
35666
35844
  return fs48.readdirSync(root).filter((entry) => isSafePathId(entry)).map((entry) => readEntry(root, scope, entry)).filter((entry) => entry !== void 0);
35667
35845
  }
35668
35846
  function listImportedRuns(cwd) {
35669
- const projectRoot = path38.join(projectCrewRoot(cwd), DEFAULT_PATHS.state.importsSubdir);
35670
- const userRoot = path38.join(userCrewRoot(), DEFAULT_PATHS.state.importsSubdir);
35847
+ const projectRoot = path39.join(projectCrewRoot(cwd), DEFAULT_PATHS.state.importsSubdir);
35848
+ const userRoot = path39.join(userCrewRoot(), DEFAULT_PATHS.state.importsSubdir);
35671
35849
  return [...collect(userRoot, "user"), ...collect(projectRoot, "project")].sort(
35672
35850
  (a, b) => (b.importedAt ?? "").localeCompare(a.importedAt ?? "")
35673
35851
  );
@@ -35685,7 +35863,7 @@ var init_import_index = __esm({
35685
35863
  import * as crypto4 from "node:crypto";
35686
35864
  import * as fs49 from "node:fs";
35687
35865
  import * as os12 from "node:os";
35688
- import * as path39 from "node:path";
35866
+ import * as path40 from "node:path";
35689
35867
  function escapeRegex(str) {
35690
35868
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
35691
35869
  }
@@ -35749,7 +35927,7 @@ function exportRunBundle(manifest, tasks) {
35749
35927
  ""
35750
35928
  ].join("\n")
35751
35929
  });
35752
- fs49.statSync(path39.dirname(json.path));
35930
+ fs49.statSync(path40.dirname(json.path));
35753
35931
  return { jsonPath: json.path, markdownPath: markdown.path };
35754
35932
  }
35755
35933
  var init_run_export = __esm({
@@ -35992,13 +36170,13 @@ var init_run_bundle_schema = __esm({
35992
36170
  // src/extension/run-import.ts
35993
36171
  import * as crypto5 from "node:crypto";
35994
36172
  import * as fs50 from "node:fs";
35995
- import * as path40 from "node:path";
36173
+ import * as path41 from "node:path";
35996
36174
  function importRoot(cwd, scope) {
35997
36175
  const base = scope === "project" ? projectCrewRoot(cwd) : userCrewRoot();
35998
- return path40.join(base, DEFAULT_PATHS.state.importsSubdir);
36176
+ return path41.join(base, DEFAULT_PATHS.state.importsSubdir);
35999
36177
  }
36000
36178
  function importRunBundle(cwd, bundlePath, scope = "project") {
36001
- const resolvedPath = path40.isAbsolute(bundlePath) ? bundlePath : path40.resolve(cwd, bundlePath);
36179
+ const resolvedPath = path41.isAbsolute(bundlePath) ? bundlePath : path41.resolve(cwd, bundlePath);
36002
36180
  const allowedBases = [];
36003
36181
  try {
36004
36182
  allowedBases.push(userCrewRoot());
@@ -36045,7 +36223,7 @@ function importRunBundle(cwd, bundlePath, scope = "project") {
36045
36223
  );
36046
36224
  let conflictReport;
36047
36225
  try {
36048
- const existingManifestPath = path40.join(importRoot(cwd, scope), runId, "run-export.json");
36226
+ const existingManifestPath = path41.join(importRoot(cwd, scope), runId, "run-export.json");
36049
36227
  if (fs50.existsSync(existingManifestPath)) {
36050
36228
  const existingRaw = JSON.parse(fs50.readFileSync(existingManifestPath, "utf-8"));
36051
36229
  conflictReport = detectImportConflicts(
@@ -36061,13 +36239,13 @@ function importRunBundle(cwd, bundlePath, scope = "project") {
36061
36239
  const importsRoot = importRoot(cwd, scope);
36062
36240
  fs50.mkdirSync(importsRoot, { recursive: true });
36063
36241
  if (fs50.lstatSync(importsRoot).isSymbolicLink()) throw new Error(`Invalid import root: ${importsRoot}`);
36064
- resolveRealContainedPath(path40.dirname(importsRoot), path40.basename(importsRoot));
36242
+ resolveRealContainedPath(path41.dirname(importsRoot), path41.basename(importsRoot));
36065
36243
  const root = resolveContainedRelativePath(importsRoot, runId, "runId");
36066
36244
  fs50.mkdirSync(root, { recursive: true });
36067
36245
  if (fs50.lstatSync(root).isSymbolicLink()) throw new Error(`Invalid import directory: ${root}`);
36068
36246
  resolveRealContainedPath(importsRoot, runId);
36069
- const targetJson = path40.join(root, "run-export.json");
36070
- const targetSummary = path40.join(root, "README.md");
36247
+ const targetJson = path41.join(root, "run-export.json");
36248
+ const targetSummary = path41.join(root, "README.md");
36071
36249
  for (const target of [targetJson, targetSummary]) {
36072
36250
  if (fs50.existsSync(target) && fs50.lstatSync(target).isSymbolicLink()) throw new Error(`Invalid import target: ${target}`);
36073
36251
  }
@@ -36116,13 +36294,13 @@ var init_run_import = __esm({
36116
36294
 
36117
36295
  // src/extension/run-maintenance.ts
36118
36296
  import * as fs51 from "node:fs";
36119
- import * as path41 from "node:path";
36297
+ import * as path42 from "node:path";
36120
36298
  function isFinished(run) {
36121
36299
  return run.status === "completed" || run.status === "failed" || run.status === "cancelled";
36122
36300
  }
36123
36301
  function isSafeToPrune(cwd, run) {
36124
36302
  try {
36125
- const crewRoot = run.stateRoot.startsWith(userCrewRoot() + path41.sep) ? userCrewRoot() : projectCrewRoot(cwd);
36303
+ const crewRoot = run.stateRoot.startsWith(userCrewRoot() + path42.sep) ? userCrewRoot() : projectCrewRoot(cwd);
36126
36304
  resolveRealContainedPath(crewRoot, run.stateRoot);
36127
36305
  resolveRealContainedPath(crewRoot, run.artifactsRoot);
36128
36306
  return true;
@@ -36132,8 +36310,8 @@ function isSafeToPrune(cwd, run) {
36132
36310
  }
36133
36311
  function appendPruneAudit(cwd, payload) {
36134
36312
  try {
36135
- const filePath = path41.join(projectCrewRoot(cwd), "audit", "prune.jsonl");
36136
- fs51.mkdirSync(path41.dirname(filePath), { recursive: true });
36313
+ const filePath = path42.join(projectCrewRoot(cwd), "audit", "prune.jsonl");
36314
+ fs51.mkdirSync(path42.dirname(filePath), { recursive: true });
36137
36315
  fs51.appendFileSync(filePath, `${JSON.stringify(redactSecrets({ ...payload, auditedAt: (/* @__PURE__ */ new Date()).toISOString() }))}
36138
36316
  `, "utf-8");
36139
36317
  return filePath;
@@ -36185,14 +36363,14 @@ function pruneFinishedRuns(cwd, keep, options = {}) {
36185
36363
  }
36186
36364
  function pruneUserLevelRuns(keep) {
36187
36365
  const crewRoot = userCrewRoot();
36188
- const runsRoot = path41.join(crewRoot, DEFAULT_PATHS.state.runsSubdir);
36366
+ const runsRoot = path42.join(crewRoot, DEFAULT_PATHS.state.runsSubdir);
36189
36367
  if (!fs51.existsSync(runsRoot)) return { kept: [], removed: [] };
36190
36368
  const MAX_DIRS = 500;
36191
36369
  const finished = [];
36192
36370
  const ghostRemoved = [];
36193
36371
  const dirs = fs51.readdirSync(runsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && isSafePathId(entry.name)).slice(0, MAX_DIRS).map((entry) => entry.name);
36194
36372
  for (const dir of dirs) {
36195
- const manifestPath = path41.join(runsRoot, dir, DEFAULT_PATHS.state.manifestFile);
36373
+ const manifestPath = path42.join(runsRoot, dir, DEFAULT_PATHS.state.manifestFile);
36196
36374
  let manifest;
36197
36375
  try {
36198
36376
  manifest = JSON.parse(fs51.readFileSync(manifestPath, "utf-8"));
@@ -36201,7 +36379,7 @@ function pruneUserLevelRuns(keep) {
36201
36379
  }
36202
36380
  const isActive = manifest.status === "queued" || manifest.status === "running" || manifest.status === "planning";
36203
36381
  if (isActive && manifest.cwd && !fs51.existsSync(manifest.cwd)) {
36204
- fs51.rmSync(path41.join(runsRoot, dir), {
36382
+ fs51.rmSync(path42.join(runsRoot, dir), {
36205
36383
  recursive: true,
36206
36384
  force: true
36207
36385
  });
@@ -36248,7 +36426,7 @@ var init_run_maintenance = __esm({
36248
36426
 
36249
36427
  // src/extension/team-tool/lifecycle-actions.ts
36250
36428
  import * as fs52 from "node:fs";
36251
- import * as path42 from "node:path";
36429
+ import * as path43 from "node:path";
36252
36430
  function handleWorktrees(params, ctx) {
36253
36431
  if (!params.runId) return result("Worktrees requires runId.", { action: "worktrees", status: "error" }, true);
36254
36432
  const loaded = loadRunManifestById(ctx.cwd, params.runId);
@@ -36441,7 +36619,7 @@ async function handleForget(params, ctx) {
36441
36619
  logInternalError("team-tool.handleForget.killAsync", error, `runId=${loaded.manifest.runId},pid=${asyncPid}`);
36442
36620
  }
36443
36621
  }
36444
- const crewRoot = loaded.manifest.stateRoot.startsWith(userCrewRoot() + path42.sep) ? userCrewRoot() : projectCrewRoot(loaded.manifest.cwd);
36622
+ const crewRoot = loaded.manifest.stateRoot.startsWith(userCrewRoot() + path43.sep) ? userCrewRoot() : projectCrewRoot(loaded.manifest.cwd);
36445
36623
  const resolvedStateRoot = resolveRealContainedPath(crewRoot, loaded.manifest.stateRoot);
36446
36624
  const resolvedArtifactsRoot = resolveRealContainedPath(crewRoot, loaded.manifest.artifactsRoot);
36447
36625
  fs52.rmSync(resolvedStateRoot, { recursive: true, force: true });
@@ -36485,7 +36663,7 @@ function handleProjectCleanup(params, ctx) {
36485
36663
  );
36486
36664
  }
36487
36665
  const lines = ["Project cleanup for pi-crew:"];
36488
- const guidancePath = path42.join(cwd, "AGENTS.md");
36666
+ const guidancePath = path43.join(cwd, "AGENTS.md");
36489
36667
  const guidanceResult = dryRun ? {
36490
36668
  path: guidancePath,
36491
36669
  modified: fs52.existsSync(guidancePath),
@@ -36517,7 +36695,7 @@ function handleProjectCleanup(params, ctx) {
36517
36695
  lines.push(` - ERROR: could not resolve ${crewRoot} (skipped)`);
36518
36696
  return result(lines.join("\n"), { action: "cleanup", status: "ok", scope }, false);
36519
36697
  }
36520
- if (!resolved.endsWith(path42.sep + ".crew") && !resolved.endsWith("/teams") && path42.basename(resolved) !== ".crew") {
36698
+ if (!resolved.endsWith(path43.sep + ".crew") && !resolved.endsWith("/teams") && path43.basename(resolved) !== ".crew") {
36521
36699
  lines.push(` - ERROR: refused to remove ${resolved} (does not look like a .crew dir) \u2014 skipped`);
36522
36700
  } else {
36523
36701
  if (!dryRun) {
@@ -36571,7 +36749,7 @@ function handleUserCleanup(params, ctx) {
36571
36749
  } else {
36572
36750
  lines.push(" - (not present \u2014 nothing to do)");
36573
36751
  }
36574
- const userConfigPath = path42.join(userPiRoot(), "pi-crew.json");
36752
+ const userConfigPath = path43.join(userPiRoot(), "pi-crew.json");
36575
36753
  lines.push("pi-crew global config:");
36576
36754
  if (!fs52.existsSync(userConfigPath)) {
36577
36755
  lines.push(` - (not present at ${userConfigPath} \u2014 nothing to do)`);
@@ -36587,14 +36765,14 @@ function handleUserCleanup(params, ctx) {
36587
36765
  }
36588
36766
  lines.push(` - ${dryRun ? "would remove" : "removed"}: ${userConfigPath}`);
36589
36767
  }
36590
- const agentsDir = path42.join(userPiRoot(), "agents");
36768
+ const agentsDir = path43.join(userPiRoot(), "agents");
36591
36769
  lines.push("pi-crew test junk in agents dir:");
36592
36770
  const bakJunk = [];
36593
36771
  if (fs52.existsSync(agentsDir)) {
36594
36772
  try {
36595
36773
  for (const entry of fs52.readdirSync(agentsDir)) {
36596
36774
  if (/^.*\.md\.bak-\d{17,}-[0-9a-f]+$/i.test(entry)) {
36597
- bakJunk.push(path42.join(agentsDir, entry));
36775
+ bakJunk.push(path43.join(agentsDir, entry));
36598
36776
  }
36599
36777
  }
36600
36778
  } catch {
@@ -36608,7 +36786,7 @@ function handleUserCleanup(params, ctx) {
36608
36786
  try {
36609
36787
  fs52.rmSync(junk, { force: true });
36610
36788
  } catch (e) {
36611
- lines.push(` - ERROR removing ${path42.basename(junk)}: ${e.message}`);
36789
+ lines.push(` - ERROR removing ${path43.basename(junk)}: ${e.message}`);
36612
36790
  }
36613
36791
  }
36614
36792
  }
@@ -36632,7 +36810,7 @@ function dirSize(dir) {
36632
36810
  continue;
36633
36811
  }
36634
36812
  for (const entry of entries) {
36635
- const full = path42.join(cur, entry);
36813
+ const full = path43.join(cur, entry);
36636
36814
  try {
36637
36815
  const stat2 = fs52.statSync(full);
36638
36816
  if (stat2.isDirectory()) stack.push(full);
@@ -37057,7 +37235,7 @@ var init_workflow_serializer = __esm({
37057
37235
  // src/extension/management.ts
37058
37236
  import * as crypto6 from "node:crypto";
37059
37237
  import * as fs53 from "node:fs";
37060
- import * as path43 from "node:path";
37238
+ import * as path44 from "node:path";
37061
37239
  function invalidateResourceCaches() {
37062
37240
  invalidateAgentDiscoveryCache();
37063
37241
  invalidateTeamDiscoveryCache();
@@ -37068,9 +37246,9 @@ function result2(text, status = "ok", isError = false) {
37068
37246
  }
37069
37247
  function scopeDir(ctx, resource, scope) {
37070
37248
  const base = scope === "user" ? userPiRoot() : projectCrewRoot(ctx.cwd);
37071
- if (resource === "agent") return path43.join(base, "agents");
37072
- if (resource === "team") return path43.join(base, "teams");
37073
- return path43.join(base, "workflows");
37249
+ if (resource === "agent") return path44.join(base, "agents");
37250
+ if (resource === "team") return path44.join(base, "teams");
37251
+ return path44.join(base, "workflows");
37074
37252
  }
37075
37253
  function extensionFor(resource) {
37076
37254
  if (resource === "agent") return ".md";
@@ -37085,7 +37263,7 @@ function backupFile(filePath) {
37085
37263
  return backupPath;
37086
37264
  }
37087
37265
  function targetPath(ctx, resource, scope, name) {
37088
- return path43.join(scopeDir(ctx, resource, scope), `${name}${extensionFor(resource)}`);
37266
+ return path44.join(scopeDir(ctx, resource, scope), `${name}${extensionFor(resource)}`);
37089
37267
  }
37090
37268
  function parseStringArray(value) {
37091
37269
  if (typeof value === "string")
@@ -37201,7 +37379,7 @@ function walkTsFiles(dir) {
37201
37379
  const results = [];
37202
37380
  if (!fs53.existsSync(dir)) return results;
37203
37381
  for (const entry of fs53.readdirSync(dir, { withFileTypes: true })) {
37204
- const fullPath = path43.join(dir, entry.name);
37382
+ const fullPath = path44.join(dir, entry.name);
37205
37383
  if (entry.isDirectory()) {
37206
37384
  results.push(...walkTsFiles(fullPath));
37207
37385
  } else if (entry.name.endsWith(".ts") || entry.name.endsWith(".md")) {
@@ -37249,7 +37427,7 @@ function updateReferencesForRename(ctx, resource, oldName, newName, scope, dryRu
37249
37427
  atomicWriteFile(workflow.filePath, serializeWorkflow({ ...workflow, steps: newSteps }));
37250
37428
  }
37251
37429
  }
37252
- const testDir = scope === "user" ? path43.join(projectCrewRoot(ctx.cwd), "test") : path43.join(ctx.cwd, "test", "fixtures");
37430
+ const testDir = scope === "user" ? path44.join(projectCrewRoot(ctx.cwd), "test") : path44.join(ctx.cwd, "test", "fixtures");
37253
37431
  if (fs53.existsSync(testDir)) {
37254
37432
  for (const fixture of walkTsFiles(testDir)) {
37255
37433
  const content = fs53.readFileSync(fixture, "utf-8");
@@ -37301,7 +37479,7 @@ function handleCreate(params, ctx) {
37301
37479
  const scope = cfg.scope === "project" ? "project" : "user";
37302
37480
  const filePath = targetPath(ctx, params.resource, scope, name);
37303
37481
  if (fs53.existsSync(filePath)) return result2(`File already exists: ${filePath}`, "error", true);
37304
- fs53.mkdirSync(path43.dirname(filePath), { recursive: true });
37482
+ fs53.mkdirSync(path44.dirname(filePath), { recursive: true });
37305
37483
  let content;
37306
37484
  if (params.resource === "agent") {
37307
37485
  const agent = {
@@ -37526,7 +37704,7 @@ var init_management = __esm({
37526
37704
 
37527
37705
  // src/extension/project-init.ts
37528
37706
  import * as fs54 from "node:fs";
37529
- import * as path44 from "node:path";
37707
+ import * as path45 from "node:path";
37530
37708
  function ensureDir(dir, createdDirs) {
37531
37709
  if (!fs54.existsSync(dir)) {
37532
37710
  fs54.mkdirSync(dir, { recursive: true });
@@ -37536,11 +37714,11 @@ function ensureDir(dir, createdDirs) {
37536
37714
  }
37537
37715
  }
37538
37716
  function copyBuiltinDir(kind, targetDir, overwrite, copiedFiles, skippedFiles) {
37539
- const sourceDir = path44.join(packageRoot(), kind);
37717
+ const sourceDir = path45.join(packageRoot(), kind);
37540
37718
  if (!fs54.existsSync(sourceDir)) return;
37541
37719
  for (const entry of fs54.readdirSync(sourceDir)) {
37542
- const source = path44.join(sourceDir, entry);
37543
- const target = path44.join(targetDir, entry);
37720
+ const source = path45.join(sourceDir, entry);
37721
+ const target = path45.join(targetDir, entry);
37544
37722
  if (!fs54.statSync(source).isFile()) continue;
37545
37723
  if (fs54.existsSync(target) && !overwrite) {
37546
37724
  skippedFiles.push(target);
@@ -37555,22 +37733,22 @@ function initializeProject(cwd, options = {}) {
37555
37733
  const copiedFiles = [];
37556
37734
  const skippedFiles = [];
37557
37735
  const crewRoot = projectCrewRoot(cwd);
37558
- const usingLegacyPi = path44.basename(crewRoot) === "teams" && path44.basename(path44.dirname(crewRoot)) === ".pi";
37736
+ const usingLegacyPi = path45.basename(crewRoot) === "teams" && path45.basename(path45.dirname(crewRoot)) === ".pi";
37559
37737
  const ignorePrefix = usingLegacyPi ? ".pi/teams" : ".crew";
37560
- const agentsDir = path44.join(crewRoot, "agents");
37561
- const teamsDir = path44.join(crewRoot, "teams");
37562
- const workflowsDir = path44.join(crewRoot, "workflows");
37738
+ const agentsDir = path45.join(crewRoot, "agents");
37739
+ const teamsDir = path45.join(crewRoot, "teams");
37740
+ const workflowsDir = path45.join(crewRoot, "workflows");
37563
37741
  const configScope = options.configScope ?? "global";
37564
- const configPath3 = configScope === "project" ? path44.join(projectPiRoot(cwd), "pi-crew.json") : configScope === "global" ? configPath() : "";
37742
+ const configPath3 = configScope === "project" ? path45.join(projectPiRoot(cwd), "pi-crew.json") : configScope === "global" ? configPath() : "";
37565
37743
  ensureDir(agentsDir, createdDirs);
37566
37744
  ensureDir(teamsDir, createdDirs);
37567
37745
  ensureDir(workflowsDir, createdDirs);
37568
- ensureDir(path44.join(crewRoot, "imports"), createdDirs);
37746
+ ensureDir(path45.join(crewRoot, "imports"), createdDirs);
37569
37747
  let configCreated = false;
37570
37748
  let configSkipped = false;
37571
37749
  if (configPath3) {
37572
- if (configScope === "project") ensureDir(path44.dirname(configPath3), createdDirs);
37573
- else fs54.mkdirSync(path44.dirname(configPath3), { recursive: true });
37750
+ if (configScope === "project") ensureDir(path45.dirname(configPath3), createdDirs);
37751
+ else fs54.mkdirSync(path45.dirname(configPath3), { recursive: true });
37574
37752
  if (!fs54.existsSync(configPath3) || options.overwrite === true) {
37575
37753
  fs54.writeFileSync(configPath3, `${JSON.stringify(DEFAULT_PI_CREW_CONFIG, null, 2)}
37576
37754
  `, "utf-8");
@@ -37586,10 +37764,10 @@ function initializeProject(cwd, options = {}) {
37586
37764
  }
37587
37765
  const ignoreMethod = options.ignoreMethod ?? "gitignore";
37588
37766
  const desired = [`${ignorePrefix}/state/`, `${ignorePrefix}/artifacts/`, `${ignorePrefix}/worktrees/`, `${ignorePrefix}/imports/`];
37589
- const gitignorePath = ignoreMethod === "exclude" ? path44.join(cwd, ".git", "info", "exclude") : path44.join(cwd, ".gitignore");
37767
+ const gitignorePath = ignoreMethod === "exclude" ? path45.join(cwd, ".git", "info", "exclude") : path45.join(cwd, ".gitignore");
37590
37768
  let gitignoreUpdated = false;
37591
37769
  if (ignoreMethod === "exclude") {
37592
- const infoDir = path44.dirname(gitignorePath);
37770
+ const infoDir = path45.dirname(gitignorePath);
37593
37771
  if (!fs54.existsSync(infoDir)) {
37594
37772
  fs54.mkdirSync(infoDir, { recursive: true });
37595
37773
  }
@@ -37809,8 +37987,8 @@ var init_theme_discovery = __esm({
37809
37987
  });
37810
37988
 
37811
37989
  // src/extension/team-tool/handle-settings.ts
37812
- function setNested(obj, path86, value) {
37813
- const keys = path86.split(".");
37990
+ function setNested(obj, path87, value) {
37991
+ const keys = path87.split(".");
37814
37992
  let target = obj;
37815
37993
  for (let i = 0; i < keys.length - 1; i++) {
37816
37994
  if (!target[keys[i]] || typeof target[keys[i]] !== "object") {
@@ -37820,8 +37998,8 @@ function setNested(obj, path86, value) {
37820
37998
  }
37821
37999
  target[keys[keys.length - 1]] = value;
37822
38000
  }
37823
- function getNested(obj, path86) {
37824
- const keys = path86.split(".");
38001
+ function getNested(obj, path87) {
38002
+ const keys = path87.split(".");
37825
38003
  let current = obj;
37826
38004
  for (const key of keys) {
37827
38005
  if (!current || typeof current !== "object") return void 0;
@@ -38265,9 +38443,9 @@ var init_handle_settings = __esm({
38265
38443
 
38266
38444
  // src/extension/team-tool/workflow-manage.ts
38267
38445
  import { existsSync as existsSync41, readFileSync as readFileSync39, rmSync as rmSync14, writeFileSync as writeFileSync8 } from "node:fs";
38268
- import { dirname as dirname27, join as join43 } from "node:path";
38446
+ import { dirname as dirname28, join as join44 } from "node:path";
38269
38447
  function allowedWorkflowDirs(cwd) {
38270
- return [join43(projectCrewRoot(cwd), "workflows"), join43(userPiRoot(), "workflows"), join43(packageRoot(), "workflows")];
38448
+ return [join44(projectCrewRoot(cwd), "workflows"), join44(userPiRoot(), "workflows"), join44(packageRoot(), "workflows")];
38271
38449
  }
38272
38450
  function validateScriptContent(content) {
38273
38451
  for (const pattern of FORBIDDEN_PATTERNS) {
@@ -38279,7 +38457,7 @@ function validateScriptContent(content) {
38279
38457
  }
38280
38458
  function resolveWorkflowWritePath(cwd, name, scope = "project") {
38281
38459
  assertSafePathId("workflowName", name);
38282
- const base = scope === "user" ? join43(userPiRoot(), "workflows") : join43(projectCrewRoot(cwd), "workflows");
38460
+ const base = scope === "user" ? join44(userPiRoot(), "workflows") : join44(projectCrewRoot(cwd), "workflows");
38283
38461
  return resolveRealContainedPath(base, `${name}.dwf.ts`);
38284
38462
  }
38285
38463
  function handleWorkflowCreate(params, ctx) {
@@ -38623,8 +38801,8 @@ var init_manage = __esm({
38623
38801
  });
38624
38802
 
38625
38803
  // src/runtime/goal-state-store.ts
38626
- import { closeSync as closeSync10, existsSync as existsSync42, mkdirSync as mkdirSync24, openSync as openSync10, readdirSync as readdirSync19, readFileSync as readFileSync40, statSync as statSync27, unlinkSync as unlinkSync5 } from "node:fs";
38627
- import { dirname as dirname28 } from "node:path";
38804
+ import { closeSync as closeSync10, existsSync as existsSync42, mkdirSync as mkdirSync24, openSync as openSync10, readdirSync as readdirSync20, readFileSync as readFileSync40, statSync as statSync27, unlinkSync as unlinkSync6 } from "node:fs";
38805
+ import { dirname as dirname29 } from "node:path";
38628
38806
  function resolveGoalsRoot(cwd) {
38629
38807
  const crewRoot = projectCrewRoot(cwd) ?? userCrewRoot();
38630
38808
  return `${crewRoot}/state/goals`;
@@ -38654,10 +38832,10 @@ var init_goal_state_store = __esm({
38654
38832
  }
38655
38833
  /** Load a goal by id. Returns undefined if missing/corrupt. Throws on unsafe goalId (§0c C10). */
38656
38834
  load(goalId) {
38657
- const path86 = goalFilePath(this.cwd, goalId);
38835
+ const path87 = goalFilePath(this.cwd, goalId);
38658
38836
  try {
38659
- if (!existsSync42(path86)) return void 0;
38660
- const raw = readFileSync40(path86, "utf-8");
38837
+ if (!existsSync42(path87)) return void 0;
38838
+ const raw = readFileSync40(path87, "utf-8");
38661
38839
  const parsed = JSON.parse(raw);
38662
38840
  if (!parsed || typeof parsed !== "object" || typeof parsed.goalId !== "string") return void 0;
38663
38841
  return parsed;
@@ -38668,11 +38846,11 @@ var init_goal_state_store = __esm({
38668
38846
  /** Atomically persist a goal state. Emits a goal.state_changed event if eventsPath given. */
38669
38847
  save(state, eventsPath) {
38670
38848
  assertSafePathId("goalId", state.goalId);
38671
- const path86 = goalFilePath(this.cwd, state.goalId);
38849
+ const path87 = goalFilePath(this.cwd, state.goalId);
38672
38850
  const next = { ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
38673
38851
  try {
38674
- mkdirSync24(dirname28(path86), { recursive: true });
38675
- atomicWriteJson(path86, next);
38852
+ mkdirSync24(dirname29(path87), { recursive: true });
38853
+ atomicWriteJson(path87, next);
38676
38854
  if (eventsPath) {
38677
38855
  appendEvent(eventsPath, {
38678
38856
  type: "goal.state_changed",
@@ -38739,7 +38917,7 @@ var init_goal_state_store = __esm({
38739
38917
  return updated;
38740
38918
  } finally {
38741
38919
  try {
38742
- unlinkSync5(lockPath2);
38920
+ unlinkSync6(lockPath2);
38743
38921
  } catch {
38744
38922
  }
38745
38923
  }
@@ -38756,7 +38934,7 @@ var init_goal_state_store = __esm({
38756
38934
  try {
38757
38935
  const stat2 = statSync27(lockPath2);
38758
38936
  if (Date.now() - stat2.mtimeMs > 5e3) {
38759
- unlinkSync5(lockPath2);
38937
+ unlinkSync6(lockPath2);
38760
38938
  const fd = openSync10(lockPath2, "wx");
38761
38939
  closeSync10(fd);
38762
38940
  return true;
@@ -38769,9 +38947,9 @@ var init_goal_state_store = __esm({
38769
38947
  /** Remove a goal file (used by `goal clear`). Returns true if deleted. */
38770
38948
  remove(goalId) {
38771
38949
  try {
38772
- const path86 = goalFilePath(this.cwd, goalId);
38773
- if (!existsSync42(path86)) return false;
38774
- unlinkSync5(path86);
38950
+ const path87 = goalFilePath(this.cwd, goalId);
38951
+ if (!existsSync42(path87)) return false;
38952
+ unlinkSync6(path87);
38775
38953
  return true;
38776
38954
  } catch (error) {
38777
38955
  logInternalError("goal-state-store.remove", error, `goalId=${goalId}`);
@@ -38783,7 +38961,7 @@ var init_goal_state_store = __esm({
38783
38961
  try {
38784
38962
  const root = resolveGoalsRoot(this.cwd);
38785
38963
  if (!existsSync42(root)) return [];
38786
- const entries = readdirSync19(root);
38964
+ const entries = readdirSync20(root);
38787
38965
  const goals = [];
38788
38966
  for (const entry of entries) {
38789
38967
  if (!entry.endsWith(".json")) continue;
@@ -38806,11 +38984,11 @@ var init_goal_state_store = __esm({
38806
38984
  // src/runtime/verification-integrity.ts
38807
38985
  import { createHash as createHash6 } from "node:crypto";
38808
38986
  import * as fs55 from "node:fs";
38809
- import * as path45 from "node:path";
38987
+ import * as path46 from "node:path";
38810
38988
  function snapshotManifests(cwd) {
38811
38989
  const snapshot = {};
38812
38990
  for (const rel of MANIFEST_FILES) {
38813
- const abs = path45.join(cwd, rel);
38991
+ const abs = path46.join(cwd, rel);
38814
38992
  let stat2;
38815
38993
  try {
38816
38994
  stat2 = fs55.statSync(abs);
@@ -38847,14 +39025,14 @@ var init_verification_integrity = __esm({
38847
39025
 
38848
39026
  // src/runtime/workspace-lock.ts
38849
39027
  import { createHash as createHash7 } from "node:crypto";
38850
- import { closeSync as closeSync11, existsSync as existsSync43, mkdirSync as mkdirSync25, openSync as openSync11, readdirSync as readdirSync20, readFileSync as readFileSync42, statSync as statSync29, unlinkSync as unlinkSync6, writeFileSync as writeFileSync9 } from "node:fs";
38851
- import * as path46 from "node:path";
39028
+ import { closeSync as closeSync11, existsSync as existsSync43, mkdirSync as mkdirSync25, openSync as openSync11, readdirSync as readdirSync21, readFileSync as readFileSync42, statSync as statSync29, unlinkSync as unlinkSync7, writeFileSync as writeFileSync9 } from "node:fs";
39029
+ import * as path47 from "node:path";
38852
39030
  function workspaceLockPath(cwd) {
38853
- const absCwd = path46.resolve(cwd);
39031
+ const absCwd = path47.resolve(cwd);
38854
39032
  const crewRoot = projectCrewRoot(absCwd) ?? userCrewRoot();
38855
- const locksDir = path46.join(crewRoot, "state", "workspace-locks");
39033
+ const locksDir = path47.join(crewRoot, "state", "workspace-locks");
38856
39034
  const hash = createHash7("sha256").update(absCwd).digest("hex");
38857
- return path46.join(locksDir, `${hash}.lock`);
39035
+ return path47.join(locksDir, `${hash}.lock`);
38858
39036
  }
38859
39037
  function readLock(lockPath2) {
38860
39038
  if (!existsSync43(lockPath2)) return void 0;
@@ -38915,7 +39093,7 @@ var init_workspace_lock = __esm({
38915
39093
  // src/runtime/orphan-worker-registry.ts
38916
39094
  import { execFileSync as execFileSync4 } from "node:child_process";
38917
39095
  import * as fs56 from "node:fs";
38918
- import * as path47 from "node:path";
39096
+ import * as path48 from "node:path";
38919
39097
  function getProcessStartTime(pid) {
38920
39098
  try {
38921
39099
  process.kill(pid, 0);
@@ -38999,7 +39177,7 @@ function readRegistry() {
38999
39177
  }
39000
39178
  function writeRegistry(entries) {
39001
39179
  const p = getRegistryPath();
39002
- const dir = path47.dirname(p);
39180
+ const dir = path48.dirname(p);
39003
39181
  for (const entry of entries) {
39004
39182
  if (!isValidId(entry.sessionId) || !isValidId(entry.runId)) {
39005
39183
  logInternalError(
@@ -39155,7 +39333,7 @@ var init_orphan_worker_registry = __esm({
39155
39333
  init_paths();
39156
39334
  STALE_REGISTRATION_MS = 60 * 60 * 1e3;
39157
39335
  GRACE_PERIOD_MS = 5 * 60 * 1e3;
39158
- REGISTRY_PATH = path47.join(userPiRoot(), "state", "orphan-workers.json");
39336
+ REGISTRY_PATH = path48.join(userPiRoot(), "state", "orphan-workers.json");
39159
39337
  }
39160
39338
  });
39161
39339
 
@@ -39163,22 +39341,22 @@ var init_orphan_worker_registry = __esm({
39163
39341
  import { spawn as spawn3 } from "node:child_process";
39164
39342
  import * as fs57 from "node:fs";
39165
39343
  import { createRequire as createRequire3 } from "node:module";
39166
- import * as path48 from "node:path";
39344
+ import * as path49 from "node:path";
39167
39345
  import { fileURLToPath as fileURLToPath6, pathToFileURL as pathToFileURL2 } from "node:url";
39168
39346
  function packageRootFromRuntime() {
39169
- return path48.resolve(path48.dirname(fileURLToPath6(import.meta.url)), "..", "..");
39347
+ return path49.resolve(path49.dirname(fileURLToPath6(import.meta.url)), "..", "..");
39170
39348
  }
39171
39349
  function jitiRegisterPathFromPackageJson(packageJsonPath) {
39172
- return path48.join(path48.dirname(packageJsonPath), "lib", "jiti-register.mjs");
39350
+ return path49.join(path49.dirname(packageJsonPath), "lib", "jiti-register.mjs");
39173
39351
  }
39174
39352
  function resolveJitiRegisterPath(packageRoot2 = packageRootFromRuntime(), exists = fs57.existsSync) {
39175
- let current = path48.resolve(packageRoot2);
39176
- const root = path48.parse(current).root;
39353
+ let current = path49.resolve(packageRoot2);
39354
+ const root = path49.parse(current).root;
39177
39355
  while (true) {
39178
- const candidate = path48.join(current, "node_modules", "jiti", "lib", "jiti-register.mjs");
39356
+ const candidate = path49.join(current, "node_modules", "jiti", "lib", "jiti-register.mjs");
39179
39357
  if (exists(candidate)) return candidate;
39180
39358
  if (current === root) break;
39181
- const parent = path48.dirname(current);
39359
+ const parent = path49.dirname(current);
39182
39360
  if (parent === current) break;
39183
39361
  current = parent;
39184
39362
  }
@@ -39186,8 +39364,8 @@ function resolveJitiRegisterPath(packageRoot2 = packageRootFromRuntime(), exists
39186
39364
  const pkgPath = requireFromHere.resolve("jiti/package.json");
39187
39365
  const candidates = [
39188
39366
  jitiRegisterPathFromPackageJson(pkgPath),
39189
- path48.join(path48.dirname(pkgPath), "register.mjs"),
39190
- path48.join(path48.dirname(pkgPath), "dist", "register.mjs")
39367
+ path49.join(path49.dirname(pkgPath), "register.mjs"),
39368
+ path49.join(path49.dirname(pkgPath), "dist", "register.mjs")
39191
39369
  ];
39192
39370
  for (const c of candidates) if (exists(c)) return c;
39193
39371
  } catch {
@@ -39227,7 +39405,7 @@ function getBackgroundRunnerCommand(runnerPath, cwd, runId, loaderInput = resolv
39227
39405
  if (!loader) throw new Error(buildLoaderUnavailableMessage(packageRootFromRuntime()));
39228
39406
  const memoryLimit = "--max-old-space-size=512";
39229
39407
  const reportOn = !(process.env.PI_CREW_BG_REPORT_ON_FATAL === "0" || process.env.PI_TEAMS_BG_REPORT_ON_FATAL === "0");
39230
- const reportDir = reportDirectory ?? path48.dirname(runnerPath);
39408
+ const reportDir = reportDirectory ?? path49.dirname(runnerPath);
39231
39409
  const reportFlags = reportOn ? ["--report-on-fatalerror", "--report-compact", `--report-directory=${reportDir}`] : [];
39232
39410
  if (loader.kind === "jiti") {
39233
39411
  return {
@@ -39252,8 +39430,8 @@ function getBackgroundRunnerCommand(runnerPath, cwd, runId, loaderInput = resolv
39252
39430
  };
39253
39431
  }
39254
39432
  async function spawnBackgroundTeamRun(manifest) {
39255
- const runnerPath = path48.join(packageRoot(), "src", "runtime", "background-runner.ts");
39256
- const logPath = path48.join(manifest.stateRoot, "background.log");
39433
+ const runnerPath = path49.join(packageRoot(), "src", "runtime", "background-runner.ts");
39434
+ const logPath = path49.join(manifest.stateRoot, "background.log");
39257
39435
  fs57.mkdirSync(manifest.stateRoot, { recursive: true });
39258
39436
  const filteredEnv = sanitizeEnvSecrets(process.env, {
39259
39437
  allowList: BACKGROUND_RUNNER_ENV_ALLOWLIST
@@ -42108,7 +42286,7 @@ var init_theme_adapter = __esm({
42108
42286
  // src/runtime/stale-reconciler.ts
42109
42287
  import * as fs61 from "node:fs";
42110
42288
  import * as os13 from "node:os";
42111
- import * as path49 from "node:path";
42289
+ import * as path50 from "node:path";
42112
42290
  function isPlanApprovalPending(manifest) {
42113
42291
  return manifest.status === "blocked" && manifest.planApproval?.required === true && manifest.planApproval.status === "pending";
42114
42292
  }
@@ -42158,7 +42336,7 @@ function checkPidLiveness(pid, stateRoot) {
42158
42336
  let heartbeatNote = "";
42159
42337
  if (stateRoot) {
42160
42338
  try {
42161
- const heartbeatPath = path49.join(stateRoot, "heartbeat.json");
42339
+ const heartbeatPath = path50.join(stateRoot, "heartbeat.json");
42162
42340
  if (fs61.existsSync(heartbeatPath)) {
42163
42341
  const hb = JSON.parse(fs61.readFileSync(heartbeatPath, "utf-8"));
42164
42342
  if (hb?.pid === pid && hb?.at) {
@@ -42343,16 +42521,16 @@ function reconcileOrphanedTempWorkspaces(now = Date.now(), options) {
42343
42521
  const candidates = entries.filter((e) => e.isDirectory() && e.name.startsWith("pi-crew-")).sort((a, b) => a.name.localeCompare(b.name)).slice(0, scanBatch);
42344
42522
  for (const entry of candidates) {
42345
42523
  if (!entry.isDirectory() || !entry.name.startsWith("pi-crew-")) continue;
42346
- const workspaceDir = path49.join(tmpDir, entry.name);
42347
- const crewDir = path49.join(workspaceDir, ".crew");
42524
+ const workspaceDir = path50.join(tmpDir, entry.name);
42525
+ const crewDir = path50.join(workspaceDir, ".crew");
42348
42526
  if (!fs61.existsSync(crewDir)) continue;
42349
- const stateRunsDir = path49.join(crewDir, "state", "runs");
42527
+ const stateRunsDir = path50.join(crewDir, "state", "runs");
42350
42528
  if (!fs61.existsSync(stateRunsDir)) continue;
42351
42529
  let hasRunning = false;
42352
42530
  try {
42353
42531
  for (const runDir of fs61.readdirSync(stateRunsDir)) {
42354
- const manifestPath = path49.join(stateRunsDir, runDir, "manifest.json");
42355
- const tasksPath = path49.join(stateRunsDir, runDir, "tasks.json");
42532
+ const manifestPath = path50.join(stateRunsDir, runDir, "manifest.json");
42533
+ const tasksPath = path50.join(stateRunsDir, runDir, "tasks.json");
42356
42534
  if (!fs61.existsSync(manifestPath) || !fs61.existsSync(tasksPath)) continue;
42357
42535
  try {
42358
42536
  const manifest = JSON.parse(fs61.readFileSync(manifestPath, "utf-8"));
@@ -42396,7 +42574,7 @@ function reconcileOrphanedTempWorkspaces(now = Date.now(), options) {
42396
42574
  hasRunning = true;
42397
42575
  console.warn(`[stale-reconciler] Skipping unreadable runs dir: ${stateRunsDir}: ${err2}`);
42398
42576
  }
42399
- const sentinelPath = path49.join(workspaceDir, ".cleanup-in-progress");
42577
+ const sentinelPath = path50.join(workspaceDir, ".cleanup-in-progress");
42400
42578
  let canCleanup = !hasRunning;
42401
42579
  const cleanupEnabled = options?.cleanupOrphanedTempDirs !== false;
42402
42580
  let dirAge = 0;
@@ -42423,7 +42601,7 @@ function reconcileOrphanedTempWorkspaces(now = Date.now(), options) {
42423
42601
  if (fs61.existsSync(stateRunsDir)) {
42424
42602
  try {
42425
42603
  for (const runDir of fs61.readdirSync(stateRunsDir)) {
42426
- const manifestPath = path49.join(stateRunsDir, runDir, "manifest.json");
42604
+ const manifestPath = path50.join(stateRunsDir, runDir, "manifest.json");
42427
42605
  if (!fs61.existsSync(manifestPath)) continue;
42428
42606
  let manifest;
42429
42607
  try {
@@ -42448,7 +42626,7 @@ function reconcileOrphanedTempWorkspaces(now = Date.now(), options) {
42448
42626
  if (fs61.existsSync(stateRunsDir)) {
42449
42627
  try {
42450
42628
  for (const runDir of fs61.readdirSync(stateRunsDir)) {
42451
- const manifestPath = path49.join(stateRunsDir, runDir, "manifest.json");
42629
+ const manifestPath = path50.join(stateRunsDir, runDir, "manifest.json");
42452
42630
  if (!fs61.existsSync(manifestPath)) continue;
42453
42631
  try {
42454
42632
  const manifest = JSON.parse(fs61.readFileSync(manifestPath, "utf-8"));
@@ -42516,7 +42694,7 @@ __export(crash_recovery_exports, {
42516
42694
  reconcileAllStaleRuns: () => reconcileAllStaleRuns
42517
42695
  });
42518
42696
  import * as fs62 from "node:fs";
42519
- import * as path50 from "node:path";
42697
+ import * as path51 from "node:path";
42520
42698
  function isTerminalTask(task) {
42521
42699
  return task.status === "completed" || task.status === "failed" || task.status === "cancelled" || task.status === "skipped" || task.status === "needs_attention";
42522
42700
  }
@@ -42689,7 +42867,7 @@ function tryRemoveRunDirectories(entry) {
42689
42867
  }
42690
42868
  function heartbeatAgeMs2(entry, now) {
42691
42869
  try {
42692
- const mtime = fs62.statSync(path50.join(entry.stateRoot, "heartbeat.json")).mtimeMs;
42870
+ const mtime = fs62.statSync(path51.join(entry.stateRoot, "heartbeat.json")).mtimeMs;
42693
42871
  return Number.isFinite(mtime) ? now - mtime : Infinity;
42694
42872
  } catch {
42695
42873
  return Infinity;
@@ -43609,10 +43787,92 @@ var init_tool_progress_formatter = __esm({
43609
43787
  }
43610
43788
  });
43611
43789
 
43790
+ // src/extension/team-tool/param-error.ts
43791
+ import { Value as Value3 } from "@sinclair/typebox/value";
43792
+ function describeValue(v) {
43793
+ if (v === null) return "null";
43794
+ if (Array.isArray(v)) return `array (length ${v.length})`;
43795
+ if (typeof v === "object") return "object";
43796
+ if (typeof v === "string") return `string "${v.length > 40 ? `${v.slice(0, 37)}...` : v}"`;
43797
+ return `${typeof v} (${String(v).slice(0, 40)})`;
43798
+ }
43799
+ function diagnoseCommonMistakes(params) {
43800
+ const hints = [];
43801
+ if (typeof params !== "object" || params === null || Array.isArray(params)) {
43802
+ return hints;
43803
+ }
43804
+ const p = params;
43805
+ if ("action" in p) {
43806
+ const a = p.action;
43807
+ if (typeof a !== "string") {
43808
+ hints.push(` \u2022 'action': must be a lowercase string (e.g. "run", "status", "list") \u2014 got ${describeValue(a)}.`);
43809
+ } else if (a !== a.toLowerCase()) {
43810
+ hints.push(` \u2022 'action': "${a}" has wrong casing \u2014 action is case-sensitive. Use "${a.toLowerCase()}".`);
43811
+ }
43812
+ }
43813
+ const stringFields = ["goal", "team", "runId", "task", "role", "agent", "workflow", "model", "cwd", "chain"];
43814
+ for (const f of stringFields) {
43815
+ if (!(f in p)) continue;
43816
+ const v = p[f];
43817
+ if (typeof v === "string") continue;
43818
+ if (Array.isArray(v)) {
43819
+ hints.push(
43820
+ ` \u2022 '${f}': must be a single flat string \u2014 got an array (length ${v.length}). Pass e.g. "${f}": "<value>", not a list.`
43821
+ );
43822
+ } else if (typeof v === "object" && v !== null) {
43823
+ hints.push(` \u2022 '${f}': must be a single flat string \u2014 got an object. Pass e.g. "${f}": "<value>".`);
43824
+ } else {
43825
+ hints.push(` \u2022 '${f}': must be a string \u2014 got ${describeValue(v)}.`);
43826
+ }
43827
+ }
43828
+ return hints;
43829
+ }
43830
+ function formatTeamToolParamError(schema, params) {
43831
+ const issues = [...diagnoseCommonMistakes(params)];
43832
+ try {
43833
+ const errors2 = [...Value3.Errors(schema, params)];
43834
+ const seen = /* @__PURE__ */ new Set();
43835
+ for (const e of errors2) {
43836
+ if (issues.length >= 8) break;
43837
+ const key = `${e.path}|${e.type}`;
43838
+ if (seen.has(key)) continue;
43839
+ seen.add(key);
43840
+ const pathLabel = e.path ? `'${e.path}'` : "(schema)";
43841
+ issues.push(` \u2022 ${pathLabel}: ${e.message} \u2014 received ${describeValue(e.value)}`);
43842
+ }
43843
+ } catch {
43844
+ }
43845
+ if (issues.length === 0) {
43846
+ issues.push(" \u2022 params did not match any valid team-tool action shape");
43847
+ }
43848
+ return [
43849
+ "Invalid team tool parameters \u2014 the call was rejected by schema validation.",
43850
+ "",
43851
+ "What went wrong:",
43852
+ ...issues,
43853
+ "",
43854
+ "Correct call shapes \u2014 `action` is case-sensitive (lowercase); `goal`,",
43855
+ "`team`, `runId`, `task`, `role` MUST be flat strings, never objects/arrays:",
43856
+ ' \u2022 Run a team: { "action": "run", "goal": "<what to achieve>", "team": "implementation" }',
43857
+ ' \u2022 Suggest a team: { "action": "recommend", "goal": "<what to achieve>" }',
43858
+ ' \u2022 List recent runs: { "action": "list" }',
43859
+ ' \u2022 Run status: { "action": "status", "runId": "<runId>" }',
43860
+ ' \u2022 Direct one agent: { "action": "run", "role": "<agent>", "task": "<one task>" }',
43861
+ "",
43862
+ 'Common mistakes: `action` uppercase (use "run" not "Run"); `goal` passed',
43863
+ "as an array/object instead of a single string; params nested instead of flat."
43864
+ ].join("\n");
43865
+ }
43866
+ var init_param_error = __esm({
43867
+ "src/extension/team-tool/param-error.ts"() {
43868
+ "use strict";
43869
+ }
43870
+ });
43871
+
43612
43872
  // src/extension/registration/team-tool.ts
43613
43873
  import { statSync as statSync32 } from "node:fs";
43614
43874
  import { Text as Text3 } from "@earendil-works/pi-tui";
43615
- import { Value as Value3 } from "@sinclair/typebox/value";
43875
+ import { Value as Value4 } from "@sinclair/typebox/value";
43616
43876
  async function handleTeamTool(params, ctx) {
43617
43877
  if (!_cachedHandleTeamTool) {
43618
43878
  const mod = await Promise.resolve().then(() => (init_team_tool2(), team_tool_exports));
@@ -43664,8 +43924,8 @@ function registerTeamTool(pi, deps) {
43664
43924
  signal?.addEventListener("abort", abort, { once: true });
43665
43925
  const stopProgress = startTeamToolProgressBinder(onUpdate);
43666
43926
  try {
43667
- if (!Value3.Check(TeamToolParams, params)) {
43668
- return toolResult("Invalid team tool parameters", { action: "list", status: "error" }, true);
43927
+ if (!Value4.Check(TeamToolParams, params)) {
43928
+ return toolResult(formatTeamToolParamError(TeamToolParams, params), { action: "list", status: "error" }, true);
43669
43929
  }
43670
43930
  const resolved = params;
43671
43931
  const cwdOverride = resolveCwdOverride(ctx.cwd, resolved.cwd);
@@ -43796,6 +44056,7 @@ var init_team_tool = __esm({
43796
44056
  init_tool_progress_formatter();
43797
44057
  init_internal_error();
43798
44058
  init_context();
44059
+ init_param_error();
43799
44060
  init_tool_result();
43800
44061
  TEAM_TOOL_PROGRESS_TICK_MS = 1e3;
43801
44062
  }
@@ -44098,7 +44359,7 @@ var init_run = __esm({
44098
44359
 
44099
44360
  // src/runtime/checkpoint.ts
44100
44361
  import * as fs63 from "node:fs";
44101
- import * as path51 from "node:path";
44362
+ import * as path52 from "node:path";
44102
44363
  var FileCheckpointStore;
44103
44364
  var init_checkpoint = __esm({
44104
44365
  "src/runtime/checkpoint.ts"() {
@@ -44113,10 +44374,10 @@ var init_checkpoint = __esm({
44113
44374
  this.stateRoot = stateRoot;
44114
44375
  }
44115
44376
  checkpointDir() {
44116
- return path51.join(this.stateRoot, "checkpoints");
44377
+ return path52.join(this.stateRoot, "checkpoints");
44117
44378
  }
44118
44379
  checkpointPath(taskId) {
44119
- return path51.join(this.checkpointDir(), `${taskId}.json`);
44380
+ return path52.join(this.checkpointDir(), `${taskId}.json`);
44120
44381
  }
44121
44382
  ensureDir() {
44122
44383
  const dir = this.checkpointDir();
@@ -44169,7 +44430,7 @@ var init_checkpoint = __esm({
44169
44430
  if (!fs63.existsSync(dir)) return [];
44170
44431
  return fs63.readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => {
44171
44432
  try {
44172
- return JSON.parse(fs63.readFileSync(path51.join(dir, f), "utf-8"));
44433
+ return JSON.parse(fs63.readFileSync(path52.join(dir, f), "utf-8"));
44173
44434
  } catch {
44174
44435
  return null;
44175
44436
  }
@@ -44185,17 +44446,17 @@ var init_checkpoint = __esm({
44185
44446
  // src/state/run-cache.ts
44186
44447
  import * as crypto7 from "node:crypto";
44187
44448
  import * as fs64 from "node:fs";
44188
- import * as path52 from "node:path";
44449
+ import * as path53 from "node:path";
44189
44450
  function computeRunCacheKey(goal, team, workflow, _cwd) {
44190
44451
  const normalized = goal.trim().toLowerCase().replace(/\s+/g, " ");
44191
44452
  return crypto7.createHash("sha256").update(normalized).update(team).update(workflow).update(_cwd).digest("hex").slice(0, 16);
44192
44453
  }
44193
44454
  function cacheDir(cwd) {
44194
- return path52.join(projectCrewRoot(cwd), "cache");
44455
+ return path53.join(projectCrewRoot(cwd), "cache");
44195
44456
  }
44196
44457
  function getCachedRun(cwd, cacheKey2) {
44197
44458
  const dir = cacheDir(cwd);
44198
- const indexPath = path52.join(dir, "index.json");
44459
+ const indexPath = path53.join(dir, "index.json");
44199
44460
  if (!fs64.existsSync(indexPath)) return null;
44200
44461
  try {
44201
44462
  const index = JSON.parse(fs64.readFileSync(indexPath, "utf-8"));
@@ -44224,7 +44485,7 @@ function getCacheStats(cwd) {
44224
44485
  if (!fs64.existsSync(dir)) return { entries: 0, sizeBytes: 0 };
44225
44486
  let sizeBytes = 0;
44226
44487
  let entries = 0;
44227
- const indexPath = path52.join(dir, "index.json");
44488
+ const indexPath = path53.join(dir, "index.json");
44228
44489
  if (fs64.existsSync(indexPath)) {
44229
44490
  try {
44230
44491
  const index = JSON.parse(fs64.readFileSync(indexPath, "utf-8"));
@@ -44254,11 +44515,11 @@ var init_run_cache = __esm({
44254
44515
 
44255
44516
  // src/state/run-graph.ts
44256
44517
  import * as fs65 from "node:fs";
44257
- import * as path53 from "node:path";
44518
+ import * as path54 from "node:path";
44258
44519
  function loadRunGraph(cwd, runId) {
44259
44520
  assertSafePathId("runId", runId);
44260
44521
  const crewRoot = projectCrewRoot(cwd);
44261
- const graphPath = path53.join(crewRoot, "graphs", `${runId}.json`);
44522
+ const graphPath = path54.join(crewRoot, "graphs", `${runId}.json`);
44262
44523
  if (!fs65.existsSync(graphPath)) return null;
44263
44524
  try {
44264
44525
  return JSON.parse(fs65.readFileSync(graphPath, "utf-8"));
@@ -44268,7 +44529,7 @@ function loadRunGraph(cwd, runId) {
44268
44529
  }
44269
44530
  function listRunGraphs(cwd) {
44270
44531
  const crewRoot = projectCrewRoot(cwd);
44271
- const graphsDir = path53.join(crewRoot, "graphs");
44532
+ const graphsDir = path54.join(crewRoot, "graphs");
44272
44533
  if (!fs65.existsSync(graphsDir)) return [];
44273
44534
  return fs65.readdirSync(graphsDir).filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, ""));
44274
44535
  }
@@ -44517,16 +44778,16 @@ var init_help = __esm({
44517
44778
 
44518
44779
  // src/extension/team-onboard.ts
44519
44780
  import * as fs66 from "node:fs";
44520
- import * as path54 from "node:path";
44781
+ import * as path55 from "node:path";
44521
44782
  function loadRunSummaries(cwd, options = {}) {
44522
44783
  const crewRoot = projectCrewRoot(cwd);
44523
- const runsRoot = path54.join(crewRoot, "state", "runs");
44784
+ const runsRoot = path55.join(crewRoot, "state", "runs");
44524
44785
  if (!fs66.existsSync(runsRoot)) return [];
44525
44786
  const limit = options.limit ?? 5;
44526
44787
  const teamFilter = options.team;
44527
44788
  const entries = fs66.readdirSync(runsRoot).filter((e) => {
44528
44789
  try {
44529
- return fs66.statSync(path54.join(runsRoot, e)).isDirectory();
44790
+ return fs66.statSync(path55.join(runsRoot, e)).isDirectory();
44530
44791
  } catch {
44531
44792
  return false;
44532
44793
  }
@@ -44534,7 +44795,7 @@ function loadRunSummaries(cwd, options = {}) {
44534
44795
  const summaries = [];
44535
44796
  for (const runId of entries) {
44536
44797
  if (summaries.length >= limit) break;
44537
- const manifestPath = path54.join(runsRoot, runId, "manifest.json");
44798
+ const manifestPath = path55.join(runsRoot, runId, "manifest.json");
44538
44799
  if (!fs66.existsSync(manifestPath)) continue;
44539
44800
  try {
44540
44801
  const raw = JSON.parse(fs66.readFileSync(manifestPath, "utf-8"));
@@ -44871,7 +45132,7 @@ var init_team_recommendation = __esm({
44871
45132
 
44872
45133
  // src/extension/team-tool/explain.ts
44873
45134
  import * as fs67 from "node:fs";
44874
- import * as path55 from "node:path";
45135
+ import * as path56 from "node:path";
44875
45136
  function result3(text, details, isError) {
44876
45137
  return { isError, text };
44877
45138
  }
@@ -44925,7 +45186,7 @@ function buildTaskExplainContext(manifest, tasks, taskId) {
44925
45186
  try {
44926
45187
  const entries = fs67.readdirSync(artifactsPath);
44927
45188
  for (const entry of entries) {
44928
- const fullPath = path55.join(artifactsPath, entry);
45189
+ const fullPath = path56.join(artifactsPath, entry);
44929
45190
  try {
44930
45191
  if (fs67.statSync(fullPath).isFile()) {
44931
45192
  filesTouched.push(entry);
@@ -45086,9 +45347,9 @@ var init_explain = __esm({
45086
45347
  // src/extension/team-tool/health-monitor.ts
45087
45348
  import * as fs68 from "node:fs";
45088
45349
  import * as os14 from "node:os";
45089
- import * as path56 from "node:path";
45350
+ import * as path57 from "node:path";
45090
45351
  function readRunTasks(stateRoot) {
45091
- const tasksPath = path56.join(stateRoot, "tasks.json");
45352
+ const tasksPath = path57.join(stateRoot, "tasks.json");
45092
45353
  try {
45093
45354
  return JSON.parse(fs68.readFileSync(tasksPath, "utf-8"));
45094
45355
  } catch {
@@ -45129,13 +45390,13 @@ function scanZombieTempWorkspaces(tmpDir, now) {
45129
45390
  const entries = fs68.readdirSync(tmpDir, { withFileTypes: true });
45130
45391
  for (const entry of entries) {
45131
45392
  if (!entry.isDirectory() || !entry.name.startsWith("pi-crew-")) continue;
45132
- const workspaceDir = path56.join(tmpDir, entry.name);
45133
- const stateRunsDir = path56.join(workspaceDir, ".crew", "state", "runs");
45393
+ const workspaceDir = path57.join(tmpDir, entry.name);
45394
+ const stateRunsDir = path57.join(workspaceDir, ".crew", "state", "runs");
45134
45395
  if (!fs68.existsSync(stateRunsDir)) continue;
45135
45396
  let runCount = 0;
45136
45397
  try {
45137
45398
  for (const runDir of fs68.readdirSync(stateRunsDir)) {
45138
- const manifestPath = path56.join(stateRunsDir, runDir, "manifest.json");
45399
+ const manifestPath = path57.join(stateRunsDir, runDir, "manifest.json");
45139
45400
  if (fs68.existsSync(manifestPath)) {
45140
45401
  try {
45141
45402
  const manifest = JSON.parse(fs68.readFileSync(manifestPath, "utf-8"));
@@ -45162,11 +45423,11 @@ function collectTempWorkspaceRuns(primaryRuns, tmpDir) {
45162
45423
  const entries = fs68.readdirSync(tmpDir, { withFileTypes: true });
45163
45424
  for (const entry of entries) {
45164
45425
  if (!entry.isDirectory() || !entry.name.startsWith("pi-crew-")) continue;
45165
- const stateRunsDir = path56.join(tmpDir, entry.name, ".crew", "state", "runs");
45426
+ const stateRunsDir = path57.join(tmpDir, entry.name, ".crew", "state", "runs");
45166
45427
  if (!fs68.existsSync(stateRunsDir)) continue;
45167
45428
  try {
45168
45429
  for (const runDir of fs68.readdirSync(stateRunsDir)) {
45169
- const manifestPath = path56.join(stateRunsDir, runDir, "manifest.json");
45430
+ const manifestPath = path57.join(stateRunsDir, runDir, "manifest.json");
45170
45431
  if (!fs68.existsSync(manifestPath)) continue;
45171
45432
  try {
45172
45433
  const manifest = JSON.parse(fs68.readFileSync(manifestPath, "utf-8"));
@@ -45520,7 +45781,7 @@ var init_inspect = __esm({
45520
45781
 
45521
45782
  // src/runtime/attention-events.ts
45522
45783
  function appendTaskAttentionEvent(input) {
45523
- const recent = readEvents(input.manifest.eventsPath).slice(-200);
45784
+ const recent = readJsonlTail(input.manifest.eventsPath, 256 * 1024).items.slice(-200);
45524
45785
  const dedupKey = `${input.taskId ?? ""}:${input.data.reason}:${input.data.activityState}`;
45525
45786
  const duplicate = recent.some(
45526
45787
  (event) => event.type === "task.attention" && `${event.taskId ?? ""}:${event.data?.reason ?? ""}:${event.data?.activityState ?? ""}` === dedupKey
@@ -45539,6 +45800,7 @@ var init_attention_events = __esm({
45539
45800
  "src/runtime/attention-events.ts"() {
45540
45801
  "use strict";
45541
45802
  init_event_log();
45803
+ init_incremental_reader();
45542
45804
  }
45543
45805
  });
45544
45806
 
@@ -46078,6 +46340,9 @@ function handleStatus2(params, ctx) {
46078
46340
  const phaseProgress = computePhaseProgress(tasks);
46079
46341
  const allEvents = readEvents(manifest.eventsPath);
46080
46342
  const events = allEvents.slice(-8);
46343
+ const ackTimeoutRequestIds = new Set(
46344
+ allEvents.filter((event) => event.type === "agent.group_join.ack_timeout").map((event) => String(event.data?.requestId ?? ""))
46345
+ );
46081
46346
  const attentionByTask = new Map(
46082
46347
  allEvents.filter((event) => event.type === "task.attention" && event.taskId).map((event) => [event.taskId, event])
46083
46348
  );
@@ -46094,7 +46359,7 @@ function handleStatus2(params, ctx) {
46094
46359
  const ageMs = Date.now() - new Date(message.createdAt).getTime();
46095
46360
  const requestId3 = String(message.data?.requestId ?? "unknown");
46096
46361
  const timedOut = ack === "pending" && ackTimeoutMs !== void 0 && Number.isFinite(ageMs) && ageMs > ackTimeoutMs;
46097
- if (timedOut && !allEvents.some((event) => event.type === "agent.group_join.ack_timeout" && event.data?.requestId === requestId3)) {
46362
+ if (timedOut && !ackTimeoutRequestIds.has(requestId3)) {
46098
46363
  appendEvent(manifest.eventsPath, {
46099
46364
  type: "agent.group_join.ack_timeout",
46100
46365
  runId: manifest.runId,
@@ -46248,7 +46513,7 @@ var init_status = __esm({
46248
46513
  });
46249
46514
 
46250
46515
  // src/extension/team-tool/dispatch/status.ts
46251
- import * as path57 from "node:path";
46516
+ import * as path58 from "node:path";
46252
46517
  async function handleStatusDomain(params, ctx) {
46253
46518
  switch (params.action) {
46254
46519
  case "list":
@@ -46384,7 +46649,7 @@ Skill cache: ${skillStats.hits} hits, ${skillStats.misses} misses (${(skillStats
46384
46649
  }
46385
46650
  assertSafePathId("runId", params.runId);
46386
46651
  assertSafePathId("taskId", params.taskId);
46387
- const stateRoot = path57.join(projectCrewRoot(ctx.cwd), "state", "runs", params.runId);
46652
+ const stateRoot = path58.join(projectCrewRoot(ctx.cwd), "state", "runs", params.runId);
46388
46653
  const store = new FileCheckpointStore(stateRoot);
46389
46654
  const checkpoint = store.load(params.runId, params.taskId);
46390
46655
  if (!checkpoint) {
@@ -46695,7 +46960,7 @@ var init_task_health = __esm({
46695
46960
 
46696
46961
  // src/state/health-store.ts
46697
46962
  import * as fs70 from "node:fs";
46698
- import * as path58 from "node:path";
46963
+ import * as path59 from "node:path";
46699
46964
  var HEALTH_DIR, HealthStore;
46700
46965
  var init_health_store = __esm({
46701
46966
  "src/state/health-store.ts"() {
@@ -46709,7 +46974,7 @@ var init_health_store = __esm({
46709
46974
  this.crewRoot = crewRoot;
46710
46975
  }
46711
46976
  healthDir() {
46712
- return path58.join(this.crewRoot, HEALTH_DIR);
46977
+ return path59.join(this.crewRoot, HEALTH_DIR);
46713
46978
  }
46714
46979
  saveSnapshot(manifest) {
46715
46980
  const health = computeRunHealth(manifest);
@@ -46722,7 +46987,7 @@ var init_health_store = __esm({
46722
46987
  };
46723
46988
  const dir = this.healthDir();
46724
46989
  fs70.mkdirSync(dir, { recursive: true });
46725
- const file = path58.join(dir, `${manifest.runId}.json`);
46990
+ const file = path59.join(dir, `${manifest.runId}.json`);
46726
46991
  atomicWriteFile(file, JSON.stringify(snapshot, null, 2) + "\n");
46727
46992
  return snapshot;
46728
46993
  }
@@ -46739,7 +47004,7 @@ var init_health_store = __esm({
46739
47004
  if (!fs70.existsSync(dir)) return [];
46740
47005
  const snapshots = fs70.readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => {
46741
47006
  try {
46742
- return JSON.parse(fs70.readFileSync(path58.join(dir, f), "utf8"));
47007
+ return JSON.parse(fs70.readFileSync(path59.join(dir, f), "utf8"));
46743
47008
  } catch {
46744
47009
  return null;
46745
47010
  }
@@ -46966,6 +47231,101 @@ var init_coalesce_tasks = __esm({
46966
47231
  }
46967
47232
  });
46968
47233
 
47234
+ // src/runtime/semaphore.ts
47235
+ var Semaphore;
47236
+ var init_semaphore = __esm({
47237
+ "src/runtime/semaphore.ts"() {
47238
+ "use strict";
47239
+ Semaphore = class _Semaphore {
47240
+ #max;
47241
+ #current = 0;
47242
+ #queue = [];
47243
+ // FIX (Round 15): Cap the waiter queue to prevent unbounded memory growth
47244
+ // if the semaphore is held for a long period and many tasks accumulate.
47245
+ static MAX_QUEUE = 1e4;
47246
+ constructor(max) {
47247
+ this.#max = Math.max(1, max);
47248
+ }
47249
+ async acquire() {
47250
+ if (this.#current < this.#max) {
47251
+ this.#current++;
47252
+ return;
47253
+ }
47254
+ if (this.#queue.length >= _Semaphore.MAX_QUEUE) {
47255
+ return Promise.reject(
47256
+ new Error(`Semaphore queue full: ${this.#queue.length} waiters (max ${_Semaphore.MAX_QUEUE}); cannot acquire slot`)
47257
+ );
47258
+ }
47259
+ const { promise, resolve: resolve23 } = (() => {
47260
+ let res;
47261
+ const p = new Promise((r) => {
47262
+ res = r;
47263
+ });
47264
+ return { promise: p, resolve: res };
47265
+ })();
47266
+ this.#queue.push(resolve23);
47267
+ return promise;
47268
+ }
47269
+ release() {
47270
+ const next = this.#queue.shift();
47271
+ if (next) {
47272
+ next();
47273
+ } else if (this.#current > 0) {
47274
+ this.#current--;
47275
+ }
47276
+ }
47277
+ /** Current number of acquired slots. */
47278
+ get current() {
47279
+ return this.#current;
47280
+ }
47281
+ /** Number of waiters in the queue. */
47282
+ get waiting() {
47283
+ return this.#queue.length;
47284
+ }
47285
+ };
47286
+ }
47287
+ });
47288
+
47289
+ // src/runtime/global-worker-cap.ts
47290
+ import * as os15 from "node:os";
47291
+ function resolveCapacity() {
47292
+ const env = process.env.PI_CREW_MAX_WORKERS;
47293
+ if (env !== void 0 && env !== "") {
47294
+ const parsed = Number.parseInt(env, 10);
47295
+ if (Number.isFinite(parsed) && parsed > 0) {
47296
+ return parsed;
47297
+ }
47298
+ }
47299
+ const cpus2 = os15.cpus().length;
47300
+ return Math.max(2, cpus2 - 2);
47301
+ }
47302
+ function getWorkerCapCapacity() {
47303
+ return capacity;
47304
+ }
47305
+ async function acquireWorkerSlot() {
47306
+ await semaphore.acquire();
47307
+ }
47308
+ function releaseWorkerSlot() {
47309
+ semaphore.release();
47310
+ }
47311
+ async function withWorkerSlot(fn) {
47312
+ await acquireWorkerSlot();
47313
+ try {
47314
+ return await fn();
47315
+ } finally {
47316
+ releaseWorkerSlot();
47317
+ }
47318
+ }
47319
+ var capacity, semaphore;
47320
+ var init_global_worker_cap = __esm({
47321
+ "src/runtime/global-worker-cap.ts"() {
47322
+ "use strict";
47323
+ init_semaphore();
47324
+ capacity = resolveCapacity();
47325
+ semaphore = new Semaphore(capacity);
47326
+ }
47327
+ });
47328
+
46969
47329
  // src/runtime/concurrency.ts
46970
47330
  function defaultWorkflowConcurrency(workflowName, workflowMaxConcurrency) {
46971
47331
  if (workflowMaxConcurrency !== void 0) return workflowMaxConcurrency;
@@ -46991,9 +47351,10 @@ function resolveBatchConcurrency(input) {
46991
47351
  else if (teamMax !== void 0) source = "team";
46992
47352
  else source = "workflow";
46993
47353
  const hardCap = positiveInteger2(input.hardCap) ?? DEFAULT_CONCURRENCY.hardCap;
46994
- const maxConcurrent = input.allowUnboundedConcurrency ? requested : Math.min(requested, hardCap);
47354
+ const workerCap = positiveInteger2(input.workerCap) ?? getWorkerCapCapacity();
47355
+ const maxConcurrent = input.allowUnboundedConcurrency ? requested : Math.min(requested, hardCap, workerCap);
46995
47356
  const readyCount = Math.max(0, Math.trunc(Number.isFinite(input.readyCount) ? input.readyCount : 0));
46996
- const cappedReason = maxConcurrent < requested ? `;capped:${hardCap}` : "";
47357
+ const cappedReason = maxConcurrent < requested ? `;capped:hard=${hardCap},worker=${workerCap}` : "";
46997
47358
  const unboundedReason = input.allowUnboundedConcurrency && requested > hardCap ? `;unbounded:${hardCap}` : "";
46998
47359
  return {
46999
47360
  maxConcurrent,
@@ -47006,14 +47367,15 @@ var init_concurrency = __esm({
47006
47367
  "src/runtime/concurrency.ts"() {
47007
47368
  "use strict";
47008
47369
  init_defaults();
47370
+ init_global_worker_cap();
47009
47371
  }
47010
47372
  });
47011
47373
 
47012
47374
  // src/runtime/deadletter.ts
47013
47375
  import * as fs71 from "node:fs";
47014
- import * as path59 from "node:path";
47376
+ import * as path60 from "node:path";
47015
47377
  function deadletterPath(manifest) {
47016
- return path59.join(manifest.stateRoot, "deadletter.jsonl");
47378
+ return path60.join(manifest.stateRoot, "deadletter.jsonl");
47017
47379
  }
47018
47380
  function appendDeadletter(manifest, entry) {
47019
47381
  try {
@@ -47433,7 +47795,7 @@ var init_tool_output_pruner = __esm({
47433
47795
 
47434
47796
  // src/runtime/task-output-context.ts
47435
47797
  import * as fs72 from "node:fs";
47436
- import * as path60 from "node:path";
47798
+ import * as path61 from "node:path";
47437
47799
  function containedExists(filePath, baseDir) {
47438
47800
  try {
47439
47801
  const safePath = baseDir ? resolveRealContainedPath(baseDir, filePath) : filePath;
@@ -47447,11 +47809,11 @@ function safeTeeName(taskId, artifactName) {
47447
47809
  return `${safe(taskId)}-${safe(artifactName)}.full.txt`;
47448
47810
  }
47449
47811
  function teePathForArtifact(artifactsRoot, taskId, artifactName) {
47450
- return path60.join(artifactsRoot, "tee", safeTeeName(taskId, artifactName));
47812
+ return path61.join(artifactsRoot, "tee", safeTeeName(taskId, artifactName));
47451
47813
  }
47452
47814
  function writeTeeFile(fullOutputPath, content) {
47453
47815
  try {
47454
- fs72.mkdirSync(path60.dirname(fullOutputPath), { recursive: true });
47816
+ fs72.mkdirSync(path61.dirname(fullOutputPath), { recursive: true });
47455
47817
  atomicWriteFile(fullOutputPath, content);
47456
47818
  return true;
47457
47819
  } catch {
@@ -47496,15 +47858,15 @@ function readIfSmall(filePath, baseDir) {
47496
47858
  }
47497
47859
  function safeSharedName(name) {
47498
47860
  const normalized = name.replaceAll("\\", "/").replace(/^\.\/+/, "");
47499
- if (!normalized || normalized.split("/").some((segment) => segment === "..") || path60.isAbsolute(normalized))
47861
+ if (!normalized || normalized.split("/").some((segment) => segment === "..") || path61.isAbsolute(normalized))
47500
47862
  throw new Error(`Invalid shared artifact name: ${name}`);
47501
47863
  return normalized;
47502
47864
  }
47503
47865
  function sharedPath(manifest, name) {
47504
- const sharedRoot = path60.resolve(manifest.artifactsRoot, "shared");
47505
- const resolved = path60.resolve(sharedRoot, safeSharedName(name));
47506
- const relative9 = path60.relative(sharedRoot, resolved);
47507
- if (relative9.startsWith("..") || path60.isAbsolute(relative9)) throw new Error(`Invalid shared artifact name: ${name}`);
47866
+ const sharedRoot = path61.resolve(manifest.artifactsRoot, "shared");
47867
+ const resolved = path61.resolve(sharedRoot, safeSharedName(name));
47868
+ const relative9 = path61.relative(sharedRoot, resolved);
47869
+ if (relative9.startsWith("..") || path61.isAbsolute(relative9)) throw new Error(`Invalid shared artifact name: ${name}`);
47508
47870
  return resolved;
47509
47871
  }
47510
47872
  function tryParseJson(text) {
@@ -47519,7 +47881,7 @@ function listTaskArtifacts(manifest, taskId) {
47519
47881
  const produced = manifest.artifacts.filter((a) => a.producer === taskId);
47520
47882
  if (produced.length === 0) return void 0;
47521
47883
  return produced.map((a) => {
47522
- const relative9 = path60.relative(manifest.artifactsRoot, a.path);
47884
+ const relative9 = path61.relative(manifest.artifactsRoot, a.path);
47523
47885
  return relative9.startsWith("..") ? a.path : relative9;
47524
47886
  });
47525
47887
  }
@@ -47577,7 +47939,7 @@ function pruneSharedReads(reads, dependencies, artifactsRoot) {
47577
47939
  for (const artifact of produced) {
47578
47940
  if (typeof artifact !== "string") continue;
47579
47941
  fileEdits.push({
47580
- target: path60.resolve(artifactsRoot, artifact),
47942
+ target: path61.resolve(artifactsRoot, artifact),
47581
47943
  index: reads.length + depIndex
47582
47944
  });
47583
47945
  }
@@ -47630,7 +47992,7 @@ function collectDependencyOutputContext(manifest, tasks, task, step) {
47630
47992
  const filePath = sharedPath(manifest, name);
47631
47993
  const teePath = teePathForArtifact(manifest.artifactsRoot, task.id, name);
47632
47994
  const teeResult = readIfSmallWithTee(filePath, {
47633
- baseDir: path60.resolve(manifest.artifactsRoot, "shared"),
47995
+ baseDir: path61.resolve(manifest.artifactsRoot, "shared"),
47634
47996
  tee: { fullOutputPath: teePath }
47635
47997
  });
47636
47998
  if (teeResult === void 0) return { name, path: filePath, content: "" };
@@ -48123,96 +48485,6 @@ var init_retry_executor = __esm({
48123
48485
  }
48124
48486
  });
48125
48487
 
48126
- // src/runtime/semaphore.ts
48127
- var Semaphore;
48128
- var init_semaphore = __esm({
48129
- "src/runtime/semaphore.ts"() {
48130
- "use strict";
48131
- Semaphore = class _Semaphore {
48132
- #max;
48133
- #current = 0;
48134
- #queue = [];
48135
- // FIX (Round 15): Cap the waiter queue to prevent unbounded memory growth
48136
- // if the semaphore is held for a long period and many tasks accumulate.
48137
- static MAX_QUEUE = 1e4;
48138
- constructor(max) {
48139
- this.#max = Math.max(1, max);
48140
- }
48141
- async acquire() {
48142
- if (this.#current < this.#max) {
48143
- this.#current++;
48144
- return;
48145
- }
48146
- if (this.#queue.length >= _Semaphore.MAX_QUEUE) {
48147
- throw new Error(`Semaphore queue full: ${this.#queue.length} waiters (max ${_Semaphore.MAX_QUEUE}); cannot acquire slot`);
48148
- }
48149
- const { promise, resolve: resolve23 } = (() => {
48150
- let res;
48151
- const p = new Promise((r) => {
48152
- res = r;
48153
- });
48154
- return { promise: p, resolve: res };
48155
- })();
48156
- this.#queue.push(resolve23);
48157
- return promise;
48158
- }
48159
- release() {
48160
- const next = this.#queue.shift();
48161
- if (next) {
48162
- next();
48163
- } else if (this.#current > 0) {
48164
- this.#current--;
48165
- }
48166
- }
48167
- /** Current number of acquired slots. */
48168
- get current() {
48169
- return this.#current;
48170
- }
48171
- /** Number of waiters in the queue. */
48172
- get waiting() {
48173
- return this.#queue.length;
48174
- }
48175
- };
48176
- }
48177
- });
48178
-
48179
- // src/runtime/global-worker-cap.ts
48180
- import * as os15 from "node:os";
48181
- function resolveCapacity() {
48182
- const env = process.env.PI_CREW_MAX_WORKERS;
48183
- if (env !== void 0 && env !== "") {
48184
- const parsed = Number.parseInt(env, 10);
48185
- if (Number.isFinite(parsed) && parsed > 0) {
48186
- return parsed;
48187
- }
48188
- }
48189
- const cpus2 = os15.cpus().length;
48190
- return Math.max(2, cpus2 - 2);
48191
- }
48192
- async function acquireWorkerSlot() {
48193
- await semaphore.acquire();
48194
- }
48195
- function releaseWorkerSlot() {
48196
- semaphore.release();
48197
- }
48198
- async function withWorkerSlot(fn) {
48199
- await acquireWorkerSlot();
48200
- try {
48201
- return await fn();
48202
- } finally {
48203
- releaseWorkerSlot();
48204
- }
48205
- }
48206
- var capacity, semaphore;
48207
- var init_global_worker_cap = __esm({
48208
- "src/runtime/global-worker-cap.ts"() {
48209
- "use strict";
48210
- init_semaphore();
48211
- capacity = resolveCapacity();
48212
- semaphore = new Semaphore(capacity);
48213
- }
48214
- });
48215
-
48216
48488
  // src/runtime/run-worker.ts
48217
48489
  async function runWorker(input) {
48218
48490
  const { cap = true, ...childPiInput } = input;
@@ -48271,7 +48543,7 @@ var init_task_id = __esm({
48271
48543
  });
48272
48544
 
48273
48545
  // src/runtime/task-packet.ts
48274
- import * as path61 from "node:path";
48546
+ import * as path62 from "node:path";
48275
48547
  function sanitizeTaskText(task) {
48276
48548
  let sanitized = task;
48277
48549
  sanitized = sanitized.replace(/[\u200B-\u200F\u2028-\u202F\u2060-\u206F\uFEFF]/g, "");
@@ -48308,7 +48580,7 @@ function buildTaskPacket(input) {
48308
48580
  objective: sanitizedTask.replaceAll("{goal}", sanitizedGoal),
48309
48581
  scope,
48310
48582
  scopePath,
48311
- repo: path61.basename(input.manifest.cwd) || input.manifest.cwd,
48583
+ repo: path62.basename(input.manifest.cwd) || input.manifest.cwd,
48312
48584
  worktree: input.worktreePath,
48313
48585
  branchPolicy: input.manifest.workspaceMode === "worktree" ? "Use the assigned task worktree and avoid modifying the leader checkout." : "Use the current checkout; do not create branches unless explicitly requested.",
48314
48586
  acceptanceTests: [],
@@ -48459,7 +48731,7 @@ var init_team_runner_artifacts = __esm({
48459
48731
 
48460
48732
  // src/runtime/workspace-tree.ts
48461
48733
  import * as fs73 from "node:fs/promises";
48462
- import * as path62 from "node:path";
48734
+ import * as path63 from "node:path";
48463
48735
  function formatBytes2(bytes) {
48464
48736
  if (bytes < 1024) return `${bytes}B`;
48465
48737
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
@@ -48494,7 +48766,7 @@ function applyDirLimit(children, limit) {
48494
48766
  return { visible, dropped: children.length - limit };
48495
48767
  }
48496
48768
  async function readChildren(rootPath, parent, excludedDirs) {
48497
- const dirPath = parent.relativePath ? path62.join(rootPath, parent.relativePath) : rootPath;
48769
+ const dirPath = parent.relativePath ? path63.join(rootPath, parent.relativePath) : rootPath;
48498
48770
  let names;
48499
48771
  try {
48500
48772
  names = await fs73.readdir(dirPath);
@@ -48505,7 +48777,7 @@ async function readChildren(rootPath, parent, excludedDirs) {
48505
48777
  names.map(async (name) => {
48506
48778
  if (name.startsWith(".")) return null;
48507
48779
  const relativePath = parent.relativePath ? `${parent.relativePath}/${name}` : name;
48508
- const absolutePath = path62.join(rootPath, relativePath);
48780
+ const absolutePath = path63.join(rootPath, relativePath);
48509
48781
  try {
48510
48782
  const stat2 = await fs73.stat(absolutePath);
48511
48783
  if (stat2.isDirectory() && excludedDirs.has(name)) return null;
@@ -48608,10 +48880,10 @@ function applyLineCap(lines, cap) {
48608
48880
  return { lines: kept, elided: removable.length };
48609
48881
  }
48610
48882
  function treeCacheKey(cwd, options) {
48611
- return `${path62.resolve(cwd)}|${options?.maxDepth ?? ""}|${options?.dirLimit ?? ""}|${options?.lineCap ?? ""}`;
48883
+ return `${path63.resolve(cwd)}|${options?.maxDepth ?? ""}|${options?.dirLimit ?? ""}|${options?.lineCap ?? ""}`;
48612
48884
  }
48613
48885
  async function buildWorkspaceTree(cwd, options) {
48614
- const rootPath = path62.resolve(cwd);
48886
+ const rootPath = path63.resolve(cwd);
48615
48887
  const cacheKey2 = treeCacheKey(cwd, options);
48616
48888
  const cached = treeCache.get(cacheKey2);
48617
48889
  if (cached && cached.expiresAt > Date.now()) {
@@ -49056,9 +49328,9 @@ var init_task_graph_scheduler = __esm({
49056
49328
 
49057
49329
  // src/extension/knowledge-injection.ts
49058
49330
  import * as fs74 from "node:fs";
49059
- import * as path63 from "node:path";
49331
+ import * as path64 from "node:path";
49060
49332
  function knowledgePath(cwd) {
49061
- return path63.join(projectCrewRoot(cwd), KNOWLEDGE_FILENAME);
49333
+ return path64.join(projectCrewRoot(cwd), KNOWLEDGE_FILENAME);
49062
49334
  }
49063
49335
  function tokenizeHeader(header) {
49064
49336
  const tokens = /* @__PURE__ */ new Set();
@@ -49306,7 +49578,7 @@ var init_knowledge_injection = __esm({
49306
49578
  // src/runtime/agent-memory.ts
49307
49579
  import * as fs75 from "node:fs";
49308
49580
  import * as os16 from "node:os";
49309
- import * as path64 from "node:path";
49581
+ import * as path65 from "node:path";
49310
49582
  function isUnsafeMemoryName(name) {
49311
49583
  return !name || name.length > 128 || !/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name);
49312
49584
  }
@@ -49327,9 +49599,9 @@ function safeReadMemoryFile(filePath) {
49327
49599
  }
49328
49600
  function resolveMemoryDir(agentName, scope, cwd) {
49329
49601
  if (isUnsafeMemoryName(agentName)) throw new Error(`Unsafe agent name for memory directory: ${agentName}`);
49330
- if (scope === "user") return path64.join(os16.homedir(), ".pi", "agent-memory", agentName);
49331
- if (scope === "project") return path64.join(cwd, ".pi", "agent-memory", agentName);
49332
- return path64.join(cwd, ".pi", "agent-memory-local", agentName);
49602
+ if (scope === "user") return path65.join(os16.homedir(), ".pi", "agent-memory", agentName);
49603
+ if (scope === "project") return path65.join(cwd, ".pi", "agent-memory", agentName);
49604
+ return path65.join(cwd, ".pi", "agent-memory-local", agentName);
49333
49605
  }
49334
49606
  function ensureMemoryDir(memoryDir) {
49335
49607
  if (fs75.existsSync(memoryDir)) {
@@ -49340,7 +49612,7 @@ function ensureMemoryDir(memoryDir) {
49340
49612
  }
49341
49613
  function readMemoryIndex(memoryDir) {
49342
49614
  if (isSymlink(memoryDir)) return void 0;
49343
- const memPath = path64.join(memoryDir, "MEMORY.md");
49615
+ const memPath = path65.join(memoryDir, "MEMORY.md");
49344
49616
  const content = safeReadMemoryFile(memPath);
49345
49617
  if (content === void 0) return void 0;
49346
49618
  const lines = content.split(/\r?\n/);
@@ -49424,7 +49696,7 @@ var init_context_retrieval = __esm({
49424
49696
  // src/runtime/task-runner/retrieval-orchestrator.ts
49425
49697
  import { spawn as spawn4 } from "node:child_process";
49426
49698
  import * as fs76 from "node:fs";
49427
- import * as path65 from "node:path";
49699
+ import * as path66 from "node:path";
49428
49700
  async function detectRipgrep() {
49429
49701
  if (cachedRgCheck !== void 0) return cachedRgCheck;
49430
49702
  return await new Promise((resolve23) => {
@@ -49517,18 +49789,18 @@ async function walkFilesFallback(cwd, keywords) {
49517
49789
  }
49518
49790
  for (const entry of entries) {
49519
49791
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
49520
- const full = path65.join(dir, entry.name);
49792
+ const full = path66.join(dir, entry.name);
49521
49793
  if (entry.isDirectory()) {
49522
49794
  await walk(full);
49523
49795
  continue;
49524
49796
  }
49525
49797
  if (!entry.isFile()) continue;
49526
- const ext = path65.extname(entry.name).toLowerCase();
49798
+ const ext = path66.extname(entry.name).toLowerCase();
49527
49799
  if (!RELEVANT_EXTS.has(ext)) continue;
49528
49800
  const content = "";
49529
49801
  const score = scoreRelevance(full, content, keywords);
49530
49802
  if (score > 0) {
49531
- out.push({ path: path65.relative(lowerCwd, full), score, reason: reasonFor(full, keywords) });
49803
+ out.push({ path: path66.relative(lowerCwd, full), score, reason: reasonFor(full, keywords) });
49532
49804
  }
49533
49805
  }
49534
49806
  }
@@ -49551,7 +49823,7 @@ async function runRetrievalCycle(task, goal, cwd) {
49551
49823
  try {
49552
49824
  if (useRg) {
49553
49825
  const stdout = await runRipgrep(["--files", "-g", "!node_modules", "-g", "!.git", cwd], cwd);
49554
- discovered = stdout.split("\n").map((p) => p.trim()).filter((p) => p && RELEVANT_EXTS.has(path65.extname(p).toLowerCase())).map((p) => path65.relative(cwd, p));
49826
+ discovered = stdout.split("\n").map((p) => p.trim()).filter((p) => p && RELEVANT_EXTS.has(path66.extname(p).toLowerCase())).map((p) => path66.relative(cwd, p));
49555
49827
  } else {
49556
49828
  discovered = (await walkFilesFallback(cwd, keywords)).map((f) => f.path);
49557
49829
  }
@@ -49563,7 +49835,7 @@ async function runRetrievalCycle(task, goal, cwd) {
49563
49835
  for (const relPath of discovered) {
49564
49836
  if (seenInThisCycle.has(relPath)) continue;
49565
49837
  seenInThisCycle.add(relPath);
49566
- const absPath = path65.isAbsolute(relPath) ? relPath : path65.join(cwd, relPath);
49838
+ const absPath = path66.isAbsolute(relPath) ? relPath : path66.join(cwd, relPath);
49567
49839
  const score = scoreRelevance(absPath, "", keywords);
49568
49840
  if (score > 0) {
49569
49841
  evaluations.push({
@@ -49581,7 +49853,7 @@ async function runRetrievalCycle(task, goal, cwd) {
49581
49853
  evaluations.sort((a, b) => b.relevance - a.relevance);
49582
49854
  const cap = Math.min(MAX_SUGGESTED_FILES, Math.max(MIN_SUGGESTED_FILES, evaluations.length));
49583
49855
  const top = evaluations.slice(0, cap).map((e) => ({
49584
- path: path65.isAbsolute(e.path) ? path65.relative(cwd, e.path) : e.path,
49856
+ path: path66.isAbsolute(e.path) ? path66.relative(cwd, e.path) : e.path,
49585
49857
  score: e.relevance,
49586
49858
  reason: e.reason
49587
49859
  }));
@@ -50002,29 +50274,24 @@ function recordSupervisorContact(manifest, payload) {
50002
50274
  logInternalError("supervisor-contact.record", error, `runId=${manifest.runId} taskId=${payload.taskId}`);
50003
50275
  }
50004
50276
  }
50005
- function parseSupervisorContactFromLine(line4) {
50006
- if (!line4.trim()) return void 0;
50007
- let parsed;
50008
- try {
50009
- parsed = JSON.parse(line4);
50010
- } catch {
50011
- return void 0;
50012
- }
50013
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
50014
- const record = parsed;
50277
+ function supervisorContactFromEvent(event) {
50278
+ if (!event || typeof event !== "object" || Array.isArray(event)) return void 0;
50279
+ const record = event;
50015
50280
  if (record.type !== "supervisor_contact" && record.type !== "crew_supervisor_contact") return void 0;
50016
50281
  return {
50017
50282
  taskId: typeof record.taskId === "string" ? record.taskId : "",
50018
- reason: typeof record.reason === "string" && ["decision_needed", "clarification", "approval", "error_escalation", "custom"].includes(record.reason) ? record.reason : "custom",
50283
+ reason: typeof record.reason === "string" && SUPERVISOR_CONTACT_REASONS.includes(record.reason) ? record.reason : "custom",
50019
50284
  message: typeof record.message === "string" ? record.message : String(record.message ?? ""),
50020
50285
  data: record.data && typeof record.data === "object" && !Array.isArray(record.data) ? record.data : void 0
50021
50286
  };
50022
50287
  }
50288
+ var SUPERVISOR_CONTACT_REASONS;
50023
50289
  var init_supervisor_contact = __esm({
50024
50290
  "src/runtime/supervisor-contact.ts"() {
50025
50291
  "use strict";
50026
50292
  init_event_log();
50027
50293
  init_internal_error();
50294
+ SUPERVISOR_CONTACT_REASONS = ["decision_needed", "clarification", "approval", "error_escalation", "custom"];
50028
50295
  }
50029
50296
  });
50030
50297
 
@@ -50349,7 +50616,7 @@ var init_tail_read = __esm({
50349
50616
 
50350
50617
  // src/runtime/task-runner/child-executor.ts
50351
50618
  import * as fs80 from "node:fs";
50352
- import * as path66 from "node:path";
50619
+ import * as path67 from "node:path";
50353
50620
  async function appendSteeringAsync(steeringDir, taskId, steers) {
50354
50621
  try {
50355
50622
  await fs80.promises.mkdir(steeringDir, { recursive: true });
@@ -50499,7 +50766,7 @@ async function runChildProcessTask(ctx) {
50499
50766
  };
50500
50767
  for (let i = 0; i < attemptModels.length; i++) {
50501
50768
  transcriptPath = `${manifest.artifactsRoot}/transcripts/${task.id}.attempt-${i}.jsonl`;
50502
- await fs80.promises.mkdir(path66.join(manifest.artifactsRoot, "transcripts"), {
50769
+ await fs80.promises.mkdir(path67.join(manifest.artifactsRoot, "transcripts"), {
50503
50770
  recursive: true
50504
50771
  });
50505
50772
  const model = attemptModels[i];
@@ -50598,16 +50865,11 @@ async function runChildProcessTask(ctx) {
50598
50865
  onStdoutLine: (line4) => {
50599
50866
  appendCrewAgentOutput(manifest, task.id, line4);
50600
50867
  persistHeartbeat();
50601
- const contact = parseSupervisorContactFromLine(line4);
50602
- if (contact) {
50603
- recordSupervisorContact(manifest, {
50604
- runId: manifest.runId,
50605
- ...contact
50606
- });
50607
- }
50608
50868
  },
50609
50869
  onJsonEvent: (event) => {
50610
50870
  try {
50871
+ const contact = supervisorContactFromEvent(event);
50872
+ if (contact) recordSupervisorContact(manifest, { runId: manifest.runId, ...contact });
50611
50873
  appendCrewAgentEvent(manifest, task.id, event);
50612
50874
  if (collectedJsonEvents && event && typeof event === "object" && !Array.isArray(event))
50613
50875
  collectedJsonEvents.push(event);
@@ -50910,7 +51172,7 @@ var init_child_executor = __esm({
50910
51172
  import { execFile, execFileSync as execFileSync6, spawnSync as spawnSync3 } from "node:child_process";
50911
51173
  import { randomBytes as randomBytes3 } from "node:crypto";
50912
51174
  import * as fs81 from "node:fs";
50913
- import * as path67 from "node:path";
51175
+ import * as path68 from "node:path";
50914
51176
  import { promisify } from "node:util";
50915
51177
  function git3(cwd, args) {
50916
51178
  return execFileSync6("git", args, {
@@ -51012,8 +51274,8 @@ async function assertCleanLeaderAsync(repoRoot) {
51012
51274
  _cleanLeaderCache.add(repoRoot);
51013
51275
  }
51014
51276
  function linkNodeModulesIfPresent(repoRoot, worktreePath) {
51015
- const source = path67.join(repoRoot, "node_modules");
51016
- const target = path67.join(worktreePath, "node_modules");
51277
+ const source = path68.join(repoRoot, "node_modules");
51278
+ const target = path68.join(worktreePath, "node_modules");
51017
51279
  let sourceStat;
51018
51280
  try {
51019
51281
  sourceStat = fs81.statSync(source);
@@ -51036,15 +51298,15 @@ function linkNodeModulesIfPresent(repoRoot, worktreePath) {
51036
51298
  }
51037
51299
  }
51038
51300
  function normalizeSyntheticPath(worktreePath, rawPath) {
51039
- const resolved = path67.resolve(worktreePath, rawPath);
51040
- const relative9 = path67.relative(worktreePath, resolved);
51041
- if (!relative9 || relative9.startsWith("..") || path67.isAbsolute(relative9)) throw new Error(`synthetic path escapes worktree: ${rawPath}`);
51042
- return path67.normalize(relative9);
51301
+ const resolved = path68.resolve(worktreePath, rawPath);
51302
+ const relative9 = path68.relative(worktreePath, resolved);
51303
+ if (!relative9 || relative9.startsWith("..") || path68.isAbsolute(relative9)) throw new Error(`synthetic path escapes worktree: ${rawPath}`);
51304
+ return path68.normalize(relative9);
51043
51305
  }
51044
51306
  function isAllowedSetupHook(hookPath) {
51045
51307
  if (!hookPath || hookPath.trim().length === 0) return false;
51046
- if (!path67.isAbsolute(hookPath)) {
51047
- const normalized = path67.posix.normalize(hookPath);
51308
+ if (!path68.isAbsolute(hookPath)) {
51309
+ const normalized = path68.posix.normalize(hookPath);
51048
51310
  return normalized === ".hooks" || normalized.startsWith(".hooks/");
51049
51311
  }
51050
51312
  const normalizedHookPath = hookPath.replace(/\\/g, "/");
@@ -51054,8 +51316,8 @@ function isAllowedSetupHook(hookPath) {
51054
51316
  function isHookPathContainedInRepoRoot(repoRoot, hookPath) {
51055
51317
  try {
51056
51318
  const realRepoRoot = fs81.realpathSync(repoRoot);
51057
- const realHookPath = fs81.realpathSync(path67.dirname(hookPath));
51058
- return realHookPath.startsWith(realRepoRoot + path67.sep) || realHookPath === realRepoRoot;
51319
+ const realHookPath = fs81.realpathSync(path68.dirname(hookPath));
51320
+ return realHookPath.startsWith(realRepoRoot + path68.sep) || realHookPath === realRepoRoot;
51059
51321
  } catch {
51060
51322
  return false;
51061
51323
  }
@@ -51068,15 +51330,15 @@ function runSetupHook(manifest, task, repoRoot, worktreePath, branch) {
51068
51330
  logInternalError("worktree.setupHook.rejected", new Error("hook path not allowed: " + rawHookPath), `cwd=${manifest.cwd}`);
51069
51331
  return [];
51070
51332
  }
51071
- if (path67.isAbsolute(rawHookPath)) {
51333
+ if (path68.isAbsolute(rawHookPath)) {
51072
51334
  logInternalError(
51073
51335
  "worktree.setupHook.homeHook",
51074
51336
  new Error("Home directory hook used \u2014 ensure ~/.pi/hooks/ is trusted"),
51075
51337
  `hookPath=${rawHookPath}`
51076
51338
  );
51077
51339
  }
51078
- const hookPath = path67.isAbsolute(rawHookPath) ? rawHookPath : path67.resolve(repoRoot, rawHookPath);
51079
- if (!path67.isAbsolute(rawHookPath) && !isHookPathContainedInRepoRoot(repoRoot, hookPath)) {
51340
+ const hookPath = path68.isAbsolute(rawHookPath) ? rawHookPath : path68.resolve(repoRoot, rawHookPath);
51341
+ if (!path68.isAbsolute(rawHookPath) && !isHookPathContainedInRepoRoot(repoRoot, hookPath)) {
51080
51342
  logInternalError(
51081
51343
  "worktree.setupHook.contained",
51082
51344
  new Error("hook path escapes repoRoot after realpath resolution: " + hookPath),
@@ -51202,24 +51464,33 @@ async function branchExistsAsync(repoRoot, branch) {
51202
51464
  }
51203
51465
  }
51204
51466
  async function pruneStaleWorktreesAsync(repoRoot) {
51205
- try {
51206
- await execFileAsync("git", ["worktree", "prune"], {
51207
- cwd: repoRoot,
51208
- windowsHide: true
51209
- });
51210
- } catch {
51211
- }
51467
+ if (_prunedRepos.has(repoRoot)) return;
51468
+ const inFlight = _pruneInFlight.get(repoRoot);
51469
+ if (inFlight) return inFlight;
51470
+ const p = (async () => {
51471
+ try {
51472
+ await execFileAsync("git", ["worktree", "prune"], {
51473
+ cwd: repoRoot,
51474
+ windowsHide: true
51475
+ });
51476
+ } catch {
51477
+ }
51478
+ _prunedRepos.add(repoRoot);
51479
+ _pruneInFlight.delete(repoRoot);
51480
+ })();
51481
+ _pruneInFlight.set(repoRoot, p);
51482
+ return p;
51212
51483
  }
51213
51484
  function normalizeSeedPaths(seedPaths, repoRoot) {
51214
- const resolvedRepoRoot = path67.resolve(repoRoot);
51485
+ const resolvedRepoRoot = path68.resolve(repoRoot);
51215
51486
  const entries = Array.isArray(seedPaths) ? seedPaths : [];
51216
51487
  const seen = /* @__PURE__ */ new Set();
51217
51488
  const normalized = [];
51218
51489
  for (const entry of entries) {
51219
51490
  if (typeof entry !== "string" || entry.trim().length === 0) continue;
51220
- const absolutePath = path67.resolve(resolvedRepoRoot, entry);
51221
- const relativePath = path67.relative(resolvedRepoRoot, absolutePath);
51222
- if (relativePath.startsWith("..") || path67.isAbsolute(relativePath)) {
51491
+ const absolutePath = path68.resolve(resolvedRepoRoot, entry);
51492
+ const relativePath = path68.relative(resolvedRepoRoot, absolutePath);
51493
+ if (relativePath.startsWith("..") || path68.isAbsolute(relativePath)) {
51223
51494
  throw new Error(`seedPaths entries must stay inside repoRoot: ${entry}`);
51224
51495
  }
51225
51496
  try {
@@ -51233,7 +51504,7 @@ function normalizeSeedPaths(seedPaths, repoRoot) {
51233
51504
  throw new Error(`seedPaths entries must be accessible: ${entry}`);
51234
51505
  }
51235
51506
  }
51236
- const normalizedPath = relativePath.split(path67.sep).join("/");
51507
+ const normalizedPath = relativePath.split(path68.sep).join("/");
51237
51508
  if (seen.has(normalizedPath)) continue;
51238
51509
  seen.add(normalizedPath);
51239
51510
  normalized.push(normalizedPath);
@@ -51243,8 +51514,8 @@ function normalizeSeedPaths(seedPaths, repoRoot) {
51243
51514
  function overlaySeedPaths(repoRoot, worktreePath, seedPaths) {
51244
51515
  const normalized = normalizeSeedPaths(seedPaths, repoRoot);
51245
51516
  for (const seedPath of normalized) {
51246
- const sourcePath = path67.join(repoRoot, seedPath);
51247
- const destinationPath = path67.join(worktreePath, seedPath);
51517
+ const sourcePath = path68.join(repoRoot, seedPath);
51518
+ const destinationPath = path68.join(worktreePath, seedPath);
51248
51519
  let sourceStat;
51249
51520
  try {
51250
51521
  sourceStat = fs81.lstatSync(sourcePath);
@@ -51260,7 +51531,7 @@ function overlaySeedPaths(repoRoot, worktreePath, seedPaths) {
51260
51531
  logInternalError("worktree.seedPaths.invalid", new Error(`Seed path is neither file nor directory: ${seedPath}`));
51261
51532
  continue;
51262
51533
  }
51263
- fs81.mkdirSync(path67.dirname(destinationPath), { recursive: true });
51534
+ fs81.mkdirSync(path68.dirname(destinationPath), { recursive: true });
51264
51535
  fs81.rmSync(destinationPath, { force: true, recursive: true });
51265
51536
  fs81.cpSync(sourcePath, destinationPath, {
51266
51537
  dereference: true,
@@ -51292,7 +51563,7 @@ function snapshotDirtyWorktree(manifest, task, worktreePath, dirtyStatus) {
51292
51563
  const rel = line4.slice(3).replace(/^"|"$/g, "");
51293
51564
  if (!rel) continue;
51294
51565
  try {
51295
- const abs = path67.join(worktreePath, rel);
51566
+ const abs = path68.join(worktreePath, rel);
51296
51567
  if (!fs81.existsSync(abs) || fs81.statSync(abs).isDirectory()) continue;
51297
51568
  const content = fs81.readFileSync(abs, "utf-8");
51298
51569
  parts.push(`## Untracked file: ${rel}`, "```", content, "```", "");
@@ -51336,7 +51607,7 @@ async function prepareTaskWorkspaceAsync(manifest, task, stepSeedPaths) {
51336
51607
  const loadedConfig = loadConfig(manifest.cwd);
51337
51608
  if (loadedConfig.config.requireCleanWorktreeLeader !== false) await assertCleanLeaderAsync(repoRoot);
51338
51609
  const sanitizedRunId = manifest.runId.replace(/[^a-zA-Z0-9._-]/g, "-").replace(/^-+|-+$/g, "") || "run";
51339
- const worktreeRoot = path67.join(projectCrewRoot(manifest.cwd), DEFAULT_PATHS.state.worktreesSubdir, sanitizedRunId);
51610
+ const worktreeRoot = path68.join(projectCrewRoot(manifest.cwd), DEFAULT_PATHS.state.worktreesSubdir, sanitizedRunId);
51340
51611
  fs81.mkdirSync(worktreeRoot, { recursive: true });
51341
51612
  let resolvedWorktreeRoot = worktreeRoot;
51342
51613
  try {
@@ -51349,7 +51620,7 @@ async function prepareTaskWorkspaceAsync(manifest, task, stepSeedPaths) {
51349
51620
  }
51350
51621
  }
51351
51622
  const sanitizedTaskId = sanitizeBranchPart2(task.id);
51352
- const worktreePath = path67.join(resolvedWorktreeRoot, sanitizedTaskId);
51623
+ const worktreePath = path68.join(resolvedWorktreeRoot, sanitizedTaskId);
51353
51624
  const branch = `pi-crew/${sanitizeBranchPart2(manifest.runId)}/${sanitizeBranchPart2(task.id)}`;
51354
51625
  let worktreeExists = false;
51355
51626
  try {
@@ -51501,10 +51772,10 @@ async function prepareAgentWorktreeAsync(manifest, agentId) {
51501
51772
  const loadedConfig = loadConfig(manifest.cwd);
51502
51773
  if (loadedConfig.config.requireCleanWorktreeLeader !== false) await assertCleanLeaderAsync(repoRoot);
51503
51774
  const sanitizedRunId = manifest.runId.replace(/[^a-zA-Z0-9._-]/g, "-").replace(/^-+|-+$/g, "") || "run";
51504
- const worktreeRoot = path67.join(projectCrewRoot(manifest.cwd), DEFAULT_PATHS.state.worktreesSubdir, sanitizedRunId);
51775
+ const worktreeRoot = path68.join(projectCrewRoot(manifest.cwd), DEFAULT_PATHS.state.worktreesSubdir, sanitizedRunId);
51505
51776
  fs81.mkdirSync(worktreeRoot, { recursive: true });
51506
51777
  const sanitizedAgentId = sanitizeBranchPart2(agentId);
51507
- const worktreePath = path67.join(worktreeRoot, sanitizedAgentId);
51778
+ const worktreePath = path68.join(worktreeRoot, sanitizedAgentId);
51508
51779
  const branch = `pi-crew/${sanitizedRunId}/${sanitizedAgentId}`;
51509
51780
  await pruneStaleWorktreesAsync(repoRoot);
51510
51781
  await gitAsync(repoRoot, ["worktree", "add", "-b", branch, worktreePath, "HEAD"]);
@@ -51562,7 +51833,7 @@ async function cleanupAgentWorktreeAsync(manifest, worktreePath, branch) {
51562
51833
  logInternalError("worktree.agent-cleanup.prune", error, `worktreePath=${worktreePath}`);
51563
51834
  }
51564
51835
  }
51565
- var execFileAsync, _gitRootCache, _cleanLeaderCache;
51836
+ var execFileAsync, _gitRootCache, _cleanLeaderCache, _prunedRepos, _pruneInFlight;
51566
51837
  var init_worktree_manager = __esm({
51567
51838
  "src/worktree/worktree-manager.ts"() {
51568
51839
  "use strict";
@@ -51576,6 +51847,8 @@ var init_worktree_manager = __esm({
51576
51847
  execFileAsync = promisify(execFile);
51577
51848
  _gitRootCache = /* @__PURE__ */ new Map();
51578
51849
  _cleanLeaderCache = /* @__PURE__ */ new Set();
51850
+ _prunedRepos = /* @__PURE__ */ new Set();
51851
+ _pruneInFlight = /* @__PURE__ */ new Map();
51579
51852
  }
51580
51853
  });
51581
51854
 
@@ -51635,7 +51908,7 @@ var init_output_validator = __esm({
51635
51908
  // src/runtime/verification-gates.ts
51636
51909
  import { spawn as spawn5 } from "node:child_process";
51637
51910
  import * as fs82 from "node:fs";
51638
- import * as path68 from "node:path";
51911
+ import * as path69 from "node:path";
51639
51912
  function isVerificationEnvSanitizeEnabled() {
51640
51913
  if (process.env.PI_CREW_VERIFICATION_SANITIZE_ENV === "0" || process.env.PI_TEAMS_VERIFICATION_SANITIZE_ENV === "0") {
51641
51914
  return false;
@@ -51791,7 +52064,7 @@ async function executeVerificationCommands(contract, cwd, runId, taskId, artifac
51791
52064
  critical: true
51792
52065
  // All verification commands are critical by default
51793
52066
  }));
51794
- const gatesDir = path68.join(artifactsRoot, "verification-gates");
52067
+ const gatesDir = path69.join(artifactsRoot, "verification-gates");
51795
52068
  if (!fs82.existsSync(gatesDir)) {
51796
52069
  fs82.mkdirSync(gatesDir, { recursive: true });
51797
52070
  }
@@ -51957,13 +52230,13 @@ var init_capabilities = __esm({
51957
52230
  });
51958
52231
 
51959
52232
  // src/runtime/task-runner/prompt-pipeline.ts
51960
- import * as path69 from "node:path";
52233
+ import * as path70 from "node:path";
51961
52234
  function artifactReference(artifactsRoot, artifact) {
51962
52235
  if (!artifact) return void 0;
51963
- const root = path69.resolve(artifactsRoot);
51964
- const target = path69.resolve(artifact.path);
51965
- const relative9 = path69.relative(root, target);
51966
- if (!relative9 || relative9.startsWith("..") || path69.isAbsolute(relative9)) return void 0;
52236
+ const root = path70.resolve(artifactsRoot);
52237
+ const target = path70.resolve(artifact.path);
52238
+ const relative9 = path70.relative(root, target);
52239
+ if (!relative9 || relative9.startsWith("..") || path70.isAbsolute(relative9)) return void 0;
51967
52240
  return relative9.replaceAll("\\", "/");
51968
52241
  }
51969
52242
  function buildWorkerPromptPipeline(input) {
@@ -53839,9 +54112,9 @@ __export(team_runner_exports, {
53839
54112
  shouldUseRetry: () => shouldUseRetry
53840
54113
  });
53841
54114
  import * as fs85 from "node:fs";
53842
- import * as path70 from "node:path";
54115
+ import * as path71 from "node:path";
53843
54116
  function startTeamRunHeartbeat(stateRoot, runId) {
53844
- const heartbeatPath = path70.join(stateRoot, "heartbeat.json");
54117
+ const heartbeatPath = path71.join(stateRoot, "heartbeat.json");
53845
54118
  const writeHeartbeat = () => {
53846
54119
  try {
53847
54120
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -54316,8 +54589,9 @@ async function executeTeamRun(input) {
54316
54589
  await saveRunTasksAsync(manifest, tasks);
54317
54590
  const existingRuntimeByTask = new Map(readCrewAgents(manifest).map((agent) => [agent.taskId, agent.runtime]));
54318
54591
  const globalRuntime = input.runtime?.kind ?? "child-process";
54592
+ const taskById2 = new Map(tasks.map((item) => [item.id, item]));
54319
54593
  const runtimeForAgent = (agent) => {
54320
- const task = tasks.find((item) => item.id === agent.taskId);
54594
+ const task = taskById2.get(agent.taskId);
54321
54595
  return existingRuntimeByTask.get(agent.taskId) ?? resolveTaskRuntimeKind(globalRuntime, task?.role ?? agent.role, input.runtimeConfig?.isolationPolicy);
54322
54596
  };
54323
54597
  saveCrewAgents(
@@ -54370,14 +54644,17 @@ async function cancelRunFromSignal(ctx) {
54370
54644
  return base;
54371
54645
  });
54372
54646
  await saveRunTasksAsync(ctx.manifest, ctx.tasks);
54373
- for (const taskId of cancelledTaskIds)
54374
- await appendEventAsync(ctx.manifest.eventsPath, {
54375
- type: "task.cancelled",
54376
- runId: ctx.manifest.runId,
54377
- taskId,
54378
- message,
54379
- data: { reason: cancelReason.code }
54380
- });
54647
+ await Promise.all(
54648
+ cancelledTaskIds.map(
54649
+ (taskId) => appendEventAsync(ctx.manifest.eventsPath, {
54650
+ type: "task.cancelled",
54651
+ runId: ctx.manifest.runId,
54652
+ taskId,
54653
+ message,
54654
+ data: { reason: cancelReason.code }
54655
+ })
54656
+ )
54657
+ );
54381
54658
  ctx.manifest = updateRunStatus(ctx.manifest, "cancelled", message, {
54382
54659
  data: { reason: cancelReason.code, cancelledTaskIds }
54383
54660
  });
@@ -54458,7 +54735,8 @@ async function selectDispatchBatch(ctx) {
54458
54735
  }
54459
54736
  }
54460
54737
  }
54461
- const readyRoles = readyBeforeFilter.map((taskId) => ctx.tasks.find((task) => task.id === taskId)?.role).filter((role) => Boolean(role));
54738
+ const taskByIdReady = new Map(ctx.tasks.map((t2) => [t2.id, t2]));
54739
+ const readyRoles = readyBeforeFilter.map((taskId) => taskByIdReady.get(taskId)?.role).filter((role) => Boolean(role));
54462
54740
  const concurrency = resolveBatchConcurrency({
54463
54741
  workflowName: ctx.workflow.name,
54464
54742
  workflowMaxConcurrency: ctx.workflow.maxConcurrency,
@@ -54513,7 +54791,8 @@ async function selectDispatchBatch(ctx) {
54513
54791
  const approvalPending = isPlanApprovalPending2(ctx.manifest);
54514
54792
  const dispatchableReady = serializedReady.filter((id) => !inFlightTaskIds.has(id));
54515
54793
  const readyIds = approvalPending ? dispatchableReady : dispatchableReady.slice(0, slotsAvailable);
54516
- const candidateBatch = readyIds.map((id) => ctx.tasks.find((task) => task.id === id)).filter((task) => Boolean(task));
54794
+ const taskByIdDispatch = new Map(ctx.tasks.map((t2) => [t2.id, t2]));
54795
+ const candidateBatch = readyIds.map((id) => taskByIdDispatch.get(id)).filter((task) => Boolean(task));
54517
54796
  const readyBatch = approvalPending ? candidateBatch.filter((task) => !isMutatingTask(task)).slice(0, slotsAvailable) : candidateBatch;
54518
54797
  if (readyBatch.length === 0) {
54519
54798
  if (ctx.pendingUnits.size > 0) {
@@ -54551,12 +54830,16 @@ async function dispatchBatch(ctx, decision2) {
54551
54830
  concurrencyReason: approvalPending ? `${concurrency.reason};plan-approval-read-only` : concurrency.reason
54552
54831
  }
54553
54832
  });
54554
- for (const task of readyBatch) {
54555
- const taskReport = await executeHook("before_task_start", {
54556
- runId: ctx.manifest.runId,
54557
- taskId: task.id,
54558
- cwd: ctx.manifest.cwd
54559
- });
54833
+ const beforeTaskStartReports = await Promise.all(
54834
+ readyBatch.map(
54835
+ (task) => executeHook("before_task_start", {
54836
+ runId: ctx.manifest.runId,
54837
+ taskId: task.id,
54838
+ cwd: ctx.manifest.cwd
54839
+ }).then((taskReport) => ({ task, taskReport }))
54840
+ )
54841
+ );
54842
+ for (const { task, taskReport } of beforeTaskStartReports) {
54560
54843
  appendHookEvent(ctx.manifest, taskReport);
54561
54844
  if (taskReport.outcome === "block") {
54562
54845
  ctx.tasks = ctx.tasks.map(
@@ -54569,7 +54852,11 @@ async function dispatchBatch(ctx, decision2) {
54569
54852
  ctx.manifest = updateRunStatus(ctx.manifest, ctx.manifest.status, `Task '${task.id}' blocked by hook.`);
54570
54853
  }
54571
54854
  }
54572
- const batchTasks = readyBatch.filter((task) => ctx.tasks.find((t2) => t2.id === task.id && t2.status !== "skipped"));
54855
+ const ctxTaskById = new Map(ctx.tasks.map((t2) => [t2.id, t2]));
54856
+ const batchTasks = readyBatch.filter((task) => {
54857
+ const t2 = ctxTaskById.get(task.id);
54858
+ return t2 !== void 0 && t2.status !== "skipped";
54859
+ });
54573
54860
  if (batchTasks.length > 1) {
54574
54861
  await appendEventAsync(ctx.manifest.eventsPath, {
54575
54862
  type: "task.parallel_start",
@@ -54879,12 +55166,13 @@ async function advanceWorkflowPhases(ctx) {
54879
55166
  existing.push(task.id);
54880
55167
  phaseTaskMap.set(task.stepId, existing);
54881
55168
  }
55169
+ const taskById2 = new Map(tasks.map((t2) => [t2.id, t2]));
54882
55170
  for (let pi = wfMachine.currentPhaseIndex; pi < wfMachine.phases.length; pi++) {
54883
55171
  const phase = wfMachine.phases[pi];
54884
55172
  const phaseTaskIds = phaseTaskMap.get(phase.name) ?? [];
54885
55173
  if (phaseTaskIds.length === 0) continue;
54886
55174
  const allTerminal = phaseTaskIds.every((taskId) => {
54887
- const task = tasks.find((t2) => t2.id === taskId);
55175
+ const task = taskById2.get(taskId);
54888
55176
  return task ? terminalStatuses.has(task.status) : false;
54889
55177
  });
54890
55178
  if (!allTerminal) break;
@@ -54900,7 +55188,7 @@ async function advanceWorkflowPhases(ctx) {
54900
55188
  outputPath: t2.resultArtifact?.path
54901
55189
  }))
54902
55190
  };
54903
- const phaseTasks = phaseTaskIds.map((taskId) => tasks.find((t2) => t2.id === taskId)).filter((t2) => t2 !== void 0);
55191
+ const phaseTasks = phaseTaskIds.map((taskId) => taskById2.get(taskId)).filter((t2) => t2 !== void 0);
54904
55192
  const hasFailedOrCancelled = phaseTasks.some((t2) => t2.status === "failed" || t2.status === "cancelled");
54905
55193
  const phaseStatus = hasFailedOrCancelled ? "failed" : "completed";
54906
55194
  const transition = transitionPhase(wfMachine, pi, phaseStatus, wfContext);
@@ -54971,23 +55259,31 @@ async function enforceRunBudget(ctx) {
54971
55259
  }
54972
55260
  });
54973
55261
  }
55262
+ const fairShareAppends = [];
54974
55263
  for (const violatorId of budgetCheck.fairShareViolators) {
54975
55264
  const violator = tasks.find((t2) => t2.id === violatorId);
54976
55265
  if (!violator) continue;
54977
55266
  const taskTotal = (violator.usage?.input ?? 0) + (violator.usage?.output ?? 0) + (violator.usage?.cacheWrite ?? 0);
54978
55267
  const message = `Task '${violatorId}' consumed ${formatTokens(taskTotal)} (${Math.round(taskTotal / input.budgetTotal * 100)}% of total budget) \u2014 exceeds fair share`;
54979
55268
  console.warn(`[team-runner.fair-share] ${message}`);
54980
- await appendEventAsync(manifest.eventsPath, {
54981
- type: "task.budget_fair_share",
54982
- runId: manifest.runId,
54983
- taskId: violatorId,
54984
- message,
54985
- data: {
54986
- budgetTotal: input.budgetTotal,
54987
- taskUsage: taskTotal
54988
- }
54989
- });
55269
+ fairShareAppends.push(
55270
+ appendEventAsync(manifest.eventsPath, {
55271
+ type: "task.budget_fair_share",
55272
+ runId: manifest.runId,
55273
+ taskId: violatorId,
55274
+ message,
55275
+ data: {
55276
+ budgetTotal: input.budgetTotal,
55277
+ taskUsage: taskTotal
55278
+ }
55279
+ }).then(
55280
+ () => {
55281
+ },
55282
+ (error) => logInternalError("team-runner.fair-share-event", error, `taskId=${violatorId}`)
55283
+ )
55284
+ );
54990
55285
  }
55286
+ await Promise.all(fairShareAppends);
54991
55287
  }
54992
55288
  return null;
54993
55289
  }
@@ -55003,7 +55299,7 @@ async function finalizeRun(ctx) {
55003
55299
  const missingOutputs = [];
55004
55300
  for (const step of input.workflow.steps) {
55005
55301
  if (step.output && typeof step.output === "string") {
55006
- const outputPath = path70.join(manifest.artifactsRoot, step.output);
55302
+ const outputPath = path71.join(manifest.artifactsRoot, step.output);
55007
55303
  if (!fs85.existsSync(outputPath)) {
55008
55304
  missingOutputs.push(step.output);
55009
55305
  }
@@ -55097,7 +55393,7 @@ async function finalizeRun(ctx) {
55097
55393
  await saveRunTasksAsync(finalManifest, tasks);
55098
55394
  });
55099
55395
  manifest = finalManifest;
55100
- const crewRoot = path70.dirname(path70.dirname(path70.dirname(finalManifest.stateRoot)));
55396
+ const crewRoot = path71.dirname(path71.dirname(path71.dirname(finalManifest.stateRoot)));
55101
55397
  const healthStore = new HealthStore(crewRoot);
55102
55398
  healthStore.saveSnapshot({
55103
55399
  runId: finalManifest.runId,
@@ -55287,7 +55583,7 @@ async function executeTeamRunCore(input, manifest, workflow) {
55287
55583
  return { manifest, tasks };
55288
55584
  }
55289
55585
  await saveRunTasksAsync(manifest, tasks);
55290
- saveCrewAgents(manifest, recordsForMaterializedTasks(manifest, tasks, runtimeKind));
55586
+ saveCrewAgentsCoalesced(manifest, recordsForMaterializedTasks(manifest, tasks, runtimeKind));
55291
55587
  const completedBatch = tasks.filter((t2) => settledTaskIds.includes(t2.id));
55292
55588
  const batchArtifact = writeArtifact(manifest.artifactsRoot, {
55293
55589
  kind: "summary",
@@ -55718,7 +56014,7 @@ __export(crew_init_exports, {
55718
56014
  updateGitignore: () => updateGitignore
55719
56015
  });
55720
56016
  import * as fs87 from "node:fs";
55721
- import * as path71 from "node:path";
56017
+ import * as path72 from "node:path";
55722
56018
  function buildCrewReadme() {
55723
56019
  return `# .crew \u2014 pi-crew Runtime Directory
55724
56020
 
@@ -55788,7 +56084,7 @@ function safeDirname(p) {
55788
56084
  return p.slice(0, idx);
55789
56085
  }
55790
56086
  function safeResolve(p, pathDep) {
55791
- const dep = pathDep ?? path71;
56087
+ const dep = pathDep ?? path72;
55792
56088
  if (dep && typeof dep.resolve === "function") return dep.resolve(p);
55793
56089
  return p;
55794
56090
  }
@@ -57044,9 +57340,9 @@ __export(parallel_research_exports, {
57044
57340
  sourcePiProjects: () => sourcePiProjects
57045
57341
  });
57046
57342
  import * as fs88 from "node:fs";
57047
- import * as path72 from "node:path";
57343
+ import * as path73 from "node:path";
57048
57344
  function sourcePiProjects(cwd) {
57049
- const sourceDir = path72.join(cwd, "Source");
57345
+ const sourceDir = path73.join(cwd, "Source");
57050
57346
  try {
57051
57347
  return fs88.readdirSync(sourceDir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.startsWith("pi-")).map((entry) => `Source/${entry.name}`).sort();
57052
57348
  } catch {
@@ -57224,8 +57520,8 @@ var init_deterministic_ast = __esm({
57224
57520
  });
57225
57521
 
57226
57522
  // src/runtime/dwf-state-store.ts
57227
- import { existsSync as existsSync70, mkdirSync as mkdirSync39, readFileSync as readFileSync65, unlinkSync as unlinkSync10 } from "node:fs";
57228
- import { dirname as dirname35 } from "node:path";
57523
+ import { existsSync as existsSync70, mkdirSync as mkdirSync39, readFileSync as readFileSync65, unlinkSync as unlinkSync11 } from "node:fs";
57524
+ import { dirname as dirname36 } from "node:path";
57229
57525
  var DwfStore;
57230
57526
  var init_dwf_state_store = __esm({
57231
57527
  "src/runtime/dwf-state-store.ts"() {
@@ -57242,10 +57538,10 @@ var init_dwf_state_store = __esm({
57242
57538
  }
57243
57539
  /** Load the checkpoint for this run's stateRoot. Returns undefined if missing or corrupt (fresh run). */
57244
57540
  load() {
57245
- const path86 = this.path;
57541
+ const path87 = this.path;
57246
57542
  try {
57247
- if (!existsSync70(path86)) return void 0;
57248
- const raw = readFileSync65(path86, "utf-8");
57543
+ if (!existsSync70(path87)) return void 0;
57544
+ const raw = readFileSync65(path87, "utf-8");
57249
57545
  const parsed = JSON.parse(raw);
57250
57546
  if (!parsed || typeof parsed !== "object" || typeof parsed.runId !== "string") return void 0;
57251
57547
  return parsed;
@@ -57255,11 +57551,11 @@ var init_dwf_state_store = __esm({
57255
57551
  }
57256
57552
  /** Atomically persist a checkpoint state. Stamps `updatedAt` (callers need not set it). */
57257
57553
  save(state) {
57258
- const path86 = this.path;
57554
+ const path87 = this.path;
57259
57555
  const next = { ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
57260
57556
  try {
57261
- mkdirSync39(dirname35(path86), { recursive: true });
57262
- atomicWriteJson(path86, next);
57557
+ mkdirSync39(dirname36(path87), { recursive: true });
57558
+ atomicWriteJson(path87, next);
57263
57559
  } catch (error) {
57264
57560
  logInternalError("dwf-state-store.save", error, `runId=${state.runId}`);
57265
57561
  throw error;
@@ -57267,10 +57563,10 @@ var init_dwf_state_store = __esm({
57267
57563
  }
57268
57564
  /** Remove the checkpoint file (after a clean completion). Best-effort; never throws. */
57269
57565
  delete() {
57270
- const path86 = this.path;
57566
+ const path87 = this.path;
57271
57567
  try {
57272
- if (!existsSync70(path86)) return;
57273
- unlinkSync10(path86);
57568
+ if (!existsSync70(path87)) return;
57569
+ unlinkSync11(path87);
57274
57570
  } catch (error) {
57275
57571
  logInternalError("dwf-state-store.delete", error);
57276
57572
  }
@@ -57302,7 +57598,7 @@ var init_parallel_utils = __esm({
57302
57598
  });
57303
57599
 
57304
57600
  // src/runtime/result-extractor.ts
57305
- import { Value as Value4 } from "@sinclair/typebox/value";
57601
+ import { Value as Value5 } from "@sinclair/typebox/value";
57306
57602
  function extractStructuredResult(raw, schema) {
57307
57603
  const trimmed = raw.trim();
57308
57604
  if (!trimmed) {
@@ -57330,7 +57626,7 @@ function finalize(candidate, raw, schema) {
57330
57626
  if (!schema) {
57331
57627
  return { structured: true, data: candidate, rawText: raw };
57332
57628
  }
57333
- const ok = Value4.Check(schema, candidate);
57629
+ const ok = Value5.Check(schema, candidate);
57334
57630
  if (ok) {
57335
57631
  return { structured: true, data: candidate, rawText: raw };
57336
57632
  }
@@ -57338,10 +57634,10 @@ function finalize(candidate, raw, schema) {
57338
57634
  structured: false,
57339
57635
  data: null,
57340
57636
  rawText: raw,
57341
- error: `structured output does not match schema: expected shape ${describeSchemaShape(schema)}, got ${describeValue(candidate)}`
57637
+ error: `structured output does not match schema: expected shape ${describeSchemaShape(schema)}, got ${describeValue2(candidate)}`
57342
57638
  };
57343
57639
  }
57344
- function describeValue(value) {
57640
+ function describeValue2(value) {
57345
57641
  try {
57346
57642
  const json = JSON.stringify(value);
57347
57643
  return json.length > 200 ? `${json.slice(0, 200)}\u2026` : json;
@@ -58075,7 +58371,7 @@ __export(dynamic_workflow_runner_exports, {
58075
58371
  runDynamicWorkflow: () => runDynamicWorkflow
58076
58372
  });
58077
58373
  import { readFileSync as readFileSync66 } from "node:fs";
58078
- import { join as join69 } from "node:path";
58374
+ import { join as join70 } from "node:path";
58079
58375
  import { transformSync } from "esbuild";
58080
58376
  function assertStructuredCloneable(value, name) {
58081
58377
  try {
@@ -58087,7 +58383,7 @@ function assertStructuredCloneable(value, name) {
58087
58383
  }
58088
58384
  function resolveScriptPath(workflow, cwd) {
58089
58385
  const crewRoot = projectCrewRoot(cwd);
58090
- const allowedBases = [join69(projectCrewRoot(cwd), "workflows"), join69(userPiRoot(), "workflows"), join69(packageRoot(), "workflows")];
58386
+ const allowedBases = [join70(projectCrewRoot(cwd), "workflows"), join70(userPiRoot(), "workflows"), join70(packageRoot(), "workflows")];
58091
58387
  for (const base of allowedBases) {
58092
58388
  try {
58093
58389
  const real = resolveRealContainedPath(base, workflow.filePath);
@@ -58263,7 +58559,7 @@ __export(run_exports, {
58263
58559
  handleRun: () => handleRun2
58264
58560
  });
58265
58561
  import * as fs89 from "node:fs";
58266
- import * as path73 from "node:path";
58562
+ import * as path74 from "node:path";
58267
58563
  async function executeTeamRun2(...args) {
58268
58564
  if (!_cachedExecuteTeamRun) {
58269
58565
  const mod = await Promise.resolve().then(() => (init_team_runner(), team_runner_exports));
@@ -58404,7 +58700,7 @@ function formatRunResult(manifest, options) {
58404
58700
  const summaryArtifact = manifest.artifacts?.find((a) => a.kind === "summary");
58405
58701
  if (summaryArtifact) {
58406
58702
  try {
58407
- const sumPath = path73.join(manifest.artifactsRoot, summaryArtifact.path);
58703
+ const sumPath = path74.join(manifest.artifactsRoot, summaryArtifact.path);
58408
58704
  summaryContent = fs89.readFileSync(sumPath, "utf-8").trim().slice(0, 4e3);
58409
58705
  } catch {
58410
58706
  }
@@ -59112,7 +59408,7 @@ __export(team_tool_exports, {
59112
59408
  uninstallCrewGlobalRegistry: () => uninstallCrewGlobalRegistry
59113
59409
  });
59114
59410
  import * as fs90 from "node:fs";
59115
- import * as path74 from "node:path";
59411
+ import * as path75 from "node:path";
59116
59412
  async function executeTeamRun3(...args) {
59117
59413
  if (_cachedExecuteTeamRun2 === void 0) {
59118
59414
  const mod = await Promise.resolve().then(() => (init_team_runner(), team_runner_exports));
@@ -59225,7 +59521,7 @@ async function recoverCheckpointedTasks(manifest, tasks) {
59225
59521
  };
59226
59522
  }
59227
59523
  if (task.checkpoint.phase === "child-stdout-final") {
59228
- const transcriptsDir = path74.join(manifest.artifactsRoot, "transcripts");
59524
+ const transcriptsDir = path75.join(manifest.artifactsRoot, "transcripts");
59229
59525
  let transcriptPath;
59230
59526
  if (fs90.existsSync(transcriptsDir)) {
59231
59527
  const files = fs90.readdirSync(transcriptsDir).filter((f) => f.startsWith(`${task.id}.attempt-`) && f.endsWith(".jsonl"));
@@ -59235,7 +59531,7 @@ async function recoverCheckpointedTasks(manifest, tasks) {
59235
59531
  const idxB = parseInt(b.match(/\.attempt-(\d+)\./)?.[1] ?? "0", 10);
59236
59532
  return idxB - idxA;
59237
59533
  });
59238
- transcriptPath = path74.join(transcriptsDir, files[0]);
59534
+ transcriptPath = path75.join(transcriptsDir, files[0]);
59239
59535
  }
59240
59536
  }
59241
59537
  if (!transcriptPath) return task;
@@ -59529,7 +59825,7 @@ function locateRunCwd(runId, baseCwd) {
59529
59825
  if (entry.name.startsWith(".")) {
59530
59826
  if (!entry.name.startsWith(".crew") && !entry.name.startsWith(".pi") && !entry.name.startsWith(".tmp-crew")) continue;
59531
59827
  }
59532
- const candidate = path74.join(baseCwd, entry.name);
59828
+ const candidate = path75.join(baseCwd, entry.name);
59533
59829
  if (loadRunManifestById(candidate, runId)) {
59534
59830
  return candidate;
59535
59831
  }
@@ -60440,26 +60736,26 @@ var init_syntax_highlight = __esm({
60440
60736
 
60441
60737
  // src/ui/transcript-cache.ts
60442
60738
  import * as fs91 from "node:fs";
60443
- function cacheKey(path86, options) {
60444
- return `${path86}:${options.full ? "full" : `tail:${options.maxTailBytes}`}`;
60739
+ function cacheKey(path87, options) {
60740
+ return `${path87}:${options.full ? "full" : `tail:${options.maxTailBytes}`}`;
60445
60741
  }
60446
- function getTranscriptCacheEntry(path86, options = {}) {
60742
+ function getTranscriptCacheEntry(path87, options = {}) {
60447
60743
  const normalized = {
60448
60744
  full: options.full === true,
60449
60745
  maxTailBytes: options.maxTailBytes ?? DEFAULT_TAIL_BYTES
60450
60746
  };
60451
- return transcriptCache.get(cacheKey(path86, normalized)) ?? transcriptCache.get(path86);
60747
+ return transcriptCache.get(cacheKey(path87, normalized)) ?? transcriptCache.get(path87);
60452
60748
  }
60453
- function readTranscriptText(path86, stat2, options) {
60749
+ function readTranscriptText(path87, stat2, options) {
60454
60750
  if (options.full || stat2.size <= options.maxTailBytes) {
60455
60751
  return {
60456
- text: fs91.readFileSync(path86, "utf-8"),
60752
+ text: fs91.readFileSync(path87, "utf-8"),
60457
60753
  bytesRead: stat2.size,
60458
60754
  truncated: false
60459
60755
  };
60460
60756
  }
60461
60757
  const bytesToRead = Math.min(stat2.size, options.maxTailBytes);
60462
- const fd = fs91.openSync(path86, "r");
60758
+ const fd = fs91.openSync(path87, "r");
60463
60759
  try {
60464
60760
  const buffer = Buffer.alloc(bytesToRead);
60465
60761
  fs91.readSync(fd, buffer, 0, bytesToRead, stat2.size - bytesToRead);
@@ -60471,16 +60767,16 @@ function readTranscriptText(path86, stat2, options) {
60471
60767
  fs91.closeSync(fd);
60472
60768
  }
60473
60769
  }
60474
- function readTranscriptLinesCached(path86, parse4, now = Date.now(), options = {}) {
60770
+ function readTranscriptLinesCached(path87, parse4, now = Date.now(), options = {}) {
60475
60771
  const normalized = {
60476
60772
  full: options.full === true,
60477
60773
  maxTailBytes: Math.max(1024, options.maxTailBytes ?? DEFAULT_TAIL_BYTES)
60478
60774
  };
60479
- const key = cacheKey(path86, normalized);
60775
+ const key = cacheKey(path87, normalized);
60480
60776
  const previous = transcriptCache.get(key);
60481
60777
  let stat2;
60482
60778
  try {
60483
- stat2 = fs91.statSync(path86);
60779
+ stat2 = fs91.statSync(path87);
60484
60780
  } catch {
60485
60781
  return previous?.lines ?? [];
60486
60782
  }
@@ -60489,10 +60785,10 @@ function readTranscriptLinesCached(path86, parse4, now = Date.now(), options = {
60489
60785
  return previous.lines;
60490
60786
  }
60491
60787
  try {
60492
- const read = readTranscriptText(path86, stat2, normalized);
60788
+ const read = readTranscriptText(path87, stat2, normalized);
60493
60789
  const lines = parse4(read.text);
60494
60790
  const entry = {
60495
- path: path86,
60791
+ path: path87,
60496
60792
  mtimeMs: stat2.mtimeMs,
60497
60793
  size: stat2.size,
60498
60794
  lines,
@@ -63349,8 +63645,8 @@ function formatValue2(value, id) {
63349
63645
  if (typeof value === "object") return JSON.stringify(value);
63350
63646
  return String(value);
63351
63647
  }
63352
- function getNestedValue(obj, path86) {
63353
- const keys = path86.split(".");
63648
+ function getNestedValue(obj, path87) {
63649
+ const keys = path87.split(".");
63354
63650
  let current = obj;
63355
63651
  for (const key of keys) {
63356
63652
  if (!current || typeof current !== "object") return void 0;
@@ -64220,7 +64516,7 @@ __export(commands_exports, {
64220
64516
  registerTeamCommands: () => registerTeamCommands
64221
64517
  });
64222
64518
  import * as fs94 from "node:fs";
64223
- import * as path75 from "node:path";
64519
+ import * as path76 from "node:path";
64224
64520
  async function handleTeamTool5(params, ctx) {
64225
64521
  if (!_cachedHandleTeamTool4) {
64226
64522
  if (!_handleTeamToolPromise) {
@@ -64470,7 +64766,7 @@ async function handleHealthDashboardAction(ctx, selection) {
64470
64766
  return;
64471
64767
  }
64472
64768
  if (selection.action === "health-diagnostic-export") {
64473
- const diagDir = path75.join(loaded.manifest.artifactsRoot, "diagnostic");
64769
+ const diagDir = path76.join(loaded.manifest.artifactsRoot, "diagnostic");
64474
64770
  const recent = listRecentDiagnostic(diagDir, 6e4);
64475
64771
  if (recent) {
64476
64772
  const confirmed = await openConfirm(ctx, {
@@ -65168,10 +65464,10 @@ function registerTeamCommands(pi, deps) {
65168
65464
  await notifyCommandResult(ctx, error instanceof Error ? error.message : String(error));
65169
65465
  return;
65170
65466
  }
65171
- const skillsDir = path75.resolve(
65467
+ const skillsDir = path76.resolve(
65172
65468
  cwd,
65173
- useProject ? "skills" : path75.join(
65174
- path75.dirname(
65469
+ useProject ? "skills" : path76.join(
65470
+ path76.dirname(
65175
65471
  __require.resolve("../../../package.json", {
65176
65472
  paths: [__dirname]
65177
65473
  })
@@ -65179,8 +65475,8 @@ function registerTeamCommands(pi, deps) {
65179
65475
  "skills"
65180
65476
  )
65181
65477
  );
65182
- const skillDir = path75.join(skillsDir, template.id);
65183
- const skillPath = path75.join(skillDir, "SKILL.md");
65478
+ const skillDir = path76.join(skillsDir, template.id);
65479
+ const skillPath = path76.join(skillDir, "SKILL.md");
65184
65480
  try {
65185
65481
  fs94.mkdirSync(skillDir, { recursive: true });
65186
65482
  atomicWriteFile(skillPath, instantiated.content);
@@ -65250,13 +65546,13 @@ var init_commands = __esm({
65250
65546
 
65251
65547
  // src/runtime/subagent-manager.ts
65252
65548
  import * as fs98 from "node:fs";
65253
- import * as path78 from "node:path";
65549
+ import * as path79 from "node:path";
65254
65550
  function isValidSubagentId(id) {
65255
65551
  return /^[a-z0-9_]+$/i.test(id) && id.length <= 128;
65256
65552
  }
65257
65553
  function persistedSubagentPath(cwd, id) {
65258
65554
  if (!isValidSubagentId(id)) throw new Error(`Invalid subagent id: ${id}`);
65259
- return path78.join(projectCrewRoot(cwd), DEFAULT_PATHS.state.subagentsSubdir, `${id}.json`);
65555
+ return path79.join(projectCrewRoot(cwd), DEFAULT_PATHS.state.subagentsSubdir, `${id}.json`);
65260
65556
  }
65261
65557
  function serializableRecord(record) {
65262
65558
  const { promise: _promise, ...rest } = record;
@@ -65265,7 +65561,7 @@ function serializableRecord(record) {
65265
65561
  function savePersistedSubagentRecord(cwd, record) {
65266
65562
  try {
65267
65563
  const filePath = persistedSubagentPath(cwd, record.id);
65268
- fs98.mkdirSync(path78.dirname(filePath), { recursive: true });
65564
+ fs98.mkdirSync(path79.dirname(filePath), { recursive: true });
65269
65565
  fs98.writeFileSync(filePath, `${JSON.stringify(redactSecrets(serializableRecord(record)), null, 2)}
65270
65566
  `, "utf-8");
65271
65567
  fs98.chmodSync(filePath, 384);
@@ -65811,13 +66107,13 @@ function line3(text, width) {
65811
66107
  function border(left, fill, right, width) {
65812
66108
  return `${left}${fill.repeat(Math.max(0, width - 2))}${right}`;
65813
66109
  }
65814
- function readTasks3(path86) {
66110
+ function readTasks3(path87) {
65815
66111
  const parse4 = () => {
65816
- const parsed = JSON.parse(fs100.readFileSync(path86, "utf-8"));
66112
+ const parsed = JSON.parse(fs100.readFileSync(path87, "utf-8"));
65817
66113
  return Array.isArray(parsed) ? parsed : [];
65818
66114
  };
65819
66115
  try {
65820
- return readJsonFileCoalesced(path86, TASK_READ_TTL_MS3, parse4);
66116
+ return readJsonFileCoalesced(path87, TASK_READ_TTL_MS3, parse4);
65821
66117
  } catch {
65822
66118
  return [];
65823
66119
  }
@@ -66508,13 +66804,13 @@ __export(notification_sink_exports, {
66508
66804
  createJsonlSink: () => createJsonlSink
66509
66805
  });
66510
66806
  import * as fs102 from "node:fs";
66511
- import * as path80 from "node:path";
66807
+ import * as path81 from "node:path";
66512
66808
  function rotateOldFiles(dir, retentionDays, now = Date.now()) {
66513
66809
  if (!fs102.existsSync(dir)) return;
66514
66810
  const cutoff = now - retentionDays * 24 * 60 * 60 * 1e3;
66515
66811
  for (const entry of fs102.readdirSync(dir, { withFileTypes: true })) {
66516
66812
  if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
66517
- const filePath = path80.join(dir, entry.name);
66813
+ const filePath = path81.join(dir, entry.name);
66518
66814
  try {
66519
66815
  if (fs102.statSync(filePath).mtimeMs < cutoff) fs102.unlinkSync(filePath);
66520
66816
  } catch (error) {
@@ -66523,7 +66819,7 @@ function rotateOldFiles(dir, retentionDays, now = Date.now()) {
66523
66819
  }
66524
66820
  }
66525
66821
  function createJsonlSink(crewRoot, retentionDays = 7) {
66526
- const dir = path80.join(crewRoot, "state", "notifications");
66822
+ const dir = path81.join(crewRoot, "state", "notifications");
66527
66823
  let lastRotateDate = "";
66528
66824
  return {
66529
66825
  write(notification) {
@@ -66539,7 +66835,7 @@ function createJsonlSink(crewRoot, retentionDays = 7) {
66539
66835
  ...notification,
66540
66836
  timestamp
66541
66837
  });
66542
- fs102.appendFileSync(path80.join(dir, `${date}.jsonl`), `${JSON.stringify(payload)}
66838
+ fs102.appendFileSync(path81.join(dir, `${date}.jsonl`), `${JSON.stringify(payload)}
66543
66839
  `, "utf-8");
66544
66840
  } catch (error) {
66545
66841
  logInternalError("notification-sink.write", error);
@@ -67781,13 +68077,13 @@ __export(metric_sink_exports, {
67781
68077
  createMetricFileSink: () => createMetricFileSink
67782
68078
  });
67783
68079
  import * as fs103 from "node:fs";
67784
- import * as path81 from "node:path";
68080
+ import * as path82 from "node:path";
67785
68081
  function rotateOldFiles2(dir, retentionDays, now = Date.now()) {
67786
68082
  if (!fs103.existsSync(dir)) return;
67787
68083
  const maxAge = retentionDays * 24 * 60 * 60 * 1e3;
67788
68084
  for (const file of fs103.readdirSync(dir)) {
67789
68085
  if (!file.endsWith(".jsonl")) continue;
67790
- const fullPath = path81.join(dir, file);
68086
+ const fullPath = path82.join(dir, file);
67791
68087
  try {
67792
68088
  if (now - fs103.statSync(fullPath).mtimeMs > maxAge) fs103.unlinkSync(fullPath);
67793
68089
  } catch (error) {
@@ -67796,7 +68092,7 @@ function rotateOldFiles2(dir, retentionDays, now = Date.now()) {
67796
68092
  }
67797
68093
  }
67798
68094
  function createMetricFileSink(opts) {
67799
- const dir = path81.join(opts.crewRoot, "state", "metrics");
68095
+ const dir = path82.join(opts.crewRoot, "state", "metrics");
67800
68096
  const retentionDays = opts.retentionDays ?? 7;
67801
68097
  let fd;
67802
68098
  let fdDate;
@@ -67811,7 +68107,7 @@ function createMetricFileSink(opts) {
67811
68107
  }
67812
68108
  fs103.mkdirSync(dir, { recursive: true });
67813
68109
  rotateOldFiles2(dir, retentionDays);
67814
- fd = fs103.openSync(path81.join(dir, `${date}.jsonl`), "a");
68110
+ fd = fs103.openSync(path82.join(dir, `${date}.jsonl`), "a");
67815
68111
  fdDate = date;
67816
68112
  return fd;
67817
68113
  };
@@ -67870,7 +68166,7 @@ __export(heartbeat_watcher_exports, {
67870
68166
  HeartbeatWatcher: () => HeartbeatWatcher
67871
68167
  });
67872
68168
  import * as fs104 from "node:fs";
67873
- import * as path82 from "node:path";
68169
+ import * as path83 from "node:path";
67874
68170
  var HeartbeatWatcher;
67875
68171
  var init_heartbeat_watcher = __esm({
67876
68172
  "src/runtime/heartbeat-watcher.ts"() {
@@ -67952,9 +68248,9 @@ var init_heartbeat_watcher = __esm({
67952
68248
  level = "stale";
67953
68249
  }
67954
68250
  if (level === "dead" && !isProcessAlive && loaded.manifest.artifactsRoot) {
67955
- const resultsDir = path82.resolve(loaded.manifest.artifactsRoot, "results");
67956
- const candidate = path82.resolve(resultsDir, `${task.id}.txt`);
67957
- if (candidate.startsWith(resultsDir + path82.sep) && fs104.existsSync(candidate)) {
68251
+ const resultsDir = path83.resolve(loaded.manifest.artifactsRoot, "results");
68252
+ const candidate = path83.resolve(resultsDir, `${task.id}.txt`);
68253
+ if (candidate.startsWith(resultsDir + path83.sep) && fs104.existsSync(candidate)) {
67958
68254
  level = "stale";
67959
68255
  }
67960
68256
  }
@@ -69059,20 +69355,20 @@ init_internal_error();
69059
69355
 
69060
69356
  // src/extension/crew-vibes/config.ts
69061
69357
  import { existsSync as existsSync76, mkdirSync as mkdirSync42, readFileSync as readFileSync72, writeFileSync as writeFileSync11 } from "node:fs";
69062
- import { dirname as dirname37, join as join74 } from "node:path";
69358
+ import { dirname as dirname38, join as join75 } from "node:path";
69063
69359
 
69064
69360
  // src/extension/crew-vibes/font-detect.ts
69065
69361
  import { existsSync as existsSync75, readFileSync as readFileSync71 } from "node:fs";
69066
69362
  import { homedir as homedir11, platform } from "node:os";
69067
- import { join as join73 } from "node:path";
69363
+ import { join as join74 } from "node:path";
69068
69364
  function fontPath() {
69069
69365
  const os18 = platform();
69070
69366
  const home = homedir11();
69071
- if (os18 === "darwin") return join73(home, "Library", "Fonts", "crew-vibes.ttf");
69072
- if (os18 === "linux") return join73(home, ".local", "share", "fonts", "crew-vibes.ttf");
69367
+ if (os18 === "darwin") return join74(home, "Library", "Fonts", "crew-vibes.ttf");
69368
+ if (os18 === "linux") return join74(home, ".local", "share", "fonts", "crew-vibes.ttf");
69073
69369
  if (os18 === "win32") {
69074
- const local = process.env.LOCALAPPDATA ?? join73(home, "AppData", "Local");
69075
- return join73(local, "Microsoft", "Windows", "Fonts", "crew-vibes.ttf");
69370
+ const local = process.env.LOCALAPPDATA ?? join74(home, "AppData", "Local");
69371
+ return join74(local, "Microsoft", "Windows", "Fonts", "crew-vibes.ttf");
69076
69372
  }
69077
69373
  return "";
69078
69374
  }
@@ -69121,7 +69417,7 @@ function resolveHome() {
69121
69417
  return (process.env.PI_TEAMS_HOME ?? process.env.PI_CREW_HOME)?.trim() || process.env.HOME || process.env.USERPROFILE || "";
69122
69418
  }
69123
69419
  function configPath2() {
69124
- return join74(resolveHome(), ".pi", "agent", "pi-crew-vibes.json");
69420
+ return join75(resolveHome(), ".pi", "agent", "pi-crew-vibes.json");
69125
69421
  }
69126
69422
  var DEFAULT_CONFIG2 = {
69127
69423
  enabled: true,
@@ -69234,17 +69530,17 @@ function normalizeConfig(raw) {
69234
69530
  }
69235
69531
  function loadConfig2() {
69236
69532
  try {
69237
- const path86 = configPath2();
69238
- if (!existsSync76(path86)) return normalizeConfig(void 0);
69239
- return normalizeConfig(JSON.parse(readFileSync72(path86, "utf8")));
69533
+ const path87 = configPath2();
69534
+ if (!existsSync76(path87)) return normalizeConfig(void 0);
69535
+ return normalizeConfig(JSON.parse(readFileSync72(path87, "utf8")));
69240
69536
  } catch {
69241
69537
  return normalizeConfig(void 0);
69242
69538
  }
69243
69539
  }
69244
69540
  function saveConfig(config) {
69245
- const path86 = configPath2();
69246
- mkdirSync42(dirname37(path86), { recursive: true });
69247
- writeFileSync11(path86, `${JSON.stringify(normalizeConfig(config), null, 2)}
69541
+ const path87 = configPath2();
69542
+ mkdirSync42(dirname38(path87), { recursive: true });
69543
+ writeFileSync11(path87, `${JSON.stringify(normalizeConfig(config), null, 2)}
69248
69544
  `);
69249
69545
  }
69250
69546
 
@@ -69622,14 +69918,14 @@ function createCrewVibesFooter(deps) {
69622
69918
  // src/extension/crew-vibes/provider-usage.ts
69623
69919
  import { readFileSync as readFileSync73 } from "node:fs";
69624
69920
  import { homedir as homedir12 } from "node:os";
69625
- import { join as join75 } from "node:path";
69921
+ import { join as join76 } from "node:path";
69626
69922
  function withTimeout(ms, fn) {
69627
69923
  const controller = new AbortController();
69628
69924
  const timeoutId = setTimeout(() => controller.abort(), ms);
69629
69925
  return fn(controller.signal).finally(() => clearTimeout(timeoutId));
69630
69926
  }
69631
69927
  function piAuthPath() {
69632
- return join75(homedir12(), ".pi", "agent", "auth.json");
69928
+ return join76(homedir12(), ".pi", "agent", "auth.json");
69633
69929
  }
69634
69930
  function loadAnthropicToken() {
69635
69931
  const envToken = process.env.ANTHROPIC_OAUTH_TOKEN?.trim();
@@ -69674,8 +69970,8 @@ function tokenFromHostEntry(entry) {
69674
69970
  return void 0;
69675
69971
  }
69676
69972
  function loadLegacyCopilotToken() {
69677
- const configHome = process.env.XDG_CONFIG_HOME?.trim() || join75(homedir12(), ".config");
69678
- const candidates = [join75(configHome, "github-copilot", "hosts.json"), join75(homedir12(), ".github-copilot", "hosts.json")];
69973
+ const configHome = process.env.XDG_CONFIG_HOME?.trim() || join76(homedir12(), ".config");
69974
+ const candidates = [join76(configHome, "github-copilot", "hosts.json"), join76(homedir12(), ".github-copilot", "hosts.json")];
69679
69975
  for (const hostsPath of candidates) {
69680
69976
  try {
69681
69977
  const data = JSON.parse(readFileSync73(hostsPath, "utf8"));
@@ -70752,7 +71048,7 @@ var BatchBarrier = class {
70752
71048
  init_defaults();
70753
71049
  init_active_run_registry();
70754
71050
  import * as fs96 from "node:fs";
70755
- import * as path76 from "node:path";
71051
+ import * as path77 from "node:path";
70756
71052
 
70757
71053
  // src/utils/fs-watch.ts
70758
71054
  import * as fs95 from "node:fs";
@@ -70765,9 +71061,9 @@ function closeWatcher(watcher) {
70765
71061
  } catch {
70766
71062
  }
70767
71063
  }
70768
- function watchWithErrorHandler(path86, listener, onError) {
71064
+ function watchWithErrorHandler(path87, listener, onError) {
70769
71065
  try {
70770
- const watcher = fs95.watch(path86, listener);
71066
+ const watcher = fs95.watch(path87, listener);
70771
71067
  watcher.on("error", onError);
70772
71068
  return watcher;
70773
71069
  } catch (error) {
@@ -70783,7 +71079,7 @@ var DEFAULT_TTL_MS = 500;
70783
71079
  function manifestPathForRun(root, runId) {
70784
71080
  if (!isSafePathId(runId)) return void 0;
70785
71081
  try {
70786
- return path76.join(resolveRealContainedPath(root, runId), DEFAULT_PATHS.state.manifestFile);
71082
+ return path77.join(resolveRealContainedPath(root, runId), DEFAULT_PATHS.state.manifestFile);
70787
71083
  } catch {
70788
71084
  return void 0;
70789
71085
  }
@@ -70796,7 +71092,7 @@ function parseManifest(filePath) {
70796
71092
  }
70797
71093
  }
70798
71094
  function sameFilesystemPath(left, right) {
70799
- if (path76.resolve(left) === path76.resolve(right)) return true;
71095
+ if (path77.resolve(left) === path77.resolve(right)) return true;
70800
71096
  try {
70801
71097
  return fs96.realpathSync.native(left) === fs96.realpathSync.native(right);
70802
71098
  } catch {
@@ -70807,13 +71103,13 @@ function validateManifestForRoot(root, runId, manifest) {
70807
71103
  try {
70808
71104
  if (!isSafePathId(runId)) return false;
70809
71105
  const stateRoot = resolveContainedRelativePath(root, runId, "runId");
70810
- const crewRoot = path76.dirname(path76.dirname(root));
70811
- const artifactsRoot = resolveContainedRelativePath(path76.join(crewRoot, DEFAULT_PATHS.state.artifactsSubdir), runId, "runId");
70812
- if (manifest.runId !== runId || !sameFilesystemPath(manifest.stateRoot, stateRoot) || !sameFilesystemPath(manifest.tasksPath, path76.join(stateRoot, DEFAULT_PATHS.state.tasksFile)) || !sameFilesystemPath(manifest.eventsPath, path76.join(stateRoot, DEFAULT_PATHS.state.eventsFile)) || !sameFilesystemPath(manifest.artifactsRoot, artifactsRoot))
71106
+ const crewRoot = path77.dirname(path77.dirname(root));
71107
+ const artifactsRoot = resolveContainedRelativePath(path77.join(crewRoot, DEFAULT_PATHS.state.artifactsSubdir), runId, "runId");
71108
+ if (manifest.runId !== runId || !sameFilesystemPath(manifest.stateRoot, stateRoot) || !sameFilesystemPath(manifest.tasksPath, path77.join(stateRoot, DEFAULT_PATHS.state.tasksFile)) || !sameFilesystemPath(manifest.eventsPath, path77.join(stateRoot, DEFAULT_PATHS.state.eventsFile)) || !sameFilesystemPath(manifest.artifactsRoot, artifactsRoot))
70813
71109
  return false;
70814
71110
  if (fs96.existsSync(artifactsRoot)) {
70815
71111
  if (fs96.lstatSync(artifactsRoot).isSymbolicLink()) return false;
70816
- resolveRealContainedPath(path76.dirname(artifactsRoot), path76.basename(artifactsRoot));
71112
+ resolveRealContainedPath(path77.dirname(artifactsRoot), path77.basename(artifactsRoot));
70817
71113
  }
70818
71114
  return true;
70819
71115
  } catch {
@@ -70828,7 +71124,7 @@ function parseManifestIfChanged(root, runId, filePath, previous) {
70828
71124
  return void 0;
70829
71125
  }
70830
71126
  if (previous && previous.mtimeMs === stat2.mtimeMs && previous.size === stat2.size) {
70831
- return validateManifestForRoot(root, runId, previous.manifest) ? previous : void 0;
71127
+ return previous;
70832
71128
  }
70833
71129
  const manifest = parseManifest(filePath);
70834
71130
  if (!manifest || !validateManifestForRoot(root, runId, manifest)) return void 0;
@@ -70842,9 +71138,9 @@ function parseManifestIfChanged(root, runId, filePath, previous) {
70842
71138
  }
70843
71139
  function listRunRoots(cwd) {
70844
71140
  const roots = /* @__PURE__ */ new Set();
70845
- roots.add(path76.join(userCrewRoot(), DEFAULT_PATHS.state.runsSubdir));
71141
+ roots.add(path77.join(userCrewRoot(), DEFAULT_PATHS.state.runsSubdir));
70846
71142
  const projectRoot = findRepoRoot(cwd);
70847
- if (projectRoot) roots.add(path76.join(projectCrewRoot(cwd), DEFAULT_PATHS.state.runsSubdir));
71143
+ if (projectRoot) roots.add(path77.join(projectCrewRoot(cwd), DEFAULT_PATHS.state.runsSubdir));
70848
71144
  return [...roots];
70849
71145
  }
70850
71146
  function collectRoots(root) {
@@ -70896,7 +71192,7 @@ function createManifestCache(cwd, options = {}) {
70896
71192
  if (!isSafePathId(runId)) return void 0;
70897
71193
  const activeEntry = activeRunEntries().find((entry) => entry.runId === runId);
70898
71194
  if (activeEntry) {
70899
- const activeRoot = path76.dirname(activeEntry.stateRoot);
71195
+ const activeRoot = path77.dirname(activeEntry.stateRoot);
70900
71196
  const parsed = parseManifestIfChanged(activeRoot, runId, activeEntry.manifestPath, cached);
70901
71197
  if (parsed) {
70902
71198
  manifestIndex.set(runId, parsed);
@@ -70937,7 +71233,7 @@ function createManifestCache(cwd, options = {}) {
70937
71233
  for (const entry of parsedEntries) {
70938
71234
  if (entry.runId.length === 0) continue;
70939
71235
  let cached2 = manifestIndex.get(entry.runId);
70940
- const root = path76.dirname(path76.dirname(entry.path));
71236
+ const root = path77.dirname(path77.dirname(entry.path));
70941
71237
  const parsed = parseManifestIfChanged(root, entry.runId, entry.path, cached2);
70942
71238
  if (parsed) {
70943
71239
  cached2 = parsed;
@@ -70983,7 +71279,7 @@ function createManifestCache(cwd, options = {}) {
70983
71279
  for (const entry of parsedEntries) {
70984
71280
  if (entry.runId.length === 0) continue;
70985
71281
  let cached = manifestIndex.get(entry.runId);
70986
- const root = path76.dirname(path76.dirname(entry.path));
71282
+ const root = path77.dirname(path77.dirname(entry.path));
70987
71283
  const parsed = parseManifestIfChanged(root, entry.runId, entry.path, cached);
70988
71284
  if (parsed) {
70989
71285
  cached = parsed;
@@ -71042,7 +71338,7 @@ init_dwf_phase_display();
71042
71338
  init_run_event_bus();
71043
71339
  import { createHash as createHash10 } from "node:crypto";
71044
71340
  import * as fs97 from "node:fs";
71045
- import * as path77 from "node:path";
71341
+ import * as path78 from "node:path";
71046
71342
  var DEFAULT_TTL_MS2 = 1500;
71047
71343
  var DEFAULT_MAX_ENTRIES = 24;
71048
71344
  var DEFAULT_RECENT_EVENTS = 20;
@@ -71098,22 +71394,22 @@ function combineStamps(stamps) {
71098
71394
  );
71099
71395
  }
71100
71396
  function mailboxStamp(manifest) {
71101
- const root = path77.join(manifest.stateRoot, "mailbox");
71102
- const tasksRoot = path77.join(root, "tasks");
71397
+ const root = path78.join(manifest.stateRoot, "mailbox");
71398
+ const tasksRoot = path78.join(root, "tasks");
71103
71399
  return combineStamps([
71104
- stampFile(path77.join(root, "inbox.jsonl")),
71105
- stampFile(path77.join(root, "outbox.jsonl")),
71106
- stampFile(path77.join(root, "delivery.json")),
71400
+ stampFile(path78.join(root, "inbox.jsonl")),
71401
+ stampFile(path78.join(root, "outbox.jsonl")),
71402
+ stampFile(path78.join(root, "delivery.json")),
71107
71403
  stampFile(tasksRoot)
71108
71404
  ]);
71109
71405
  }
71110
71406
  async function mailboxStampAsync(manifest) {
71111
- const root = path77.join(manifest.stateRoot, "mailbox");
71112
- const tasksRoot = path77.join(root, "tasks");
71407
+ const root = path78.join(manifest.stateRoot, "mailbox");
71408
+ const tasksRoot = path78.join(root, "tasks");
71113
71409
  return combineStamps([
71114
- await stampFileAsync(path77.join(root, "inbox.jsonl")),
71115
- await stampFileAsync(path77.join(root, "outbox.jsonl")),
71116
- await stampFileAsync(path77.join(root, "delivery.json")),
71410
+ await stampFileAsync(path78.join(root, "inbox.jsonl")),
71411
+ await stampFileAsync(path78.join(root, "outbox.jsonl")),
71412
+ await stampFileAsync(path78.join(root, "delivery.json")),
71117
71413
  await stampFileAsync(tasksRoot)
71118
71414
  ]);
71119
71415
  }
@@ -71443,14 +71739,14 @@ async function readMailboxCountsAsync(filePath, delivery) {
71443
71739
  };
71444
71740
  }
71445
71741
  function groupJoinsFrom(manifest) {
71446
- const root = path77.join(manifest.stateRoot, "mailbox");
71447
- const delivery = readDeliveryMessages(path77.join(root, "delivery.json"));
71448
- return readGroupJoinMailbox(path77.join(root, "outbox.jsonl"), delivery).slice(-5);
71742
+ const root = path78.join(manifest.stateRoot, "mailbox");
71743
+ const delivery = readDeliveryMessages(path78.join(root, "delivery.json"));
71744
+ return readGroupJoinMailbox(path78.join(root, "outbox.jsonl"), delivery).slice(-5);
71449
71745
  }
71450
71746
  async function groupJoinsFromAsync(manifest) {
71451
- const root = path77.join(manifest.stateRoot, "mailbox");
71452
- const delivery = await readDeliveryMessagesAsync(path77.join(root, "delivery.json"));
71453
- return (await readGroupJoinMailboxAsync(path77.join(root, "outbox.jsonl"), delivery)).slice(-5);
71747
+ const root = path78.join(manifest.stateRoot, "mailbox");
71748
+ const delivery = await readDeliveryMessagesAsync(path78.join(root, "delivery.json"));
71749
+ return (await readGroupJoinMailboxAsync(path78.join(root, "outbox.jsonl"), delivery)).slice(-5);
71454
71750
  }
71455
71751
  function mergeKindCounts(a, b) {
71456
71752
  return {
@@ -71463,18 +71759,18 @@ function mergeKindCounts(a, b) {
71463
71759
  };
71464
71760
  }
71465
71761
  function mailboxFrom(manifest, agents) {
71466
- const root = path77.join(manifest.stateRoot, "mailbox");
71467
- const delivery = readDeliveryMessages(path77.join(root, "delivery.json"));
71468
- let inbox = readMailboxCounts(path77.join(root, "inbox.jsonl"), delivery);
71469
- let outbox = readMailboxCounts(path77.join(root, "outbox.jsonl"), delivery);
71470
- const tasksRoot = path77.join(root, "tasks");
71762
+ const root = path78.join(manifest.stateRoot, "mailbox");
71763
+ const delivery = readDeliveryMessages(path78.join(root, "delivery.json"));
71764
+ let inbox = readMailboxCounts(path78.join(root, "inbox.jsonl"), delivery);
71765
+ let outbox = readMailboxCounts(path78.join(root, "outbox.jsonl"), delivery);
71766
+ const tasksRoot = path78.join(root, "tasks");
71471
71767
  try {
71472
71768
  for (const entry of fs97.readdirSync(tasksRoot, {
71473
71769
  withFileTypes: true
71474
71770
  })) {
71475
71771
  if (!entry.isDirectory()) continue;
71476
- const taskInbox = readMailboxCounts(path77.join(tasksRoot, entry.name, "inbox.jsonl"), delivery);
71477
- const taskOutbox = readMailboxCounts(path77.join(tasksRoot, entry.name, "outbox.jsonl"), delivery);
71772
+ const taskInbox = readMailboxCounts(path78.join(tasksRoot, entry.name, "inbox.jsonl"), delivery);
71773
+ const taskOutbox = readMailboxCounts(path78.join(tasksRoot, entry.name, "outbox.jsonl"), delivery);
71478
71774
  inbox = mergeKindCounts(inbox, taskInbox);
71479
71775
  outbox = mergeKindCounts(outbox, taskOutbox);
71480
71776
  }
@@ -71493,18 +71789,18 @@ function mailboxFrom(manifest, agents) {
71493
71789
  };
71494
71790
  }
71495
71791
  async function mailboxFromAsync(manifest, agents) {
71496
- const root = path77.join(manifest.stateRoot, "mailbox");
71497
- const delivery = await readDeliveryMessagesAsync(path77.join(root, "delivery.json"));
71498
- let inbox = await readMailboxCountsAsync(path77.join(root, "inbox.jsonl"), delivery);
71499
- let outbox = await readMailboxCountsAsync(path77.join(root, "outbox.jsonl"), delivery);
71500
- const tasksRoot = path77.join(root, "tasks");
71792
+ const root = path78.join(manifest.stateRoot, "mailbox");
71793
+ const delivery = await readDeliveryMessagesAsync(path78.join(root, "delivery.json"));
71794
+ let inbox = await readMailboxCountsAsync(path78.join(root, "inbox.jsonl"), delivery);
71795
+ let outbox = await readMailboxCountsAsync(path78.join(root, "outbox.jsonl"), delivery);
71796
+ const tasksRoot = path78.join(root, "tasks");
71501
71797
  try {
71502
71798
  for (const entry of await fs97.promises.readdir(tasksRoot, {
71503
71799
  withFileTypes: true
71504
71800
  })) {
71505
71801
  if (!entry.isDirectory()) continue;
71506
- const taskInbox = await readMailboxCountsAsync(path77.join(tasksRoot, entry.name, "inbox.jsonl"), delivery);
71507
- const taskOutbox = await readMailboxCountsAsync(path77.join(tasksRoot, entry.name, "outbox.jsonl"), delivery);
71802
+ const taskInbox = await readMailboxCountsAsync(path78.join(tasksRoot, entry.name, "inbox.jsonl"), delivery);
71803
+ const taskOutbox = await readMailboxCountsAsync(path78.join(tasksRoot, entry.name, "outbox.jsonl"), delivery);
71508
71804
  inbox = mergeKindCounts(inbox, taskInbox);
71509
71805
  outbox = mergeKindCounts(outbox, taskOutbox);
71510
71806
  }
@@ -71587,7 +71883,7 @@ function signatureFor(input, stamps, sliceSignatures) {
71587
71883
  }
71588
71884
  function stampsFor(manifest, _agents) {
71589
71885
  return {
71590
- manifest: stampFile(path77.join(manifest.stateRoot, "manifest.json")),
71886
+ manifest: stampFile(path78.join(manifest.stateRoot, "manifest.json")),
71591
71887
  tasks: stampFile(manifest.tasksPath),
71592
71888
  agents: stampFile(agentsPath(manifest)),
71593
71889
  events: eventsStamp(manifest.eventsPath),
@@ -71596,7 +71892,7 @@ function stampsFor(manifest, _agents) {
71596
71892
  }
71597
71893
  async function stampsForAsync(manifest, _agents) {
71598
71894
  const [manifestStamp, tasksStamp, agentsStamp, eventsStampValue, mailbox] = await Promise.all([
71599
- stampFileAsync(path77.join(manifest.stateRoot, "manifest.json")),
71895
+ stampFileAsync(path78.join(manifest.stateRoot, "manifest.json")),
71600
71896
  stampFileAsync(manifest.tasksPath),
71601
71897
  stampFileAsync(agentsPath(manifest)),
71602
71898
  eventsStampAsync(manifest.eventsPath),
@@ -71752,7 +72048,7 @@ function createRunSnapshotCache(cwd, options = {}) {
71752
72048
  function currentStamps(previous) {
71753
72049
  const manifest = previous.snapshot.manifest;
71754
72050
  return {
71755
- manifest: stampFile(path77.join(manifest.stateRoot, "manifest.json")),
72051
+ manifest: stampFile(path78.join(manifest.stateRoot, "manifest.json")),
71756
72052
  tasks: stampFile(manifest.tasksPath),
71757
72053
  agents: stampFile(agentsPath(manifest)),
71758
72054
  events: eventsStamp(manifest.eventsPath),
@@ -72141,7 +72437,7 @@ function startForegroundRunImpl(pi, ctx, extensionCtx, runner, runId) {
72141
72437
  // src/extension/registration/hook-registration.ts
72142
72438
  init_config();
72143
72439
  import * as fs101 from "node:fs";
72144
- import * as path79 from "node:path";
72440
+ import * as path80 from "node:path";
72145
72441
  import { fileURLToPath as fileURLToPath7 } from "node:url";
72146
72442
 
72147
72443
  // src/runtime/per-write-validator.ts
@@ -72160,9 +72456,9 @@ function validateJson(content, _filePath) {
72160
72456
  var DEFAULT_VALIDATORS = /* @__PURE__ */ new Map([["json", validateJson]]);
72161
72457
  var MAX_DEDUP_ENTRIES = 256;
72162
72458
  var seenContent = /* @__PURE__ */ new Map();
72163
- function rememberSeen(path86, content) {
72164
- if (seenContent.has(path86)) seenContent.delete(path86);
72165
- seenContent.set(path86, content);
72459
+ function rememberSeen(path87, content) {
72460
+ if (seenContent.has(path87)) seenContent.delete(path87);
72461
+ seenContent.set(path87, content);
72166
72462
  while (seenContent.size > MAX_DEDUP_ENTRIES) {
72167
72463
  const oldest = seenContent.keys().next().value;
72168
72464
  if (oldest === void 0) break;
@@ -72244,8 +72540,8 @@ function installResourcesDiscoverHook(pi, ctx) {
72244
72540
  try {
72245
72541
  pi.on("resources_discover", () => {
72246
72542
  const sessionCwd = ctx.currentCtx?.cwd ?? process.cwd();
72247
- const skillDir = path79.resolve(sessionCwd, "skills");
72248
- const extSkillDir = path79.resolve(path79.dirname(fileURLToPath7(import.meta.url)), "..", "..", "skills");
72543
+ const skillDir = path80.resolve(sessionCwd, "skills");
72544
+ const extSkillDir = path80.resolve(path80.dirname(fileURLToPath7(import.meta.url)), "..", "..", "skills");
72249
72545
  const paths = [];
72250
72546
  if (fs101.existsSync(extSkillDir)) paths.push(extSkillDir);
72251
72547
  if (skillDir !== extSkillDir && fs101.existsSync(skillDir)) {
@@ -72368,7 +72664,7 @@ init_run_maintenance();
72368
72664
  init_broker_issuer();
72369
72665
  init_crash_recovery();
72370
72666
  import * as fs105 from "node:fs";
72371
- import * as path85 from "node:path";
72667
+ import * as path86 from "node:path";
72372
72668
 
72373
72669
  // src/runtime/crew-broker.ts
72374
72670
  init_event_log();
@@ -72565,7 +72861,7 @@ import { createHash as createHash11 } from "node:crypto";
72565
72861
  import * as fsp2 from "node:fs/promises";
72566
72862
  import * as net from "node:net";
72567
72863
  import * as os17 from "node:os";
72568
- import * as path83 from "node:path";
72864
+ import * as path84 from "node:path";
72569
72865
  var DEFAULT_PATH_HASH_LEN = 8;
72570
72866
  var POSIX_SUN_PATH_BUDGET = 107;
72571
72867
  function hashSessionId(sessionId, length = DEFAULT_PATH_HASH_LEN) {
@@ -72595,7 +72891,7 @@ function getPerUserSocketDir(platform2 = process.platform) {
72595
72891
  if (platform2 === "win32") return "";
72596
72892
  const base = process.env.XDG_RUNTIME_DIR || os17.tmpdir();
72597
72893
  const uid = getCurrentUid();
72598
- return path83.join(base, `pi-crew-${uid}`);
72894
+ return path84.join(base, `pi-crew-${uid}`);
72599
72895
  }
72600
72896
  function getBrokerSocketPath(sessionId, platform2 = process.platform) {
72601
72897
  const hash = hashSessionId(sessionId);
@@ -72603,7 +72899,7 @@ function getBrokerSocketPath(sessionId, platform2 = process.platform) {
72603
72899
  return `\\\\.\\pipe\\pi-crew-broker-${hash}`;
72604
72900
  }
72605
72901
  const perUserDir = getPerUserSocketDir(platform2);
72606
- const sock = path83.join(perUserDir, `pi-crew-${hash}.sock`);
72902
+ const sock = path84.join(perUserDir, `pi-crew-${hash}.sock`);
72607
72903
  const encoded = Buffer.byteLength(sock, "utf8");
72608
72904
  if (encoded > POSIX_SUN_PATH_BUDGET) {
72609
72905
  throw new Error(
@@ -72614,7 +72910,7 @@ function getBrokerSocketPath(sessionId, platform2 = process.platform) {
72614
72910
  }
72615
72911
  async function prepareBrokerSocketDir(sockPath) {
72616
72912
  if (process.platform === "win32") return;
72617
- const dir = path83.dirname(sockPath);
72913
+ const dir = path84.dirname(sockPath);
72618
72914
  await fsp2.mkdir(dir, { recursive: true, mode: 448 });
72619
72915
  try {
72620
72916
  await fsp2.chmod(dir, 448);
@@ -73915,14 +74211,14 @@ init_defaults();
73915
74211
  init_artifact_store();
73916
74212
  init_internal_error();
73917
74213
  init_paths();
73918
- import * as path84 from "node:path";
74214
+ import * as path85 from "node:path";
73919
74215
  function runArtifactCleanup(cwd) {
73920
74216
  try {
73921
- cleanupOldArtifacts(path84.join(userCrewRoot(), DEFAULT_PATHS.state.artifactsSubdir), {
74217
+ cleanupOldArtifacts(path85.join(userCrewRoot(), DEFAULT_PATHS.state.artifactsSubdir), {
73922
74218
  maxAgeDays: DEFAULT_ARTIFACT_CLEANUP.maxAgeDays,
73923
74219
  markerFile: CLEANUP_MARKER_FILE
73924
74220
  });
73925
- cleanupOldArtifacts(path84.join(projectCrewRoot(cwd), DEFAULT_PATHS.state.artifactsSubdir), {
74221
+ cleanupOldArtifacts(path85.join(projectCrewRoot(cwd), DEFAULT_PATHS.state.artifactsSubdir), {
73926
74222
  maxAgeDays: DEFAULT_ARTIFACT_CLEANUP.maxAgeDays,
73927
74223
  markerFile: CLEANUP_MARKER_FILE
73928
74224
  });
@@ -74426,7 +74722,7 @@ function setupRenderLoop(pi, ctx, extensionCtx, loadedConfig) {
74426
74722
  try {
74427
74723
  ctx.crewRunWatchers?.closeAll();
74428
74724
  ctx.crewRunWatchers = void 0;
74429
- const crewRunsDir = path85.join(projectCrewRoot(extensionCtx.cwd), "state", "runs");
74725
+ const crewRunsDir = path86.join(projectCrewRoot(extensionCtx.cwd), "state", "runs");
74430
74726
  if (fs105.existsSync(crewRunsDir)) {
74431
74727
  ctx.crewRunWatchers = new RunWatcherRegistry();
74432
74728
  ctx.crewRunWatchers.setRootWatcher(crewRunsDir, crewRunWatcherOnChange, crewRunWatcherOnError);
@@ -74437,7 +74733,7 @@ function setupRenderLoop(pi, ctx, extensionCtx, loadedConfig) {
74437
74733
  try {
74438
74734
  ctx.userCrewWatchers?.closeAll();
74439
74735
  ctx.userCrewWatchers = void 0;
74440
- const userRunsDir = path85.join(userCrewRoot(), "state", "runs");
74736
+ const userRunsDir = path86.join(userCrewRoot(), "state", "runs");
74441
74737
  if (fs105.existsSync(userRunsDir)) {
74442
74738
  ctx.userCrewWatchers = new RunWatcherRegistry();
74443
74739
  ctx.userCrewWatchers.setRootWatcher(userRunsDir, crewRunWatcherOnChange, crewRunWatcherOnError);