ultimate-pi 0.18.1 → 0.19.1

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 (325) hide show
  1. package/.agents/skills/harness-debate-plan/SKILL.md +1 -1
  2. package/.agents/skills/harness-decisions/SKILL.md +1 -2
  3. package/.agents/skills/harness-governor/SKILL.md +6 -5
  4. package/.agents/skills/web-retrieval/SKILL.md +163 -0
  5. package/.agents/skills/wiki-autoresearch/SKILL.md +6 -6
  6. package/.pi/PACKAGING.md +4 -4
  7. package/.pi/SYSTEM.md +75 -123
  8. package/.pi/agents/harness/incident-recorder.md +0 -1
  9. package/.pi/agents/harness/planning/decompose.md +0 -2
  10. package/.pi/agents/harness/planning/execution-plan-author.md +0 -2
  11. package/.pi/agents/harness/planning/hypothesis-validator.md +0 -2
  12. package/.pi/agents/harness/planning/hypothesis.md +0 -2
  13. package/.pi/agents/harness/planning/implementation-researcher.md +1 -3
  14. package/.pi/agents/harness/planning/plan-adversary.md +0 -2
  15. package/.pi/agents/harness/planning/plan-evaluator.md +1 -3
  16. package/.pi/agents/harness/planning/planning-context.md +0 -2
  17. package/.pi/agents/harness/planning/review-integrator.md +0 -2
  18. package/.pi/agents/harness/planning/sprint-contract-auditor.md +0 -2
  19. package/.pi/agents/harness/planning/stack-researcher.md +5 -3
  20. package/.pi/agents/harness/reviewing/adversary.md +0 -2
  21. package/.pi/agents/harness/reviewing/evaluator.md +0 -2
  22. package/.pi/agents/harness/reviewing/tie-breaker.md +0 -2
  23. package/.pi/agents/harness/running/executor.md +0 -2
  24. package/.pi/agents/harness/sentrux-bootstrap.md +0 -1
  25. package/.pi/agents/harness/sentrux-steward.md +0 -2
  26. package/.pi/agents/harness/trace-librarian.md +0 -1
  27. package/.pi/agents/harness/web-retrieval/web-answerer.md +35 -0
  28. package/.pi/agents/harness/web-retrieval/web-criteria-verifier.md +28 -0
  29. package/.pi/agents/harness/web-retrieval/web-gap-analyzer.md +31 -0
  30. package/.pi/agents/harness/web-retrieval/web-query-expander-fast.md +34 -0
  31. package/.pi/agents/harness/web-retrieval/web-query-expander.md +60 -0
  32. package/.pi/agents/harness/web-retrieval/web-summarizer.md +18 -0
  33. package/.pi/extensions/agt-kill-switch.ts +57 -0
  34. package/.pi/extensions/agt-prompt-guard.ts +32 -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 +6 -6
  39. package/.pi/extensions/harness-ask-user.ts +7 -7
  40. package/.pi/extensions/harness-debate-tools.ts +26 -42
  41. package/.pi/extensions/harness-lens.ts +94 -0
  42. package/.pi/extensions/harness-plan-approval.ts +11 -11
  43. package/.pi/extensions/harness-run-context.ts +1070 -876
  44. package/.pi/extensions/harness-subagent-governance.ts +8 -0
  45. package/.pi/extensions/harness-subagent-submit.ts +34 -163
  46. package/.pi/extensions/harness-subagents.ts +3 -3
  47. package/.pi/extensions/harness-telemetry.ts +2 -2
  48. package/.pi/extensions/harness-web-guard.ts +2 -1
  49. package/.pi/extensions/harness-web-tools.ts +691 -53
  50. package/.pi/extensions/policy-gate.ts +25 -5
  51. package/.pi/extensions/sentrux-rules-sync.ts +1 -1
  52. package/.pi/extensions/subagent-governance.ts +92 -0
  53. package/.pi/extensions/trace-recorder.ts +1 -1
  54. package/.pi/extensions/{ultimate-pi-vcc.ts → vcc-compaction.ts} +1 -1
  55. package/.pi/harness/README.md +6 -2
  56. package/.pi/harness/agents.manifest.json +46 -25
  57. package/.pi/harness/agents.policy.yaml +309 -0
  58. package/.pi/harness/docs/adrs/0030-inhouse-vcc-compaction.md +1 -1
  59. package/.pi/harness/docs/adrs/0035-plan-phase-review-gate.md +1 -1
  60. package/.pi/harness/docs/adrs/0045-harness-lens-minimal-contract.md +49 -0
  61. package/.pi/harness/docs/adrs/0046-agt-policy-engine.md +51 -0
  62. package/.pi/harness/docs/adrs/0047-agt-layered-security.md +39 -0
  63. package/.pi/harness/docs/adrs/0048-tool-call-hook-order.md +25 -0
  64. package/.pi/harness/docs/adrs/0049-agents-policy-manifest.md +36 -0
  65. package/.pi/harness/docs/adrs/0050-agentic-web-retrieval-stack.md +46 -0
  66. package/.pi/harness/docs/adrs/README.md +5 -0
  67. package/.pi/harness/docs/harness-web-search.md +97 -0
  68. package/.pi/harness/env.harness.template +9 -1
  69. package/.pi/harness/evolution/README.md +1 -2
  70. package/.pi/harness/examples/agents.policy.project.yaml +19 -0
  71. package/.pi/harness/examples/policies/custom-deny-bash.yaml +9 -0
  72. package/.pi/harness/examples/web-heuristic-angles.project.yaml +22 -0
  73. package/.pi/harness/policies/bash-denylists.yaml +5 -0
  74. package/.pi/harness/policies/defaults.yaml +51 -0
  75. package/.pi/harness/policies/orchestrator.yaml +18 -0
  76. package/.pi/harness/policies/phases.yaml +10 -0
  77. package/.pi/harness/policies/roles.yaml +5 -0
  78. package/.pi/harness/policies/web-guard.yaml +5 -0
  79. package/.pi/harness/policies/workflow-sequences.yaml +9 -0
  80. package/.pi/harness/sentrux/architecture.manifest.json +26 -4
  81. package/.pi/harness/specs/observation.schema.json +2 -1
  82. package/.pi/harness/web-heuristic-angles.json +278 -0
  83. package/.pi/harness/web-heuristic-angles.yaml +182 -0
  84. package/.pi/lib/agents-policy.d.mts +70 -0
  85. package/.pi/lib/agents-policy.mjs +331 -0
  86. package/.pi/lib/agents-policy.ts +19 -0
  87. package/.pi/lib/agt/audit-run-sink.ts +52 -0
  88. package/.pi/lib/agt/build-evaluation-context.ts +285 -0
  89. package/.pi/lib/agt/config.ts +28 -0
  90. package/.pi/lib/agt/delegation.ts +69 -0
  91. package/.pi/lib/agt/evaluate-policy.ts +56 -0
  92. package/.pi/lib/agt/identity-registry.ts +41 -0
  93. package/.pi/lib/agt/index.ts +55 -0
  94. package/.pi/lib/agt/kill-switch-state.ts +11 -0
  95. package/.pi/lib/agt/legacy-evaluate.ts +101 -0
  96. package/.pi/lib/agt/policy-engine.ts +154 -0
  97. package/.pi/lib/agt/rings.ts +21 -0
  98. package/.pi/lib/agt/sre-hooks.ts +45 -0
  99. package/.pi/lib/agt/trust-run-store.ts +26 -0
  100. package/.pi/lib/agt/workflow-history.ts +29 -0
  101. package/.pi/lib/agt-governance-active.ts +14 -0
  102. package/.pi/lib/agt-tool-guard.ts +78 -0
  103. package/.pi/lib/ask-user/dialog.ts +314 -0
  104. package/.pi/{extensions/lib → lib}/debate-bus-core.ts +10 -10
  105. package/.pi/{extensions/lib → lib}/debate-bus-state.ts +1 -1
  106. package/.pi/{extensions/lib → lib}/extension-load-guard.ts +13 -2
  107. package/.pi/lib/harness-agt-tool-guard.ts +5 -0
  108. package/.pi/{extensions/lib → lib}/harness-artifact-gate.ts +1 -1
  109. package/.pi/lib/harness-debate-core-deps.ts +14 -0
  110. package/.pi/lib/harness-debate-workflow-deps.ts +43 -0
  111. package/.pi/lib/harness-lens/.gitattributes +1 -0
  112. package/.pi/lib/harness-lens/clients/edit-autopatch.ts +88 -0
  113. package/.pi/lib/harness-lens/clients/file-kinds.ts +380 -0
  114. package/.pi/lib/harness-lens/clients/file-time.ts +215 -0
  115. package/.pi/lib/harness-lens/clients/file-utils.ts +484 -0
  116. package/.pi/lib/harness-lens/clients/format-service.ts +276 -0
  117. package/.pi/lib/harness-lens/clients/formatters.ts +1000 -0
  118. package/.pi/lib/harness-lens/clients/git-guard.ts +31 -0
  119. package/.pi/lib/harness-lens/clients/indent-retarget.ts +90 -0
  120. package/.pi/lib/harness-lens/clients/installer/index.ts +2368 -0
  121. package/.pi/lib/harness-lens/clients/latency-logger.ts +80 -0
  122. package/.pi/lib/harness-lens/clients/lens-config.ts +43 -0
  123. package/.pi/lib/harness-lens/clients/lens-events.ts +164 -0
  124. package/.pi/lib/harness-lens/clients/lsp/aggregation.ts +91 -0
  125. package/.pi/lib/harness-lens/clients/lsp/client.ts +1466 -0
  126. package/.pi/lib/harness-lens/clients/lsp/config.ts +216 -0
  127. package/.pi/lib/harness-lens/clients/lsp/edits.ts +297 -0
  128. package/.pi/lib/harness-lens/clients/lsp/index.ts +1355 -0
  129. package/.pi/lib/harness-lens/clients/lsp/interactive-install.ts +424 -0
  130. package/.pi/lib/harness-lens/clients/lsp/language.ts +223 -0
  131. package/.pi/lib/harness-lens/clients/lsp/launch.ts +939 -0
  132. package/.pi/lib/harness-lens/clients/lsp/lsp-index.ts +11 -0
  133. package/.pi/lib/harness-lens/clients/lsp/path-utils.ts +12 -0
  134. package/.pi/lib/harness-lens/clients/lsp/server-strategies.ts +81 -0
  135. package/.pi/lib/harness-lens/clients/lsp/server.ts +1971 -0
  136. package/.pi/lib/harness-lens/clients/path-utils.ts +182 -0
  137. package/.pi/lib/harness-lens/clients/pipeline.ts +360 -0
  138. package/.pi/lib/harness-lens/clients/project-profile.ts +117 -0
  139. package/.pi/lib/harness-lens/clients/runtime-agent-end.ts +112 -0
  140. package/.pi/lib/harness-lens/clients/runtime-config.ts +33 -0
  141. package/.pi/lib/harness-lens/clients/runtime-coordinator.ts +186 -0
  142. package/.pi/lib/harness-lens/clients/runtime-tool-result.ts +171 -0
  143. package/.pi/lib/harness-lens/clients/safe-spawn.ts +339 -0
  144. package/.pi/lib/harness-lens/clients/secrets-scanner.ts +214 -0
  145. package/.pi/lib/harness-lens/clients/tool-policy.ts +2072 -0
  146. package/.pi/lib/harness-lens/clients/types.ts +59 -0
  147. package/.pi/lib/harness-lens/clients/widget-state.ts +283 -0
  148. package/.pi/lib/harness-lens/index.ts +532 -0
  149. package/.pi/lib/harness-lens/tools/lsp-diagnostics.ts +706 -0
  150. package/.pi/lib/harness-lens/tools/lsp-navigation.ts +1246 -0
  151. package/.pi/{extensions/lib → lib}/harness-posthog.ts +3 -0
  152. package/.pi/lib/harness-run-context-responses.ts +9 -0
  153. package/.pi/lib/harness-run-context.ts +0 -2
  154. package/.pi/{extensions/lib/spawn-policy.ts → lib/harness-spawn-policy.ts} +1 -0
  155. package/.pi/{extensions/lib → lib}/harness-spawn-topology.ts +1 -1
  156. package/.pi/lib/harness-subagent-auth.ts +81 -0
  157. package/.pi/{extensions/lib → lib}/harness-subagent-precheck.ts +10 -7
  158. package/.pi/{extensions/lib → lib}/harness-subagent-submit-pipeline.ts +3 -3
  159. package/.pi/lib/harness-subagent-submit-register.ts +163 -0
  160. package/.pi/{extensions/lib → lib}/harness-subagent-submit-registry.ts +1 -37
  161. package/.pi/{extensions/lib → lib}/harness-subagents-bridge.ts +74 -14
  162. package/.pi/{extensions/lib → lib}/harness-subprocess-bootstrap.ts +1 -1
  163. package/.pi/lib/harness-web/artifacts.ts +200 -0
  164. package/.pi/lib/harness-web/cache.ts +369 -0
  165. package/.pi/{extensions/lib → lib}/harness-web/run-cli.ts +42 -2
  166. package/.pi/{extensions/lib → lib}/plan-approval/create-plan.ts +2 -2
  167. package/.pi/{extensions/lib → lib}/plan-approval/format-plan.ts +2 -2
  168. package/.pi/{extensions/lib → lib}/plan-approval/plan-review.ts +162 -201
  169. package/.pi/{extensions/lib → lib}/plan-approval/render.ts +1 -1
  170. package/.pi/{extensions/lib → lib}/plan-approval/resolve-disk.ts +2 -2
  171. package/.pi/{extensions/lib → lib}/plan-approval/types.ts +1 -1
  172. package/.pi/{extensions/lib → lib}/plan-approval/validate.ts +3 -3
  173. package/.pi/{extensions/lib → lib}/plan-debate-envelope.ts +1 -1
  174. package/.pi/{extensions/lib → lib}/plan-debate-gate.ts +1 -1
  175. package/.pi/{extensions/lib → lib}/plan-debate-lane.ts +1 -4
  176. package/.pi/{extensions/lib → lib}/plan-messenger.ts +1 -1
  177. package/.pi/prompts/harness-plan.md +2 -1
  178. package/.pi/prompts/harness-setup.md +40 -65
  179. package/.pi/scripts/README.md +2 -5
  180. package/.pi/scripts/gen-web-heuristic-angles-json.mjs +24 -0
  181. package/.pi/scripts/generate-agents-policy-yaml.mjs +148 -0
  182. package/.pi/scripts/harness-agents-manifest.mjs +60 -3
  183. package/.pi/scripts/harness-agt-doctor.ts +36 -0
  184. package/.pi/scripts/harness-cli-verify.sh +14 -2
  185. package/.pi/scripts/harness-verify.mjs +191 -39
  186. package/.pi/scripts/harness-web-policy-guard.mjs +3 -3
  187. package/.pi/scripts/harness-web.py +218 -15
  188. package/.pi/scripts/harness_web/deep_search.py +55 -0
  189. package/.pi/scripts/harness_web/evidence_bundle.py +47 -0
  190. package/.pi/scripts/harness_web/find_similar.py +88 -0
  191. package/.pi/scripts/harness_web/heuristic_angles_shipped.py +85 -0
  192. package/.pi/scripts/harness_web/heuristic_config.py +251 -0
  193. package/.pi/scripts/harness_web/highlights.py +47 -0
  194. package/.pi/scripts/harness_web/multi_search.py +59 -0
  195. package/.pi/scripts/harness_web/output.py +24 -0
  196. package/.pi/scripts/harness_web/query_angles.py +116 -0
  197. package/.pi/scripts/harness_web/rank.py +163 -0
  198. package/.pi/scripts/harness_web/scrape.py +30 -0
  199. package/.pi/scripts/tests/test_harness_web_heuristic_config.py +132 -0
  200. package/.pi/scripts/tests/test_harness_web_query_angles.py +45 -0
  201. package/.pi/scripts/tests/test_harness_web_rank.py +56 -0
  202. package/.pi/scripts/validate-plan-dag.mjs +65 -74
  203. package/.pi/scripts/vendor-pi-vcc-settings.stub.ts +2 -2
  204. package/.pi/scripts/vendor-sync-pi-vcc.sh +1 -1
  205. package/.pi/skills/architecture/broker-domain/SKILL.md +65 -0
  206. package/.pi/skills/architecture/cqrs/SKILL.md +63 -0
  207. package/.pi/skills/architecture/event-driven/SKILL.md +60 -0
  208. package/.pi/skills/architecture/hexagonal-ports-adapters/SKILL.md +66 -0
  209. package/.pi/skills/architecture/layered/SKILL.md +68 -0
  210. package/.pi/skills/architecture/microkernel/SKILL.md +62 -0
  211. package/.pi/skills/architecture/microservices/SKILL.md +64 -0
  212. package/.pi/skills/architecture/modular-monolith/SKILL.md +65 -0
  213. package/.pi/skills/architecture/orchestration-driven-soa/SKILL.md +61 -0
  214. package/.pi/skills/architecture/pipeline/SKILL.md +63 -0
  215. package/.pi/skills/architecture/service-based/SKILL.md +64 -0
  216. package/.pi/skills/architecture/service-mesh/SKILL.md +60 -0
  217. package/.pi/skills/architecture/space-based/SKILL.md +60 -0
  218. package/.pi/skills/ast-grep/SKILL.md +40 -321
  219. package/.pi/skills/delivery/debugging-discipline/SKILL.md +36 -0
  220. package/.pi/skills/delivery/documentation-update/SKILL.md +33 -0
  221. package/.pi/skills/delivery/requirements-to-implementation/SKILL.md +34 -0
  222. package/.pi/skills/delivery/risk-based-verification/SKILL.md +43 -0
  223. package/.pi/skills/delivery/tradeoff-analysis/SKILL.md +34 -0
  224. package/.pi/skills/engineering/api-contract-design/SKILL.md +38 -0
  225. package/.pi/skills/engineering/cohesion-coupling/SKILL.md +43 -0
  226. package/.pi/skills/engineering/complexity-control/SKILL.md +31 -0
  227. package/.pi/skills/engineering/defensive-programming/SKILL.md +38 -0
  228. package/.pi/skills/engineering/dependency-management/SKILL.md +29 -0
  229. package/.pi/skills/engineering/domain-modeling/SKILL.md +32 -0
  230. package/.pi/skills/engineering/error-handling/SKILL.md +37 -0
  231. package/.pi/skills/engineering/legacy-code-seams/SKILL.md +35 -0
  232. package/.pi/skills/engineering/naming-and-intent/SKILL.md +29 -0
  233. package/.pi/skills/engineering/refactoring-safe-evolution/SKILL.md +35 -0
  234. package/.pi/skills/engineering/routine-function-design/SKILL.md +34 -0
  235. package/.pi/skills/engineering/small-change-discipline/SKILL.md +35 -0
  236. package/.pi/skills/lsp-navigation/SKILL.md +89 -0
  237. package/.pi/skills/quality/code-review-self-check/SKILL.md +35 -0
  238. package/.pi/skills/quality/privacy-data-handling/SKILL.md +26 -0
  239. package/.pi/skills/quality/security-review/SKILL.md +34 -0
  240. package/.pi/skills/quality/test-strategy/SKILL.md +33 -0
  241. package/.pi/skills/quality/testability-design/SKILL.md +33 -0
  242. package/.pi/skills/systems/concurrency-safety/SKILL.md +32 -0
  243. package/.pi/skills/systems/data-modeling-migrations/SKILL.md +31 -0
  244. package/.pi/skills/systems/observability-instrumentation/SKILL.md +32 -0
  245. package/.pi/skills/systems/performance-measurement/SKILL.md +35 -0
  246. package/.pi/skills/systems/reliability-design/SKILL.md +32 -0
  247. package/.sentrux/rules.toml +20 -4
  248. package/AGENTS.md +7 -2
  249. package/CHANGELOG.md +20 -0
  250. package/README.md +3 -12
  251. package/THIRD_PARTY_NOTICES.md +12 -21
  252. package/package.json +17 -7
  253. package/vendor/pi-subagents/src/agents.ts +45 -1
  254. package/vendor/pi-subagents/src/subagents.ts +866 -811
  255. package/vendor/pi-vcc/src/core/brief.ts +68 -99
  256. package/vendor/pi-vcc/src/core/settings.ts +2 -2
  257. package/.agents/skills/caveman/SKILL.md +0 -67
  258. package/.agents/skills/scrapling-web/SKILL.md +0 -98
  259. package/.pi/agents/harness/meta-optimizer.md +0 -36
  260. package/.pi/extensions/00-posthog-network-bootstrap.ts +0 -11
  261. package/.pi/extensions/lib/ask-user/dialog.ts +0 -260
  262. package/.pi/extensions/lib/harness-subagent-auth.ts +0 -207
  263. package/.pi/extensions/lib/harness-subagent-policy.ts +0 -236
  264. package/.pi/extensions/pi-model-router-harness.ts +0 -42
  265. package/.pi/harness/evolution/meta-optimizer.mjs +0 -99
  266. package/.pi/harness/specs/router-tuning-proposal.schema.json +0 -114
  267. package/.pi/model-router.example.json +0 -36
  268. package/.pi/prompts/harness-critic.md +0 -10
  269. package/.pi/prompts/harness-eval.md +0 -10
  270. package/.pi/prompts/harness-router-tune.md +0 -52
  271. package/.pi/scripts/harness-generate-model-router.mjs +0 -327
  272. package/.pi/scripts/harness-model-router-routing.test.mjs +0 -97
  273. package/.pi/scripts/harness-sync-model-router.mjs +0 -97
  274. package/.pi/scripts/harness_web/__pycache__/__init__.cpython-314.pyc +0 -0
  275. package/.pi/scripts/harness_web/__pycache__/config.cpython-314.pyc +0 -0
  276. package/.pi/scripts/harness_web/__pycache__/output.cpython-314.pyc +0 -0
  277. package/.pi/scripts/harness_web/__pycache__/scrape.cpython-314.pyc +0 -0
  278. package/.pi/scripts/harness_web/__pycache__/search.cpython-314.pyc +0 -0
  279. package/.pi/scripts/harness_web/__pycache__/search_ddg.cpython-314.pyc +0 -0
  280. package/.pi/scripts/harness_web/__pycache__/search_searxng.cpython-314.pyc +0 -0
  281. package/.pi/scripts/vendor-sync-pi-model-router.sh +0 -47
  282. package/vendor/pi-model-router/.prettierignore +0 -4
  283. package/vendor/pi-model-router/.prettierrc +0 -5
  284. package/vendor/pi-model-router/AGENTS.md +0 -39
  285. package/vendor/pi-model-router/LICENSE +0 -21
  286. package/vendor/pi-model-router/README.md +0 -99
  287. package/vendor/pi-model-router/UPSTREAM_PIN.md +0 -10
  288. package/vendor/pi-model-router/docs/ARCHITECTURE.md +0 -54
  289. package/vendor/pi-model-router/extensions/commands.ts +0 -720
  290. package/vendor/pi-model-router/extensions/config.ts +0 -348
  291. package/vendor/pi-model-router/extensions/constants.ts +0 -1
  292. package/vendor/pi-model-router/extensions/index.ts +0 -478
  293. package/vendor/pi-model-router/extensions/provider.ts +0 -580
  294. package/vendor/pi-model-router/extensions/routing.ts +0 -564
  295. package/vendor/pi-model-router/extensions/state.ts +0 -52
  296. package/vendor/pi-model-router/extensions/types.ts +0 -95
  297. package/vendor/pi-model-router/extensions/ui.ts +0 -144
  298. package/vendor/pi-model-router/model-router.example.json +0 -48
  299. package/vendor/pi-model-router/package.json +0 -48
  300. package/vendor/pi-model-router/tsconfig.json +0 -16
  301. /package/.pi/{prompts → harness/docs}/planning-rubrics.md +0 -0
  302. /package/.pi/{extensions/lib → lib}/ask-user/fallback.ts +0 -0
  303. /package/.pi/{extensions/lib → lib}/ask-user/render.ts +0 -0
  304. /package/.pi/{extensions/lib → lib}/ask-user/schema.ts +0 -0
  305. /package/.pi/{extensions/lib → lib}/ask-user/types.ts +0 -0
  306. /package/.pi/{extensions/lib → lib}/ask-user/validate-core.mjs +0 -0
  307. /package/.pi/{extensions/lib → lib}/ask-user/validate.ts +0 -0
  308. /package/.pi/{extensions/lib → lib}/harness-cocoindex-refresh.ts +0 -0
  309. /package/.pi/{extensions/lib → lib}/harness-paths.ts +0 -0
  310. /package/.pi/{extensions/lib → lib}/harness-spawn-budget.ts +0 -0
  311. /package/.pi/{extensions/lib → lib}/harness-vcc-settings.ts +0 -0
  312. /package/.pi/{extensions/lib → lib}/plan-approval/dialog.ts +0 -0
  313. /package/.pi/{extensions/lib → lib}/plan-approval/schema.ts +0 -0
  314. /package/.pi/{extensions/lib → lib}/plan-approval-readiness.ts +0 -0
  315. /package/.pi/{extensions/lib → lib}/plan-debate-eligibility.ts +0 -0
  316. /package/.pi/{extensions/lib → lib}/plan-debate-focus.ts +0 -0
  317. /package/.pi/{extensions/lib → lib}/plan-debate-id.ts +0 -0
  318. /package/.pi/{extensions/lib → lib}/plan-debate-lanes.ts +0 -0
  319. /package/.pi/{extensions/lib → lib}/plan-debate-round-status.ts +0 -0
  320. /package/.pi/{extensions/lib → lib}/plan-debate-write-guard.ts +0 -0
  321. /package/.pi/{extensions/lib → lib}/plan-review-gate.ts +0 -0
  322. /package/.pi/{extensions/lib → lib}/plan-review-integrator-rules.ts +0 -0
  323. /package/.pi/{extensions/lib → lib}/plan-scope-guard.ts +0 -0
  324. /package/.pi/{extensions/lib → lib}/posthog-client.ts +0 -0
  325. /package/.pi/{extensions/lib → lib}/posthog-node.d.ts +0 -0
@@ -8,7 +8,6 @@
8
8
  import type {
9
9
  ExtensionAPI,
10
10
  ExtensionContext,
11
- ThemeColor,
12
11
  } from "@earendil-works/pi-coding-agent";
13
12
  import type { TUI } from "@earendil-works/pi-tui";
14
13
  import {
@@ -17,56 +16,7 @@ import {
17
16
  truncateToWidth,
18
17
  visibleWidth,
19
18
  } from "@earendil-works/pi-tui";
20
-
21
- // ── router decision reader ──────────────────────────────────────────
22
-
23
- /** Extract last routing decision from model-router session entries. */
24
- function readRouterDecision(ctx: ExtensionContext): {
25
- targetProvider: string;
26
- targetModelId: string;
27
- thinking: string;
28
- profile: string;
29
- enabled: boolean;
30
- } | null {
31
- try {
32
- const entries = ctx.sessionManager.getEntries();
33
- for (let i = entries.length - 1; i >= 0; i--) {
34
- const e = entries[i];
35
- if (
36
- e.type === "custom" &&
37
- (e as any).customType === "router-state" &&
38
- (e as any).data
39
- ) {
40
- const data = (e as any).data;
41
- const d = data.lastDecision;
42
- if (d?.targetProvider && d?.targetModelId) {
43
- return {
44
- targetProvider: d.targetProvider,
45
- targetModelId: d.targetModelId,
46
- thinking: d.thinking,
47
- profile: data.selectedProfile ?? d.profile,
48
- enabled: data.enabled ?? true,
49
- };
50
- }
51
- }
52
- }
53
- } catch {
54
- // session not ready
55
- }
56
- return null;
57
- }
58
-
59
- // ── profile colors ────────────────────────────────────────────────
60
-
61
- const PROFILE_COLORS: Record<string, ThemeColor> = {
62
- auto: "accent",
63
- cheap: "success",
64
- deep: "toolTitle",
65
- };
66
-
67
- function profileColor(profile: string): ThemeColor {
68
- return PROFILE_COLORS[profile] ?? "muted";
69
- }
19
+ import { getLSPService } from "../lib/harness-lens/clients/lsp/index.js";
70
20
 
71
21
  // ── token formatting ──────────────────────────────────────────────
72
22
 
@@ -145,20 +95,6 @@ function modelInfo(ctx: ExtensionContext): ModelInfo {
145
95
  const m = ctx.model;
146
96
  if (!m) return { id: "no-model", provider: "unknown", reasoning: false };
147
97
 
148
- // Router provider — extract actual model from routing decision
149
- if (m.provider === "router") {
150
- const decision = readRouterDecision(ctx);
151
- if (decision) {
152
- return {
153
- id: decision.targetModelId,
154
- provider: decision.targetProvider,
155
- reasoning: true,
156
- };
157
- }
158
- // No decision yet — show profile name so user knows router is active
159
- return { id: m.id, provider: "router", reasoning: m.reasoning };
160
- }
161
-
162
98
  return { id: m.id, provider: m.provider, reasoning: m.reasoning };
163
99
  }
164
100
 
@@ -190,8 +126,17 @@ function pathLabel(
190
126
 
191
127
  // ── extension ─────────────────────────────────────────────────────
192
128
 
129
+ function lspAlive(): boolean {
130
+ try {
131
+ return getLSPService().getAliveClientCount() > 0;
132
+ } catch {
133
+ return false;
134
+ }
135
+ }
136
+
193
137
  export default function customFooter(pi: ExtensionAPI) {
194
138
  let unsubBranch: (() => void) | null = null;
139
+ let lspInvalidateTimer: ReturnType<typeof setInterval> | null = null;
195
140
 
196
141
  const state: {
197
142
  tui: TUI | null;
@@ -204,8 +149,6 @@ export default function customFooter(pi: ExtensionAPI) {
204
149
  modelProvider: string;
205
150
  modelReasoning: boolean;
206
151
  thinkingLevel: string | null;
207
- routerProfile: string | null;
208
- routerActive: boolean;
209
152
  branch: string | null;
210
153
  } = {
211
154
  tui: null,
@@ -218,8 +161,6 @@ export default function customFooter(pi: ExtensionAPI) {
218
161
  modelProvider: "…",
219
162
  modelReasoning: false,
220
163
  thinkingLevel: null,
221
- routerProfile: null,
222
- routerActive: false,
223
164
  branch: null,
224
165
  };
225
166
 
@@ -235,17 +176,7 @@ export default function customFooter(pi: ExtensionAPI) {
235
176
  state.modelProvider = mi.provider;
236
177
  state.modelReasoning = mi.reasoning;
237
178
 
238
- // When router active, use thinking from the routing decision
239
- if (ctx.model?.provider === "router") {
240
- const routerDecision = readRouterDecision(ctx);
241
- state.thinkingLevel = routerDecision?.thinking ?? pi.getThinkingLevel();
242
- state.routerProfile = routerDecision?.profile ?? ctx.model?.id;
243
- state.routerActive = routerDecision?.enabled ?? true;
244
- } else {
245
- state.thinkingLevel = pi.getThinkingLevel();
246
- state.routerProfile = null;
247
- state.routerActive = false;
248
- }
179
+ state.thinkingLevel = pi.getThinkingLevel();
249
180
  }
250
181
 
251
182
  pi.on("session_start", (_event, ctx) => {
@@ -258,6 +189,10 @@ export default function customFooter(pi: ExtensionAPI) {
258
189
  unsubBranch();
259
190
  unsubBranch = null;
260
191
  }
192
+ if (lspInvalidateTimer) {
193
+ clearInterval(lspInvalidateTimer);
194
+ lspInvalidateTimer = null;
195
+ }
261
196
 
262
197
  state.tui = tui;
263
198
  state.branch = footerData.getGitBranch();
@@ -274,12 +209,19 @@ export default function customFooter(pi: ExtensionAPI) {
274
209
  state.box = box;
275
210
  state.textLine = textLine;
276
211
 
212
+ lspInvalidateTimer = setInterval(invalidate, 2000);
213
+ lspInvalidateTimer.unref?.();
214
+
277
215
  return {
278
216
  dispose() {
279
217
  if (unsubBranch) {
280
218
  unsubBranch();
281
219
  unsubBranch = null;
282
220
  }
221
+ if (lspInvalidateTimer) {
222
+ clearInterval(lspInvalidateTimer);
223
+ lspInvalidateTimer = null;
224
+ }
283
225
  state.tui = null;
284
226
  state.box = null;
285
227
  state.textLine = null;
@@ -328,59 +270,39 @@ export default function customFooter(pi: ExtensionAPI) {
328
270
  const tl = thinkingLabel(state.thinkingLevel, state.modelReasoning);
329
271
  const modelDisplay = tl ? `${state.modelId} ${tl}` : state.modelId;
330
272
 
331
- // Colorize: router profile gets mode color, model gets thinking color
332
- const rightStr = state.routerActive
333
- ? (() => {
334
- const pColor = profileColor(state.routerProfile ?? "router");
335
- const profileStr = theme.fg(
336
- pColor,
337
- state.routerProfile ?? "router",
338
- );
339
- const thinkingColorFn = theme.getThinkingBorderColor(
340
- (state.thinkingLevel as any) ?? "medium",
341
- );
342
- const modelStr = thinkingColorFn(modelDisplay);
343
- return `${profileStr} • ${modelStr}`;
344
- })()
345
- : `${state.modelProvider} • ${modelDisplay}`;
273
+ const lspActive = lspAlive();
274
+ const lspIndicator = theme.fg(
275
+ lspActive ? "success" : "error",
276
+ lspActive ? "LSP✓" : "LSP×",
277
+ );
278
+ const rightStr = `${state.modelProvider} • ${modelDisplay}`;
346
279
 
347
280
  // ── compose single line ──
348
281
  const colLeft = leftStr;
349
- const finalRight = state.routerActive ? rightStr : dim(rightStr);
282
+ const contextDisplay = `${lspIndicator} ${barFull}`;
283
+ const finalRight = dim(rightStr);
350
284
  const lw = visibleWidth(colLeft);
351
285
  const rw = visibleWidth(finalRight);
352
- const bw = visibleWidth(barFull);
286
+ const cw = visibleWidth(contextDisplay);
353
287
  const gap = 2;
354
288
 
355
- if (lw + gap + bw + gap + rw <= innerW) {
356
- const pad = innerW - lw - gap - bw - gap - rw;
289
+ if (lw + gap + cw + gap + rw <= innerW) {
290
+ const pad = innerW - lw - gap - cw - gap - rw;
357
291
  const line =
358
292
  colLeft +
359
293
  " ".repeat(gap + pad) +
360
- barFull +
294
+ contextDisplay +
361
295
  " ".repeat(gap) +
362
296
  finalRight;
363
297
  textLine.setText(truncateToWidth(line, innerW));
364
298
  } else {
365
- // Priority: keep bar visible, keep left (cwd) intact, truncate modelId first
299
+ // Priority: keep LSP + context bar visible, keep left (cwd) intact, truncate modelId first
366
300
  const tlNow = thinkingLabel(
367
301
  state.thinkingLevel,
368
302
  state.modelReasoning,
369
303
  );
370
- const thinkingColorFn = theme.getThinkingBorderColor(
371
- (state.thinkingLevel as any) ?? "medium",
372
- );
373
304
  const buildRight = (mid: string) => {
374
305
  const modelPart = tlNow ? `${mid} ${tlNow}` : mid;
375
- if (state.routerActive) {
376
- const pColor = profileColor(state.routerProfile ?? "router");
377
- const profileStr = theme.fg(
378
- pColor,
379
- state.routerProfile ?? "router",
380
- );
381
- const modelStr = thinkingColorFn(modelPart);
382
- return `${profileStr} • ${modelStr}`;
383
- }
384
306
  const parts: string[] = [state.modelProvider];
385
307
  if (modelPart) parts.push(modelPart);
386
308
  return dim(parts.join(" • "));
@@ -392,25 +314,25 @@ export default function customFooter(pi: ExtensionAPI) {
392
314
 
393
315
  while (
394
316
  truncMid.length > 0 &&
395
- lw + gap + bw + gap + rwNow > innerW
317
+ lw + gap + cw + gap + rwNow > innerW
396
318
  ) {
397
319
  truncMid = truncMid.slice(0, -1);
398
320
  dimR = buildRight(truncMid);
399
321
  rwNow = visibleWidth(dimR);
400
322
  }
401
323
 
402
- if (lw + gap + bw + gap + rwNow <= innerW) {
403
- const pad = innerW - lw - gap - bw - gap - rwNow;
324
+ if (lw + gap + cw + gap + rwNow <= innerW) {
325
+ const pad = innerW - lw - gap - cw - gap - rwNow;
404
326
  const line =
405
327
  colLeft +
406
328
  " ".repeat(gap + pad) +
407
- barFull +
329
+ contextDisplay +
408
330
  " ".repeat(gap) +
409
331
  dimR;
410
332
  textLine.setText(truncateToWidth(line, innerW));
411
333
  } else {
412
334
  // ModelId gone, still overflows: truncate leftStr
413
- const avail = innerW - bw - rwNow - gap - gap;
335
+ const avail = innerW - cw - rwNow - gap - gap;
414
336
  if (avail < 1) {
415
337
  textLine.setText(truncateToWidth(dimR, innerW));
416
338
  } else {
@@ -418,7 +340,7 @@ export default function customFooter(pi: ExtensionAPI) {
418
340
  const line =
419
341
  truncLeft +
420
342
  " ".repeat(gap) +
421
- barFull +
343
+ contextDisplay +
422
344
  " ".repeat(gap) +
423
345
  dimR;
424
346
  textLine.setText(truncateToWidth(line, innerW));
@@ -442,32 +364,11 @@ export default function customFooter(pi: ExtensionAPI) {
442
364
  });
443
365
 
444
366
  // Track model changes
445
- pi.on("model_select", (event, ctx) => {
446
- if (event.model?.provider === "router") {
447
- const routerDecision = readRouterDecision(ctx);
448
- if (routerDecision) {
449
- state.modelId = routerDecision.targetModelId;
450
- state.modelProvider = routerDecision.targetProvider;
451
- state.modelReasoning = true;
452
- state.thinkingLevel = routerDecision.thinking;
453
- state.routerProfile = routerDecision.profile;
454
- state.routerActive = routerDecision.enabled;
455
- } else {
456
- state.modelId = event.model.id ?? "…";
457
- state.modelProvider = "router";
458
- state.modelReasoning = event.model?.reasoning ?? false;
459
- state.thinkingLevel = pi.getThinkingLevel();
460
- state.routerProfile = event.model.id;
461
- state.routerActive = true;
462
- }
463
- } else {
464
- state.modelId = event.model?.id ?? "…";
465
- state.modelProvider = event.model?.provider ?? "…";
466
- state.modelReasoning = event.model?.reasoning ?? false;
467
- state.thinkingLevel = pi.getThinkingLevel();
468
- state.routerProfile = null;
469
- state.routerActive = false;
470
- }
367
+ pi.on("model_select", (event) => {
368
+ state.modelId = event.model?.id ?? "";
369
+ state.modelProvider = event.model?.provider ?? "…";
370
+ state.modelReasoning = event.model?.reasoning ?? false;
371
+ state.thinkingLevel = pi.getThinkingLevel();
471
372
  invalidate();
472
373
  });
473
374
 
@@ -9,7 +9,7 @@
9
9
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
10
10
  import { truncateToWidth } from "@earendil-works/pi-tui";
11
11
  import * as JimpModule from "jimp";
12
- import { resolveHarnessAsset } from "./lib/harness-paths.js";
12
+ import { resolveHarnessAsset } from "../lib/harness-paths.js";
13
13
 
14
14
  /** Shipped next to this extension in the npm package — not the host project's .pi dir. */
15
15
  const imagePath = resolveHarnessAsset(
@@ -15,7 +15,7 @@ import type {
15
15
  ExtensionAPI,
16
16
  } from "@earendil-works/pi-coding-agent";
17
17
  import { formatSkillsForPrompt } from "@earendil-works/pi-coding-agent";
18
- import { resolveHarnessAsset } from "./lib/harness-paths.js";
18
+ import { resolveHarnessAsset } from "../lib/harness-paths.js";
19
19
 
20
20
  // @ts-expect-error pi extensions run as ESM
21
21
  const MODULE_URL = import.meta.url;
@@ -6,20 +6,20 @@
6
6
 
7
7
  import { join } from "node:path";
8
8
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
9
- import { isHarnessProjectEnabled } from "../lib/harness-project-config.js";
10
- import { getRunIdFromSession } from "../lib/harness-run-context.js";
11
9
  import {
12
10
  acceptDebateRound,
13
11
  finalizeDebateConsensus,
14
12
  openDebateBus,
15
13
  parseRoundEnvelope,
16
- } from "./lib/debate-bus-core.js";
14
+ } from "../lib/debate-bus-core.js";
17
15
  import {
18
16
  getDebateState,
19
17
  restoreDebateStateFromEntry,
20
- } from "./lib/debate-bus-state.js";
21
- import { normalizePlanDebateId } from "./lib/plan-debate-id.js";
22
- import { initPlanMessenger } from "./lib/plan-messenger.js";
18
+ } from "../lib/debate-bus-state.js";
19
+ import { isHarnessProjectEnabled } from "../lib/harness-project-config.js";
20
+ import { getRunIdFromSession } from "../lib/harness-run-context.js";
21
+ import { normalizePlanDebateId } from "../lib/plan-debate-id.js";
22
+ import { initPlanMessenger } from "../lib/plan-messenger.js";
23
23
 
24
24
  function getRunId(ctx: {
25
25
  sessionManager: { getEntries(): unknown[]; getSessionId(): string };
@@ -4,21 +4,21 @@
4
4
  */
5
5
 
6
6
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
7
- import { runAskDialog } from "./lib/ask-user/dialog.js";
8
- import { runAskFallback } from "./lib/ask-user/fallback.js";
9
- import { renderAskCall, renderAskResult } from "./lib/ask-user/render.js";
7
+ import { runAskDialog } from "../lib/ask-user/dialog.js";
8
+ import { runAskFallback } from "../lib/ask-user/fallback.js";
9
+ import { renderAskCall, renderAskResult } from "../lib/ask-user/render.js";
10
10
  import {
11
11
  AskUserParamsSchema,
12
12
  PROMPT_GUIDELINES,
13
13
  PROMPT_SNIPPET,
14
- } from "./lib/ask-user/schema.js";
15
- import type { AskUserParams, DialogResult } from "./lib/ask-user/types.js";
14
+ } from "../lib/ask-user/schema.js";
15
+ import type { AskUserParams, DialogResult } from "../lib/ask-user/types.js";
16
16
  import {
17
17
  formatResultText,
18
18
  toToolDetails,
19
19
  validateAskParams,
20
- } from "./lib/ask-user/validate.js";
21
- import { claimHarnessGovernanceLoad } from "./lib/extension-load-guard.js";
20
+ } from "../lib/ask-user/validate.js";
21
+ import { claimHarnessGovernanceLoad } from "../lib/extension-load-guard.js";
22
22
 
23
23
  // @ts-expect-error pi extensions run as ESM
24
24
  const MODULE_URL = import.meta.url;
@@ -5,67 +5,51 @@
5
5
  import { mkdir, readFile } from "node:fs/promises";
6
6
  import { dirname, join } from "node:path";
7
7
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
8
- import { Type } from "@sinclair/typebox";
9
- import { parse as parseYaml } from "yaml";
10
- import type { DebateParticipant } from "../lib/debate-orchestrator-types.js";
8
+ import { claimHarnessGovernanceLoad } from "../lib/extension-load-guard.js";
11
9
  import {
10
+ captureHarnessEvent,
11
+ DEBATE_AGENT_SUBMIT_TOOL,
12
+ type DebateParticipant,
12
13
  extractLastSubmitCall,
13
- type MessageLike,
14
- } from "../lib/harness-agent-output.js";
15
- import {
16
14
  getLatestRunContext,
17
15
  getRunIdFromSession,
18
- } from "../lib/harness-run-context.js";
19
- import { writeYamlFile } from "../lib/harness-yaml.js";
16
+ type MessageLike,
17
+ parseYaml,
18
+ Type,
19
+ writeYamlFile,
20
+ } from "../lib/harness-debate-core-deps.js";
20
21
  import {
21
22
  acceptDebateRound,
22
- capsForDebate,
23
- finalizeDebateConsensus,
24
- openDebateBus,
25
- } from "./lib/debate-bus-core.js";
26
- import { getDebateState } from "./lib/debate-bus-state.js";
27
- import { claimHarnessGovernanceLoad } from "./lib/extension-load-guard.js";
28
- import { captureHarnessEvent } from "./lib/harness-posthog.js";
29
- import { DEBATE_AGENT_SUBMIT_TOOL } from "./lib/harness-subagent-submit-registry.js";
30
- import {
31
- type DebateEligibilityInput,
32
- harnessPlanDebateEligibility,
33
- } from "./lib/plan-debate-eligibility.js";
34
- import {
35
- buildPlanReviewRoundEnvelope,
36
- type PlanReviewRoundDraft,
37
- } from "./lib/plan-debate-envelope.js";
38
- import {
39
- getPlanFocusCoverage,
40
- planDebateOutcomeComplete,
41
- } from "./lib/plan-debate-focus.js";
42
- import {
43
- normalizePlanDebateId,
44
- planDebateIdForRun,
45
- } from "./lib/plan-debate-id.js";
46
- import {
47
23
  applyDebateLane,
48
24
  applyDebateLaneFromDoc,
25
+ assessPlanScopeDrift,
26
+ buildPlanReviewRoundEnvelope,
27
+ capsForDebate,
28
+ type DebateEligibilityInput,
49
29
  type DebateLaneKind,
50
30
  debateLaneForAgent,
31
+ finalizeDebateConsensus,
51
32
  formatApplyLaneMessage,
52
- } from "./lib/plan-debate-lane.js";
53
- import { getPlanDebateRoundStatus } from "./lib/plan-debate-round-status.js";
54
- import { withReviewRoundYamlWrite } from "./lib/plan-debate-write-guard.js";
55
- import {
56
33
  formatTranscriptForSpawn,
34
+ getDebateState,
57
35
  getMessengerRoundState,
36
+ getPlanDebateRoundStatus,
37
+ getPlanFocusCoverage,
38
+ harnessPlanDebateEligibility,
58
39
  initPlanMessenger,
59
40
  loadMessengerState,
41
+ loadValidationTurnYaml,
60
42
  messengerRoundDebateReady,
43
+ normalizePlanDebateId,
44
+ openDebateBus,
45
+ type PlanReviewRoundDraft,
46
+ planDebateIdForRun,
47
+ planDebateOutcomeComplete,
61
48
  postMessengerMessage,
62
49
  readRoundTranscript,
63
- } from "./lib/plan-messenger.js";
64
- import {
65
- loadValidationTurnYaml,
66
50
  validateIntegratorDraft,
67
- } from "./lib/plan-review-integrator-rules.js";
68
- import { assessPlanScopeDrift } from "./lib/plan-scope-guard.js";
51
+ withReviewRoundYamlWrite,
52
+ } from "../lib/harness-debate-workflow-deps.js";
69
53
 
70
54
  // @ts-expect-error pi extensions run as ESM
71
55
  const MODULE_URL = import.meta.url;
@@ -0,0 +1,94 @@
1
+ import * as path from "node:path";
2
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
+ import {
4
+ captureHarnessEvent,
5
+ type HarnessPostHogEventName,
6
+ } from "../lib/harness-posthog.js";
7
+
8
+ const LENS_EVENT_TO_POSTHOG: Record<string, HarnessPostHogEventName> = {
9
+ "pi-lens/analysis-complete": "harness_lens_analysis_complete",
10
+ "pi-lens/findings": "harness_lens_findings",
11
+ "pi-lens/turn-findings": "harness_lens_turn_findings",
12
+ };
13
+
14
+ type EventBusLike = {
15
+ on?: (event: string, handler: (payload: unknown) => void) => void;
16
+ };
17
+
18
+ function lensConfigRoot(cwd = process.cwd()): string {
19
+ return path.join(cwd, ".pi", "harness", ".lens");
20
+ }
21
+
22
+ function configureHarnessLensPaths(): void {
23
+ const root = lensConfigRoot();
24
+ process.env.PI_LENS_CONFIG_PATH ??= path.join(root, "config.json");
25
+ process.env.PILENS_DATA_DIR ??= path.join(root, "projects");
26
+ process.env.PI_LENS_DASHBOARD = "0";
27
+ }
28
+
29
+ function toCount(value: unknown): number {
30
+ return Array.isArray(value) ? value.length : 0;
31
+ }
32
+
33
+ function firstString(...values: unknown[]): string | undefined {
34
+ for (const value of values) {
35
+ if (typeof value === "string" && value.trim()) return value;
36
+ }
37
+ return undefined;
38
+ }
39
+
40
+ function lensPostHogProperties(
41
+ eventName: string,
42
+ payload: Record<string, unknown>,
43
+ ): Record<string, unknown> {
44
+ return {
45
+ lens_event: eventName,
46
+ lens_source: "harness-lens",
47
+ tool_name: firstString(payload.toolName, payload.tool_name) ?? "",
48
+ model: firstString(payload.model) ?? "unknown",
49
+ file_path: firstString(payload.filePath, payload.file_path) ?? "",
50
+ file_count: toCount(payload.filePaths),
51
+ diagnostic_count: toCount(payload.diagnostics),
52
+ blocker_count: toCount(payload.blockers),
53
+ warning_count: toCount(payload.warnings),
54
+ fixed_count: toCount(payload.fixed),
55
+ resolved_count: Number(payload.resolvedCount ?? 0),
56
+ duration_ms: Number(payload.durationMs ?? 0),
57
+ has_blockers: Boolean(payload.hasBlockers),
58
+ file_modified: Boolean(payload.fileModified),
59
+ changed_file_count: toCount(payload.changedFiles),
60
+ blocker_sections: Number(payload.blockerSections ?? 0),
61
+ advisory_sections: Number(payload.advisorySections ?? 0),
62
+ };
63
+ }
64
+
65
+ function installLensPostHogBridge(pi: ExtensionAPI): void {
66
+ const bus = (pi as { events?: EventBusLike }).events;
67
+ if (typeof bus?.on !== "function") return;
68
+
69
+ for (const [eventName, posthogEvent] of Object.entries(
70
+ LENS_EVENT_TO_POSTHOG,
71
+ )) {
72
+ bus.on(eventName, (payload: unknown) => {
73
+ if (!payload || typeof payload !== "object") return;
74
+ const data = payload as Record<string, unknown>;
75
+ const distinctId =
76
+ firstString(data.sessionId, data.pi_session_id) ?? "harness-lens";
77
+ captureHarnessEvent(
78
+ distinctId,
79
+ posthogEvent,
80
+ lensPostHogProperties(eventName, data),
81
+ );
82
+ });
83
+ }
84
+ }
85
+
86
+ export default async function harnessLens(pi: ExtensionAPI) {
87
+ configureHarnessLensPaths();
88
+ installLensPostHogBridge(pi);
89
+
90
+ const lens = (await import("../lib/harness-lens/index.js")) as unknown as {
91
+ default: (pi: ExtensionAPI) => unknown;
92
+ };
93
+ return lens.default(pi);
94
+ }
@@ -4,6 +4,7 @@
4
4
 
5
5
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
6
6
  import { Text } from "@earendil-works/pi-tui";
7
+ import { claimHarnessGovernanceLoad } from "../lib/extension-load-guard.js";
7
8
  import type { PlanPacketLike } from "../lib/harness-run-context.js";
8
9
  import {
9
10
  appendPlanApprovalIfNew,
@@ -12,41 +13,40 @@ import {
12
13
  parsePlanApprovalFromMessage,
13
14
  planPacketSummary,
14
15
  } from "../lib/harness-run-context.js";
15
- import { claimHarnessGovernanceLoad } from "./lib/extension-load-guard.js";
16
16
  import {
17
17
  CREATE_PLAN_GUIDELINES,
18
18
  CREATE_PLAN_SNIPPET,
19
19
  executeCreatePlan,
20
20
  formatCreatePlanResultText,
21
- } from "./lib/plan-approval/create-plan.js";
21
+ } from "../lib/plan-approval/create-plan.js";
22
22
  import {
23
23
  buildPlanApprovalMarkdown,
24
24
  runPlanApprovalDialog,
25
- } from "./lib/plan-approval/dialog.js";
26
- import { writePlanReviewMarkdown } from "./lib/plan-approval/plan-review.js";
25
+ } from "../lib/plan-approval/dialog.js";
26
+ import { writePlanReviewMarkdown } from "../lib/plan-approval/plan-review.js";
27
27
  import {
28
28
  renderApprovePlanCall,
29
29
  renderApprovePlanResult,
30
30
  renderHarnessPlanDraft,
31
- } from "./lib/plan-approval/render.js";
32
- import { resolveApprovePlanParamsFromDisk } from "./lib/plan-approval/resolve-disk.js";
31
+ } from "../lib/plan-approval/render.js";
32
+ import { resolveApprovePlanParamsFromDisk } from "../lib/plan-approval/resolve-disk.js";
33
33
  import {
34
34
  ApprovePlanParamsSchema,
35
35
  CreatePlanParamsSchema,
36
36
  PROMPT_GUIDELINES,
37
37
  PROMPT_SNIPPET,
38
- } from "./lib/plan-approval/schema.js";
38
+ } from "../lib/plan-approval/schema.js";
39
39
  import type {
40
40
  ApprovePlanParams,
41
41
  PlanApprovalDialogResult,
42
- } from "./lib/plan-approval/types.js";
42
+ } from "../lib/plan-approval/types.js";
43
43
  import {
44
44
  formatApprovePlanResultText,
45
45
  toApprovePlanToolDetails,
46
46
  validateApprovePlanParams,
47
- } from "./lib/plan-approval/validate.js";
48
- import { validatePlanApprovalReadiness } from "./lib/plan-approval-readiness.js";
49
- import { validatePlanDebateGate } from "./lib/plan-debate-gate.js";
47
+ } from "../lib/plan-approval/validate.js";
48
+ import { validatePlanApprovalReadiness } from "../lib/plan-approval-readiness.js";
49
+ import { validatePlanDebateGate } from "../lib/plan-debate-gate.js";
50
50
 
51
51
  // @ts-expect-error pi extensions run as ESM
52
52
  const MODULE_URL = import.meta.url;