pi-crew 0.9.62 → 0.9.64
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 +92 -0
- package/README.md +1 -0
- package/agents/critic.md +1 -1
- package/agents/explorer.md +1 -1
- package/agents/planner.md +1 -1
- package/agents/reviewer.md +1 -1
- package/agents/security-reviewer.md +1 -1
- package/agents/test-engineer.md +1 -1
- package/agents/writer.md +1 -1
- package/dist/index.mjs +162 -67
- package/package.json +5 -2
- package/src/agents/agent-config.ts +4 -0
- package/src/agents/agent-serializer.ts +1 -0
- package/src/agents/discover-agents.ts +8 -0
- package/src/config/role-tools.ts +49 -1
- package/src/prompt/prompt-runtime.ts +6 -0
- package/src/prompt/scratchpad-lifecycle.ts +605 -0
- package/src/runtime/child-pi/child-pi-spawn.ts +42 -1
- package/src/runtime/child-pi/child-pi.ts +5 -0
- package/src/runtime/model/pi-args.ts +1 -1
- package/src/runtime/recovery/crash-recovery.ts +1 -1
- package/src/runtime/scratchpad/README.md +184 -0
- package/src/runtime/scratchpad/engine.ts +610 -0
- package/src/runtime/scratchpad/guest.ts +360 -0
- package/src/runtime/scratchpad/index.ts +22 -0
- package/src/runtime/scratchpad/protocol.ts +88 -0
- package/src/runtime/scratchpad/snapshot-lookup.ts +74 -0
- package/src/runtime/scratchpad/transform.ts +363 -0
- package/src/runtime/task-runner/child-executor.ts +48 -31
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,98 @@
|
|
|
2
2
|
|
|
3
3
|
> **Note:** `atomic-write-v2.ts` / `AtomicWriter` mentioned in historical entries below was consolidated into `atomic-write.ts` as of v0.9.42. This changelog is preserved as historical record — the migration was completed (the v2 class was never adopted; v1 won on simplicity + symlink-safety + link+unlink atomicity). See `docs/migration/atomic-write-v2-migration.md` for the decision rationale.
|
|
4
4
|
|
|
5
|
+
## [0.9.64] — pi-rlm→pi-crew pattern transfer: worker scratchpad + crash-resume + cancellation + quick wins (2026-08-09)
|
|
6
|
+
|
|
7
|
+
### Quick Wins (patterns 17/19/20/11 + spike CI)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
- **Schema-driven docs (QW17)**: `agents/*.md` frontmatter `tools:` now matches the
|
|
11
|
+
enforced `ROLE_TOOL_CONFIGS` (4 drifts fixed); a sync-test pins the derivation;
|
|
12
|
+
`scripts/gen-role-tools-docs.mjs` renders `docs/role-tools.md` from the source.
|
|
13
|
+
- **Retry-resume contract suite (QW19)**: pins `executeWithRetry` (`?`-glob, empty-
|
|
14
|
+
retryableErrors, maxAttempts:0, abort-during-sleep, default attemptId),
|
|
15
|
+
`FileCheckpointStore` (corrupt-file quarantine, list-skip, wrong-runId delete),
|
|
16
|
+
and exports `shouldRecoverTask` for direct testing.
|
|
17
|
+
- **Failure-mode inventory (QW20)**: `docs/failure-mode-inventory.md` maps the 7
|
|
18
|
+
pi-rlm failure modes to pi-crew handlers (wedge gap closed by Phase 1
|
|
19
|
+
ping-before-execute; EPIPE/timeout interplay declared as gaps).
|
|
20
|
+
- **Error-as-data contract (QW11)**: `evidenceStatusFor` + `attemptErrorFor`
|
|
21
|
+
extracted as pure functions from `runChildProcessTask`; contract test pins the
|
|
22
|
+
precedence (cancelled > failed > completed; E007 timedOut override; 429 gated).
|
|
23
|
+
- **`test:spike` script**: wires the scratchpad spike tests into CI.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Phase 3 cancellation hardening (experimental)
|
|
27
|
+
|
|
28
|
+
### Features
|
|
29
|
+
|
|
30
|
+
- **Atomic snapshot write (D2')**: `engine.snapshotState` now writes via
|
|
31
|
+
`temp + rename` (same directory), eliminating the theoretical torn-write race
|
|
32
|
+
between the debounce timer and the F3 quit flush.
|
|
33
|
+
- **Kill-and-restore verified**: the existing SIGTERM → pi print-mode dispose →
|
|
34
|
+
`session_shutdown` reason:"quit" → F3 flush chain already captures a fresh
|
|
35
|
+
snapshot on worker kill (no new handler required). Documented + pinned by a
|
|
36
|
+
gated real-worker test.
|
|
37
|
+
- **EngineBusyError: deliberately skipped** — ping-before-execute already
|
|
38
|
+
detects a wedged guest; the FIFO execute queue makes a busy-reject redundant.
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### Phase 2 crash-resume (experimental)
|
|
42
|
+
|
|
43
|
+
### Features
|
|
44
|
+
|
|
45
|
+
- **Cross-attempt restore (crash-resume)**: a scratchpad worker attempt N+1 (retry
|
|
46
|
+
/ crash-recovery re-queue / manual re-run) automatically revives the namespace
|
|
47
|
+
from the previous attempt's redacted snapshot artifact — via a single
|
|
48
|
+
spawn-time lookup (`findLatestScratchpadSnapshot`), no retry-loop / recovery
|
|
49
|
+
changes needed. Restores lazily on the first `execute` call (D7 lazy invariant
|
|
50
|
+
kept) with a one-line model-visible notice.
|
|
51
|
+
- Lookup: latest mtime (model-fallback index resets each retry round → number
|
|
52
|
+
is not write-order); tie-break lowest attempt = newest round.
|
|
53
|
+
- Security: read-time re-validation (containment + filename pattern + lstat +
|
|
54
|
+
size + mtime hint, D10); fail-open (D11) never breaks the worker; strict scan
|
|
55
|
+
(D12); base64 round-trip (D13); redacted secret → literal `"***"` (D4).
|
|
56
|
+
- **Guest zombie backstop (SEC-1)**: the engine now overrides
|
|
57
|
+
`PI_CREW_PARENT_PID=worker pid` for the guest (D5), so an orphaned guest
|
|
58
|
+
(worker SIGKILL'd) is flagged by the zombie scanner — pure inheritance left
|
|
59
|
+
guests LIVE forever holding provider keys + broker token.
|
|
60
|
+
- **Snapshot cap (D6)**: 4 MiB two-sided (write-side raw byteLength trim, read-
|
|
61
|
+
side file + per-var 256 KiB) bounds v8.deserialize amplification.
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
### Phase 1 worker scratchpad (experimental)
|
|
65
|
+
|
|
66
|
+
### Features
|
|
67
|
+
|
|
68
|
+
- **Worker stateful scratchpad (experimental)**: opt-in persistent Bun-free JS
|
|
69
|
+
evaluator (`execute` tool) for workers, ported from the pi-rlm pattern.
|
|
70
|
+
State (variables, parsed data) compounds across `execute` calls within a task
|
|
71
|
+
attempt — intermediate results live in a namespace instead of being re-derived
|
|
72
|
+
from transcript text. Snapshot per-attempt into the run artifact store
|
|
73
|
+
(redacted + atomic) prepares the ground for Phase 2 crash-resume.
|
|
74
|
+
- Opt-in per role: `executor`, `test-engineer`, `verifier` (default on); other
|
|
75
|
+
roles via agent frontmatter `scratchpad: true` (write roles only).
|
|
76
|
+
- Security: S-6 read-only roles are gated out regardless of frontmatter
|
|
77
|
+
(privilege-elevation guard); F6 `scratchpad: false` is an explicit kill-switch;
|
|
78
|
+
raw snapshots never land in the artifact root (temp dir → redacted
|
|
79
|
+
`writeArtifact`).
|
|
80
|
+
- Dormant by default: only active when `PI_CREW_SCRATCHPAD=1` is set by the
|
|
81
|
+
spawner; zero behavior change for non-opt-in workers.
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
## [0.9.63] — built-in performance observability + local-path provider-extension discovery (2026-08-08)
|
|
85
|
+
|
|
86
|
+
### Features
|
|
87
|
+
|
|
88
|
+
- **Built-in performance observability (byte-built-in, always-on).** Every team run now auto-attaches a detached resource sampler and auto-generates a detailed performance report on completion — no separate benchmark harness needed. Toggle per-team via frontmatter `observability: true|false` (default `true` for parsed team files; direct-object `TeamConfig` fixtures stay unset for test isolation).
|
|
89
|
+
- **Live resource sampler** (`scripts/resource-sampler.mjs`): samples CPU/RSS per-PID every 2s via ppid-tree attribution (root runner + all child workers, including respawns), with PID-reuse guard (`/proc` starttime), first-sample CPU exclusion, and **6 live warning categories** — `high_cpu` (≥300%), `rss_jump` (+200MB/interval), `rss_high` (≥1GB), `rss_leak` (window-30 monotonic +100MB), `proc_died`, `proc_zombie`. Rate-limited (10s/pid/category); `--no-live-warn` flag to silence.
|
|
90
|
+
- **Post-hoc analyzer** (`scripts/analyze-run.mjs`): combines `events.jsonl` + transcripts + `resources.jsonl` into a markdown report at `docs/perf-report-<runId>.md` with **22 anomaly categories** (task_failed, model_retry/model_cascade, large_gap, slow_phase, launch_delay, drain_stall, token_imbalance, no_cache, worker_respawn_churn, api_error_storm, zero_output_completion, sustained_cpu, transient_cpu/rss_spike, rss_growth, run_not_completed, high_failure_rate, run_idle, cost_unreported, missing_transcript, sampler_gap, tool_churn), a per-subagent timeline (launch / respawn / startup / active-work / drain / finalize), and token/cost/model attribution. Optional `--agents` flag emits per-agent breakdowns.
|
|
91
|
+
- **Runtime wiring** (`src/runtime/team-runner.ts`): `startPerfSampler` spawns the sampler detached + `unref`'d (death never affects the run); `schedulePerfAnalyze` runs the analyzer +3s after `after_run_complete` via an `unref`'d `setTimeout` (never blocks run completion). Strict `observability !== true` keeps test fixtures from spawning. The sampler auto-stops when the run manifest reaches a terminal status (`--watch-run` mode).
|
|
92
|
+
- **Overhead ≈ 0** (measured A/B): sampler ~0.05% of one core, 56MB RSS fixed; analyzer ~72ms one-shot after run; ~32KB artifacts/run. Verified end-to-end on real runs — see `docs/real-test/reports/real-test-2026-08-07-perf-obs-overhead.md`.
|
|
93
|
+
|
|
94
|
+
### Bug fixes
|
|
95
|
+
|
|
96
|
+
- **Local-path provider extensions were not discovered for child workers (oc-go and any `pi install <local-path>` provider went "Model not found").** `discoverProviderExtensions` only resolved `npm:` specs from `~/.pi/agent/settings.json` `packages`, skipping local-path specs (e.g. `../../source/my_pi/source/pi-other-provider`) on the assumption that local paths were the pi-crew extension itself. That assumption was wrong for local provider extensions: `--no-extensions` in `buildPiWorkerArgs` stripped the provider from every child spawn → every model from that provider hit `Error: Model "…" not found` → the fallback chain burned 5 spawn-fails (~10s) per task before landing on a builtin provider. Fix: resolve local-path specs (`./`, `../`, absolute) relative to the settings.json dir — same trust level as `npm:` (settings packages are a sanctioned channel written by `pi install`); skip the pi-crew package itself via `packageRoot()` (a worker must not re-load the orchestrator). **SEC-1 preserved** (project/project-pi AGENT extensions in `.crew/agents/*.md` frontmatter stay gated — that is a separate, untrusted channel). Tests in `test/unit/runtime/model/provider-extensions.test.ts`. Investigation + correction of the earlier "hidden models" mis-attribution in `docs/real-test/reports/real-test-2026-08-08-provider-ext-local-path.md`.
|
|
5
97
|
|
|
6
98
|
## [0.9.62] — provider-quota attribution per live-session agent + dead-worker alert re-fire fix (2026-08-06)
|
|
7
99
|
|
package/README.md
CHANGED
|
@@ -69,6 +69,7 @@ repo: https://github.com/baphuongna/pi-crew
|
|
|
69
69
|
- **Durable event replay** (L1, v0.9.8) — `RunEventBus.onWithReplay()` catches up a re-subscribing dashboard/overlay with events it missed during transient absence (toggle, reconnect), replaying from the durable JSONL log with seq-based dedup. No information loss even if the live subscriber was briefly gone.
|
|
70
70
|
- **Lossless-by-default output handling** (L4, v0.9.8) — worker output thresholds sized from measured data (100% of real outputs fit without compaction); when compaction is unavoidable it keeps head+tail (preserves closing code fences/headings) instead of head-only truncation. No more `[pi-crew compacted N chars]` markers eating the end of a worker's result.
|
|
71
71
|
- **Inter-pi broker** (v0.9.47, default-on) — a Unix-domain-socket message bus that lets concurrently-running Pi sessions pass messages, steering notes, and task-status events to each other. **On by default** on Linux + macOS; auto-disabled on native Windows (no unix socket). Three independent kill switches: `broker.enabled: false` (config), `PI_CREW_BROKER=0` (env, always wins), Windows auto-disable. See [docs/decisions/2026-07-22-broker-phase4-gated-on.md](docs/decisions/2026-07-22-broker-phase4-gated-on.md).
|
|
72
|
+
- **Worker stateful scratchpad** (experimental, opt-in per role) — `executor` / `test-engineer` / `verifier` workers get a `scratchpad` tool: a persistent Bun-free JS evaluator whose namespace **compounds across calls within a task attempt** (variables set in one cell are visible in the next), so intermediate results live in memory instead of being re-derived from the transcript. Snapshots are flushed (redacted, atomic) per-attempt into the artifact store; the next attempt (retry / crash-recovery re-queue / re-run) **automatically revives the namespace** from the latest snapshot. Dormant by default (armed only when the spawner sets `PI_CREW_SCRATCHPAD=1`); zero behavior change for non-opt-in workers. Ported from the `@shift-labs/pi-rlm` pattern. See [src/runtime/scratchpad/README.md](src/runtime/scratchpad/README.md) (Phase 1-3 design, env keys, guards, threat model).
|
|
72
73
|
- **`test:critical` + `real-test-pi-crew` skill** (v0.9.47) — a curated 14-file / 97-test subset (`npm run test:critical`, ~20s) for fast in-loop verification, plus a bundled skill distilling the full 8-tier end-to-end verification discipline (unit → 3-path kill-switch proof → typecheck/bundle → live TUI probing → smoke team run). Prevents the verifier-worker hang that full `npm test` (>4 min) caused against the 300s worker timeout.
|
|
73
74
|
- **Provider extensions in subagents** (v0.9.57) — pi-crew spawns child-pi workers with `--no-extensions` (security posture), which made extension-registered providers (e.g. `pi-commandcode-provider`) unresolvable inside subagents. pi-crew now **auto-discovers provider packages** from `~/.pi/agent/settings.json` `packages` (npm: specs) and loads them via `--extension` in every builtin/user subagent — so **all provider models work in subagents**. An explicit `runtime.agentExtensions: string[]` config is an optional extra allowlist on top of auto-discovery. **SEC-1 preserved:** project/project-pi agents never receive these (env-gate unchanged).
|
|
74
75
|
|
package/agents/critic.md
CHANGED
|
@@ -5,7 +5,7 @@ model: false
|
|
|
5
5
|
systemPromptMode: replace
|
|
6
6
|
inheritProjectContext: true
|
|
7
7
|
inheritSkills: false
|
|
8
|
-
tools: read, grep, find, ls
|
|
8
|
+
tools: read, grep, find, ls, glob
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
You are a critical reviewer. Find flaws, missing steps, unsafe assumptions, overengineering, underengineering, and verification gaps. Return concrete fixes to the plan.
|
package/agents/explorer.md
CHANGED
|
@@ -5,7 +5,7 @@ model: false
|
|
|
5
5
|
systemPromptMode: replace
|
|
6
6
|
inheritProjectContext: true
|
|
7
7
|
inheritSkills: false
|
|
8
|
-
tools: read, grep, find, ls
|
|
8
|
+
tools: read, grep, find, ls, glob, bash
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
You are a fast codebase explorer. Map relevant files, symbols, data flow, and constraints. Do not modify files. Return concise findings with paths and evidence.
|
package/agents/planner.md
CHANGED
|
@@ -5,7 +5,7 @@ model: false
|
|
|
5
5
|
systemPromptMode: replace
|
|
6
6
|
inheritProjectContext: true
|
|
7
7
|
inheritSkills: false
|
|
8
|
-
tools: read, grep, find, ls
|
|
8
|
+
tools: read, grep, find, ls, glob
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
You are a planning specialist. Convert the goal and discovery notes into a concrete, ordered plan. Identify dependencies, risks, validation steps, and handoff instructions for implementers.
|
package/agents/reviewer.md
CHANGED
|
@@ -5,7 +5,7 @@ model: false
|
|
|
5
5
|
systemPromptMode: replace
|
|
6
6
|
inheritProjectContext: true
|
|
7
7
|
inheritSkills: false
|
|
8
|
-
tools: read, grep, find, ls, bash
|
|
8
|
+
tools: read, grep, find, ls, glob, bash
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
You are a code reviewer. Review the implementation for bugs, regressions, maintainability issues, missing tests, and project-rule violations. Return prioritized findings with evidence.
|
|
@@ -5,7 +5,7 @@ model: false
|
|
|
5
5
|
systemPromptMode: replace
|
|
6
6
|
inheritProjectContext: true
|
|
7
7
|
inheritSkills: false
|
|
8
|
-
tools: read, grep, find
|
|
8
|
+
tools: read, grep, find
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
You are a security reviewer. Look for injection, authn/authz flaws, insecure defaults, secret exposure, unsafe filesystem/network behavior, and dependency risks. Return severity and remediation.
|
package/agents/test-engineer.md
CHANGED
|
@@ -5,7 +5,7 @@ model: false
|
|
|
5
5
|
systemPromptMode: replace
|
|
6
6
|
inheritProjectContext: true
|
|
7
7
|
inheritSkills: false
|
|
8
|
-
tools: read,
|
|
8
|
+
tools: read, edit, write, bash, ls
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
You are a test engineer. Identify the right test level, add or adjust tests when asked, detect flaky assumptions, and report exact validation commands and results.
|
package/agents/writer.md
CHANGED
|
@@ -5,7 +5,7 @@ model: false
|
|
|
5
5
|
systemPromptMode: replace
|
|
6
6
|
inheritProjectContext: true
|
|
7
7
|
inheritSkills: false
|
|
8
|
-
tools: read,
|
|
8
|
+
tools: read, edit, write, ls
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
You are a documentation specialist. Produce clear, concise, maintainable docs and summaries. Preserve technical accuracy and avoid marketing fluff.
|
package/dist/index.mjs
CHANGED
|
@@ -11602,15 +11602,51 @@ var init_frontmatter = __esm({
|
|
|
11602
11602
|
}
|
|
11603
11603
|
});
|
|
11604
11604
|
|
|
11605
|
+
// src/runtime/role-permission.ts
|
|
11606
|
+
function permissionForRole(role) {
|
|
11607
|
+
if (READ_ONLY_ROLES.has(role)) return "read_only";
|
|
11608
|
+
if (WRITE_ROLES.has(role)) return "workspace_write";
|
|
11609
|
+
return "read_only";
|
|
11610
|
+
}
|
|
11611
|
+
function currentCrewRole(env = process.env) {
|
|
11612
|
+
return env.PI_CREW_ROLE?.trim() || env.PI_TEAMS_ROLE?.trim() || void 0;
|
|
11613
|
+
}
|
|
11614
|
+
function checkSubagentSpawnPermission(role) {
|
|
11615
|
+
if (!role) return { allowed: true, mode: "workspace_write" };
|
|
11616
|
+
const mode = permissionForRole(role);
|
|
11617
|
+
if (mode === "read_only")
|
|
11618
|
+
return {
|
|
11619
|
+
allowed: false,
|
|
11620
|
+
mode,
|
|
11621
|
+
reason: `Role '${role}' is read-only and cannot spawn additional subagents.`
|
|
11622
|
+
};
|
|
11623
|
+
return { allowed: true, mode };
|
|
11624
|
+
}
|
|
11625
|
+
var READ_ONLY_ROLES, WRITE_ROLES;
|
|
11626
|
+
var init_role_permission = __esm({
|
|
11627
|
+
"src/runtime/role-permission.ts"() {
|
|
11628
|
+
"use strict";
|
|
11629
|
+
READ_ONLY_ROLES = /* @__PURE__ */ new Set(["explorer", "reviewer", "security-reviewer", "analyst", "critic", "planner"]);
|
|
11630
|
+
WRITE_ROLES = /* @__PURE__ */ new Set(["executor", "test-engineer", "writer", "verifier", "agent", "cold-verifier", "chain-executor", "worker"]);
|
|
11631
|
+
}
|
|
11632
|
+
});
|
|
11633
|
+
|
|
11605
11634
|
// src/config/role-tools.ts
|
|
11606
11635
|
function getToolConfig(role) {
|
|
11607
11636
|
const key = role.includes("_") ? role.replaceAll("_", "-") : role;
|
|
11608
11637
|
return ROLE_TOOL_CONFIGS[key] ?? ROLE_TOOL_CONFIGS[role] ?? {};
|
|
11609
11638
|
}
|
|
11639
|
+
function isScratchpadEnabledForRole(role, agent) {
|
|
11640
|
+
const normalized = role.includes("_") ? role.replaceAll("_", "-") : role;
|
|
11641
|
+
if (permissionForRole(normalized) === "read_only") return false;
|
|
11642
|
+
if (agent?.scratchpad === false) return false;
|
|
11643
|
+
return agent?.scratchpad === true || getToolConfig(normalized).scratchpad === true;
|
|
11644
|
+
}
|
|
11610
11645
|
var ROLE_TOOL_CONFIGS;
|
|
11611
11646
|
var init_role_tools = __esm({
|
|
11612
11647
|
"src/config/role-tools.ts"() {
|
|
11613
11648
|
"use strict";
|
|
11649
|
+
init_role_permission();
|
|
11614
11650
|
ROLE_TOOL_CONFIGS = {
|
|
11615
11651
|
// Explorer - Read-only exploration; bash is included for git log/show
|
|
11616
11652
|
// (decisions stream needs commit-history mining) but edit/write stay
|
|
@@ -11641,9 +11677,11 @@ var init_role_tools = __esm({
|
|
|
11641
11677
|
tools: ["read", "grep", "find", "ls", "glob"],
|
|
11642
11678
|
excludeTools: ["edit", "write", "bash", "web"]
|
|
11643
11679
|
},
|
|
11644
|
-
// Executor - Full access (default)
|
|
11680
|
+
// Executor - Full access (default). Phase 1 scratchpad-enabled (stateful
|
|
11681
|
+
// evaluator compounds intermediate results across execute calls).
|
|
11645
11682
|
executor: {
|
|
11646
11683
|
// No restrictions - full tool access
|
|
11684
|
+
scratchpad: true
|
|
11647
11685
|
},
|
|
11648
11686
|
// Reviewer - Read and review, no write
|
|
11649
11687
|
reviewer: {
|
|
@@ -11670,12 +11708,16 @@ var init_role_tools = __esm({
|
|
|
11670
11708
|
// integrity is preserved during verification. Mirrors cold-verifier behavior.
|
|
11671
11709
|
verifier: {
|
|
11672
11710
|
tools: ["read", "grep", "find", "ls", "bash"],
|
|
11673
|
-
excludeTools: ["edit", "write", "web"]
|
|
11711
|
+
excludeTools: ["edit", "write", "web"],
|
|
11712
|
+
// Phase 1 scratchpad: multi-cell test/verify flows reuse parsed state.
|
|
11713
|
+
scratchpad: true
|
|
11674
11714
|
},
|
|
11675
11715
|
// Test Engineer - Can write tests (F1: hyphenated key)
|
|
11676
11716
|
"test-engineer": {
|
|
11677
11717
|
tools: ["read", "edit", "write", "bash", "ls"],
|
|
11678
|
-
excludeTools: ["web"]
|
|
11718
|
+
excludeTools: ["web"],
|
|
11719
|
+
// Phase 1 scratchpad: build/run test suites with state across cells.
|
|
11720
|
+
scratchpad: true
|
|
11679
11721
|
}
|
|
11680
11722
|
};
|
|
11681
11723
|
}
|
|
@@ -11891,6 +11933,14 @@ function parseAgentFile(filePath, source) {
|
|
|
11891
11933
|
fallbackModels: parseCsv(frontmatter.fallbackModels),
|
|
11892
11934
|
thinking: frontmatter.thinking === "false" ? void 0 : frontmatter.thinking || void 0,
|
|
11893
11935
|
tools: parseToolsField(frontmatter.tools),
|
|
11936
|
+
// Phase 1 scratchpad opt-in (Q3: pi ignores unknown frontmatter keys; pi-crew
|
|
11937
|
+
// is the sole consumer in the worker path — task arrives via -p, agent file
|
|
11938
|
+
// is not re-read by pi). 3-STATE parse (NOT `=== "true"` like
|
|
11939
|
+
// inheritProjectContext): omitted/malformed → undefined so the F6 kill-switch
|
|
11940
|
+
// (`agent.scratchpad === false`) only fires on an EXPLICIT `scratchpad: false`,
|
|
11941
|
+
// not on every agent without the key (which would wrongly kill role
|
|
11942
|
+
// default-on). Only the literal "true"/"false" are honored.
|
|
11943
|
+
scratchpad: frontmatter.scratchpad === "true" ? true : frontmatter.scratchpad === "false" ? false : void 0,
|
|
11894
11944
|
// SEC-1: Strip extensions/excludeExtensions for untrusted project-sourced
|
|
11895
11945
|
// agents (RCE prevention). Both `project` (.crew/agents/) and
|
|
11896
11946
|
// `project-pi` (.pi/agents/) are repo-adjacent / untrusted sources —
|
|
@@ -14860,6 +14910,55 @@ var init_env_filter = __esm({
|
|
|
14860
14910
|
}
|
|
14861
14911
|
});
|
|
14862
14912
|
|
|
14913
|
+
// src/runtime/scratchpad/snapshot-lookup.ts
|
|
14914
|
+
import { lstatSync as lstatSync5, readdirSync as readdirSync8 } from "node:fs";
|
|
14915
|
+
import { join as join18 } from "node:path";
|
|
14916
|
+
function findLatestScratchpadSnapshot(artifactsRoot, agentId) {
|
|
14917
|
+
const scratchpadDir = join18(artifactsRoot, "scratchpad");
|
|
14918
|
+
let dirStat;
|
|
14919
|
+
try {
|
|
14920
|
+
dirStat = lstatSync5(scratchpadDir);
|
|
14921
|
+
} catch {
|
|
14922
|
+
return null;
|
|
14923
|
+
}
|
|
14924
|
+
if (dirStat.isSymbolicLink() || !dirStat.isDirectory()) return null;
|
|
14925
|
+
let entries;
|
|
14926
|
+
try {
|
|
14927
|
+
entries = readdirSync8(scratchpadDir, { withFileTypes: true });
|
|
14928
|
+
} catch {
|
|
14929
|
+
return null;
|
|
14930
|
+
}
|
|
14931
|
+
const prefix = `${agentId}.attempt-`;
|
|
14932
|
+
let best = null;
|
|
14933
|
+
for (const dirent of entries) {
|
|
14934
|
+
if (dirent.isSymbolicLink() || !dirent.isFile()) continue;
|
|
14935
|
+
const name = dirent.name;
|
|
14936
|
+
if (!name.startsWith(prefix) || !name.endsWith(SNAPSHOT_SUFFIX)) continue;
|
|
14937
|
+
const attemptPart = name.slice(prefix.length, name.length - SNAPSHOT_SUFFIX.length);
|
|
14938
|
+
if (!/^\d+$/.test(attemptPart)) continue;
|
|
14939
|
+
const attempt = Number.parseInt(attemptPart, 10);
|
|
14940
|
+
let stat2;
|
|
14941
|
+
try {
|
|
14942
|
+
stat2 = lstatSync5(join18(scratchpadDir, name));
|
|
14943
|
+
} catch {
|
|
14944
|
+
continue;
|
|
14945
|
+
}
|
|
14946
|
+
if (!stat2.isFile()) continue;
|
|
14947
|
+
const hit = { path: join18(scratchpadDir, name), attempt, mtimeMs: stat2.mtimeMs };
|
|
14948
|
+
if (best === null || hit.mtimeMs > best.mtimeMs || hit.mtimeMs === best.mtimeMs && hit.attempt < best.attempt) {
|
|
14949
|
+
best = hit;
|
|
14950
|
+
}
|
|
14951
|
+
}
|
|
14952
|
+
return best;
|
|
14953
|
+
}
|
|
14954
|
+
var SNAPSHOT_SUFFIX;
|
|
14955
|
+
var init_snapshot_lookup = __esm({
|
|
14956
|
+
"src/runtime/scratchpad/snapshot-lookup.ts"() {
|
|
14957
|
+
"use strict";
|
|
14958
|
+
SNAPSHOT_SUFFIX = ".snapshot.json";
|
|
14959
|
+
}
|
|
14960
|
+
});
|
|
14961
|
+
|
|
14863
14962
|
// src/runtime/child-pi/child-pi-spawn.ts
|
|
14864
14963
|
import * as fs18 from "node:fs";
|
|
14865
14964
|
import * as path18 from "node:path";
|
|
@@ -14956,6 +15055,21 @@ function prepareSpawnContext(input, effectiveTask) {
|
|
|
14956
15055
|
if (input.runId) built.env.PI_CREW_BROKER_RUN_ID = input.runId;
|
|
14957
15056
|
if (input.agentId) built.env.PI_CREW_BROKER_TASK_ID = input.agentId;
|
|
14958
15057
|
}
|
|
15058
|
+
if (input.agentId && isScratchpadEnabledForRole(input.role ?? input.agent.name, input.agent)) {
|
|
15059
|
+
built.env.PI_CREW_SCRATCHPAD = "1";
|
|
15060
|
+
built.env.PI_CREW_TASK_ID = input.agentId;
|
|
15061
|
+
built.env.PI_CREW_ATTEMPT = String(input.attempt ?? 0);
|
|
15062
|
+
if (input.artifactsRoot) {
|
|
15063
|
+
built.env.PI_CREW_ARTIFACTS_ROOT = input.artifactsRoot;
|
|
15064
|
+
}
|
|
15065
|
+
const scratchTempDir = built.tempDir ?? createSafeTempDir(getPiTempBase(), "pi-crew-scratchpad-");
|
|
15066
|
+
built.env.PI_CREW_SCRATCHPAD_SNAPSHOT = resolveRealContainedPath(scratchTempDir, `${input.agentId}.snapshot.json`);
|
|
15067
|
+
const restoreHit = input.artifactsRoot ? findLatestScratchpadSnapshot(input.artifactsRoot, input.agentId) : null;
|
|
15068
|
+
if (restoreHit) {
|
|
15069
|
+
built.env.PI_CREW_SCRATCHPAD_RESTORE = restoreHit.path;
|
|
15070
|
+
built.env.PI_CREW_SCRATCHPAD_RESTORE_MTIME = String(restoreHit.mtimeMs);
|
|
15071
|
+
}
|
|
15072
|
+
}
|
|
14959
15073
|
if (input.signal?.aborted) {
|
|
14960
15074
|
return {
|
|
14961
15075
|
kind: "aborted",
|
|
@@ -14983,11 +15097,14 @@ var BASE_ALLOWLIST;
|
|
|
14983
15097
|
var init_child_pi_spawn = __esm({
|
|
14984
15098
|
"src/runtime/child-pi/child-pi-spawn.ts"() {
|
|
14985
15099
|
"use strict";
|
|
15100
|
+
init_role_tools();
|
|
14986
15101
|
init_env_allowlist();
|
|
14987
15102
|
init_env_filter();
|
|
14988
15103
|
init_internal_error();
|
|
15104
|
+
init_safe_paths();
|
|
14989
15105
|
init_pi_args();
|
|
14990
15106
|
init_pi_spawn();
|
|
15107
|
+
init_snapshot_lookup();
|
|
14991
15108
|
BASE_ALLOWLIST = [
|
|
14992
15109
|
"PATH",
|
|
14993
15110
|
"HOME",
|
|
@@ -23005,12 +23122,12 @@ var init_crew_hooks = __esm({
|
|
|
23005
23122
|
|
|
23006
23123
|
// src/runtime/skill-effectiveness.ts
|
|
23007
23124
|
import { existsSync as existsSync23, mkdirSync as mkdirSync14, readFileSync as readFileSync23, writeFileSync as writeFileSync4 } from "node:fs";
|
|
23008
|
-
import { dirname as dirname16, join as
|
|
23125
|
+
import { dirname as dirname16, join as join30 } from "node:path";
|
|
23009
23126
|
function getSkillMetricsPath(cwd, runId) {
|
|
23010
|
-
return
|
|
23127
|
+
return join30(projectCrewRoot(cwd), `state/runs/${runId}/skill-metrics.jsonl`);
|
|
23011
23128
|
}
|
|
23012
23129
|
function getSkillActivationsPath(cwd, runId) {
|
|
23013
|
-
return
|
|
23130
|
+
return join30(projectCrewRoot(cwd), `state/runs/${runId}/skill-activations.jsonl`);
|
|
23014
23131
|
}
|
|
23015
23132
|
function ensureSkillMetricsDir(cwd, runId) {
|
|
23016
23133
|
const dir = dirname16(getSkillMetricsPath(cwd, runId));
|
|
@@ -33743,35 +33860,6 @@ var init_live_session_runtime = __esm({
|
|
|
33743
33860
|
}
|
|
33744
33861
|
});
|
|
33745
33862
|
|
|
33746
|
-
// src/runtime/role-permission.ts
|
|
33747
|
-
function permissionForRole(role) {
|
|
33748
|
-
if (READ_ONLY_ROLES.has(role)) return "read_only";
|
|
33749
|
-
if (WRITE_ROLES.has(role)) return "workspace_write";
|
|
33750
|
-
return "read_only";
|
|
33751
|
-
}
|
|
33752
|
-
function currentCrewRole(env = process.env) {
|
|
33753
|
-
return env.PI_CREW_ROLE?.trim() || env.PI_TEAMS_ROLE?.trim() || void 0;
|
|
33754
|
-
}
|
|
33755
|
-
function checkSubagentSpawnPermission(role) {
|
|
33756
|
-
if (!role) return { allowed: true, mode: "workspace_write" };
|
|
33757
|
-
const mode = permissionForRole(role);
|
|
33758
|
-
if (mode === "read_only")
|
|
33759
|
-
return {
|
|
33760
|
-
allowed: false,
|
|
33761
|
-
mode,
|
|
33762
|
-
reason: `Role '${role}' is read-only and cannot spawn additional subagents.`
|
|
33763
|
-
};
|
|
33764
|
-
return { allowed: true, mode };
|
|
33765
|
-
}
|
|
33766
|
-
var READ_ONLY_ROLES, WRITE_ROLES;
|
|
33767
|
-
var init_role_permission = __esm({
|
|
33768
|
-
"src/runtime/role-permission.ts"() {
|
|
33769
|
-
"use strict";
|
|
33770
|
-
READ_ONLY_ROLES = /* @__PURE__ */ new Set(["explorer", "reviewer", "security-reviewer", "analyst", "critic", "planner"]);
|
|
33771
|
-
WRITE_ROLES = /* @__PURE__ */ new Set(["executor", "test-engineer", "writer", "verifier", "agent", "cold-verifier", "chain-executor", "worker"]);
|
|
33772
|
-
}
|
|
33773
|
-
});
|
|
33774
|
-
|
|
33775
33863
|
// src/state/coordination/task-claims.ts
|
|
33776
33864
|
import { randomUUID as randomUUID4, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
33777
33865
|
function createTaskClaim(owner, leaseMs = 5 * 6e4, now = /* @__PURE__ */ new Date()) {
|
|
@@ -39426,6 +39514,7 @@ function serializeAgent(agent) {
|
|
|
39426
39514
|
line("fallbackModels", agent.fallbackModels),
|
|
39427
39515
|
line("thinking", agent.thinking),
|
|
39428
39516
|
line("tools", agent.tools),
|
|
39517
|
+
line("scratchpad", agent.scratchpad),
|
|
39429
39518
|
agent.extensions !== void 0 ? line("extensions", agent.extensions) ?? "extensions:" : void 0,
|
|
39430
39519
|
line("skills", agent.skills),
|
|
39431
39520
|
line("systemPromptMode", agent.systemPromptMode),
|
|
@@ -40772,9 +40861,9 @@ var init_handle_settings = __esm({
|
|
|
40772
40861
|
|
|
40773
40862
|
// src/extension/team-tool/workflow-manage.ts
|
|
40774
40863
|
import { existsSync as existsSync41, readFileSync as readFileSync40, rmSync as rmSync14, writeFileSync as writeFileSync7 } from "node:fs";
|
|
40775
|
-
import { dirname as dirname29, join as
|
|
40864
|
+
import { dirname as dirname29, join as join46 } from "node:path";
|
|
40776
40865
|
function allowedWorkflowDirs(cwd) {
|
|
40777
|
-
return [
|
|
40866
|
+
return [join46(projectCrewRoot(cwd), "workflows"), join46(userPiRoot(), "workflows"), join46(packageRoot(), "workflows")];
|
|
40778
40867
|
}
|
|
40779
40868
|
function validateScriptContent(content) {
|
|
40780
40869
|
for (const pattern of FORBIDDEN_PATTERNS) {
|
|
@@ -40786,7 +40875,7 @@ function validateScriptContent(content) {
|
|
|
40786
40875
|
}
|
|
40787
40876
|
function resolveWorkflowWritePath(cwd, name, scope = "project") {
|
|
40788
40877
|
assertSafePathId("workflowName", name);
|
|
40789
|
-
const base = scope === "user" ?
|
|
40878
|
+
const base = scope === "user" ? join46(userPiRoot(), "workflows") : join46(projectCrewRoot(cwd), "workflows");
|
|
40790
40879
|
return resolveRealContainedPath(base, `${name}.dwf.ts`);
|
|
40791
40880
|
}
|
|
40792
40881
|
function handleWorkflowCreate(params, ctx) {
|
|
@@ -41640,7 +41729,7 @@ var init_async_runner = __esm({
|
|
|
41640
41729
|
});
|
|
41641
41730
|
|
|
41642
41731
|
// src/runtime/goal-workflow/goal-state-store.ts
|
|
41643
|
-
import { closeSync as closeSync10, existsSync as existsSync44, mkdirSync as mkdirSync26, openSync as openSync10, readdirSync as
|
|
41732
|
+
import { closeSync as closeSync10, existsSync as existsSync44, mkdirSync as mkdirSync26, openSync as openSync10, readdirSync as readdirSync21, readFileSync as readFileSync42, statSync as statSync33, unlinkSync as unlinkSync7 } from "node:fs";
|
|
41644
41733
|
import { dirname as dirname32 } from "node:path";
|
|
41645
41734
|
function resolveGoalsRoot(cwd) {
|
|
41646
41735
|
const crewRoot = projectCrewRoot(cwd) ?? userCrewRoot();
|
|
@@ -41800,7 +41889,7 @@ var init_goal_state_store = __esm({
|
|
|
41800
41889
|
try {
|
|
41801
41890
|
const root = resolveGoalsRoot(this.cwd);
|
|
41802
41891
|
if (!existsSync44(root)) return [];
|
|
41803
|
-
const entries =
|
|
41892
|
+
const entries = readdirSync21(root);
|
|
41804
41893
|
const goals = [];
|
|
41805
41894
|
for (const entry of entries) {
|
|
41806
41895
|
if (!entry.endsWith(".json")) continue;
|
|
@@ -41864,7 +41953,7 @@ var init_verification_integrity = __esm({
|
|
|
41864
41953
|
|
|
41865
41954
|
// src/runtime/workspace-lock.ts
|
|
41866
41955
|
import { createHash as createHash7 } from "node:crypto";
|
|
41867
|
-
import { closeSync as closeSync11, existsSync as existsSync45, mkdirSync as mkdirSync27, openSync as openSync11, readdirSync as
|
|
41956
|
+
import { closeSync as closeSync11, existsSync as existsSync45, mkdirSync as mkdirSync27, openSync as openSync11, readdirSync as readdirSync22, readFileSync as readFileSync44, statSync as statSync35, unlinkSync as unlinkSync8, writeFileSync as writeFileSync8 } from "node:fs";
|
|
41868
41957
|
import * as path50 from "node:path";
|
|
41869
41958
|
function workspaceLockPath(cwd) {
|
|
41870
41959
|
const absCwd = path50.resolve(cwd);
|
|
@@ -45069,7 +45158,8 @@ __export(crash_recovery_exports, {
|
|
|
45069
45158
|
detectInterruptedRuns: () => detectInterruptedRuns,
|
|
45070
45159
|
purgeStaleActiveRunIndex: () => purgeStaleActiveRunIndex,
|
|
45071
45160
|
readManifestWithTransientRetry: () => readManifestWithTransientRetry,
|
|
45072
|
-
reconcileAllStaleRuns: () => reconcileAllStaleRuns
|
|
45161
|
+
reconcileAllStaleRuns: () => reconcileAllStaleRuns,
|
|
45162
|
+
shouldRecoverTask: () => shouldRecoverTask
|
|
45073
45163
|
});
|
|
45074
45164
|
import * as fs63 from "node:fs";
|
|
45075
45165
|
import * as path52 from "node:path";
|
|
@@ -53188,6 +53278,20 @@ function detectRetryableModelFailureFromOutput(parsed) {
|
|
|
53188
53278
|
}
|
|
53189
53279
|
return void 0;
|
|
53190
53280
|
}
|
|
53281
|
+
function evidenceStatusFor(childResult) {
|
|
53282
|
+
return childResult.exitStatus?.cancelled ? "cancelled" : childResult.error || childResult.exitCode && childResult.exitCode !== 0 ? "failed" : "completed";
|
|
53283
|
+
}
|
|
53284
|
+
function attemptErrorFor(childResult, parsedOutput, taskId) {
|
|
53285
|
+
let err2 = childResult.error || (childResult.exitCode && childResult.exitCode !== 0 ? childResult.stderr || `Child Pi exited with ${childResult.exitCode}` : void 0);
|
|
53286
|
+
if (childResult.exitStatus?.timedOut) {
|
|
53287
|
+
err2 = errors.childTimeout({ taskId, stderr: childResult.stderr }).message;
|
|
53288
|
+
}
|
|
53289
|
+
if (!err2 && parsedOutput) {
|
|
53290
|
+
const rateLimitErr = detectRetryableModelFailureFromOutput(parsedOutput);
|
|
53291
|
+
if (rateLimitErr) err2 = rateLimitErr;
|
|
53292
|
+
}
|
|
53293
|
+
return err2;
|
|
53294
|
+
}
|
|
53191
53295
|
async function runChildProcessTask(ctx) {
|
|
53192
53296
|
const input = ctx.input;
|
|
53193
53297
|
const manifest = ctx.manifest;
|
|
@@ -53371,6 +53475,7 @@ async function runChildProcessTask(ctx) {
|
|
|
53371
53475
|
runId: manifest.runId,
|
|
53372
53476
|
agentId: task.id,
|
|
53373
53477
|
artifactsRoot: manifest.artifactsRoot,
|
|
53478
|
+
attempt: i,
|
|
53374
53479
|
steeringFile: resolveRealContainedPath(`${manifest.artifactsRoot}/steering`, `${task.id}.jsonl`),
|
|
53375
53480
|
onSpawn: (pid) => {
|
|
53376
53481
|
try {
|
|
@@ -53459,7 +53564,7 @@ async function runChildProcessTask(ctx) {
|
|
|
53459
53564
|
input.signal.removeEventListener("abort", externalAbortListener);
|
|
53460
53565
|
}
|
|
53461
53566
|
}
|
|
53462
|
-
const evidenceStatus = childResult
|
|
53567
|
+
const evidenceStatus = evidenceStatusFor(childResult);
|
|
53463
53568
|
terminalEvidence = [
|
|
53464
53569
|
...terminalEvidence,
|
|
53465
53570
|
{
|
|
@@ -53505,17 +53610,7 @@ async function runChildProcessTask(ctx) {
|
|
|
53505
53610
|
parsedOutput = parsePiJsonOutput(transcriptText2);
|
|
53506
53611
|
rawFinalText = childResult.rawFinalText;
|
|
53507
53612
|
intermediateFindings = childResult.intermediateFindings;
|
|
53508
|
-
error =
|
|
53509
|
-
if (childResult.exitStatus?.timedOut) {
|
|
53510
|
-
error = errors.childTimeout({
|
|
53511
|
-
taskId: task.id,
|
|
53512
|
-
stderr: childResult.stderr
|
|
53513
|
-
}).message;
|
|
53514
|
-
}
|
|
53515
|
-
if (!error && parsedOutput) {
|
|
53516
|
-
const rateLimitErr = detectRetryableModelFailureFromOutput(parsedOutput);
|
|
53517
|
-
if (rateLimitErr) error = rateLimitErr;
|
|
53518
|
-
}
|
|
53613
|
+
error = attemptErrorFor(childResult, parsedOutput, task.id);
|
|
53519
53614
|
persistHeartbeat(true);
|
|
53520
53615
|
persistChildProgress({ type: "attempt_finished" }, true);
|
|
53521
53616
|
const attempt = {
|
|
@@ -61073,7 +61168,7 @@ __export(dynamic_workflow_runner_exports, {
|
|
|
61073
61168
|
runDynamicWorkflow: () => runDynamicWorkflow
|
|
61074
61169
|
});
|
|
61075
61170
|
import { readFileSync as readFileSync67 } from "node:fs";
|
|
61076
|
-
import { join as
|
|
61171
|
+
import { join as join72 } from "node:path";
|
|
61077
61172
|
import { transformSync } from "esbuild";
|
|
61078
61173
|
function assertStructuredCloneable(value, name) {
|
|
61079
61174
|
try {
|
|
@@ -61085,7 +61180,7 @@ function assertStructuredCloneable(value, name) {
|
|
|
61085
61180
|
}
|
|
61086
61181
|
function resolveScriptPath(workflow, cwd) {
|
|
61087
61182
|
const crewRoot = projectCrewRoot(cwd);
|
|
61088
|
-
const allowedBases = [
|
|
61183
|
+
const allowedBases = [join72(projectCrewRoot(cwd), "workflows"), join72(userPiRoot(), "workflows"), join72(packageRoot(), "workflows")];
|
|
61089
61184
|
for (const base of allowedBases) {
|
|
61090
61185
|
try {
|
|
61091
61186
|
const real = resolveRealContainedPath(base, workflow.filePath);
|
|
@@ -72238,20 +72333,20 @@ init_internal_error();
|
|
|
72238
72333
|
|
|
72239
72334
|
// src/extension/crew-vibes/config.ts
|
|
72240
72335
|
import { existsSync as existsSync75, mkdirSync as mkdirSync42, readFileSync as readFileSync74, writeFileSync as writeFileSync9 } from "node:fs";
|
|
72241
|
-
import { dirname as dirname39, join as
|
|
72336
|
+
import { dirname as dirname39, join as join78 } from "node:path";
|
|
72242
72337
|
|
|
72243
72338
|
// src/extension/crew-vibes/font-detect.ts
|
|
72244
72339
|
import { existsSync as existsSync74, readFileSync as readFileSync73 } from "node:fs";
|
|
72245
72340
|
import { homedir as homedir11, platform } from "node:os";
|
|
72246
|
-
import { join as
|
|
72341
|
+
import { join as join77 } from "node:path";
|
|
72247
72342
|
function fontPath() {
|
|
72248
72343
|
const os18 = platform();
|
|
72249
72344
|
const home = homedir11();
|
|
72250
|
-
if (os18 === "darwin") return
|
|
72251
|
-
if (os18 === "linux") return
|
|
72345
|
+
if (os18 === "darwin") return join77(home, "Library", "Fonts", "crew-vibes.ttf");
|
|
72346
|
+
if (os18 === "linux") return join77(home, ".local", "share", "fonts", "crew-vibes.ttf");
|
|
72252
72347
|
if (os18 === "win32") {
|
|
72253
|
-
const local = process.env.LOCALAPPDATA ??
|
|
72254
|
-
return
|
|
72348
|
+
const local = process.env.LOCALAPPDATA ?? join77(home, "AppData", "Local");
|
|
72349
|
+
return join77(local, "Microsoft", "Windows", "Fonts", "crew-vibes.ttf");
|
|
72255
72350
|
}
|
|
72256
72351
|
return "";
|
|
72257
72352
|
}
|
|
@@ -72300,7 +72395,7 @@ function resolveHome() {
|
|
|
72300
72395
|
return (process.env.PI_TEAMS_HOME ?? process.env.PI_CREW_HOME)?.trim() || process.env.HOME || process.env.USERPROFILE || "";
|
|
72301
72396
|
}
|
|
72302
72397
|
function configPath2() {
|
|
72303
|
-
return
|
|
72398
|
+
return join78(resolveHome(), ".pi", "agent", "pi-crew-vibes.json");
|
|
72304
72399
|
}
|
|
72305
72400
|
var DEFAULT_CONFIG2 = {
|
|
72306
72401
|
enabled: true,
|
|
@@ -72800,14 +72895,14 @@ function createCrewVibesFooter(deps) {
|
|
|
72800
72895
|
// src/extension/crew-vibes/provider-usage.ts
|
|
72801
72896
|
import { readFileSync as readFileSync75 } from "node:fs";
|
|
72802
72897
|
import { homedir as homedir12 } from "node:os";
|
|
72803
|
-
import { join as
|
|
72898
|
+
import { join as join79 } from "node:path";
|
|
72804
72899
|
function withTimeout(ms, fn) {
|
|
72805
72900
|
const controller = new AbortController();
|
|
72806
72901
|
const timeoutId = setTimeout(() => controller.abort(), ms);
|
|
72807
72902
|
return fn(controller.signal).finally(() => clearTimeout(timeoutId));
|
|
72808
72903
|
}
|
|
72809
72904
|
function piAuthPath() {
|
|
72810
|
-
return
|
|
72905
|
+
return join79(homedir12(), ".pi", "agent", "auth.json");
|
|
72811
72906
|
}
|
|
72812
72907
|
function loadAnthropicToken() {
|
|
72813
72908
|
const envToken = process.env.ANTHROPIC_OAUTH_TOKEN?.trim();
|
|
@@ -72852,8 +72947,8 @@ function tokenFromHostEntry(entry) {
|
|
|
72852
72947
|
return void 0;
|
|
72853
72948
|
}
|
|
72854
72949
|
function loadLegacyCopilotToken() {
|
|
72855
|
-
const configHome = process.env.XDG_CONFIG_HOME?.trim() ||
|
|
72856
|
-
const candidates = [
|
|
72950
|
+
const configHome = process.env.XDG_CONFIG_HOME?.trim() || join79(homedir12(), ".config");
|
|
72951
|
+
const candidates = [join79(configHome, "github-copilot", "hosts.json"), join79(homedir12(), ".github-copilot", "hosts.json")];
|
|
72857
72952
|
for (const hostsPath of candidates) {
|
|
72858
72953
|
try {
|
|
72859
72954
|
const data = JSON.parse(readFileSync75(hostsPath, "utf8"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-crew",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.64",
|
|
4
4
|
"description": "Pi extension for coordinated AI teams, workflows, worktrees, and async task orchestration",
|
|
5
5
|
"author": "baphuongna",
|
|
6
6
|
"license": "MIT",
|
|
@@ -61,7 +61,9 @@
|
|
|
61
61
|
"types/",
|
|
62
62
|
"CHANGELOG.md",
|
|
63
63
|
"LICENSE",
|
|
64
|
-
"NOTICE.md"
|
|
64
|
+
"NOTICE.md",
|
|
65
|
+
"scripts/resource-sampler.mjs",
|
|
66
|
+
"scripts/analyze-run.mjs"
|
|
65
67
|
],
|
|
66
68
|
"scripts": {
|
|
67
69
|
"check": "npm run ci",
|
|
@@ -79,6 +81,7 @@
|
|
|
79
81
|
"test:watch": "tsx --watch --test --test-concurrency=4 --test-timeout=30000 --test-force-exit 'test/unit/**/*.test.ts'",
|
|
80
82
|
"test:integration": "node scripts/test-runner.mjs --test-concurrency=1 --test-timeout=300000 test/integration/*.test.ts",
|
|
81
83
|
"test:smoke": "node scripts/test-runner.mjs --test-concurrency=1 --test-timeout=180000 test/smoke/*.smoke.ts",
|
|
84
|
+
"test:spike": "node scripts/test-runner.mjs --test-concurrency=2 --test-timeout=120000 --test-force-exit test/runtime/scratchpad/*.test.ts",
|
|
82
85
|
"build:bundle": "node scripts/build-bundle.mjs",
|
|
83
86
|
"test:bundle": "node --experimental-strip-types --test --test-force-exit test/unit/bundle-load.test.ts",
|
|
84
87
|
"watch:bundle": "node scripts/watch-bundle.mjs",
|