groundswell 0.0.2 → 1.0.0

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 (554) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -9
  3. package/dist/cache/cache-key.d.ts +86 -0
  4. package/dist/cache/cache-key.d.ts.map +1 -0
  5. package/dist/cache/cache-key.js +204 -0
  6. package/dist/cache/cache-key.js.map +1 -0
  7. package/dist/cache/cache.d.ts +104 -0
  8. package/dist/cache/cache.d.ts.map +1 -0
  9. package/dist/cache/cache.js +179 -0
  10. package/dist/cache/cache.js.map +1 -0
  11. package/{src/cache/index.ts → dist/cache/index.d.ts} +1 -1
  12. package/dist/cache/index.d.ts.map +1 -0
  13. package/dist/cache/index.js +6 -0
  14. package/dist/cache/index.js.map +1 -0
  15. package/dist/core/agent.d.ts +203 -0
  16. package/dist/core/agent.d.ts.map +1 -0
  17. package/dist/core/agent.js +833 -0
  18. package/dist/core/agent.js.map +1 -0
  19. package/{src/core/context.ts → dist/core/context.d.ts} +16 -67
  20. package/dist/core/context.d.ts.map +1 -0
  21. package/dist/core/context.js +80 -0
  22. package/dist/core/context.js.map +1 -0
  23. package/dist/core/event-tree.d.ts +72 -0
  24. package/dist/core/event-tree.d.ts.map +1 -0
  25. package/dist/core/event-tree.js +211 -0
  26. package/dist/core/event-tree.js.map +1 -0
  27. package/{src/core/factory.ts → dist/core/factory.d.ts} +6 -27
  28. package/dist/core/factory.d.ts.map +1 -0
  29. package/dist/core/factory.js +110 -0
  30. package/dist/core/factory.js.map +1 -0
  31. package/{src/core/index.ts → dist/core/index.d.ts} +2 -10
  32. package/dist/core/index.d.ts.map +1 -0
  33. package/dist/core/index.js +9 -0
  34. package/dist/core/index.js.map +1 -0
  35. package/dist/core/logger.d.ts +50 -0
  36. package/dist/core/logger.d.ts.map +1 -0
  37. package/dist/core/logger.js +91 -0
  38. package/dist/core/logger.js.map +1 -0
  39. package/dist/core/mcp-handler.d.ts +127 -0
  40. package/dist/core/mcp-handler.d.ts.map +1 -0
  41. package/dist/core/mcp-handler.js +323 -0
  42. package/dist/core/mcp-handler.js.map +1 -0
  43. package/dist/core/prompt.d.ts +80 -0
  44. package/dist/core/prompt.d.ts.map +1 -0
  45. package/dist/core/prompt.js +120 -0
  46. package/dist/core/prompt.js.map +1 -0
  47. package/dist/core/workflow-context.d.ts +61 -0
  48. package/dist/core/workflow-context.d.ts.map +1 -0
  49. package/dist/core/workflow-context.js +358 -0
  50. package/dist/core/workflow-context.js.map +1 -0
  51. package/dist/core/workflow.d.ts +543 -0
  52. package/dist/core/workflow.d.ts.map +1 -0
  53. package/dist/core/workflow.js +986 -0
  54. package/dist/core/workflow.js.map +1 -0
  55. package/dist/debugger/event-replayer.d.ts +422 -0
  56. package/dist/debugger/event-replayer.d.ts.map +1 -0
  57. package/dist/debugger/event-replayer.js +639 -0
  58. package/dist/debugger/event-replayer.js.map +1 -0
  59. package/dist/debugger/index.d.ts +2 -0
  60. package/dist/debugger/index.d.ts.map +1 -0
  61. package/{src/debugger/index.ts → dist/debugger/index.js} +1 -0
  62. package/dist/debugger/index.js.map +1 -0
  63. package/dist/debugger/tree-debugger.d.ts +240 -0
  64. package/dist/debugger/tree-debugger.d.ts.map +1 -0
  65. package/dist/debugger/tree-debugger.js +620 -0
  66. package/dist/debugger/tree-debugger.js.map +1 -0
  67. package/dist/decorators/index.d.ts +4 -0
  68. package/dist/decorators/index.d.ts.map +1 -0
  69. package/{src/decorators/index.ts → dist/decorators/index.js} +1 -0
  70. package/dist/decorators/index.js.map +1 -0
  71. package/dist/decorators/observed-state.d.ts +32 -0
  72. package/dist/decorators/observed-state.d.ts.map +1 -0
  73. package/dist/decorators/observed-state.js +79 -0
  74. package/dist/decorators/observed-state.js.map +1 -0
  75. package/dist/decorators/step.d.ts +15 -0
  76. package/dist/decorators/step.d.ts.map +1 -0
  77. package/dist/decorators/step.js +192 -0
  78. package/dist/decorators/step.js.map +1 -0
  79. package/dist/decorators/task.d.ts +50 -0
  80. package/dist/decorators/task.d.ts.map +1 -0
  81. package/dist/decorators/task.js +118 -0
  82. package/dist/decorators/task.js.map +1 -0
  83. package/dist/examples/index.d.ts +3 -0
  84. package/dist/examples/index.d.ts.map +1 -0
  85. package/{src/examples/index.ts → dist/examples/index.js} +1 -0
  86. package/dist/examples/index.js.map +1 -0
  87. package/dist/examples/tdd-orchestrator.d.ts +15 -0
  88. package/dist/examples/tdd-orchestrator.d.ts.map +1 -0
  89. package/dist/examples/tdd-orchestrator.js +121 -0
  90. package/dist/examples/tdd-orchestrator.js.map +1 -0
  91. package/dist/examples/test-cycle-workflow.d.ts +14 -0
  92. package/dist/examples/test-cycle-workflow.d.ts.map +1 -0
  93. package/dist/examples/test-cycle-workflow.js +116 -0
  94. package/dist/examples/test-cycle-workflow.js.map +1 -0
  95. package/dist/harnesses/claude-code-harness.d.ts +391 -0
  96. package/dist/harnesses/claude-code-harness.d.ts.map +1 -0
  97. package/dist/harnesses/claude-code-harness.js +1076 -0
  98. package/dist/harnesses/claude-code-harness.js.map +1 -0
  99. package/dist/harnesses/harness-registry.d.ts +440 -0
  100. package/dist/harnesses/harness-registry.d.ts.map +1 -0
  101. package/dist/harnesses/harness-registry.js +543 -0
  102. package/dist/harnesses/harness-registry.js.map +1 -0
  103. package/dist/harnesses/index.d.ts +12 -0
  104. package/dist/harnesses/index.d.ts.map +1 -0
  105. package/dist/harnesses/index.js +11 -0
  106. package/dist/harnesses/index.js.map +1 -0
  107. package/dist/harnesses/pi-harness.d.ts +219 -0
  108. package/dist/harnesses/pi-harness.d.ts.map +1 -0
  109. package/dist/harnesses/pi-harness.js +676 -0
  110. package/dist/harnesses/pi-harness.js.map +1 -0
  111. package/dist/harnesses/pi-schema-converter.d.ts +24 -0
  112. package/dist/harnesses/pi-schema-converter.d.ts.map +1 -0
  113. package/dist/harnesses/pi-schema-converter.js +81 -0
  114. package/dist/harnesses/pi-schema-converter.js.map +1 -0
  115. package/dist/harnesses/register-defaults.d.ts +24 -0
  116. package/dist/harnesses/register-defaults.d.ts.map +1 -0
  117. package/dist/harnesses/register-defaults.js +40 -0
  118. package/dist/harnesses/register-defaults.js.map +1 -0
  119. package/dist/harnesses/session-store.d.ts +201 -0
  120. package/dist/harnesses/session-store.d.ts.map +1 -0
  121. package/dist/harnesses/session-store.js +254 -0
  122. package/dist/harnesses/session-store.js.map +1 -0
  123. package/dist/index.d.ts +37 -0
  124. package/dist/index.d.ts.map +1 -0
  125. package/dist/index.js +57 -0
  126. package/dist/index.js.map +1 -0
  127. package/dist/reflection/index.d.ts +5 -0
  128. package/dist/reflection/index.d.ts.map +1 -0
  129. package/{src/reflection/index.ts → dist/reflection/index.js} +1 -1
  130. package/dist/reflection/index.js.map +1 -0
  131. package/dist/reflection/reflection.d.ts +84 -0
  132. package/dist/reflection/reflection.d.ts.map +1 -0
  133. package/dist/reflection/reflection.js +344 -0
  134. package/dist/reflection/reflection.js.map +1 -0
  135. package/dist/tools/index.d.ts +6 -0
  136. package/dist/tools/index.d.ts.map +1 -0
  137. package/dist/tools/index.js +11 -0
  138. package/dist/tools/index.js.map +1 -0
  139. package/dist/tools/introspection.d.ts +165 -0
  140. package/dist/tools/introspection.d.ts.map +1 -0
  141. package/dist/tools/introspection.js +324 -0
  142. package/dist/tools/introspection.js.map +1 -0
  143. package/dist/types/agent.d.ts +1317 -0
  144. package/dist/types/agent.d.ts.map +1 -0
  145. package/dist/types/agent.js +423 -0
  146. package/dist/types/agent.js.map +1 -0
  147. package/dist/types/decorators.d.ts +40 -0
  148. package/dist/types/decorators.d.ts.map +1 -0
  149. package/dist/types/decorators.js +2 -0
  150. package/dist/types/decorators.js.map +1 -0
  151. package/dist/types/error-strategy.d.ts +13 -0
  152. package/dist/types/error-strategy.d.ts.map +1 -0
  153. package/dist/types/error-strategy.js +2 -0
  154. package/dist/types/error-strategy.js.map +1 -0
  155. package/dist/types/error.d.ts +20 -0
  156. package/dist/types/error.d.ts.map +1 -0
  157. package/dist/types/error.js +2 -0
  158. package/dist/types/error.js.map +1 -0
  159. package/dist/types/events.d.ts +113 -0
  160. package/dist/types/events.d.ts.map +1 -0
  161. package/dist/types/events.js +2 -0
  162. package/dist/types/events.js.map +1 -0
  163. package/dist/types/harnesses.d.ts +474 -0
  164. package/dist/types/harnesses.d.ts.map +1 -0
  165. package/dist/types/harnesses.js +2 -0
  166. package/dist/types/harnesses.js.map +1 -0
  167. package/dist/types/index.d.ts +23 -0
  168. package/dist/types/index.d.ts.map +1 -0
  169. package/dist/types/index.js +8 -0
  170. package/dist/types/index.js.map +1 -0
  171. package/dist/types/logging.d.ts +24 -0
  172. package/dist/types/logging.d.ts.map +1 -0
  173. package/dist/types/logging.js +2 -0
  174. package/dist/types/logging.js.map +1 -0
  175. package/dist/types/observer.d.ts +18 -0
  176. package/dist/types/observer.d.ts.map +1 -0
  177. package/dist/types/observer.js +2 -0
  178. package/dist/types/observer.js.map +1 -0
  179. package/dist/types/prompt.d.ts +31 -0
  180. package/dist/types/prompt.d.ts.map +1 -0
  181. package/dist/types/prompt.js +6 -0
  182. package/dist/types/prompt.js.map +1 -0
  183. package/dist/types/providers.d.ts +691 -0
  184. package/dist/types/providers.d.ts.map +1 -0
  185. package/dist/types/providers.js +14 -0
  186. package/dist/types/providers.js.map +1 -0
  187. package/dist/types/reflection.d.ts +96 -0
  188. package/dist/types/reflection.d.ts.map +1 -0
  189. package/dist/types/reflection.js +24 -0
  190. package/dist/types/reflection.js.map +1 -0
  191. package/dist/types/restart.d.ts +132 -0
  192. package/dist/types/restart.d.ts.map +1 -0
  193. package/dist/types/restart.js +2 -0
  194. package/dist/types/restart.js.map +1 -0
  195. package/dist/types/sdk-primitives.d.ts +118 -0
  196. package/dist/types/sdk-primitives.d.ts.map +1 -0
  197. package/dist/types/sdk-primitives.js +6 -0
  198. package/dist/types/sdk-primitives.js.map +1 -0
  199. package/{src/types/snapshot.ts → dist/types/snapshot.d.ts} +5 -5
  200. package/dist/types/snapshot.d.ts.map +1 -0
  201. package/dist/types/snapshot.js +2 -0
  202. package/dist/types/snapshot.js.map +1 -0
  203. package/dist/types/streaming.d.ts +194 -0
  204. package/dist/types/streaming.d.ts.map +1 -0
  205. package/dist/types/streaming.js +67 -0
  206. package/dist/types/streaming.js.map +1 -0
  207. package/dist/types/workflow-context.d.ts +275 -0
  208. package/dist/types/workflow-context.d.ts.map +1 -0
  209. package/dist/types/workflow-context.js +8 -0
  210. package/dist/types/workflow-context.js.map +1 -0
  211. package/dist/types/workflow.d.ts +30 -0
  212. package/dist/types/workflow.d.ts.map +1 -0
  213. package/dist/types/workflow.js +2 -0
  214. package/dist/types/workflow.js.map +1 -0
  215. package/dist/utils/agent-validation.d.ts +88 -0
  216. package/dist/utils/agent-validation.d.ts.map +1 -0
  217. package/dist/utils/agent-validation.js +87 -0
  218. package/dist/utils/agent-validation.js.map +1 -0
  219. package/dist/utils/delay.d.ts +7 -0
  220. package/dist/utils/delay.d.ts.map +1 -0
  221. package/dist/utils/delay.js +9 -0
  222. package/dist/utils/delay.js.map +1 -0
  223. package/dist/utils/harness-config.d.ts +180 -0
  224. package/dist/utils/harness-config.d.ts.map +1 -0
  225. package/dist/utils/harness-config.js +311 -0
  226. package/dist/utils/harness-config.js.map +1 -0
  227. package/dist/utils/id.d.ts +6 -0
  228. package/dist/utils/id.d.ts.map +1 -0
  229. package/dist/utils/id.js +12 -0
  230. package/dist/utils/id.js.map +1 -0
  231. package/dist/utils/index.d.ts +13 -0
  232. package/dist/utils/index.d.ts.map +1 -0
  233. package/dist/utils/index.js +11 -0
  234. package/dist/utils/index.js.map +1 -0
  235. package/dist/utils/model-spec.d.ts +110 -0
  236. package/dist/utils/model-spec.d.ts.map +1 -0
  237. package/dist/utils/model-spec.js +149 -0
  238. package/dist/utils/model-spec.js.map +1 -0
  239. package/dist/utils/observable.d.ts +54 -0
  240. package/dist/utils/observable.d.ts.map +1 -0
  241. package/dist/utils/observable.js +82 -0
  242. package/dist/utils/observable.js.map +1 -0
  243. package/dist/utils/provider-config.d.ts +10 -0
  244. package/dist/utils/provider-config.d.ts.map +1 -0
  245. package/dist/utils/provider-config.js +10 -0
  246. package/dist/utils/provider-config.js.map +1 -0
  247. package/dist/utils/restart-analysis.d.ts +202 -0
  248. package/dist/utils/restart-analysis.d.ts.map +1 -0
  249. package/dist/utils/restart-analysis.js +426 -0
  250. package/dist/utils/restart-analysis.js.map +1 -0
  251. package/dist/utils/session-serialization.d.ts +118 -0
  252. package/dist/utils/session-serialization.d.ts.map +1 -0
  253. package/dist/utils/session-serialization.js +217 -0
  254. package/dist/utils/session-serialization.js.map +1 -0
  255. package/dist/utils/workflow-error-utils.d.ts +22 -0
  256. package/dist/utils/workflow-error-utils.d.ts.map +1 -0
  257. package/dist/utils/workflow-error-utils.js +45 -0
  258. package/dist/utils/workflow-error-utils.js.map +1 -0
  259. package/package.json +34 -5
  260. package/.claude/commands/subtask-planning/prp-base-create.md +0 -120
  261. package/.claude/commands/subtask-planning/prp-base-execute.md +0 -65
  262. package/.claude/commands/task-breakdown.md +0 -94
  263. package/.claude/settings.local.json +0 -9
  264. package/.claude/system_prompts/task-breakdown.md +0 -101
  265. package/CHANGELOG.md +0 -188
  266. package/PRD.md +0 -543
  267. package/PRPs/001-hierarchical-workflow-engine.md +0 -2438
  268. package/PRPs/PRDs/002-agent-prompt.md +0 -390
  269. package/PRPs/PRDs/003-agent-prompt.md +0 -943
  270. package/PRPs/PRDs/004-agent-prompt.md +0 -1136
  271. package/PRPs/PRDs/tasks-001.json +0 -492
  272. package/PRPs/README.md +0 -83
  273. package/PRPs/templates/prp_base.md +0 -222
  274. package/docs/agent.md +0 -422
  275. package/docs/prompt.md +0 -419
  276. package/docs/workflow.md +0 -600
  277. package/examples/README.md +0 -258
  278. package/examples/examples/01-basic-workflow.ts +0 -100
  279. package/examples/examples/02-decorator-options.ts +0 -217
  280. package/examples/examples/03-parent-child.ts +0 -241
  281. package/examples/examples/04-observers-debugger.ts +0 -340
  282. package/examples/examples/05-error-handling.ts +0 -387
  283. package/examples/examples/06-concurrent-tasks.ts +0 -352
  284. package/examples/examples/07-agent-loops.ts +0 -432
  285. package/examples/examples/08-sdk-features.ts +0 -667
  286. package/examples/examples/09-reflection.ts +0 -573
  287. package/examples/examples/10-introspection.ts +0 -550
  288. package/examples/examples/11-reparenting-workflows.ts +0 -269
  289. package/examples/index.ts +0 -147
  290. package/examples/utils/helpers.ts +0 -57
  291. package/package-lock.json +0 -2398
  292. package/plan/001_d3bb02af4886/TEST_RESULTS.md +0 -259
  293. package/plan/001_d3bb02af4886/backlog.json +0 -867
  294. package/plan/001_d3bb02af4886/bug_fix_tasks.json +0 -484
  295. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S1/PRP.md +0 -488
  296. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S2/PRP.md +0 -581
  297. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S3/PRP.md +0 -687
  298. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S1/PRP.md +0 -492
  299. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/PRP.md +0 -932
  300. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/concurrent_error_testing_patterns.md +0 -1109
  301. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/vitest_concurrent_testing.md +0 -802
  302. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/workflow_engine_test_references.md +0 -603
  303. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S1/PRP.md +0 -564
  304. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S3/PRP.md +0 -518
  305. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S4/PRP.md +0 -1252
  306. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/PRP.md +0 -364
  307. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/CODEBASE_INVENTORY.md +0 -114
  308. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/DECORATOR_DOCUMENTATION_PATTERNS.md +0 -205
  309. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/PRD_LOCATION_ANALYSIS.md +0 -199
  310. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/ULTRATHINK_PRP_PLAN.md +0 -134
  311. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/PRP.md +0 -495
  312. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/research/console_error_inventory.md +0 -435
  313. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S2/PRP.md +0 -506
  314. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S3/PRP.md +0 -612
  315. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/PRP.md +0 -558
  316. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/research/external_research.md +0 -788
  317. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S2/PRP.md +0 -460
  318. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S3/PRP.md +0 -454
  319. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/PRP.md +0 -520
  320. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/RECOMMENDATION.md +0 -417
  321. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/external_workflow_engines_research.md +0 -760
  322. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/security_implications_analysis.md +0 -245
  323. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S2/PRP.md +0 -792
  324. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/PRP.md +0 -535
  325. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/TEST_EXECUTION_REPORT.md +0 -190
  326. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/PRP.md +0 -654
  327. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/TEST_FIX_REPORT.md +0 -227
  328. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/KEY_FINDINGS.md +0 -345
  329. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/QUICK_REFERENCE.md +0 -193
  330. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/test_maintenance_research.md +0 -1323
  331. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/BREAKING_CHANGES_AUDIT.md +0 -1011
  332. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/PRP.md +0 -927
  333. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S2/PRP.md +0 -505
  334. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/architecture/logger_child_signature_analysis.md +0 -401
  335. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/child_implementation_research.md +0 -142
  336. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/test_patterns_research.md +0 -112
  337. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/vitest_patterns_research.md +0 -159
  338. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/PRP.md +0 -549
  339. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/VERIFICATION_REPORT.md +0 -368
  340. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/edge_case_analysis.md +0 -172
  341. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/usage_inventory.md +0 -175
  342. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S2/PRP.md +0 -696
  343. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S4/PRP.md +0 -860
  344. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/PRP.md +0 -1066
  345. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01-testing-aggregated-errors.md +0 -1103
  346. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01_typescript_error_aggregation_patterns.md +0 -789
  347. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02-error-merge-strategy-testing-guide.md +0 -1098
  348. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02_aggregate_error_patterns.md +0 -1037
  349. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03-promise-allsettled-testing-patterns.md +0 -916
  350. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03_error_merging_strategies.md +0 -1045
  351. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/04_github_stackoverflow_examples.md +0 -890
  352. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/05_comprehensive_summary.md +0 -822
  353. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/INDEX.md +0 -668
  354. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/QUICK_REFERENCE.md +0 -706
  355. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/README.md +0 -265
  356. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/RESEARCH_REPORT.md +0 -655
  357. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S4/research/vitest_testing_patterns.md +0 -1103
  358. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T3S2/PRP.md +0 -426
  359. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/PRP.md +0 -506
  360. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/QUICK_REFERENCE.md +0 -114
  361. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/RESEARCH_SUMMARY.md +0 -316
  362. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/vitest_observer_error_logging_best_practices.md +0 -754
  363. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S3/PRP.md +0 -612
  364. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/PRP.md +0 -719
  365. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/README.md +0 -215
  366. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/analysis.md +0 -765
  367. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S3/PRP.md +0 -718
  368. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/DECISION.md +0 -149
  369. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/PRP.md +0 -470
  370. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/ULTRATHINK_PLAN.md +0 -332
  371. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/codebase_workflow_name_analysis.md +0 -167
  372. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/external_best_practices.md +0 -265
  373. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/validation_patterns.md +0 -273
  374. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S1/workflow_engine_ancestry_api_research.md +0 -760
  375. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S3-PRP.md +0 -434
  376. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S1/PRP.md +0 -717
  377. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/PRP.md +0 -472
  378. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/VALIDATION_REPORT.md +0 -125
  379. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/research/ULTRATHINK_PRP_PLAN.md +0 -301
  380. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/error-logging-best-practices.md +0 -1170
  381. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/research_typescript_partial_and_overloads.md +0 -940
  382. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-quick-reference.md +0 -151
  383. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-research.md +0 -650
  384. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/prd_snapshot.md +0 -259
  385. package/plan/001_d3bb02af4886/bugfix/P1M1T1S1/PRP.md +0 -457
  386. package/plan/001_d3bb02af4886/bugfix/RESEARCH_SUMMARY.md +0 -346
  387. package/plan/001_d3bb02af4886/bugfix/architecture/codebase_structure.md +0 -311
  388. package/plan/001_d3bb02af4886/bugfix/architecture/concurrent_execution_best_practices.md +0 -1565
  389. package/plan/001_d3bb02af4886/bugfix/architecture/error_handling_patterns.md +0 -288
  390. package/plan/001_d3bb02af4886/bugfix/architecture/promise_all_analysis.md +0 -741
  391. package/plan/001_d3bb02af4886/docs/PRP/P1M1T1S4-functional-workflow-error-state-capture-test.md +0 -652
  392. package/plan/001_d3bb02af4886/docs/PRP/P1P2-PRP.md +0 -527
  393. package/plan/001_d3bb02af4886/docs/PRP/P3P4-PRP.md +0 -1388
  394. package/plan/001_d3bb02af4886/docs/PRP/P4P5-PRP.md +0 -1136
  395. package/plan/001_d3bb02af4886/docs/PRP/PRP.md +0 -527
  396. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S1-PRP.md +0 -415
  397. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S2-PRP.md +0 -378
  398. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S4-PRP.md +0 -713
  399. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M2T1S4-PRP.md +0 -370
  400. package/plan/001_d3bb02af4886/docs/PRP_P1M3T1S3.md +0 -499
  401. package/plan/001_d3bb02af4886/docs/TEST_RESULTS.md +0 -230
  402. package/plan/001_d3bb02af4886/docs/architecture/external_deps.md +0 -358
  403. package/plan/001_d3bb02af4886/docs/architecture/system_context.md +0 -242
  404. package/plan/001_d3bb02af4886/docs/bugfix/ANALYSIS_PRD_VS_IMPLEMENTATION.md +0 -1134
  405. package/plan/001_d3bb02af4886/docs/bugfix/GAP_ANALYSIS_SUMMARY.md +0 -179
  406. package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/PRP.md +0 -629
  407. package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/validation-report.md +0 -214
  408. package/plan/001_d3bb02af4886/docs/bugfix/PRP_P1M4T2S3.md +0 -629
  409. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_PRP.md +0 -529
  410. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_QUICK_REFERENCE.md +0 -142
  411. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_README.md +0 -304
  412. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_TEST_RESULTS.md +0 -558
  413. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_VALIDATION_SUMMARY.md +0 -256
  414. package/plan/001_d3bb02af4886/docs/bugfix/system_context.md +0 -346
  415. package/plan/001_d3bb02af4886/docs/bugfix-architecture/bug_analysis.md +0 -415
  416. package/plan/001_d3bb02af4886/docs/bugfix-architecture/implementation_patterns.md +0 -489
  417. package/plan/001_d3bb02af4886/docs/bugfix-architecture/system_context.md +0 -218
  418. package/plan/001_d3bb02af4886/docs/bugfix_INITIATION_SUMMARY.md +0 -380
  419. package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_PATTERNS.md +0 -1923
  420. package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_QUICK_REF.md +0 -319
  421. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/codebase-context.md +0 -115
  422. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/cycle-detection-algorithms.md +0 -134
  423. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/test-patterns.md +0 -153
  424. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/workflow-class.md +0 -132
  425. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_BEST_PRACTICES.md +0 -716
  426. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_QUICK_REF.md +0 -186
  427. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/GROUNDSWELL_DECORATOR_EXAMPLES.md +0 -604
  428. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/INDEX.md +0 -213
  429. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/codebase_structure.md +0 -30
  430. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/existing_test_pattern.md +0 -56
  431. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/getRootObservers_implementation.md +0 -53
  432. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/test_conventions.md +0 -49
  433. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/PRP.md +0 -958
  434. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/QUICK_REFERENCE.md +0 -339
  435. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/README.md +0 -305
  436. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/SUMMARY.md +0 -433
  437. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/bidirectional-tree-consistency-testing.md +0 -1574
  438. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/test-pattern-examples.md +0 -1014
  439. package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_BEST_PRACTICES.md +0 -1929
  440. package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_CODE_PATTERNS.md +0 -857
  441. package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_INTEGRATION_GUIDE.md +0 -738
  442. package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_RESEARCH_INDEX.md +0 -424
  443. package/plan/001_d3bb02af4886/docs/research/P1P2/REFLECTION_INDEX.md +0 -291
  444. package/plan/001_d3bb02af4886/docs/research/P1P2/REFLECTION_RESEARCH_REPORT.md +0 -1342
  445. package/plan/001_d3bb02af4886/docs/research/P1P2/RESEARCH_SUMMARY.md +0 -342
  446. package/plan/001_d3bb02af4886/docs/research/P1P2/anthropic-sdk.md +0 -174
  447. package/plan/001_d3bb02af4886/docs/research/P1P2/async-local-storage.md +0 -200
  448. package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-code-patterns.md +0 -1205
  449. package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-decision-matrix.md +0 -421
  450. package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-implementation-guide.md +0 -1341
  451. package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-integration-guide.md +0 -834
  452. package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-patterns.md +0 -1468
  453. package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-quick-reference.md +0 -558
  454. package/plan/001_d3bb02af4886/docs/research/P1P2/zod-schema.md +0 -152
  455. package/plan/001_d3bb02af4886/docs/research/P3P4/caching-lru.md +0 -116
  456. package/plan/001_d3bb02af4886/docs/research/P3P4/introspection-tools.md +0 -177
  457. package/plan/001_d3bb02af4886/docs/research/P3P4/reflection-patterns.md +0 -117
  458. package/plan/001_d3bb02af4886/docs/research/P4P5/RESEARCH_SUMMARY.md +0 -151
  459. package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_QUICK_REF.md +0 -376
  460. package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_RESEARCH.md +0 -1507
  461. package/plan/001_d3bb02af4886/docs/research/bugfix_typescript_patterns.md +0 -949
  462. package/plan/001_d3bb02af4886/docs/research/error-testing-research.md +0 -619
  463. package/plan/001_d3bb02af4886/docs/research/error_handling_patterns.md +0 -723
  464. package/plan/001_d3bb02af4886/docs/research/general/INTROSPECTION_RESEARCH_SUMMARY.md +0 -378
  465. package/plan/001_d3bb02af4886/docs/research/general/README-INTROSPECTION.md +0 -352
  466. package/plan/001_d3bb02af4886/docs/research/general/agent-introspection-patterns.md +0 -1085
  467. package/plan/001_d3bb02af4886/docs/research/general/introspection-security-guide.md +0 -984
  468. package/plan/001_d3bb02af4886/docs/research/general/introspection-tool-examples.md +0 -875
  469. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/PRP_TEMPLATE.md +0 -460
  470. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/QUICK_REFERENCE.md +0 -324
  471. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/README.md +0 -175
  472. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/RESEARCH_REPORT.md +0 -499
  473. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/SUMMARY.md +0 -163
  474. package/plan/001_d3bb02af4886/prd_snapshot.md +0 -543
  475. package/plan/bugfix/BUG_FIX_SUMMARY.md +0 -961
  476. package/scripts/generate-llms-full.ts +0 -206
  477. package/src/__tests__/adversarial/attachChild-performance.test.ts +0 -216
  478. package/src/__tests__/adversarial/circular-reference.test.ts +0 -101
  479. package/src/__tests__/adversarial/complex-circular-reference.test.ts +0 -139
  480. package/src/__tests__/adversarial/concurrent-task-failures.test.ts +0 -571
  481. package/src/__tests__/adversarial/deep-analysis.test.ts +0 -729
  482. package/src/__tests__/adversarial/deep-hierarchy-stress.test.ts +0 -213
  483. package/src/__tests__/adversarial/e2e-prd-validation.test.ts +0 -448
  484. package/src/__tests__/adversarial/edge-case.test.ts +0 -703
  485. package/src/__tests__/adversarial/error-merge-strategy.test.ts +0 -760
  486. package/src/__tests__/adversarial/incremental-performance.test.ts +0 -140
  487. package/src/__tests__/adversarial/node-map-update-benchmarks.test.ts +0 -457
  488. package/src/__tests__/adversarial/observer-propagation.test.ts +0 -487
  489. package/src/__tests__/adversarial/parent-validation.test.ts +0 -143
  490. package/src/__tests__/adversarial/prd-12-2-compliance.test.ts +0 -611
  491. package/src/__tests__/adversarial/prd-compliance.test.ts +0 -731
  492. package/src/__tests__/compatibility/backward-compatibility.test.ts +0 -1572
  493. package/src/__tests__/helpers/index.ts +0 -18
  494. package/src/__tests__/helpers/tree-verification.ts +0 -257
  495. package/src/__tests__/integration/agent-workflow.test.ts +0 -256
  496. package/src/__tests__/integration/bidirectional-consistency.test.ts +0 -847
  497. package/src/__tests__/integration/observer-logging.test.ts +0 -643
  498. package/src/__tests__/integration/tree-mirroring.test.ts +0 -151
  499. package/src/__tests__/integration/workflow-reparenting.test.ts +0 -303
  500. package/src/__tests__/unit/agent.test.ts +0 -169
  501. package/src/__tests__/unit/cache-key.test.ts +0 -182
  502. package/src/__tests__/unit/cache.test.ts +0 -172
  503. package/src/__tests__/unit/context.test.ts +0 -217
  504. package/src/__tests__/unit/decorators.test.ts +0 -100
  505. package/src/__tests__/unit/introspection-tools.test.ts +0 -277
  506. package/src/__tests__/unit/logger.test.ts +0 -293
  507. package/src/__tests__/unit/observable.test.ts +0 -321
  508. package/src/__tests__/unit/prompt.test.ts +0 -135
  509. package/src/__tests__/unit/reflection.test.ts +0 -210
  510. package/src/__tests__/unit/tree-debugger-incremental.test.ts +0 -170
  511. package/src/__tests__/unit/tree-debugger.test.ts +0 -85
  512. package/src/__tests__/unit/utils/workflow-error-utils.test.ts +0 -209
  513. package/src/__tests__/unit/workflow-detachChild.test.ts +0 -100
  514. package/src/__tests__/unit/workflow-emitEvent-childDetached.test.ts +0 -153
  515. package/src/__tests__/unit/workflow-isDescendantOf.test.ts +0 -180
  516. package/src/__tests__/unit/workflow.test.ts +0 -357
  517. package/src/cache/cache-key.ts +0 -244
  518. package/src/cache/cache.ts +0 -236
  519. package/src/core/agent.ts +0 -593
  520. package/src/core/event-tree.ts +0 -260
  521. package/src/core/logger.ts +0 -112
  522. package/src/core/mcp-handler.ts +0 -184
  523. package/src/core/prompt.ts +0 -150
  524. package/src/core/workflow-context.ts +0 -351
  525. package/src/core/workflow.ts +0 -540
  526. package/src/debugger/tree-debugger.ts +0 -255
  527. package/src/decorators/observed-state.ts +0 -95
  528. package/src/decorators/step.ts +0 -139
  529. package/src/decorators/task.ts +0 -159
  530. package/src/examples/tdd-orchestrator.ts +0 -65
  531. package/src/examples/test-cycle-workflow.ts +0 -64
  532. package/src/index.ts +0 -142
  533. package/src/reflection/reflection.ts +0 -407
  534. package/src/tools/index.ts +0 -36
  535. package/src/tools/introspection.ts +0 -464
  536. package/src/types/agent.ts +0 -90
  537. package/src/types/decorators.ts +0 -32
  538. package/src/types/error-strategy.ts +0 -13
  539. package/src/types/error.ts +0 -20
  540. package/src/types/events.ts +0 -75
  541. package/src/types/index.ts +0 -55
  542. package/src/types/logging.ts +0 -24
  543. package/src/types/observer.ts +0 -18
  544. package/src/types/prompt.ts +0 -40
  545. package/src/types/reflection.ts +0 -117
  546. package/src/types/sdk-primitives.ts +0 -128
  547. package/src/types/workflow-context.ts +0 -163
  548. package/src/types/workflow.ts +0 -37
  549. package/src/utils/id.ts +0 -11
  550. package/src/utils/index.ts +0 -4
  551. package/src/utils/observable.ts +0 -106
  552. package/src/utils/workflow-error-utils.ts +0 -56
  553. package/tsconfig.json +0 -22
  554. package/vitest.config.ts +0 -16
@@ -0,0 +1,676 @@
1
+ import { MCPHandler } from "../core/mcp-handler.js";
2
+ import { parseModelSpec } from "../utils/model-spec.js";
3
+ import { getGlobalHarnessConfig } from "../utils/harness-config.js";
4
+ import { AGENT_ERROR_CODES } from "../types/agent.js";
5
+ import { createSuccessResponse, createErrorResponse } from "../types/agent.js";
6
+ import { ConfigError } from "./claude-code-harness.js";
7
+ import { ModelRegistry, AuthStorage } from "@earendil-works/pi-coding-agent";
8
+ /**
9
+ * Pi harness implementation (PRD §7.1).
10
+ *
11
+ * Wraps `@earendil-works/pi-coding-agent` (the vendor-neutral default runtime). This file is the
12
+ * S2 implementation: it wires the SDK via lazy import in `initialize()`, builds a headless
13
+ * `ModelRegistry`, and provides `resolveModel()` to map `ModelSpec` → Pi `Model<Api>`.
14
+ * Tools/streaming/hooks/skills land in P2.M3/P2.M4.
15
+ *
16
+ * ## Capabilities (PRD §7.4 `pi` column — ALL supported)
17
+ * - **MCP**: via Groundswell `MCPHandler` (tools registered with the harness)
18
+ * - **Skills**: native agentskills.io
19
+ * - **LSP**: via MCP plugins through `MCPHandler`
20
+ * - **Streaming**: `session.subscribe` (`MessageUpdateEvent`)
21
+ * - **Sessions**: `SessionManager` (fork/switch/clone)
22
+ * - **Extended Thinking**: model-dependent
23
+ *
24
+ * Pi is vendor-neutral: it runs ANY LLM provider (PRD §7.4/§7.8), so `normalizeModel` applies NO
25
+ * provider constraint (unlike `ClaudeCodeHarness`).
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { PiHarness } from './harnesses/pi-harness.js';
30
+ * const harness = new PiHarness();
31
+ * await harness.initialize({ apiKey: 'sk-...' });
32
+ * const spec = harness.normalizeModel('anthropic/claude-sonnet-4');
33
+ * const model = harness.resolveModel(spec); // Model<Api>
34
+ * ```
35
+ */
36
+ export class PiHarness {
37
+ /** Harness identifier (PRD §7.2). */
38
+ id = "pi";
39
+ /** Capability flags — PRD §7.4 `pi` column (all true; vendor-neutral runtime). */
40
+ capabilities = {
41
+ mcp: true,
42
+ skills: true,
43
+ lsp: true,
44
+ streaming: true,
45
+ sessions: true,
46
+ extendedThinking: true,
47
+ };
48
+ // ── S2: SDK + registry state (all nullable for idempotent terminate) ───────────────────────
49
+ /** Lazily-imported Pi SDK module (mirrors ClaudeCodeHarness.sdk). Null until initialize(). */
50
+ sdk = null;
51
+ /** Headless auth store (env/runtime API-key resolution). Null until initialize(). */
52
+ authStorage = null;
53
+ /** Model registry (built-in + custom models; per-provider auth). Null until initialize(). */
54
+ modelRegistry = null;
55
+ /** Caller-supplied options (apiKey forwarded per-provider at resolveModel time). */
56
+ options = null;
57
+ /** MCP tool registry — mirrors ClaudeCodeHarness L177. */
58
+ mcpHandler = new MCPHandler();
59
+ /**
60
+ * Combined skills prompt (agentskills.io XML) from loadSkills(), injected into the session's system
61
+ * prompt during execute() via a DefaultResourceLoader.appendSystemPrompt (parity with
62
+ * ClaudeCodeHarness.skillsPrompt). Empty string when no skills are loaded (loadSkills not called, or
63
+ * called with []). When empty, execute() omits the resourceLoader → Pi builds its own default loader
64
+ * (current behavior preserved — no regression).
65
+ * @internal
66
+ */
67
+ skillsPrompt = "";
68
+ // ── S2: lifecycle ──────────────────────────────────────────────────────────────────────────
69
+ /**
70
+ * Initialize the Pi harness (PRD §7.3).
71
+ *
72
+ * Lazily `await import`s the Pi SDK, builds a headless `ModelRegistry.inMemory(...)`, and stores
73
+ * the caller's options. Does NOT call `createAgentSession` — that is T2 (P2.M2.T2.S1), which
74
+ * consumes `this.sdk`, `this.modelRegistry`, and `this.resolveModel(spec)`.
75
+ *
76
+ * Idempotent: a no-op if already initialized. API keys are resolved per-provider at
77
+ * `resolveModel` time (the provider is unknown until a model string is parsed — GOTCHA #8).
78
+ */
79
+ async initialize(options) {
80
+ // Idempotent guard (mirror ClaudeCodeHarness L233-235).
81
+ if (this.sdk)
82
+ return;
83
+ // Lazy SDK import (mirror ClaudeCodeHarness L237-248).
84
+ try {
85
+ this.sdk = await import("@earendil-works/pi-coding-agent");
86
+ }
87
+ catch (error) {
88
+ throw new Error(`Failed to load @earendil-works/pi-coding-agent: ${error instanceof Error ? error.message : "Unknown error"}`);
89
+ }
90
+ if (!this.sdk) {
91
+ throw new Error("Failed to load @earendil-works/pi-coding-agent: Import returned null");
92
+ }
93
+ // Headless registry: no disk (no agentDir/models.json/auth.json). Env-var key resolution
94
+ // is built into AuthStorage.getApiKey (GOTCHA #7).
95
+ this.authStorage = AuthStorage.inMemory();
96
+ this.modelRegistry = ModelRegistry.inMemory(this.authStorage);
97
+ // Store options; apiKey is applied per-provider in resolveModel (GOTCHA #8).
98
+ this.options = options ?? null;
99
+ }
100
+ /**
101
+ * Terminate the harness and release references (PRD §7.3).
102
+ *
103
+ * Idempotent. Nulls sdk/authStorage/modelRegistry/options to allow GC. The Pi SDK manages its
104
+ * own resources internally; no session exists at this layer (createAgentSession is T2).
105
+ */
106
+ async terminate() {
107
+ // Idempotent guard (mirror ClaudeCodeHarness L333-335).
108
+ if (this.sdk === null)
109
+ return;
110
+ this.sdk = null;
111
+ this.authStorage = null;
112
+ this.modelRegistry = null;
113
+ this.options = null;
114
+ }
115
+ // ── S2: ModelSpec → Model<Api> resolution (the "map to Model<any>" step) ───────────────────
116
+ /**
117
+ * Resolve a parsed {@link ModelSpec} to a Pi `Model<Api>` via the registry (PRD §7.8).
118
+ *
119
+ * Uses `modelRegistry.find(provider, model)` — the open-set, registry/auth-aware seam (NOT
120
+ * `getModel`, which is generic-constrained to known providers/models and not importable —
121
+ * research/model-resolution-path.md). T2 passes the result to `createAgentSession({ model })`.
122
+ *
123
+ * @throws {Error} if initialize() has not been called.
124
+ * @throws {ConfigError} (code CONFIG_ERROR) if the model is not in the registry.
125
+ */
126
+ resolveModel(spec) {
127
+ if (!this.modelRegistry || !this.authStorage) {
128
+ throw new Error("PiHarness not initialized. Call initialize() first.");
129
+ }
130
+ // Inject the caller's apiKey for THIS provider (provider unknown until parse time — GOTCHA #8).
131
+ if (this.options?.apiKey) {
132
+ this.authStorage.setRuntimeApiKey(spec.provider, this.options.apiKey);
133
+ }
134
+ const model = this.modelRegistry.find(spec.provider, spec.model);
135
+ if (!model) {
136
+ throw new ConfigError(`Model "${spec.provider}/${spec.model}" not found in the Pi model registry. ` +
137
+ `Ensure the provider/model id is correct and auth is configured ` +
138
+ `(env var, auth.json, or HarnessOptions.apiKey). (PRD §7.8)`, {
139
+ code: AGENT_ERROR_CODES.CONFIG_ERROR,
140
+ details: { provider: spec.provider, model: spec.model, harnessId: this.id },
141
+ });
142
+ }
143
+ return model;
144
+ }
145
+ /**
146
+ * Execute a prompt and return a structured AgentResponse (PRD §7.3, §7.11, §7.14.4).
147
+ *
148
+ * Creates a Pi AgentSession via createAgentSession, drives one prompt through session.prompt(),
149
+ * aggregates the terminal assistant text + token usage + tool-call count from the event stream
150
+ * (session.subscribe), fires session lifecycle hooks, and returns an AgentResponse<T>.
151
+ *
152
+ * Non-streaming path (P2.M2.T2.S1): returns Promise<AgentResponse<T>>.
153
+ * Streaming path: delegates to executeStreaming() (P2.M3.T2.S1) — returns AsyncGenerator<StreamEvent, AgentResponse<T>>.
154
+ * Tool delegation: customTools wired via buildCustomTools (P2.M3.T1).
155
+ * All hooks fire: session hooks inline (S1/P2.M2.T2.S1); tool/stream hooks via fireHookEvents() (P2.M3.T2.S2).
156
+ */
157
+ execute(request, toolExecutor, hooks) {
158
+ // STREAMING branch — P2.M3.T2.S1. Init guard BEFORE returning the generator (synchronous return).
159
+ // Mirror ClaudeCodeHarness L386-395: if (streaming) { guard; return this.executeStreaming(...); }
160
+ if (request.options.streaming) {
161
+ if (!this.sdk || !this.modelRegistry || !this.authStorage) {
162
+ throw new Error("PiHarness not initialized. Call initialize() first.");
163
+ }
164
+ return this.executeStreaming(request, toolExecutor, hooks);
165
+ }
166
+ // NON-STREAMING branch — IIFE returning Promise<AgentResponse<T>> (mirrors ClaudeCodeHarness).
167
+ return (async () => {
168
+ // Uninitialized guard (mirror ClaudeCodeHarness's `if (!this.sdk) throw …`).
169
+ if (!this.sdk || !this.modelRegistry || !this.authStorage) {
170
+ throw new Error("PiHarness not initialized. Call initialize() first.");
171
+ }
172
+ const startTime = Date.now(); // capture BEFORE createAgentSession (duration includes setup)
173
+ // Model resolution (S2's resolveModel; S1/S2's normalizeModel).
174
+ const modelSpec = this.normalizeModel(request.options.model ?? "claude-sonnet-4-20250514");
175
+ const model = this.resolveModel(modelSpec); // throws ConfigError if absent — let it propagate
176
+ // PiHarness creates a fresh AgentSession per execute() call, so loadSkills() state
177
+ // takes effect on the next execute() — no session rebuild is required.
178
+ const resourceLoader = await this.buildSkillsResourceLoader(request.options.systemPrompt);
179
+ // Create the Pi session. customTools: [] — Groundswell tools wired in P2.M3.T1.
180
+ const { session } = await this.sdk.createAgentSession({
181
+ model,
182
+ modelRegistry: this.modelRegistry,
183
+ authStorage: this.authStorage,
184
+ customTools: this.buildCustomTools(toolExecutor),
185
+ ...(resourceLoader ? { resourceLoader } : {}), // skills injection; omitted when no skills
186
+ });
187
+ // Aggregation closure — terminal assistant text + usage + tool-call count from events.
188
+ // Pi's prompt() resolves void; the answer is ONLY available via the event stream.
189
+ let lastAssistantText = "";
190
+ let totalInput = 0;
191
+ let totalOutput = 0;
192
+ let toolCallCount = 0;
193
+ // Hook dispatch context — mutable accumulators for fireHookEvents (P2.M3.T2.S2).
194
+ const hookCtx = {
195
+ toolStarts: new Map(),
196
+ streamText: { value: "" },
197
+ };
198
+ const listener = (event) => {
199
+ this.fireHookEvents(event, hooks, hookCtx); // P2.M3.T2.S2 — tool/stream hooks
200
+ // Structural cast — AgentMessage/AssistantMessage are NON-importable transitive types.
201
+ const e = event;
202
+ switch (e.type) {
203
+ case "session_start": // PRD §7.11 → onSessionStart
204
+ void hooks?.onSessionStart?.();
205
+ break;
206
+ case "session_shutdown": // PRD §7.11 → onSessionEnd(duration)
207
+ void hooks?.onSessionEnd?.(Date.now() - startTime);
208
+ break;
209
+ case "turn_end": {
210
+ const msg = e.message;
211
+ if (msg && msg.role === "assistant" && Array.isArray(msg.content)) {
212
+ // Text: last turn wins (final assistant message after all tool calls).
213
+ const text = msg.content
214
+ .filter((b) => b?.type === "text")
215
+ .map((b) => b.text ?? "")
216
+ .join("");
217
+ if (text)
218
+ lastAssistantText = text;
219
+ // Usage: accumulate across turns (input→input_tokens, output→output_tokens).
220
+ if (msg.usage) {
221
+ totalInput += msg.usage.input ?? 0;
222
+ totalOutput += msg.usage.output ?? 0;
223
+ }
224
+ // Tool calls: count toolCall blocks in this turn's message.
225
+ for (const b of msg.content) {
226
+ if (b?.type === "toolCall")
227
+ toolCallCount++;
228
+ }
229
+ }
230
+ break;
231
+ }
232
+ // agent_end is the terminal signal but turn_end already captured everything we need.
233
+ }
234
+ };
235
+ const unsubscribe = session.subscribe(listener);
236
+ try {
237
+ await session.prompt(request.prompt); // resolves when the turn/loop is processed; events already fired
238
+ }
239
+ catch (error) {
240
+ // EXECUTION_FAILED path (parity with ClaudeCodeHarness's createErrorResponse usage).
241
+ return createErrorResponse(AGENT_ERROR_CODES.EXECUTION_FAILED, `Pi agent execution failed: ${error instanceof Error ? error.message : String(error)}`, {
242
+ prompt: request.prompt,
243
+ model: modelSpec.raw,
244
+ ...(error instanceof Error && error.stack ? { stack: error.stack } : {}),
245
+ }, true);
246
+ }
247
+ finally {
248
+ unsubscribe(); // detach even on success to avoid leaks if the session is reused
249
+ }
250
+ const duration = Date.now() - startTime;
251
+ return createSuccessResponse(lastAssistantText, {
252
+ agentId: this.id,
253
+ timestamp: Date.now(),
254
+ duration,
255
+ usage: { input_tokens: totalInput, output_tokens: totalOutput },
256
+ toolCalls: toolCallCount,
257
+ });
258
+ })();
259
+ }
260
+ /**
261
+ * Stream a Pi turn as `StreamEvent`s (PRD §7.3, §7.4, §7.14.4).
262
+ *
263
+ * Pi's `session.subscribe(listener)` is SYNCHRONOUS — a listener cannot `yield`. This method
264
+ * bridges sync callbacks → async generator via an internal queue: the listener `enqueue`s events
265
+ * (and resolves a parked drain), the generator `dequeue`s/maps/`yield`s. `session.prompt()` runs
266
+ * detached; its resolution flips the terminal condition.
267
+ *
268
+ * Mapping (PRD §7.11): message_update→text_delta (snapshot-diff), tool_execution_start→tool_call_start,
269
+ * tool_execution_end→tool_call_done, turn_end→usage, terminal→done, errors→error.
270
+ *
271
+ * Hooks (Decision 5): session lifecycle hooks (onSessionStart/onSessionEnd) fire for parity with
272
+ * the non-streaming path. onToolStart/onToolEnd/onStream are P2.M3.T2.S2 (NOT wired here).
273
+ */
274
+ async *executeStreaming(request, toolExecutor, hooks) {
275
+ if (!this.sdk || !this.modelRegistry || !this.authStorage) {
276
+ throw new Error("PiHarness not initialized. Call initialize() first.");
277
+ }
278
+ const startTime = Date.now();
279
+ const modelSpec = this.normalizeModel(request.options.model ?? "claude-sonnet-4-20250514");
280
+ const model = this.resolveModel(modelSpec); // throws ConfigError if absent — let it propagate
281
+ // PiHarness creates a fresh AgentSession per execute() call, so loadSkills() state
282
+ // takes effect on the next execute() — no session rebuild is required.
283
+ const resourceLoader = await this.buildSkillsResourceLoader(request.options.systemPrompt);
284
+ // REUSE P2.M3.T1.S1's customTools seam (Decision 1) — do NOT pass customTools: [].
285
+ const { session } = await this.sdk.createAgentSession({
286
+ model,
287
+ modelRegistry: this.modelRegistry,
288
+ authStorage: this.authStorage,
289
+ customTools: this.buildCustomTools(toolExecutor),
290
+ ...(resourceLoader ? { resourceLoader } : {}), // skills injection; omitted when no skills
291
+ });
292
+ // Yield metadata FIRST (mirror ClaudeCodeHarness L696-701).
293
+ yield {
294
+ type: "metadata",
295
+ metadata: {
296
+ requestId: `${this.id}-${Date.now()}`,
297
+ model: modelSpec.model,
298
+ provider: modelSpec.provider,
299
+ },
300
+ };
301
+ // ── Async-queue bridge (Decision 3) ─────────────────────────────────────────────
302
+ const queue = [];
303
+ let resolveNext = null;
304
+ let turnDone = false;
305
+ const enqueue = (e) => {
306
+ queue.push(e);
307
+ resolveNext?.();
308
+ resolveNext = null;
309
+ };
310
+ // Aggregation state (mirrors the non-streaming listener).
311
+ let fullText = "";
312
+ let textIndex = 0;
313
+ let toolIndex = 0;
314
+ let lastInput = 0;
315
+ let lastOutput = 0;
316
+ let lastCache;
317
+ // Hook dispatch context — mutable accumulators for fireHookEvents (P2.M3.T2.S2).
318
+ const hookCtx = {
319
+ toolStarts: new Map(),
320
+ streamText: { value: "" },
321
+ };
322
+ const listener = (event) => {
323
+ const e = event;
324
+ // Session lifecycle hooks — parity with non-streaming (Decision 5).
325
+ switch (e.type) {
326
+ case "session_start":
327
+ void hooks?.onSessionStart?.();
328
+ break;
329
+ case "session_shutdown":
330
+ void hooks?.onSessionEnd?.(Date.now() - startTime);
331
+ break;
332
+ }
333
+ this.fireHookEvents(event, hooks, hookCtx); // P2.M3.T2.S2 — BEFORE enqueue → ordering (PRD §7.14.3)
334
+ enqueue(event); // every event flows through the bridge for mapping
335
+ };
336
+ const unsubscribe = session.subscribe(listener);
337
+ // Kick off prompt() WITHOUT awaiting in the generator body (Decision 3). Capture rejection.
338
+ let promptError = null;
339
+ void session
340
+ .prompt(request.prompt)
341
+ .catch((err) => {
342
+ promptError = err;
343
+ })
344
+ .finally(() => {
345
+ turnDone = true;
346
+ resolveNext?.();
347
+ resolveNext = null;
348
+ });
349
+ try {
350
+ // ── Drain loop: map Pi events → StreamEvent ──────────────────────────────────
351
+ while (!turnDone || queue.length > 0) {
352
+ if (queue.length === 0) {
353
+ await new Promise((r) => {
354
+ resolveNext = r;
355
+ });
356
+ }
357
+ while (queue.length > 0) {
358
+ const event = queue.shift();
359
+ const e = event;
360
+ switch (e.type) {
361
+ case "message_update": {
362
+ // Snapshot-diff (Decision 2) — assistant text only.
363
+ if (e.message?.role === "assistant" && Array.isArray(e.message.content)) {
364
+ const text = e.message.content
365
+ .filter((b) => b?.type === "text")
366
+ .map((b) => b.text ?? "")
367
+ .join("");
368
+ if (text.length > fullText.length && text.startsWith(fullText)) {
369
+ yield {
370
+ type: "text_delta",
371
+ delta: text.slice(fullText.length),
372
+ index: textIndex++,
373
+ };
374
+ fullText = text;
375
+ }
376
+ else if (text.length > fullText.length) {
377
+ // Non-prefix growth (rare replays) — emit the whole new tail.
378
+ yield { type: "text_delta", delta: text.slice(fullText.length), index: textIndex++ };
379
+ fullText = text;
380
+ }
381
+ }
382
+ break;
383
+ }
384
+ case "tool_execution_start":
385
+ yield {
386
+ type: "tool_call_start",
387
+ id: String(e.toolCallId ?? ""),
388
+ name: String(e.toolName ?? ""),
389
+ index: toolIndex++,
390
+ };
391
+ break;
392
+ case "tool_execution_end":
393
+ yield {
394
+ type: "tool_call_done",
395
+ id: String(e.toolCallId ?? ""),
396
+ result: e.result ?? null,
397
+ };
398
+ break;
399
+ case "turn_end": {
400
+ const msg = e.message;
401
+ if (msg && msg.role === "assistant" && msg.usage) {
402
+ lastInput = msg.usage.input ?? 0;
403
+ lastOutput = msg.usage.output ?? 0;
404
+ lastCache = msg.usage.cacheRead ?? msg.usage.cacheWrite; // mirror ClaudeCodeHarness L843-845
405
+ }
406
+ break;
407
+ }
408
+ // session_start/session_shutdown/agent_end/turn_start/etc. handled by hooks or ignored.
409
+ }
410
+ }
411
+ }
412
+ // ── Terminal ─────────────────────────────────────────────────────────────────
413
+ if (promptError) {
414
+ const message = promptError instanceof Error ? promptError.message : String(promptError);
415
+ yield {
416
+ type: "error",
417
+ error: new Error(`Pi agent execution failed: ${message}`),
418
+ code: AGENT_ERROR_CODES.EXECUTION_FAILED,
419
+ retryable: true,
420
+ };
421
+ return createErrorResponse(AGENT_ERROR_CODES.EXECUTION_FAILED, `Pi agent execution failed: ${message}`, {
422
+ prompt: request.prompt,
423
+ model: modelSpec.raw,
424
+ ...(promptError instanceof Error && promptError.stack ? { stack: promptError.stack } : {}),
425
+ }, true);
426
+ }
427
+ // Usage (one event — final turn wins; GOTCHA #9).
428
+ if (lastInput || lastOutput) {
429
+ const usageEvent = {
430
+ type: "usage",
431
+ inputTokens: lastInput,
432
+ outputTokens: lastOutput,
433
+ };
434
+ if (lastCache !== undefined)
435
+ usageEvent.cacheTokens = lastCache;
436
+ yield usageEvent;
437
+ }
438
+ yield { type: "done", finishReason: "stop" };
439
+ return createSuccessResponse(fullText, {
440
+ agentId: this.id,
441
+ timestamp: Date.now(),
442
+ duration: Date.now() - startTime,
443
+ usage: { input_tokens: lastInput, output_tokens: lastOutput },
444
+ });
445
+ }
446
+ finally {
447
+ unsubscribe(); // detach even on early break / abort (GOTCHA #16)
448
+ }
449
+ }
450
+ /**
451
+ * Dispatch the three harness hooks owned by P2.M3.T2.S2 (PRD §7.11):
452
+ * tool_execution_start → onToolStart({name, input})
453
+ * tool_execution_end → onToolEnd({name, input}, {content, isError}, duration)
454
+ * message_update → onStream(delta) [snapshot-diff; assistant text only]
455
+ *
456
+ * Session hooks (onSessionStart/onSessionEnd) are NOT handled here — they stay inline in the
457
+ * listeners as S1/P2.M2.T2.S1 wrote them (no scope overlap, no merge conflict).
458
+ *
459
+ * Pi fidelity advantage over claude-code (item note): onToolEnd observes the REAL isError
460
+ * (ToolExecutionEndEvent.isError) and a REAL duration (computed from the stashed start timestamp);
461
+ * claude-code's PostToolUse cannot (always isError:false, duration:0).
462
+ *
463
+ * Hooks are FIRE-AND-TRACK (`void`): the Pi listener runs SYNCHRONOUSLY during session.prompt()
464
+ * and cannot `await` a hook Promise (would block/reorder the SDK event loop). Matches the existing
465
+ * `void hooks?.onSessionStart?.()` pattern. Tests use sync vi.fn() hooks for deterministic assertions.
466
+ *
467
+ * @param event Pi session event (structurally cast — transitive types are non-importable).
468
+ * @param hooks Optional HarnessHookEvents. Early-returns on `!hooks` (cheap no-op).
469
+ * @param ctx Mutable accumulators (toolStarts for duration/input reconstruction; streamText for onStream).
470
+ */
471
+ fireHookEvents(event, hooks, ctx) {
472
+ if (!hooks)
473
+ return; // no hooks → cheap no-op
474
+ const e = event;
475
+ switch (e.type) {
476
+ case "tool_execution_start": {
477
+ const req = { name: e.toolName ?? "", input: e.args };
478
+ if (e.toolCallId) {
479
+ ctx.toolStarts.set(e.toolCallId, {
480
+ name: req.name,
481
+ input: req.input,
482
+ timestamp: Date.now(), // tool events carry NO timestamp; we record it
483
+ });
484
+ }
485
+ void hooks.onToolStart?.(req); // fire-and-track
486
+ break;
487
+ }
488
+ case "tool_execution_end": {
489
+ const id = e.toolCallId ?? "";
490
+ const start = ctx.toolStarts.get(id);
491
+ const duration = start ? Date.now() - start.timestamp : 0;
492
+ // Reconstruct the request from the STASHED start info (end event lacks args).
493
+ const req = start
494
+ ? { name: start.name, input: start.input }
495
+ : { name: e.toolName ?? "", input: undefined }; // graceful degradation
496
+ const result = {
497
+ content: e.result ?? null,
498
+ isError: e.isError ?? false, // REAL isError (Pi > claude-code)
499
+ };
500
+ if (id)
501
+ ctx.toolStarts.delete(id); // defend against duplicate end events
502
+ void hooks.onToolEnd?.(req, result, duration); // fire-and-track
503
+ break;
504
+ }
505
+ case "message_update": {
506
+ // onStream snapshot-diff; INDEPENDENT accumulator (ctx.streamText) decoupled
507
+ // from the drain loop's `fullText` so S2 never edits the drain loop. Both produce identical
508
+ // deltas for the same chunk (same algorithm, same event).
509
+ const msg = e.message;
510
+ if (msg?.role === "assistant" && Array.isArray(msg.content)) {
511
+ const text = msg.content
512
+ .filter((b) => b?.type === "text")
513
+ .map((b) => b.text ?? "")
514
+ .join("");
515
+ if (text.length > ctx.streamText.value.length) {
516
+ const delta = text.slice(ctx.streamText.value.length);
517
+ void hooks.onStream?.(delta);
518
+ ctx.streamText.value = text;
519
+ }
520
+ }
521
+ break;
522
+ }
523
+ // session_start/session_shutdown handled inline in the listeners (NOT here — scope boundary).
524
+ // tool_execution_update/turn_end/etc. — no hook mapping (PRD §7.11 table).
525
+ }
526
+ }
527
+ async registerMCPs(servers) {
528
+ if (!this.sdk) {
529
+ throw new Error("PiHarness not initialized. Call initialize() first.");
530
+ }
531
+ for (const server of servers) {
532
+ this.mcpHandler.registerServer(server);
533
+ }
534
+ return this.mcpHandler.getTools();
535
+ }
536
+ /**
537
+ * Build Pi `ToolDefinition[]` from the registered MCPHandler tools (PRD §7.10, §7.12, §7.14.1).
538
+ *
539
+ * Delegates to `MCPHandler.toPiCustomTools()` (P2.M4.T1.S2) which produces schema-faithful
540
+ * ToolDefinitions with REAL TypeBox `parameters` (converted via `jsonSchemaToTypebox`) and
541
+ * `execute` delegating to `registered.executor` (Claude parity).
542
+ *
543
+ * When `toolExecutor` is provided (PRD §7.10 bridge), forwards it to `toPiCustomTools` so
544
+ * each tool's `execute` dispatches through the caller-supplied executor instead of the
545
+ * harness's internal `registered.executor`.
546
+ */
547
+ buildCustomTools(toolExecutor) {
548
+ return this.mcpHandler.toPiCustomTools(toolExecutor);
549
+ }
550
+ /**
551
+ * Load skills via Pi's NATIVE agentskills.io implementation (PRD §7.12, §7.14.2).
552
+ *
553
+ * For each Groundswell {@link Skill} ({name, path}), calls Pi's `loadSkillsFromDir({dir: path,
554
+ * source: name})` (which reads SKILL.md from the dir), collects all returned Pi Skills, then formats
555
+ * them to agentskills.io XML via `formatSkillsForPrompt` and stores the result in {@link skillsPrompt}.
556
+ *
557
+ * ## No session re-init required
558
+ * PiHarness creates a FRESH AgentSession per execute()/executeStreaming() call (P2.M2.T2.S1 /
559
+ * P2.M3.T2.S1), so this stored skillsPrompt is consumed on the NEXT execute() when
560
+ * buildSkillsResourceLoader() builds the DefaultResourceLoader. This mirrors how registerMCPs()
561
+ * state is consumed when execute() builds customTools. (A long-lived-session model would need an
562
+ * explicit rebuild; not the case here.)
563
+ *
564
+ * ## Parity with ClaudeCodeHarness
565
+ * ClaudeCodeHarness reads each SKILL.md and joins with markdown; PiHarness uses Pi's native loaders
566
+ * and emits the agentskills.io XML format. Both store the result in a `skillsPrompt` field and inject
567
+ * at BOTH execute sites. EFFECT is identical: the skill's SKILL.md content reaches the model's system
568
+ * prompt.
569
+ *
570
+ * @param skills - Groundswell portable Skill list ({name, path}). path = dir containing SKILL.md.
571
+ * @throws {Error} /not initialized/i if initialize() has not been called.
572
+ * @throws {Error} "Failed to load skill '<name>' from <path>: <msg>" if loadSkillsFromDir throws.
573
+ */
574
+ async loadSkills(skills) {
575
+ // Init guard (mirror registerMCPs / ClaudeCodeHarness.loadSkills).
576
+ if (!this.sdk) {
577
+ throw new Error("PiHarness not initialized. Call initialize() first.");
578
+ }
579
+ // Empty → clear (mirror ClaudeCodeHarness; also ensures a prior loadSkills doesn't linger).
580
+ if (skills.length === 0) {
581
+ this.skillsPrompt = "";
582
+ return;
583
+ }
584
+ // NATIVE agentskills.io loading: map each Groundswell Skill {name,path} → Pi loadSkillsFromDir.
585
+ // Collect ALL Pi Skills, then format to ONE agentskills.io XML string.
586
+ const collected = [];
587
+ for (const skill of skills) {
588
+ try {
589
+ // loadSkillsFromDir is SYNC; reads SKILL.md from `dir` (skill root / .md children / recurse).
590
+ // `source` is the SourceInfo identifier (use the Groundswell skill name).
591
+ const result = this.sdk.loadSkillsFromDir({
592
+ dir: skill.path,
593
+ source: skill.name,
594
+ });
595
+ collected.push(...result.skills);
596
+ }
597
+ catch (error) {
598
+ // Wrap with context (mirror ClaudeCodeHarness L983-988 error wrapping).
599
+ throw new Error(`Failed to load skill '${skill.name}' from ${skill.path}: ` +
600
+ `${error instanceof Error ? error.message : "Unknown error"}`);
601
+ }
602
+ }
603
+ // formatSkillsForPrompt → agentskills.io XML; EXCLUDES disableModelInvocation:true (Pi filters).
604
+ this.skillsPrompt = this.sdk.formatSkillsForPrompt(collected);
605
+ }
606
+ /**
607
+ * Build a DefaultResourceLoader that appends the loaded skills ({@link skillsPrompt}) to the
608
+ * session's system prompt (PRD §7.12, §7.14.2).
609
+ *
610
+ * Returns `undefined` when no skills are loaded (`skillsPrompt === ""`), so execute() OMITS the
611
+ * `resourceLoader` option and Pi builds its own default loader — current behavior is preserved
612
+ * (zero regression in the execute/streaming suites).
613
+ *
614
+ * ## Parity: noSkills: true
615
+ * Suppresses Pi's DEFAULT skill discovery (~/.pi/agent/skills, cwd-local) so the session's skills are
616
+ * EXACTLY Groundswell's portable Skill[] (parity with ClaudeCodeHarness, which builds its prompt only
617
+ * from the passed skills). `appendSystemPrompt` is INDEPENDENT of `noSkills`, so our pre-formatted
618
+ * agentskills.io XML is still appended to the system prompt.
619
+ *
620
+ * createAgentSession uses a caller-provided loader AS-IS (no reload), so we `await loader.reload()`.
621
+ *
622
+ * @returns A configured DefaultResourceLoader, or undefined when no skills are loaded.
623
+ * @throws {Error} /not initialized/i if called before initialize() (defensive — execute() guards too).
624
+ */
625
+ async buildSkillsResourceLoader(systemPrompt) {
626
+ if (!this.sdk) {
627
+ throw new Error("PiHarness not initialized. Call initialize() first.");
628
+ }
629
+ // Forward BOTH the harness system prompt (the agent persona, e.g.
630
+ // TASK_BREAKDOWN_PROMPT) AND the loaded skills to Pi via appendSystemPrompt.
631
+ // Without this, HarnessRequest.options.systemPrompt is silently dropped —
632
+ // createAgentSession never receives it — so every agent runs under Pi's
633
+ // generic coding persona (e.g. the architect implements the PRD directly
634
+ // instead of decomposing it into tasks.json).
635
+ const appendParts = [];
636
+ if (systemPrompt)
637
+ appendParts.push(systemPrompt);
638
+ if (this.skillsPrompt)
639
+ appendParts.push(this.skillsPrompt);
640
+ if (appendParts.length === 0)
641
+ return undefined; // nothing to inject → let Pi use its default loader
642
+ // cwd/agentDir are REQUIRED by DefaultResourceLoaderOptions. agentDir = Pi's default (~/.pi/agent).
643
+ const loader = new this.sdk.DefaultResourceLoader({
644
+ cwd: process.cwd(),
645
+ agentDir: this.sdk.getAgentDir(),
646
+ appendSystemPrompt: appendParts, // persona + agentskills.io XML appended to the system prompt
647
+ noSkills: true, // parity: don't ALSO load Pi's default skills
648
+ });
649
+ await loader.reload(); // createAgentSession will NOT reload a caller-provided loader
650
+ return loader;
651
+ }
652
+ /**
653
+ * Parse a model string into a ModelSpec (PRD §7.8).
654
+ *
655
+ * Pi is vendor-neutral — ANY provider is valid (PRD §7.4 "LLM providers: any"). Unlike
656
+ * `ClaudeCodeHarness`, there is NO anthropic-only constraint here. Delegates to `parseModelSpec`
657
+ * (open `ModelProviderId` set; rejects harness-qualified 3-segment strings per PRD §7.8).
658
+ *
659
+ * Threads the global `defaultModelProvider` when configured (backward-compatible — when unset,
660
+ * `defaultModelProvider` is `undefined`, so `parseModelSpec` defaults to `'anthropic'` exactly
661
+ * as S1 does).
662
+ *
663
+ * This is the string→ModelSpec layer. `resolveModel()` owns the ModelSpec→Pi `Model<Api>` step.
664
+ */
665
+ normalizeModel(model) {
666
+ const defaultProvider = getGlobalHarnessConfig().defaultModelProvider;
667
+ return parseModelSpec(model, defaultProvider);
668
+ }
669
+ supports(capability) {
670
+ return this.capabilities[capability];
671
+ }
672
+ requiresFeatures(features) {
673
+ return features.every((f) => this.capabilities[f]);
674
+ }
675
+ }
676
+ //# sourceMappingURL=pi-harness.js.map