ultimate-pi 0.18.0 → 0.19.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 (314) hide show
  1. package/.agents/skills/harness-debate-plan/SKILL.md +1 -1
  2. package/.agents/skills/harness-decisions/SKILL.md +2 -3
  3. package/.agents/skills/harness-governor/SKILL.md +6 -5
  4. package/.agents/skills/harness-orchestration/SKILL.md +4 -4
  5. package/.agents/skills/harness-review/SKILL.md +7 -7
  6. package/.agents/skills/harness-sentrux-setup/SKILL.md +4 -3
  7. package/.agents/skills/harness-steer/SKILL.md +1 -1
  8. package/.agents/skills/sentrux/SKILL.md +9 -9
  9. package/.pi/PACKAGING.md +4 -4
  10. package/.pi/SYSTEM.md +54 -120
  11. package/.pi/agents/harness/incident-recorder.md +0 -1
  12. package/.pi/agents/harness/planning/decompose.md +1 -3
  13. package/.pi/agents/harness/planning/execution-plan-author.md +0 -2
  14. package/.pi/agents/harness/planning/hypothesis-validator.md +0 -2
  15. package/.pi/agents/harness/planning/hypothesis.md +0 -2
  16. package/.pi/agents/harness/planning/implementation-researcher.md +0 -2
  17. package/.pi/agents/harness/planning/plan-adversary.md +0 -2
  18. package/.pi/agents/harness/planning/plan-evaluator.md +1 -3
  19. package/.pi/agents/harness/planning/planning-context.md +0 -2
  20. package/.pi/agents/harness/planning/review-integrator.md +0 -2
  21. package/.pi/agents/harness/planning/sprint-contract-auditor.md +0 -2
  22. package/.pi/agents/harness/planning/stack-researcher.md +0 -2
  23. package/.pi/agents/harness/{adversary.md → reviewing/adversary.md} +0 -2
  24. package/.pi/agents/harness/{evaluator.md → reviewing/evaluator.md} +0 -2
  25. package/.pi/agents/harness/{tie-breaker.md → reviewing/tie-breaker.md} +0 -2
  26. package/.pi/agents/harness/{executor.md → running/executor.md} +0 -2
  27. package/.pi/agents/harness/sentrux-bootstrap.md +0 -1
  28. package/.pi/agents/harness/sentrux-steward.md +0 -2
  29. package/.pi/agents/harness/trace-librarian.md +0 -1
  30. package/.pi/extensions/00-harness-project-control.ts +133 -0
  31. package/.pi/extensions/00-posthog-network-bootstrap.ts +1 -1
  32. package/.pi/extensions/agt-kill-switch.ts +57 -0
  33. package/.pi/extensions/agt-prompt-guard.ts +32 -0
  34. package/.pi/extensions/budget-guard.ts +2 -0
  35. package/.pi/extensions/custom-footer.ts +46 -145
  36. package/.pi/extensions/custom-header.ts +1 -1
  37. package/.pi/extensions/custom-system-prompt.ts +1 -1
  38. package/.pi/extensions/debate-orchestrator.ts +7 -5
  39. package/.pi/extensions/harness-ask-user.ts +8 -8
  40. package/.pi/extensions/harness-debate-tools.ts +27 -43
  41. package/.pi/extensions/harness-lens.ts +94 -0
  42. package/.pi/extensions/harness-live-widget.ts +33 -2
  43. package/.pi/extensions/harness-plan-approval.ts +12 -12
  44. package/.pi/extensions/harness-run-context.ts +1214 -852
  45. package/.pi/extensions/harness-subagent-governance.ts +8 -0
  46. package/.pi/extensions/harness-subagent-submit.ts +36 -164
  47. package/.pi/extensions/harness-subagents.ts +4 -4
  48. package/.pi/extensions/harness-telemetry.ts +3 -1
  49. package/.pi/extensions/harness-web-tools.ts +3 -3
  50. package/.pi/extensions/observation-bus.ts +2 -0
  51. package/.pi/extensions/policy-gate.ts +27 -5
  52. package/.pi/extensions/review-integrity.ts +91 -10
  53. package/.pi/extensions/sentrux-rules-sync.ts +3 -1
  54. package/.pi/extensions/subagent-governance.ts +92 -0
  55. package/.pi/extensions/test-diff-integrity.ts +1 -0
  56. package/.pi/extensions/trace-recorder.ts +3 -1
  57. package/.pi/extensions/{ultimate-pi-vcc.ts → vcc-compaction.ts} +1 -1
  58. package/.pi/harness/README.md +6 -2
  59. package/.pi/harness/agents.manifest.json +38 -49
  60. package/.pi/harness/agents.policy.yaml +275 -0
  61. package/.pi/harness/corpus/graphify-kb-updater.config.json +55 -0
  62. package/.pi/harness/docs/adrs/0006-sentrux-dual-layer.md +2 -1
  63. package/.pi/harness/docs/adrs/0030-inhouse-vcc-compaction.md +1 -1
  64. package/.pi/harness/docs/adrs/0035-plan-phase-review-gate.md +1 -1
  65. package/.pi/harness/docs/adrs/0044-harness-steer-loop.md +3 -2
  66. package/.pi/harness/docs/adrs/0045-harness-lens-minimal-contract.md +49 -0
  67. package/.pi/harness/docs/adrs/0045-phase-scoped-agent-directories.md +33 -0
  68. package/.pi/harness/docs/adrs/0046-agt-policy-engine.md +51 -0
  69. package/.pi/harness/docs/adrs/0047-agt-layered-security.md +39 -0
  70. package/.pi/harness/docs/adrs/0048-tool-call-hook-order.md +25 -0
  71. package/.pi/harness/docs/adrs/0049-agents-policy-manifest.md +36 -0
  72. package/.pi/harness/docs/adrs/README.md +6 -0
  73. package/.pi/harness/docs/graphify-kb-updater-runbook.md +11 -5
  74. package/.pi/harness/docs/practice-map.md +2 -2
  75. package/.pi/harness/evolution/README.md +1 -2
  76. package/.pi/harness/examples/agents.policy.project.yaml +19 -0
  77. package/.pi/harness/examples/policies/custom-deny-bash.yaml +9 -0
  78. package/.pi/harness/policies/bash-denylists.yaml +5 -0
  79. package/.pi/harness/policies/defaults.yaml +51 -0
  80. package/.pi/harness/policies/orchestrator.yaml +18 -0
  81. package/.pi/harness/policies/phases.yaml +10 -0
  82. package/.pi/harness/policies/roles.yaml +5 -0
  83. package/.pi/harness/policies/web-guard.yaml +5 -0
  84. package/.pi/harness/policies/workflow-sequences.yaml +9 -0
  85. package/.pi/harness/sentrux/architecture.manifest.json +26 -4
  86. package/.pi/harness/specs/harness-spawn-context.schema.json +1 -1
  87. package/.pi/harness/specs/observation.schema.json +2 -1
  88. package/.pi/lib/agents-policy.d.mts +70 -0
  89. package/.pi/lib/agents-policy.mjs +325 -0
  90. package/.pi/lib/agents-policy.ts +19 -0
  91. package/.pi/lib/agt/audit-run-sink.ts +52 -0
  92. package/.pi/lib/agt/build-evaluation-context.ts +285 -0
  93. package/.pi/lib/agt/config.ts +28 -0
  94. package/.pi/lib/agt/delegation.ts +69 -0
  95. package/.pi/lib/agt/evaluate-policy.ts +56 -0
  96. package/.pi/lib/agt/identity-registry.ts +41 -0
  97. package/.pi/lib/agt/index.ts +55 -0
  98. package/.pi/lib/agt/kill-switch-state.ts +11 -0
  99. package/.pi/lib/agt/legacy-evaluate.ts +101 -0
  100. package/.pi/lib/agt/policy-engine.ts +154 -0
  101. package/.pi/lib/agt/rings.ts +21 -0
  102. package/.pi/lib/agt/sre-hooks.ts +45 -0
  103. package/.pi/lib/agt/trust-run-store.ts +26 -0
  104. package/.pi/lib/agt/workflow-history.ts +29 -0
  105. package/.pi/lib/agt-governance-active.ts +14 -0
  106. package/.pi/lib/agt-tool-guard.ts +78 -0
  107. package/.pi/lib/ask-user/dialog.ts +314 -0
  108. package/.pi/{extensions/lib → lib}/debate-bus-core.ts +10 -10
  109. package/.pi/{extensions/lib → lib}/debate-bus-state.ts +1 -1
  110. package/.pi/{extensions/lib → lib}/extension-load-guard.ts +21 -0
  111. package/.pi/lib/harness-agt-tool-guard.ts +5 -0
  112. package/.pi/{extensions/lib → lib}/harness-artifact-gate.ts +6 -16
  113. package/.pi/lib/harness-debate-core-deps.ts +14 -0
  114. package/.pi/lib/harness-debate-workflow-deps.ts +43 -0
  115. package/.pi/lib/harness-lens/.gitattributes +1 -0
  116. package/.pi/lib/harness-lens/clients/edit-autopatch.ts +88 -0
  117. package/.pi/lib/harness-lens/clients/file-kinds.ts +380 -0
  118. package/.pi/lib/harness-lens/clients/file-time.ts +215 -0
  119. package/.pi/lib/harness-lens/clients/file-utils.ts +484 -0
  120. package/.pi/lib/harness-lens/clients/format-service.ts +276 -0
  121. package/.pi/lib/harness-lens/clients/formatters.ts +1000 -0
  122. package/.pi/lib/harness-lens/clients/git-guard.ts +31 -0
  123. package/.pi/lib/harness-lens/clients/indent-retarget.ts +90 -0
  124. package/.pi/lib/harness-lens/clients/installer/index.ts +2368 -0
  125. package/.pi/lib/harness-lens/clients/latency-logger.ts +80 -0
  126. package/.pi/lib/harness-lens/clients/lens-config.ts +43 -0
  127. package/.pi/lib/harness-lens/clients/lens-events.ts +164 -0
  128. package/.pi/lib/harness-lens/clients/lsp/aggregation.ts +91 -0
  129. package/.pi/lib/harness-lens/clients/lsp/client.ts +1466 -0
  130. package/.pi/lib/harness-lens/clients/lsp/config.ts +216 -0
  131. package/.pi/lib/harness-lens/clients/lsp/edits.ts +297 -0
  132. package/.pi/lib/harness-lens/clients/lsp/index.ts +1355 -0
  133. package/.pi/lib/harness-lens/clients/lsp/interactive-install.ts +424 -0
  134. package/.pi/lib/harness-lens/clients/lsp/language.ts +223 -0
  135. package/.pi/lib/harness-lens/clients/lsp/launch.ts +939 -0
  136. package/.pi/lib/harness-lens/clients/lsp/lsp-index.ts +11 -0
  137. package/.pi/lib/harness-lens/clients/lsp/path-utils.ts +12 -0
  138. package/.pi/lib/harness-lens/clients/lsp/server-strategies.ts +81 -0
  139. package/.pi/lib/harness-lens/clients/lsp/server.ts +1971 -0
  140. package/.pi/lib/harness-lens/clients/path-utils.ts +182 -0
  141. package/.pi/lib/harness-lens/clients/pipeline.ts +360 -0
  142. package/.pi/lib/harness-lens/clients/project-profile.ts +117 -0
  143. package/.pi/lib/harness-lens/clients/runtime-agent-end.ts +112 -0
  144. package/.pi/lib/harness-lens/clients/runtime-config.ts +33 -0
  145. package/.pi/lib/harness-lens/clients/runtime-coordinator.ts +186 -0
  146. package/.pi/lib/harness-lens/clients/runtime-tool-result.ts +171 -0
  147. package/.pi/lib/harness-lens/clients/safe-spawn.ts +339 -0
  148. package/.pi/lib/harness-lens/clients/secrets-scanner.ts +214 -0
  149. package/.pi/lib/harness-lens/clients/tool-policy.ts +2072 -0
  150. package/.pi/lib/harness-lens/clients/types.ts +59 -0
  151. package/.pi/lib/harness-lens/clients/widget-state.ts +283 -0
  152. package/.pi/lib/harness-lens/index.ts +532 -0
  153. package/.pi/lib/harness-lens/tools/lsp-diagnostics.ts +706 -0
  154. package/.pi/lib/harness-lens/tools/lsp-navigation.ts +1246 -0
  155. package/.pi/{extensions/lib → lib}/harness-posthog.ts +3 -0
  156. package/.pi/lib/harness-project-config.ts +91 -0
  157. package/.pi/lib/harness-run-context-responses.ts +9 -0
  158. package/.pi/lib/harness-run-context.ts +1 -3
  159. package/.pi/{extensions/lib/spawn-policy.ts → lib/harness-spawn-policy.ts} +4 -3
  160. package/.pi/{extensions/lib → lib}/harness-spawn-topology.ts +5 -28
  161. package/.pi/lib/harness-subagent-auth.ts +51 -0
  162. package/.pi/{extensions/lib → lib}/harness-subagent-precheck.ts +13 -10
  163. package/.pi/{extensions/lib → lib}/harness-subagent-submit-pipeline.ts +3 -3
  164. package/.pi/lib/harness-subagent-submit-register.ts +163 -0
  165. package/.pi/{extensions/lib → lib}/harness-subagent-submit-registry.ts +1 -55
  166. package/.pi/{extensions/lib → lib}/harness-subagents-bridge.ts +53 -14
  167. package/.pi/{extensions/lib → lib}/harness-subprocess-bootstrap.ts +1 -1
  168. package/.pi/lib/harness-ui-state.ts +27 -12
  169. package/.pi/{extensions/lib → lib}/plan-approval/create-plan.ts +2 -2
  170. package/.pi/{extensions/lib → lib}/plan-approval/format-plan.ts +2 -2
  171. package/.pi/{extensions/lib → lib}/plan-approval/plan-review.ts +162 -201
  172. package/.pi/{extensions/lib → lib}/plan-approval/render.ts +1 -1
  173. package/.pi/{extensions/lib → lib}/plan-approval/resolve-disk.ts +2 -2
  174. package/.pi/{extensions/lib → lib}/plan-approval/types.ts +1 -1
  175. package/.pi/{extensions/lib → lib}/plan-approval/validate.ts +3 -3
  176. package/.pi/{extensions/lib → lib}/plan-approval-readiness.ts +3 -52
  177. package/.pi/{extensions/lib → lib}/plan-debate-envelope.ts +1 -1
  178. package/.pi/{extensions/lib → lib}/plan-debate-gate.ts +1 -1
  179. package/.pi/{extensions/lib → lib}/plan-debate-lane.ts +1 -4
  180. package/.pi/{extensions/lib → lib}/plan-messenger.ts +1 -1
  181. package/.pi/prompts/harness-auto.md +2 -2
  182. package/.pi/prompts/harness-plan.md +4 -6
  183. package/.pi/prompts/harness-review.md +9 -9
  184. package/.pi/prompts/harness-run.md +7 -7
  185. package/.pi/prompts/harness-setup.md +42 -68
  186. package/.pi/prompts/harness-steer.md +2 -2
  187. package/.pi/scripts/README.md +3 -5
  188. package/.pi/scripts/generate-agents-policy-yaml.mjs +148 -0
  189. package/.pi/scripts/graphify-kb-updater.mjs +48 -8
  190. package/.pi/scripts/harness-agents-manifest.mjs +61 -4
  191. package/.pi/scripts/harness-agt-doctor.ts +36 -0
  192. package/.pi/scripts/harness-cli-verify.sh +9 -2
  193. package/.pi/scripts/harness-project-toggle.mjs +129 -0
  194. package/.pi/scripts/harness-sentrux-cli.mjs +142 -0
  195. package/.pi/scripts/harness-verify.mjs +113 -39
  196. package/.pi/scripts/harness-web-policy-guard.mjs +2 -2
  197. package/.pi/scripts/validate-plan-dag.mjs +65 -74
  198. package/.pi/scripts/vendor-pi-vcc-settings.stub.ts +2 -2
  199. package/.pi/scripts/vendor-sync-pi-vcc.sh +1 -1
  200. package/.pi/skills/architecture/broker-domain/SKILL.md +65 -0
  201. package/.pi/skills/architecture/cqrs/SKILL.md +63 -0
  202. package/.pi/skills/architecture/event-driven/SKILL.md +60 -0
  203. package/.pi/skills/architecture/hexagonal-ports-adapters/SKILL.md +66 -0
  204. package/.pi/skills/architecture/layered/SKILL.md +68 -0
  205. package/.pi/skills/architecture/microkernel/SKILL.md +62 -0
  206. package/.pi/skills/architecture/microservices/SKILL.md +64 -0
  207. package/.pi/skills/architecture/modular-monolith/SKILL.md +65 -0
  208. package/.pi/skills/architecture/orchestration-driven-soa/SKILL.md +61 -0
  209. package/.pi/skills/architecture/pipeline/SKILL.md +63 -0
  210. package/.pi/skills/architecture/service-based/SKILL.md +64 -0
  211. package/.pi/skills/architecture/service-mesh/SKILL.md +60 -0
  212. package/.pi/skills/architecture/space-based/SKILL.md +60 -0
  213. package/.pi/skills/ast-grep/SKILL.md +40 -321
  214. package/.pi/skills/delivery/debugging-discipline/SKILL.md +36 -0
  215. package/.pi/skills/delivery/documentation-update/SKILL.md +33 -0
  216. package/.pi/skills/delivery/requirements-to-implementation/SKILL.md +34 -0
  217. package/.pi/skills/delivery/risk-based-verification/SKILL.md +43 -0
  218. package/.pi/skills/delivery/tradeoff-analysis/SKILL.md +34 -0
  219. package/.pi/skills/engineering/api-contract-design/SKILL.md +38 -0
  220. package/.pi/skills/engineering/cohesion-coupling/SKILL.md +43 -0
  221. package/.pi/skills/engineering/complexity-control/SKILL.md +31 -0
  222. package/.pi/skills/engineering/defensive-programming/SKILL.md +38 -0
  223. package/.pi/skills/engineering/dependency-management/SKILL.md +29 -0
  224. package/.pi/skills/engineering/domain-modeling/SKILL.md +32 -0
  225. package/.pi/skills/engineering/error-handling/SKILL.md +37 -0
  226. package/.pi/skills/engineering/legacy-code-seams/SKILL.md +35 -0
  227. package/.pi/skills/engineering/naming-and-intent/SKILL.md +29 -0
  228. package/.pi/skills/engineering/refactoring-safe-evolution/SKILL.md +35 -0
  229. package/.pi/skills/engineering/routine-function-design/SKILL.md +34 -0
  230. package/.pi/skills/engineering/small-change-discipline/SKILL.md +35 -0
  231. package/.pi/skills/lsp-navigation/SKILL.md +89 -0
  232. package/.pi/skills/quality/code-review-self-check/SKILL.md +35 -0
  233. package/.pi/skills/quality/privacy-data-handling/SKILL.md +26 -0
  234. package/.pi/skills/quality/security-review/SKILL.md +34 -0
  235. package/.pi/skills/quality/test-strategy/SKILL.md +33 -0
  236. package/.pi/skills/quality/testability-design/SKILL.md +33 -0
  237. package/.pi/skills/systems/concurrency-safety/SKILL.md +32 -0
  238. package/.pi/skills/systems/data-modeling-migrations/SKILL.md +31 -0
  239. package/.pi/skills/systems/observability-instrumentation/SKILL.md +32 -0
  240. package/.pi/skills/systems/performance-measurement/SKILL.md +35 -0
  241. package/.pi/skills/systems/reliability-design/SKILL.md +32 -0
  242. package/.sentrux/rules.toml +20 -4
  243. package/AGENTS.md +5 -0
  244. package/CHANGELOG.md +26 -0
  245. package/README.md +85 -58
  246. package/THIRD_PARTY_NOTICES.md +12 -21
  247. package/package.json +15 -7
  248. package/vendor/pi-subagents/src/agents.ts +45 -1
  249. package/vendor/pi-subagents/src/subagents.ts +866 -811
  250. package/vendor/pi-vcc/src/core/brief.ts +68 -99
  251. package/vendor/pi-vcc/src/core/settings.ts +2 -2
  252. package/.agents/skills/caveman/SKILL.md +0 -67
  253. package/.pi/agents/harness/meta-optimizer.md +0 -36
  254. package/.pi/agents/harness/planning/scout-graphify.md +0 -39
  255. package/.pi/agents/harness/planning/scout-semantic.md +0 -41
  256. package/.pi/agents/harness/planning/scout-structure.md +0 -37
  257. package/.pi/extensions/lib/ask-user/dialog.ts +0 -260
  258. package/.pi/extensions/lib/harness-subagent-auth.ts +0 -209
  259. package/.pi/extensions/lib/harness-subagent-policy.ts +0 -236
  260. package/.pi/extensions/pi-model-router-harness.ts +0 -42
  261. package/.pi/harness/evolution/meta-optimizer.mjs +0 -99
  262. package/.pi/harness/specs/router-tuning-proposal.schema.json +0 -114
  263. package/.pi/model-router.example.json +0 -36
  264. package/.pi/prompts/harness-critic.md +0 -10
  265. package/.pi/prompts/harness-eval.md +0 -10
  266. package/.pi/prompts/harness-router-tune.md +0 -52
  267. package/.pi/scripts/harness-generate-model-router.mjs +0 -327
  268. package/.pi/scripts/harness-model-router-routing.test.mjs +0 -97
  269. package/.pi/scripts/harness-sync-model-router.mjs +0 -97
  270. package/.pi/scripts/vendor-sync-pi-model-router.sh +0 -47
  271. package/vendor/pi-model-router/.prettierignore +0 -4
  272. package/vendor/pi-model-router/.prettierrc +0 -5
  273. package/vendor/pi-model-router/AGENTS.md +0 -39
  274. package/vendor/pi-model-router/LICENSE +0 -21
  275. package/vendor/pi-model-router/README.md +0 -99
  276. package/vendor/pi-model-router/UPSTREAM_PIN.md +0 -10
  277. package/vendor/pi-model-router/docs/ARCHITECTURE.md +0 -54
  278. package/vendor/pi-model-router/extensions/commands.ts +0 -720
  279. package/vendor/pi-model-router/extensions/config.ts +0 -348
  280. package/vendor/pi-model-router/extensions/constants.ts +0 -1
  281. package/vendor/pi-model-router/extensions/index.ts +0 -478
  282. package/vendor/pi-model-router/extensions/provider.ts +0 -580
  283. package/vendor/pi-model-router/extensions/routing.ts +0 -564
  284. package/vendor/pi-model-router/extensions/state.ts +0 -52
  285. package/vendor/pi-model-router/extensions/types.ts +0 -95
  286. package/vendor/pi-model-router/extensions/ui.ts +0 -144
  287. package/vendor/pi-model-router/model-router.example.json +0 -48
  288. package/vendor/pi-model-router/package.json +0 -48
  289. package/vendor/pi-model-router/tsconfig.json +0 -16
  290. /package/.pi/{prompts → harness/docs}/planning-rubrics.md +0 -0
  291. /package/.pi/{extensions/lib → lib}/ask-user/fallback.ts +0 -0
  292. /package/.pi/{extensions/lib → lib}/ask-user/render.ts +0 -0
  293. /package/.pi/{extensions/lib → lib}/ask-user/schema.ts +0 -0
  294. /package/.pi/{extensions/lib → lib}/ask-user/types.ts +0 -0
  295. /package/.pi/{extensions/lib → lib}/ask-user/validate-core.mjs +0 -0
  296. /package/.pi/{extensions/lib → lib}/ask-user/validate.ts +0 -0
  297. /package/.pi/{extensions/lib → lib}/harness-cocoindex-refresh.ts +0 -0
  298. /package/.pi/{extensions/lib → lib}/harness-paths.ts +0 -0
  299. /package/.pi/{extensions/lib → lib}/harness-spawn-budget.ts +0 -0
  300. /package/.pi/{extensions/lib → lib}/harness-vcc-settings.ts +0 -0
  301. /package/.pi/{extensions/lib → lib}/harness-web/run-cli.ts +0 -0
  302. /package/.pi/{extensions/lib → lib}/plan-approval/dialog.ts +0 -0
  303. /package/.pi/{extensions/lib → lib}/plan-approval/schema.ts +0 -0
  304. /package/.pi/{extensions/lib → lib}/plan-debate-eligibility.ts +0 -0
  305. /package/.pi/{extensions/lib → lib}/plan-debate-focus.ts +0 -0
  306. /package/.pi/{extensions/lib → lib}/plan-debate-id.ts +0 -0
  307. /package/.pi/{extensions/lib → lib}/plan-debate-lanes.ts +0 -0
  308. /package/.pi/{extensions/lib → lib}/plan-debate-round-status.ts +0 -0
  309. /package/.pi/{extensions/lib → lib}/plan-debate-write-guard.ts +0 -0
  310. /package/.pi/{extensions/lib → lib}/plan-review-gate.ts +0 -0
  311. /package/.pi/{extensions/lib → lib}/plan-review-integrator-rules.ts +0 -0
  312. /package/.pi/{extensions/lib → lib}/plan-scope-guard.ts +0 -0
  313. /package/.pi/{extensions/lib → lib}/posthog-client.ts +0 -0
  314. /package/.pi/{extensions/lib → lib}/posthog-node.d.ts +0 -0
@@ -1,580 +0,0 @@
1
- import {
2
- createAssistantMessageEventStream,
3
- streamSimple,
4
- type Api,
5
- type AssistantMessage,
6
- type AssistantMessageEventStream,
7
- type Context,
8
- type Model,
9
- type SimpleStreamOptions,
10
- type Message,
11
- } from '@earendil-works/pi-ai';
12
- import type {
13
- ExtensionAPI,
14
- ExtensionContext,
15
- } from '@earendil-works/pi-coding-agent';
16
- import type {
17
- RouterConfig,
18
- RoutingDecision,
19
- RouterTier,
20
- RouterPinByProfile,
21
- RouterThinkingByProfile,
22
- SessionLock,
23
- } from './types.js';
24
- import { profileNames, parseCanonicalModelRef, ROUTER_TIERS } from './config.js';
25
- import {
26
- phaseForTier,
27
- buildRoutingDecision,
28
- decideRouting,
29
- decideSessionLock,
30
- runClassifier,
31
- extractTextFromContent,
32
- hasImageAttachment,
33
- buildSessionLockContext,
34
- sessionLockToRoutingDecision,
35
- routingDecisionToSessionLock,
36
- applyThinkingToDecision,
37
- } from './routing.js';
38
-
39
- export const createErrorMessage = (
40
- model: Model<Api>,
41
- message: string,
42
- ): AssistantMessage => {
43
- return {
44
- role: 'assistant',
45
- content: [],
46
- api: model.api,
47
- provider: model.provider,
48
- model: model.id,
49
- usage: {
50
- input: 0,
51
- output: 0,
52
- cacheRead: 0,
53
- cacheWrite: 0,
54
- totalTokens: 0,
55
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
56
- },
57
- stopReason: 'error',
58
- errorMessage: message,
59
- timestamp: Date.now(),
60
- };
61
- };
62
-
63
- /**
64
- * Heuristic token estimator (conservative: 3 characters per token)
65
- */
66
- const estimateTokens = (text: string): number => Math.ceil(text.length / 3);
67
-
68
- /**
69
- * Truncate context to fit within a target token limit by removing oldest messages.
70
- * Always preserves the first system message and the latest user message.
71
- */
72
- const truncateContext = (context: Context, limit: number): Context => {
73
- const messages = [...context.messages];
74
- if (messages.length <= 1) return context;
75
-
76
- const getSystemTokens = () =>
77
- context.systemPrompt ? estimateTokens(context.systemPrompt) : 0;
78
-
79
- // Initial estimate
80
- const totalTokens =
81
- getSystemTokens() +
82
- messages.reduce(
83
- (sum, m) => sum + estimateTokens(extractTextFromContent(m.content)),
84
- 0,
85
- );
86
- if (totalTokens <= limit) return context;
87
-
88
- const latestMessage = messages.pop();
89
- if (!latestMessage) return context;
90
-
91
- // Remove oldest until it fits
92
- while (messages.length > 0) {
93
- const currentTokens =
94
- getSystemTokens() +
95
- estimateTokens(extractTextFromContent(latestMessage.content)) +
96
- messages.reduce(
97
- (sum, m) => sum + estimateTokens(extractTextFromContent(m.content)),
98
- 0,
99
- );
100
-
101
- if (currentTokens <= limit) break;
102
- messages.shift(); // Remove oldest
103
- }
104
-
105
- const finalMessages: Message[] = [];
106
- finalMessages.push(...messages);
107
- finalMessages.push(latestMessage);
108
-
109
- return { ...context, messages: finalMessages };
110
- };
111
-
112
- const supportsReasoning = (
113
- profile: RouterConfig['profiles'][string],
114
- modelRegistry: ExtensionContext['modelRegistry'] | undefined,
115
- ): boolean => {
116
- if (!modelRegistry) return false;
117
-
118
- for (const tier of ROUTER_TIERS) {
119
- try {
120
- const { provider, modelId } = parseCanonicalModelRef(profile[tier].model);
121
- if (modelRegistry.find(provider, modelId)?.reasoning) {
122
- return true;
123
- }
124
- } catch (_error) {
125
- // ignore invalid model refs here; config normalization handles warnings
126
- }
127
- }
128
-
129
- return false;
130
- };
131
-
132
- export const registerRouterProvider = (
133
- pi: ExtensionAPI,
134
- state: {
135
- lastRegisteredModels: string;
136
- readonly currentConfig: RouterConfig;
137
- readonly currentModelRegistry:
138
- | ExtensionContext['modelRegistry']
139
- | undefined;
140
- readonly lastExtensionContext: ExtensionContext | undefined;
141
- selectedProfile: string;
142
- routerEnabled: boolean;
143
- lastDecision: RoutingDecision | undefined;
144
- readonly thinkingByProfile: RouterThinkingByProfile;
145
- readonly pinnedTierByProfile: RouterPinByProfile;
146
- accumulatedCost: number;
147
- get sessionLock(): SessionLock | undefined;
148
- set sessionLock(v: SessionLock | undefined);
149
- },
150
- actions: {
151
- persistState: () => void;
152
- recordDebugDecision: (decision: RoutingDecision) => void;
153
- getThinkingOverride: (profileName: string, tier: RouterTier) => any;
154
- updateStatus: (ctx: ExtensionContext) => void;
155
- },
156
- ) => {
157
- const profileList = profileNames(state.currentConfig);
158
-
159
- // Map profiles to their capacities
160
- const modelDefinitions = profileList.map((name) => {
161
- const profile = state.currentConfig.profiles[name];
162
- let contextWindow = 1_000_000;
163
- let maxTokens = 64_000;
164
-
165
- if (state.currentModelRegistry) {
166
- for (const tier of ROUTER_TIERS) {
167
- try {
168
- const { provider, modelId } = parseCanonicalModelRef(
169
- profile[tier].model,
170
- );
171
- const tierModel = state.currentModelRegistry.find(provider, modelId);
172
- if (tierModel) {
173
- if (tier === 'high') {
174
- contextWindow = tierModel.contextWindow ?? contextWindow;
175
- maxTokens = tierModel.maxTokens ?? maxTokens;
176
- }
177
- }
178
- } catch (_error) {
179
- // ignore
180
- }
181
- }
182
- }
183
-
184
- return {
185
- id: name,
186
- name: `Router ${name}`,
187
- reasoning: supportsReasoning(profile, state.currentModelRegistry),
188
- input: ['text', 'image'] as ('text' | 'image')[],
189
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
190
- contextWindow,
191
- maxTokens,
192
- };
193
- });
194
-
195
- const modelsKey = modelDefinitions
196
- .map((m) => `${m.id}:${m.contextWindow}:${m.maxTokens}:${m.reasoning}`)
197
- .join(',');
198
- if (state.lastRegisteredModels === modelsKey) return;
199
-
200
- pi.registerProvider('router', {
201
- baseUrl: 'router://local',
202
- apiKey: 'pi-model-router',
203
- api: 'router-local-api',
204
- models: modelDefinitions,
205
- streamSimple(
206
- model: Model<Api>,
207
- context: Context,
208
- options?: SimpleStreamOptions,
209
- ): AssistantMessageEventStream {
210
- const stream = createAssistantMessageEventStream();
211
-
212
- (async () => {
213
- try {
214
- if (!state.currentModelRegistry) {
215
- throw new Error(
216
- 'Router provider not initialized yet. Wait for session_start and retry.',
217
- );
218
- }
219
- const profile = state.currentConfig.profiles[model.id];
220
- if (!profile) {
221
- throw new Error(`Unknown router profile: ${model.id}`);
222
- }
223
-
224
- state.selectedProfile = model.id;
225
- state.routerEnabled = true;
226
-
227
- const pinnedTier = state.pinnedTierByProfile[model.id];
228
- const thinkingOverrides = state.thinkingByProfile[model.id];
229
- const isBudgetExceeded =
230
- state.currentConfig.maxSessionBudget !== undefined &&
231
- state.accumulatedCost >= state.currentConfig.maxSessionBudget;
232
-
233
- const checkModelSupportsImage = (modelRef: string) => {
234
- try {
235
- const { provider, modelId } = parseCanonicalModelRef(modelRef);
236
- const m = state.currentModelRegistry?.find(provider, modelId);
237
- return m?.input?.includes('image') ?? false;
238
- } catch {
239
- return false;
240
- }
241
- };
242
-
243
- const pickVisionCapableLock = (
244
- lockDecision: RoutingDecision,
245
- ): RoutingDecision => {
246
- if (!hasImageAttachment(context)) return lockDecision;
247
- const candidates = [
248
- lockDecision.targetLabel,
249
- ...(profile[lockDecision.tier].fallbacks ?? []),
250
- ];
251
- if (candidates.some(checkModelSupportsImage)) return lockDecision;
252
- for (const tier of ROUTER_TIERS) {
253
- const refs = [profile[tier].model, ...(profile[tier].fallbacks ?? [])];
254
- const visionRef = refs.find(checkModelSupportsImage);
255
- if (visionRef) {
256
- const { provider, modelId } = parseCanonicalModelRef(visionRef);
257
- return {
258
- ...lockDecision,
259
- tier,
260
- targetLabel: visionRef,
261
- targetProvider: provider,
262
- targetModelId: modelId,
263
- reasoning: `${lockDecision.reasoning} | Vision-capable model for image input.`,
264
- };
265
- }
266
- }
267
- return lockDecision;
268
- };
269
-
270
- let lock = state.sessionLock;
271
- if (!lock || lock.profile !== model.id) {
272
- const lockContext = buildSessionLockContext(context);
273
- let lockDecision = decideSessionLock(
274
- lockContext,
275
- model.id,
276
- profile,
277
- pinnedTier,
278
- thinkingOverrides,
279
- state.currentConfig.phaseBias,
280
- state.currentConfig.rules,
281
- );
282
-
283
- if (
284
- state.currentConfig.classifierModel &&
285
- !pinnedTier &&
286
- !lockDecision.isRuleMatched
287
- ) {
288
- const classifierResult = await runClassifier(
289
- state.currentConfig.classifierModel,
290
- state.currentModelRegistry,
291
- lockContext,
292
- undefined,
293
- );
294
- if (classifierResult) {
295
- lockDecision = buildRoutingDecision(
296
- model.id,
297
- profile,
298
- classifierResult.tier,
299
- phaseForTier(classifierResult.tier),
300
- `Session lock classifier: ${classifierResult.reasoning}`,
301
- thinkingOverrides,
302
- true,
303
- );
304
- }
305
- }
306
-
307
- lockDecision = pickVisionCapableLock(lockDecision);
308
- lock = routingDecisionToSessionLock(lockDecision);
309
- state.sessionLock = lock;
310
- }
311
-
312
- const lockedBase = sessionLockToRoutingDecision(
313
- lock,
314
- profile,
315
- thinkingOverrides,
316
- );
317
-
318
- let thinkingDecision: RoutingDecision = decideRouting(
319
- context,
320
- model.id,
321
- profile,
322
- state.lastDecision,
323
- pinnedTier,
324
- thinkingOverrides,
325
- state.currentConfig.phaseBias,
326
- state.currentConfig.rules,
327
- isBudgetExceeded,
328
- );
329
-
330
- if (
331
- state.currentConfig.largeContextThreshold &&
332
- thinkingDecision.tier !== 'high' &&
333
- state.lastExtensionContext
334
- ) {
335
- try {
336
- const usage = await state.lastExtensionContext.getContextUsage();
337
- if (
338
- usage?.tokens &&
339
- usage.tokens > state.currentConfig.largeContextThreshold
340
- ) {
341
- thinkingDecision = {
342
- ...thinkingDecision,
343
- tier: 'high',
344
- phase: 'planning',
345
- reasoning: `Context usage (${usage.tokens}) exceeds threshold (${state.currentConfig.largeContextThreshold}). Forced high thinking.`,
346
- isContextTriggered: true,
347
- };
348
- }
349
- } catch (_e) {
350
- // ignore
351
- }
352
- }
353
-
354
- if (
355
- state.currentConfig.classifierModel &&
356
- !pinnedTier &&
357
- !thinkingDecision.isContextTriggered &&
358
- !thinkingDecision.isRuleMatched
359
- ) {
360
- const classifierResult = await runClassifier(
361
- state.currentConfig.classifierModel,
362
- state.currentModelRegistry,
363
- context,
364
- state.lastDecision?.phase,
365
- );
366
- if (classifierResult) {
367
- thinkingDecision = buildRoutingDecision(
368
- model.id,
369
- profile,
370
- classifierResult.tier,
371
- phaseForTier(classifierResult.tier),
372
- `Thinking classifier: ${classifierResult.reasoning}`,
373
- thinkingOverrides,
374
- true,
375
- );
376
- if (isBudgetExceeded && thinkingDecision.tier === 'high') {
377
- thinkingDecision = {
378
- ...thinkingDecision,
379
- tier: 'medium',
380
- phase: 'implementation',
381
- reasoning: `Budget exceeded. Downgraded thinking to medium. (Original: ${thinkingDecision.reasoning})`,
382
- isBudgetForced: true,
383
- };
384
- }
385
- }
386
- }
387
-
388
- let decision = applyThinkingToDecision(
389
- lockedBase,
390
- thinkingDecision,
391
- profile,
392
- thinkingOverrides,
393
- );
394
-
395
- const lastMessage = context.messages[context.messages.length - 1];
396
- const previousDecision = state.lastDecision;
397
- const isGoogleThinkingToolContinuation =
398
- lastMessage?.role === 'toolResult' &&
399
- previousDecision?.profile === model.id &&
400
- previousDecision.targetProvider === 'google' &&
401
- previousDecision.thinking !== 'off' &&
402
- decision.targetProvider === 'google' &&
403
- decision.thinking !== 'off' &&
404
- previousDecision.targetLabel === decision.targetLabel;
405
-
406
- if (isGoogleThinkingToolContinuation) {
407
- decision = {
408
- ...decision,
409
- tier: previousDecision!.tier,
410
- phase: previousDecision!.phase,
411
- targetProvider: previousDecision!.targetProvider,
412
- targetModelId: previousDecision!.targetModelId,
413
- targetLabel: previousDecision!.targetLabel,
414
- thinking: previousDecision!.thinking,
415
- reasoning:
416
- `Preserved ${previousDecision!.targetLabel} for a Google tool-result continuation ` +
417
- `to avoid thought-signature replay errors. (Original: ${decision.reasoning})`,
418
- };
419
- }
420
-
421
- state.lastDecision = decision;
422
- actions.recordDebugDecision(decision);
423
-
424
- if (state.lastExtensionContext) {
425
- actions.updateStatus(state.lastExtensionContext);
426
- }
427
-
428
- const lockTier = lock.tier;
429
- let modelsToTry = [
430
- lock.modelRef,
431
- ...(profile[lockTier].fallbacks ?? []),
432
- ];
433
- const imageAttached = hasImageAttachment(context);
434
- if (imageAttached) {
435
- modelsToTry = modelsToTry.filter((modelRef) => {
436
- try {
437
- const { provider, modelId } = parseCanonicalModelRef(modelRef);
438
- const m = state.currentModelRegistry?.find(provider, modelId);
439
- return m?.input?.includes('image') ?? false;
440
- } catch {
441
- return false;
442
- }
443
- });
444
- if (modelsToTry.length === 0) {
445
- modelsToTry = [decision.targetLabel];
446
- }
447
- }
448
- let lastError: any;
449
- let success = false;
450
-
451
- for (let i = 0; i < modelsToTry.length; i++) {
452
- const modelRef = modelsToTry[i];
453
- const { provider: targetProvider, modelId: targetModelId } =
454
- parseCanonicalModelRef(modelRef);
455
-
456
- if (targetProvider === 'router') continue;
457
-
458
- const targetModel = state.currentModelRegistry.find(
459
- targetProvider,
460
- targetModelId,
461
- );
462
- if (!targetModel) {
463
- lastError = new Error(
464
- `Routed model not found: ${targetProvider}/${targetModelId}`,
465
- );
466
- continue;
467
- }
468
-
469
- const auth =
470
- await state.currentModelRegistry.getApiKeyAndHeaders(targetModel);
471
- if (!auth.ok || !auth.apiKey) {
472
- lastError = new Error(
473
- auth.ok
474
- ? `No API key for routed model: ${targetProvider}/${targetModelId}`
475
- : `Auth failed for routed model: ${targetProvider}/${targetModelId}: ${auth.error}`,
476
- );
477
- continue;
478
- }
479
- const apiKey = auth.apiKey;
480
- const headers = auth.headers;
481
-
482
- try {
483
- // HONESTY CHECK & AUTO-TRUNCATION
484
- // If the picked model has a smaller context than what we reported, truncate now.
485
- let effectiveContext = context;
486
- const targetLimit = targetModel.contextWindow || 128_000;
487
- if (targetLimit < model.contextWindow!) {
488
- effectiveContext = truncateContext(context, targetLimit);
489
- }
490
-
491
- const thinkingOverride = actions.getThinkingOverride(
492
- model.id,
493
- decision.tier,
494
- );
495
- const delegatedReasoning =
496
- targetModel.reasoning &&
497
- (thinkingOverride ?? decision.thinking) !== 'off'
498
- ? (thinkingOverride ?? decision.thinking)
499
- : undefined;
500
-
501
- if (state.lastExtensionContext) {
502
- if (delegatedReasoning) {
503
- state.lastExtensionContext.ui.setHiddenThinkingLabel?.(
504
- `Thinking (${targetProvider}/${targetModelId})...`,
505
- );
506
- } else {
507
- state.lastExtensionContext.ui.setHiddenThinkingLabel?.();
508
- }
509
- }
510
-
511
- const delegatedStream = streamSimple(
512
- targetModel,
513
- effectiveContext,
514
- {
515
- ...options,
516
- apiKey,
517
- headers,
518
- ...(delegatedReasoning
519
- ? { reasoning: delegatedReasoning }
520
- : {}),
521
- },
522
- );
523
-
524
- let contentReceived = false;
525
- for await (const event of delegatedStream) {
526
- if (event.type === 'done') {
527
- const cost = event.message.usage?.cost?.total ?? 0;
528
- state.accumulatedCost += cost;
529
- }
530
- if (event.type === 'error' && !contentReceived) {
531
- throw new Error(
532
- (event as any).error?.errorMessage ||
533
- 'Model failed before sending content.',
534
- );
535
- }
536
- const isContent =
537
- event.type === 'text_delta' ||
538
- event.type === 'thinking_delta' ||
539
- event.type === 'toolcall_delta' ||
540
- event.type === 'toolcall_end';
541
- if (isContent) contentReceived = true;
542
- stream.push(event);
543
- }
544
- success = true;
545
- if (i > 0) decision.isFallback = true;
546
- break;
547
- } catch (err) {
548
- lastError = err;
549
- }
550
- }
551
-
552
- if (!success) {
553
- throw (
554
- lastError ||
555
- new Error('Failed to delegate to any model in the chain.')
556
- );
557
- }
558
-
559
- stream.end();
560
- } catch (error) {
561
- stream.push({
562
- type: 'error',
563
- reason: 'error',
564
- error: createErrorMessage(
565
- model,
566
- error instanceof Error ? error.message : String(error),
567
- ),
568
- });
569
- stream.end();
570
- } finally {
571
- actions.persistState();
572
- }
573
- })();
574
-
575
- return stream;
576
- },
577
- });
578
-
579
- state.lastRegisteredModels = modelsKey;
580
- };