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/CHANGELOG.md +29 -0
- package/dist/index.mjs +1153 -857
- package/package.json +1 -2
- package/scripts/smoke-team-perf.ts +43 -0
- package/src/extension/registration/team-tool.ts +2 -1
- package/src/extension/team-tool/param-error.ts +114 -0
- package/src/extension/team-tool/status.ts +6 -1
- package/src/runtime/attention-events.ts +3 -2
- package/src/runtime/child-pi-streams.ts +12 -0
- package/src/runtime/child-pi.ts +20 -7
- package/src/runtime/compact-stages/bounded-tail.ts +84 -0
- package/src/runtime/concurrency.ts +8 -2
- package/src/runtime/crew-agent-records.ts +48 -2
- package/src/runtime/diagnostic-export.ts +3 -2
- package/src/runtime/manifest-cache.ts +5 -1
- package/src/runtime/semaphore.ts +4 -1
- package/src/runtime/supervisor-contact.ts +27 -12
- package/src/runtime/task-runner/child-executor.ts +5 -9
- package/src/runtime/team-runner.ts +62 -37
- package/src/schema/team-tool-schema.ts +19 -11
- package/src/state/event-log-rotation.ts +28 -0
- package/src/state/event-log.ts +39 -13
- package/src/state/state-store.ts +18 -4
- package/src/utils/redaction.ts +39 -0
- package/src/worktree/worktree-manager.ts +23 -8
- package/dist/build-meta.json +0 -16807
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
|
|
1899
|
+
const path87 = errorPathFromValidation(error);
|
|
1900
1900
|
const message = error.message ?? "invalid value";
|
|
1901
1901
|
if (error.keyword === "additionalProperties") {
|
|
1902
|
-
const offendingKey =
|
|
1902
|
+
const offendingKey = path87.split("/").pop() ?? path87;
|
|
1903
1903
|
const suggestion = suggestConfigKey(offendingKey, KNOWN_TOP_LEVEL_KEYS);
|
|
1904
|
-
if (suggestion) return `${
|
|
1904
|
+
if (suggestion) return `${path87}: ${message} (did you mean '${suggestion}'?)`;
|
|
1905
1905
|
}
|
|
1906
|
-
return `${
|
|
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
|
|
3844
|
+
let path87 = "";
|
|
3845
3845
|
const scpLikeMatch = repoWithoutRef.match(/^git@([^:]+):(.+)$/);
|
|
3846
3846
|
if (scpLikeMatch) {
|
|
3847
3847
|
host = scpLikeMatch[1] ?? "";
|
|
3848
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
|
4210
|
+
const basename18 = path11.basename(filePath, ".dwf.ts");
|
|
4211
4211
|
return {
|
|
4212
|
-
name:
|
|
4213
|
-
description: `Dynamic workflow script (${
|
|
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
|
-
|
|
7589
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
8847
|
-
return new CrewError(ErrorCode.FileReadError, `Failed to read ${
|
|
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(
|
|
8852
|
-
return new CrewError(ErrorCode.FileWriteError, `Failed to write ${
|
|
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
|
|
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(
|
|
9756
|
+
fs25.mkdirSync(path21.dirname(eventsPath), { recursive: true });
|
|
9515
9757
|
const lockDir = `${eventsPath}.mkdirlock`;
|
|
9516
|
-
const pidFile =
|
|
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(
|
|
9976
|
+
await fs25.promises.mkdir(path21.dirname(eventsPath), { recursive: true });
|
|
9735
9977
|
const lockDir = `${eventsPath}.alock`;
|
|
9736
|
-
const pidFile =
|
|
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
|
-
|
|
9897
|
-
|
|
9898
|
-
|
|
9899
|
-
|
|
9900
|
-
|
|
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 (
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
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 !==
|
|
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 =
|
|
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(
|
|
10600
|
-
const artifactsRoot = resolveContainedRelativePath(
|
|
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:
|
|
10606
|
-
tasksPath:
|
|
10607
|
-
eventsPath:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
10899
|
-
const tasksPath =
|
|
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 =
|
|
10967
|
-
const tasksPath =
|
|
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
|
|
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 =
|
|
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 =
|
|
11540
|
+
const dir = path23.join(loaded.manifest.artifactsRoot, "diagnostic");
|
|
11366
11541
|
fs27.mkdirSync(dir, { recursive: true });
|
|
11367
|
-
const filePath =
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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 =
|
|
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 === "..") ||
|
|
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(
|
|
11883
|
-
resolveRealContainedPath(artifactsRoot,
|
|
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
|
|
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
|
|
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(
|
|
11953
|
-
const correctedDir =
|
|
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
|
|
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("..") ||
|
|
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 =
|
|
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 =
|
|
11986
|
-
const relative9 =
|
|
11987
|
-
if (relative9.startsWith("..") ||
|
|
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(
|
|
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(
|
|
12179
|
+
return safeMailboxFile(path25.join(parent, "delivery.json"), parent);
|
|
12005
12180
|
} catch (err2) {
|
|
12006
12181
|
if (err2.code === "ENOENT") {
|
|
12007
|
-
return
|
|
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(
|
|
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(
|
|
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 =
|
|
12099
|
-
const base =
|
|
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 =
|
|
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 =
|
|
12128
|
-
const base =
|
|
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(
|
|
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
|
|
13006
|
+
import * as path26 from "node:path";
|
|
12832
13007
|
function asyncStartMarkerPath(manifest) {
|
|
12833
|
-
return
|
|
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
|
|
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 =
|
|
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
|
|
13326
|
+
import { dirname as dirname15, join as join27 } from "node:path";
|
|
13152
13327
|
function getSkillMetricsPath(cwd, runId) {
|
|
13153
|
-
return
|
|
13328
|
+
return join27(projectCrewRoot(cwd), `state/runs/${runId}/skill-metrics.jsonl`);
|
|
13154
13329
|
}
|
|
13155
13330
|
function getSkillActivationsPath(cwd, runId) {
|
|
13156
|
-
return
|
|
13331
|
+
return join27(projectCrewRoot(cwd), `state/runs/${runId}/skill-activations.jsonl`);
|
|
13157
13332
|
}
|
|
13158
13333
|
function ensureSkillMetricsDir(cwd, runId) {
|
|
13159
|
-
const dir =
|
|
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
|
|
13378
|
+
const path87 = getSkillActivationsPath(cwd, activation.runId);
|
|
13204
13379
|
const line4 = JSON.stringify(activation) + "\n";
|
|
13205
|
-
writeFileSync5(
|
|
13380
|
+
writeFileSync5(path87, line4, { flag: "a", encoding: "utf-8" });
|
|
13206
13381
|
return activation;
|
|
13207
13382
|
}
|
|
13208
13383
|
function getSkillActivations(cwd, runId) {
|
|
13209
|
-
const
|
|
13210
|
-
if (!existsSync22(
|
|
13384
|
+
const path87 = getSkillActivationsPath(cwd, runId);
|
|
13385
|
+
if (!existsSync22(path87)) {
|
|
13211
13386
|
return [];
|
|
13212
13387
|
}
|
|
13213
|
-
const content = readFileSync21(
|
|
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
|
|
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:
|
|
13619
|
+
{ root: path28.resolve(cwd, ".pi", "skills"), source: "project-pi" },
|
|
13445
13620
|
{
|
|
13446
|
-
root:
|
|
13621
|
+
root: path28.resolve(cwd, ".agents", "skills"),
|
|
13447
13622
|
source: "project-agents"
|
|
13448
13623
|
},
|
|
13449
|
-
{ root:
|
|
13450
|
-
{ root:
|
|
13624
|
+
{ root: path28.resolve(cwd, "skills"), source: "project" },
|
|
13625
|
+
{ root: path28.join(getAgentDir(), "skills"), source: "user-pi" },
|
|
13451
13626
|
{
|
|
13452
|
-
root:
|
|
13627
|
+
root: path28.join(os9.homedir(), ".agents", "skills"),
|
|
13453
13628
|
source: "user-agents"
|
|
13454
13629
|
},
|
|
13455
|
-
{ root:
|
|
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 = `${
|
|
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 =
|
|
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(
|
|
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: ${
|
|
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 =
|
|
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,
|
|
14426
|
-
const ctrl = callVisitor(key, node, visitor,
|
|
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,
|
|
14429
|
-
return visit_(key, ctrl, visitor,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
14447
|
-
const ck = visit_("key", node.key, visitor,
|
|
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,
|
|
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,
|
|
14474
|
-
const ctrl = await callVisitor(key, node, visitor,
|
|
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,
|
|
14477
|
-
return visitAsync_(key, ctrl, visitor,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
14495
|
-
const ck = await visitAsync_("key", node.key, visitor,
|
|
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,
|
|
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,
|
|
14702
|
+
function callVisitor(key, node, visitor, path87) {
|
|
14528
14703
|
if (typeof visitor === "function")
|
|
14529
|
-
return visitor(key, node,
|
|
14704
|
+
return visitor(key, node, path87);
|
|
14530
14705
|
if (identity.isMap(node))
|
|
14531
|
-
return visitor.Map?.(key, node,
|
|
14706
|
+
return visitor.Map?.(key, node, path87);
|
|
14532
14707
|
if (identity.isSeq(node))
|
|
14533
|
-
return visitor.Seq?.(key, node,
|
|
14708
|
+
return visitor.Seq?.(key, node, path87);
|
|
14534
14709
|
if (identity.isPair(node))
|
|
14535
|
-
return visitor.Pair?.(key, node,
|
|
14710
|
+
return visitor.Pair?.(key, node, path87);
|
|
14536
14711
|
if (identity.isScalar(node))
|
|
14537
|
-
return visitor.Scalar?.(key, node,
|
|
14712
|
+
return visitor.Scalar?.(key, node, path87);
|
|
14538
14713
|
if (identity.isAlias(node))
|
|
14539
|
-
return visitor.Alias?.(key, node,
|
|
14714
|
+
return visitor.Alias?.(key, node, path87);
|
|
14540
14715
|
return void 0;
|
|
14541
14716
|
}
|
|
14542
|
-
function replaceNode(key,
|
|
14543
|
-
const parent =
|
|
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,
|
|
15328
|
+
function collectionFromPath(schema, path87, value) {
|
|
15154
15329
|
let v = value;
|
|
15155
|
-
for (let i =
|
|
15156
|
-
const k =
|
|
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 = (
|
|
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(
|
|
15206
|
-
if (isEmptyPath(
|
|
15380
|
+
addIn(path87, value) {
|
|
15381
|
+
if (isEmptyPath(path87))
|
|
15207
15382
|
this.add(value);
|
|
15208
15383
|
else {
|
|
15209
|
-
const [key, ...rest] =
|
|
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(
|
|
15224
|
-
const [key, ...rest] =
|
|
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(
|
|
15239
|
-
const [key, ...rest] =
|
|
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(
|
|
15258
|
-
const [key, ...rest] =
|
|
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(
|
|
15269
|
-
const [key, ...rest] =
|
|
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(
|
|
17959
|
+
addIn(path87, value) {
|
|
17785
17960
|
if (assertCollection(this.contents))
|
|
17786
|
-
this.contents.addIn(
|
|
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(
|
|
17862
|
-
if (Collection.isEmptyPath(
|
|
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(
|
|
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(
|
|
17884
|
-
if (Collection.isEmptyPath(
|
|
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(
|
|
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(
|
|
17898
|
-
if (Collection.isEmptyPath(
|
|
18072
|
+
hasIn(path87) {
|
|
18073
|
+
if (Collection.isEmptyPath(path87))
|
|
17899
18074
|
return this.contents !== void 0;
|
|
17900
|
-
return identity.isCollection(this.contents) ? this.contents.hasIn(
|
|
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(
|
|
17918
|
-
if (Collection.isEmptyPath(
|
|
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(
|
|
18096
|
+
this.contents = Collection.collectionFromPath(this.schema, Array.from(path87), value);
|
|
17922
18097
|
} else if (assertCollection(this.contents)) {
|
|
17923
|
-
this.contents.setIn(
|
|
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,
|
|
20058
|
+
visit.itemAtPath = (cst, path87) => {
|
|
19884
20059
|
let item = cst;
|
|
19885
|
-
for (const [field, index] of
|
|
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,
|
|
19895
|
-
const parent = visit.itemAtPath(cst,
|
|
19896
|
-
const field =
|
|
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(
|
|
19903
|
-
let ctrl = visitor(item,
|
|
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(
|
|
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,
|
|
20096
|
+
ctrl = ctrl(item, path87);
|
|
19922
20097
|
}
|
|
19923
20098
|
}
|
|
19924
|
-
return typeof ctrl === "function" ? ctrl(item,
|
|
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
|
|
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(
|
|
21699
|
-
return { path:
|
|
21873
|
+
function hard(path87, field, reason) {
|
|
21874
|
+
return { path: path87, field, reason, severity: "error" };
|
|
21700
21875
|
}
|
|
21701
|
-
function warn(
|
|
21702
|
-
return { path:
|
|
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 =
|
|
21707
|
-
const derivedName =
|
|
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
|
|
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:
|
|
22024
|
+
{ root: path30.resolve(cwd, ".pi", "skills"), source: "project-pi" },
|
|
21850
22025
|
{
|
|
21851
|
-
root:
|
|
22026
|
+
root: path30.resolve(cwd, ".agents", "skills"),
|
|
21852
22027
|
source: "project-agents"
|
|
21853
22028
|
},
|
|
21854
|
-
{ root:
|
|
21855
|
-
{ root:
|
|
22029
|
+
{ root: path30.resolve(cwd, "skills"), source: "project" },
|
|
22030
|
+
{ root: path30.join(getAgentDir(), "skills"), source: "user-pi" },
|
|
21856
22031
|
{
|
|
21857
|
-
root:
|
|
22032
|
+
root: path30.join(os10.homedir(), ".agents", "skills"),
|
|
21858
22033
|
source: "user-agents"
|
|
21859
22034
|
},
|
|
21860
|
-
{ root:
|
|
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 =
|
|
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 =
|
|
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:
|
|
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(
|
|
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 =
|
|
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
|
|
22248
|
+
import * as path31 from "node:path";
|
|
22074
22249
|
function foregroundControlPath(manifest) {
|
|
22075
|
-
return
|
|
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 =
|
|
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(
|
|
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
|
|
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
|
|
23607
|
+
if (envDir.startsWith("~/")) return path32.join(os11.homedir(), envDir.slice(2));
|
|
23433
23608
|
return envDir;
|
|
23434
23609
|
}
|
|
23435
|
-
return
|
|
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(
|
|
23467
|
-
const projectSettings = cwd ? readJsonObject(
|
|
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(
|
|
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
|
|
23855
|
+
import * as path33 from "node:path";
|
|
23681
23856
|
function writeSidechainEntry(filePath, entry) {
|
|
23682
|
-
fs39.mkdirSync(
|
|
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
|
|
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
|
|
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 =
|
|
23889
|
+
const outputDir = path34.join(manifest.artifactsRoot, "streaming");
|
|
23715
23890
|
fs40.mkdirSync(outputDir, { recursive: true });
|
|
23716
|
-
const outputPath =
|
|
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(
|
|
27012
|
-
let input =
|
|
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 [
|
|
27265
|
-
wsComponent.path =
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
33379
|
+
return path36.join(homedir8(), ".pi", "crew-settings.json");
|
|
33205
33380
|
}
|
|
33206
33381
|
function projectPath(cwd) {
|
|
33207
|
-
return
|
|
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(
|
|
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,
|
|
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 = [...
|
|
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(
|
|
34128
|
-
return
|
|
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
|
-
|
|
34721
|
-
|
|
34722
|
-
|
|
34723
|
-
|
|
34724
|
-
|
|
34725
|
-
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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,
|
|
35635
|
-
summaryPath =
|
|
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(
|
|
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 =
|
|
35670
|
-
const userRoot =
|
|
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
|
|
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(
|
|
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
|
|
36173
|
+
import * as path41 from "node:path";
|
|
35996
36174
|
function importRoot(cwd, scope) {
|
|
35997
36175
|
const base = scope === "project" ? projectCrewRoot(cwd) : userCrewRoot();
|
|
35998
|
-
return
|
|
36176
|
+
return path41.join(base, DEFAULT_PATHS.state.importsSubdir);
|
|
35999
36177
|
}
|
|
36000
36178
|
function importRunBundle(cwd, bundlePath, scope = "project") {
|
|
36001
|
-
const resolvedPath =
|
|
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 =
|
|
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(
|
|
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 =
|
|
36070
|
-
const targetSummary =
|
|
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
|
|
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() +
|
|
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 =
|
|
36136
|
-
fs51.mkdirSync(
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
|
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() +
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 ${
|
|
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 =
|
|
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
|
|
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
|
|
37072
|
-
if (resource === "team") return
|
|
37073
|
-
return
|
|
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
|
|
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 =
|
|
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" ?
|
|
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(
|
|
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
|
|
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 =
|
|
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 =
|
|
37543
|
-
const target =
|
|
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 =
|
|
37736
|
+
const usingLegacyPi = path45.basename(crewRoot) === "teams" && path45.basename(path45.dirname(crewRoot)) === ".pi";
|
|
37559
37737
|
const ignorePrefix = usingLegacyPi ? ".pi/teams" : ".crew";
|
|
37560
|
-
const agentsDir =
|
|
37561
|
-
const teamsDir =
|
|
37562
|
-
const workflowsDir =
|
|
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" ?
|
|
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(
|
|
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(
|
|
37573
|
-
else fs54.mkdirSync(
|
|
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" ?
|
|
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 =
|
|
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,
|
|
37813
|
-
const keys =
|
|
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,
|
|
37824
|
-
const keys =
|
|
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
|
|
38446
|
+
import { dirname as dirname28, join as join44 } from "node:path";
|
|
38269
38447
|
function allowedWorkflowDirs(cwd) {
|
|
38270
|
-
return [
|
|
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" ?
|
|
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
|
|
38627
|
-
import { dirname as
|
|
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
|
|
38835
|
+
const path87 = goalFilePath(this.cwd, goalId);
|
|
38658
38836
|
try {
|
|
38659
|
-
if (!existsSync42(
|
|
38660
|
-
const raw = readFileSync40(
|
|
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
|
|
38849
|
+
const path87 = goalFilePath(this.cwd, state.goalId);
|
|
38672
38850
|
const next = { ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
38673
38851
|
try {
|
|
38674
|
-
mkdirSync24(
|
|
38675
|
-
atomicWriteJson(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
38773
|
-
if (!existsSync42(
|
|
38774
|
-
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
38851
|
-
import * as
|
|
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 =
|
|
39031
|
+
const absCwd = path47.resolve(cwd);
|
|
38854
39032
|
const crewRoot = projectCrewRoot(absCwd) ?? userCrewRoot();
|
|
38855
|
-
const locksDir =
|
|
39033
|
+
const locksDir = path47.join(crewRoot, "state", "workspace-locks");
|
|
38856
39034
|
const hash = createHash7("sha256").update(absCwd).digest("hex");
|
|
38857
|
-
return
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
39347
|
+
return path49.resolve(path49.dirname(fileURLToPath6(import.meta.url)), "..", "..");
|
|
39170
39348
|
}
|
|
39171
39349
|
function jitiRegisterPathFromPackageJson(packageJsonPath) {
|
|
39172
|
-
return
|
|
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 =
|
|
39176
|
-
const root =
|
|
39353
|
+
let current = path49.resolve(packageRoot2);
|
|
39354
|
+
const root = path49.parse(current).root;
|
|
39177
39355
|
while (true) {
|
|
39178
|
-
const candidate =
|
|
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 =
|
|
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
|
-
|
|
39190
|
-
|
|
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 ??
|
|
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 =
|
|
39256
|
-
const logPath =
|
|
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
|
|
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 =
|
|
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 =
|
|
42347
|
-
const crewDir =
|
|
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 =
|
|
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 =
|
|
42355
|
-
const tasksPath =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
|
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 (!
|
|
43668
|
-
return toolResult(
|
|
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
|
|
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
|
|
44377
|
+
return path52.join(this.stateRoot, "checkpoints");
|
|
44117
44378
|
}
|
|
44118
44379
|
checkpointPath(taskId) {
|
|
44119
|
-
return
|
|
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(
|
|
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
|
|
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
|
|
44455
|
+
return path53.join(projectCrewRoot(cwd), "cache");
|
|
44195
44456
|
}
|
|
44196
44457
|
function getCachedRun(cwd, cacheKey2) {
|
|
44197
44458
|
const dir = cacheDir(cwd);
|
|
44198
|
-
const indexPath =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
44781
|
+
import * as path55 from "node:path";
|
|
44521
44782
|
function loadRunSummaries(cwd, options = {}) {
|
|
44522
44783
|
const crewRoot = projectCrewRoot(cwd);
|
|
44523
|
-
const runsRoot =
|
|
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(
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
45350
|
+
import * as path57 from "node:path";
|
|
45090
45351
|
function readRunTasks(stateRoot) {
|
|
45091
|
-
const tasksPath =
|
|
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 =
|
|
45133
|
-
const stateRunsDir =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 && !
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
47376
|
+
import * as path60 from "node:path";
|
|
47015
47377
|
function deadletterPath(manifest) {
|
|
47016
|
-
return
|
|
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
|
|
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
|
|
47812
|
+
return path61.join(artifactsRoot, "tee", safeTeeName(taskId, artifactName));
|
|
47451
47813
|
}
|
|
47452
47814
|
function writeTeeFile(fullOutputPath, content) {
|
|
47453
47815
|
try {
|
|
47454
|
-
fs72.mkdirSync(
|
|
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 === "..") ||
|
|
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 =
|
|
47505
|
-
const resolved =
|
|
47506
|
-
const relative9 =
|
|
47507
|
-
if (relative9.startsWith("..") ||
|
|
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 =
|
|
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:
|
|
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:
|
|
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
|
|
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:
|
|
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
|
|
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 ?
|
|
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 =
|
|
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 `${
|
|
48883
|
+
return `${path63.resolve(cwd)}|${options?.maxDepth ?? ""}|${options?.dirLimit ?? ""}|${options?.lineCap ?? ""}`;
|
|
48612
48884
|
}
|
|
48613
48885
|
async function buildWorkspaceTree(cwd, options) {
|
|
48614
|
-
const rootPath =
|
|
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
|
|
49331
|
+
import * as path64 from "node:path";
|
|
49060
49332
|
function knowledgePath(cwd) {
|
|
49061
|
-
return
|
|
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
|
|
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
|
|
49331
|
-
if (scope === "project") return
|
|
49332
|
-
return
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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:
|
|
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(
|
|
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 =
|
|
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:
|
|
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
|
|
50006
|
-
if (!
|
|
50007
|
-
|
|
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" &&
|
|
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
|
|
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(
|
|
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
|
|
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 =
|
|
51016
|
-
const target =
|
|
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 =
|
|
51040
|
-
const relative9 =
|
|
51041
|
-
if (!relative9 || relative9.startsWith("..") ||
|
|
51042
|
-
return
|
|
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 (!
|
|
51047
|
-
const normalized =
|
|
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(
|
|
51058
|
-
return realHookPath.startsWith(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 (
|
|
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 =
|
|
51079
|
-
if (!
|
|
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
|
-
|
|
51206
|
-
|
|
51207
|
-
|
|
51208
|
-
|
|
51209
|
-
|
|
51210
|
-
|
|
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 =
|
|
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 =
|
|
51221
|
-
const relativePath =
|
|
51222
|
-
if (relativePath.startsWith("..") ||
|
|
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(
|
|
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 =
|
|
51247
|
-
const destinationPath =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
52233
|
+
import * as path70 from "node:path";
|
|
51961
52234
|
function artifactReference(artifactsRoot, artifact) {
|
|
51962
52235
|
if (!artifact) return void 0;
|
|
51963
|
-
const root =
|
|
51964
|
-
const target =
|
|
51965
|
-
const relative9 =
|
|
51966
|
-
if (!relative9 || relative9.startsWith("..") ||
|
|
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
|
|
54115
|
+
import * as path71 from "node:path";
|
|
53843
54116
|
function startTeamRunHeartbeat(stateRoot, runId) {
|
|
53844
|
-
const heartbeatPath =
|
|
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 =
|
|
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
|
-
|
|
54374
|
-
|
|
54375
|
-
|
|
54376
|
-
|
|
54377
|
-
|
|
54378
|
-
|
|
54379
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
54555
|
-
|
|
54556
|
-
|
|
54557
|
-
|
|
54558
|
-
|
|
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
|
|
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 =
|
|
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) =>
|
|
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
|
-
|
|
54981
|
-
|
|
54982
|
-
|
|
54983
|
-
|
|
54984
|
-
|
|
54985
|
-
|
|
54986
|
-
|
|
54987
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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 ??
|
|
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
|
|
57343
|
+
import * as path73 from "node:path";
|
|
57048
57344
|
function sourcePiProjects(cwd) {
|
|
57049
|
-
const sourceDir =
|
|
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
|
|
57228
|
-
import { dirname as
|
|
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
|
|
57541
|
+
const path87 = this.path;
|
|
57246
57542
|
try {
|
|
57247
|
-
if (!existsSync70(
|
|
57248
|
-
const raw = readFileSync65(
|
|
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
|
|
57554
|
+
const path87 = this.path;
|
|
57259
57555
|
const next = { ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
57260
57556
|
try {
|
|
57261
|
-
mkdirSync39(
|
|
57262
|
-
atomicWriteJson(
|
|
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
|
|
57566
|
+
const path87 = this.path;
|
|
57271
57567
|
try {
|
|
57272
|
-
if (!existsSync70(
|
|
57273
|
-
|
|
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
|
|
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 =
|
|
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 ${
|
|
57637
|
+
error: `structured output does not match schema: expected shape ${describeSchemaShape(schema)}, got ${describeValue2(candidate)}`
|
|
57342
57638
|
};
|
|
57343
57639
|
}
|
|
57344
|
-
function
|
|
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
|
|
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 = [
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
60444
|
-
return `${
|
|
60739
|
+
function cacheKey(path87, options) {
|
|
60740
|
+
return `${path87}:${options.full ? "full" : `tail:${options.maxTailBytes}`}`;
|
|
60445
60741
|
}
|
|
60446
|
-
function getTranscriptCacheEntry(
|
|
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(
|
|
60747
|
+
return transcriptCache.get(cacheKey(path87, normalized)) ?? transcriptCache.get(path87);
|
|
60452
60748
|
}
|
|
60453
|
-
function readTranscriptText(
|
|
60749
|
+
function readTranscriptText(path87, stat2, options) {
|
|
60454
60750
|
if (options.full || stat2.size <= options.maxTailBytes) {
|
|
60455
60751
|
return {
|
|
60456
|
-
text: fs91.readFileSync(
|
|
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(
|
|
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(
|
|
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(
|
|
60775
|
+
const key = cacheKey(path87, normalized);
|
|
60480
60776
|
const previous = transcriptCache.get(key);
|
|
60481
60777
|
let stat2;
|
|
60482
60778
|
try {
|
|
60483
|
-
stat2 = fs91.statSync(
|
|
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(
|
|
60788
|
+
const read = readTranscriptText(path87, stat2, normalized);
|
|
60493
60789
|
const lines = parse4(read.text);
|
|
60494
60790
|
const entry = {
|
|
60495
|
-
path:
|
|
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,
|
|
63353
|
-
const keys =
|
|
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
|
|
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 =
|
|
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 =
|
|
65467
|
+
const skillsDir = path76.resolve(
|
|
65172
65468
|
cwd,
|
|
65173
|
-
useProject ? "skills" :
|
|
65174
|
-
|
|
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 =
|
|
65183
|
-
const skillPath =
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
66110
|
+
function readTasks3(path87) {
|
|
65815
66111
|
const parse4 = () => {
|
|
65816
|
-
const parsed = JSON.parse(fs100.readFileSync(
|
|
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(
|
|
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
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
|
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 =
|
|
67956
|
-
const candidate =
|
|
67957
|
-
if (candidate.startsWith(resultsDir +
|
|
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
|
|
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
|
|
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
|
|
69072
|
-
if (os18 === "linux") return
|
|
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 ??
|
|
69075
|
-
return
|
|
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
|
|
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
|
|
69238
|
-
if (!existsSync76(
|
|
69239
|
-
return normalizeConfig(JSON.parse(readFileSync72(
|
|
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
|
|
69246
|
-
mkdirSync42(
|
|
69247
|
-
writeFileSync11(
|
|
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
|
|
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
|
|
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() ||
|
|
69678
|
-
const candidates = [
|
|
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
|
|
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(
|
|
71064
|
+
function watchWithErrorHandler(path87, listener, onError) {
|
|
70769
71065
|
try {
|
|
70770
|
-
const watcher = fs95.watch(
|
|
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
|
|
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 (
|
|
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 =
|
|
70811
|
-
const artifactsRoot = resolveContainedRelativePath(
|
|
70812
|
-
if (manifest.runId !== runId || !sameFilesystemPath(manifest.stateRoot, stateRoot) || !sameFilesystemPath(manifest.tasksPath,
|
|
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(
|
|
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
|
|
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(
|
|
71141
|
+
roots.add(path77.join(userCrewRoot(), DEFAULT_PATHS.state.runsSubdir));
|
|
70846
71142
|
const projectRoot = findRepoRoot(cwd);
|
|
70847
|
-
if (projectRoot) roots.add(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
71102
|
-
const tasksRoot =
|
|
71397
|
+
const root = path78.join(manifest.stateRoot, "mailbox");
|
|
71398
|
+
const tasksRoot = path78.join(root, "tasks");
|
|
71103
71399
|
return combineStamps([
|
|
71104
|
-
stampFile(
|
|
71105
|
-
stampFile(
|
|
71106
|
-
stampFile(
|
|
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 =
|
|
71112
|
-
const tasksRoot =
|
|
71407
|
+
const root = path78.join(manifest.stateRoot, "mailbox");
|
|
71408
|
+
const tasksRoot = path78.join(root, "tasks");
|
|
71113
71409
|
return combineStamps([
|
|
71114
|
-
await stampFileAsync(
|
|
71115
|
-
await stampFileAsync(
|
|
71116
|
-
await stampFileAsync(
|
|
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 =
|
|
71447
|
-
const delivery = readDeliveryMessages(
|
|
71448
|
-
return readGroupJoinMailbox(
|
|
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 =
|
|
71452
|
-
const delivery = await readDeliveryMessagesAsync(
|
|
71453
|
-
return (await readGroupJoinMailboxAsync(
|
|
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 =
|
|
71467
|
-
const delivery = readDeliveryMessages(
|
|
71468
|
-
let inbox = readMailboxCounts(
|
|
71469
|
-
let outbox = readMailboxCounts(
|
|
71470
|
-
const tasksRoot =
|
|
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(
|
|
71477
|
-
const taskOutbox = readMailboxCounts(
|
|
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 =
|
|
71497
|
-
const delivery = await readDeliveryMessagesAsync(
|
|
71498
|
-
let inbox = await readMailboxCountsAsync(
|
|
71499
|
-
let outbox = await readMailboxCountsAsync(
|
|
71500
|
-
const tasksRoot =
|
|
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(
|
|
71507
|
-
const taskOutbox = await readMailboxCountsAsync(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
72164
|
-
if (seenContent.has(
|
|
72165
|
-
seenContent.set(
|
|
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 =
|
|
72248
|
-
const extSkillDir =
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
74214
|
+
import * as path85 from "node:path";
|
|
73919
74215
|
function runArtifactCleanup(cwd) {
|
|
73920
74216
|
try {
|
|
73921
|
-
cleanupOldArtifacts(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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);
|