pi-crew 0.9.26 → 0.9.28
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 +102 -0
- package/NOTICE.md +14 -0
- package/assets/crew-vibes.ttf +0 -0
- package/assets/runner-spritesheet.png +0 -0
- package/dist/build-meta.json +245 -48
- package/dist/index.mjs +1611 -243
- package/dist/index.mjs.map +4 -4
- package/docs/perf/optimization-plan-2026-07-verified.md +396 -0
- package/package.json +9 -2
- package/scripts/bench-check.mjs +96 -0
- package/scripts/bench-cold-start.mjs +216 -0
- package/scripts/build-bundle.mjs +84 -0
- package/scripts/build-crew-vibes-font.py +328 -0
- package/scripts/check-all-skills.ts +294 -0
- package/scripts/check-bundle-staleness.mjs +97 -0
- package/scripts/check-conflict-markers.mjs +91 -0
- package/scripts/check-lazy-imports.mjs +28 -0
- package/scripts/install-crew-vibes-font.mjs +91 -0
- package/scripts/postinstall.mjs +47 -0
- package/scripts/profile-startup.mjs +125 -0
- package/scripts/release-smoke.mjs +74 -0
- package/scripts/run-bench.mjs +47 -0
- package/scripts/run-real-chain.ts +41 -0
- package/scripts/test-issue-29-crash.ts +111 -0
- package/scripts/test-issue-29-e2e.ts +183 -0
- package/scripts/test-issue-29-real-runtime.ts +330 -0
- package/scripts/test-issue-29-real-tasks.ts +387 -0
- package/scripts/test-issue-29-team-tool.ts +105 -0
- package/scripts/test-runner.mjs +74 -0
- package/scripts/verify-flicker-fix.ts +109 -0
- package/scripts/verify-skill.ts +550 -0
- package/scripts/watch-bundle.mjs +259 -0
- package/scripts/watchdog-harness.ts +119 -0
- package/src/agents/agent-config.ts +2 -0
- package/src/agents/discover-agents.ts +10 -1
- package/src/config/defaults.ts +6 -0
- package/src/extension/crew-vibes/cat-frames.ts +18 -0
- package/src/extension/crew-vibes/config.ts +195 -0
- package/src/extension/crew-vibes/figures.ts +94 -0
- package/src/extension/crew-vibes/font-detect.ts +58 -0
- package/src/extension/crew-vibes/index.ts +385 -0
- package/src/extension/crew-vibes/provider-usage.ts +396 -0
- package/src/extension/crew-vibes/render.ts +206 -0
- package/src/extension/crew-vibes/speed.ts +286 -0
- package/src/extension/knowledge-injection.ts +12 -3
- package/src/extension/management.ts +23 -3
- package/src/extension/register.ts +7 -0
- package/src/extension/team-tool.ts +11 -0
- package/src/prompt/prompt-runtime.ts +65 -0
- package/src/runtime/child-pi.ts +123 -10
- package/src/runtime/crew-agent-records.ts +10 -3
- package/src/runtime/pi-args.ts +2 -0
- package/src/runtime/retry-executor.ts +4 -1
- package/src/runtime/task-runner/state-helpers.ts +9 -30
- package/src/runtime/task-runner.ts +1 -0
- package/src/runtime/team-runner.ts +5 -3
- package/src/state/atomic-write.ts +153 -49
- package/src/state/event-log.ts +16 -10
- package/src/state/locks.ts +7 -8
- package/src/state/mailbox.ts +15 -4
- package/src/state/state-store.ts +39 -10
- package/src/teams/discover-teams.ts +56 -1
- package/src/utils/safe-paths.ts +2 -1
- package/src/workflows/discover-workflows.ts +72 -1
package/dist/index.mjs
CHANGED
|
@@ -8693,6 +8693,7 @@ __export(atomic_write_exports, {
|
|
|
8693
8693
|
atomicWriteJsonAsync: () => atomicWriteJsonAsync,
|
|
8694
8694
|
atomicWriteJsonCoalesced: () => atomicWriteJsonCoalesced,
|
|
8695
8695
|
flushPendingAtomicWrites: () => flushPendingAtomicWrites,
|
|
8696
|
+
invalidateSymlinkSafeCache: () => invalidateSymlinkSafeCache,
|
|
8696
8697
|
isSymlinkSafePath: () => isSymlinkSafePath,
|
|
8697
8698
|
readJsonFile: () => readJsonFile,
|
|
8698
8699
|
renameWithRetry: () => renameWithRetry,
|
|
@@ -8774,6 +8775,32 @@ function isSymlinkSafePath(filePath) {
|
|
|
8774
8775
|
return false;
|
|
8775
8776
|
}
|
|
8776
8777
|
}
|
|
8778
|
+
function invalidateSymlinkSafeCache(dir) {
|
|
8779
|
+
if (dir) symlinkSafeCache.delete(dir);
|
|
8780
|
+
else symlinkSafeCache.clear();
|
|
8781
|
+
}
|
|
8782
|
+
function isTargetNotSymlink(filePath) {
|
|
8783
|
+
try {
|
|
8784
|
+
if (fs2.lstatSync(filePath).isSymbolicLink()) return false;
|
|
8785
|
+
} catch {
|
|
8786
|
+
}
|
|
8787
|
+
return true;
|
|
8788
|
+
}
|
|
8789
|
+
function isSymlinkSafeDirCached(filePath) {
|
|
8790
|
+
const now = Date.now();
|
|
8791
|
+
const dir = path2.dirname(filePath);
|
|
8792
|
+
if (!isTargetNotSymlink(filePath)) return false;
|
|
8793
|
+
const hit = symlinkSafeCache.get(dir);
|
|
8794
|
+
if (hit && now - hit.at < SYMLINK_SAFE_TTL_MS) return hit.safe;
|
|
8795
|
+
const verdict = isSymlinkSafePath(path2.join(dir, ".symlink-safe-check"));
|
|
8796
|
+
symlinkSafeCache.set(dir, { safe: verdict, at: now });
|
|
8797
|
+
while (symlinkSafeCache.size > SYMLINK_SAFE_MAX_ENTRIES) {
|
|
8798
|
+
const oldest = symlinkSafeCache.keys().next().value;
|
|
8799
|
+
if (oldest === void 0) break;
|
|
8800
|
+
symlinkSafeCache.delete(oldest);
|
|
8801
|
+
}
|
|
8802
|
+
return verdict;
|
|
8803
|
+
}
|
|
8777
8804
|
function sleep2(ms) {
|
|
8778
8805
|
return new Promise((resolve21) => setTimeout(resolve21, ms));
|
|
8779
8806
|
}
|
|
@@ -8889,8 +8916,19 @@ async function renameWithRetryAsync(tempPath, filePath, retries = 8, rename = (s
|
|
|
8889
8916
|
}
|
|
8890
8917
|
throw lastError;
|
|
8891
8918
|
}
|
|
8892
|
-
function
|
|
8893
|
-
if (
|
|
8919
|
+
function normalizeOptions(arg) {
|
|
8920
|
+
if (typeof arg === "string") return { expectedHash: arg, durability: "full" };
|
|
8921
|
+
if (arg && typeof arg === "object") {
|
|
8922
|
+
const o = arg;
|
|
8923
|
+
const durability = o.durability === "best-effort" ? "best-effort" : "full";
|
|
8924
|
+
return { expectedHash: o.expectedHash, durability };
|
|
8925
|
+
}
|
|
8926
|
+
return { durability: "full" };
|
|
8927
|
+
}
|
|
8928
|
+
function atomicWriteFile(filePath, content, options) {
|
|
8929
|
+
const { durability } = normalizeOptions(options);
|
|
8930
|
+
if (!isSymlinkSafeDirCached(filePath))
|
|
8931
|
+
throw new Error(`Refusing to write: target is a symlink or inside untrusted directory: ${filePath}`);
|
|
8894
8932
|
const canonicalize = (p) => {
|
|
8895
8933
|
try {
|
|
8896
8934
|
const r = fs2.realpathSync.native(p);
|
|
@@ -8925,14 +8963,14 @@ function atomicWriteFile(filePath, content, expectedHash) {
|
|
|
8925
8963
|
throw new Error(`Refusing to write: opened path is not a regular file: ${tempPath}`);
|
|
8926
8964
|
}
|
|
8927
8965
|
fs2.writeSync(fd, content, void 0, "utf-8");
|
|
8928
|
-
fs2.fsyncSync(fd);
|
|
8966
|
+
if (durability === "full") fs2.fsyncSync(fd);
|
|
8929
8967
|
fs2.closeSync(fd);
|
|
8930
8968
|
try {
|
|
8931
|
-
if (!
|
|
8969
|
+
if (!isSymlinkSafeDirCached(filePath)) {
|
|
8932
8970
|
throw new Error(`Refusing to rename: target became a symlink or inside untrusted directory: ${filePath}`);
|
|
8933
8971
|
}
|
|
8934
8972
|
renameWithLinkSync(tempPath, filePath);
|
|
8935
|
-
if (process.platform !== "win32") {
|
|
8973
|
+
if (durability === "full" && process.platform !== "win32") {
|
|
8936
8974
|
try {
|
|
8937
8975
|
const dirFd = fs2.openSync(path2.dirname(filePath), "r");
|
|
8938
8976
|
fs2.fsyncSync(dirFd);
|
|
@@ -8963,11 +9001,13 @@ function atomicWriteFile(filePath, content, expectedHash) {
|
|
|
8963
9001
|
}
|
|
8964
9002
|
}
|
|
8965
9003
|
}
|
|
8966
|
-
async function atomicWriteFileAsync(filePath, content) {
|
|
9004
|
+
async function atomicWriteFileAsync(filePath, content, options) {
|
|
9005
|
+
const { durability } = normalizeOptions(options);
|
|
8967
9006
|
if (isWorkerAtomicWriterEnabled()) {
|
|
8968
9007
|
return atomicWriteFileViaWorker(filePath, content);
|
|
8969
9008
|
}
|
|
8970
|
-
if (!
|
|
9009
|
+
if (!isSymlinkSafeDirCached(filePath))
|
|
9010
|
+
throw new Error(`Refusing to write: target is a symlink or inside untrusted directory: ${filePath}`);
|
|
8971
9011
|
await fs2.promises.mkdir(path2.dirname(filePath), { recursive: true });
|
|
8972
9012
|
const tempPath = `${filePath}.${crypto.randomUUID()}.tmp`;
|
|
8973
9013
|
try {
|
|
@@ -8979,33 +9019,12 @@ async function atomicWriteFileAsync(filePath, content) {
|
|
|
8979
9019
|
throw new Error(`Refusing to write: opened path is not a regular file: ${tempPath}`);
|
|
8980
9020
|
}
|
|
8981
9021
|
await fd.writeFile(content, "utf-8");
|
|
9022
|
+
if (durability === "full") await fd.sync();
|
|
8982
9023
|
await fd.close();
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
try {
|
|
8986
|
-
await fs2.promises.rm(tempPath, { force: true });
|
|
8987
|
-
} catch {
|
|
8988
|
-
}
|
|
8989
|
-
throw new Error(`Refusing to rename: target became a symlink or inside untrusted directory: ${filePath}`);
|
|
8990
|
-
}
|
|
8991
|
-
await renameWithLinkAsync(tempPath, filePath);
|
|
8992
|
-
} catch (renameError) {
|
|
8993
|
-
let matches = false;
|
|
8994
|
-
try {
|
|
8995
|
-
const existing = await fs2.promises.readFile(filePath, "utf-8");
|
|
8996
|
-
matches = existing === content;
|
|
8997
|
-
} catch {
|
|
8998
|
-
}
|
|
8999
|
-
if (matches) {
|
|
9000
|
-
try {
|
|
9001
|
-
await fs2.promises.rm(tempPath, { force: true });
|
|
9002
|
-
} catch (cleanupError) {
|
|
9003
|
-
logInternalError("atomic-write.cleanupAsync", cleanupError, `tempPath=${tempPath}`);
|
|
9004
|
-
}
|
|
9005
|
-
return;
|
|
9006
|
-
}
|
|
9007
|
-
throw renameError;
|
|
9024
|
+
if (!isSymlinkSafeDirCached(filePath)) {
|
|
9025
|
+
throw new Error(`Refusing to rename: target became a symlink or inside untrusted directory: ${filePath}`);
|
|
9008
9026
|
}
|
|
9027
|
+
await renameWithLinkAsync(tempPath, filePath);
|
|
9009
9028
|
} catch (error) {
|
|
9010
9029
|
try {
|
|
9011
9030
|
await fs2.promises.rm(tempPath, { force: true });
|
|
@@ -9015,15 +9034,15 @@ async function atomicWriteFileAsync(filePath, content) {
|
|
|
9015
9034
|
throw error;
|
|
9016
9035
|
}
|
|
9017
9036
|
}
|
|
9018
|
-
function atomicWriteJson(filePath, value) {
|
|
9037
|
+
function atomicWriteJson(filePath, value, options) {
|
|
9019
9038
|
atomicWriteFile(filePath, `${JSON.stringify(value, null, 2)}
|
|
9020
|
-
|
|
9039
|
+
`, options);
|
|
9021
9040
|
}
|
|
9022
|
-
async function atomicWriteJsonAsync(filePath, value) {
|
|
9041
|
+
async function atomicWriteJsonAsync(filePath, value, options) {
|
|
9023
9042
|
await atomicWriteFileAsync(filePath, `${JSON.stringify(value, null, 2)}
|
|
9024
|
-
|
|
9043
|
+
`, options);
|
|
9025
9044
|
}
|
|
9026
|
-
function atomicWriteJsonCoalesced(filePath, value, coalesceMs = DEFAULT_ATOMIC_COALESCE_MS) {
|
|
9045
|
+
function atomicWriteJsonCoalesced(filePath, value, coalesceMs = DEFAULT_ATOMIC_COALESCE_MS, options) {
|
|
9027
9046
|
const content = `${JSON.stringify(value, null, 2)}
|
|
9028
9047
|
`;
|
|
9029
9048
|
const previous = pendingAtomicWrites.get(filePath);
|
|
@@ -9031,12 +9050,14 @@ function atomicWriteJsonCoalesced(filePath, value, coalesceMs = DEFAULT_ATOMIC_C
|
|
|
9031
9050
|
const timer = setTimeout(() => flushOnePendingAtomicWrite(filePath), coalesceMs);
|
|
9032
9051
|
timer.unref();
|
|
9033
9052
|
const generation = ++writeGeneration;
|
|
9053
|
+
const normalized = normalizeOptions(options);
|
|
9034
9054
|
pendingAtomicWrites.set(filePath, {
|
|
9035
9055
|
content,
|
|
9036
9056
|
timer,
|
|
9037
9057
|
coalesceMs,
|
|
9038
9058
|
retryCount: 0,
|
|
9039
|
-
generation
|
|
9059
|
+
generation,
|
|
9060
|
+
durability: normalized.durability
|
|
9040
9061
|
});
|
|
9041
9062
|
}
|
|
9042
9063
|
function flushOnePendingAtomicWrite(filePath) {
|
|
@@ -9045,7 +9066,7 @@ function flushOnePendingAtomicWrite(filePath) {
|
|
|
9045
9066
|
const savedGeneration = entry.generation;
|
|
9046
9067
|
clearTimeout(entry.timer);
|
|
9047
9068
|
try {
|
|
9048
|
-
atomicWriteFile(filePath, entry.content);
|
|
9069
|
+
atomicWriteFile(filePath, entry.content, { durability: entry.durability });
|
|
9049
9070
|
if (pendingAtomicWrites.get(filePath)?.generation === savedGeneration) {
|
|
9050
9071
|
pendingAtomicWrites.delete(filePath);
|
|
9051
9072
|
}
|
|
@@ -9090,7 +9111,7 @@ function readJsonFile(filePath) {
|
|
|
9090
9111
|
}
|
|
9091
9112
|
}
|
|
9092
9113
|
}
|
|
9093
|
-
var RETRYABLE_RENAME_CODES, RETRYABLE_LINK_CODES, __test__renameWithRetry, __test__renameWithRetryAsync, MAX_FLUSH_RETRIES, pendingAtomicWrites, DEFAULT_ATOMIC_COALESCE_MS, writeGeneration, flushInProgress;
|
|
9114
|
+
var RETRYABLE_RENAME_CODES, RETRYABLE_LINK_CODES, SYMLINK_SAFE_TTL_MS, SYMLINK_SAFE_MAX_ENTRIES, symlinkSafeCache, __test__renameWithRetry, __test__renameWithRetryAsync, MAX_FLUSH_RETRIES, pendingAtomicWrites, DEFAULT_ATOMIC_COALESCE_MS, writeGeneration, flushInProgress;
|
|
9094
9115
|
var init_atomic_write = __esm({
|
|
9095
9116
|
"src/state/atomic-write.ts"() {
|
|
9096
9117
|
"use strict";
|
|
@@ -9099,6 +9120,9 @@ var init_atomic_write = __esm({
|
|
|
9099
9120
|
init_worker_atomic_writer();
|
|
9100
9121
|
RETRYABLE_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES"]);
|
|
9101
9122
|
RETRYABLE_LINK_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOENT"]);
|
|
9123
|
+
SYMLINK_SAFE_TTL_MS = 3e4;
|
|
9124
|
+
SYMLINK_SAFE_MAX_ENTRIES = 128;
|
|
9125
|
+
symlinkSafeCache = /* @__PURE__ */ new Map();
|
|
9102
9126
|
__test__renameWithRetry = renameWithRetry;
|
|
9103
9127
|
__test__renameWithRetryAsync = renameWithRetryAsync;
|
|
9104
9128
|
MAX_FLUSH_RETRIES = 5;
|
|
@@ -9120,6 +9144,7 @@ var init_defaults = __esm({
|
|
|
9120
9144
|
DEFAULT_CHILD_PI = {
|
|
9121
9145
|
postExitStdioGuardMs: 3e3,
|
|
9122
9146
|
finalDrainMs: 5e3,
|
|
9147
|
+
finalDrainQuietMs: 800,
|
|
9123
9148
|
hardKillMs: 3e3,
|
|
9124
9149
|
// Child workers can spend more than a few seconds in provider calls or long-running tools without emitting stdout.
|
|
9125
9150
|
// Keep this as a coarse stuck-worker guard rather than a short per-message latency budget.
|
|
@@ -9325,14 +9350,10 @@ function readLockToken(filePath) {
|
|
|
9325
9350
|
}
|
|
9326
9351
|
}
|
|
9327
9352
|
function timingSafeTokenMatch(a, b) {
|
|
9328
|
-
|
|
9329
|
-
const
|
|
9330
|
-
const
|
|
9331
|
-
|
|
9332
|
-
const safeB = Buffer.alloc(len);
|
|
9333
|
-
bufA.copy(safeA);
|
|
9334
|
-
bufB.copy(safeB);
|
|
9335
|
-
return timingSafeEqual(safeA, safeB);
|
|
9353
|
+
if (a.length !== b.length) return false;
|
|
9354
|
+
const bufA = Buffer.from(a);
|
|
9355
|
+
const bufB = Buffer.from(b);
|
|
9356
|
+
return timingSafeEqual(bufA, bufB);
|
|
9336
9357
|
}
|
|
9337
9358
|
function releaseLock(filePath, token) {
|
|
9338
9359
|
let isSymlink2 = false;
|
|
@@ -11703,9 +11724,6 @@ function resetEventLogMode() {
|
|
|
11703
11724
|
asyncQueues.clear();
|
|
11704
11725
|
}
|
|
11705
11726
|
async function appendEventAsync(eventsPath, event) {
|
|
11706
|
-
if (!TERMINAL_EVENT_TYPES.has(event.type)) {
|
|
11707
|
-
return appendEventBuffered(eventsPath, event);
|
|
11708
|
-
}
|
|
11709
11727
|
const queueKey = eventsPath;
|
|
11710
11728
|
const prev = asyncQueues.get(queueKey) ?? Promise.resolve();
|
|
11711
11729
|
const next = prev.then(async () => {
|
|
@@ -12014,12 +12032,14 @@ function appendEventInsideLock(eventsPath, event) {
|
|
|
12014
12032
|
if (!skippedDueToSize) {
|
|
12015
12033
|
fs8.appendFileSync(eventsPath, `${JSON.stringify(redactSecrets(fullEvent))}
|
|
12016
12034
|
`, "utf-8");
|
|
12017
|
-
|
|
12018
|
-
|
|
12019
|
-
|
|
12020
|
-
|
|
12021
|
-
|
|
12022
|
-
|
|
12035
|
+
if (isTerminal) {
|
|
12036
|
+
const fd = fs8.openSync(eventsPath, "r+");
|
|
12037
|
+
try {
|
|
12038
|
+
fs8.fsyncSync(fd);
|
|
12039
|
+
} catch {
|
|
12040
|
+
} finally {
|
|
12041
|
+
fs8.closeSync(fd);
|
|
12042
|
+
}
|
|
12023
12043
|
}
|
|
12024
12044
|
persistSequence(eventsPath, seq);
|
|
12025
12045
|
try {
|
|
@@ -12212,6 +12232,20 @@ var init_event_log = __esm({
|
|
|
12212
12232
|
}
|
|
12213
12233
|
asyncQueues.clear();
|
|
12214
12234
|
});
|
|
12235
|
+
process.on("beforeExit", async () => {
|
|
12236
|
+
if (bufferedQueues.size > 0) {
|
|
12237
|
+
try {
|
|
12238
|
+
await flushEventLogBuffer();
|
|
12239
|
+
} catch {
|
|
12240
|
+
}
|
|
12241
|
+
}
|
|
12242
|
+
if (asyncQueues.size > 0) {
|
|
12243
|
+
try {
|
|
12244
|
+
await drainAsyncQueues();
|
|
12245
|
+
} catch {
|
|
12246
|
+
}
|
|
12247
|
+
}
|
|
12248
|
+
});
|
|
12215
12249
|
process.on("SIGTERM", () => setImmediate(() => flushEventLogBuffer()));
|
|
12216
12250
|
process.on("SIGINT", () => setImmediate(() => flushEventLogBuffer()));
|
|
12217
12251
|
process.on("uncaughtException", (error) => {
|
|
@@ -12514,7 +12548,7 @@ function resolveRealContainedPath(baseDir, targetPath2) {
|
|
|
12514
12548
|
if (process.platform === "darwin") {
|
|
12515
12549
|
const resolvedSymlink = resolvedAccumulated;
|
|
12516
12550
|
const knownDarwinSymlinks = ["/var", "/tmp", "/etc", "/private/var", "/private/tmp", "/private/etc"];
|
|
12517
|
-
if (knownDarwinSymlinks.
|
|
12551
|
+
if (knownDarwinSymlinks.some((s) => resolvedSymlink === s || resolvedSymlink.startsWith(s + "/"))) continue;
|
|
12518
12552
|
}
|
|
12519
12553
|
throw new Error("Refusing to resolve: target path ancestor is a symlink: " + resolvedAccumulated);
|
|
12520
12554
|
}
|
|
@@ -13155,6 +13189,9 @@ function statManifestWithWindowsRetry(manifestPath) {
|
|
|
13155
13189
|
}
|
|
13156
13190
|
return fs12.statSync(manifestPath);
|
|
13157
13191
|
}
|
|
13192
|
+
function genOf(stateRoot) {
|
|
13193
|
+
return manifestCacheGeneration.get(stateRoot) ?? 0;
|
|
13194
|
+
}
|
|
13158
13195
|
function __test__setManifestCache(stateRoot, entry) {
|
|
13159
13196
|
setManifestCache(stateRoot, entry);
|
|
13160
13197
|
}
|
|
@@ -13164,7 +13201,7 @@ function __test__getManifestCacheEntry(stateRoot) {
|
|
|
13164
13201
|
function setManifestCache(stateRoot, entry) {
|
|
13165
13202
|
if (manifestCache.has(stateRoot)) manifestCache.delete(stateRoot);
|
|
13166
13203
|
entry.cachedAt = Date.now();
|
|
13167
|
-
entry.generation =
|
|
13204
|
+
entry.generation = genOf(stateRoot);
|
|
13168
13205
|
const now = Date.now();
|
|
13169
13206
|
for (const [key, val] of manifestCache.entries()) {
|
|
13170
13207
|
if (val.cachedAt && now - val.cachedAt > MANIFEST_CACHE_TTL_MS) {
|
|
@@ -13191,7 +13228,7 @@ function useProjectState(cwd) {
|
|
|
13191
13228
|
}
|
|
13192
13229
|
function invalidateRunCache(stateRoot) {
|
|
13193
13230
|
manifestCache.delete(stateRoot);
|
|
13194
|
-
manifestCacheGeneration
|
|
13231
|
+
manifestCacheGeneration.set(stateRoot, genOf(stateRoot) + 1);
|
|
13195
13232
|
}
|
|
13196
13233
|
function scopeBaseRoot(cwd) {
|
|
13197
13234
|
return useProjectState(cwd) ? projectCrewRoot(cwd) : userCrewRoot();
|
|
@@ -13332,13 +13369,24 @@ function saveRunManifest(manifest) {
|
|
|
13332
13369
|
const manifestPath = path10.join(manifest.stateRoot, "manifest.json");
|
|
13333
13370
|
atomicWriteJson(manifestPath, manifest);
|
|
13334
13371
|
const manifestStat = fs12.statSync(manifestPath);
|
|
13372
|
+
let tasks = [];
|
|
13373
|
+
let tasksMtimeMs = 0;
|
|
13374
|
+
let tasksSize = 0;
|
|
13375
|
+
try {
|
|
13376
|
+
const tasksPath = path10.join(manifest.stateRoot, "tasks.json");
|
|
13377
|
+
const tasksStat = fs12.statSync(tasksPath);
|
|
13378
|
+
tasks = JSON.parse(fs12.readFileSync(tasksPath, "utf-8"));
|
|
13379
|
+
tasksMtimeMs = tasksStat.mtimeMs;
|
|
13380
|
+
tasksSize = tasksStat.size;
|
|
13381
|
+
} catch {
|
|
13382
|
+
}
|
|
13335
13383
|
setManifestCache(manifest.stateRoot, {
|
|
13336
13384
|
manifest,
|
|
13337
|
-
tasks
|
|
13385
|
+
tasks,
|
|
13338
13386
|
manifestMtimeMs: manifestStat.mtimeMs,
|
|
13339
13387
|
manifestSize: manifestStat.size,
|
|
13340
|
-
tasksMtimeMs
|
|
13341
|
-
tasksSize
|
|
13388
|
+
tasksMtimeMs,
|
|
13389
|
+
tasksSize
|
|
13342
13390
|
});
|
|
13343
13391
|
}
|
|
13344
13392
|
async function saveRunManifestAsync(manifest) {
|
|
@@ -13506,7 +13554,7 @@ function loadRunManifestById(cwd, runId) {
|
|
|
13506
13554
|
tasksStat = void 0;
|
|
13507
13555
|
}
|
|
13508
13556
|
const tasksMtimeMs = tasksStat?.mtimeMs ?? 0;
|
|
13509
|
-
if (cached && cached.manifestMtimeMs === manifestStat.mtimeMs && cached.manifestSize === manifestStat.size && cached.tasksMtimeMs === tasksMtimeMs && cached.tasksSize === (tasksStat?.size ?? 0) && cached.generation ===
|
|
13557
|
+
if (cached && cached.manifestMtimeMs === manifestStat.mtimeMs && cached.manifestSize === manifestStat.size && cached.tasksMtimeMs === tasksMtimeMs && cached.tasksSize === (tasksStat?.size ?? 0) && cached.generation === genOf(stateRoot)) {
|
|
13510
13558
|
if (!cached.cachedAt || Date.now() - cached.cachedAt > MANIFEST_CACHE_TTL_MS) {
|
|
13511
13559
|
manifestCache.delete(stateRoot);
|
|
13512
13560
|
} else if (!validateRunManifestPaths(cwd, runId, cached.manifest, stateRoot, tasksPath)) {
|
|
@@ -13569,7 +13617,7 @@ async function loadRunManifestByIdAsync(cwd, runId) {
|
|
|
13569
13617
|
tasksStat = void 0;
|
|
13570
13618
|
}
|
|
13571
13619
|
const tasksMtimeMs = tasksStat?.mtimeMs ?? 0;
|
|
13572
|
-
if (cached && cached.manifestMtimeMs === manifestStat.mtimeMs && cached.manifestSize === manifestStat.size && cached.tasksMtimeMs === tasksMtimeMs && cached.tasksSize === (tasksStat?.size ?? 0) && cached.generation ===
|
|
13620
|
+
if (cached && cached.manifestMtimeMs === manifestStat.mtimeMs && cached.manifestSize === manifestStat.size && cached.tasksMtimeMs === tasksMtimeMs && cached.tasksSize === (tasksStat?.size ?? 0) && cached.generation === genOf(stateRoot)) {
|
|
13573
13621
|
if (!cached.cachedAt || Date.now() - cached.cachedAt > MANIFEST_CACHE_TTL_MS) {
|
|
13574
13622
|
manifestCache.delete(stateRoot);
|
|
13575
13623
|
} else if (!validateRunManifestPaths(cwd, runId, cached.manifest, stateRoot, tasksPath)) {
|
|
@@ -13629,7 +13677,7 @@ var init_state_store = __esm({
|
|
|
13629
13677
|
init_contracts();
|
|
13630
13678
|
init_event_log();
|
|
13631
13679
|
init_locks();
|
|
13632
|
-
manifestCacheGeneration =
|
|
13680
|
+
manifestCacheGeneration = /* @__PURE__ */ new Map();
|
|
13633
13681
|
MANIFEST_CACHE_TTL_MS = 15 * 1e3;
|
|
13634
13682
|
LOAD_MANIFEST_RETRY_LIMIT = 5;
|
|
13635
13683
|
manifestCache = /* @__PURE__ */ new Map();
|
|
@@ -13950,18 +13998,20 @@ function upsertCrewAgent(manifest, record) {
|
|
|
13950
13998
|
}
|
|
13951
13999
|
function writeCrewAgentStatus(manifest, record) {
|
|
13952
14000
|
ensureAgentStateDir(manifest, record.taskId);
|
|
13953
|
-
atomicWriteJson(agentStatusPath(manifest, record.taskId), redactSecrets(record));
|
|
14001
|
+
atomicWriteJson(agentStatusPath(manifest, record.taskId), redactSecrets(record), { durability: "full" });
|
|
13954
14002
|
}
|
|
13955
14003
|
function saveCrewAgentsCoalesced(manifest, records) {
|
|
13956
14004
|
const filePath = agentsPath(manifest);
|
|
13957
14005
|
fs14.mkdirSync(manifest.stateRoot, { recursive: true });
|
|
13958
|
-
atomicWriteJsonCoalesced(filePath, redactSecrets(records), AGENT_COALESCE_MS);
|
|
14006
|
+
atomicWriteJsonCoalesced(filePath, redactSecrets(records), AGENT_COALESCE_MS, { durability: "best-effort" });
|
|
13959
14007
|
asyncAgentReaderCache.delete(filePath);
|
|
13960
14008
|
for (const record of records) writeCrewAgentStatusCoalesced(manifest, record);
|
|
13961
14009
|
}
|
|
13962
14010
|
function writeCrewAgentStatusCoalesced(manifest, record) {
|
|
13963
14011
|
ensureAgentStateDir(manifest, record.taskId);
|
|
13964
|
-
atomicWriteJsonCoalesced(agentStatusPath(manifest, record.taskId), redactSecrets(record), AGENT_COALESCE_MS
|
|
14012
|
+
atomicWriteJsonCoalesced(agentStatusPath(manifest, record.taskId), redactSecrets(record), AGENT_COALESCE_MS, {
|
|
14013
|
+
durability: "best-effort"
|
|
14014
|
+
});
|
|
13965
14015
|
}
|
|
13966
14016
|
function readCrewAgentStatus(manifest, taskOrAgentId) {
|
|
13967
14017
|
try {
|
|
@@ -15549,12 +15599,12 @@ function getProcessStartTime2(pid) {
|
|
|
15549
15599
|
} catch {
|
|
15550
15600
|
return void 0;
|
|
15551
15601
|
}
|
|
15552
|
-
const
|
|
15553
|
-
if (
|
|
15602
|
+
const platform2 = process.platform;
|
|
15603
|
+
if (platform2 === "linux") {
|
|
15554
15604
|
return getProcessStartTimeLinux(pid);
|
|
15555
|
-
} else if (
|
|
15605
|
+
} else if (platform2 === "darwin") {
|
|
15556
15606
|
return getProcessStartTimeMacOS(pid);
|
|
15557
|
-
} else if (
|
|
15607
|
+
} else if (platform2 === "win32") {
|
|
15558
15608
|
return getProcessStartTimeWindows(pid);
|
|
15559
15609
|
}
|
|
15560
15610
|
return void 0;
|
|
@@ -16440,7 +16490,9 @@ function buildPiWorkerArgs(input) {
|
|
|
16440
16490
|
PI_TEAMS_INHERIT_SKILLS: input.agent.inheritSkills ? "1" : "0",
|
|
16441
16491
|
PI_TEAMS_DEPTH: String(parentDepth + 1),
|
|
16442
16492
|
PI_TEAMS_MAX_DEPTH: String(maxDepth),
|
|
16443
|
-
PI_TEAMS_ROLE: input.agent.name
|
|
16493
|
+
PI_TEAMS_ROLE: input.agent.name,
|
|
16494
|
+
// maxTokens cap for background workers — prompt-runtime reads this to cap API output
|
|
16495
|
+
...input.agent.maxTokens ? { PI_CREW_MAX_OUTPUT: String(input.agent.maxTokens) } : {}
|
|
16444
16496
|
},
|
|
16445
16497
|
tempDir
|
|
16446
16498
|
};
|
|
@@ -18663,6 +18715,7 @@ ${JSON.stringify({ type: "message_end", usage: { input: 10, output: 5, cost: 1e-
|
|
|
18663
18715
|
skillPaths: input.skillPaths,
|
|
18664
18716
|
role: input.role
|
|
18665
18717
|
});
|
|
18718
|
+
if (input.steeringFile) built.env.PI_CREW_STEERING_FILE = input.steeringFile;
|
|
18666
18719
|
const spawnSpec = getPiSpawnCommand(built.args);
|
|
18667
18720
|
try {
|
|
18668
18721
|
return await new Promise((resolve21) => {
|
|
@@ -18714,6 +18767,7 @@ ${JSON.stringify({ type: "message_end", usage: { input: 10, output: 5, cost: 1e-
|
|
|
18714
18767
|
const finalDrainMs = input.finalDrainMs ?? FINAL_DRAIN_MS;
|
|
18715
18768
|
const hardKillMs = input.hardKillMs ?? HARD_KILL_MS;
|
|
18716
18769
|
let finalDrainArmed = false;
|
|
18770
|
+
let lastStdoutActivityMonotonicMs = performance.now();
|
|
18717
18771
|
let finalDrainFiredMonotonicMs;
|
|
18718
18772
|
const spawnMonotonicMs = performance.now();
|
|
18719
18773
|
let finalAssistantEventMonotonicMs;
|
|
@@ -18872,10 +18926,59 @@ ${JSON.stringify({ type: "message_end", usage: { input: 10, output: 5, cost: 1e-
|
|
|
18872
18926
|
completeOperation(eventOpId);
|
|
18873
18927
|
throw err2;
|
|
18874
18928
|
}
|
|
18929
|
+
lastStdoutActivityMonotonicMs = performance.now();
|
|
18875
18930
|
input.onJsonEvent?.(event);
|
|
18876
18931
|
if (!isFinalAssistantEvent(event) || childExited || settled || finalDrainTimer) return;
|
|
18877
18932
|
finalAssistantEventMonotonicMs = performance.now();
|
|
18878
18933
|
finalDrainArmed = true;
|
|
18934
|
+
const quietMs = input.finalDrainQuietMs ?? DEFAULT_CHILD_PI.finalDrainQuietMs;
|
|
18935
|
+
if (quietMs < (input.finalDrainMs ?? DEFAULT_CHILD_PI.finalDrainMs)) {
|
|
18936
|
+
const pollHandle = setInterval(() => {
|
|
18937
|
+
if (settled || childExited) {
|
|
18938
|
+
clearInterval(pollHandle);
|
|
18939
|
+
pollHandle.unref();
|
|
18940
|
+
return;
|
|
18941
|
+
}
|
|
18942
|
+
const sinceLast = performance.now() - lastStdoutActivityMonotonicMs;
|
|
18943
|
+
if (sinceLast >= quietMs) {
|
|
18944
|
+
clearInterval(pollHandle);
|
|
18945
|
+
pollHandle.unref();
|
|
18946
|
+
forcedFinalDrain = true;
|
|
18947
|
+
finalDrainFiredMonotonicMs = performance.now();
|
|
18948
|
+
input.onLifecycleEvent?.({
|
|
18949
|
+
type: "final_drain",
|
|
18950
|
+
pid: child.pid,
|
|
18951
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18952
|
+
reason: "stdout-quiet"
|
|
18953
|
+
});
|
|
18954
|
+
try {
|
|
18955
|
+
child.kill(process.platform === "win32" ? void 0 : "SIGTERM");
|
|
18956
|
+
} catch (error) {
|
|
18957
|
+
logInternalError("child-pi.quiet-drain-term", error, `pid=${child.pid}`);
|
|
18958
|
+
}
|
|
18959
|
+
hardKillTimer = setTimeout(() => {
|
|
18960
|
+
if (settled || childExited) return;
|
|
18961
|
+
try {
|
|
18962
|
+
hardKilled = true;
|
|
18963
|
+
input.onLifecycleEvent?.({
|
|
18964
|
+
type: "hard_kill",
|
|
18965
|
+
pid: child.pid,
|
|
18966
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
18967
|
+
});
|
|
18968
|
+
child.kill(process.platform === "win32" ? void 0 : "SIGKILL");
|
|
18969
|
+
} catch (error) {
|
|
18970
|
+
logInternalError("child-pi.quiet-drain-hard-kill", error, `pid=${child.pid}`);
|
|
18971
|
+
}
|
|
18972
|
+
}, hardKillMs);
|
|
18973
|
+
hardKillTimer.unref();
|
|
18974
|
+
if (finalDrainTimer) {
|
|
18975
|
+
clearTimeout(finalDrainTimer);
|
|
18976
|
+
finalDrainTimer = void 0;
|
|
18977
|
+
}
|
|
18978
|
+
}
|
|
18979
|
+
}, 200);
|
|
18980
|
+
pollHandle.unref();
|
|
18981
|
+
}
|
|
18879
18982
|
finalDrainTimer = setTimeout(() => {
|
|
18880
18983
|
if (settled || childExited) return;
|
|
18881
18984
|
forcedFinalDrain = true;
|
|
@@ -19199,6 +19302,15 @@ var init_child_pi = __esm({
|
|
|
19199
19302
|
MAX_COMPACT_CONTENT_CHARS = DEFAULT_CHILD_PI.maxCompactContentChars;
|
|
19200
19303
|
activeChildProcesses = /* @__PURE__ */ new Map();
|
|
19201
19304
|
childHardKillTimers = /* @__PURE__ */ new Map();
|
|
19305
|
+
setInterval(() => {
|
|
19306
|
+
for (const [pid, child] of activeChildProcesses) {
|
|
19307
|
+
try {
|
|
19308
|
+
process.kill(pid, 0);
|
|
19309
|
+
} catch {
|
|
19310
|
+
activeChildProcesses.delete(pid);
|
|
19311
|
+
}
|
|
19312
|
+
}
|
|
19313
|
+
}, 6e4).unref();
|
|
19202
19314
|
BASE_ALLOWLIST = [
|
|
19203
19315
|
"PATH",
|
|
19204
19316
|
"HOME",
|
|
@@ -19239,22 +19351,29 @@ var init_child_pi = __esm({
|
|
|
19239
19351
|
"PI_TEAMS_INHERIT_SKILLS",
|
|
19240
19352
|
"PI_TEAMS_PI_BIN",
|
|
19241
19353
|
"PI_TEAMS_MOCK_CHILD_PI",
|
|
19242
|
-
"PI_CREW_ALLOW_MOCK"
|
|
19354
|
+
"PI_CREW_ALLOW_MOCK",
|
|
19355
|
+
"PI_CREW_MAX_OUTPUT",
|
|
19356
|
+
"PI_CREW_STEERING_FILE"
|
|
19243
19357
|
];
|
|
19244
|
-
ChildPiLineObserver = class {
|
|
19358
|
+
ChildPiLineObserver = class _ChildPiLineObserver {
|
|
19245
19359
|
buffer = "";
|
|
19246
19360
|
input;
|
|
19247
|
-
/** RAW
|
|
19248
|
-
*
|
|
19249
|
-
*
|
|
19250
|
-
*
|
|
19251
|
-
*
|
|
19361
|
+
/** F9: bounded ring buffer for RAW assistant-text fragments. Consumers
|
|
19362
|
+
* (getRawFinalText) only read the last element, but the legacy implementation
|
|
19363
|
+
* accumulated every fragment unconditionally, which let a verbose/long-running
|
|
19364
|
+
* worker grow this array linearly with output. We retain the last 2 entries:
|
|
19365
|
+
* the consumer needs the last; we keep the second-to-last only as a defensive
|
|
19366
|
+
* fence against a race where a final event arrives just after the consumer
|
|
19367
|
+
* read (the previous "last" is still the most-recent pre-final text in that
|
|
19368
|
+
* window). 2 is well below any plausible consumer's "tail-only" need while
|
|
19369
|
+
* bounding memory. */
|
|
19370
|
+
static MAX_RAW_TEXT_EVENTS = 2;
|
|
19252
19371
|
rawTextEvents = [];
|
|
19253
|
-
/**
|
|
19254
|
-
*
|
|
19255
|
-
*
|
|
19256
|
-
*
|
|
19257
|
-
|
|
19372
|
+
/** F9: bounded ring buffer for intermediate findings. The downstream digest
|
|
19373
|
+
* (getIntermediateFindings) slices the last 20, but the array previously grew
|
|
19374
|
+
* to 1000s of entries. We keep MAX_INTERMEDIATE_DIGEST_LINES + headroom so
|
|
19375
|
+
* the public API behaviour is preserved (still returns "last 20 lines"). */
|
|
19376
|
+
static MAX_INTERMEDIATE_FINDINGS = 32;
|
|
19258
19377
|
intermediateFindings = [];
|
|
19259
19378
|
constructor(input) {
|
|
19260
19379
|
this.input = input;
|
|
@@ -19298,9 +19417,13 @@ var init_child_pi = __esm({
|
|
|
19298
19417
|
const rawTexts = extractText(rawParsed);
|
|
19299
19418
|
if (rawTexts.length > 0) {
|
|
19300
19419
|
this.rawTextEvents.push(...rawTexts);
|
|
19420
|
+
const rawOverflow = this.rawTextEvents.length - _ChildPiLineObserver.MAX_RAW_TEXT_EVENTS;
|
|
19421
|
+
if (rawOverflow > 0) this.rawTextEvents.splice(0, rawOverflow);
|
|
19301
19422
|
const last = rawTexts[rawTexts.length - 1];
|
|
19302
19423
|
if (last.trim().length > 0) {
|
|
19303
19424
|
this.intermediateFindings.push(last.trim());
|
|
19425
|
+
const findingsOverflow = this.intermediateFindings.length - _ChildPiLineObserver.MAX_INTERMEDIATE_FINDINGS;
|
|
19426
|
+
if (findingsOverflow > 0) this.intermediateFindings.splice(0, findingsOverflow);
|
|
19304
19427
|
}
|
|
19305
19428
|
}
|
|
19306
19429
|
} catch {
|
|
@@ -19321,6 +19444,8 @@ var init_child_pi = __esm({
|
|
|
19321
19444
|
logInternalError("child-pi.on-stdout-line", error, `line=${compact.displayLine}`);
|
|
19322
19445
|
}
|
|
19323
19446
|
this.intermediateFindings.push(compact.displayLine.trim());
|
|
19447
|
+
const findingsOverflow = this.intermediateFindings.length - _ChildPiLineObserver.MAX_INTERMEDIATE_FINDINGS;
|
|
19448
|
+
if (findingsOverflow > 0) this.intermediateFindings.splice(0, findingsOverflow);
|
|
19324
19449
|
}
|
|
19325
19450
|
}
|
|
19326
19451
|
};
|
|
@@ -19970,15 +20095,56 @@ function parseDynamicWorkflowFile(filePath, source) {
|
|
|
19970
20095
|
return void 0;
|
|
19971
20096
|
}
|
|
19972
20097
|
}
|
|
20098
|
+
function workflowDirStamp(cwd) {
|
|
20099
|
+
const dirs = [
|
|
20100
|
+
path26.join(packageRoot(), "workflows"),
|
|
20101
|
+
path26.join(userPiRoot(), "workflows"),
|
|
20102
|
+
path26.join(projectCrewRoot(cwd), "workflows")
|
|
20103
|
+
];
|
|
20104
|
+
let out = "";
|
|
20105
|
+
for (const d of dirs) {
|
|
20106
|
+
try {
|
|
20107
|
+
const st = fs30.statSync(d);
|
|
20108
|
+
out += `${st.mtimeMs}|`;
|
|
20109
|
+
} catch {
|
|
20110
|
+
out += "0|";
|
|
20111
|
+
}
|
|
20112
|
+
}
|
|
20113
|
+
return out;
|
|
20114
|
+
}
|
|
20115
|
+
function invalidateWorkflowDiscoveryCache(cwd) {
|
|
20116
|
+
if (cwd) {
|
|
20117
|
+
workflowCache.delete(cwd);
|
|
20118
|
+
} else {
|
|
20119
|
+
workflowCache.clear();
|
|
20120
|
+
}
|
|
20121
|
+
}
|
|
19973
20122
|
function discoverWorkflows(cwd) {
|
|
19974
20123
|
if (!cwd || typeof cwd !== "string") {
|
|
19975
20124
|
return { builtin: [], user: [], project: [] };
|
|
19976
20125
|
}
|
|
19977
|
-
|
|
20126
|
+
const now = Date.now();
|
|
20127
|
+
const stamp = workflowDirStamp(cwd);
|
|
20128
|
+
const cached = workflowCache.get(cwd);
|
|
20129
|
+
if (cached && cached.expiresAt > now && cached.dirStamp === stamp) {
|
|
20130
|
+
return cached.result;
|
|
20131
|
+
}
|
|
20132
|
+
const result4 = {
|
|
19978
20133
|
builtin: readWorkflowDir(path26.join(packageRoot(), "workflows"), "builtin"),
|
|
19979
20134
|
user: readWorkflowDir(path26.join(userPiRoot(), "workflows"), "user"),
|
|
19980
20135
|
project: readWorkflowDir(path26.join(projectCrewRoot(cwd), "workflows"), "project")
|
|
19981
20136
|
};
|
|
20137
|
+
workflowCache.set(cwd, {
|
|
20138
|
+
result: result4,
|
|
20139
|
+
expiresAt: now + WORKFLOW_DISCOVERY_TTL_MS,
|
|
20140
|
+
dirStamp: stamp
|
|
20141
|
+
});
|
|
20142
|
+
while (workflowCache.size > WORKFLOW_DISCOVERY_MAX_ENTRIES) {
|
|
20143
|
+
const oldest = workflowCache.keys().next().value;
|
|
20144
|
+
if (oldest === void 0) break;
|
|
20145
|
+
workflowCache.delete(oldest);
|
|
20146
|
+
}
|
|
20147
|
+
return result4;
|
|
19982
20148
|
}
|
|
19983
20149
|
function allWorkflows(discovery) {
|
|
19984
20150
|
if (!discovery) return [];
|
|
@@ -19988,7 +20154,7 @@ function allWorkflows(discovery) {
|
|
|
19988
20154
|
}
|
|
19989
20155
|
return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
19990
20156
|
}
|
|
19991
|
-
var STEP_CONFIG_KEYS, parseOptionalInteger, parseOptionalBoolean, parseTopology;
|
|
20157
|
+
var STEP_CONFIG_KEYS, parseOptionalInteger, parseOptionalBoolean, parseTopology, WORKFLOW_DISCOVERY_TTL_MS, WORKFLOW_DISCOVERY_MAX_ENTRIES, workflowCache;
|
|
19992
20158
|
var init_discover_workflows = __esm({
|
|
19993
20159
|
"src/workflows/discover-workflows.ts"() {
|
|
19994
20160
|
"use strict";
|
|
@@ -20033,6 +20199,9 @@ var init_discover_workflows = __esm({
|
|
|
20033
20199
|
}
|
|
20034
20200
|
return void 0;
|
|
20035
20201
|
};
|
|
20202
|
+
WORKFLOW_DISCOVERY_TTL_MS = 5e3;
|
|
20203
|
+
WORKFLOW_DISCOVERY_MAX_ENTRIES = 32;
|
|
20204
|
+
workflowCache = /* @__PURE__ */ new Map();
|
|
20036
20205
|
}
|
|
20037
20206
|
});
|
|
20038
20207
|
|
|
@@ -21993,6 +22162,10 @@ function parseAgentFile(filePath, source) {
|
|
|
21993
22162
|
const n = Number.parseInt(frontmatter.maxTurns, 10);
|
|
21994
22163
|
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
21995
22164
|
})(),
|
|
22165
|
+
maxTokens: (() => {
|
|
22166
|
+
const n = Number.parseInt(frontmatter.maxTokens, 10);
|
|
22167
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
22168
|
+
})(),
|
|
21996
22169
|
effort: frontmatter.effort === "low" || frontmatter.effort === "medium" || frontmatter.effort === "high" ? frontmatter.effort : void 0,
|
|
21997
22170
|
disabled: frontmatter.disabled === "true" || frontmatter.enabled === "false",
|
|
21998
22171
|
routing: triggers || useWhen || avoidWhen || cost || category ? { triggers, useWhen, avoidWhen, cost, category } : void 0
|
|
@@ -22165,7 +22338,7 @@ var init_discover_agents = __esm({
|
|
|
22165
22338
|
MAX_SECURITY_LOG_ENTRIES = 1e3;
|
|
22166
22339
|
securityEventLog = [];
|
|
22167
22340
|
warnedForkAgents = /* @__PURE__ */ new Set();
|
|
22168
|
-
DISCOVERY_CACHE_TTL_MS =
|
|
22341
|
+
DISCOVERY_CACHE_TTL_MS = 5e3;
|
|
22169
22342
|
discoveryCache = /* @__PURE__ */ new Map();
|
|
22170
22343
|
DISCOVERY_CACHE_MAX_ENTRIES = 32;
|
|
22171
22344
|
dynamicAgents = /* @__PURE__ */ new Map();
|
|
@@ -22362,7 +22535,8 @@ var init_git = __esm({
|
|
|
22362
22535
|
var discover_teams_exports = {};
|
|
22363
22536
|
__export(discover_teams_exports, {
|
|
22364
22537
|
allTeams: () => allTeams,
|
|
22365
|
-
discoverTeams: () => discoverTeams
|
|
22538
|
+
discoverTeams: () => discoverTeams,
|
|
22539
|
+
invalidateTeamDiscoveryCache: () => invalidateTeamDiscoveryCache
|
|
22366
22540
|
});
|
|
22367
22541
|
import * as fs34 from "node:fs";
|
|
22368
22542
|
import * as path29 from "node:path";
|
|
@@ -22446,12 +22620,48 @@ function readTeamDir(dir, source) {
|
|
|
22446
22620
|
if (!fs34.existsSync(dir)) return [];
|
|
22447
22621
|
return fs34.readdirSync(dir).filter((entry) => entry.endsWith(".team.md")).map((entry) => parseTeamFile(path29.join(dir, entry), source)).filter((team) => team !== void 0).sort((a, b) => a.name.localeCompare(b.name));
|
|
22448
22622
|
}
|
|
22623
|
+
function teamDirStamp(cwd) {
|
|
22624
|
+
const dirs = [path29.join(packageRoot(), "teams"), path29.join(userPiRoot(), "teams"), path29.join(projectCrewRoot(cwd), "teams")];
|
|
22625
|
+
let out = "";
|
|
22626
|
+
for (const d of dirs) {
|
|
22627
|
+
try {
|
|
22628
|
+
out += `${fs34.statSync(d).mtimeMs}|`;
|
|
22629
|
+
} catch {
|
|
22630
|
+
out += "0|";
|
|
22631
|
+
}
|
|
22632
|
+
}
|
|
22633
|
+
return out;
|
|
22634
|
+
}
|
|
22635
|
+
function invalidateTeamDiscoveryCache(cwd) {
|
|
22636
|
+
if (cwd) {
|
|
22637
|
+
teamCache.delete(cwd);
|
|
22638
|
+
} else {
|
|
22639
|
+
teamCache.clear();
|
|
22640
|
+
}
|
|
22641
|
+
}
|
|
22449
22642
|
function discoverTeams(cwd) {
|
|
22450
|
-
|
|
22643
|
+
const now = Date.now();
|
|
22644
|
+
const stamp = teamDirStamp(cwd);
|
|
22645
|
+
const cached = teamCache.get(cwd);
|
|
22646
|
+
if (cached && cached.expiresAt > now && cached.dirStamp === stamp) {
|
|
22647
|
+
return cached.result;
|
|
22648
|
+
}
|
|
22649
|
+
const result4 = {
|
|
22451
22650
|
builtin: readTeamDir(path29.join(packageRoot(), "teams"), "builtin"),
|
|
22452
22651
|
user: readTeamDir(path29.join(userPiRoot(), "teams"), "user"),
|
|
22453
22652
|
project: readTeamDir(path29.join(projectCrewRoot(cwd), "teams"), "project")
|
|
22454
22653
|
};
|
|
22654
|
+
teamCache.set(cwd, {
|
|
22655
|
+
result: result4,
|
|
22656
|
+
expiresAt: now + TEAM_DISCOVERY_TTL_MS,
|
|
22657
|
+
dirStamp: stamp
|
|
22658
|
+
});
|
|
22659
|
+
while (teamCache.size > TEAM_DISCOVERY_MAX_ENTRIES) {
|
|
22660
|
+
const oldest = teamCache.keys().next().value;
|
|
22661
|
+
if (oldest === void 0) break;
|
|
22662
|
+
teamCache.delete(oldest);
|
|
22663
|
+
}
|
|
22664
|
+
return result4;
|
|
22455
22665
|
}
|
|
22456
22666
|
function allTeams(discovery) {
|
|
22457
22667
|
if (!discovery) return [];
|
|
@@ -22461,12 +22671,16 @@ function allTeams(discovery) {
|
|
|
22461
22671
|
}
|
|
22462
22672
|
return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
22463
22673
|
}
|
|
22674
|
+
var TEAM_DISCOVERY_TTL_MS, TEAM_DISCOVERY_MAX_ENTRIES, teamCache;
|
|
22464
22675
|
var init_discover_teams = __esm({
|
|
22465
22676
|
"src/teams/discover-teams.ts"() {
|
|
22466
22677
|
"use strict";
|
|
22467
22678
|
init_frontmatter();
|
|
22468
22679
|
init_git();
|
|
22469
22680
|
init_paths();
|
|
22681
|
+
TEAM_DISCOVERY_TTL_MS = 5e3;
|
|
22682
|
+
TEAM_DISCOVERY_MAX_ENTRIES = 32;
|
|
22683
|
+
teamCache = /* @__PURE__ */ new Map();
|
|
22470
22684
|
}
|
|
22471
22685
|
});
|
|
22472
22686
|
|
|
@@ -23615,7 +23829,7 @@ function readDeliveryState(manifest) {
|
|
|
23615
23829
|
return { messages: {}, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
23616
23830
|
}
|
|
23617
23831
|
}
|
|
23618
|
-
function writeDeliveryState(manifest, state) {
|
|
23832
|
+
function writeDeliveryState(manifest, state, options) {
|
|
23619
23833
|
ensureRunMailbox(manifest);
|
|
23620
23834
|
const MAX_DELIVERY_MESSAGES = 1e4;
|
|
23621
23835
|
if (Object.keys(state.messages).length > MAX_DELIVERY_MESSAGES) {
|
|
@@ -23627,7 +23841,9 @@ function writeDeliveryState(manifest, state) {
|
|
|
23627
23841
|
state.messages = Object.fromEntries(trimmed);
|
|
23628
23842
|
}
|
|
23629
23843
|
atomicWriteFile(deliveryFile(manifest, true), `${JSON.stringify(redactSecrets(state), null, 2)}
|
|
23630
|
-
|
|
23844
|
+
`, {
|
|
23845
|
+
durability: options?.durability ?? "best-effort"
|
|
23846
|
+
});
|
|
23631
23847
|
}
|
|
23632
23848
|
function appendMailboxMessage(manifest, message) {
|
|
23633
23849
|
if (message.taskId) ensureTaskMailbox(manifest, message.taskId);
|
|
@@ -23666,7 +23882,7 @@ function appendMailboxMessage(manifest, message) {
|
|
|
23666
23882
|
const delivery = readDeliveryState(manifest);
|
|
23667
23883
|
delivery.messages[complete.id] = complete.status;
|
|
23668
23884
|
delivery.updatedAt = createdAt;
|
|
23669
|
-
writeDeliveryState(manifest, delivery);
|
|
23885
|
+
writeDeliveryState(manifest, delivery, { durability: "full" });
|
|
23670
23886
|
});
|
|
23671
23887
|
return complete;
|
|
23672
23888
|
}
|
|
@@ -23710,7 +23926,7 @@ function acknowledgeMailboxMessage(manifest, messageId) {
|
|
|
23710
23926
|
if (!delivery.messages[messageId]) throw new Error(`Mailbox message '${messageId}' not found.`);
|
|
23711
23927
|
delivery.messages[messageId] = "acknowledged";
|
|
23712
23928
|
delivery.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
23713
|
-
writeDeliveryState(manifest, delivery);
|
|
23929
|
+
writeDeliveryState(manifest, delivery, { durability: "full" });
|
|
23714
23930
|
return delivery;
|
|
23715
23931
|
});
|
|
23716
23932
|
}
|
|
@@ -24164,6 +24380,11 @@ var init_intent_policy = __esm({
|
|
|
24164
24380
|
import * as crypto3 from "node:crypto";
|
|
24165
24381
|
import * as fs38 from "node:fs";
|
|
24166
24382
|
import * as path33 from "node:path";
|
|
24383
|
+
function invalidateResourceCaches() {
|
|
24384
|
+
invalidateAgentDiscoveryCache();
|
|
24385
|
+
invalidateTeamDiscoveryCache();
|
|
24386
|
+
invalidateWorkflowDiscoveryCache();
|
|
24387
|
+
}
|
|
24167
24388
|
function result2(text, status = "ok", isError = false) {
|
|
24168
24389
|
return toolResult(text, { action: "management", status }, isError);
|
|
24169
24390
|
}
|
|
@@ -24461,6 +24682,7 @@ ${content}`);
|
|
|
24461
24682
|
true
|
|
24462
24683
|
);
|
|
24463
24684
|
}
|
|
24685
|
+
invalidateResourceCaches();
|
|
24464
24686
|
return result2(`Created ${params.resource} '${name}' at ${filePath}.`);
|
|
24465
24687
|
}
|
|
24466
24688
|
function handleUpdate(params, ctx) {
|
|
@@ -24565,6 +24787,7 @@ function handleUpdate(params, ctx) {
|
|
|
24565
24787
|
);
|
|
24566
24788
|
}
|
|
24567
24789
|
const updatedRefs = params.updateReferences ? updateReferencesForRename(ctx, params.resource, current2.name, nextName, source, false) : [];
|
|
24790
|
+
invalidateResourceCaches();
|
|
24568
24791
|
return result2(
|
|
24569
24792
|
[
|
|
24570
24793
|
`Updated ${params.resource} at ${nextPath}. Backup: ${backupPath}.`,
|
|
@@ -24603,6 +24826,7 @@ ${refs.map((ref2) => `- ${ref2}`).join("\n")}` : ""}`
|
|
|
24603
24826
|
true
|
|
24604
24827
|
);
|
|
24605
24828
|
}
|
|
24829
|
+
invalidateResourceCaches();
|
|
24606
24830
|
return result2(`Deleted ${params.resource} at ${resolved.resource.filePath}. Backup: ${backupPath}.`);
|
|
24607
24831
|
}
|
|
24608
24832
|
var init_management = __esm({
|
|
@@ -24658,18 +24882,18 @@ function initializeProject(cwd, options = {}) {
|
|
|
24658
24882
|
const teamsDir = path34.join(crewRoot, "teams");
|
|
24659
24883
|
const workflowsDir = path34.join(crewRoot, "workflows");
|
|
24660
24884
|
const configScope = options.configScope ?? "global";
|
|
24661
|
-
const
|
|
24885
|
+
const configPath3 = configScope === "project" ? path34.join(projectPiRoot(cwd), "pi-crew.json") : configScope === "global" ? configPath() : "";
|
|
24662
24886
|
ensureDir(agentsDir, createdDirs);
|
|
24663
24887
|
ensureDir(teamsDir, createdDirs);
|
|
24664
24888
|
ensureDir(workflowsDir, createdDirs);
|
|
24665
24889
|
ensureDir(path34.join(crewRoot, "imports"), createdDirs);
|
|
24666
24890
|
let configCreated = false;
|
|
24667
24891
|
let configSkipped = false;
|
|
24668
|
-
if (
|
|
24669
|
-
if (configScope === "project") ensureDir(path34.dirname(
|
|
24670
|
-
else fs39.mkdirSync(path34.dirname(
|
|
24671
|
-
if (!fs39.existsSync(
|
|
24672
|
-
fs39.writeFileSync(
|
|
24892
|
+
if (configPath3) {
|
|
24893
|
+
if (configScope === "project") ensureDir(path34.dirname(configPath3), createdDirs);
|
|
24894
|
+
else fs39.mkdirSync(path34.dirname(configPath3), { recursive: true });
|
|
24895
|
+
if (!fs39.existsSync(configPath3) || options.overwrite === true) {
|
|
24896
|
+
fs39.writeFileSync(configPath3, `${JSON.stringify(DEFAULT_PI_CREW_CONFIG, null, 2)}
|
|
24673
24897
|
`, "utf-8");
|
|
24674
24898
|
configCreated = true;
|
|
24675
24899
|
} else {
|
|
@@ -24708,7 +24932,7 @@ ${missing.join("\n")}
|
|
|
24708
24932
|
skippedFiles,
|
|
24709
24933
|
gitignorePath,
|
|
24710
24934
|
gitignoreUpdated,
|
|
24711
|
-
configPath:
|
|
24935
|
+
configPath: configPath3,
|
|
24712
24936
|
configScope,
|
|
24713
24937
|
configCreated,
|
|
24714
24938
|
configSkipped
|
|
@@ -44086,7 +44310,7 @@ var init_crew_hooks = __esm({
|
|
|
44086
44310
|
});
|
|
44087
44311
|
|
|
44088
44312
|
// src/runtime/skill-effectiveness.ts
|
|
44089
|
-
import { existsSync as existsSync38, mkdirSync as mkdirSync26, readFileSync as
|
|
44313
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync26, readFileSync as readFileSync41, writeFileSync as writeFileSync18 } from "fs";
|
|
44090
44314
|
import { dirname as dirname24, join as join43 } from "path";
|
|
44091
44315
|
function getSkillMetricsPath(cwd, runId) {
|
|
44092
44316
|
return join43(projectCrewRoot(cwd), `state/runs/${runId}/skill-metrics.jsonl`);
|
|
@@ -44149,7 +44373,7 @@ function getSkillActivations(cwd, runId) {
|
|
|
44149
44373
|
if (!existsSync38(path81)) {
|
|
44150
44374
|
return [];
|
|
44151
44375
|
}
|
|
44152
|
-
const content =
|
|
44376
|
+
const content = readFileSync41(path81, "utf-8");
|
|
44153
44377
|
if (!content.trim()) {
|
|
44154
44378
|
return [];
|
|
44155
44379
|
}
|
|
@@ -47311,7 +47535,7 @@ var init_explain = __esm({
|
|
|
47311
47535
|
});
|
|
47312
47536
|
|
|
47313
47537
|
// src/runtime/goal-state-store.ts
|
|
47314
|
-
import { closeSync as closeSync13, existsSync as existsSync45, mkdirSync as mkdirSync29, openSync as openSync13, readdirSync as readdirSync23, readFileSync as
|
|
47538
|
+
import { closeSync as closeSync13, existsSync as existsSync45, mkdirSync as mkdirSync29, openSync as openSync13, readdirSync as readdirSync23, readFileSync as readFileSync47, statSync as statSync31, unlinkSync as unlinkSync9 } from "node:fs";
|
|
47315
47539
|
import { dirname as dirname26 } from "node:path";
|
|
47316
47540
|
function resolveGoalsRoot(cwd) {
|
|
47317
47541
|
const crewRoot = projectCrewRoot(cwd) ?? userCrewRoot();
|
|
@@ -47345,7 +47569,7 @@ var init_goal_state_store = __esm({
|
|
|
47345
47569
|
const path81 = goalFilePath(this.cwd, goalId);
|
|
47346
47570
|
try {
|
|
47347
47571
|
if (!existsSync45(path81)) return void 0;
|
|
47348
|
-
const raw =
|
|
47572
|
+
const raw = readFileSync47(path81, "utf-8");
|
|
47349
47573
|
const parsed = JSON.parse(raw);
|
|
47350
47574
|
if (!parsed || typeof parsed !== "object" || typeof parsed.goalId !== "string") return void 0;
|
|
47351
47575
|
return parsed;
|
|
@@ -47442,7 +47666,7 @@ var init_goal_state_store = __esm({
|
|
|
47442
47666
|
const code = error.code;
|
|
47443
47667
|
if (code !== "EEXIST") return false;
|
|
47444
47668
|
try {
|
|
47445
|
-
const stat2 =
|
|
47669
|
+
const stat2 = statSync31(lockPath2);
|
|
47446
47670
|
if (Date.now() - stat2.mtimeMs > 5e3) {
|
|
47447
47671
|
unlinkSync9(lockPath2);
|
|
47448
47672
|
const fd = openSync13(lockPath2, "wx");
|
|
@@ -47533,7 +47757,7 @@ var init_verification_integrity = __esm({
|
|
|
47533
47757
|
|
|
47534
47758
|
// src/runtime/workspace-lock.ts
|
|
47535
47759
|
import { createHash as createHash7 } from "node:crypto";
|
|
47536
|
-
import { closeSync as closeSync14, existsSync as existsSync46, mkdirSync as mkdirSync30, openSync as openSync14, readdirSync as readdirSync24, readFileSync as
|
|
47760
|
+
import { closeSync as closeSync14, existsSync as existsSync46, mkdirSync as mkdirSync30, openSync as openSync14, readdirSync as readdirSync24, readFileSync as readFileSync49, statSync as statSync33, unlinkSync as unlinkSync10, writeFileSync as writeFileSync23 } from "node:fs";
|
|
47537
47761
|
import * as path51 from "node:path";
|
|
47538
47762
|
function workspaceLockPath(cwd) {
|
|
47539
47763
|
const absCwd = path51.resolve(cwd);
|
|
@@ -47545,7 +47769,7 @@ function workspaceLockPath(cwd) {
|
|
|
47545
47769
|
function readLock(lockPath2) {
|
|
47546
47770
|
if (!existsSync46(lockPath2)) return void 0;
|
|
47547
47771
|
try {
|
|
47548
|
-
const parsed = JSON.parse(
|
|
47772
|
+
const parsed = JSON.parse(readFileSync49(lockPath2, "utf-8"));
|
|
47549
47773
|
if (!parsed || typeof parsed !== "object") return void 0;
|
|
47550
47774
|
return parsed;
|
|
47551
47775
|
} catch {
|
|
@@ -47584,7 +47808,7 @@ var init_workspace_lock = __esm({
|
|
|
47584
47808
|
DEFAULT_HEARTBEAT_STALE_MS = 6e4;
|
|
47585
47809
|
defaultStartTimeResolver = (pid) => {
|
|
47586
47810
|
try {
|
|
47587
|
-
const stat2 =
|
|
47811
|
+
const stat2 = readFileSync49(`/proc/${pid}/stat`, "utf-8");
|
|
47588
47812
|
const lastParen = stat2.lastIndexOf(")");
|
|
47589
47813
|
if (lastParen === -1) return void 0;
|
|
47590
47814
|
const fieldsAfterComm = stat2.slice(lastParen + 1).trim().split(/\s+/);
|
|
@@ -51508,7 +51732,7 @@ var init_tool_progress_formatter = __esm({
|
|
|
51508
51732
|
});
|
|
51509
51733
|
|
|
51510
51734
|
// src/extension/registration/team-tool.ts
|
|
51511
|
-
import { statSync as
|
|
51735
|
+
import { statSync as statSync36 } from "node:fs";
|
|
51512
51736
|
import { Text as Text4 } from "@earendil-works/pi-tui";
|
|
51513
51737
|
async function handleTeamTool(params, ctx) {
|
|
51514
51738
|
if (!_cachedHandleTeamTool) {
|
|
@@ -51521,7 +51745,7 @@ function resolveCwdOverride(baseCwd, override) {
|
|
|
51521
51745
|
if (!override) return { ok: true, cwd: baseCwd };
|
|
51522
51746
|
try {
|
|
51523
51747
|
const resolved = resolveRealContainedPath(baseCwd, override);
|
|
51524
|
-
const stat2 =
|
|
51748
|
+
const stat2 = statSync36(resolved);
|
|
51525
51749
|
if (!stat2.isDirectory())
|
|
51526
51750
|
return {
|
|
51527
51751
|
ok: false,
|
|
@@ -52795,7 +53019,7 @@ var init_status = __esm({
|
|
|
52795
53019
|
});
|
|
52796
53020
|
|
|
52797
53021
|
// src/extension/team-tool/workflow-manage.ts
|
|
52798
|
-
import { existsSync as existsSync58, readFileSync as
|
|
53022
|
+
import { existsSync as existsSync58, readFileSync as readFileSync58, rmSync as rmSync16, writeFileSync as writeFileSync26 } from "node:fs";
|
|
52799
53023
|
import { dirname as dirname33, join as join59 } from "node:path";
|
|
52800
53024
|
function allowedWorkflowDirs(cwd) {
|
|
52801
53025
|
return [join59(projectCrewRoot(cwd), "workflows"), join59(userPiRoot(), "workflows"), join59(packageRoot(), "workflows")];
|
|
@@ -52867,7 +53091,7 @@ function handleWorkflowGet(params, ctx) {
|
|
|
52867
53091
|
let source = "(static workflow \u2014 no script source)";
|
|
52868
53092
|
if (isDynamic && wf.filePath && existsSync58(wf.filePath)) {
|
|
52869
53093
|
try {
|
|
52870
|
-
source =
|
|
53094
|
+
source = readFileSync58(wf.filePath, "utf-8").slice(0, 8e3);
|
|
52871
53095
|
} catch (error) {
|
|
52872
53096
|
logInternalError("workflow-manage.get", error, `filePath=${wf.filePath}`);
|
|
52873
53097
|
}
|
|
@@ -54413,7 +54637,7 @@ function asError(error) {
|
|
|
54413
54637
|
return error instanceof Error ? error : new Error(String(error));
|
|
54414
54638
|
}
|
|
54415
54639
|
function globToRegex(pattern) {
|
|
54416
|
-
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
54640
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
54417
54641
|
return new RegExp(`^${escaped}$`, "i");
|
|
54418
54642
|
}
|
|
54419
54643
|
function isRetryable(error, policy) {
|
|
@@ -56385,6 +56609,10 @@ function readKnowledge(cwd, query) {
|
|
|
56385
56609
|
knowledgeCache.delete(p);
|
|
56386
56610
|
return "";
|
|
56387
56611
|
}
|
|
56612
|
+
if (stat2.isSymbolicLink) {
|
|
56613
|
+
logInternalError("knowledge-injection.symlink", new Error(`Refusing to read symlink: ${p}`));
|
|
56614
|
+
return "";
|
|
56615
|
+
}
|
|
56388
56616
|
const cacheKey2 = `${stat2.mtimeMs}:${stat2.size}`;
|
|
56389
56617
|
if (!query || !query.goal && !query.taskText) {
|
|
56390
56618
|
const cached = knowledgeCache.get(p);
|
|
@@ -56434,8 +56662,8 @@ Full file: ${p} -->`
|
|
|
56434
56662
|
}
|
|
56435
56663
|
function tryStat(p) {
|
|
56436
56664
|
try {
|
|
56437
|
-
const s = fs77.
|
|
56438
|
-
return { mtimeMs: s.mtimeMs, size: s.size };
|
|
56665
|
+
const s = fs77.lstatSync(p);
|
|
56666
|
+
return { mtimeMs: s.mtimeMs, size: s.size, isSymbolicLink: s.isSymbolicLink() };
|
|
56439
56667
|
} catch {
|
|
56440
56668
|
return void 0;
|
|
56441
56669
|
}
|
|
@@ -56466,6 +56694,7 @@ var KNOWLEDGE_FILENAME, MAX_SESSION_LOG_BYTES, CONVENTION_HEADERS, STOPWORDS, kn
|
|
|
56466
56694
|
var init_knowledge_injection = __esm({
|
|
56467
56695
|
"src/extension/knowledge-injection.ts"() {
|
|
56468
56696
|
"use strict";
|
|
56697
|
+
init_internal_error();
|
|
56469
56698
|
init_paths();
|
|
56470
56699
|
KNOWLEDGE_FILENAME = "knowledge.md";
|
|
56471
56700
|
MAX_SESSION_LOG_BYTES = 5e3;
|
|
@@ -57087,32 +57316,12 @@ function persistSingleTaskUpdate(manifest, fallbackTasks, updated, checkpointPha
|
|
|
57087
57316
|
try {
|
|
57088
57317
|
currentMtime = fs80.statSync(manifest.tasksPath).mtimeMs;
|
|
57089
57318
|
} catch {
|
|
57090
|
-
|
|
57319
|
+
return fallbackTasks;
|
|
57091
57320
|
}
|
|
57092
57321
|
if (currentMtime !== baseMtime) {
|
|
57093
57322
|
baseMtime = currentMtime;
|
|
57094
57323
|
continue;
|
|
57095
57324
|
}
|
|
57096
|
-
let recheckMtime;
|
|
57097
|
-
try {
|
|
57098
|
-
recheckMtime = fs80.statSync(manifest.tasksPath).mtimeMs;
|
|
57099
|
-
} catch {
|
|
57100
|
-
return fallbackTasks;
|
|
57101
|
-
}
|
|
57102
|
-
if (recheckMtime !== baseMtime) {
|
|
57103
|
-
baseMtime = recheckMtime;
|
|
57104
|
-
continue;
|
|
57105
|
-
}
|
|
57106
|
-
let preWriteMtime;
|
|
57107
|
-
try {
|
|
57108
|
-
preWriteMtime = fs80.statSync(manifest.tasksPath).mtimeMs;
|
|
57109
|
-
} catch {
|
|
57110
|
-
preWriteMtime = 0;
|
|
57111
|
-
}
|
|
57112
|
-
if (preWriteMtime !== baseMtime) {
|
|
57113
|
-
baseMtime = preWriteMtime;
|
|
57114
|
-
continue;
|
|
57115
|
-
}
|
|
57116
57325
|
break;
|
|
57117
57326
|
}
|
|
57118
57327
|
if (merged === void 0) {
|
|
@@ -57934,6 +58143,7 @@ async function runTeamTask(input) {
|
|
|
57934
58143
|
runId: manifest.runId,
|
|
57935
58144
|
agentId: task.id,
|
|
57936
58145
|
artifactsRoot: manifest.artifactsRoot,
|
|
58146
|
+
steeringFile: `${manifest.artifactsRoot}/steering/${task.id}.jsonl`,
|
|
57937
58147
|
onSpawn: (pid) => {
|
|
57938
58148
|
try {
|
|
57939
58149
|
({ task, tasks } = checkpointTask(manifest, tasks, task, "child-spawned", pid));
|
|
@@ -59593,8 +59803,7 @@ function checkPerTaskBudget(tasks, budgetTotal, budgetWarning, budgetAbort, fair
|
|
|
59593
59803
|
const totalUsed = (usage?.input ?? 0) + (usage?.output ?? 0) + (usage?.cacheWrite ?? 0);
|
|
59594
59804
|
const abort = totalUsed >= budgetAbort * budgetTotal;
|
|
59595
59805
|
const warning = !abort && totalUsed >= budgetWarning * budgetTotal;
|
|
59596
|
-
const
|
|
59597
|
-
const fairShareThreshold = remainingBudget * fairShareFraction;
|
|
59806
|
+
const fairShareThreshold = budgetTotal * fairShareFraction;
|
|
59598
59807
|
const fairShareViolators = [];
|
|
59599
59808
|
for (const task of tasks) {
|
|
59600
59809
|
if (!task.usage) continue;
|
|
@@ -60031,6 +60240,8 @@ async function executeTeamRun(input) {
|
|
|
60031
60240
|
cleanupUsage();
|
|
60032
60241
|
await flushEventLogBuffer();
|
|
60033
60242
|
return result4;
|
|
60243
|
+
} finally {
|
|
60244
|
+
await flushEventLogBuffer();
|
|
60034
60245
|
}
|
|
60035
60246
|
}
|
|
60036
60247
|
async function executeTeamRunCore(input, manifest, workflow) {
|
|
@@ -60906,122 +61117,126 @@ var init_pipeline_runner = __esm({
|
|
|
60906
61117
|
const stages = [];
|
|
60907
61118
|
let previousResults = [];
|
|
60908
61119
|
const startTime = Date.now();
|
|
60909
|
-
|
|
60910
|
-
type: "pipeline:started",
|
|
60911
|
-
runId,
|
|
60912
|
-
message: `Pipeline '${workflow.name}' started`,
|
|
60913
|
-
data: { stages: workflow.stages.map((s) => s.name) }
|
|
60914
|
-
});
|
|
60915
|
-
for (let i2 = 0; i2 < workflow.stages.length; i2++) {
|
|
60916
|
-
const stage = workflow.stages[i2];
|
|
60917
|
-
const stageStartTime = Date.now();
|
|
60918
|
-
const effectiveStopOnError = stage.stopOnError ?? workflow.stopOnError ?? this.stopOnError;
|
|
61120
|
+
try {
|
|
60919
61121
|
await appendEventAsync(eventsPath, {
|
|
60920
|
-
type: "pipeline:
|
|
61122
|
+
type: "pipeline:started",
|
|
60921
61123
|
runId,
|
|
60922
|
-
message: `
|
|
60923
|
-
data: {
|
|
61124
|
+
message: `Pipeline '${workflow.name}' started`,
|
|
61125
|
+
data: { stages: workflow.stages.map((s) => s.name) }
|
|
60924
61126
|
});
|
|
60925
|
-
|
|
60926
|
-
const
|
|
60927
|
-
|
|
60928
|
-
|
|
60929
|
-
previousResults,
|
|
60930
|
-
totalStages: workflow.stages.length,
|
|
60931
|
-
runId
|
|
60932
|
-
};
|
|
60933
|
-
const inputs = this.resolveInputs(stage.inputs, previousResults, context);
|
|
60934
|
-
const results = await this.executeStageInternal(stage, inputs, stageContext, executeStage);
|
|
60935
|
-
const duration = Date.now() - stageStartTime;
|
|
60936
|
-
stages.push({
|
|
60937
|
-
name: stage.name,
|
|
60938
|
-
status: "completed",
|
|
60939
|
-
results,
|
|
60940
|
-
duration,
|
|
60941
|
-
fanOutItems: Array.isArray(inputs) ? inputs.length : void 0
|
|
60942
|
-
});
|
|
60943
|
-
previousResults = results;
|
|
61127
|
+
for (let i2 = 0; i2 < workflow.stages.length; i2++) {
|
|
61128
|
+
const stage = workflow.stages[i2];
|
|
61129
|
+
const stageStartTime = Date.now();
|
|
61130
|
+
const effectiveStopOnError = stage.stopOnError ?? workflow.stopOnError ?? this.stopOnError;
|
|
60944
61131
|
await appendEventAsync(eventsPath, {
|
|
60945
|
-
type: "pipeline:
|
|
61132
|
+
type: "pipeline:stage_started",
|
|
60946
61133
|
runId,
|
|
60947
|
-
message: `Stage '${stage.name}'
|
|
60948
|
-
data: {
|
|
61134
|
+
message: `Stage '${stage.name}' started`,
|
|
61135
|
+
data: { stageIndex: i2, stageName: stage.name }
|
|
61136
|
+
});
|
|
61137
|
+
try {
|
|
61138
|
+
const stageContext = {
|
|
60949
61139
|
stageIndex: i2,
|
|
60950
61140
|
stageName: stage.name,
|
|
60951
|
-
|
|
60952
|
-
|
|
60953
|
-
|
|
60954
|
-
});
|
|
60955
|
-
} catch (error) {
|
|
60956
|
-
const duration = Date.now() - stageStartTime;
|
|
60957
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
60958
|
-
if (effectiveStopOnError) {
|
|
60959
|
-
stages.push({
|
|
60960
|
-
name: stage.name,
|
|
60961
|
-
status: "failed",
|
|
60962
|
-
results: [],
|
|
60963
|
-
error: errorMessage,
|
|
60964
|
-
duration
|
|
60965
|
-
});
|
|
60966
|
-
await appendEventAsync(eventsPath, {
|
|
60967
|
-
type: "pipeline:stage_failed",
|
|
60968
|
-
runId,
|
|
60969
|
-
message: `Stage '${stage.name}' failed: ${errorMessage}`,
|
|
60970
|
-
data: {
|
|
60971
|
-
stageIndex: i2,
|
|
60972
|
-
stageName: stage.name,
|
|
60973
|
-
duration,
|
|
60974
|
-
error: errorMessage
|
|
60975
|
-
}
|
|
60976
|
-
});
|
|
60977
|
-
await appendEventAsync(eventsPath, {
|
|
60978
|
-
type: "pipeline:failed",
|
|
60979
|
-
runId,
|
|
60980
|
-
message: `Pipeline '${workflow.name}' failed at stage '${stage.name}'`,
|
|
60981
|
-
data: { failedStage: stage.name, error: errorMessage }
|
|
60982
|
-
});
|
|
60983
|
-
return {
|
|
60984
|
-
stages,
|
|
60985
|
-
totalDuration: Date.now() - startTime,
|
|
60986
|
-
finalResults: previousResults,
|
|
60987
|
-
status: "failed"
|
|
61141
|
+
previousResults,
|
|
61142
|
+
totalStages: workflow.stages.length,
|
|
61143
|
+
runId
|
|
60988
61144
|
};
|
|
60989
|
-
|
|
61145
|
+
const inputs = this.resolveInputs(stage.inputs, previousResults, context);
|
|
61146
|
+
const results = await this.executeStageInternal(stage, inputs, stageContext, executeStage);
|
|
61147
|
+
const duration = Date.now() - stageStartTime;
|
|
60990
61148
|
stages.push({
|
|
60991
61149
|
name: stage.name,
|
|
60992
|
-
status: "
|
|
60993
|
-
results
|
|
60994
|
-
|
|
60995
|
-
|
|
61150
|
+
status: "completed",
|
|
61151
|
+
results,
|
|
61152
|
+
duration,
|
|
61153
|
+
fanOutItems: Array.isArray(inputs) ? inputs.length : void 0
|
|
60996
61154
|
});
|
|
61155
|
+
previousResults = results;
|
|
60997
61156
|
await appendEventAsync(eventsPath, {
|
|
60998
|
-
type: "pipeline:
|
|
61157
|
+
type: "pipeline:stage_completed",
|
|
60999
61158
|
runId,
|
|
61000
|
-
message: `Stage '${stage.name}'
|
|
61159
|
+
message: `Stage '${stage.name}' completed`,
|
|
61001
61160
|
data: {
|
|
61002
61161
|
stageIndex: i2,
|
|
61003
61162
|
stageName: stage.name,
|
|
61004
61163
|
duration,
|
|
61005
|
-
|
|
61164
|
+
resultCount: results.length
|
|
61006
61165
|
}
|
|
61007
61166
|
});
|
|
61167
|
+
} catch (error) {
|
|
61168
|
+
const duration = Date.now() - stageStartTime;
|
|
61169
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
61170
|
+
if (effectiveStopOnError) {
|
|
61171
|
+
stages.push({
|
|
61172
|
+
name: stage.name,
|
|
61173
|
+
status: "failed",
|
|
61174
|
+
results: [],
|
|
61175
|
+
error: errorMessage,
|
|
61176
|
+
duration
|
|
61177
|
+
});
|
|
61178
|
+
await appendEventAsync(eventsPath, {
|
|
61179
|
+
type: "pipeline:stage_failed",
|
|
61180
|
+
runId,
|
|
61181
|
+
message: `Stage '${stage.name}' failed: ${errorMessage}`,
|
|
61182
|
+
data: {
|
|
61183
|
+
stageIndex: i2,
|
|
61184
|
+
stageName: stage.name,
|
|
61185
|
+
duration,
|
|
61186
|
+
error: errorMessage
|
|
61187
|
+
}
|
|
61188
|
+
});
|
|
61189
|
+
await appendEventAsync(eventsPath, {
|
|
61190
|
+
type: "pipeline:failed",
|
|
61191
|
+
runId,
|
|
61192
|
+
message: `Pipeline '${workflow.name}' failed at stage '${stage.name}'`,
|
|
61193
|
+
data: { failedStage: stage.name, error: errorMessage }
|
|
61194
|
+
});
|
|
61195
|
+
return {
|
|
61196
|
+
stages,
|
|
61197
|
+
totalDuration: Date.now() - startTime,
|
|
61198
|
+
finalResults: previousResults,
|
|
61199
|
+
status: "failed"
|
|
61200
|
+
};
|
|
61201
|
+
} else {
|
|
61202
|
+
stages.push({
|
|
61203
|
+
name: stage.name,
|
|
61204
|
+
status: "failed",
|
|
61205
|
+
results: [],
|
|
61206
|
+
error: errorMessage,
|
|
61207
|
+
duration
|
|
61208
|
+
});
|
|
61209
|
+
await appendEventAsync(eventsPath, {
|
|
61210
|
+
type: "pipeline:stage_skipped",
|
|
61211
|
+
runId,
|
|
61212
|
+
message: `Stage '${stage.name}' skipped due to error`,
|
|
61213
|
+
data: {
|
|
61214
|
+
stageIndex: i2,
|
|
61215
|
+
stageName: stage.name,
|
|
61216
|
+
duration,
|
|
61217
|
+
error: errorMessage
|
|
61218
|
+
}
|
|
61219
|
+
});
|
|
61220
|
+
}
|
|
61008
61221
|
}
|
|
61009
61222
|
}
|
|
61223
|
+
await appendEventAsync(eventsPath, {
|
|
61224
|
+
type: "pipeline:completed",
|
|
61225
|
+
runId,
|
|
61226
|
+
message: `Pipeline '${workflow.name}' completed`,
|
|
61227
|
+
data: {
|
|
61228
|
+
stages: stages.map((s) => ({ name: s.name, status: s.status }))
|
|
61229
|
+
}
|
|
61230
|
+
});
|
|
61231
|
+
return {
|
|
61232
|
+
stages,
|
|
61233
|
+
totalDuration: Date.now() - startTime,
|
|
61234
|
+
finalResults: previousResults,
|
|
61235
|
+
status: stages.some((s) => s.status === "failed") ? "partial" : "completed"
|
|
61236
|
+
};
|
|
61237
|
+
} finally {
|
|
61238
|
+
await flushEventLogBuffer();
|
|
61010
61239
|
}
|
|
61011
|
-
await appendEventAsync(eventsPath, {
|
|
61012
|
-
type: "pipeline:completed",
|
|
61013
|
-
runId,
|
|
61014
|
-
message: `Pipeline '${workflow.name}' completed`,
|
|
61015
|
-
data: {
|
|
61016
|
-
stages: stages.map((s) => ({ name: s.name, status: s.status }))
|
|
61017
|
-
}
|
|
61018
|
-
});
|
|
61019
|
-
return {
|
|
61020
|
-
stages,
|
|
61021
|
-
totalDuration: Date.now() - startTime,
|
|
61022
|
-
finalResults: previousResults,
|
|
61023
|
-
status: stages.some((s) => s.status === "failed") ? "partial" : "completed"
|
|
61024
|
-
};
|
|
61025
61240
|
}
|
|
61026
61241
|
/**
|
|
61027
61242
|
* Execute a single stage, handling fan-out for array inputs.
|
|
@@ -68717,7 +68932,7 @@ var init_deterministic_ast = __esm({
|
|
|
68717
68932
|
});
|
|
68718
68933
|
|
|
68719
68934
|
// src/runtime/dwf-state-store.ts
|
|
68720
|
-
import { existsSync as existsSync70, mkdirSync as mkdirSync42, readFileSync as
|
|
68935
|
+
import { existsSync as existsSync70, mkdirSync as mkdirSync42, readFileSync as readFileSync68, unlinkSync as unlinkSync11 } from "node:fs";
|
|
68721
68936
|
import { dirname as dirname37 } from "node:path";
|
|
68722
68937
|
var DwfStore;
|
|
68723
68938
|
var init_dwf_state_store = __esm({
|
|
@@ -68738,7 +68953,7 @@ var init_dwf_state_store = __esm({
|
|
|
68738
68953
|
const path81 = this.path;
|
|
68739
68954
|
try {
|
|
68740
68955
|
if (!existsSync70(path81)) return void 0;
|
|
68741
|
-
const raw =
|
|
68956
|
+
const raw = readFileSync68(path81, "utf-8");
|
|
68742
68957
|
const parsed = JSON.parse(raw);
|
|
68743
68958
|
if (!parsed || typeof parsed !== "object" || typeof parsed.runId !== "string") return void 0;
|
|
68744
68959
|
return parsed;
|
|
@@ -69560,7 +69775,7 @@ var dynamic_workflow_runner_exports = {};
|
|
|
69560
69775
|
__export(dynamic_workflow_runner_exports, {
|
|
69561
69776
|
runDynamicWorkflow: () => runDynamicWorkflow
|
|
69562
69777
|
});
|
|
69563
|
-
import { readFileSync as
|
|
69778
|
+
import { readFileSync as readFileSync69 } from "node:fs";
|
|
69564
69779
|
import { join as join71 } from "node:path";
|
|
69565
69780
|
function assertStructuredCloneable(value, name) {
|
|
69566
69781
|
try {
|
|
@@ -69585,7 +69800,7 @@ function resolveScriptPath(workflow, cwd) {
|
|
|
69585
69800
|
);
|
|
69586
69801
|
}
|
|
69587
69802
|
async function loadWorkflowModule(scriptPath) {
|
|
69588
|
-
const scriptSource =
|
|
69803
|
+
const scriptSource = readFileSync69(scriptPath, "utf-8");
|
|
69589
69804
|
if (isDeterminismCheckEnabled()) {
|
|
69590
69805
|
assertDeterministicScript(scriptSource);
|
|
69591
69806
|
}
|
|
@@ -69708,7 +69923,7 @@ async function runDynamicWorkflow(input) {
|
|
|
69708
69923
|
}
|
|
69709
69924
|
function readFinalArtifact(artifactPath) {
|
|
69710
69925
|
try {
|
|
69711
|
-
return
|
|
69926
|
+
return readFileSync69(artifactPath, "utf-8");
|
|
69712
69927
|
} catch (error) {
|
|
69713
69928
|
logInternalError("dynamic-workflow-runner.readFinal", error, `artifactPath=${artifactPath}`);
|
|
69714
69929
|
return `(failed to read final artifact ${artifactPath})`;
|
|
@@ -70991,6 +71206,15 @@ function handleSteer(params, ctx) {
|
|
|
70991
71206
|
}
|
|
70992
71207
|
task.pendingSteers.push(message);
|
|
70993
71208
|
saveRunTasks(loaded.manifest, loaded.tasks);
|
|
71209
|
+
try {
|
|
71210
|
+
const steeringDir = `${loaded.manifest.artifactsRoot}/steering`;
|
|
71211
|
+
fs91.mkdirSync(steeringDir, { recursive: true });
|
|
71212
|
+
fs91.appendFileSync(
|
|
71213
|
+
`${steeringDir}/${taskId}.jsonl`,
|
|
71214
|
+
JSON.stringify({ type: "steer", message, ts: (/* @__PURE__ */ new Date()).toISOString() }) + "\n"
|
|
71215
|
+
);
|
|
71216
|
+
} catch {
|
|
71217
|
+
}
|
|
70994
71218
|
appendEvent(loaded.manifest.eventsPath, {
|
|
70995
71219
|
type: "task.steer_queued",
|
|
70996
71220
|
runId,
|
|
@@ -75827,7 +76051,7 @@ function teamCommandContext(ctx) {
|
|
|
75827
76051
|
}
|
|
75828
76052
|
async function openTeamSettingsOverlay(ctx) {
|
|
75829
76053
|
if (!ctx.hasUI) return;
|
|
75830
|
-
const [{ updateConfig: updateConfig2, parseConfig: parseConfig2 }, { asCrewTheme:
|
|
76054
|
+
const [{ updateConfig: updateConfig2, parseConfig: parseConfig2 }, { asCrewTheme: asCrewTheme3 }, { createSettingsOverlay: createSettingsOverlay2 }] = await Promise.all([
|
|
75831
76055
|
Promise.resolve().then(() => (init_config(), config_exports)),
|
|
75832
76056
|
Promise.resolve().then(() => (init_theme_adapter(), theme_adapter_exports)),
|
|
75833
76057
|
Promise.resolve().then(() => (init_settings_overlay(), settings_overlay_exports))
|
|
@@ -75836,7 +76060,7 @@ async function openTeamSettingsOverlay(ctx) {
|
|
|
75836
76060
|
const config = loaded.config;
|
|
75837
76061
|
await ctx.ui.custom(
|
|
75838
76062
|
(_tui, _theme, _keybindings, done) => {
|
|
75839
|
-
const theme =
|
|
76063
|
+
const theme = asCrewTheme3(_theme);
|
|
75840
76064
|
const { overlay } = createSettingsOverlay2(
|
|
75841
76065
|
config,
|
|
75842
76066
|
theme,
|
|
@@ -79776,7 +80000,7 @@ init_orphan_worker_registry();
|
|
|
79776
80000
|
init_peer_dep();
|
|
79777
80001
|
|
|
79778
80002
|
// src/runtime/per-write-validator.ts
|
|
79779
|
-
import { readFileSync as
|
|
80003
|
+
import { readFileSync as readFileSync18 } from "node:fs";
|
|
79780
80004
|
import { extname as pathExtname } from "node:path";
|
|
79781
80005
|
function validateJson(content, _filePath) {
|
|
79782
80006
|
if (content.trim() === "") return { ok: true };
|
|
@@ -79820,7 +80044,7 @@ function validateWrittenFile(filePath) {
|
|
|
79820
80044
|
if (!validator) return null;
|
|
79821
80045
|
let content;
|
|
79822
80046
|
try {
|
|
79823
|
-
content =
|
|
80047
|
+
content = readFileSync18(filePath, "utf-8");
|
|
79824
80048
|
} catch {
|
|
79825
80049
|
return null;
|
|
79826
80050
|
}
|
|
@@ -81478,6 +81702,1145 @@ function registerCrewShortcuts(pi) {
|
|
|
81478
81702
|
}
|
|
81479
81703
|
var CREW_SHORTCUT_KEYS = CREW_SHORTCUTS.map((s) => s.key);
|
|
81480
81704
|
|
|
81705
|
+
// src/extension/crew-vibes/config.ts
|
|
81706
|
+
import { existsSync as existsSync76, mkdirSync as mkdirSync45, readFileSync as readFileSync75, writeFileSync as writeFileSync33 } from "node:fs";
|
|
81707
|
+
import { dirname as dirname39, join as join76 } from "node:path";
|
|
81708
|
+
|
|
81709
|
+
// src/extension/crew-vibes/font-detect.ts
|
|
81710
|
+
import { existsSync as existsSync75, readFileSync as readFileSync74 } from "node:fs";
|
|
81711
|
+
import { homedir as homedir11, platform } from "node:os";
|
|
81712
|
+
import { join as join75 } from "node:path";
|
|
81713
|
+
function fontPath() {
|
|
81714
|
+
const os16 = platform();
|
|
81715
|
+
const home = homedir11();
|
|
81716
|
+
if (os16 === "darwin") return join75(home, "Library", "Fonts", "crew-vibes.ttf");
|
|
81717
|
+
if (os16 === "linux") return join75(home, ".local", "share", "fonts", "crew-vibes.ttf");
|
|
81718
|
+
if (os16 === "win32") {
|
|
81719
|
+
const local = process.env.LOCALAPPDATA ?? join75(home, "AppData", "Local");
|
|
81720
|
+
return join75(local, "Microsoft", "Windows", "Fonts", "crew-vibes.ttf");
|
|
81721
|
+
}
|
|
81722
|
+
return "";
|
|
81723
|
+
}
|
|
81724
|
+
var _hasFontFile = null;
|
|
81725
|
+
function hasCrewFontFile() {
|
|
81726
|
+
if (_hasFontFile !== null) return _hasFontFile;
|
|
81727
|
+
const p = fontPath();
|
|
81728
|
+
_hasFontFile = p !== "" && existsSync75(p);
|
|
81729
|
+
return _hasFontFile;
|
|
81730
|
+
}
|
|
81731
|
+
function isWebTerminal() {
|
|
81732
|
+
if (process.env.GOTTY || process.env.WEBTERM) return true;
|
|
81733
|
+
if (process.env.TERM === "dumb") return true;
|
|
81734
|
+
try {
|
|
81735
|
+
let pid = process.pid;
|
|
81736
|
+
for (let i2 = 0; i2 < 6 && pid > 1; i2++) {
|
|
81737
|
+
const cgroup = readFileSync74(`/proc/${pid}/cgroup`, "utf8");
|
|
81738
|
+
if (cgroup.includes("gotty") || cgroup.includes("wetty")) return true;
|
|
81739
|
+
const match = cgroup.match(/\d+:.*:(.*)/);
|
|
81740
|
+
const status = readFileSync74(`/proc/${pid}/status`, "utf8");
|
|
81741
|
+
const ppid = status.match(/^PPid:\s+(\d+)/m);
|
|
81742
|
+
pid = ppid ? Number.parseInt(ppid[1], 10) : 1;
|
|
81743
|
+
}
|
|
81744
|
+
} catch {
|
|
81745
|
+
}
|
|
81746
|
+
return false;
|
|
81747
|
+
}
|
|
81748
|
+
|
|
81749
|
+
// src/extension/crew-vibes/config.ts
|
|
81750
|
+
var SPEED_STATUS_ID = "pi-crew-speed";
|
|
81751
|
+
var CAPACITY_STATUS_ID = "pi-crew-bar";
|
|
81752
|
+
var PROVIDER_STATUS_ID = "pi-crew-bar";
|
|
81753
|
+
function resolveHome() {
|
|
81754
|
+
return process.env.PI_TEAMS_HOME?.trim() || process.env.HOME || process.env.USERPROFILE || "";
|
|
81755
|
+
}
|
|
81756
|
+
function configPath2() {
|
|
81757
|
+
return join76(resolveHome(), ".pi", "agent", "pi-crew-vibes.json");
|
|
81758
|
+
}
|
|
81759
|
+
var DEFAULT_CONFIG2 = {
|
|
81760
|
+
enabled: true,
|
|
81761
|
+
speed: {
|
|
81762
|
+
enabled: true,
|
|
81763
|
+
footer: false,
|
|
81764
|
+
indicator: true,
|
|
81765
|
+
label: "tok/s",
|
|
81766
|
+
renderIntervalMs: 250,
|
|
81767
|
+
slidingWindowMs: 1e3,
|
|
81768
|
+
minReliableDurationMs: 1e3,
|
|
81769
|
+
maxDisplayTokS: 500,
|
|
81770
|
+
defaultIntervalMs: 167,
|
|
81771
|
+
minIntervalMs: 50,
|
|
81772
|
+
maxIntervalMs: 250,
|
|
81773
|
+
scale: 6e3
|
|
81774
|
+
},
|
|
81775
|
+
capacity: {
|
|
81776
|
+
enabled: true,
|
|
81777
|
+
tokenDisplay: "tokens",
|
|
81778
|
+
showLabel: true,
|
|
81779
|
+
refreshIntervalMs: 2e3,
|
|
81780
|
+
labels: ["Orbit", "Cruise", "Warp", "Black Hole", "Supernova", "Big Bang"],
|
|
81781
|
+
icons: ["\uE710", "\uE711", "\uE712", "\uE713", "\uE714", "\uE715"],
|
|
81782
|
+
providerUsage: true,
|
|
81783
|
+
providerRefreshMs: 3e5
|
|
81784
|
+
}
|
|
81785
|
+
};
|
|
81786
|
+
var FALLBACK_CAPACITY_ICONS = [
|
|
81787
|
+
"\u25CB ",
|
|
81788
|
+
// ○ empty circle (lean)
|
|
81789
|
+
"\u25D4 ",
|
|
81790
|
+
// ◔ circle with dot (chonking)
|
|
81791
|
+
"\u25D1 ",
|
|
81792
|
+
// ◑ circle half filled (chonky)
|
|
81793
|
+
"\u25CF ",
|
|
81794
|
+
// ● filled circle (big chonk)
|
|
81795
|
+
"\u2B24 ",
|
|
81796
|
+
// ⬤ large filled circle (mega chonk)
|
|
81797
|
+
"\u2B22 "
|
|
81798
|
+
// ⬢ filled hexagon (oh lawd)
|
|
81799
|
+
];
|
|
81800
|
+
function capacityIcons() {
|
|
81801
|
+
if (isWebTerminal()) return FALLBACK_CAPACITY_ICONS;
|
|
81802
|
+
return hasCrewFontFile() ? DEFAULT_CONFIG2.capacity.icons : FALLBACK_CAPACITY_ICONS;
|
|
81803
|
+
}
|
|
81804
|
+
function asRecord10(value) {
|
|
81805
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
81806
|
+
}
|
|
81807
|
+
function boolFrom(raw, fallback2) {
|
|
81808
|
+
return typeof raw === "boolean" ? raw : fallback2;
|
|
81809
|
+
}
|
|
81810
|
+
function stringFrom(raw, fallback2) {
|
|
81811
|
+
return typeof raw === "string" ? raw : fallback2;
|
|
81812
|
+
}
|
|
81813
|
+
function positiveFrom(raw, fallback2) {
|
|
81814
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : fallback2;
|
|
81815
|
+
}
|
|
81816
|
+
function sextet(raw, fallback2) {
|
|
81817
|
+
if (Array.isArray(raw) && raw.length === 6 && raw.every((entry) => typeof entry === "string")) {
|
|
81818
|
+
return raw;
|
|
81819
|
+
}
|
|
81820
|
+
return fallback2;
|
|
81821
|
+
}
|
|
81822
|
+
function tokenDisplayFrom(raw, fallback2) {
|
|
81823
|
+
return raw === "off" || raw === "tokens" || raw === "percentage" ? raw : fallback2;
|
|
81824
|
+
}
|
|
81825
|
+
function normalizeSpeed(raw) {
|
|
81826
|
+
const input = asRecord10(raw);
|
|
81827
|
+
const speed = {
|
|
81828
|
+
enabled: boolFrom(input.enabled, DEFAULT_CONFIG2.speed.enabled),
|
|
81829
|
+
footer: boolFrom(input.footer, DEFAULT_CONFIG2.speed.footer),
|
|
81830
|
+
indicator: boolFrom(input.indicator, DEFAULT_CONFIG2.speed.indicator),
|
|
81831
|
+
label: stringFrom(input.label, DEFAULT_CONFIG2.speed.label),
|
|
81832
|
+
renderIntervalMs: positiveFrom(input.renderIntervalMs, DEFAULT_CONFIG2.speed.renderIntervalMs),
|
|
81833
|
+
slidingWindowMs: positiveFrom(input.slidingWindowMs, DEFAULT_CONFIG2.speed.slidingWindowMs),
|
|
81834
|
+
minReliableDurationMs: positiveFrom(input.minReliableDurationMs, DEFAULT_CONFIG2.speed.minReliableDurationMs),
|
|
81835
|
+
maxDisplayTokS: positiveFrom(input.maxDisplayTokS, DEFAULT_CONFIG2.speed.maxDisplayTokS),
|
|
81836
|
+
defaultIntervalMs: positiveFrom(input.defaultIntervalMs, DEFAULT_CONFIG2.speed.defaultIntervalMs),
|
|
81837
|
+
minIntervalMs: positiveFrom(input.minIntervalMs, DEFAULT_CONFIG2.speed.minIntervalMs),
|
|
81838
|
+
maxIntervalMs: positiveFrom(input.maxIntervalMs, DEFAULT_CONFIG2.speed.maxIntervalMs),
|
|
81839
|
+
scale: positiveFrom(input.scale, DEFAULT_CONFIG2.speed.scale)
|
|
81840
|
+
};
|
|
81841
|
+
if (speed.minIntervalMs > speed.maxIntervalMs) {
|
|
81842
|
+
speed.minIntervalMs = DEFAULT_CONFIG2.speed.minIntervalMs;
|
|
81843
|
+
speed.maxIntervalMs = DEFAULT_CONFIG2.speed.maxIntervalMs;
|
|
81844
|
+
}
|
|
81845
|
+
return speed;
|
|
81846
|
+
}
|
|
81847
|
+
function normalizeCapacity(raw) {
|
|
81848
|
+
const input = asRecord10(raw);
|
|
81849
|
+
return {
|
|
81850
|
+
enabled: boolFrom(input.enabled, DEFAULT_CONFIG2.capacity.enabled),
|
|
81851
|
+
tokenDisplay: tokenDisplayFrom(input.tokenDisplay, DEFAULT_CONFIG2.capacity.tokenDisplay),
|
|
81852
|
+
showLabel: boolFrom(input.showLabel, DEFAULT_CONFIG2.capacity.showLabel),
|
|
81853
|
+
refreshIntervalMs: positiveFrom(input.refreshIntervalMs, DEFAULT_CONFIG2.capacity.refreshIntervalMs),
|
|
81854
|
+
labels: sextet(input.labels, DEFAULT_CONFIG2.capacity.labels),
|
|
81855
|
+
icons: sextet(input.icons, DEFAULT_CONFIG2.capacity.icons),
|
|
81856
|
+
providerUsage: boolFrom(input.providerUsage, DEFAULT_CONFIG2.capacity.providerUsage),
|
|
81857
|
+
providerRefreshMs: positiveFrom(input.providerRefreshMs, DEFAULT_CONFIG2.capacity.providerRefreshMs)
|
|
81858
|
+
};
|
|
81859
|
+
}
|
|
81860
|
+
function normalizeConfig(raw) {
|
|
81861
|
+
const input = asRecord10(raw);
|
|
81862
|
+
return {
|
|
81863
|
+
enabled: boolFrom(input.enabled, DEFAULT_CONFIG2.enabled),
|
|
81864
|
+
speed: normalizeSpeed(input.speed),
|
|
81865
|
+
capacity: normalizeCapacity(input.capacity)
|
|
81866
|
+
};
|
|
81867
|
+
}
|
|
81868
|
+
function loadConfig2() {
|
|
81869
|
+
try {
|
|
81870
|
+
const path81 = configPath2();
|
|
81871
|
+
if (!existsSync76(path81)) return normalizeConfig(void 0);
|
|
81872
|
+
return normalizeConfig(JSON.parse(readFileSync75(path81, "utf8")));
|
|
81873
|
+
} catch {
|
|
81874
|
+
return normalizeConfig(void 0);
|
|
81875
|
+
}
|
|
81876
|
+
}
|
|
81877
|
+
function saveConfig(config) {
|
|
81878
|
+
const path81 = configPath2();
|
|
81879
|
+
mkdirSync45(dirname39(path81), { recursive: true });
|
|
81880
|
+
writeFileSync33(path81, `${JSON.stringify(normalizeConfig(config), null, 2)}
|
|
81881
|
+
`);
|
|
81882
|
+
}
|
|
81883
|
+
|
|
81884
|
+
// src/extension/crew-vibes/provider-usage.ts
|
|
81885
|
+
import { readFileSync as readFileSync76 } from "node:fs";
|
|
81886
|
+
import { homedir as homedir12 } from "node:os";
|
|
81887
|
+
import { join as join77 } from "node:path";
|
|
81888
|
+
function withTimeout(ms, fn) {
|
|
81889
|
+
const controller = new AbortController();
|
|
81890
|
+
const timeoutId = setTimeout(() => controller.abort(), ms);
|
|
81891
|
+
return fn(controller.signal).finally(() => clearTimeout(timeoutId));
|
|
81892
|
+
}
|
|
81893
|
+
function piAuthPath() {
|
|
81894
|
+
return join77(homedir12(), ".pi", "agent", "auth.json");
|
|
81895
|
+
}
|
|
81896
|
+
function loadAnthropicToken() {
|
|
81897
|
+
const envToken = process.env.ANTHROPIC_OAUTH_TOKEN?.trim();
|
|
81898
|
+
if (envToken) return envToken;
|
|
81899
|
+
try {
|
|
81900
|
+
const data2 = JSON.parse(readFileSync76(piAuthPath(), "utf8"));
|
|
81901
|
+
const token = data2.anthropic?.access;
|
|
81902
|
+
return typeof token === "string" && token.length > 0 ? token : void 0;
|
|
81903
|
+
} catch {
|
|
81904
|
+
return void 0;
|
|
81905
|
+
}
|
|
81906
|
+
}
|
|
81907
|
+
function loadZaiToken() {
|
|
81908
|
+
const envKey = process.env.ZAI_API_KEY?.trim() || process.env.Z_AI_API_KEY?.trim();
|
|
81909
|
+
if (envKey) return envKey;
|
|
81910
|
+
try {
|
|
81911
|
+
const data2 = JSON.parse(readFileSync76(piAuthPath(), "utf8"));
|
|
81912
|
+
const key = data2["z-ai"]?.access || data2["z-ai"]?.key || data2.zai?.access || data2.zai?.key;
|
|
81913
|
+
return typeof key === "string" && key.length > 0 ? key : void 0;
|
|
81914
|
+
} catch {
|
|
81915
|
+
return void 0;
|
|
81916
|
+
}
|
|
81917
|
+
}
|
|
81918
|
+
function loadMinimaxToken() {
|
|
81919
|
+
const envKey = process.env.MINIMAX_API_KEY?.trim();
|
|
81920
|
+
if (envKey) return envKey;
|
|
81921
|
+
try {
|
|
81922
|
+
const data2 = JSON.parse(readFileSync76(piAuthPath(), "utf8"));
|
|
81923
|
+
const key = data2.minimax?.key;
|
|
81924
|
+
return typeof key === "string" && key.length > 0 ? key : void 0;
|
|
81925
|
+
} catch {
|
|
81926
|
+
return void 0;
|
|
81927
|
+
}
|
|
81928
|
+
}
|
|
81929
|
+
var COPILOT_TOKEN_KEYS = ["oauth_token", "user_token", "github_token", "token"];
|
|
81930
|
+
function tokenFromHostEntry(entry) {
|
|
81931
|
+
if (!entry) return void 0;
|
|
81932
|
+
for (const key of COPILOT_TOKEN_KEYS) {
|
|
81933
|
+
const value = entry[key];
|
|
81934
|
+
if (typeof value === "string" && value.length > 0) return value;
|
|
81935
|
+
}
|
|
81936
|
+
return void 0;
|
|
81937
|
+
}
|
|
81938
|
+
function loadLegacyCopilotToken() {
|
|
81939
|
+
const configHome = process.env.XDG_CONFIG_HOME?.trim() || join77(homedir12(), ".config");
|
|
81940
|
+
const candidates = [join77(configHome, "github-copilot", "hosts.json"), join77(homedir12(), ".github-copilot", "hosts.json")];
|
|
81941
|
+
for (const hostsPath of candidates) {
|
|
81942
|
+
try {
|
|
81943
|
+
const data2 = JSON.parse(readFileSync76(hostsPath, "utf8"));
|
|
81944
|
+
if (!data2 || typeof data2 !== "object") continue;
|
|
81945
|
+
const normalized = {};
|
|
81946
|
+
for (const [host, entry] of Object.entries(data2)) {
|
|
81947
|
+
normalized[host.toLowerCase()] = entry;
|
|
81948
|
+
}
|
|
81949
|
+
const preferred = tokenFromHostEntry(normalized["github.com"]) ?? tokenFromHostEntry(normalized["api.github.com"]);
|
|
81950
|
+
if (preferred) return preferred;
|
|
81951
|
+
for (const entry of Object.values(normalized)) {
|
|
81952
|
+
const token = tokenFromHostEntry(entry);
|
|
81953
|
+
if (token) return token;
|
|
81954
|
+
}
|
|
81955
|
+
} catch {
|
|
81956
|
+
}
|
|
81957
|
+
}
|
|
81958
|
+
return void 0;
|
|
81959
|
+
}
|
|
81960
|
+
function loadCopilotToken() {
|
|
81961
|
+
const envToken = (process.env.COPILOT_GITHUB_TOKEN || process.env.GH_TOKEN || process.env.GITHUB_TOKEN || "").trim();
|
|
81962
|
+
if (envToken) return envToken;
|
|
81963
|
+
try {
|
|
81964
|
+
const data2 = JSON.parse(readFileSync76(piAuthPath(), "utf8"));
|
|
81965
|
+
const piToken = data2["github-copilot"]?.refresh || data2["github-copilot"]?.access;
|
|
81966
|
+
if (typeof piToken === "string" && piToken.length > 0) return piToken;
|
|
81967
|
+
} catch {
|
|
81968
|
+
}
|
|
81969
|
+
return loadLegacyCopilotToken();
|
|
81970
|
+
}
|
|
81971
|
+
async function fetchAnthropicUsage(token) {
|
|
81972
|
+
const data2 = await withTimeout(1e4, async (signal) => {
|
|
81973
|
+
const res = await fetch("https://api.anthropic.com/api/oauth/usage", {
|
|
81974
|
+
headers: {
|
|
81975
|
+
Authorization: `Bearer ${token}`,
|
|
81976
|
+
"anthropic-beta": "oauth-2025-04-20"
|
|
81977
|
+
},
|
|
81978
|
+
signal
|
|
81979
|
+
});
|
|
81980
|
+
if (!res.ok) throw new Error(`anthropic usage HTTP ${res.status}`);
|
|
81981
|
+
return await res.json();
|
|
81982
|
+
});
|
|
81983
|
+
return {
|
|
81984
|
+
fiveHourPercent: data2.five_hour?.utilization ?? 0,
|
|
81985
|
+
weeklyPercent: data2.seven_day?.utilization ?? 0,
|
|
81986
|
+
fiveHourResetAt: data2.five_hour?.resets_at ?? null,
|
|
81987
|
+
weeklyResetAt: data2.seven_day?.resets_at ?? null
|
|
81988
|
+
};
|
|
81989
|
+
}
|
|
81990
|
+
async function fetchCopilotMonthlyPercent(token) {
|
|
81991
|
+
const data2 = await withTimeout(1e4, async (signal) => {
|
|
81992
|
+
const res = await fetch("https://api.github.com/copilot_internal/user", {
|
|
81993
|
+
headers: {
|
|
81994
|
+
Authorization: `token ${token}`,
|
|
81995
|
+
"Editor-Version": "vscode/1.96.2",
|
|
81996
|
+
"User-Agent": "GitHubCopilotChat/0.26.7",
|
|
81997
|
+
"X-Github-Api-Version": "2025-04-01",
|
|
81998
|
+
Accept: "application/json"
|
|
81999
|
+
},
|
|
82000
|
+
signal
|
|
82001
|
+
});
|
|
82002
|
+
if (!res.ok) throw new Error(`copilot user HTTP ${res.status}`);
|
|
82003
|
+
return await res.json();
|
|
82004
|
+
});
|
|
82005
|
+
const percentRemaining = data2.quota_snapshots?.premium_interactions?.percent_remaining;
|
|
82006
|
+
if (typeof percentRemaining !== "number") return void 0;
|
|
82007
|
+
return Math.max(0, 100 - percentRemaining);
|
|
82008
|
+
}
|
|
82009
|
+
async function fetchZaiUsage(token) {
|
|
82010
|
+
const data2 = await withTimeout(1e4, async (signal) => {
|
|
82011
|
+
const res = await fetch("https://api.z.ai/api/monitor/usage/quota/limit", {
|
|
82012
|
+
method: "GET",
|
|
82013
|
+
headers: {
|
|
82014
|
+
Authorization: `Bearer ${token}`,
|
|
82015
|
+
Accept: "application/json"
|
|
82016
|
+
},
|
|
82017
|
+
signal
|
|
82018
|
+
});
|
|
82019
|
+
if (!res.ok) throw new Error(`z.ai usage HTTP ${res.status}`);
|
|
82020
|
+
return await res.json();
|
|
82021
|
+
});
|
|
82022
|
+
if (!data2.success || data2.code !== 200) throw new Error(data2.msg || "z.ai API error");
|
|
82023
|
+
const limits = data2.data?.limits ?? [];
|
|
82024
|
+
let tokensPercent = 0;
|
|
82025
|
+
let monthlyPercent = 0;
|
|
82026
|
+
let tokensResetAt = null;
|
|
82027
|
+
let monthlyResetAt = null;
|
|
82028
|
+
for (const limit of limits) {
|
|
82029
|
+
const pct = limit.percentage ?? 0;
|
|
82030
|
+
const resetIso = typeof limit.nextResetTime === "number" ? new Date(limit.nextResetTime).toISOString() : typeof limit.nextResetTime === "string" ? limit.nextResetTime : null;
|
|
82031
|
+
if (limit.type === "TOKENS_LIMIT") {
|
|
82032
|
+
tokensPercent = pct;
|
|
82033
|
+
tokensResetAt = resetIso;
|
|
82034
|
+
} else if (limit.type === "TIME_LIMIT") {
|
|
82035
|
+
monthlyPercent = pct;
|
|
82036
|
+
monthlyResetAt = resetIso;
|
|
82037
|
+
}
|
|
82038
|
+
}
|
|
82039
|
+
return {
|
|
82040
|
+
providerName: "z.ai",
|
|
82041
|
+
fiveHourPercent: tokensPercent,
|
|
82042
|
+
fiveHourResetAt: tokensResetAt,
|
|
82043
|
+
weeklyPercent: monthlyPercent,
|
|
82044
|
+
weeklyResetAt: monthlyResetAt
|
|
82045
|
+
};
|
|
82046
|
+
}
|
|
82047
|
+
var cachedUsage = null;
|
|
82048
|
+
var cachedAt = 0;
|
|
82049
|
+
function clearProviderUsageCache() {
|
|
82050
|
+
cachedUsage = null;
|
|
82051
|
+
cachedAt = 0;
|
|
82052
|
+
}
|
|
82053
|
+
async function fetchMinimaxUsage(token) {
|
|
82054
|
+
const data2 = await withTimeout(1e4, async (signal) => {
|
|
82055
|
+
const res = await fetch("https://www.minimax.io/v1/token_plan/remains", {
|
|
82056
|
+
headers: { Authorization: `Bearer ${token}`, Accept: "application/json" },
|
|
82057
|
+
signal
|
|
82058
|
+
});
|
|
82059
|
+
if (!res.ok) throw new Error(`minimax usage HTTP ${res.status}`);
|
|
82060
|
+
return await res.json();
|
|
82061
|
+
});
|
|
82062
|
+
if (data2.base_resp?.status_code !== 0) throw new Error(data2.base_resp?.status_msg || "minimax API error");
|
|
82063
|
+
const models = data2.model_remains ?? [];
|
|
82064
|
+
const general = models.find((m) => m.model_name === "general") ?? models[0];
|
|
82065
|
+
if (!general) throw new Error("minimax: no model data");
|
|
82066
|
+
const intervalUsed = 100 - (general.current_interval_remaining_percent ?? 100);
|
|
82067
|
+
const weeklyUsed = 100 - (general.current_weekly_remaining_percent ?? 100);
|
|
82068
|
+
const intervalReset = typeof general.end_time === "number" ? new Date(general.end_time).toISOString() : null;
|
|
82069
|
+
const weeklyReset = typeof general.weekly_end_time === "number" ? new Date(general.weekly_end_time).toISOString() : null;
|
|
82070
|
+
return {
|
|
82071
|
+
providerName: "Minimax",
|
|
82072
|
+
fiveHourPercent: intervalUsed,
|
|
82073
|
+
fiveHourResetAt: intervalReset,
|
|
82074
|
+
weeklyPercent: weeklyUsed,
|
|
82075
|
+
weeklyResetAt: weeklyReset
|
|
82076
|
+
};
|
|
82077
|
+
}
|
|
82078
|
+
var QUOTA_PROVIDERS = /* @__PURE__ */ new Set(["anthropic", "minimax", "minimax-cn", "zai", "github-copilot"]);
|
|
82079
|
+
async function fetchForProvider(provider) {
|
|
82080
|
+
switch (provider) {
|
|
82081
|
+
case "anthropic": {
|
|
82082
|
+
const token = loadAnthropicToken();
|
|
82083
|
+
if (!token) return null;
|
|
82084
|
+
const base = await fetchAnthropicUsage(token);
|
|
82085
|
+
return { providerName: "Claude", ...base };
|
|
82086
|
+
}
|
|
82087
|
+
case "minimax":
|
|
82088
|
+
case "minimax-cn": {
|
|
82089
|
+
const token = loadMinimaxToken();
|
|
82090
|
+
if (!token) return null;
|
|
82091
|
+
return await fetchMinimaxUsage(token);
|
|
82092
|
+
}
|
|
82093
|
+
case "zai": {
|
|
82094
|
+
const token = loadZaiToken();
|
|
82095
|
+
if (!token) return null;
|
|
82096
|
+
const usage = await fetchZaiUsage(token);
|
|
82097
|
+
usage.providerName = "z.ai";
|
|
82098
|
+
return usage;
|
|
82099
|
+
}
|
|
82100
|
+
case "github-copilot": {
|
|
82101
|
+
const token = loadCopilotToken();
|
|
82102
|
+
if (!token) return null;
|
|
82103
|
+
const pct = await fetchCopilotMonthlyPercent(token);
|
|
82104
|
+
if (pct === void 0) return null;
|
|
82105
|
+
return {
|
|
82106
|
+
providerName: "Copilot",
|
|
82107
|
+
fiveHourPercent: 0,
|
|
82108
|
+
fiveHourResetAt: null,
|
|
82109
|
+
weeklyPercent: pct,
|
|
82110
|
+
weeklyResetAt: null,
|
|
82111
|
+
copilotMonthlyPercent: pct
|
|
82112
|
+
};
|
|
82113
|
+
}
|
|
82114
|
+
default:
|
|
82115
|
+
return null;
|
|
82116
|
+
}
|
|
82117
|
+
}
|
|
82118
|
+
async function fetchProviderUsage(maxAgeMs = 3e5, provider) {
|
|
82119
|
+
if (!provider || !QUOTA_PROVIDERS.has(provider)) {
|
|
82120
|
+
cachedUsage = null;
|
|
82121
|
+
return null;
|
|
82122
|
+
}
|
|
82123
|
+
if (cachedUsage !== null && Date.now() - cachedAt < maxAgeMs) {
|
|
82124
|
+
return cachedUsage;
|
|
82125
|
+
}
|
|
82126
|
+
try {
|
|
82127
|
+
const usage = await fetchForProvider(provider);
|
|
82128
|
+
if (usage) {
|
|
82129
|
+
cachedUsage = usage;
|
|
82130
|
+
cachedAt = Date.now();
|
|
82131
|
+
}
|
|
82132
|
+
return usage;
|
|
82133
|
+
} catch {
|
|
82134
|
+
return null;
|
|
82135
|
+
}
|
|
82136
|
+
}
|
|
82137
|
+
|
|
82138
|
+
// src/extension/crew-vibes/figures.ts
|
|
82139
|
+
var BRAILLE_FRAMES = [
|
|
82140
|
+
"\u280B ",
|
|
82141
|
+
// ⠋
|
|
82142
|
+
"\u2819 ",
|
|
82143
|
+
// ⠙
|
|
82144
|
+
"\u2839 ",
|
|
82145
|
+
// ⠹
|
|
82146
|
+
"\u2838 ",
|
|
82147
|
+
// ⠸
|
|
82148
|
+
"\u283C ",
|
|
82149
|
+
// ⠼
|
|
82150
|
+
"\u2834 ",
|
|
82151
|
+
// ⠴
|
|
82152
|
+
"\u2826 ",
|
|
82153
|
+
// ⠦
|
|
82154
|
+
"\u2827 ",
|
|
82155
|
+
// ⠧
|
|
82156
|
+
"\u2807 ",
|
|
82157
|
+
// ⠇
|
|
82158
|
+
"\u280F "
|
|
82159
|
+
// ⠏
|
|
82160
|
+
];
|
|
82161
|
+
var PUA_CREW_FRAMES = [
|
|
82162
|
+
"\uE700 ",
|
|
82163
|
+
"\uE701 ",
|
|
82164
|
+
"\uE702 ",
|
|
82165
|
+
"\uE703 ",
|
|
82166
|
+
"\uE704 ",
|
|
82167
|
+
"\uE705 ",
|
|
82168
|
+
"\uE706 ",
|
|
82169
|
+
"\uE707 ",
|
|
82170
|
+
"\uE708 ",
|
|
82171
|
+
"\uE709 ",
|
|
82172
|
+
"\uE70A ",
|
|
82173
|
+
"\uE70B ",
|
|
82174
|
+
"\uE70C ",
|
|
82175
|
+
"\uE70D ",
|
|
82176
|
+
"\uE70E ",
|
|
82177
|
+
"\uE70F "
|
|
82178
|
+
];
|
|
82179
|
+
function crewFrames(style = "pua") {
|
|
82180
|
+
if (style === "pua" && isWebTerminal()) return BRAILLE_FRAMES;
|
|
82181
|
+
return style === "pua" ? PUA_CREW_FRAMES : BRAILLE_FRAMES;
|
|
82182
|
+
}
|
|
82183
|
+
function intervalForSpeed(config, speed) {
|
|
82184
|
+
if (speed === null || !Number.isFinite(speed) || speed <= 0) return config.defaultIntervalMs;
|
|
82185
|
+
return Math.max(config.minIntervalMs, Math.min(config.maxIntervalMs, Math.round(config.scale / speed)));
|
|
82186
|
+
}
|
|
82187
|
+
function capacityIndex(percent, levels = 6) {
|
|
82188
|
+
if (percent === null || percent === void 0 || !Number.isFinite(percent)) return 0;
|
|
82189
|
+
return Math.max(0, Math.min(levels - 1, Math.floor(Math.max(0, Math.min(100, percent)) / 100 * levels)));
|
|
82190
|
+
}
|
|
82191
|
+
function isDangerStage(index, levels) {
|
|
82192
|
+
return index >= Math.max(0, levels - 2);
|
|
82193
|
+
}
|
|
82194
|
+
|
|
82195
|
+
// src/extension/crew-vibes/render.ts
|
|
82196
|
+
function formatCount(value) {
|
|
82197
|
+
if (value < 1e3) return value.toString();
|
|
82198
|
+
if (value < 1e4) return `${(value / 1e3).toFixed(1)}k`;
|
|
82199
|
+
if (value < 1e6) return `${Math.round(value / 1e3)}k`;
|
|
82200
|
+
if (value < 1e7) return `${(value / 1e6).toFixed(1)}M`;
|
|
82201
|
+
return `${Math.round(value / 1e6)}M`;
|
|
82202
|
+
}
|
|
82203
|
+
function asCrewTheme2(theme) {
|
|
82204
|
+
if (theme && typeof theme === "object" && typeof theme.fg === "function") {
|
|
82205
|
+
return theme;
|
|
82206
|
+
}
|
|
82207
|
+
return void 0;
|
|
82208
|
+
}
|
|
82209
|
+
function getCapacityUsage(ctx) {
|
|
82210
|
+
const fn = ctx.getContextUsage;
|
|
82211
|
+
const usage = typeof fn === "function" ? fn.call(ctx) : null;
|
|
82212
|
+
return {
|
|
82213
|
+
tokens: typeof usage?.tokens === "number" && Number.isFinite(usage.tokens) ? usage.tokens : null,
|
|
82214
|
+
percent: typeof usage?.percent === "number" && Number.isFinite(usage.percent) ? usage.percent : null
|
|
82215
|
+
};
|
|
82216
|
+
}
|
|
82217
|
+
function formatSpeed(config, speed) {
|
|
82218
|
+
return speed === null ? `-- ${config.label}` : `${speed.toFixed(1)} ${config.label}`;
|
|
82219
|
+
}
|
|
82220
|
+
function renderSpeedFooter(theme, config, speed) {
|
|
82221
|
+
const value = speed === null ? "--" : speed.toFixed(1);
|
|
82222
|
+
const valueTone = speed === null ? "dim" : "accent";
|
|
82223
|
+
const styled = theme ? `${theme.fg(valueTone, value)} ${theme.fg("dim", config.label)}` : `${value} ${config.label}`;
|
|
82224
|
+
return styled;
|
|
82225
|
+
}
|
|
82226
|
+
function renderWorkingMessage(theme, config, speed) {
|
|
82227
|
+
const left = "Working";
|
|
82228
|
+
const speedText = theme ? `${theme.fg(speed === null ? "dim" : "accent", speed === null ? "--" : speed.toFixed(1))} ${theme.fg("dim", config.label)}` : `${speed === null ? "--" : speed.toFixed(1)} ${config.label}`;
|
|
82229
|
+
return theme ? `${theme.fg("muted", left)} ${speedText}` : `${left} ${speedText}`;
|
|
82230
|
+
}
|
|
82231
|
+
function crewIndicatorFrames(theme) {
|
|
82232
|
+
const frames = crewFrames();
|
|
82233
|
+
if (!theme) return [...frames];
|
|
82234
|
+
return frames.map((frame) => theme.fg("accent", frame));
|
|
82235
|
+
}
|
|
82236
|
+
function formatCapacityPrefix(config, usage) {
|
|
82237
|
+
const display = config.tokenDisplay;
|
|
82238
|
+
if (display === "off") return "";
|
|
82239
|
+
if (display === "percentage") {
|
|
82240
|
+
return `${usage.percent === null ? "?" : Math.round(Math.max(0, Math.min(999, usage.percent)))}% `;
|
|
82241
|
+
}
|
|
82242
|
+
return `${usage.tokens === null ? "?" : formatCount(usage.tokens)} `;
|
|
82243
|
+
}
|
|
82244
|
+
function colorStage(theme, index, levels, text) {
|
|
82245
|
+
if (!theme || text.length === 0) return text;
|
|
82246
|
+
return theme.fg(isDangerStage(index, levels) ? "error" : "success", text);
|
|
82247
|
+
}
|
|
82248
|
+
function renderCapacity(theme, config, usage) {
|
|
82249
|
+
const icons = capacityIcons();
|
|
82250
|
+
const levels = icons.length;
|
|
82251
|
+
const index = capacityIndex(usage.percent, levels);
|
|
82252
|
+
const icon = icons[index] ?? icons[0];
|
|
82253
|
+
const label = config.labels[index] ?? config.labels[0];
|
|
82254
|
+
const prefix = theme ? theme.fg("muted", formatCapacityPrefix(config, usage)) : formatCapacityPrefix(config, usage);
|
|
82255
|
+
const coloredIcon = colorStage(theme, index, levels, icon);
|
|
82256
|
+
const afterIcon = config.showLabel ? ` ${colorStage(theme, index, levels, label)}` : " ";
|
|
82257
|
+
return `${prefix}${coloredIcon}${afterIcon}`;
|
|
82258
|
+
}
|
|
82259
|
+
function setSpeedStatus(ctx, config, text) {
|
|
82260
|
+
if (!ctx?.hasUI) return;
|
|
82261
|
+
if (!config.enabled || !config.speed.enabled || !config.speed.footer) {
|
|
82262
|
+
ctx.ui.setStatus(SPEED_STATUS_ID, void 0);
|
|
82263
|
+
return;
|
|
82264
|
+
}
|
|
82265
|
+
ctx.ui.setStatus(SPEED_STATUS_ID, text);
|
|
82266
|
+
}
|
|
82267
|
+
function setCapacityStatus(ctx, config, text) {
|
|
82268
|
+
if (!ctx?.hasUI) return;
|
|
82269
|
+
if (!config.enabled || !config.capacity.enabled) {
|
|
82270
|
+
ctx.ui.setStatus(CAPACITY_STATUS_ID, void 0);
|
|
82271
|
+
return;
|
|
82272
|
+
}
|
|
82273
|
+
ctx.ui.setStatus(CAPACITY_STATUS_ID, text);
|
|
82274
|
+
}
|
|
82275
|
+
function clearVibesStatus(ctx) {
|
|
82276
|
+
if (!ctx?.hasUI) return;
|
|
82277
|
+
ctx.ui.setStatus(SPEED_STATUS_ID, void 0);
|
|
82278
|
+
ctx.ui.setStatus(CAPACITY_STATUS_ID, void 0);
|
|
82279
|
+
ctx.ui.setStatus(PROVIDER_STATUS_ID, void 0);
|
|
82280
|
+
if (ctx.ui.setWorkingIndicator) ctx.ui.setWorkingIndicator();
|
|
82281
|
+
if (ctx.ui.setWorkingMessage) ctx.ui.setWorkingMessage();
|
|
82282
|
+
}
|
|
82283
|
+
function formatResetTimer(resetAt) {
|
|
82284
|
+
if (!resetAt) return null;
|
|
82285
|
+
const diffMs = new Date(resetAt).getTime() - Date.now();
|
|
82286
|
+
if (diffMs < 0) return null;
|
|
82287
|
+
const mins = Math.floor(diffMs / 6e4);
|
|
82288
|
+
if (mins < 60) return `${mins}m`;
|
|
82289
|
+
const hours = Math.floor(mins / 60);
|
|
82290
|
+
if (hours < 48) {
|
|
82291
|
+
const remMins = mins % 60;
|
|
82292
|
+
return remMins > 0 ? `${hours}h${remMins}m` : `${hours}h`;
|
|
82293
|
+
}
|
|
82294
|
+
const days = Math.floor(hours / 24);
|
|
82295
|
+
const remHours = hours % 24;
|
|
82296
|
+
return remHours > 0 ? `${days}d${remHours}h` : `${days}d`;
|
|
82297
|
+
}
|
|
82298
|
+
function renderBar(percent, width = 8) {
|
|
82299
|
+
const clamped = Math.max(0, Math.min(100, percent));
|
|
82300
|
+
const filled = Math.round(clamped / 100 * width);
|
|
82301
|
+
return `${"\u2501".repeat(filled)}${"\u2504".repeat(width - filled)}`;
|
|
82302
|
+
}
|
|
82303
|
+
function renderProviderUsage(theme, usage) {
|
|
82304
|
+
if (!usage) return void 0;
|
|
82305
|
+
const parts = [];
|
|
82306
|
+
if (usage.providerName) {
|
|
82307
|
+
const nameText = usage.providerName;
|
|
82308
|
+
parts.push(theme ? theme.fg("muted", nameText) : nameText);
|
|
82309
|
+
}
|
|
82310
|
+
const fiveHourBar = renderBar(usage.fiveHourPercent);
|
|
82311
|
+
const fiveHourRounded = Math.round(usage.fiveHourPercent);
|
|
82312
|
+
const fiveHourReset = formatResetTimer(usage.fiveHourResetAt);
|
|
82313
|
+
const fiveHourText = `5h ${fiveHourBar} ${fiveHourRounded}%${fiveHourReset ? " " + fiveHourReset : ""}`;
|
|
82314
|
+
const fiveHourColor = usage.fiveHourPercent >= 80 ? "error" : "accent";
|
|
82315
|
+
parts.push(theme ? theme.fg(fiveHourColor, fiveHourText) : fiveHourText);
|
|
82316
|
+
const weeklyBar = renderBar(usage.weeklyPercent);
|
|
82317
|
+
const weeklyRounded = Math.round(usage.weeklyPercent);
|
|
82318
|
+
const weeklyReset = formatResetTimer(usage.weeklyResetAt);
|
|
82319
|
+
const weeklyText = `Wk ${weeklyBar} ${weeklyRounded}%${weeklyReset ? " " + weeklyReset : ""}`;
|
|
82320
|
+
parts.push(theme ? theme.fg("dim", weeklyText) : weeklyText);
|
|
82321
|
+
if (typeof usage.copilotMonthlyPercent === "number" && Number.isFinite(usage.copilotMonthlyPercent)) {
|
|
82322
|
+
const monthlyRounded = Math.round(usage.copilotMonthlyPercent);
|
|
82323
|
+
const monthlyText = `Mo: ${monthlyRounded}%`;
|
|
82324
|
+
parts.push(theme ? theme.fg("dim", monthlyText) : monthlyText);
|
|
82325
|
+
}
|
|
82326
|
+
return parts.join(" ");
|
|
82327
|
+
}
|
|
82328
|
+
|
|
82329
|
+
// src/extension/crew-vibes/speed.ts
|
|
82330
|
+
var COMPACTION_THRESHOLD = 5e3;
|
|
82331
|
+
function estimateTokensFromDelta(text) {
|
|
82332
|
+
if (!text) return 0;
|
|
82333
|
+
const matches = text.match(/\w+|[^\s\w]/g);
|
|
82334
|
+
return matches ? matches.length : 0;
|
|
82335
|
+
}
|
|
82336
|
+
var TokenSpeedEngine = class {
|
|
82337
|
+
_isStreaming = false;
|
|
82338
|
+
_tokenCount = 0;
|
|
82339
|
+
_startTime = 0;
|
|
82340
|
+
_endTime = 0;
|
|
82341
|
+
_events = [];
|
|
82342
|
+
_windowStartIndex = 0;
|
|
82343
|
+
_lastStableTokS = 0;
|
|
82344
|
+
_lastUsageOutput = 0;
|
|
82345
|
+
_config;
|
|
82346
|
+
constructor(config) {
|
|
82347
|
+
this._config = config;
|
|
82348
|
+
}
|
|
82349
|
+
updateConfig(config) {
|
|
82350
|
+
this._config = config;
|
|
82351
|
+
}
|
|
82352
|
+
get isStreaming() {
|
|
82353
|
+
return this._isStreaming;
|
|
82354
|
+
}
|
|
82355
|
+
get tokenCount() {
|
|
82356
|
+
return this._tokenCount;
|
|
82357
|
+
}
|
|
82358
|
+
get elapsedMs() {
|
|
82359
|
+
if (this._startTime === 0) return 0;
|
|
82360
|
+
return this._isStreaming ? Date.now() - this._startTime : this._endTime - this._startTime;
|
|
82361
|
+
}
|
|
82362
|
+
get avgTokS() {
|
|
82363
|
+
const elapsedSec = this.elapsedMs / 1e3;
|
|
82364
|
+
if (elapsedSec <= 0) return 0;
|
|
82365
|
+
return this._tokenCount / elapsedSec;
|
|
82366
|
+
}
|
|
82367
|
+
sanitizeTokS(value, durationMs = this.elapsedMs) {
|
|
82368
|
+
if (value === null || !Number.isFinite(value) || value <= 0) return null;
|
|
82369
|
+
if (durationMs < this._config.minReliableDurationMs) return null;
|
|
82370
|
+
if (value > this._config.maxDisplayTokS) return null;
|
|
82371
|
+
return value;
|
|
82372
|
+
}
|
|
82373
|
+
get tokS() {
|
|
82374
|
+
const candidate = this.rawTokS;
|
|
82375
|
+
const stable = this.sanitizeTokS(candidate);
|
|
82376
|
+
if (stable !== null) this._lastStableTokS = stable;
|
|
82377
|
+
return this._lastStableTokS;
|
|
82378
|
+
}
|
|
82379
|
+
get rawTokS() {
|
|
82380
|
+
if (this.elapsedMs < this._config.slidingWindowMs) return this.avgTokS;
|
|
82381
|
+
if (!this._isStreaming) return this.avgTokS;
|
|
82382
|
+
const now = Date.now();
|
|
82383
|
+
const windowStart = now - this._config.slidingWindowMs;
|
|
82384
|
+
while (this._windowStartIndex < this._events.length && this._events[this._windowStartIndex].time < windowStart) {
|
|
82385
|
+
this._windowStartIndex++;
|
|
82386
|
+
}
|
|
82387
|
+
if (this._windowStartIndex >= this._events.length) return this.avgTokS;
|
|
82388
|
+
let windowTokenCount = 0;
|
|
82389
|
+
for (let i2 = this._windowStartIndex; i2 < this._events.length; i2++) {
|
|
82390
|
+
windowTokenCount += this._events[i2].tokens;
|
|
82391
|
+
}
|
|
82392
|
+
if (windowTokenCount === 0) return this.avgTokS;
|
|
82393
|
+
const windowDuration = (now - this._events[this._windowStartIndex].time) / 1e3;
|
|
82394
|
+
if (windowDuration <= 0) return 0;
|
|
82395
|
+
return windowTokenCount / windowDuration;
|
|
82396
|
+
}
|
|
82397
|
+
start() {
|
|
82398
|
+
this._tokenCount = 0;
|
|
82399
|
+
this._isStreaming = true;
|
|
82400
|
+
this._startTime = Date.now();
|
|
82401
|
+
this._endTime = this._startTime;
|
|
82402
|
+
this._events = [];
|
|
82403
|
+
this._windowStartIndex = 0;
|
|
82404
|
+
this._lastStableTokS = 0;
|
|
82405
|
+
this._lastUsageOutput = 0;
|
|
82406
|
+
}
|
|
82407
|
+
stop() {
|
|
82408
|
+
this._isStreaming = false;
|
|
82409
|
+
this._endTime = Date.now();
|
|
82410
|
+
this._events = [];
|
|
82411
|
+
this._windowStartIndex = 0;
|
|
82412
|
+
}
|
|
82413
|
+
recordDelta(delta, usageOutput) {
|
|
82414
|
+
if (!this._isStreaming) return;
|
|
82415
|
+
if (usageOutput !== void 0 && usageOutput > 0) {
|
|
82416
|
+
const increment = usageOutput - this._lastUsageOutput;
|
|
82417
|
+
this._lastUsageOutput = usageOutput;
|
|
82418
|
+
this.recordTokens(Math.max(0, increment));
|
|
82419
|
+
return;
|
|
82420
|
+
}
|
|
82421
|
+
this.recordTokens(estimateTokensFromDelta(delta));
|
|
82422
|
+
}
|
|
82423
|
+
reconcileTotal(tokens) {
|
|
82424
|
+
if (tokens > 0) this._tokenCount = tokens;
|
|
82425
|
+
}
|
|
82426
|
+
recordTokens(tokens) {
|
|
82427
|
+
if (!this._isStreaming || tokens <= 0) return;
|
|
82428
|
+
this._tokenCount += tokens;
|
|
82429
|
+
this._events.push({ time: Date.now(), tokens });
|
|
82430
|
+
if (this._windowStartIndex >= COMPACTION_THRESHOLD) this.compact();
|
|
82431
|
+
}
|
|
82432
|
+
compact() {
|
|
82433
|
+
if (this._windowStartIndex === 0) return;
|
|
82434
|
+
this._events = this._events.slice(this._windowStartIndex);
|
|
82435
|
+
this._windowStartIndex = 0;
|
|
82436
|
+
}
|
|
82437
|
+
};
|
|
82438
|
+
function isSuccessfulStop(stopReason) {
|
|
82439
|
+
return stopReason !== "error" && stopReason !== "aborted";
|
|
82440
|
+
}
|
|
82441
|
+
var SpeedTracker = class {
|
|
82442
|
+
engine;
|
|
82443
|
+
lastStableTokS = null;
|
|
82444
|
+
sessionOutputTokens = 0;
|
|
82445
|
+
sessionDurationMs = 0;
|
|
82446
|
+
constructor(config) {
|
|
82447
|
+
this.engine = new TokenSpeedEngine(config);
|
|
82448
|
+
}
|
|
82449
|
+
updateConfig(config) {
|
|
82450
|
+
this.engine.updateConfig(config);
|
|
82451
|
+
}
|
|
82452
|
+
get isStreaming() {
|
|
82453
|
+
return this.engine.isStreaming;
|
|
82454
|
+
}
|
|
82455
|
+
get lastTokS() {
|
|
82456
|
+
return this.lastStableTokS;
|
|
82457
|
+
}
|
|
82458
|
+
resetSession() {
|
|
82459
|
+
this.sessionOutputTokens = 0;
|
|
82460
|
+
this.sessionDurationMs = 0;
|
|
82461
|
+
}
|
|
82462
|
+
startMessage() {
|
|
82463
|
+
this.engine.start();
|
|
82464
|
+
}
|
|
82465
|
+
recordDelta(delta, usageOutput) {
|
|
82466
|
+
this.engine.recordDelta(delta, usageOutput);
|
|
82467
|
+
}
|
|
82468
|
+
stopMessage() {
|
|
82469
|
+
if (this.engine.isStreaming) this.engine.stop();
|
|
82470
|
+
}
|
|
82471
|
+
liveTokS() {
|
|
82472
|
+
const speed = this.engine.tokS;
|
|
82473
|
+
return speed > 0 ? speed : this.lastStableTokS;
|
|
82474
|
+
}
|
|
82475
|
+
sessionAvgTokS() {
|
|
82476
|
+
return this.sessionDurationMs > 0 ? this.sessionOutputTokens / (this.sessionDurationMs / 1e3) : null;
|
|
82477
|
+
}
|
|
82478
|
+
finishMessage(outputTokens, stopReason) {
|
|
82479
|
+
if (!this.engine.isStreaming) return null;
|
|
82480
|
+
this.engine.reconcileTotal(outputTokens);
|
|
82481
|
+
const durationMs = this.engine.elapsedMs;
|
|
82482
|
+
const tokens = this.engine.tokenCount;
|
|
82483
|
+
const rawAvgTokS = durationMs > 0 ? tokens / (durationMs / 1e3) : null;
|
|
82484
|
+
const tokS = this.engine.sanitizeTokS(rawAvgTokS, durationMs);
|
|
82485
|
+
this.lastStableTokS = tokS;
|
|
82486
|
+
this.engine.stop();
|
|
82487
|
+
if (tokS !== null && isSuccessfulStop(stopReason)) {
|
|
82488
|
+
this.sessionOutputTokens += tokens;
|
|
82489
|
+
this.sessionDurationMs += durationMs;
|
|
82490
|
+
}
|
|
82491
|
+
return { outputTokens: tokens, durationMs, tokS };
|
|
82492
|
+
}
|
|
82493
|
+
};
|
|
82494
|
+
var SpeedAnimator = class {
|
|
82495
|
+
from = null;
|
|
82496
|
+
target = null;
|
|
82497
|
+
startedAt = 0;
|
|
82498
|
+
durationMs;
|
|
82499
|
+
constructor(durationMs) {
|
|
82500
|
+
this.durationMs = durationMs;
|
|
82501
|
+
}
|
|
82502
|
+
updateDuration(durationMs) {
|
|
82503
|
+
this.durationMs = durationMs;
|
|
82504
|
+
}
|
|
82505
|
+
reset(value = null, now = Date.now()) {
|
|
82506
|
+
this.from = value;
|
|
82507
|
+
this.target = value;
|
|
82508
|
+
this.startedAt = now;
|
|
82509
|
+
}
|
|
82510
|
+
setTarget(target, now = Date.now()) {
|
|
82511
|
+
if (target === null) {
|
|
82512
|
+
this.reset(null, now);
|
|
82513
|
+
return null;
|
|
82514
|
+
}
|
|
82515
|
+
const current2 = this.value(now);
|
|
82516
|
+
if (current2 === null) {
|
|
82517
|
+
this.reset(target, now);
|
|
82518
|
+
return target;
|
|
82519
|
+
}
|
|
82520
|
+
if (this.target !== null && Math.abs(target - this.target) < 0.05) return current2;
|
|
82521
|
+
this.from = current2;
|
|
82522
|
+
this.target = target;
|
|
82523
|
+
this.startedAt = now;
|
|
82524
|
+
return current2;
|
|
82525
|
+
}
|
|
82526
|
+
value(now = Date.now()) {
|
|
82527
|
+
if (this.target === null) return null;
|
|
82528
|
+
if (this.from === null || this.durationMs <= 0) return this.target;
|
|
82529
|
+
const progress = Math.max(0, Math.min(1, (now - this.startedAt) / this.durationMs));
|
|
82530
|
+
if (progress >= 1) {
|
|
82531
|
+
this.from = this.target;
|
|
82532
|
+
return this.target;
|
|
82533
|
+
}
|
|
82534
|
+
return this.from + (this.target - this.from) * progress;
|
|
82535
|
+
}
|
|
82536
|
+
isAnimating(now = Date.now()) {
|
|
82537
|
+
return this.target !== null && this.from !== null && Math.abs(this.target - this.from) >= 0.05 && now - this.startedAt < this.durationMs;
|
|
82538
|
+
}
|
|
82539
|
+
};
|
|
82540
|
+
|
|
82541
|
+
// src/extension/crew-vibes/index.ts
|
|
82542
|
+
function isAssistantMessage(message) {
|
|
82543
|
+
return typeof message === "object" && message !== null && message.role === "assistant";
|
|
82544
|
+
}
|
|
82545
|
+
function assistantUsageOutput(message) {
|
|
82546
|
+
const usage = message.usage;
|
|
82547
|
+
const output = usage?.output;
|
|
82548
|
+
return typeof output === "number" && Number.isFinite(output) ? output : void 0;
|
|
82549
|
+
}
|
|
82550
|
+
function assistantStopReason(message) {
|
|
82551
|
+
const reason = message.stopReason;
|
|
82552
|
+
return typeof reason === "string" ? reason : void 0;
|
|
82553
|
+
}
|
|
82554
|
+
function assistantEventType(event) {
|
|
82555
|
+
return typeof event.type === "string" ? event.type : void 0;
|
|
82556
|
+
}
|
|
82557
|
+
function registerCrewVibes(pi) {
|
|
82558
|
+
let config = loadConfig2();
|
|
82559
|
+
let lastRenderedAt = 0;
|
|
82560
|
+
let currentIntervalMs = 0;
|
|
82561
|
+
const speedTracker = new SpeedTracker(config.speed);
|
|
82562
|
+
const footerAnimator = new SpeedAnimator(config.speed.renderIntervalMs);
|
|
82563
|
+
let liveTimer;
|
|
82564
|
+
let footerTimer;
|
|
82565
|
+
let capacityTimer;
|
|
82566
|
+
let providerTimer;
|
|
82567
|
+
let lastProviderText;
|
|
82568
|
+
let currentProvider;
|
|
82569
|
+
function visibleLen(text) {
|
|
82570
|
+
return text.replace(/\x1b\[[0-9;]*m/g, "").length;
|
|
82571
|
+
}
|
|
82572
|
+
function spreadLine(left, right) {
|
|
82573
|
+
const cols = process.stdout.columns || 120;
|
|
82574
|
+
const padding = Math.max(2, cols - visibleLen(left) - visibleLen(right));
|
|
82575
|
+
return left + "\xA0".repeat(padding) + right;
|
|
82576
|
+
}
|
|
82577
|
+
function themeOf(ctx) {
|
|
82578
|
+
return asCrewTheme2(ctx.hasUI ? ctx.ui.theme : void 0);
|
|
82579
|
+
}
|
|
82580
|
+
function publishCapacity(ctx) {
|
|
82581
|
+
if (!ctx?.hasUI) return;
|
|
82582
|
+
if (!config.enabled || !config.capacity.enabled) {
|
|
82583
|
+
setCapacityStatus(ctx, config, void 0);
|
|
82584
|
+
return;
|
|
82585
|
+
}
|
|
82586
|
+
const capText = renderCapacity(themeOf(ctx), config.capacity, getCapacityUsage(ctx));
|
|
82587
|
+
const combined = lastProviderText ? spreadLine(capText, lastProviderText) : capText;
|
|
82588
|
+
setCapacityStatus(ctx, config, combined);
|
|
82589
|
+
}
|
|
82590
|
+
function publishSpeedFooter(ctx, speed = footerAnimator.value()) {
|
|
82591
|
+
if (!config.enabled || !config.speed.enabled || !config.speed.footer) {
|
|
82592
|
+
setSpeedStatus(ctx, config, void 0);
|
|
82593
|
+
return;
|
|
82594
|
+
}
|
|
82595
|
+
setSpeedStatus(ctx, config, renderSpeedFooter(themeOf(ctx), config.speed, speed));
|
|
82596
|
+
}
|
|
82597
|
+
function applyIndicator(ctx, speed, force = false) {
|
|
82598
|
+
if (!ctx.hasUI || !ctx.ui.setWorkingIndicator) return;
|
|
82599
|
+
if (!config.enabled || !config.speed.enabled || !config.speed.indicator) {
|
|
82600
|
+
ctx.ui.setWorkingIndicator();
|
|
82601
|
+
return;
|
|
82602
|
+
}
|
|
82603
|
+
const next = intervalForSpeed(config.speed, speed);
|
|
82604
|
+
if (!force && Math.abs(next - currentIntervalMs) < 10) return;
|
|
82605
|
+
ctx.ui.setWorkingIndicator({
|
|
82606
|
+
frames: crewIndicatorFrames(themeOf(ctx)),
|
|
82607
|
+
intervalMs: next
|
|
82608
|
+
});
|
|
82609
|
+
currentIntervalMs = next;
|
|
82610
|
+
}
|
|
82611
|
+
function renderWorking(ctx, speed) {
|
|
82612
|
+
if (!config.enabled || !config.speed.enabled || !ctx.hasUI) return;
|
|
82613
|
+
ctx.ui.setWorkingMessage(renderWorkingMessage(themeOf(ctx), config.speed, speed));
|
|
82614
|
+
}
|
|
82615
|
+
function stopLiveTimer() {
|
|
82616
|
+
if (!liveTimer) return;
|
|
82617
|
+
clearInterval(liveTimer);
|
|
82618
|
+
liveTimer = void 0;
|
|
82619
|
+
}
|
|
82620
|
+
function stopFooterTimer() {
|
|
82621
|
+
if (!footerTimer) return;
|
|
82622
|
+
clearInterval(footerTimer);
|
|
82623
|
+
footerTimer = void 0;
|
|
82624
|
+
}
|
|
82625
|
+
function stopCapacityTimer() {
|
|
82626
|
+
if (!capacityTimer) return;
|
|
82627
|
+
clearInterval(capacityTimer);
|
|
82628
|
+
capacityTimer = void 0;
|
|
82629
|
+
}
|
|
82630
|
+
function stopProviderTimer() {
|
|
82631
|
+
if (!providerTimer) return;
|
|
82632
|
+
clearInterval(providerTimer);
|
|
82633
|
+
providerTimer = void 0;
|
|
82634
|
+
}
|
|
82635
|
+
function startLiveTimer(ctx) {
|
|
82636
|
+
if (liveTimer || !ctx.hasUI) return;
|
|
82637
|
+
liveTimer = setInterval(() => {
|
|
82638
|
+
if (!config.enabled || !config.speed.enabled || !speedTracker.isStreaming) {
|
|
82639
|
+
stopLiveTimer();
|
|
82640
|
+
return;
|
|
82641
|
+
}
|
|
82642
|
+
const speed = speedTracker.liveTokS();
|
|
82643
|
+
applyIndicator(ctx, speed);
|
|
82644
|
+
renderWorking(ctx, speed);
|
|
82645
|
+
}, config.speed.renderIntervalMs);
|
|
82646
|
+
liveTimer.unref?.();
|
|
82647
|
+
}
|
|
82648
|
+
function startFooterTimer(ctx) {
|
|
82649
|
+
if (footerTimer || !ctx.hasUI) return;
|
|
82650
|
+
footerTimer = setInterval(() => {
|
|
82651
|
+
if (!config.enabled || !config.speed.enabled) {
|
|
82652
|
+
stopFooterTimer();
|
|
82653
|
+
return;
|
|
82654
|
+
}
|
|
82655
|
+
publishSpeedFooter(ctx);
|
|
82656
|
+
if (!footerAnimator.isAnimating()) stopFooterTimer();
|
|
82657
|
+
}, config.speed.renderIntervalMs);
|
|
82658
|
+
footerTimer.unref?.();
|
|
82659
|
+
}
|
|
82660
|
+
function startCapacityTimer(ctx) {
|
|
82661
|
+
if (capacityTimer) return;
|
|
82662
|
+
const interval = Math.max(250, config.capacity.refreshIntervalMs);
|
|
82663
|
+
capacityTimer = setInterval(() => publishCapacity(ctx), interval);
|
|
82664
|
+
capacityTimer.unref?.();
|
|
82665
|
+
}
|
|
82666
|
+
function startProviderTimer(ctx) {
|
|
82667
|
+
if (providerTimer) return;
|
|
82668
|
+
if (!config.capacity.providerUsage) return;
|
|
82669
|
+
const interval = Math.max(1e4, config.capacity.providerRefreshMs);
|
|
82670
|
+
async function tick() {
|
|
82671
|
+
if (!config.enabled || !config.capacity.providerUsage) {
|
|
82672
|
+
stopProviderTimer();
|
|
82673
|
+
return;
|
|
82674
|
+
}
|
|
82675
|
+
try {
|
|
82676
|
+
const usage = await fetchProviderUsage(config.capacity.providerRefreshMs, currentProvider);
|
|
82677
|
+
lastProviderText = renderProviderUsage(themeOf(ctx), usage);
|
|
82678
|
+
publishCapacity(ctx);
|
|
82679
|
+
} catch {
|
|
82680
|
+
lastProviderText = void 0;
|
|
82681
|
+
publishCapacity(ctx);
|
|
82682
|
+
}
|
|
82683
|
+
}
|
|
82684
|
+
tick();
|
|
82685
|
+
providerTimer = setInterval(tick, interval);
|
|
82686
|
+
providerTimer.unref?.();
|
|
82687
|
+
}
|
|
82688
|
+
function resetWorking(ctx) {
|
|
82689
|
+
applyIndicator(ctx, null, true);
|
|
82690
|
+
renderWorking(ctx, speedTracker.lastTokS);
|
|
82691
|
+
}
|
|
82692
|
+
function applyConfig(ctx) {
|
|
82693
|
+
saveConfig(config);
|
|
82694
|
+
speedTracker.updateConfig(config.speed);
|
|
82695
|
+
footerAnimator.updateDuration(config.speed.renderIntervalMs);
|
|
82696
|
+
if (!config.enabled) {
|
|
82697
|
+
stopLiveTimer();
|
|
82698
|
+
stopFooterTimer();
|
|
82699
|
+
stopCapacityTimer();
|
|
82700
|
+
stopProviderTimer();
|
|
82701
|
+
clearVibesStatus(ctx);
|
|
82702
|
+
return;
|
|
82703
|
+
}
|
|
82704
|
+
publishCapacity(ctx);
|
|
82705
|
+
publishSpeedFooter(ctx);
|
|
82706
|
+
if (config.capacity.providerUsage) startProviderTimer(ctx);
|
|
82707
|
+
}
|
|
82708
|
+
pi.on("session_start", (_event, ctx) => {
|
|
82709
|
+
stopLiveTimer();
|
|
82710
|
+
stopFooterTimer();
|
|
82711
|
+
stopCapacityTimer();
|
|
82712
|
+
stopProviderTimer();
|
|
82713
|
+
config = loadConfig2();
|
|
82714
|
+
speedTracker.updateConfig(config.speed);
|
|
82715
|
+
footerAnimator.updateDuration(config.speed.renderIntervalMs);
|
|
82716
|
+
speedTracker.resetSession();
|
|
82717
|
+
footerAnimator.reset(null);
|
|
82718
|
+
clearProviderUsageCache();
|
|
82719
|
+
currentProvider = ctx.model?.provider;
|
|
82720
|
+
if (!config.enabled) {
|
|
82721
|
+
clearVibesStatus(ctx);
|
|
82722
|
+
return;
|
|
82723
|
+
}
|
|
82724
|
+
publishCapacity(ctx);
|
|
82725
|
+
publishSpeedFooter(ctx);
|
|
82726
|
+
startCapacityTimer(ctx);
|
|
82727
|
+
startProviderTimer(ctx);
|
|
82728
|
+
applyIndicator(ctx, null, true);
|
|
82729
|
+
});
|
|
82730
|
+
pi.on("agent_start", (_event, ctx) => {
|
|
82731
|
+
if (!config.enabled) return;
|
|
82732
|
+
resetWorking(ctx);
|
|
82733
|
+
});
|
|
82734
|
+
pi.on("turn_start", (_event, ctx) => {
|
|
82735
|
+
if (!config.enabled) return;
|
|
82736
|
+
resetWorking(ctx);
|
|
82737
|
+
});
|
|
82738
|
+
pi.on("message_start", (event, ctx) => {
|
|
82739
|
+
if (!config.enabled || !config.speed.enabled || !isAssistantMessage(event.message)) return;
|
|
82740
|
+
speedTracker.startMessage();
|
|
82741
|
+
footerAnimator.reset(speedTracker.lastTokS);
|
|
82742
|
+
startLiveTimer(ctx);
|
|
82743
|
+
lastRenderedAt = 0;
|
|
82744
|
+
});
|
|
82745
|
+
pi.on("message_update", (event, ctx) => {
|
|
82746
|
+
if (!config.enabled || !config.speed.enabled || !isAssistantMessage(event.message) || !speedTracker.isStreaming) return;
|
|
82747
|
+
const ev = event.assistantMessageEvent;
|
|
82748
|
+
const type = assistantEventType(ev);
|
|
82749
|
+
if (type === "text_delta" || type === "thinking_delta") {
|
|
82750
|
+
const delta = ev.delta ?? "";
|
|
82751
|
+
speedTracker.recordDelta(delta, assistantUsageOutput(event.message));
|
|
82752
|
+
}
|
|
82753
|
+
if (type === "start") resetWorking(ctx);
|
|
82754
|
+
const now = Date.now();
|
|
82755
|
+
if (now - lastRenderedAt < config.speed.renderIntervalMs && type !== "done") return;
|
|
82756
|
+
lastRenderedAt = now;
|
|
82757
|
+
const speed = speedTracker.liveTokS();
|
|
82758
|
+
applyIndicator(ctx, speed);
|
|
82759
|
+
renderWorking(ctx, speed);
|
|
82760
|
+
});
|
|
82761
|
+
pi.on("message_end", (event, ctx) => {
|
|
82762
|
+
if (!isAssistantMessage(event.message)) return;
|
|
82763
|
+
publishCapacity(ctx);
|
|
82764
|
+
if (!config.enabled || !config.speed.enabled || !speedTracker.isStreaming) return;
|
|
82765
|
+
const completed = speedTracker.finishMessage(assistantUsageOutput(event.message) ?? 0, assistantStopReason(event.message));
|
|
82766
|
+
if (!completed) return;
|
|
82767
|
+
footerAnimator.setTarget(speedTracker.sessionAvgTokS());
|
|
82768
|
+
publishSpeedFooter(ctx);
|
|
82769
|
+
startFooterTimer(ctx);
|
|
82770
|
+
applyIndicator(ctx, speedTracker.lastTokS);
|
|
82771
|
+
});
|
|
82772
|
+
pi.on("turn_end", () => {
|
|
82773
|
+
speedTracker.stopMessage();
|
|
82774
|
+
stopLiveTimer();
|
|
82775
|
+
});
|
|
82776
|
+
pi.on("agent_end", (_event, ctx) => {
|
|
82777
|
+
speedTracker.stopMessage();
|
|
82778
|
+
stopLiveTimer();
|
|
82779
|
+
if (ctx && config.enabled && ctx.hasUI) {
|
|
82780
|
+
applyIndicator(ctx, speedTracker.lastTokS);
|
|
82781
|
+
ctx.ui.setWorkingMessage();
|
|
82782
|
+
}
|
|
82783
|
+
});
|
|
82784
|
+
pi.on("model_select", (event, ctx) => {
|
|
82785
|
+
currentProvider = event.model?.provider;
|
|
82786
|
+
clearProviderUsageCache();
|
|
82787
|
+
publishCapacity(ctx);
|
|
82788
|
+
});
|
|
82789
|
+
pi.on("session_compact", (_event, ctx) => publishCapacity(ctx));
|
|
82790
|
+
pi.on("session_tree", (_event, ctx) => publishCapacity(ctx));
|
|
82791
|
+
pi.on("session_shutdown", (_event, ctx) => {
|
|
82792
|
+
stopLiveTimer();
|
|
82793
|
+
stopFooterTimer();
|
|
82794
|
+
stopCapacityTimer();
|
|
82795
|
+
stopProviderTimer();
|
|
82796
|
+
clearVibesStatus(ctx);
|
|
82797
|
+
});
|
|
82798
|
+
async function handleCommand(args, ctx) {
|
|
82799
|
+
const tokens = args.trim().split(/\s+/).filter(Boolean);
|
|
82800
|
+
const [first, second] = tokens;
|
|
82801
|
+
const mutate = (next) => {
|
|
82802
|
+
config = next;
|
|
82803
|
+
applyConfig(ctx);
|
|
82804
|
+
};
|
|
82805
|
+
if (!first) {
|
|
82806
|
+
const speed = speedTracker.liveTokS();
|
|
82807
|
+
const usage = getCapacityUsage(ctx);
|
|
82808
|
+
const stage = config.capacity.icons.length ? config.capacity.labels[Math.max(
|
|
82809
|
+
0,
|
|
82810
|
+
Math.min(
|
|
82811
|
+
config.capacity.labels.length - 1,
|
|
82812
|
+
Math.floor((usage.percent ?? 0) / 100 * config.capacity.labels.length)
|
|
82813
|
+
)
|
|
82814
|
+
)] : "?";
|
|
82815
|
+
ctx.ui.notify(
|
|
82816
|
+
`crew-vibes: ${config.enabled ? "on" : "off"} \xB7 speed ${config.speed.enabled ? "on" : "off"} (${formatSpeed(config.speed, speed)}) \xB7 capacity ${config.capacity.enabled ? "on" : "off"} (${stage})`,
|
|
82817
|
+
"info"
|
|
82818
|
+
);
|
|
82819
|
+
return;
|
|
82820
|
+
}
|
|
82821
|
+
if (first === "on" || first === "off") {
|
|
82822
|
+
mutate({ ...config, enabled: first === "on" });
|
|
82823
|
+
ctx.ui.notify(`crew-vibes ${first === "on" ? "enabled" : "disabled"}`, "info");
|
|
82824
|
+
return;
|
|
82825
|
+
}
|
|
82826
|
+
if (first === "speed" && (second === "on" || second === "off")) {
|
|
82827
|
+
mutate({ ...config, speed: { ...config.speed, enabled: second === "on" } });
|
|
82828
|
+
ctx.ui.notify(`crew-vibes speed ${second === "on" ? "enabled" : "disabled"}`, "info");
|
|
82829
|
+
return;
|
|
82830
|
+
}
|
|
82831
|
+
if (first === "capacity" && (second === "on" || second === "off")) {
|
|
82832
|
+
mutate({ ...config, capacity: { ...config.capacity, enabled: second === "on" } });
|
|
82833
|
+
ctx.ui.notify(`crew-vibes capacity ${second === "on" ? "enabled" : "disabled"}`, "info");
|
|
82834
|
+
return;
|
|
82835
|
+
}
|
|
82836
|
+
ctx.ui.notify("Usage: /team-vibes [on|off|speed on|off|capacity on|off]", "error");
|
|
82837
|
+
}
|
|
82838
|
+
pi.registerCommand("team-vibes", {
|
|
82839
|
+
description: "Toggle crew-vibes speed + context meters (on/off, speed, capacity)",
|
|
82840
|
+
handler: handleCommand
|
|
82841
|
+
});
|
|
82842
|
+
}
|
|
82843
|
+
|
|
81481
82844
|
// src/extension/cross-extension-rpc.ts
|
|
81482
82845
|
init_safe_paths();
|
|
81483
82846
|
|
|
@@ -83617,6 +84980,11 @@ Subagent may need manual intervention.`
|
|
|
83617
84980
|
registerContextStatusInjection(pi, {
|
|
83618
84981
|
enabled: loadConfig(process.cwd()).config.reliability?.ambientStatusInjection !== false
|
|
83619
84982
|
});
|
|
84983
|
+
try {
|
|
84984
|
+
registerCrewVibes(pi);
|
|
84985
|
+
} catch (err2) {
|
|
84986
|
+
console.warn("[pi-crew] crew-vibes initialization failed:", err2 instanceof Error ? err2.message : err2);
|
|
84987
|
+
}
|
|
83620
84988
|
}
|
|
83621
84989
|
|
|
83622
84990
|
// index.bundle.ts
|