pi-crew 0.9.67 → 0.10.1
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 +172 -0
- package/agents/analyst.md +1 -1
- package/agents/cold-verifier.md +3 -1
- package/agents/critic.md +1 -1
- package/agents/executor.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/verifier.md +1 -1
- package/agents/writer.md +1 -1
- package/dist/index.mjs +65847 -60331
- package/docs/README.md +2 -0
- package/docs/actions-reference.md +31 -0
- package/docs/commands-reference.md +17 -6
- package/docs/resource-formats.md +13 -0
- package/package.json +9 -6
- package/schema.json +15 -1
- package/scripts/resource-sampler.mjs +36 -2
- package/skills/requirements-to-task-packet/SKILL.md +26 -0
- package/skills/widget-rendering/SKILL.md +7 -7
- package/src/agents/agent-config.ts +36 -14
- package/src/agents/discover-agents.ts +23 -14
- package/src/config/config-merge.ts +183 -0
- package/src/config/config-validation.ts +681 -0
- package/src/config/config.ts +22 -864
- package/src/config/defaults.ts +35 -1
- package/src/config/drift-detector.ts +1 -1
- package/src/config/env-vars.ts +691 -0
- package/src/config/role-tools.ts +8 -8
- package/src/config/sanitize-project-config.ts +172 -0
- package/src/config/types.ts +30 -0
- package/src/extension/async-notifier.ts +25 -2
- package/src/extension/crew-vibes/config.ts +2 -1
- package/src/extension/plan-orchestrate.ts +132 -0
- package/src/extension/registration/commands/dashboard.ts +158 -0
- package/src/extension/registration/commands/index.ts +35 -0
- package/src/extension/registration/commands/manage.ts +303 -0
- package/src/extension/registration/commands/run.ts +214 -0
- package/src/extension/registration/commands/shared.ts +631 -0
- package/src/extension/registration/commands/status.ts +60 -0
- package/src/extension/registration/commands.ts +13 -1224
- package/src/extension/registration/lifecycle-handlers.ts +126 -15
- package/src/extension/registration/subagent-tools.ts +218 -9
- package/src/extension/rpc-hmac.ts +5 -3
- package/src/extension/team-tool/api/heartbeat.ts +47 -10
- package/src/extension/team-tool/api/plan-approval.ts +9 -0
- package/src/extension/team-tool/api/task-claims.ts +109 -40
- package/src/extension/team-tool/cancel.ts +84 -50
- package/src/extension/team-tool/dispatch/index.ts +1 -0
- package/src/extension/team-tool/dispatch/run.ts +4 -1
- package/src/extension/team-tool/doctor.ts +103 -1
- package/src/extension/team-tool/orchestrate.ts +66 -1
- package/src/extension/team-tool/plans.ts +192 -0
- package/src/extension/team-tool/respond.ts +197 -65
- package/src/extension/team-tool/run-deadline.ts +16 -1
- package/src/extension/team-tool/run-intent.ts +63 -0
- package/src/extension/team-tool/run.ts +48 -18
- package/src/extension/team-tool/status.ts +84 -26
- package/src/extension/team-tool.ts +11 -2
- package/src/hooks/registry.ts +1 -6
- package/src/i18n.ts +9 -0
- package/src/prompt/prompt-runtime.ts +521 -2
- package/src/prompt/worker-events-channel.ts +173 -0
- package/src/runtime/README.md +8 -8
- package/src/runtime/async-runner.ts +7 -3
- package/src/runtime/background-runner.ts +42 -14
- package/src/runtime/broker/broker-issuer.ts +9 -2
- package/src/runtime/broker/crew-broker-tokens.ts +43 -6
- package/src/runtime/broker/crew-broker.ts +838 -10
- package/src/runtime/broker/wait-status-cache.ts +157 -0
- package/src/runtime/budget-enforcement.ts +281 -0
- package/src/runtime/child-pi/child-pi-spawn.ts +60 -14
- package/src/runtime/child-pi/child-pi-timers.ts +324 -0
- package/src/runtime/child-pi/child-pi.ts +97 -201
- package/src/runtime/child-pi/mock-fixtures.ts +16 -2
- package/src/runtime/crew-agent-records.ts +259 -14
- package/src/runtime/delegate-spawn.ts +148 -0
- package/src/runtime/deterministic-ast.ts +2 -1
- package/src/runtime/dispatch-batch.ts +945 -0
- package/src/runtime/finalize-run.ts +557 -0
- package/src/runtime/goal-workflow/adaptive-plan.ts +87 -13
- package/src/runtime/goal-workflow/dynamic-workflow-runner.ts +3 -2
- package/src/runtime/goal-workflow/goal-state-store.ts +1 -1
- package/src/runtime/group-join.ts +11 -125
- package/src/runtime/live-session/live-session-runtime.ts +26 -1
- package/src/runtime/merge-gate.ts +7 -1
- package/src/runtime/merge-loop.ts +130 -0
- package/src/runtime/model/model-budget-summary.ts +53 -0
- package/src/runtime/model/model-fallback.ts +32 -2
- package/src/runtime/model/pi-args.ts +10 -0
- package/src/runtime/model/provider-extensions.ts +10 -0
- package/src/runtime/orphan-worker-registry.ts +1 -1
- package/src/runtime/output/output-validator.ts +45 -0
- package/src/runtime/parent-guard.ts +3 -1
- package/src/runtime/peer-dep.ts +2 -1
- package/src/runtime/per-write-validator.ts +0 -5
- package/src/runtime/pi-spawn.ts +61 -15
- package/src/runtime/plan-approval.ts +125 -0
- package/src/runtime/plan-replan.ts +151 -0
- package/src/runtime/recovery/checkpoint.ts +0 -18
- package/src/runtime/recovery/crash-recovery.ts +95 -46
- package/src/runtime/scheduler-context.ts +98 -0
- package/src/runtime/scheduling/coalesce-tasks.ts +5 -0
- package/src/runtime/scheduling/global-worker-cap.ts +2 -1
- package/src/runtime/scheduling/nested-slots.ts +70 -0
- package/src/runtime/scheduling/run-coalesced-task-group.ts +64 -13
- package/src/runtime/scheduling/task-graph-scheduler.ts +0 -10
- package/src/runtime/scratchpad/README.md +10 -5
- package/src/runtime/scratchpad/guest.ts +103 -2
- package/src/runtime/scratchpad/protocol.ts +13 -1
- package/src/runtime/scratchpad/transform.ts +206 -12
- package/src/runtime/settings-store.ts +219 -0
- package/src/runtime/spawn-policy.ts +217 -0
- package/src/runtime/stale-reconciler.ts +87 -6
- package/src/runtime/subagent-manager.ts +25 -1
- package/src/runtime/task-output-context.ts +230 -9
- package/src/runtime/task-packet.ts +23 -1
- package/src/runtime/task-runner/child-executor.ts +106 -7
- package/src/runtime/task-runner/post-execution.ts +125 -1
- package/src/runtime/task-runner/pre-execution.ts +39 -1
- package/src/runtime/task-runner/prompt-builder.ts +51 -1
- package/src/runtime/task-runner/retrieval-orchestrator.ts +72 -18
- package/src/runtime/task-runner/spec-evidence.ts +403 -0
- package/src/runtime/task-runner/state-helpers.ts +26 -24
- package/src/runtime/task-runner.ts +11 -0
- package/src/runtime/team-runner.ts +129 -1671
- package/src/runtime/verification/spec-sandbox.ts +255 -0
- package/src/runtime/verification/verification-gates.ts +3 -2
- package/src/runtime/verification/verification-worktree.ts +2 -1
- package/src/runtime/workflow-phase-advance.ts +100 -0
- package/src/runtime/workspace-tree.ts +9 -0
- package/src/schema/config-schema.ts +65 -25
- package/src/schema/sensitive-config-paths.ts +64 -0
- package/src/schema/team-tool-schema.ts +13 -3
- package/src/state/README.md +4 -10
- package/src/state/atomic-write.ts +20 -3
- package/src/state/contracts.ts +38 -0
- package/src/state/coordination/mailbox.ts +12 -2
- package/src/state/event-log/cursor.ts +223 -0
- package/src/state/event-log/event-log-rotation.ts +12 -4
- package/src/state/event-log/event-log.ts +152 -369
- package/src/state/event-log/sequence-cache.ts +373 -0
- package/src/state/event-log/worker-atomic-writer.ts +2 -1
- package/src/state/stores/active-run-registry.ts +3 -2
- package/src/state/stores/manifest-io.ts +237 -0
- package/src/state/stores/ownership-map.ts +162 -0
- package/src/state/stores/plan-store.ts +241 -0
- package/src/state/stores/run-cache.ts +0 -90
- package/src/state/stores/spec-store.ts +189 -0
- package/src/state/stores/state-store.ts +66 -229
- package/src/state/types.ts +197 -0
- package/src/ui/dashboard-panes/plan-pane.ts +136 -0
- package/src/ui/dashboard-panes/progress-pane.ts +6 -0
- package/src/ui/dashboard-panes/transcript-pane.ts +31 -0
- package/src/ui/heartbeat-aggregator.ts +9 -1
- package/src/ui/keybinding-map.ts +54 -13
- package/src/ui/powerbar-publisher.ts +52 -1
- package/src/ui/run-dashboard.ts +31 -5
- package/src/ui/run-snapshot-cache.ts +57 -30
- package/src/ui/snapshot-types.ts +6 -1
- package/src/ui/widget/widget-renderer.ts +9 -1
- package/src/utils/file-coalescer.ts +0 -4
- package/src/utils/fs-errno.ts +66 -0
- package/src/utils/fs-watch.ts +1 -1
- package/src/utils/internal-error.ts +3 -1
- package/src/utils/paths.ts +11 -3
- package/src/utils/task-name-generator.ts +1 -8
- package/src/workflows/discover-workflows.ts +19 -2
- package/src/workflows/validate-workflow.ts +7 -1
- package/src/workflows/workflow-config.ts +10 -0
- package/src/workflows/workflow-serializer.ts +3 -0
- package/src/worktree/worktree-manager.ts +22 -0
- package/src/agents/agent-search.ts +0 -98
- package/src/benchmark/benchmark-runner.ts +0 -313
- package/src/benchmark/feedback-loop.ts +0 -73
- package/src/config/resilient-parser.ts +0 -117
- package/src/extension/crew-vibes/cat-frames.ts +0 -18
- package/src/extension/result-watcher.ts +0 -139
- package/src/observability/exporters/prometheus-exporter.ts +0 -54
- package/src/observability/metric-retention.ts +0 -64
- package/src/runtime/compaction/compaction-summary.ts +0 -278
- package/src/runtime/errors/crew-errors.ts +0 -162
- package/src/runtime/live-session/intercom-bridge.ts +0 -187
- package/src/runtime/loop-gates.ts +0 -128
- package/src/runtime/metric-parser.ts +0 -36
- package/src/runtime/output/stream-preview.ts +0 -184
- package/src/runtime/output/tool-progress.ts +0 -278
- package/src/runtime/phase-tracker.ts +0 -385
- package/src/runtime/pipeline-runner.ts +0 -523
- package/src/runtime/process/process-lifecycle.ts +0 -491
- package/src/runtime/recovery/retry-runner.ts +0 -330
- package/src/runtime/run-drift.ts +0 -219
- package/src/runtime/scratchpad/snapshot-hmac.ts +0 -167
- package/src/runtime/task-quality.ts +0 -199
- package/src/runtime/task-runner/run-projection.ts +0 -128
- package/src/runtime/verification/post-checks.ts +0 -142
- package/src/state/coordination/schedule.ts +0 -166
- package/src/state/event-log/jsonl-writer.ts +0 -115
- package/src/state/hook-instinct-bridge.ts +0 -94
- package/src/state/hook-integrations.ts +0 -51
- package/src/state/session-state-map.ts +0 -51
- package/src/state/stores/blob-store.ts +0 -308
- package/src/state/stores/instinct-store.ts +0 -275
- package/src/state/stores/observation-store.ts +0 -176
- package/src/state/tiered-eval.ts +0 -480
- package/src/state/types-eval.ts +0 -58
- package/src/tools/safe-bash-extension.ts +0 -54
- package/src/tools/safe-bash.ts +0 -505
- package/src/ui/agent-management-overlay.ts +0 -160
- package/src/ui/crew-footer.ts +0 -102
- package/src/ui/crew-select-list.ts +0 -114
- package/src/ui/dashboard-panes/capability-pane.ts +0 -77
- package/src/ui/transcript-entries.ts +0 -256
- package/src/utils/conflict-detect.ts +0 -721
- package/src/utils/fingerprint.ts +0 -180
- package/src/utils/gh-protocol.ts +0 -556
- package/src/utils/project-detector.ts +0 -160
- package/src/utils/sse-parser.ts +0 -131
- package/src/workflows/cost-estimator.ts +0 -34
- package/src/workflows/intermediate-store.ts +0 -166
package/docs/README.md
CHANGED
|
@@ -30,6 +30,8 @@ stay at the root of this directory; historical/retired docs live in
|
|
|
30
30
|
| [`COVERAGE-ASSESSMENT-2026-08-01.md`](./COVERAGE-ASSESSMENT-2026-08-01.md) | v0.9.56 coverage assessment + source-reorg history |
|
|
31
31
|
| [`AUDIT-2026-07-30.md`](./AUDIT-2026-07-30.md) | v0.9.56 comprehensive audit (6 parallel streams) |
|
|
32
32
|
| [`REMEDIATION-PLAN-2026-07-30.md`](./REMEDIATION-PLAN-2026-07-30.md) | v0.9.56 remediation plan |
|
|
33
|
+
| [`refactor-plan.md`](./refactor-plan.md) | Maintainability refactor plan (phased, v0.9.68) |
|
|
34
|
+
| [`refactor-plan.review.md`](./refactor-plan.review.md) | Verification sweep 3 (vòng 4) audit trail — 3 large-file baselines CONFIRMED, 6 corrections, Phase 4 reframe |
|
|
33
35
|
|
|
34
36
|
## Subdirectories
|
|
35
37
|
|
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
The `team` tool is the primary tool that pi-crew registers with Pi. All operations go through `action`.
|
|
4
4
|
|
|
5
|
+
### `plans` — Inspect and decide a run's plan record (T2/R4)
|
|
6
|
+
|
|
7
|
+
Reads the versioned `PlanRecord` list at `<stateRoot>/plans/plans.json` (ADR-4). Pre-v2 runs without a record degrade gracefully with the manifest-gate info.
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{ "action": "plans", "runId": "team_..." }
|
|
11
|
+
{ "action": "plans", "runId": "team_...", "config": { "subAction": "get", "rev": 2 } }
|
|
12
|
+
{ "action": "plans", "runId": "team_...", "config": { "subAction": "list" } }
|
|
13
|
+
{ "action": "plans", "runId": "team_...", "config": { "subAction": "diff", "a": 1, "b": 2 } }
|
|
14
|
+
{ "action": "plans", "runId": "team_...", "config": { "subAction": "approve" } }
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- `get` (default) renders the current (or pinned `rev`) revision with derived per-item progress (done/failed/running from linked `taskIds`).
|
|
18
|
+
- `list` renders the revision history.
|
|
19
|
+
- `diff` reports item-level changes between two revisions (added / removed / dropped / status changes / retitles).
|
|
20
|
+
- `approve` / `reject` delegate to the api `approve-plan` / `cancel-plan` ops (dual-write: manifest keeps its vocabulary — `cancelled` on deny — the record side uses `rejected`).
|
|
21
|
+
|
|
5
22
|
## Quick Reference
|
|
6
23
|
|
|
7
24
|
| Action | Purpose | When to use |
|
|
@@ -10,6 +27,7 @@ The `team` tool is the primary tool that pi-crew registers with Pi. All operatio
|
|
|
10
27
|
| `run` | Create a run and execute a workflow | Main operation |
|
|
11
28
|
| `parallel` | Fan out independent tasks as concurrent runs | When you need N truly concurrent agents |
|
|
12
29
|
| `plan` | Preview a workflow without running tasks | Dry-run planning |
|
|
30
|
+
| `plans` | Inspect/decide the versioned plan record of a run | Plan revisions, diff, approve/reject |
|
|
13
31
|
| `orchestrate` | Execute from a plan document | Automate a plan |
|
|
14
32
|
| `schedule` | Schedule recurring runs | Periodic automation |
|
|
15
33
|
| `scheduled` | List scheduled jobs | View schedules |
|
|
@@ -800,6 +818,19 @@ Returns `status: "error"` when the run finished as `failed`.
|
|
|
800
818
|
> ⚠️ **Internal / experimental.** Queues a steering message that is delivered to
|
|
801
819
|
> a task's worker session on its next turn. The message is appended to
|
|
802
820
|
> `pendingSteers` and also written to a live steering file for immediate delivery.
|
|
821
|
+
>
|
|
822
|
+
> **Updated (T1/WP-1, 2026-08-17, v0.10.1):** the agent-level tools
|
|
823
|
+
> `steer_subagent` / `crew_agent_steer` are now **implemented** — they resolve the
|
|
824
|
+
> subagent record via the unified ownership map (`src/state/stores/ownership-map.ts`,
|
|
825
|
+
> task ⇄ subagent ⇄ pid ⇄ artifacts) to the run's steering file and append a
|
|
826
|
+
> `{type:"steer", message, ts}` line that the worker polls every 500ms and picks
|
|
827
|
+
> up at its next turn boundary. Terminal-task refusal + size-cap parity with
|
|
828
|
+
> `team action=steer`; the steering file is truncated at each worker spawn so
|
|
829
|
+
> lines are scoped to one worker incarnation. The record's `taskId` is linked at
|
|
830
|
+
> dispatch time (onRunStarted), so mid-run steering of a live one-shot agent
|
|
831
|
+
> works. See ADR `docs/decisions/2026-08-14-agent-steer-tools-planned-not-implemented.md`
|
|
832
|
+
> (status: CLOSED). `team action=steer` (runId + taskId + message) remains the
|
|
833
|
+
> run-level path.
|
|
803
834
|
|
|
804
835
|
```json
|
|
805
836
|
{
|
|
@@ -8,21 +8,22 @@ Slash commands are manual actions triggered from the Pi chat. Autonomous tool us
|
|
|
8
8
|
|---------|-------|
|
|
9
9
|
| `/teams` | List teams, agents, workflows, and recent runs |
|
|
10
10
|
| `/team-run [options] <goal>` | Run a team workflow |
|
|
11
|
-
| `/team-orchestrate <planPath>` | Execute from a plan document |
|
|
12
|
-
| `/team-schedule [options]` | Schedule a recurring run |
|
|
13
|
-
| `/team-scheduled` | List scheduled jobs |
|
|
14
11
|
| `/team-cancel <runId>` | Cancel a run |
|
|
15
12
|
| `/team-status <runId>` | View status |
|
|
16
13
|
| `/team-summary <runId>` | View or write a summary |
|
|
17
14
|
| `/team-resume <runId>` | Resume a stopped run |
|
|
18
|
-
| `/team-
|
|
19
|
-
| `/team-
|
|
15
|
+
| `/team-retry <runId>` | Retry a failed run |
|
|
16
|
+
| `/team-result <runId>` | Show a task result artifact |
|
|
17
|
+
| `/team-respond <taskId> <message>` | Respond to a waiting worker task |
|
|
18
|
+
| `/team-follow-up [options]` | Manage follow-up notifications |
|
|
20
19
|
| `/team-events <runId>` | View the event log |
|
|
21
20
|
| `/team-artifacts <runId>` | View artifacts |
|
|
21
|
+
| `/team-transcript <runId>` | Open the transcript viewer |
|
|
22
22
|
| `/team-worktrees <runId>` | View worktree metadata |
|
|
23
|
-
| `/team-cleanup <runId>` | Remove worktrees |
|
|
23
|
+
| `/team-cleanup <runId>` | Remove worktrees (interactive menu: `/team-cleanup-menu`) |
|
|
24
24
|
| `/team-forget <runId>` | Fully delete a run |
|
|
25
25
|
| `/team-prune` | Delete multiple old runs |
|
|
26
|
+
| `/team-invalidate [scope]` | Invalidate caches |
|
|
26
27
|
| `/team-export <runId>` | Export a run bundle |
|
|
27
28
|
| `/team-import <path>` | Import a run bundle |
|
|
28
29
|
| `/team-imports` | List imported bundles |
|
|
@@ -37,9 +38,16 @@ Slash commands are manual actions triggered from the Pi chat. Autonomous tool us
|
|
|
37
38
|
| `/team-validate` | Validate resources |
|
|
38
39
|
| `/team-help` | Help text |
|
|
39
40
|
| `/team-doctor` | Diagnose the environment |
|
|
41
|
+
| `/team-mascot` | Toggle the mascot overlay |
|
|
40
42
|
| **`/team-goal`** | **v0.9.0** Start autonomous goal loop (sub-actions: `start/status/pause/resume/stop/step/clear`) |
|
|
41
43
|
| **`/workflows`** | **v0.9.0** List static + dynamic workflows (`.dwf.ts`) |
|
|
42
44
|
|
|
45
|
+
**Removed (v0.10.1 docs hygiene):** `/team-orchestrate`, `/team-schedule`,
|
|
46
|
+
`/team-scheduled`, `/team-search`, `/team-graph` — phantom entries; none of
|
|
47
|
+
these slash commands is registered. Their functionality is reachable via the
|
|
48
|
+
`team` tool actions (`action: "orchestrate" | "schedule" | "scheduled" |
|
|
49
|
+
"search" | "graph"`) instead.
|
|
50
|
+
|
|
43
51
|
---
|
|
44
52
|
|
|
45
53
|
## `/team-run` — Details
|
|
@@ -296,6 +304,9 @@ Creates directories:
|
|
|
296
304
|
| `u` | View summary |
|
|
297
305
|
| `i` | API read-manifest |
|
|
298
306
|
| `q` or `Esc` | Close |
|
|
307
|
+
| `1`–`7` | Pane: agents / progress / mailbox / output / health / metrics / **plan** (v0.10.1, `PI_CREW_PLAN_UI=1`) |
|
|
308
|
+
| `A` / `n` | Plan approval approve/deny (progress + plan panes, while pending) |
|
|
309
|
+
| `X` | Plan revision diff (plan pane) |
|
|
299
310
|
|
|
300
311
|
---
|
|
301
312
|
|
package/docs/resource-formats.md
CHANGED
|
@@ -107,6 +107,8 @@ Format:
|
|
|
107
107
|
---
|
|
108
108
|
name: default
|
|
109
109
|
description: Explore, plan, execute, verify
|
|
110
|
+
maxConcurrency: 3
|
|
111
|
+
specStrict: false
|
|
110
112
|
---
|
|
111
113
|
|
|
112
114
|
## explore
|
|
@@ -122,6 +124,15 @@ output: plan.md
|
|
|
122
124
|
Create a plan for: {goal}
|
|
123
125
|
```
|
|
124
126
|
|
|
127
|
+
Frontmatter fields:
|
|
128
|
+
|
|
129
|
+
| Field | Meaning |
|
|
130
|
+
| --- | --- |
|
|
131
|
+
| `maxConcurrency` | Max parallel tasks for the run |
|
|
132
|
+
| `topology` | Explicit topology classification |
|
|
133
|
+
| `coalesceMicroTasks` | Coalesce micro-tasks sharing role+cwd into one worker prompt |
|
|
134
|
+
| `specStrict` | T4/R6 (ADR-6): strict spec mode — coverage AND machine-check; requires a `verifier` role step (reject-start) |
|
|
135
|
+
|
|
125
136
|
Step fields:
|
|
126
137
|
|
|
127
138
|
| Field | Meaning |
|
|
@@ -136,5 +147,7 @@ Step fields:
|
|
|
136
147
|
| `progress` | `true`/`false` |
|
|
137
148
|
| `worktree` | `true`/`false` metadata |
|
|
138
149
|
| `verify` | `true`/`false` verification marker |
|
|
150
|
+
| `specRefs` | T4/R6 (ADR-6): workspace SpecRecord ids this step is held to (frozen into the packet at dispatch) |
|
|
151
|
+
| `specStrict` | Per-step strict override (`true`/`1`) |
|
|
139
152
|
|
|
140
153
|
Each step starts with `## step-id` followed by recognized step metadata such as `role:` before the blank line. Level-2 headings inside task bodies are preserved unless they look like a step section with recognized metadata; use `###` or lower for maximum compatibility.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-crew",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Pi extension for coordinated AI teams, workflows, worktrees, and async task orchestration",
|
|
5
5
|
"author": "baphuongna",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
],
|
|
31
31
|
"files": [
|
|
32
32
|
"src/",
|
|
33
|
+
"!src/benchmark",
|
|
33
34
|
"dist/index.mjs",
|
|
34
35
|
"index.ts",
|
|
35
36
|
"install.mjs",
|
|
@@ -67,12 +68,14 @@
|
|
|
67
68
|
],
|
|
68
69
|
"scripts": {
|
|
69
70
|
"check": "npm run ci",
|
|
70
|
-
"ci": "npm run typecheck && npm run lint && npm run format:check && npm run check:conflict-markers && npm run check:decision-drift && npm run check:event-types && npm run check:lazy-imports && npm run check:bundle-staleness && npm run build:bundle && npm run check:bundle-size && npm run test:bundle && npm test && npm pack --dry-run",
|
|
71
|
+
"ci": "npm run check:lockfile-sync && npm run typecheck && npm run lint && npm run format:check && npm run check:conflict-markers && npm run check:decision-drift && npm run check:env-vars && npm run check:event-types && npm run check:lazy-imports && npm run check:bundle-staleness && npm run build:bundle && npm run check:bundle-size && npm run test:bundle && npm test && npm pack --dry-run",
|
|
72
|
+
"check:lockfile-sync": "node scripts/check-lockfile-sync.mjs",
|
|
71
73
|
"check:lazy-imports": "node scripts/check-lazy-imports.mjs",
|
|
72
74
|
"check:bundle-staleness": "node scripts/check-bundle-staleness.mjs",
|
|
73
75
|
"check:bundle-size": "node scripts/check-bundle-size.mjs",
|
|
74
76
|
"check:conflict-markers": "node scripts/check-conflict-markers.mjs",
|
|
75
77
|
"check:decision-drift": "node scripts/check-decision-drift.mjs",
|
|
78
|
+
"check:env-vars": "node scripts/check-env-vars.mjs",
|
|
76
79
|
"check:event-types": "node scripts/check-event-types-registry.mjs",
|
|
77
80
|
"typecheck": "tsc --noEmit && node --experimental-strip-types -e \"await import('./index.ts'); console.log('strip-types import ok')\"",
|
|
78
81
|
"lint": "biome check --linter-enabled=true --formatter-enabled=false --max-diagnostics=50 .",
|
|
@@ -136,10 +139,10 @@
|
|
|
136
139
|
},
|
|
137
140
|
"devDependencies": {
|
|
138
141
|
"@biomejs/biome": "^2.5.3",
|
|
139
|
-
"@earendil-works/pi-agent-core": "^0.
|
|
140
|
-
"@earendil-works/pi-ai": "^0.
|
|
141
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
142
|
-
"@earendil-works/pi-tui": "^0.
|
|
142
|
+
"@earendil-works/pi-agent-core": "^0.84.0",
|
|
143
|
+
"@earendil-works/pi-ai": "^0.84.0",
|
|
144
|
+
"@earendil-works/pi-coding-agent": "^0.84.0",
|
|
145
|
+
"@earendil-works/pi-tui": "^0.84.0",
|
|
143
146
|
"@types/node": "^25.9.5",
|
|
144
147
|
"tsx": "^4.23.0",
|
|
145
148
|
"typescript": "^7.0.2"
|
package/schema.json
CHANGED
|
@@ -256,7 +256,21 @@
|
|
|
256
256
|
"enabled": { "type": "boolean" },
|
|
257
257
|
"pathHashLen": { "type": "integer", "minimum": 4, "maximum": 32 },
|
|
258
258
|
"maxFrameBytes": { "type": "integer", "minimum": 1024, "maximum": 1048576 },
|
|
259
|
-
"outboundQueueCap": { "type": "integer", "minimum": 32, "maximum": 4096 }
|
|
259
|
+
"outboundQueueCap": { "type": "integer", "minimum": 32, "maximum": 4096 },
|
|
260
|
+
"waitMethodsEnabled": {
|
|
261
|
+
"type": "boolean",
|
|
262
|
+
"description": "WP-2/R2 (ADR-0 2026-08-17-waiting-producer-ask item 7): gate for the broker wait.* methods. Default false - fail-closed."
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
"nesting": {
|
|
267
|
+
"type": "object",
|
|
268
|
+
"additionalProperties": false,
|
|
269
|
+
"description": "Governed nesting (ADR-5 docs/decisions/2026-08-17-governed-nesting.md). Worker-to-grandchild delegation via the delegate tool. Default false - fail-closed until WP-5 completes.",
|
|
270
|
+
"properties": {
|
|
271
|
+
"enabled": { "type": "boolean", "sensitive": true, "description": "Master switch. Privilege-raising: user config only; project-level nesting.enabled is ignored." },
|
|
272
|
+
"maxSlots": { "type": "integer", "minimum": 1, "maximum": 64, "description": "Nested-slot budget override. Default max(1, floor(globalSem/2))." },
|
|
273
|
+
"maxDepth": { "type": "integer", "minimum": 1, "maximum": 10, "description": "Max crew depth for delegate-driven nesting. Default 2 (mirrors PI_CREW_MAX_DEPTH clamp)." }
|
|
260
274
|
}
|
|
261
275
|
}
|
|
262
276
|
}
|
|
@@ -147,9 +147,16 @@ function readProcStatus(pid) {
|
|
|
147
147
|
|
|
148
148
|
// ---------- fallback via ps (non-Linux) ----------
|
|
149
149
|
function readPs(pid) {
|
|
150
|
-
|
|
150
|
+
// state= makes zombie detection possible on BSD ps (macOS): a dead child
|
|
151
|
+
// stays listed by ps until reaped — without the state check, watch-parent
|
|
152
|
+
// (R4) never sees the watched PID die and live-warn (proc_died) never fires
|
|
153
|
+
// (CI incident: resource-sampler-audit.test.ts on macos-latest). Linux ps
|
|
154
|
+
// also supports state=. Z/X (and empty) = dead.
|
|
155
|
+
const res = spawnSync("ps", ["-o", "rss=,pcpu=,state=", "-p", String(pid)], { encoding: "utf8" });
|
|
151
156
|
if (res.status !== 0 || !res.stdout.trim()) return null;
|
|
152
157
|
const parts = res.stdout.trim().split(/\s+/);
|
|
158
|
+
const state = parts.length >= 3 ? parts[2] : "";
|
|
159
|
+
if (state.startsWith("Z") || state.startsWith("X")) return null;
|
|
153
160
|
return {
|
|
154
161
|
pid,
|
|
155
162
|
ppid: 0,
|
|
@@ -163,7 +170,34 @@ function readPs(pid) {
|
|
|
163
170
|
// ---------- child discovery ----------
|
|
164
171
|
function findDescendants(rootPid) {
|
|
165
172
|
// BFS over /proc to find all PIDs whose ppid chain leads to rootPid.
|
|
166
|
-
|
|
173
|
+
// Non-Linux (macOS/BSD): no /proc — build the ppid map from `ps -eo pid=,ppid=`
|
|
174
|
+
// instead (R3 on macos-latest CI: /proc-less platforms previously returned
|
|
175
|
+
// [rootPid] only, so descendants were never sampled).
|
|
176
|
+
if (!existsSync("/proc")) {
|
|
177
|
+
try {
|
|
178
|
+
const res = spawnSync("ps", ["-eo", "pid=,ppid="], { encoding: "utf8" });
|
|
179
|
+
if (res.status !== 0 || !res.stdout.trim()) return [rootPid];
|
|
180
|
+
const ppidOf = new Map();
|
|
181
|
+
for (const line of res.stdout.trim().split("\n")) {
|
|
182
|
+
const parts = line.trim().split(/\s+/);
|
|
183
|
+
if (parts.length >= 2) ppidOf.set(Number.parseInt(parts[0], 10), Number.parseInt(parts[1], 10));
|
|
184
|
+
}
|
|
185
|
+
const result = new Set([rootPid]);
|
|
186
|
+
let grew = true;
|
|
187
|
+
while (grew) {
|
|
188
|
+
grew = false;
|
|
189
|
+
for (const [pid, ppid] of ppidOf) {
|
|
190
|
+
if (result.has(ppid) && !result.has(pid)) {
|
|
191
|
+
result.add(pid);
|
|
192
|
+
grew = true;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return [...result];
|
|
197
|
+
} catch {
|
|
198
|
+
return [rootPid];
|
|
199
|
+
}
|
|
200
|
+
}
|
|
167
201
|
const all = [];
|
|
168
202
|
try {
|
|
169
203
|
for (const name of readdirSync("/proc")) {
|
|
@@ -62,6 +62,32 @@ Use observable checks:
|
|
|
62
62
|
- compatibility requirements such as Windows paths or Pi CLI flags;
|
|
63
63
|
- rollback notes.
|
|
64
64
|
|
|
65
|
+
## Spec Pairs (pi-crew v0.10.1+, ADR-6)
|
|
66
|
+
|
|
67
|
+
When the target runs pi-crew, author the **SpecRecord + TaskPacket pair** instead of prose-only acceptance:
|
|
68
|
+
|
|
69
|
+
1. **SpecRecord** (workspace `state/specs/<id>.json`): `requirements[]` with
|
|
70
|
+
`must|should|could` priority + stable ids; `acceptance[]` entries each tied to
|
|
71
|
+
a `requirementId`. Machine-checkable acceptances carry `command`,
|
|
72
|
+
`expectedDigest` (sha-256 hex of stdout) or `expectedExitCode`, and
|
|
73
|
+
`idempotent: true` — only idempotent commands are ever re-run.
|
|
74
|
+
2. **PROVENANCE — critical**: specs you (an agent/skill path) write are persisted
|
|
75
|
+
`generated` and NEVER re-executed by the orchestrator. `manual`+`trusted`
|
|
76
|
+
(the only specs strict mode re-runs) are minted exclusively by USER-facing
|
|
77
|
+
import actions — a worker cannot author a command the root re-executes.
|
|
78
|
+
3. **Wire the workflow**: add `specRefs: [<spec ids>]` to steps held to the spec;
|
|
79
|
+
`specStrict: true` in frontmatter opts the whole workflow into strict mode
|
|
80
|
+
(requires a `verifier` role step — the run rejects at start otherwise).
|
|
81
|
+
4. **Executor footer contract**: workers must END results with
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
SPEC-EVIDENCE:
|
|
85
|
+
<acceptanceId>: <one-line evidence>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Non-strict = mechanical coverage only (`unverified` badge on gaps, never
|
|
89
|
+
blocks). Strict = coverage AND machine-check; failures fail the run.
|
|
90
|
+
|
|
65
91
|
## Enforcement — Requirements to Task Packet Gate
|
|
66
92
|
|
|
67
93
|
**Before dispatching workers, verify task packet has:**
|
|
@@ -32,16 +32,16 @@ In-memory map from `live-agent-manager.ts`. Provides:
|
|
|
32
32
|
|
|
33
33
|
**When NOT used:** After `evictStaleLiveAgentHandles()` removes a handle, widget falls back to agent records on disk.
|
|
34
34
|
|
|
35
|
-
### 2. Snapshot cache (
|
|
35
|
+
### 2. Snapshot cache (1500ms TTL)
|
|
36
36
|
|
|
37
|
-
`RunSnapshotCache` from `run-snapshot-cache.ts` caches parsed manifests and agents for
|
|
37
|
+
`RunSnapshotCache` from `run-snapshot-cache.ts` caches parsed manifests and agents for 1500ms. Reduces disk reads during rapid refresh.
|
|
38
38
|
|
|
39
39
|
**When used:** As the fallback when no live handle exists. Prevents excessive disk reads on every render tick.
|
|
40
40
|
|
|
41
41
|
**Invalidation:** Cache is invalidated when:
|
|
42
42
|
- `invalidate()` is called on a specific run
|
|
43
43
|
- An empty result is returned (forces refresh on next tick)
|
|
44
|
-
- TTL expires (
|
|
44
|
+
- TTL expires (1500ms)
|
|
45
45
|
|
|
46
46
|
### 3. `agents.json` on disk (durables, lowest priority)
|
|
47
47
|
|
|
@@ -156,7 +156,7 @@ Every render cycle (`renderTick` / `requestAnimationFrame`) must complete in <16
|
|
|
156
156
|
|
|
157
157
|
### TTL interactions
|
|
158
158
|
|
|
159
|
-
- Snapshot cache TTL =
|
|
159
|
+
- Snapshot cache TTL = 1500ms
|
|
160
160
|
- Preload interval must be < TTL to avoid render-time gaps
|
|
161
161
|
- If preload interval ≥ TTL, the cache always has fresh data for render
|
|
162
162
|
|
|
@@ -248,7 +248,7 @@ If ANY answer is NO → Stop. Fix widget rendering issues before proceeding.
|
|
|
248
248
|
## Anti-patterns
|
|
249
249
|
|
|
250
250
|
- **Blocking render with fs calls**: Every `readFileSync`, `readdirSync`, `fs.statSync` in the render path causes frame drops. Preload everything async.
|
|
251
|
-
- **Stale cache in hot path**: If snapshot cache TTL is too long, widget shows outdated state. Keep TTL at
|
|
251
|
+
- **Stale cache in hot path**: If snapshot cache TTL is too long, widget shows outdated state. Keep TTL at 1500ms or less (the code default; lower only with cause).
|
|
252
252
|
- **No invalidation on empty**: When `readCrewAgents` returns `[]` (no agents yet), the cache must be invalidated on next tick to prevent showing empty for too long.
|
|
253
253
|
- **Expired handles accumulating**: Without `evictStaleLiveAgentHandles`, the Map grows indefinitely. Call it on every refresh.
|
|
254
254
|
- **Widget showing stale health warnings**: Completed/cancelled/failed runs should not show health warnings. Filter by status.
|
|
@@ -258,7 +258,7 @@ If ANY answer is NO → Stop. Fix widget rendering issues before proceeding.
|
|
|
258
258
|
## Source patterns
|
|
259
259
|
|
|
260
260
|
- `src/ui/crew-widget.ts` — render, refresh, activeWidgetRuns, evictStaleLiveAgentHandles, agentActivity, describeLiveActivity
|
|
261
|
-
- `src/ui/run-snapshot-cache.ts` — SnapshotCache, get, refreshIfStale, TTL=
|
|
261
|
+
- `src/ui/run-snapshot-cache.ts` — SnapshotCache, get, refreshIfStale, TTL=1500ms
|
|
262
262
|
- `src/runtime/crew-agent-records.ts` — readCrewAgents, agents.json
|
|
263
263
|
- `src/runtime/process-status.ts` — hasStaleAsyncProcess, isDisplayActiveRun
|
|
264
264
|
- `src/runtime/background-runner.ts` — active run filtering with async PID check
|
|
@@ -275,7 +275,7 @@ Render-path performance for the widget is non-negotiable. Treat every `render(wi
|
|
|
275
275
|
- **Prefer `snapshotCache.get(runId)`** on render paths. If a synchronous fallback is genuinely unavoidable, classify it as first-load/rare and document why it can't be preloaded.
|
|
276
276
|
- **Keep panes pure.** Dashboard panes must accept a snapshot/model and format strings only. Never call `fs.readFileSync`, `fs.readdirSync`, `fs.statSync`, network APIs, or large JSON parsing from pane render methods.
|
|
277
277
|
- **Stay non-blocking at 60fps.** Each render cycle must complete in under ~16ms. Anything that can't finish synchronously (reads, fetches, directory scans) belongs in the async preload path, not `renderTick()`.
|
|
278
|
-
- **Respect the snapshot-cache TTL of ≤
|
|
278
|
+
- **Respect the snapshot-cache TTL of ≤1500ms.** Keep the `RunSnapshotCache` TTL at 1500ms or less (the code default; lower only with cause) so the widget never shows stale state. Watch TTL interactions: the preload interval must be shorter than the cache TTL, otherwise render-time refresh gaps appear.
|
|
279
279
|
- **Guard session switches.** On a session switch, cancel timers and ensure in-flight async preloads cannot update a now-stale session's UI.
|
|
280
280
|
- **Filter stale warnings by terminal status.** Do not surface health warnings for completed/failed/cancelled runs.
|
|
281
281
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { getCrewEnv } from "../config/env-vars.ts";
|
|
1
2
|
import type { RoleToolConfig } from "../config/role-tools.ts";
|
|
2
|
-
import { getToolConfig } from "../config/role-tools.ts";
|
|
3
|
+
import { getToolConfig, isScratchpadEnabledForRole } from "../config/role-tools.ts";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* F1 (v0.7.9): canonical built-in tool name list. Used by `parseToolsField`
|
|
@@ -162,24 +163,45 @@ export function resolveToolPolicy(agent: AgentConfig, role?: string): ResolvedTo
|
|
|
162
163
|
const roleConfig = role ? getToolConfig(role) : {};
|
|
163
164
|
// allowlist: source-aware precedence (see doc above).
|
|
164
165
|
const explicitTools = agent.source === "builtin" ? (roleConfig.tools ?? agent.tools) : (agent.tools ?? roleConfig.tools);
|
|
165
|
-
|
|
166
|
-
// non-empty `defaultTools` list, merge that list into the resolved
|
|
167
|
-
// allowlist. The merge is additive (union, dedup, order-preserving) so
|
|
168
|
-
// the existing source-aware precedence is preserved and a lean agent
|
|
169
|
-
// gets a focused-but-non-empty tool set. Signal flow:
|
|
170
|
-
// agent YAML frontmatter (loadMode, defaultTools)
|
|
171
|
-
// → parsed into AgentConfig
|
|
172
|
-
// → resolveToolPolicy(agent, role) here
|
|
173
|
-
// → policy.tools returned to buildPiWorkerArgs
|
|
174
|
-
// → `args.push("--tools", policy.tools.join(","))` in pi-args.ts
|
|
175
|
-
// → child pi process sees the merged allowlist
|
|
176
|
-
const tools =
|
|
166
|
+
let tools =
|
|
177
167
|
agent.loadMode === "lean" && agent.defaultTools?.length ? uniqueToolMerge(explicitTools, agent.defaultTools) : explicitTools;
|
|
178
168
|
// denylist: additive merge of role excludeTools + agent disallowedTools.
|
|
179
|
-
|
|
169
|
+
let excludeTools = uniqueToolMerge(roleConfig.excludeTools, agent.disallowedTools);
|
|
170
|
+
// P2 (scratchpad adoption lever, rlm-deep-review-2026-08-12.md §5.1A):
|
|
171
|
+
// when scratchpad is armed for this role AND the operator opted in via
|
|
172
|
+
// PI_CREW_SCRATCHPAD_DEMOTE_BASH=1, remove `bash` from the tool surface so
|
|
173
|
+
// the model reaches for `sh()` inside scratchpad cells (structured value
|
|
174
|
+
// reuse) instead of `bash` (which always wins by default — the documented
|
|
175
|
+
// root cause of 0 scratchpad adoption). Gated behind a flag because it
|
|
176
|
+
// changes the tool surface the model sees (behavioral risk). The model
|
|
177
|
+
// keeps read/edit/write/ls/grep/find; shell ops must go via `sh()`.
|
|
178
|
+
if (shouldDemoteBashForScratchpad(role, agent)) {
|
|
179
|
+
tools = tools ? tools.filter((t) => t !== "bash") : tools;
|
|
180
|
+
excludeTools = uniqueToolMerge(excludeTools, ["bash"]);
|
|
181
|
+
}
|
|
180
182
|
return { tools, excludeTools };
|
|
181
183
|
}
|
|
182
184
|
|
|
185
|
+
/**
|
|
186
|
+
* P2: should `bash` be demoted (removed) for a scratchpad-armed role?
|
|
187
|
+
*
|
|
188
|
+
* True only when BOTH hold:
|
|
189
|
+
* (a) the role has scratchpad enabled (so the model still has a way to run
|
|
190
|
+
* shell commands — via the `sh()` binding inside scratchpad cells);
|
|
191
|
+
* (b) the operator opted in via `PI_CREW_SCRATCHPAD_DEMOTE_BASH=1`.
|
|
192
|
+
*
|
|
193
|
+
* Default off → zero behavior change (existing adoption stays at 0). On → the
|
|
194
|
+
* lever to break 0-adoption without full tool collapse. This is read-only
|
|
195
|
+
* config logic; the actual tool-surface change happens in `resolveToolPolicy`
|
|
196
|
+
* above and flows to BOTH spawn paths (child-pi `--tools`/`--exclude-tools` and
|
|
197
|
+
* live-session filterActiveTools) via the unified policy.
|
|
198
|
+
*/
|
|
199
|
+
function shouldDemoteBashForScratchpad(role: string | undefined, agent: AgentConfig): boolean {
|
|
200
|
+
if (getCrewEnv("PI_CREW_SCRATCHPAD_DEMOTE_BASH") !== "1") return false;
|
|
201
|
+
if (!role) return false;
|
|
202
|
+
return isScratchpadEnabledForRole(role, { scratchpad: agent.scratchpad });
|
|
203
|
+
}
|
|
204
|
+
|
|
183
205
|
/**
|
|
184
206
|
* Build agent session options including role-based tool restrictions.
|
|
185
207
|
* @param agent - The agent configuration
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { type LoadedPiTeamsConfig, loadConfig } from "../config/config.ts";
|
|
4
|
+
import { getCrewEnv } from "../config/env-vars.ts";
|
|
4
5
|
import { discoverProviderExtensionPaths } from "../runtime/model/provider-extensions.ts";
|
|
5
6
|
import { parseCsv, parseFrontmatter } from "../utils/frontmatter.ts";
|
|
6
7
|
import { logInternalError } from "../utils/internal-error.ts";
|
|
@@ -136,19 +137,13 @@ function logSecurityEvent(event: SecurityEvent): void {
|
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
/**
|
|
139
|
-
* Get recent security events
|
|
140
|
+
* Get recent security events. Production reader: the team doctor report
|
|
141
|
+
* surfaces a compact summary (R7-13); tests assert on the full list.
|
|
140
142
|
*/
|
|
141
143
|
export function getSecurityEventLog(): readonly SecurityEvent[] {
|
|
142
144
|
return securityEventLog;
|
|
143
145
|
}
|
|
144
146
|
|
|
145
|
-
/**
|
|
146
|
-
* Clear security event log (for testing).
|
|
147
|
-
*/
|
|
148
|
-
export function clearSecurityEventLog(): void {
|
|
149
|
-
securityEventLog.length = 0;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
147
|
/**
|
|
153
148
|
* Security check: throws if the agent name is protected.
|
|
154
149
|
*
|
|
@@ -373,7 +368,11 @@ export function sanitizeAgentSystemPrompt(content: string, source: ResourceSourc
|
|
|
373
368
|
* emitted the `contextMode: fork` warn-only notice. Avoids spam when
|
|
374
369
|
* the discovery cache reloads or the same agent is parsed multiple
|
|
375
370
|
* times in a session. Exported for test reset.
|
|
371
|
+
* R5-L5: FIFO cap so the set stays bounded in long-lived sessions
|
|
372
|
+
* (Set preserves insertion order; bounded naturally <50, cap is a
|
|
373
|
+
* safety net).
|
|
376
374
|
*/
|
|
375
|
+
const MAX_WARNED_FORK_AGENTS = 128;
|
|
377
376
|
const warnedForkAgents = new Set<string>();
|
|
378
377
|
export function __test_resetForkWarnings(): void {
|
|
379
378
|
warnedForkAgents.clear();
|
|
@@ -406,14 +405,19 @@ function parseAgentFile(filePath: string, source: ResourceSource): AgentConfig |
|
|
|
406
405
|
// so the agent will behave as `fresh` regardless of the setting.
|
|
407
406
|
// We warn (not throw) so existing configs that predate live-session
|
|
408
407
|
// keep working. Deduped per-filePath so we don't spam on cache
|
|
409
|
-
// reload.
|
|
410
|
-
//
|
|
411
|
-
// logInternalError
|
|
408
|
+
// reload. User-facing config notice (kept on console.warn deliberately
|
|
409
|
+
// so the user sees it in the interactive session; internal failures
|
|
410
|
+
// below use logInternalError).
|
|
412
411
|
if (contextMode === "fork" && !warnedForkAgents.has(filePath)) {
|
|
413
412
|
console.warn(
|
|
414
413
|
"contextMode: 'fork' is only effective in live-session runtime; current default child-process will behave as 'fresh'. See docs/runtime-flow.md.",
|
|
415
414
|
);
|
|
416
415
|
warnedForkAgents.add(filePath);
|
|
416
|
+
// R5-L5: FIFO eviction — drop the oldest entry past the cap.
|
|
417
|
+
if (warnedForkAgents.size > MAX_WARNED_FORK_AGENTS) {
|
|
418
|
+
const oldest = warnedForkAgents.values().next().value;
|
|
419
|
+
if (oldest !== undefined) warnedForkAgents.delete(oldest);
|
|
420
|
+
}
|
|
417
421
|
}
|
|
418
422
|
|
|
419
423
|
return {
|
|
@@ -442,7 +446,7 @@ function parseAgentFile(filePath: string, source: ResourceSource): AgentConfig |
|
|
|
442
446
|
// code. Bypass only when PI_CREW_TRUST_PROJECT_AGENT_EXTENSIONS=1 is
|
|
443
447
|
// explicitly set. buildPiWorkerArgs also enforces this as
|
|
444
448
|
// defense-in-depth.
|
|
445
|
-
...((source === "project" || source === "project-pi") &&
|
|
449
|
+
...((source === "project" || source === "project-pi") && getCrewEnv("PI_CREW_TRUST_PROJECT_AGENT_EXTENSIONS") !== "1"
|
|
446
450
|
? { extensions: [], excludeExtensions: [] }
|
|
447
451
|
: {
|
|
448
452
|
extensions: frontmatter.extensions === "" ? [] : parseCsv(frontmatter.extensions),
|
|
@@ -494,7 +498,12 @@ function readAgentDir(dir: string, source: ResourceSource): AgentConfig[] {
|
|
|
494
498
|
try {
|
|
495
499
|
const stat = fs.statSync(fullPath);
|
|
496
500
|
if (stat.size > MAX_AGENT_FILE_BYTES) {
|
|
497
|
-
|
|
501
|
+
logInternalError(
|
|
502
|
+
"discover-agents",
|
|
503
|
+
new Error(`Skipping oversized agent file (${stat.size} > ${MAX_AGENT_FILE_BYTES} bytes): ${fullPath}`),
|
|
504
|
+
undefined,
|
|
505
|
+
"warn",
|
|
506
|
+
);
|
|
498
507
|
return undefined;
|
|
499
508
|
}
|
|
500
509
|
} catch {
|
|
@@ -536,7 +545,7 @@ function applyAgentOverrides(agents: AgentConfig[], cwd: string, loadedConfig?:
|
|
|
536
545
|
// user-trusted config knob (provider extensions like pi-commandcode-provider)
|
|
537
546
|
// and applies to builtin / user agents only.
|
|
538
547
|
const isUntrustedProject = (agent: AgentConfig) =>
|
|
539
|
-
(agent.source === "project" || agent.source === "project-pi") &&
|
|
548
|
+
(agent.source === "project" || agent.source === "project-pi") && getCrewEnv("PI_CREW_TRUST_PROJECT_AGENT_EXTENSIONS") !== "1";
|
|
540
549
|
const withGlobalExtensions = (agent: AgentConfig): AgentConfig => {
|
|
541
550
|
if (isUntrustedProject(agent)) return agent;
|
|
542
551
|
return deduped.length > 0 || agent.extensions !== undefined
|