pi-crew 0.6.0 → 0.6.3
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 +225 -0
- package/README.md +70 -31
- package/docs/issue-29-analysis.md +189 -0
- package/docs/superpowers/plans/2026-06-09-fallow-patterns-adoption.md +1268 -0
- package/package.json +2 -2
- package/src/agents/agent-config.ts +2 -1
- package/src/benchmark/feedback-loop.ts +4 -2
- package/src/config/config.ts +106 -15
- package/src/errors.ts +107 -0
- package/src/extension/async-notifier.ts +6 -2
- package/src/extension/crew-cleanup.ts +8 -5
- package/src/extension/cross-extension-rpc.ts +48 -0
- package/src/extension/management.ts +464 -109
- package/src/extension/register.ts +194 -34
- package/src/extension/registration/commands.ts +4 -3
- package/src/extension/registration/subagent-helpers.ts +2 -2
- package/src/extension/registration/subagent-tools.ts +3 -1
- package/src/extension/registration/team-tool.ts +3 -1
- package/src/extension/registration/viewers.ts +3 -2
- package/src/extension/run-export.ts +16 -1
- package/src/extension/run-import.ts +16 -0
- package/src/extension/team-tool/anchor.ts +5 -1
- package/src/extension/team-tool/api.ts +12 -7
- package/src/extension/team-tool/cancel.ts +3 -3
- package/src/extension/team-tool/config-patch.ts +15 -1
- package/src/extension/team-tool/explain.ts +1 -1
- package/src/extension/team-tool/handle-schedule.ts +40 -0
- package/src/extension/team-tool/inspect.ts +3 -3
- package/src/extension/team-tool/lifecycle-actions.ts +4 -4
- package/src/extension/team-tool/respond.ts +2 -2
- package/src/extension/team-tool/run.ts +60 -11
- package/src/extension/team-tool/status.ts +1 -1
- package/src/extension/team-tool.ts +175 -47
- package/src/hooks/registry.ts +84 -12
- package/src/hooks/types.ts +12 -3
- package/src/i18n.ts +15 -2
- package/src/observability/exporters/otlp-exporter.ts +73 -0
- package/src/plugins/plugin-define.ts +6 -0
- package/src/plugins/plugin-registry.ts +32 -0
- package/src/plugins/plugins/index.ts +3 -0
- package/src/plugins/plugins/nextjs.ts +19 -0
- package/src/plugins/plugins/vite.ts +14 -0
- package/src/plugins/plugins/vitest.ts +14 -0
- package/src/runtime/adaptive-plan.ts +24 -0
- package/src/runtime/agent-control.ts +6 -3
- package/src/runtime/async-runner.ts +86 -3
- package/src/runtime/background-runner.ts +529 -144
- package/src/runtime/chain-parser.ts +5 -1
- package/src/runtime/chain-runner.ts +67 -3
- package/src/runtime/checkpoint.ts +262 -180
- package/src/runtime/child-pi.ts +165 -38
- package/src/runtime/crash-recovery.ts +25 -14
- package/src/runtime/crew-agent-records.ts +6 -3
- package/src/runtime/cross-extension-rpc.ts +34 -8
- package/src/runtime/diagnostic-export.ts +4 -5
- package/src/runtime/dynamic-script-runner.ts +9 -6
- package/src/runtime/foreground-watchdog.ts +3 -3
- package/src/runtime/heartbeat-watcher.ts +19 -2
- package/src/runtime/intercom-bridge.ts +7 -0
- package/src/runtime/iteration-hooks.ts +1 -1
- package/src/runtime/live-agent-manager.ts +6 -3
- package/src/runtime/live-irc.ts +4 -2
- package/src/runtime/manifest-cache.ts +4 -0
- package/src/runtime/orphan-worker-registry.ts +444 -0
- package/src/runtime/parallel-utils.ts +2 -1
- package/src/runtime/parent-guard.ts +70 -16
- package/src/runtime/pi-args.ts +437 -14
- package/src/runtime/pi-spawn.ts +1 -0
- package/src/runtime/post-checks.ts +11 -4
- package/src/runtime/retry-runner.ts +9 -3
- package/src/runtime/{drift-detectors.ts → run-drift.ts} +1 -1
- package/src/runtime/run-tracker.ts +38 -10
- package/src/runtime/sandbox.ts +42 -21
- package/src/runtime/scheduler.ts +25 -2
- package/src/runtime/semaphore.ts +2 -1
- package/src/runtime/settings-store.ts +14 -2
- package/src/runtime/skill-effectiveness.ts +109 -64
- package/src/runtime/skill-instructions.ts +114 -33
- package/src/runtime/stale-reconciler.ts +310 -69
- package/src/runtime/subagent-manager.ts +265 -53
- package/src/runtime/subprocess-tool-registry.ts +2 -2
- package/src/runtime/task-health.ts +76 -0
- package/src/runtime/task-id.ts +20 -0
- package/src/runtime/task-packet.ts +13 -1
- package/src/runtime/task-runner/live-executor.ts +1 -1
- package/src/runtime/task-runner/progress.ts +1 -1
- package/src/runtime/task-runner/state-helpers.ts +110 -6
- package/src/runtime/task-runner.ts +98 -67
- package/src/runtime/team-runner.ts +186 -20
- package/src/runtime/usage-tracker.ts +4 -2
- package/src/runtime/verification-gates.ts +36 -9
- package/src/schema/team-tool-schema.ts +27 -9
- package/src/skills/discover-skills.ts +9 -3
- package/src/state/active-run-registry.ts +170 -38
- package/src/state/artifact-store.ts +25 -13
- package/src/state/atomic-write-v2.ts +86 -0
- package/src/state/atomic-write.ts +346 -55
- package/src/state/blob-store.ts +178 -10
- package/src/state/contracts.ts +2 -1
- package/src/state/crew-init.ts +161 -28
- package/src/state/decision-ledger.ts +172 -111
- package/src/state/event-log-rotation.ts +82 -52
- package/src/state/event-log.ts +270 -75
- package/src/state/health-store.ts +71 -0
- package/src/state/hook-instinct-bridge.ts +2 -1
- package/src/state/locks.ts +109 -20
- package/src/state/mailbox.ts +45 -7
- package/src/state/observation-store.ts +4 -1
- package/src/state/run-graph.ts +141 -130
- package/src/state/run-metrics.ts +24 -8
- package/src/state/state-store.ts +333 -44
- package/src/state/task-claims.ts +9 -2
- package/src/tools/safe-bash.ts +69 -20
- package/src/types/new-api-types.ts +10 -5
- package/src/ui/keybinding-map.ts +2 -1
- package/src/ui/live-run-sidebar.ts +1 -1
- package/src/ui/loaders.ts +4 -0
- package/src/ui/overlays/agent-picker-overlay.ts +1 -1
- package/src/ui/overlays/mailbox-detail-overlay.ts +1 -1
- package/src/ui/run-action-dispatcher.ts +4 -3
- package/src/ui/run-snapshot-cache.ts +1 -1
- package/src/ui/status-colors.ts +2 -1
- package/src/ui/syntax-highlight.ts +2 -1
- package/src/ui/tool-render.ts +13 -3
- package/src/utils/env-filter.ts +66 -0
- package/src/utils/file-coalescer.ts +9 -1
- package/src/utils/fs-watch.ts +4 -2
- package/src/utils/gh-protocol.ts +2 -1
- package/src/utils/paths.ts +80 -5
- package/src/utils/redaction.ts +6 -1
- package/src/utils/safe-paths.ts +287 -10
- package/src/worktree/cleanup.ts +117 -26
- package/src/worktree/worktree-manager.ts +128 -15
- package/test-bugs-all.mjs +10 -6
- package/test-integration-check.ts +4 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface Plugin {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
readonly enablers: readonly string[];
|
|
4
|
+
readonly entryPatterns?: readonly string[];
|
|
5
|
+
readonly configPatterns?: readonly string[];
|
|
6
|
+
readonly toolingDependencies?: readonly string[];
|
|
7
|
+
readonly pathAliases?: readonly string[][];
|
|
8
|
+
readonly virtualModulePrefixes?: readonly string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class PluginRegistry {
|
|
12
|
+
private plugins: Plugin[] = [];
|
|
13
|
+
|
|
14
|
+
register(plugin: Plugin): void {
|
|
15
|
+
this.plugins.push(plugin);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
activePlugins(allDeps: string[]): Plugin[] {
|
|
19
|
+
return this.plugins.filter((p) =>
|
|
20
|
+
p.enablers.some((enabler) => {
|
|
21
|
+
if (enabler.endsWith("/")) {
|
|
22
|
+
return allDeps.some((d) => d.startsWith(enabler));
|
|
23
|
+
}
|
|
24
|
+
return allDeps.includes(enabler);
|
|
25
|
+
}),
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
allPlugins(): Plugin[] {
|
|
30
|
+
return [...this.plugins];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { definePlugin } from "../plugin-define.ts";
|
|
2
|
+
|
|
3
|
+
export const NextJsPlugin = definePlugin({
|
|
4
|
+
name: "nextjs",
|
|
5
|
+
enablers: ["next"],
|
|
6
|
+
entryPatterns: [
|
|
7
|
+
"src/app/**/*.{ts,tsx}",
|
|
8
|
+
"src/pages/**/*.{ts,tsx}",
|
|
9
|
+
"src/app/**/page.{ts,tsx}",
|
|
10
|
+
"src/app/**/layout.{ts,tsx}",
|
|
11
|
+
"src/app/**/route.{ts,tsx}",
|
|
12
|
+
"middleware.{ts,js}",
|
|
13
|
+
"next.config.{ts,js,mjs}",
|
|
14
|
+
],
|
|
15
|
+
configPatterns: ["next.config.{ts,js,mjs}"],
|
|
16
|
+
toolingDependencies: ["next", "@next/font", "@next/mdx"],
|
|
17
|
+
pathAliases: [["~", "src"]],
|
|
18
|
+
virtualModulePrefixes: ["next:"],
|
|
19
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { definePlugin } from "../plugin-define.ts";
|
|
2
|
+
|
|
3
|
+
export const VitePlugin = definePlugin({
|
|
4
|
+
name: "vite",
|
|
5
|
+
enablers: ["vite", "rolldown-vite"],
|
|
6
|
+
entryPatterns: [
|
|
7
|
+
"src/main.{ts,tsx,js,jsx}",
|
|
8
|
+
"src/index.{ts,tsx,js,jsx}",
|
|
9
|
+
"index.html",
|
|
10
|
+
],
|
|
11
|
+
configPatterns: ["vite.config.{ts,js,mts,mjs}"],
|
|
12
|
+
toolingDependencies: ["vite"],
|
|
13
|
+
virtualModulePrefixes: ["virtual:"],
|
|
14
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { definePlugin } from "../plugin-define.ts";
|
|
2
|
+
|
|
3
|
+
export const VitestPlugin = definePlugin({
|
|
4
|
+
name: "vitest",
|
|
5
|
+
enablers: ["vitest"],
|
|
6
|
+
entryPatterns: [
|
|
7
|
+
"**/*.test.{ts,tsx}",
|
|
8
|
+
"**/*.spec.{ts,tsx}",
|
|
9
|
+
"src/**/*.test.{ts,tsx}",
|
|
10
|
+
"src/**/*.spec.{ts,tsx}",
|
|
11
|
+
],
|
|
12
|
+
configPatterns: ["vitest.config.{ts,js,mjs}", "vite.config.ts"],
|
|
13
|
+
toolingDependencies: ["vitest"],
|
|
14
|
+
});
|
|
@@ -22,6 +22,7 @@ import type { TeamConfig } from "../teams/team-config.ts";
|
|
|
22
22
|
import type { WorkflowConfig, WorkflowStep } from "../workflows/workflow-config.ts";
|
|
23
23
|
import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
|
|
24
24
|
import { refreshTaskGraphQueues } from "./task-graph-scheduler.ts";
|
|
25
|
+
import { getPlanTemplate, renderPlanTemplate, listPlanTemplates } from "./plan-templates.ts";
|
|
25
26
|
|
|
26
27
|
export interface AdaptivePlanTask {
|
|
27
28
|
role: string;
|
|
@@ -70,6 +71,29 @@ export function extractAdaptivePlanJson(text: string): string | undefined {
|
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
export function parseAdaptivePlan(text: string, allowedRoles: string[]): AdaptivePlan | undefined {
|
|
74
|
+
// Check if the text is a plan template reference: "template:<name>" with optional JSON variables
|
|
75
|
+
const templateRefMatch = text.match(/^template:([a-zA-Z0-9_-]+)/);
|
|
76
|
+
if (templateRefMatch?.[1]) {
|
|
77
|
+
const template = getPlanTemplate(templateRefMatch[1]);
|
|
78
|
+
if (template) {
|
|
79
|
+
// Try to extract variables from the remaining text
|
|
80
|
+
let variables: Record<string, string> = {};
|
|
81
|
+
try {
|
|
82
|
+
const varsJson = text.slice(templateRefMatch[0].length).trim();
|
|
83
|
+
if (varsJson) variables = JSON.parse(varsJson);
|
|
84
|
+
} catch { /* use empty variables */ }
|
|
85
|
+
const rendered = renderPlanTemplate(templateRefMatch[1], variables);
|
|
86
|
+
if (rendered) {
|
|
87
|
+
// Convert RenderedPlan → AdaptivePlan
|
|
88
|
+
const phases: AdaptivePlanPhase[] = rendered.phases.map(phase => ({
|
|
89
|
+
name: phase.name,
|
|
90
|
+
tasks: [{ role: phase.role, task: phase.task }],
|
|
91
|
+
}));
|
|
92
|
+
return phases.length ? { phases } : undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
73
97
|
const raw = extractAdaptivePlanJson(text);
|
|
74
98
|
if (!raw) return undefined;
|
|
75
99
|
let parsed: unknown;
|
|
@@ -69,7 +69,8 @@ export function applyAttentionState(manifest: TeamRunManifest, agent: CrewAgentR
|
|
|
69
69
|
return updated;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
/** @internal */
|
|
73
|
+
function applyLongRunningCheck(
|
|
73
74
|
manifest: TeamRunManifest,
|
|
74
75
|
agent: CrewAgentRecord,
|
|
75
76
|
config: CrewControlConfig,
|
|
@@ -105,7 +106,8 @@ export function applyLongRunningCheck(
|
|
|
105
106
|
return updated;
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
|
|
109
|
+
/** @internal */
|
|
110
|
+
function trackConsecutiveToolFailure(
|
|
109
111
|
manifest: TeamRunManifest,
|
|
110
112
|
agent: CrewAgentRecord,
|
|
111
113
|
toolName: string,
|
|
@@ -140,7 +142,8 @@ export function trackConsecutiveToolFailure(
|
|
|
140
142
|
return updated;
|
|
141
143
|
}
|
|
142
144
|
|
|
143
|
-
|
|
145
|
+
/** @internal */
|
|
146
|
+
function resetConsecutiveToolFailures(
|
|
144
147
|
manifest: TeamRunManifest,
|
|
145
148
|
agent: CrewAgentRecord,
|
|
146
149
|
): void {
|
|
@@ -5,6 +5,11 @@ import * as path from "node:path";
|
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
6
|
import { logInternalError } from "../utils/internal-error.ts";
|
|
7
7
|
import { appendEvent } from "../state/event-log.ts";
|
|
8
|
+
import { sanitizeEnvSecrets } from "../utils/env-filter.ts";
|
|
9
|
+
import {
|
|
10
|
+
registerWorker,
|
|
11
|
+
unregisterWorker,
|
|
12
|
+
} from "./orphan-worker-registry.ts";
|
|
8
13
|
import type { TeamRunManifest } from "../state/types.ts";
|
|
9
14
|
|
|
10
15
|
|
|
@@ -131,8 +136,71 @@ export async function spawnBackgroundTeamRun(manifest: TeamRunManifest): Promise
|
|
|
131
136
|
const logPath = path.join(manifest.stateRoot, "background.log");
|
|
132
137
|
fs.mkdirSync(manifest.stateRoot, { recursive: true });
|
|
133
138
|
|
|
134
|
-
//
|
|
135
|
-
|
|
139
|
+
// SECURITY FIX: Use sanitizeEnvSecrets with same allow-list as child-pi.ts
|
|
140
|
+
// to prevent leaking all env vars (including secrets) to detached background runner.
|
|
141
|
+
// Previously, destructuring only removed PI_CREW_PARENT_PID but kept everything else.
|
|
142
|
+
const filteredEnv = sanitizeEnvSecrets(process.env, {
|
|
143
|
+
allowList: [
|
|
144
|
+
// Model provider API keys (same as child-pi.ts)
|
|
145
|
+
"MINIMAX_API_KEY",
|
|
146
|
+
"MINIMAX_GROUP_ID",
|
|
147
|
+
"OPENAI_API_KEY",
|
|
148
|
+
"OPENAI_ORG_ID",
|
|
149
|
+
"ANTHROPIC_API_KEY",
|
|
150
|
+
"GOOGLE_API_KEY",
|
|
151
|
+
"GOOGLE_GENERATIVE_LANGUAGE_API_KEY",
|
|
152
|
+
"AZURE_OPENAI_API_KEY",
|
|
153
|
+
"AZURE_OPENAI_ENDPOINT",
|
|
154
|
+
"AWS_ACCESS_KEY_ID",
|
|
155
|
+
"AWS_SECRET_ACCESS_KEY",
|
|
156
|
+
"AWS_REGION",
|
|
157
|
+
"ZEU_API_KEY",
|
|
158
|
+
"ZERODEV_API_KEY",
|
|
159
|
+
// Essential non-secret vars
|
|
160
|
+
"PATH",
|
|
161
|
+
"HOME",
|
|
162
|
+
"USER",
|
|
163
|
+
"SHELL",
|
|
164
|
+
"TERM",
|
|
165
|
+
"LANG",
|
|
166
|
+
"LC_ALL",
|
|
167
|
+
"LC_COLLATE",
|
|
168
|
+
"LC_CTYPE",
|
|
169
|
+
"LC_MESSAGES",
|
|
170
|
+
"LC_MONETARY",
|
|
171
|
+
"LC_NUMERIC",
|
|
172
|
+
"LC_TIME",
|
|
173
|
+
"XDG_CONFIG_HOME",
|
|
174
|
+
"XDG_DATA_HOME",
|
|
175
|
+
"XDG_CACHE_HOME",
|
|
176
|
+
"XDG_RUNTIME_DIR",
|
|
177
|
+
"NVM_BIN",
|
|
178
|
+
"NVM_DIR",
|
|
179
|
+
"NVM_INC",
|
|
180
|
+
"NODE_PATH",
|
|
181
|
+
"NODE_DISABLE_COLORS",
|
|
182
|
+
"NODE_EXTRA_CA_CERTS",
|
|
183
|
+
"NPM_CONFIG_REGISTRY",
|
|
184
|
+
"NPM_CONFIG_USERCONFIG",
|
|
185
|
+
"NPM_CONFIG_GLOBALCONFIG",
|
|
186
|
+
// FIX: explicit list matches child-pi.ts to prevent regression.
|
|
187
|
+
// PI_CREW_PARENT_PID is needed for parent-guard (liveness check).
|
|
188
|
+
"PI_CREW_DEPTH",
|
|
189
|
+
"PI_CREW_MAX_DEPTH",
|
|
190
|
+
"PI_CREW_INHERIT_PROJECT_CONTEXT",
|
|
191
|
+
"PI_CREW_INHERIT_SKILLS",
|
|
192
|
+
"PI_CREW_PARENT_PID",
|
|
193
|
+
"PI_TEAMS_DEPTH",
|
|
194
|
+
"PI_TEAMS_MAX_DEPTH",
|
|
195
|
+
"PI_TEAMS_INHERIT_PROJECT_CONTEXT",
|
|
196
|
+
"PI_TEAMS_INHERIT_SKILLS",
|
|
197
|
+
"PI_TEAMS_PI_BIN",
|
|
198
|
+
"PI_TEAMS_MOCK_CHILD_PI",
|
|
199
|
+
"PI_CREW_ALLOW_MOCK",
|
|
200
|
+
],
|
|
201
|
+
});
|
|
202
|
+
// FIX: removed delete workarounds — with explicit allowlist, these vars
|
|
203
|
+
// are no longer auto-leaked. Matches child-pi.ts.
|
|
136
204
|
|
|
137
205
|
const loader = resolveTypeScriptLoader();
|
|
138
206
|
if (!loader) {
|
|
@@ -159,7 +227,7 @@ export async function spawnBackgroundTeamRun(manifest: TeamRunManifest): Promise
|
|
|
159
227
|
detached: true,
|
|
160
228
|
setsid: true,
|
|
161
229
|
stdio: ["ignore", "pipe", "pipe"],
|
|
162
|
-
env:
|
|
230
|
+
env: filteredEnv,
|
|
163
231
|
windowsHide: true,
|
|
164
232
|
} as unknown as Parameters<typeof spawn>[2];
|
|
165
233
|
const child = spawn(process.execPath, command.args, spawnOpts);
|
|
@@ -168,6 +236,21 @@ export async function spawnBackgroundTeamRun(manifest: TeamRunManifest): Promise
|
|
|
168
236
|
});
|
|
169
237
|
child.unref();
|
|
170
238
|
|
|
239
|
+
// Track this worker in the orphan registry so it can be killed on
|
|
240
|
+
// session_start of a future session if the parent pi process is killed.
|
|
241
|
+
if (child.pid) {
|
|
242
|
+
registerWorker(
|
|
243
|
+
child.pid,
|
|
244
|
+
manifest.ownerSessionId ?? "unknown",
|
|
245
|
+
manifest.runId,
|
|
246
|
+
process.pid, // parentPid — used by cleanup to verify session is dead
|
|
247
|
+
);
|
|
248
|
+
// Best-effort: unregister when child exits. Background-runner writes
|
|
249
|
+
// the marker file before it dies, so we unregister on the next
|
|
250
|
+
// cleanup tick. But the child "exit" event won't fire because we
|
|
251
|
+
// unref'd and the stdio is piped + ignored.
|
|
252
|
+
}
|
|
253
|
+
|
|
171
254
|
return { pid: child.pid, logPath };
|
|
172
255
|
}
|
|
173
256
|
|