pi-crew 0.2.3 → 0.2.4

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 (348) hide show
  1. package/AGENTS.md +57 -32
  2. package/CHANGELOG.md +466 -448
  3. package/LICENSE +21 -21
  4. package/NOTICE.md +16 -16
  5. package/README.md +323 -323
  6. package/docs/FEATURE_INTAKE.md +126 -0
  7. package/docs/HARNESS.md +86 -0
  8. package/docs/HARNESS_BACKLOG.md +41 -0
  9. package/docs/TEST_MATRIX.md +49 -0
  10. package/docs/actions-reference.md +595 -595
  11. package/docs/architecture.md +180 -180
  12. package/docs/code-review-2026-05-11.md +592 -592
  13. package/docs/commands-reference.md +347 -347
  14. package/docs/comparison-pi-subagents-vs-pi-crew.md +303 -0
  15. package/docs/decisions/0001-durable-state.md +41 -0
  16. package/docs/decisions/0002-child-process-for-async.md +42 -0
  17. package/docs/decisions/0003-depth-guard.md +36 -0
  18. package/docs/decisions/0004-execfile-over-exec.md +34 -0
  19. package/docs/decisions/0005-no-parameter-properties.md +49 -0
  20. package/docs/decisions/0006-publish-bundled-esm.md +63 -0
  21. package/docs/decisions/0007-active-run-binary-index.md +54 -0
  22. package/docs/decisions/0008-child-pi-warm-pool.md +61 -0
  23. package/docs/decisions/README.md +23 -0
  24. package/docs/followup-review-round4-2026-05-13.md +107 -0
  25. package/docs/implementation-plan-top3.md +333 -0
  26. package/docs/live-mailbox-runtime.md +36 -36
  27. package/docs/next-upgrade-roadmap.md +808 -808
  28. package/docs/oh-my-pi-research.md +509 -0
  29. package/docs/perf/baseline-2026-05.md +113 -0
  30. package/docs/perf/final-report-2026-05.md +206 -0
  31. package/docs/perf/sprint-1-report.md +71 -0
  32. package/docs/perf/sprint-2-report.md +81 -0
  33. package/docs/perf/sprint-2.5-report.md +53 -0
  34. package/docs/perf/sprint-3-report.md +36 -0
  35. package/docs/perf/sprint-4-report.md +47 -0
  36. package/docs/perf/sprint-5-report.md +51 -0
  37. package/docs/perf/sprint-6-report.md +94 -0
  38. package/docs/perf/sprint-7-report.md +74 -0
  39. package/docs/perf/upgrade-plan-2026-05.md +147 -0
  40. package/docs/pi-subagents3-deep-analysis.md +508 -0
  41. package/docs/product/README.md +31 -0
  42. package/docs/product/platform.md +27 -0
  43. package/docs/product/runtime-safety.md +37 -0
  44. package/docs/product/team-run.md +39 -0
  45. package/docs/product/team-tool.md +37 -0
  46. package/docs/publishing.md +65 -65
  47. package/docs/resource-formats.md +134 -134
  48. package/docs/runtime-analysis-child-vs-live.md +171 -0
  49. package/docs/runtime-flow.md +148 -148
  50. package/docs/runtime-migration-in-process-analysis.md +250 -0
  51. package/docs/stories/README.md +30 -0
  52. package/docs/stories/backlog.md +36 -0
  53. package/docs/templates/decision.md +27 -0
  54. package/docs/templates/story.md +44 -0
  55. package/docs/templates/validation-report.md +32 -0
  56. package/docs/usage.md +238 -238
  57. package/index.ts +7 -6
  58. package/install.mjs +65 -65
  59. package/package.json +107 -100
  60. package/schema.json +222 -222
  61. package/skills/child-pi-spawning/SKILL.md +213 -0
  62. package/skills/context-artifact-hygiene/SKILL.md +32 -0
  63. package/skills/event-log-tracing/SKILL.md +299 -0
  64. package/skills/git-master/SKILL.md +225 -24
  65. package/skills/live-agent-lifecycle/SKILL.md +192 -0
  66. package/skills/mailbox-interactive/SKILL.md +300 -19
  67. package/skills/model-routing-context/SKILL.md +94 -0
  68. package/skills/multi-perspective-review/SKILL.md +88 -0
  69. package/skills/read-only-explorer/SKILL.md +250 -26
  70. package/skills/safe-bash/SKILL.md +307 -21
  71. package/skills/verification-before-done/SKILL.md +11 -2
  72. package/skills/widget-rendering/SKILL.md +258 -0
  73. package/skills/workspace-isolation/SKILL.md +202 -0
  74. package/skills/worktree-isolation/SKILL.md +202 -18
  75. package/src/adapters/claude-adapter.ts +25 -25
  76. package/src/adapters/codex-adapter.ts +21 -21
  77. package/src/adapters/cursor-adapter.ts +17 -17
  78. package/src/adapters/export-util.ts +137 -137
  79. package/src/adapters/index.ts +15 -15
  80. package/src/adapters/registry.ts +18 -18
  81. package/src/adapters/types.ts +23 -23
  82. package/src/agents/agent-config.ts +38 -38
  83. package/src/agents/agent-serializer.ts +38 -38
  84. package/src/agents/discover-agents.ts +121 -118
  85. package/src/config/config.ts +740 -858
  86. package/src/config/defaults.ts +96 -96
  87. package/src/config/drift-detector.ts +211 -211
  88. package/src/config/markers.ts +327 -327
  89. package/src/config/resilient-parser.ts +109 -108
  90. package/src/config/suggestions.ts +74 -74
  91. package/src/config/types.ts +199 -0
  92. package/src/extension/async-notifier.ts +123 -89
  93. package/src/extension/autonomous-policy.ts +169 -169
  94. package/src/extension/cross-extension-rpc.ts +104 -104
  95. package/src/extension/help.ts +47 -47
  96. package/src/extension/import-index.ts +69 -69
  97. package/src/extension/management.ts +395 -382
  98. package/src/extension/notification-router.ts +116 -116
  99. package/src/extension/notification-sink.ts +51 -51
  100. package/src/extension/project-init.ts +168 -168
  101. package/src/extension/register.ts +859 -668
  102. package/src/extension/registration/artifact-cleanup.ts +15 -15
  103. package/src/extension/registration/command-utils.ts +54 -54
  104. package/src/extension/registration/commands.ts +559 -452
  105. package/src/extension/registration/compaction-guard.ts +125 -125
  106. package/src/extension/registration/subagent-helpers.ts +102 -102
  107. package/src/extension/registration/subagent-tools.ts +220 -159
  108. package/src/extension/registration/team-tool.ts +159 -99
  109. package/src/extension/registration/viewers.ts +29 -0
  110. package/src/extension/result-watcher.ts +128 -128
  111. package/src/extension/run-bundle-schema.ts +89 -89
  112. package/src/extension/run-export.ts +73 -73
  113. package/src/extension/run-import.ts +84 -84
  114. package/src/extension/run-index.ts +94 -94
  115. package/src/extension/run-maintenance.ts +142 -142
  116. package/src/extension/session-summary.ts +8 -8
  117. package/src/extension/team-manager-command.ts +96 -96
  118. package/src/extension/team-recommendation.ts +188 -188
  119. package/src/extension/team-tool/api.ts +5 -2
  120. package/src/extension/team-tool/cancel.ts +224 -209
  121. package/src/extension/team-tool/config-patch.ts +36 -36
  122. package/src/extension/team-tool/context.ts +60 -60
  123. package/src/extension/team-tool/doctor.ts +242 -242
  124. package/src/extension/team-tool/handle-settings.ts +421 -195
  125. package/src/extension/team-tool/inspect.ts +41 -41
  126. package/src/extension/team-tool/lifecycle-actions.ts +139 -139
  127. package/src/extension/team-tool/parallel-dispatch.ts +156 -156
  128. package/src/extension/team-tool/plan.ts +19 -19
  129. package/src/extension/team-tool/respond.ts +112 -111
  130. package/src/extension/team-tool/run.ts +246 -229
  131. package/src/extension/team-tool/status.ts +110 -110
  132. package/src/extension/team-tool-types.ts +13 -13
  133. package/src/extension/team-tool.ts +344 -344
  134. package/src/extension/tool-result.ts +16 -16
  135. package/src/extension/validate-resources.ts +77 -77
  136. package/src/hooks/registry.ts +61 -61
  137. package/src/hooks/types.ts +40 -40
  138. package/src/i18n.ts +184 -184
  139. package/src/observability/correlation.ts +35 -35
  140. package/src/observability/event-to-metric.ts +68 -68
  141. package/src/observability/exporters/adapter.ts +30 -30
  142. package/src/observability/exporters/otlp-exporter.ts +106 -92
  143. package/src/observability/exporters/prometheus-exporter.ts +54 -54
  144. package/src/observability/metric-registry.ts +87 -87
  145. package/src/observability/metric-retention.ts +54 -54
  146. package/src/observability/metric-sink.ts +81 -56
  147. package/src/observability/metrics-primitives.ts +167 -167
  148. package/src/prompt/prompt-runtime.ts +72 -72
  149. package/src/runtime/adaptive-plan.ts +338 -0
  150. package/src/runtime/agent-control.ts +169 -169
  151. package/src/runtime/agent-memory.ts +72 -72
  152. package/src/runtime/agent-observability.ts +114 -114
  153. package/src/runtime/async-marker.ts +26 -26
  154. package/src/runtime/async-runner.ts +153 -153
  155. package/src/runtime/attention-events.ts +28 -28
  156. package/src/runtime/auto-resume.ts +100 -100
  157. package/src/runtime/background-runner.ts +122 -89
  158. package/src/runtime/cancellation.ts +61 -61
  159. package/src/runtime/capability-inventory.ts +116 -116
  160. package/src/runtime/child-pi-pool.ts +68 -0
  161. package/src/runtime/child-pi.ts +541 -461
  162. package/src/runtime/code-summary.ts +247 -247
  163. package/src/runtime/compaction-summary.ts +271 -271
  164. package/src/runtime/concurrency.ts +58 -58
  165. package/src/runtime/crash-recovery.ts +317 -301
  166. package/src/runtime/crew-agent-records.ts +379 -281
  167. package/src/runtime/crew-agent-runtime.ts +60 -60
  168. package/src/runtime/cross-extension-rpc.ts +72 -0
  169. package/src/runtime/custom-tools/irc-tool.ts +201 -201
  170. package/src/runtime/custom-tools/submit-result-tool.ts +90 -90
  171. package/src/runtime/deadletter.ts +47 -47
  172. package/src/runtime/delivery-coordinator.ts +176 -176
  173. package/src/runtime/delta-conflict.ts +360 -360
  174. package/src/runtime/diagnostic-export.ts +102 -102
  175. package/src/runtime/direct-run.ts +35 -35
  176. package/src/runtime/effectiveness.ts +82 -81
  177. package/src/runtime/errors/crew-errors.ts +166 -0
  178. package/src/runtime/event-stream-bridge.ts +92 -92
  179. package/src/runtime/foreground-control.ts +82 -82
  180. package/src/runtime/green-contract.ts +46 -46
  181. package/src/runtime/group-join.ts +234 -106
  182. package/src/runtime/heartbeat-watcher.ts +145 -124
  183. package/src/runtime/iteration-hooks.ts +267 -267
  184. package/src/runtime/live-agent-control.ts +88 -88
  185. package/src/runtime/live-agent-manager.ts +377 -179
  186. package/src/runtime/live-control-realtime.ts +36 -36
  187. package/src/runtime/live-session-runtime.ts +676 -600
  188. package/src/runtime/loop-gates.ts +129 -129
  189. package/src/runtime/manifest-cache.ts +263 -263
  190. package/src/runtime/mcp-proxy.ts +113 -113
  191. package/src/runtime/metric-parser.ts +40 -40
  192. package/src/runtime/model-fallback.ts +282 -274
  193. package/src/runtime/model-resolver.ts +118 -0
  194. package/src/runtime/output-validator.ts +187 -187
  195. package/src/runtime/overflow-recovery.ts +175 -175
  196. package/src/runtime/parallel-research.ts +44 -44
  197. package/src/runtime/parallel-utils.ts +156 -156
  198. package/src/runtime/parent-guard.ts +80 -80
  199. package/src/runtime/phase-progress.ts +217 -217
  200. package/src/runtime/pi-args.ts +165 -165
  201. package/src/runtime/pi-json-output.ts +111 -111
  202. package/src/runtime/pi-spawn.ts +167 -167
  203. package/src/runtime/policy-engine.ts +79 -79
  204. package/src/runtime/post-checks.ts +125 -125
  205. package/src/runtime/post-exit-stdio-guard.ts +86 -86
  206. package/src/runtime/process-status.ts +97 -73
  207. package/src/runtime/progress-event-coalescer.ts +43 -43
  208. package/src/runtime/recovery-recipes.ts +74 -74
  209. package/src/runtime/retry-executor.ts +81 -81
  210. package/src/runtime/role-permission.ts +39 -39
  211. package/src/runtime/run-tracker.ts +99 -0
  212. package/src/runtime/runtime-policy.ts +21 -0
  213. package/src/runtime/runtime-resolver.ts +94 -91
  214. package/src/runtime/scheduler.ts +294 -0
  215. package/src/runtime/semaphore.ts +131 -131
  216. package/src/runtime/sensitive-paths.ts +92 -92
  217. package/src/runtime/session-usage.ts +79 -79
  218. package/src/runtime/settings-store.ts +103 -0
  219. package/src/runtime/sidechain-output.ts +29 -29
  220. package/src/runtime/skill-instructions.ts +222 -222
  221. package/src/runtime/stale-reconciler.ts +198 -189
  222. package/src/runtime/streaming-output.ts +47 -0
  223. package/src/runtime/subagent-manager.ts +404 -400
  224. package/src/runtime/subprocess-tool-registry.ts +67 -67
  225. package/src/runtime/task-display.ts +38 -38
  226. package/src/runtime/task-graph-scheduler.ts +122 -122
  227. package/src/runtime/task-graph.ts +207 -207
  228. package/src/runtime/task-output-context.ts +177 -177
  229. package/src/runtime/task-packet.ts +93 -93
  230. package/src/runtime/task-quality.ts +207 -207
  231. package/src/runtime/task-runner/capabilities.ts +78 -78
  232. package/src/runtime/task-runner/live-executor.ts +131 -113
  233. package/src/runtime/task-runner/progress.ts +119 -119
  234. package/src/runtime/task-runner/prompt-builder.ts +139 -139
  235. package/src/runtime/task-runner/prompt-pipeline.ts +64 -64
  236. package/src/runtime/task-runner/result-utils.ts +14 -14
  237. package/src/runtime/task-runner/run-projection.ts +103 -103
  238. package/src/runtime/task-runner/state-helpers.ts +22 -22
  239. package/src/runtime/task-runner.ts +469 -459
  240. package/src/runtime/team-runner.ts +693 -945
  241. package/src/runtime/usage-tracker.ts +71 -0
  242. package/src/runtime/worker-heartbeat.ts +21 -21
  243. package/src/runtime/worker-startup.ts +57 -57
  244. package/src/runtime/workflow-state.ts +187 -187
  245. package/src/runtime/yield-handler.ts +190 -190
  246. package/src/schema/config-schema.ts +172 -168
  247. package/src/schema/team-tool-schema.ts +126 -126
  248. package/src/schema/validation-types.ts +151 -148
  249. package/src/skills/discover-skills.ts +67 -67
  250. package/src/skills/skill-templates.ts +374 -374
  251. package/src/state/active-run-registry.ts +227 -191
  252. package/src/state/artifact-store.ts +130 -129
  253. package/src/state/atomic-write.ts +262 -195
  254. package/src/state/blob-store.ts +116 -116
  255. package/src/state/contracts.ts +111 -111
  256. package/src/state/event-log-rotation.ts +161 -158
  257. package/src/state/event-log.ts +383 -303
  258. package/src/state/event-reconstructor.ts +217 -217
  259. package/src/state/jsonl-writer.ts +82 -82
  260. package/src/state/locks.ts +146 -146
  261. package/src/state/mailbox.ts +446 -405
  262. package/src/state/state-store.ts +364 -351
  263. package/src/state/task-claims.ts +44 -44
  264. package/src/state/types.ts +285 -285
  265. package/src/state/usage.ts +29 -29
  266. package/src/subagents/async-entry.ts +1 -1
  267. package/src/subagents/index.ts +3 -3
  268. package/src/subagents/live/control.ts +1 -1
  269. package/src/subagents/live/manager.ts +1 -1
  270. package/src/subagents/live/realtime.ts +1 -1
  271. package/src/subagents/live/session-runtime.ts +1 -1
  272. package/src/subagents/manager.ts +1 -1
  273. package/src/subagents/spawn.ts +1 -1
  274. package/src/teams/discover-teams.ts +116 -116
  275. package/src/teams/team-config.ts +27 -27
  276. package/src/teams/team-serializer.ts +38 -38
  277. package/src/types/diff.d.ts +18 -18
  278. package/src/ui/agent-management-overlay.ts +144 -144
  279. package/src/ui/crew-widget.ts +487 -370
  280. package/src/ui/dashboard-panes/agents-pane.ts +109 -28
  281. package/src/ui/dashboard-panes/cancellation-pane.ts +42 -42
  282. package/src/ui/dashboard-panes/capability-pane.ts +59 -59
  283. package/src/ui/dashboard-panes/health-pane.ts +30 -30
  284. package/src/ui/dashboard-panes/mailbox-pane.ts +35 -35
  285. package/src/ui/dashboard-panes/progress-pane.ts +30 -30
  286. package/src/ui/dashboard-panes/transcript-pane.ts +10 -10
  287. package/src/ui/heartbeat-aggregator.ts +63 -63
  288. package/src/ui/keybinding-map.ts +97 -94
  289. package/src/ui/live-conversation-overlay.ts +152 -0
  290. package/src/ui/live-run-sidebar.ts +180 -180
  291. package/src/ui/mascot.ts +442 -442
  292. package/src/ui/overlays/agent-picker-overlay.ts +57 -57
  293. package/src/ui/overlays/confirm-overlay.ts +58 -58
  294. package/src/ui/overlays/mailbox-compose-overlay.ts +144 -144
  295. package/src/ui/overlays/mailbox-compose-preview.ts +63 -63
  296. package/src/ui/overlays/mailbox-detail-overlay.ts +122 -122
  297. package/src/ui/pi-ui-compat.ts +57 -57
  298. package/src/ui/powerbar-publisher.ts +221 -197
  299. package/src/ui/render-scheduler.ts +216 -143
  300. package/src/ui/run-action-dispatcher.ts +118 -118
  301. package/src/ui/run-dashboard.ts +526 -464
  302. package/src/ui/run-event-bus.ts +208 -208
  303. package/src/ui/run-snapshot-cache.ts +826 -777
  304. package/src/ui/settings-overlay.ts +721 -0
  305. package/src/ui/snapshot-types.ts +86 -70
  306. package/src/ui/theme-adapter.ts +190 -190
  307. package/src/ui/tool-progress-formatter.ts +89 -0
  308. package/src/ui/transcript-cache.ts +94 -94
  309. package/src/ui/transcript-viewer.ts +335 -335
  310. package/src/utils/conflict-detect.ts +662 -0
  311. package/src/utils/file-coalescer.ts +86 -86
  312. package/src/utils/frontmatter.ts +68 -68
  313. package/src/utils/fs-watch.ts +88 -31
  314. package/src/utils/gh-protocol.ts +479 -0
  315. package/src/utils/ids.ts +17 -17
  316. package/src/utils/incremental-reader.ts +104 -104
  317. package/src/utils/internal-error.ts +6 -6
  318. package/src/utils/names.ts +27 -27
  319. package/src/utils/paths.ts +102 -63
  320. package/src/utils/redaction.ts +44 -44
  321. package/src/utils/safe-paths.ts +47 -47
  322. package/src/utils/scan-cache.ts +136 -136
  323. package/src/utils/sse-parser.ts +134 -134
  324. package/src/utils/task-name-generator.ts +337 -337
  325. package/src/utils/timings.ts +33 -33
  326. package/src/utils/visual.ts +243 -198
  327. package/src/workflows/discover-workflows.ts +139 -139
  328. package/src/workflows/validate-workflow.ts +40 -40
  329. package/src/workflows/workflow-config.ts +26 -26
  330. package/src/workflows/workflow-serializer.ts +32 -32
  331. package/src/worktree/branch-freshness.ts +45 -45
  332. package/src/worktree/cleanup.ts +75 -75
  333. package/src/worktree/worktree-manager.ts +188 -188
  334. package/teams/default.team.md +12 -12
  335. package/teams/fast-fix.team.md +11 -11
  336. package/teams/implementation.team.md +18 -18
  337. package/teams/parallel-research.team.md +14 -14
  338. package/teams/research.team.md +11 -11
  339. package/teams/review.team.md +12 -12
  340. package/tsconfig.json +19 -19
  341. package/workflows/default.workflow.md +30 -30
  342. package/workflows/fast-fix.workflow.md +23 -23
  343. package/workflows/implementation.workflow.md +43 -43
  344. package/workflows/parallel-research.workflow.md +46 -46
  345. package/workflows/research.workflow.md +22 -22
  346. package/workflows/review.workflow.md +30 -30
  347. package/skills/task-packet/SKILL.md +0 -28
  348. package/skills/verify-evidence/SKILL.md +0 -27
@@ -1,108 +1,109 @@
1
- /**
2
- * Per-field resilient config parsing — continues on error, collects all field-level issues.
3
- */
4
-
5
- import { PiTeamsConfigSchema } from "../schema/config-schema.ts";
6
- import { Value } from "typebox/value";
7
- import { suggestConfigKey } from "./suggestions.ts";
8
- import {
9
- parseConfig,
10
- type PiTeamsConfig,
11
- } from "./config.ts";
12
-
13
- // ---------------------------------------------------------------------------
14
- // Types
15
- // ---------------------------------------------------------------------------
16
-
17
- export interface FieldError {
18
- field: string;
19
- message: string;
20
- value: unknown;
21
- suggestion?: string;
22
- }
23
-
24
- export interface ResilientParseResult {
25
- config: Record<string, unknown>;
26
- errors: FieldError[];
27
- warnings: string[];
28
- valid: boolean;
29
- }
30
-
31
- // ---------------------------------------------------------------------------
32
- // Helpers
33
- // ---------------------------------------------------------------------------
34
-
35
- const KNOWN_TOP_LEVEL_KEYS: readonly string[] = Object.keys(PiTeamsConfigSchema.properties ?? {});
36
-
37
- function isObject(value: unknown): value is Record<string, unknown> {
38
- return value !== null && typeof value === "object" && !Array.isArray(value);
39
- }
40
-
41
- // ---------------------------------------------------------------------------
42
- // Implementation
43
- // ---------------------------------------------------------------------------
44
-
45
- /**
46
- * Parse a raw config value field-by-field.
47
- *
48
- * - Each top-level key is validated independently via TypeBox sub-schemas.
49
- * - Fields that fail are recorded as errors but do not block others.
50
- * - Unknown keys get a fuzzy suggestion via Levenshtein distance.
51
- * - The returned `config` contains only successfully-parsed fields (via `parseConfig`).
52
- */
53
- export function parseConfigResilient(raw: unknown): ResilientParseResult {
54
- const errors: FieldError[] = [];
55
- const warnings: string[] = [];
56
-
57
- if (!isObject(raw)) {
58
- return { config: {}, errors: [{ field: "config", message: "config must be an object", value: raw }], warnings, valid: false };
59
- }
60
-
61
- // Collect unknown top-level keys with suggestions
62
- for (const key of Object.keys(raw)) {
63
- if (!KNOWN_TOP_LEVEL_KEYS.includes(key)) {
64
- const suggestion = suggestConfigKey(key, KNOWN_TOP_LEVEL_KEYS);
65
- errors.push({
66
- field: key,
67
- message: `unknown config key '${key}'`,
68
- value: raw[key],
69
- suggestion: suggestion ?? undefined,
70
- });
71
- }
72
- }
73
-
74
- // Use TypeBox per-field validation for known keys
75
- for (const key of KNOWN_TOP_LEVEL_KEYS) {
76
- if (!(key in raw)) continue;
77
- const value = raw[key];
78
- const subSchema = (PiTeamsConfigSchema.properties as Record<string, unknown>)[key];
79
- if (subSchema && !Value.Check(subSchema as { [key: string]: unknown }, value)) {
80
- // Collect the first error for this field
81
- const fieldErrors = [...Value.Errors(subSchema as { [key: string]: unknown }, value)];
82
- if (fieldErrors.length > 0) {
83
- const first = fieldErrors[0] as unknown as Record<string, unknown>;
84
- const msg = typeof first.message === "string" ? first.message : "invalid value";
85
- errors.push({
86
- field: key,
87
- message: msg,
88
- value,
89
- });
90
- }
91
- }
92
- }
93
-
94
- // Build the valid subset using existing parseConfig (which silently drops invalid fields)
95
- const parsed: PiTeamsConfig = parseConfig(raw);
96
- const config: Record<string, unknown> = {};
97
- for (const key of Object.keys(parsed)) {
98
- const val = (parsed as Record<string, unknown>)[key];
99
- if (val !== undefined) config[key] = val;
100
- }
101
-
102
- return {
103
- config,
104
- errors,
105
- warnings,
106
- valid: errors.length === 0,
107
- };
108
- }
1
+ /**
2
+ * Per-field resilient config parsing — continues on error, collects all field-level issues.
3
+ */
4
+
5
+ import { PiTeamsConfigSchema } from "../schema/config-schema.ts";
6
+ import { type TSchema } from "@sinclair/typebox";
7
+ import { Value } from "@sinclair/typebox/value";
8
+ import { suggestConfigKey } from "./suggestions.ts";
9
+ import {
10
+ parseConfig,
11
+ type PiTeamsConfig,
12
+ } from "./config.ts";
13
+
14
+ // ---------------------------------------------------------------------------
15
+ // Types
16
+ // ---------------------------------------------------------------------------
17
+
18
+ export interface FieldError {
19
+ field: string;
20
+ message: string;
21
+ value: unknown;
22
+ suggestion?: string;
23
+ }
24
+
25
+ export interface ResilientParseResult {
26
+ config: Record<string, unknown>;
27
+ errors: FieldError[];
28
+ warnings: string[];
29
+ valid: boolean;
30
+ }
31
+
32
+ // ---------------------------------------------------------------------------
33
+ // Helpers
34
+ // ---------------------------------------------------------------------------
35
+
36
+ const KNOWN_TOP_LEVEL_KEYS: readonly string[] = Object.keys(PiTeamsConfigSchema.properties ?? {});
37
+
38
+ function isObject(value: unknown): value is Record<string, unknown> {
39
+ return value !== null && typeof value === "object" && !Array.isArray(value);
40
+ }
41
+
42
+ // ---------------------------------------------------------------------------
43
+ // Implementation
44
+ // ---------------------------------------------------------------------------
45
+
46
+ /**
47
+ * Parse a raw config value field-by-field.
48
+ *
49
+ * - Each top-level key is validated independently via TypeBox sub-schemas.
50
+ * - Fields that fail are recorded as errors but do not block others.
51
+ * - Unknown keys get a fuzzy suggestion via Levenshtein distance.
52
+ * - The returned `config` contains only successfully-parsed fields (via `parseConfig`).
53
+ */
54
+ export function parseConfigResilient(raw: unknown): ResilientParseResult {
55
+ const errors: FieldError[] = [];
56
+ const warnings: string[] = [];
57
+
58
+ if (!isObject(raw)) {
59
+ return { config: {}, errors: [{ field: "config", message: "config must be an object", value: raw }], warnings, valid: false };
60
+ }
61
+
62
+ // Collect unknown top-level keys with suggestions
63
+ for (const key of Object.keys(raw)) {
64
+ if (!KNOWN_TOP_LEVEL_KEYS.includes(key)) {
65
+ const suggestion = suggestConfigKey(key, KNOWN_TOP_LEVEL_KEYS);
66
+ errors.push({
67
+ field: key,
68
+ message: `unknown config key '${key}'`,
69
+ value: raw[key],
70
+ suggestion: suggestion ?? undefined,
71
+ });
72
+ }
73
+ }
74
+
75
+ // Use TypeBox per-field validation for known keys
76
+ for (const key of KNOWN_TOP_LEVEL_KEYS) {
77
+ if (!(key in raw)) continue;
78
+ const value = raw[key];
79
+ const subSchema = (PiTeamsConfigSchema.properties as Record<string, unknown>)[key];
80
+ if (subSchema && !Value.Check(subSchema as TSchema, value)) {
81
+ // Collect the first error for this field
82
+ const fieldErrors = [...Value.Errors(subSchema as TSchema, value)];
83
+ if (fieldErrors.length > 0) {
84
+ const first = fieldErrors[0] as unknown as Record<string, unknown>;
85
+ const msg = typeof first.message === "string" ? first.message : "invalid value";
86
+ errors.push({
87
+ field: key,
88
+ message: msg,
89
+ value,
90
+ });
91
+ }
92
+ }
93
+ }
94
+
95
+ // Build the valid subset using existing parseConfig (which silently drops invalid fields)
96
+ const parsed: PiTeamsConfig = parseConfig(raw);
97
+ const config: Record<string, unknown> = {};
98
+ for (const key of Object.keys(parsed)) {
99
+ const val = (parsed as Record<string, unknown>)[key];
100
+ if (val !== undefined) config[key] = val;
101
+ }
102
+
103
+ return {
104
+ config,
105
+ errors,
106
+ warnings,
107
+ valid: errors.length === 0,
108
+ };
109
+ }
@@ -1,74 +1,74 @@
1
- /**
2
- * Fuzzy config key suggestions — Levenshtein-based typo correction for pi-crew config keys.
3
- */
4
-
5
- /**
6
- * Classic Levenshtein edit distance between two strings.
7
- */
8
- export function levenshtein(a: string, b: string): number {
9
- const la = a.length;
10
- const lb = b.length;
11
- if (la === 0) return lb;
12
- if (lb === 0) return la;
13
-
14
- // Single-row DP to keep memory O(min(n,m))
15
- let prev = new Uint32Array(lb + 1);
16
- let curr = new Uint32Array(lb + 1);
17
-
18
- for (let j = 0; j <= lb; j++) prev[j] = j;
19
-
20
- for (let i = 1; i <= la; i++) {
21
- curr[0] = i;
22
- for (let j = 1; j <= lb; j++) {
23
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
24
- curr[j] = Math.min(
25
- prev[j] + 1, // deletion
26
- curr[j - 1] + 1, // insertion
27
- prev[j - 1] + cost // substitution
28
- );
29
- }
30
- const swap = prev;
31
- prev = curr;
32
- curr = swap;
33
- }
34
-
35
- return prev[lb];
36
- }
37
-
38
- const DEFAULT_MAX_DISTANCE = 3;
39
-
40
- /**
41
- * Find the closest matching key from a list of valid keys.
42
- * Case-insensitive. Returns null if no match within `maxDistance`.
43
- */
44
- export function findClosestKey(
45
- input: string,
46
- validKeys: readonly string[],
47
- maxDistance: number = DEFAULT_MAX_DISTANCE,
48
- ): string | null {
49
- if (validKeys.length === 0) return null;
50
-
51
- const lower = input.toLowerCase();
52
- let bestKey: string | null = null;
53
- let bestDist = maxDistance + 1;
54
-
55
- for (const key of validKeys) {
56
- const dist = levenshtein(lower, key.toLowerCase());
57
- if (dist < bestDist) {
58
- bestDist = dist;
59
- bestKey = key;
60
- }
61
- }
62
-
63
- return bestDist <= maxDistance ? bestKey : null;
64
- }
65
-
66
- /**
67
- * Convenience wrapper — suggest the closest known config key for a potentially mistyped input.
68
- */
69
- export function suggestConfigKey(
70
- input: string,
71
- knownKeys: readonly string[],
72
- ): string | null {
73
- return findClosestKey(input, knownKeys);
74
- }
1
+ /**
2
+ * Fuzzy config key suggestions — Levenshtein-based typo correction for pi-crew config keys.
3
+ */
4
+
5
+ /**
6
+ * Classic Levenshtein edit distance between two strings.
7
+ */
8
+ export function levenshtein(a: string, b: string): number {
9
+ const la = a.length;
10
+ const lb = b.length;
11
+ if (la === 0) return lb;
12
+ if (lb === 0) return la;
13
+
14
+ // Single-row DP to keep memory O(min(n,m))
15
+ let prev = new Uint32Array(lb + 1);
16
+ let curr = new Uint32Array(lb + 1);
17
+
18
+ for (let j = 0; j <= lb; j++) prev[j] = j;
19
+
20
+ for (let i = 1; i <= la; i++) {
21
+ curr[0] = i;
22
+ for (let j = 1; j <= lb; j++) {
23
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
24
+ curr[j] = Math.min(
25
+ prev[j] + 1, // deletion
26
+ curr[j - 1] + 1, // insertion
27
+ prev[j - 1] + cost // substitution
28
+ );
29
+ }
30
+ const swap = prev;
31
+ prev = curr;
32
+ curr = swap;
33
+ }
34
+
35
+ return prev[lb];
36
+ }
37
+
38
+ const DEFAULT_MAX_DISTANCE = 3;
39
+
40
+ /**
41
+ * Find the closest matching key from a list of valid keys.
42
+ * Case-insensitive. Returns null if no match within `maxDistance`.
43
+ */
44
+ export function findClosestKey(
45
+ input: string,
46
+ validKeys: readonly string[],
47
+ maxDistance: number = DEFAULT_MAX_DISTANCE,
48
+ ): string | null {
49
+ if (validKeys.length === 0) return null;
50
+
51
+ const lower = input.toLowerCase();
52
+ let bestKey: string | null = null;
53
+ let bestDist = maxDistance + 1;
54
+
55
+ for (const key of validKeys) {
56
+ const dist = levenshtein(lower, key.toLowerCase());
57
+ if (dist < bestDist) {
58
+ bestDist = dist;
59
+ bestKey = key;
60
+ }
61
+ }
62
+
63
+ return bestDist <= maxDistance ? bestKey : null;
64
+ }
65
+
66
+ /**
67
+ * Convenience wrapper — suggest the closest known config key for a potentially mistyped input.
68
+ */
69
+ export function suggestConfigKey(
70
+ input: string,
71
+ knownKeys: readonly string[],
72
+ ): string | null {
73
+ return findClosestKey(input, knownKeys);
74
+ }
@@ -0,0 +1,199 @@
1
+ // 2.9 — config interface types extracted from src/config/config.ts.
2
+ //
3
+ // All public surface types live here so that hot-path callers (loadConfig,
4
+ // merging helpers, schema validators) can import just the types without
5
+ // pulling in the parser graph. config.ts re-exports every name from this
6
+ // file for backwards compat — existing `import { CrewUiConfig } from "../config/config.ts"`
7
+ // continues to work.
8
+
9
+ export type PiTeamsAutonomyProfile = "manual" | "suggested" | "assisted" | "aggressive";
10
+
11
+ export interface PiTeamsAutonomousConfig {
12
+ profile?: PiTeamsAutonomyProfile;
13
+ enabled?: boolean;
14
+ injectPolicy?: boolean;
15
+ preferAsyncForLongTasks?: boolean;
16
+ allowWorktreeSuggestion?: boolean;
17
+ magicKeywords?: Record<string, string[]>;
18
+ }
19
+
20
+ export interface CrewLimitsConfig {
21
+ maxConcurrentWorkers?: number;
22
+ allowUnboundedConcurrency?: boolean;
23
+ maxTaskDepth?: number;
24
+ maxChildrenPerTask?: number;
25
+ maxRunMinutes?: number;
26
+ maxRetriesPerTask?: number;
27
+ maxTasksPerRun?: number;
28
+ heartbeatStaleMs?: number;
29
+ }
30
+
31
+ export type CrewRuntimeMode = "auto" | "scaffold" | "child-process" | "live-session";
32
+
33
+ export type CompletionMutationGuardMode = "off" | "warn" | "fail";
34
+ export type EffectivenessGuardMode = "off" | "warn" | "block" | "fail";
35
+
36
+ export interface CrewRuntimeConfig {
37
+ mode?: CrewRuntimeMode;
38
+ preferLiveSession?: boolean;
39
+ allowChildProcessFallback?: boolean;
40
+ maxTurns?: number;
41
+ graceTurns?: number;
42
+ inheritContext?: boolean;
43
+ promptMode?: "replace" | "append";
44
+ groupJoin?: "off" | "group" | "smart";
45
+ groupJoinAckTimeoutMs?: number;
46
+ requirePlanApproval?: boolean;
47
+ completionMutationGuard?: CompletionMutationGuardMode;
48
+ effectivenessGuard?: EffectivenessGuardMode;
49
+ yield?: { enabled?: boolean; maxReminders?: number; reminderPrompt?: string };
50
+ /** Policy for per-role runtime selection. Not sensitive — safe to keep in project config. */
51
+ isolationPolicy?: {
52
+ /** Roles that should use child-process for crash isolation. Default: no roles. */
53
+ isolatedRoles?: string[];
54
+ /** Default runtime for roles not in isolatedRoles. Default: "live-session" (uses live-session). */
55
+ defaultRuntime?: "live-session" | "child-process";
56
+ };
57
+ }
58
+
59
+ export interface CrewControlConfig {
60
+ enabled?: boolean;
61
+ needsAttentionAfterMs?: number;
62
+ }
63
+
64
+ export interface CrewWorktreeConfig {
65
+ setupHook?: string;
66
+ setupHookTimeoutMs?: number;
67
+ linkNodeModules?: boolean;
68
+ }
69
+
70
+ export interface CrewUiConfig {
71
+ widgetPlacement?: "aboveEditor" | "belowEditor";
72
+ widgetMaxLines?: number;
73
+ powerbar?: boolean;
74
+ dashboardPlacement?: "center" | "right";
75
+ dashboardWidth?: number;
76
+ dashboardLiveRefreshMs?: number;
77
+ autoOpenDashboard?: boolean;
78
+ autoOpenDashboardForForegroundRuns?: boolean;
79
+ showModel?: boolean;
80
+ showTokens?: boolean;
81
+ showTools?: boolean;
82
+ transcriptTailBytes?: number;
83
+ mascotStyle?: "cat" | "armin";
84
+ mascotEffect?: "random" | "none" | "typewriter" | "scanline" | "rain" | "fade" | "crt" | "glitch" | "dissolve";
85
+ }
86
+
87
+ export interface AgentOverrideConfig {
88
+ disabled?: boolean;
89
+ model?: string | false;
90
+ fallbackModels?: string[] | false;
91
+ thinking?: string | false;
92
+ tools?: string[] | false;
93
+ skills?: string[] | false;
94
+ }
95
+
96
+ export interface CrewAgentsConfig {
97
+ disableBuiltins?: boolean;
98
+ overrides?: Record<string, AgentOverrideConfig>;
99
+ }
100
+
101
+ export interface CrewToolsConfig {
102
+ enableClaudeStyleAliases?: boolean;
103
+ enableSteer?: boolean;
104
+ terminateOnForeground?: boolean;
105
+ }
106
+
107
+ export interface CrewTelemetryConfig {
108
+ enabled?: boolean;
109
+ }
110
+
111
+ export interface CrewPolicyConfig {
112
+ requireIntentForDestructiveActions?: boolean;
113
+ disabledCapabilities?: string[];
114
+ }
115
+
116
+ export type CrewNotificationSeverity = "info" | "warning" | "error" | "critical";
117
+
118
+ export interface CrewNotificationsConfig {
119
+ enabled?: boolean;
120
+ severityFilter?: CrewNotificationSeverity[];
121
+ dedupWindowMs?: number;
122
+ batchWindowMs?: number;
123
+ quietHours?: string;
124
+ sinkRetentionDays?: number;
125
+ }
126
+
127
+ export interface CrewObservabilityConfig {
128
+ enabled?: boolean;
129
+ pollIntervalMs?: number;
130
+ metricRetentionDays?: number;
131
+ }
132
+
133
+ export interface CrewRetryPolicyConfig {
134
+ maxAttempts?: number;
135
+ backoffMs?: number;
136
+ jitterRatio?: number;
137
+ exponentialFactor?: number;
138
+ retryableErrors?: string[];
139
+ }
140
+
141
+ export interface CrewReliabilityConfig {
142
+ autoRetry?: boolean;
143
+ retryPolicy?: CrewRetryPolicyConfig;
144
+ autoRecover?: boolean;
145
+ deadletterThreshold?: number;
146
+ }
147
+
148
+ export interface CrewOtlpConfig {
149
+ enabled?: boolean;
150
+ endpoint?: string;
151
+ headers?: Record<string, string>;
152
+ intervalMs?: number;
153
+ }
154
+
155
+ export interface PiTeamsConfig {
156
+ asyncByDefault?: boolean;
157
+ executeWorkers?: boolean;
158
+ notifierIntervalMs?: number;
159
+ requireCleanWorktreeLeader?: boolean;
160
+ ignoreMethod?: "gitignore" | "exclude";
161
+ autonomous?: PiTeamsAutonomousConfig;
162
+ limits?: CrewLimitsConfig;
163
+ runtime?: CrewRuntimeConfig;
164
+ control?: CrewControlConfig;
165
+ worktree?: CrewWorktreeConfig;
166
+ agents?: CrewAgentsConfig;
167
+ tools?: CrewToolsConfig;
168
+ telemetry?: CrewTelemetryConfig;
169
+ policy?: CrewPolicyConfig;
170
+ notifications?: CrewNotificationsConfig;
171
+ observability?: CrewObservabilityConfig;
172
+ reliability?: CrewReliabilityConfig;
173
+ otlp?: CrewOtlpConfig;
174
+ ui?: CrewUiConfig;
175
+ }
176
+
177
+ export interface LoadedPiTeamsConfig {
178
+ config: PiTeamsConfig;
179
+ path: string;
180
+ paths: string[];
181
+ error?: string;
182
+ warnings?: string[];
183
+ }
184
+
185
+ export interface ConfigValidationResult {
186
+ config: PiTeamsConfig;
187
+ warnings: string[];
188
+ }
189
+
190
+ export interface SavedPiTeamsConfig {
191
+ config: PiTeamsConfig;
192
+ path: string;
193
+ }
194
+
195
+ export interface UpdateConfigOptions {
196
+ cwd?: string;
197
+ scope?: "user" | "project";
198
+ unsetPaths?: string[];
199
+ }