pi-crew 0.1.28 → 0.1.30

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.
Files changed (59) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/NOTICE.md +1 -0
  3. package/docs/architecture.md +164 -92
  4. package/docs/refactor-tasks-phase6.md +662 -0
  5. package/docs/runtime-flow.md +148 -0
  6. package/package.json +1 -1
  7. package/schema.json +1 -0
  8. package/skills/git-master/SKILL.md +19 -0
  9. package/skills/read-only-explorer/SKILL.md +21 -0
  10. package/skills/safe-bash/SKILL.md +16 -0
  11. package/skills/task-packet/SKILL.md +23 -0
  12. package/skills/verify-evidence/SKILL.md +22 -0
  13. package/src/config/config.ts +2 -0
  14. package/src/config/defaults.ts +1 -0
  15. package/src/extension/async-notifier.ts +33 -4
  16. package/src/extension/register.ts +15 -522
  17. package/src/extension/registration/artifact-cleanup.ts +14 -0
  18. package/src/extension/registration/commands.ts +208 -0
  19. package/src/extension/registration/subagent-helpers.ts +1 -1
  20. package/src/extension/registration/subagent-tools.ts +110 -0
  21. package/src/extension/registration/team-tool.ts +44 -0
  22. package/src/extension/team-tool/api.ts +4 -4
  23. package/src/extension/team-tool/cancel.ts +31 -0
  24. package/src/extension/team-tool/inspect.ts +41 -0
  25. package/src/extension/team-tool/lifecycle-actions.ts +79 -0
  26. package/src/extension/team-tool/plan.ts +19 -0
  27. package/src/extension/team-tool/run.ts +41 -3
  28. package/src/extension/team-tool/status.ts +73 -0
  29. package/src/extension/team-tool.ts +57 -224
  30. package/src/runtime/async-marker.ts +26 -0
  31. package/src/runtime/async-runner.ts +44 -9
  32. package/src/runtime/background-runner.ts +2 -0
  33. package/src/runtime/child-pi.ts +5 -1
  34. package/src/runtime/concurrency.ts +9 -3
  35. package/src/runtime/crew-agent-records.ts +1 -0
  36. package/src/runtime/crew-agent-runtime.ts +2 -1
  37. package/src/runtime/model-fallback.ts +21 -4
  38. package/src/runtime/pi-args.ts +2 -0
  39. package/src/runtime/process-status.ts +1 -0
  40. package/src/runtime/role-permission.ts +11 -0
  41. package/src/runtime/task-runner/live-executor.ts +98 -0
  42. package/src/runtime/task-runner/progress.ts +111 -0
  43. package/src/runtime/task-runner/prompt-builder.ts +72 -0
  44. package/src/runtime/task-runner/result-utils.ts +14 -0
  45. package/src/runtime/task-runner/state-helpers.ts +22 -0
  46. package/src/runtime/task-runner.ts +38 -283
  47. package/src/runtime/team-runner.ts +116 -7
  48. package/src/schema/config-schema.ts +1 -0
  49. package/src/state/mailbox.ts +28 -0
  50. package/src/state/types.ts +16 -0
  51. package/src/subagents/async-entry.ts +1 -0
  52. package/src/subagents/index.ts +3 -0
  53. package/src/subagents/live/control.ts +1 -0
  54. package/src/subagents/live/manager.ts +1 -0
  55. package/src/subagents/live/realtime.ts +1 -0
  56. package/src/subagents/live/session-runtime.ts +1 -0
  57. package/src/subagents/manager.ts +1 -0
  58. package/src/subagents/spawn.ts +1 -0
  59. package/src/ui/live-run-sidebar.ts +1 -1
@@ -0,0 +1,148 @@
1
+ # pi-crew Runtime Flow
2
+
3
+ This document is a compact map of the runtime paths used by `pi-crew`.
4
+
5
+ ## Main sequence
6
+
7
+ ```text
8
+ User / model
9
+ │ calls team({ action: "run", ... }) or /team-run
10
+
11
+ handleTeamTool()
12
+ │ validates schema and routes action
13
+
14
+ handleRun()
15
+ ├─ discoverTeams/discoverWorkflows/discoverAgents
16
+ ├─ validateWorkflowForTeam
17
+ ├─ expandParallelResearchWorkflow when applicable
18
+ ├─ createRunManifest + tasks.json + goal artifact
19
+ ├─ if async=true ─────────────────────────────────────────────┐
20
+ │ spawnBackgroundTeamRun() │
21
+ │ ├─ resolve jiti-register.mjs │
22
+ │ ├─ fail-fast if jiti missing │
23
+ │ ├─ node --import jiti-register.mjs background-runner.ts │
24
+ │ └─ parent schedules early-exit guard │
25
+ │ ▼
26
+ │ background-runner.ts
27
+ │ ├─ append async.started
28
+ │ ├─ write async.pid startup marker
29
+ │ ├─ rediscover team/workflow/agents
30
+ │ └─ executeTeamRun()
31
+
32
+ └─ if foreground/default
33
+ ├─ startForegroundRun schedules session-bound run, or
34
+ └─ executeTeamRun inline for scaffold/non-scheduled paths
35
+
36
+ executeTeamRun()
37
+ ├─ write run.running
38
+ ├─ materialize queued/running agent records lazily
39
+ ├─ build task graph index
40
+ ├─ while queued tasks exist
41
+ │ ├─ taskGraphSnapshot
42
+ │ ├─ resolveBatchConcurrency
43
+ │ ├─ getReadyTasks
44
+ │ ├─ append task.progress batch event
45
+ │ ├─ mapConcurrent ready batch
46
+ │ │ └─ runTeamTask()
47
+ │ │ ├─ prepare workspace/worktree
48
+ │ │ ├─ build task packet
49
+ │ │ ├─ render prompt + dependency context
50
+ │ │ ├─ choose model candidates from Pi config
51
+ │ │ ├─ spawn child Pi process
52
+ │ │ ├─ ChildPiLineObserver parses stdout/stderr
53
+ │ │ ├─ append per-agent events/output
54
+ │ │ ├─ update agent progress/task state
55
+ │ │ ├─ parse final JSONL/session usage
56
+ │ │ └─ write result/log/transcript/metadata artifacts
57
+ │ ├─ merge task updates monotonically
58
+ │ ├─ optional adaptive plan injection
59
+ │ ├─ save tasks/agents/progress
60
+ │ └─ write batch artifact
61
+ ├─ policy closeout
62
+ └─ run.completed / run.failed / run.blocked / run.cancelled
63
+ ```
64
+
65
+ ## Action router
66
+
67
+ | Action | Handler | Purpose |
68
+ |---|---|---|
69
+ | `run` | `team-tool/run.ts` | Create and execute a run, foreground or async. |
70
+ | `status` | `team-tool.ts` | Show manifest/tasks/agents/events and mark stale async runs failed. |
71
+ | `summary` | `session-summary.ts`/summary handler | Write/read run summary artifact. |
72
+ | `events` | `team-tool.ts` | Tail durable run events. |
73
+ | `artifacts` | `team-tool.ts` | List run artifacts. |
74
+ | `resume` | `team-tool.ts` | Requeue failed/cancelled/skipped/running tasks. |
75
+ | `cancel` | `team-tool.ts` | Mark queued/running tasks cancelled and request foreground interrupt. |
76
+ | `forget` | `run-maintenance.ts` | Delete run state/artifacts with confirmation. |
77
+ | `prune` | `run-maintenance.ts` | Remove old finished runs with confirmation. |
78
+ | `export` | `run-export.ts` | Create portable run bundle. |
79
+ | `import` / `imports` | `run-import.ts` / `import-index.ts` | Store/list imported bundles. |
80
+ | `config` | `config.ts` + config action | Show/update user/project config. |
81
+ | `doctor` | `team-tool/doctor.ts` | Platform/resource/runtime diagnostics. |
82
+ | `validate` | `validate-resources.ts` | Validate agents/teams/workflows. |
83
+ | `recommend` | `team-recommendation.ts` | Suggest team/workflow/action for a goal. |
84
+ | management | `management.ts` | Create/update/delete/rename teams, agents, workflows. |
85
+ | API | `team-tool/api.ts` | File-backed observability/control/mailbox API. |
86
+
87
+ ## Worker modes
88
+
89
+ | Mode | Behavior |
90
+ |---|---|
91
+ | `child-process` | Default. Launches real child `pi` processes per task. |
92
+ | `scaffold` | Explicit dry-run. No child Pi worker execution. |
93
+ | `live-session` | Experimental/gated in-process/live agent path. |
94
+ | `auto` | Resolves to child-process unless config/env requests otherwise. |
95
+
96
+ ## Important files
97
+
98
+ ```text
99
+ src/extension/register.ts Pi extension entry/wiring
100
+ src/extension/team-tool/run.ts run creation and foreground/async split
101
+ src/runtime/background-runner.ts detached async entrypoint
102
+ src/runtime/async-runner.ts background spawn command/options
103
+ src/runtime/team-runner.ts workflow/task graph scheduler
104
+ src/runtime/task-runner.ts single task execution
105
+ src/runtime/child-pi.ts child Pi process and output observer
106
+ src/runtime/model-fallback.ts configured model candidates/routing
107
+ src/runtime/concurrency.ts batch concurrency decisions
108
+ src/runtime/process-status.ts pid/liveness/stale detection
109
+ src/state/state-store.ts manifest/tasks persistence
110
+ src/state/event-log.ts JSONL run events
111
+ src/runtime/crew-agent-records.ts aggregate + per-agent status files
112
+ ```
113
+
114
+ ## Environment variables
115
+
116
+ | Env | Effect |
117
+ |---|---|
118
+ | `PI_CREW_EXECUTE_WORKERS=0` | Disable real workers, use scaffold behavior. |
119
+ | `PI_TEAMS_EXECUTE_WORKERS=0` | Legacy alias for worker disable. |
120
+ | `PI_CREW_ENABLE_EXPERIMENTAL_LIVE_SESSION=1` | Allow experimental live-session runtime. |
121
+ | `PI_CREW_MOCK_LIVE_SESSION=success` | Test hook for live-session mock. |
122
+ | `PI_TEAMS_MOCK_CHILD_PI` | Test hook for mocked child Pi execution. |
123
+ | `PI_CREW_DEPTH`, `PI_CREW_MAX_DEPTH` | Canonical subagent recursion guard. |
124
+ | `PI_TEAMS_DEPTH`, `PI_TEAMS_MAX_DEPTH` | Legacy recursion guard aliases. |
125
+ | `PI_TEAMS_HOME` | Override user config/state home in tests. |
126
+ | `PI_TEAMS_PI_BIN` | Override child `pi` executable. |
127
+ | `PI_CODING_AGENT_DIR` | Override Pi settings/models directory for model discovery. |
128
+ | `PI_CREW_ASYNC_EARLY_EXIT_GUARD=0` | Disable 3s background early-exit guard. |
129
+
130
+ ## State transition summary
131
+
132
+ ```text
133
+ queued/planning/running ── completed
134
+ ├─ failed
135
+ ├─ blocked
136
+ └─ cancelled
137
+ ```
138
+
139
+ Task states follow the same durable contract plus `skipped`. Terminal states are monotonic during parallel merge.
140
+
141
+ ## Observability tips
142
+
143
+ - Use `/team-dashboard` for a UI overview.
144
+ - Use `team status runId=...` for canonical state and stale async detection.
145
+ - Read `background.log` for early import/spawn errors.
146
+ - Read `events.jsonl` for event chronology.
147
+ - Read `agents/{taskId}/status.json` for per-agent model/progress/tool status.
148
+ - Read `artifacts/{runId}/transcripts/{taskId}.jsonl` for raw child Pi transcript.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-crew",
3
- "version": "0.1.28",
3
+ "version": "0.1.30",
4
4
  "description": "Pi extension for coordinated AI teams, workflows, worktrees, and async task orchestration",
5
5
  "author": "baphuongna",
6
6
  "license": "MIT",
package/schema.json CHANGED
@@ -47,6 +47,7 @@
47
47
  "description": "Runtime safety limits for crew workers and policy decisions.",
48
48
  "properties": {
49
49
  "maxConcurrentWorkers": { "type": "integer", "minimum": 1 },
50
+ "allowUnboundedConcurrency": { "type": "boolean" },
50
51
  "maxTaskDepth": { "type": "integer", "minimum": 1 },
51
52
  "maxChildrenPerTask": { "type": "integer", "minimum": 1 },
52
53
  "maxRunMinutes": { "type": "integer", "minimum": 1 },
@@ -0,0 +1,19 @@
1
+ # git-master
2
+
3
+ Use this skill for commit/release hygiene.
4
+
5
+ ## Commit rules
6
+
7
+ - Check `git status --short` before staging.
8
+ - Stage only files related to the current task.
9
+ - Keep commits independently revertible.
10
+ - Use concise imperative commit messages.
11
+ - Do not push or publish unless explicitly requested.
12
+ - Do not include secrets, OTPs, local temp files, or generated tarballs.
13
+
14
+ ## Release rules
15
+
16
+ - Run the required verification gate before version bumps.
17
+ - Bump version only after tests pass and user confirms publish intent.
18
+ - Verify registry after publish with `npm view`.
19
+ - Install through `pi install npm:pi-crew` when validating Pi package loading.
@@ -0,0 +1,21 @@
1
+ # read-only-explorer
2
+
3
+ Use this skill for explorer, analyst, reviewer, and source-audit roles.
4
+
5
+ ## Contract
6
+
7
+ - Do not edit files.
8
+ - Do not write generated artifacts outside the run artifact directory.
9
+ - Prefer `read`, `rg`, `find`, `git status`, and package metadata inspection.
10
+ - Record exact files inspected.
11
+ - Distinguish direct evidence from inference.
12
+ - If implementation is needed, recommend it instead of modifying code.
13
+
14
+ ## Output shape
15
+
16
+ Return:
17
+
18
+ 1. files inspected;
19
+ 2. findings with path references;
20
+ 3. risks/unknowns;
21
+ 4. recommended next tests or implementation tasks.
@@ -0,0 +1,16 @@
1
+ # safe-bash
2
+
3
+ Use this skill whenever a task may execute shell commands.
4
+
5
+ ## Rules
6
+
7
+ - Prefer read-only commands first: `pwd`, `ls`, `find`, `rg`, `git status`, package-manager dry runs.
8
+ - Before mutating commands, explain the target path and expected effect.
9
+ - Never run destructive cleanup (`rm -rf`, `git clean`, force delete, prune, reset hard) without explicit confirmation.
10
+ - Avoid shell-specific assumptions when a cross-platform Node/Pi API exists.
11
+ - On Windows, prefer argv-based process execution and avoid `cmd /c start` or `/bin/bash` unless explicitly required.
12
+ - Capture verification output and summarize exit status.
13
+
14
+ ## Reporting
15
+
16
+ Mention commands run and whether they were read-only or mutating.
@@ -0,0 +1,23 @@
1
+ # task-packet
2
+
3
+ Use this skill when creating or executing a worker task.
4
+
5
+ ## Required sections
6
+
7
+ Each task should clarify:
8
+
9
+ - objective;
10
+ - scope and paths;
11
+ - constraints and permissions;
12
+ - dependencies and expected inputs;
13
+ - expected outputs/artifacts;
14
+ - acceptance criteria;
15
+ - verification commands;
16
+ - escalation conditions.
17
+
18
+ ## Worker behavior
19
+
20
+ - Read dependency outputs before starting dependent work.
21
+ - Keep outputs concise and artifact-oriented.
22
+ - Do not claim completion until required artifacts and status are durable.
23
+ - If blocked, report the blocker and the smallest recoverable next action.
@@ -0,0 +1,22 @@
1
+ # verify-evidence
2
+
3
+ Use this skill before finalizing implementation, review, or audit work.
4
+
5
+ ## Required final evidence
6
+
7
+ Include:
8
+
9
+ - changed files, or `none` for read-only work;
10
+ - tests/checks run with pass/fail result;
11
+ - relevant artifacts, run IDs, or log paths;
12
+ - unresolved risks and rollback notes when code changed.
13
+
14
+ ## Verification ladder
15
+
16
+ Prefer the smallest reliable check first, then escalate:
17
+
18
+ 1. Targeted unit tests for touched behavior.
19
+ 2. Typecheck for TypeScript changes.
20
+ 3. Integration tests for runtime/spawn/state changes.
21
+ 4. `npm pack --dry-run` for package/release/doc changes.
22
+ 5. Real Pi smoke only when needed and safe.
@@ -18,6 +18,7 @@ export interface PiTeamsAutonomousConfig {
18
18
 
19
19
  export interface CrewLimitsConfig {
20
20
  maxConcurrentWorkers?: number;
21
+ allowUnboundedConcurrency?: boolean;
21
22
  maxTaskDepth?: number;
22
23
  maxChildrenPerTask?: number;
23
24
  maxRunMinutes?: number;
@@ -292,6 +293,7 @@ function parseLimitsConfig(value: unknown): CrewLimitsConfig | undefined {
292
293
  if (!obj) return undefined;
293
294
  const limits: CrewLimitsConfig = {
294
295
  maxConcurrentWorkers: parsePositiveInteger(obj.maxConcurrentWorkers, LIMIT_CEILINGS.maxConcurrentWorkers),
296
+ allowUnboundedConcurrency: parseWithSchema(Type.Boolean(), obj.allowUnboundedConcurrency),
295
297
  maxTaskDepth: parsePositiveInteger(obj.maxTaskDepth, LIMIT_CEILINGS.maxTaskDepth),
296
298
  maxChildrenPerTask: parsePositiveInteger(obj.maxChildrenPerTask, LIMIT_CEILINGS.maxChildrenPerTask),
297
299
  maxRunMinutes: parsePositiveInteger(obj.maxRunMinutes, LIMIT_CEILINGS.maxRunMinutes),
@@ -17,6 +17,7 @@ export const DEFAULT_LOCKS = {
17
17
  };
18
18
 
19
19
  export const DEFAULT_CONCURRENCY = {
20
+ hardCap: 8,
20
21
  workflow: {
21
22
  parallelResearch: 4,
22
23
  research: 2,
@@ -1,4 +1,8 @@
1
1
  import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
2
+ import { appendEvent, readEvents, type TeamEvent } from "../state/event-log.ts";
3
+ import { checkProcessLiveness, isActiveRunStatus } from "../runtime/process-status.ts";
4
+ import { updateRunStatus } from "../state/state-store.ts";
5
+ import type { TeamRunManifest } from "../state/types.ts";
2
6
  import { listRuns } from "./run-index.ts";
3
7
 
4
8
  export interface AsyncNotifierState {
@@ -10,6 +14,30 @@ function isFinished(status: string): boolean {
10
14
  return status === "completed" || status === "failed" || status === "cancelled" || status === "blocked";
11
15
  }
12
16
 
17
+ function isAsyncTerminalEvent(event: TeamEvent): boolean {
18
+ return event.type === "async.completed" || event.type === "async.failed" || event.type === "async.died";
19
+ }
20
+
21
+ function latestEventAgeMs(events: TeamEvent[], now = Date.now()): number {
22
+ const latest = events.at(-1);
23
+ if (!latest) return Number.POSITIVE_INFINITY;
24
+ const time = new Date(latest.time).getTime();
25
+ return Number.isFinite(time) ? now - time : Number.POSITIVE_INFINITY;
26
+ }
27
+
28
+ export function markDeadAsyncRunIfNeeded(run: TeamRunManifest, now = Date.now(), quietMs = 30_000): TeamRunManifest | undefined {
29
+ if (!run.async || !isActiveRunStatus(run.status)) return undefined;
30
+ const liveness = checkProcessLiveness(run.async.pid);
31
+ if (liveness.alive) return undefined;
32
+ const events = readEvents(run.eventsPath);
33
+ if (events.some(isAsyncTerminalEvent)) return undefined;
34
+ if (latestEventAgeMs(events, now) < quietMs) return undefined;
35
+ const message = `Background runner died unexpectedly; check background.log (${liveness.detail}).`;
36
+ const failed = updateRunStatus(run, "failed", message);
37
+ appendEvent(failed.eventsPath, { type: "async.died", runId: failed.runId, message, data: { pid: run.async.pid, detail: liveness.detail } });
38
+ return failed;
39
+ }
40
+
13
41
  export function startAsyncRunNotifier(ctx: ExtensionContext, state: AsyncNotifierState, intervalMs = 5000): void {
14
42
  if (state.interval) clearInterval(state.interval);
15
43
  for (const run of listRuns(ctx.cwd)) {
@@ -20,10 +48,11 @@ export function startAsyncRunNotifier(ctx: ExtensionContext, state: AsyncNotifie
20
48
  state.interval = setInterval(() => {
21
49
  try {
22
50
  for (const run of listRuns(ctx.cwd).slice(0, 20)) {
23
- if (!isFinished(run.status) || state.seenFinishedRunIds.has(run.runId)) continue;
24
- state.seenFinishedRunIds.add(run.runId);
25
- const level = run.status === "completed" ? "info" : run.status === "cancelled" ? "warning" : "error";
26
- ctx.ui.notify(`pi-crew run ${run.status}: ${run.runId} (${run.team}/${run.workflow ?? "none"})`, level);
51
+ const current = markDeadAsyncRunIfNeeded(run) ?? run;
52
+ if (!isFinished(current.status) || state.seenFinishedRunIds.has(current.runId)) continue;
53
+ state.seenFinishedRunIds.add(current.runId);
54
+ const level = current.status === "completed" ? "info" : current.status === "cancelled" ? "warning" : "error";
55
+ ctx.ui.notify(`pi-crew run ${current.status}: ${current.runId} (${current.team}/${current.workflow ?? "none"})`, level);
27
56
  }
28
57
  } catch (error) {
29
58
  const message = error instanceof Error ? error.message : String(error);