pi-crew 0.5.14 → 0.5.17

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 (90) hide show
  1. package/CHANGELOG.md +171 -0
  2. package/README.md +1 -1
  3. package/docs/pi-crew-v0.5.16-audit-fix-plan.md +35 -0
  4. package/docs/pi-crew-v0.5.17-audit-fix-plan.md +80 -0
  5. package/docs/skills/REFERENCE.md +11 -0
  6. package/package.json +1 -1
  7. package/skills/artifact-analysis-loop/SKILL.md +1 -0
  8. package/skills/async-worker-recovery/SKILL.md +1 -0
  9. package/skills/child-pi-spawning/SKILL.md +1 -0
  10. package/skills/context-artifact-hygiene/SKILL.md +1 -0
  11. package/skills/delegation-patterns/SKILL.md +1 -0
  12. package/skills/detection-pipeline-design/SKILL.md +2 -1
  13. package/skills/event-log-tracing/SKILL.md +1 -0
  14. package/skills/git-master/SKILL.md +1 -0
  15. package/skills/hunting-investigation-loop/SKILL.md +1 -0
  16. package/skills/incident-playbook-construction/SKILL.md +1 -0
  17. package/skills/iterative-audit/SKILL.md +331 -0
  18. package/skills/live-agent-lifecycle/SKILL.md +1 -0
  19. package/skills/mailbox-interactive/SKILL.md +1 -0
  20. package/skills/model-routing-context/SKILL.md +2 -1
  21. package/skills/multi-perspective-review/SKILL.md +1 -0
  22. package/skills/observability-reliability/SKILL.md +1 -0
  23. package/skills/orchestration/SKILL.md +2 -1
  24. package/skills/ownership-session-security/SKILL.md +1 -0
  25. package/skills/pi-extension-lifecycle/SKILL.md +3 -2
  26. package/skills/post-mortem/SKILL.md +1 -0
  27. package/skills/read-only-explorer/SKILL.md +1 -0
  28. package/skills/requirements-to-task-packet/SKILL.md +1 -0
  29. package/skills/resource-discovery-config/SKILL.md +2 -1
  30. package/skills/runtime-state-reader/SKILL.md +1 -0
  31. package/skills/safe-bash/SKILL.md +1 -0
  32. package/skills/scrutinize/SKILL.md +1 -0
  33. package/skills/secure-agent-orchestration-review/SKILL.md +1 -0
  34. package/skills/security-review/SKILL.md +1 -0
  35. package/skills/state-mutation-locking/SKILL.md +1 -0
  36. package/skills/systematic-debugging/SKILL.md +1 -0
  37. package/skills/threat-hypothesis-framework/SKILL.md +1 -0
  38. package/skills/ui-render-performance/SKILL.md +2 -1
  39. package/skills/verification-before-done/SKILL.md +1 -0
  40. package/skills/widget-rendering/SKILL.md +2 -1
  41. package/skills/workspace-isolation/SKILL.md +1 -0
  42. package/skills/worktree-isolation/SKILL.md +1 -0
  43. package/src/config/types.ts +1 -0
  44. package/src/extension/management.ts +1 -1
  45. package/src/extension/plan-orchestrate.ts +0 -1
  46. package/src/extension/register.ts +16 -7
  47. package/src/extension/registration/viewers.ts +1 -1
  48. package/src/extension/run-index.ts +1 -1
  49. package/src/extension/team-tool/explain.ts +0 -1
  50. package/src/extension/team-tool/handle-schedule.ts +0 -1
  51. package/src/extension/team-tool/health-monitor.ts +0 -1
  52. package/src/extension/team-tool/orchestrate.ts +12 -4
  53. package/src/extension/team-tool/run.ts +2 -2
  54. package/src/extension/team-tool/status.ts +1 -1
  55. package/src/extension/team-tool.ts +2 -30
  56. package/src/observability/exporters/otlp-exporter.ts +11 -1
  57. package/src/runtime/adaptive-plan.ts +18 -2
  58. package/src/runtime/child-pi.ts +18 -6
  59. package/src/runtime/crash-recovery.ts +1 -1
  60. package/src/runtime/crew-agent-records.ts +23 -3
  61. package/src/runtime/crew-hooks.ts +1 -1
  62. package/src/runtime/dynamic-script-runner.ts +14 -1
  63. package/src/runtime/handoff-manager.ts +0 -1
  64. package/src/runtime/heartbeat-watcher.ts +1 -1
  65. package/src/runtime/live-session-runtime.ts +0 -1
  66. package/src/runtime/loop-gates.ts +0 -1
  67. package/src/runtime/mcp-proxy.ts +2 -2
  68. package/src/runtime/pipeline-runner.ts +1 -2
  69. package/src/runtime/sandbox.ts +8 -0
  70. package/src/runtime/task-packet.ts +124 -0
  71. package/src/runtime/task-runner/live-executor.ts +1 -2
  72. package/src/runtime/task-runner/prompt-builder.ts +4 -1
  73. package/src/runtime/task-runner.ts +2 -2
  74. package/src/schema/config-schema.ts +1 -0
  75. package/src/state/event-log.ts +7 -0
  76. package/src/state/jsonl-writer.ts +24 -0
  77. package/src/state/locks.ts +66 -35
  78. package/src/state/run-metrics.ts +1 -2
  79. package/src/state/schedule.ts +13 -5
  80. package/src/state/state-store.ts +1 -1
  81. package/src/tools/safe-bash-extension.ts +1 -1
  82. package/src/tools/safe-bash.ts +10 -1
  83. package/src/ui/crew-widget.ts +2 -2
  84. package/src/ui/render-diff.ts +1 -1
  85. package/src/ui/run-dashboard.ts +1 -2
  86. package/src/ui/tool-render.ts +20 -3
  87. package/src/utils/conflict-detect.ts +0 -1
  88. package/src/utils/gh-protocol.ts +0 -2
  89. package/src/workflows/workflow-config.ts +3 -0
  90. package/src/worktree/worktree-manager.ts +75 -1
@@ -116,6 +116,11 @@ function runSetupHook(manifest: TeamRunManifest, task: TeamTaskState, repoRoot:
116
116
  logInternalError("worktree.setupHook.rejected", new Error("hook path not allowed: " + rawHookPath), `cwd=${manifest.cwd}`);
117
117
  return [];
118
118
  }
119
+ // SECURITY WARNING: Home directory hooks (~/.pi/hooks/) are user-writable and not project-scoped.
120
+ // A rogue npm postinstall script could place malicious hooks there. Log for visibility.
121
+ if (path.isAbsolute(rawHookPath)) {
122
+ logInternalError("worktree.setupHook.homeHook", new Error("Home directory hook used — ensure ~/.pi/hooks/ is trusted"), `hookPath=${rawHookPath}`);
123
+ }
119
124
  const hookPath = path.isAbsolute(rawHookPath) ? rawHookPath : path.resolve(repoRoot, rawHookPath);
120
125
  // SECURITY: Verify the resolved hook path is contained within the real repoRoot.
121
126
  // This prevents symlink-based escape where repoRoot is a symlink.
@@ -201,7 +206,64 @@ function pruneStaleWorktrees(repoRoot: string): void {
201
206
  catch { /* best-effort */ }
202
207
  }
203
208
 
204
- export function prepareTaskWorkspace(manifest: TeamRunManifest, task: TeamTaskState): PreparedTaskWorkspace {
209
+ /**
210
+ * Normalize and validate seed paths — ensure all paths stay within repoRoot.
211
+ * Rejects path traversal (../) and absolute paths.
212
+ */
213
+ export function normalizeSeedPaths(seedPaths: string[], repoRoot: string): string[] {
214
+ const resolvedRepoRoot = path.resolve(repoRoot);
215
+ const entries = Array.isArray(seedPaths) ? seedPaths : [];
216
+ const seen = new Set<string>();
217
+ const normalized: string[] = [];
218
+
219
+ for (const entry of entries) {
220
+ if (typeof entry !== "string" || entry.trim().length === 0) continue;
221
+
222
+ const absolutePath = path.resolve(resolvedRepoRoot, entry);
223
+ const relativePath = path.relative(resolvedRepoRoot, absolutePath);
224
+
225
+ if (relativePath.startsWith("..") || path.isAbsolute(relativePath)) {
226
+ throw new Error(`seedPaths entries must stay inside repoRoot: ${entry}`);
227
+ }
228
+
229
+ const normalizedPath = relativePath.split(path.sep).join("/");
230
+ if (seen.has(normalizedPath)) continue;
231
+ seen.add(normalizedPath);
232
+ normalized.push(normalizedPath);
233
+ }
234
+
235
+ return normalized;
236
+ }
237
+
238
+ /**
239
+ * Overlay seed paths from repoRoot into worktreePath.
240
+ * Copies files and directories, creating parent dirs as needed.
241
+ * Skips non-existent sources with logInternalError (non-fatal).
242
+ */
243
+ export function overlaySeedPaths(repoRoot: string, worktreePath: string, seedPaths: string[]): void {
244
+ const normalized = normalizeSeedPaths(seedPaths, repoRoot);
245
+
246
+ for (const seedPath of normalized) {
247
+ const sourcePath = path.join(repoRoot, seedPath);
248
+ const destinationPath = path.join(worktreePath, seedPath);
249
+
250
+ if (!fs.existsSync(sourcePath)) {
251
+ logInternalError("worktree.seedPaths.missing", new Error(`Seed path does not exist: ${seedPath}`));
252
+ continue;
253
+ }
254
+
255
+ fs.mkdirSync(path.dirname(destinationPath), { recursive: true });
256
+ fs.rmSync(destinationPath, { force: true, recursive: true });
257
+ fs.cpSync(sourcePath, destinationPath, {
258
+ dereference: false,
259
+ force: true,
260
+ preserveTimestamps: true,
261
+ recursive: true,
262
+ });
263
+ }
264
+ }
265
+
266
+ export function prepareTaskWorkspace(manifest: TeamRunManifest, task: TeamTaskState, stepSeedPaths?: string[]): PreparedTaskWorkspace {
205
267
  if (manifest.workspaceMode !== "worktree") return { cwd: task.cwd };
206
268
  const repoRoot = findGitRoot(manifest.cwd);
207
269
  const loadedConfig = loadConfig(manifest.cwd);
@@ -220,6 +282,12 @@ export function prepareTaskWorkspace(manifest: TeamRunManifest, task: TeamTaskSt
220
282
  if (currentBranch !== branch) {
221
283
  throw new Error(`Existing worktree branch mismatch at ${worktreePath}: expected '${branch}', got '${currentBranch}'.`);
222
284
  }
285
+ // Overlay seed paths from config + step-level seedPaths (reused worktree)
286
+ const globalSeedPaths = loadedConfig.config.worktree?.seedPaths ?? [];
287
+ const mergedReused = normalizeSeedPaths([...globalSeedPaths, ...(stepSeedPaths ?? [])], repoRoot);
288
+ if (mergedReused.length > 0) {
289
+ overlaySeedPaths(repoRoot, worktreePath, mergedReused);
290
+ }
223
291
  return { cwd: worktreePath, worktreePath, branch, reused: true };
224
292
  }
225
293
  pruneStaleWorktrees(repoRoot);
@@ -242,6 +310,12 @@ export function prepareTaskWorkspace(manifest: TeamRunManifest, task: TeamTaskSt
242
310
  }
243
311
  const syntheticPaths = runSetupHook(manifest, task, repoRoot, worktreePath, branch);
244
312
  const nodeModulesLinked = loadedConfig.config.worktree?.linkNodeModules === true ? linkNodeModulesIfPresent(repoRoot, worktreePath) : false;
313
+ // Overlay seed paths from config + step-level seedPaths
314
+ const globalSeedPaths = loadedConfig.config.worktree?.seedPaths ?? [];
315
+ const merged = normalizeSeedPaths([...globalSeedPaths, ...(stepSeedPaths ?? [])], repoRoot);
316
+ if (merged.length > 0) {
317
+ overlaySeedPaths(repoRoot, worktreePath, merged);
318
+ }
245
319
  return { cwd: worktreePath, worktreePath, branch, reused: false, nodeModulesLinked, syntheticPaths };
246
320
  }
247
321