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
@@ -0,0 +1,484 @@
1
+ /**
2
+ * Shared file path utilities for pi-lens
3
+ */
4
+
5
+ import * as fs from "node:fs";
6
+ import * as path from "node:path";
7
+ import { minimatch } from "minimatch";
8
+ import { normalizeFilePath } from "./path-utils.js";
9
+ import { safeSpawnAsync } from "./safe-spawn.js";
10
+
11
+ /**
12
+ * Return the directory where pi-lens stores project-specific data
13
+ * (caches, indexes, worklogs, etc.).
14
+ *
15
+ * Default: store under <project>/.pi/harness/.lens/projects/<project-slug>.
16
+ *
17
+ * Override: set PILENS_DATA_DIR=/some/path — each project gets its own
18
+ * subdirectory named after a sanitized form of its absolute path, e.g.
19
+ * PILENS_DATA_DIR=.pi/harness/.lens/projects
20
+ * → .pi/harness/.lens/projects/home-user-myapp/
21
+ */
22
+ export function getProjectDataDir(cwd: string): string {
23
+ const configuredBase = process.env.PILENS_DATA_DIR?.trim();
24
+ const base =
25
+ configuredBase ||
26
+ path.join(
27
+ path.resolve(cwd || process.cwd()),
28
+ ".pi",
29
+ "harness",
30
+ ".lens",
31
+ "projects",
32
+ );
33
+ const normalized = normalizeFilePath(path.resolve(cwd));
34
+ const slug = normalized
35
+ .replace(/^[a-z]:/i, "") // strip Windows drive letter
36
+ .replace(/\/+/g, "-") // separators → dashes
37
+ .replace(/[^A-Za-z0-9-]/g, "") // strip anything else
38
+ .replace(/^-+/, "") // trim leading dashes
39
+ .replace(/-+$/, ""); // trim trailing dashes
40
+ return path.join(base.trim(), slug || "default");
41
+ }
42
+
43
+ /**
44
+ * Directories to exclude from all scans (build outputs, dependencies, caches).
45
+ * Used consistently across all scanners to avoid noise from generated files.
46
+ */
47
+ export const EXCLUDED_DIRS = [
48
+ "node_modules",
49
+ ".git",
50
+ "dist",
51
+ "build",
52
+ ".turbo",
53
+ ".cache",
54
+ "target",
55
+ "out",
56
+ ".parcel-cache",
57
+ ".svelte-kit",
58
+ ".nuxt",
59
+ ".yarn",
60
+ ".pnpm-store",
61
+ ".gradle",
62
+ ".next",
63
+ ".pi", // pi agent directory, including harness lens runtime data
64
+ ".ruff_cache", // Python linter cache
65
+ ".worktrees",
66
+ ".claude",
67
+ ".codex",
68
+ ".rescue",
69
+ ".agents",
70
+ ".gstack",
71
+ ".superpowers",
72
+ ".guardrails",
73
+ ".playwright-cli",
74
+ ".playwright-mcp",
75
+ ".vscode",
76
+ "venv",
77
+ ".venv",
78
+ "coverage",
79
+ "__pycache__",
80
+ ".tox",
81
+ ".pytest_cache",
82
+ "*.dSYM",
83
+ // Vendored upstream source conventions — universally too large to scan
84
+ "vendor", // Go modules, PHP Composer, Ruby Bundler
85
+ "third_party", // Chromium/Google convention (llama.cpp, sherpa-onnx, gRPC, TF)
86
+ "third-party",
87
+ "vendors",
88
+ ];
89
+
90
+ export interface GitignorePattern {
91
+ pattern: string;
92
+ negated: boolean;
93
+ directoryOnly: boolean;
94
+ rooted: boolean;
95
+ hasSlash: boolean;
96
+ }
97
+
98
+ export interface ProjectIgnoreMatcher {
99
+ rootDir: string;
100
+ patterns: GitignorePattern[];
101
+ isIgnored(filePath: string, isDirectory?: boolean): boolean;
102
+ }
103
+
104
+ function resolveGitIgnoreRoot(startDir: string): string {
105
+ const fallback = path.resolve(startDir);
106
+ let current = fallback;
107
+ while (true) {
108
+ if (fs.existsSync(path.join(current, ".git"))) return current;
109
+ const parent = path.dirname(current);
110
+ if (parent === current) return fallback;
111
+ current = parent;
112
+ }
113
+ }
114
+
115
+ function collapseSlashes(value: string): string {
116
+ let out = "";
117
+ let previousWasSlash = false;
118
+ for (const ch of value) {
119
+ if (ch === "/") {
120
+ if (!previousWasSlash) out += ch;
121
+ previousWasSlash = true;
122
+ continue;
123
+ }
124
+ out += ch === "\\" ? "/" : ch;
125
+ previousWasSlash = false;
126
+ }
127
+ return out;
128
+ }
129
+
130
+ function stripLeadingDotSlash(value: string): string {
131
+ return value.startsWith("./") ? value.slice(2) : value;
132
+ }
133
+
134
+ function stripTrailingSlashes(value: string): string {
135
+ let end = value.length;
136
+ while (end > 0 && value[end - 1] === "/") end -= 1;
137
+ return value.slice(0, end);
138
+ }
139
+
140
+ function stripLeadingSlashes(value: string): string {
141
+ let start = 0;
142
+ while (start < value.length && value[start] === "/") start += 1;
143
+ return value.slice(start);
144
+ }
145
+
146
+ function normalizeIgnorePath(value: string): string {
147
+ return collapseSlashes(stripLeadingDotSlash(value));
148
+ }
149
+
150
+ function stripTrailingSpaces(value: string): string {
151
+ // Good-enough gitignore whitespace handling: unescaped trailing spaces are ignored.
152
+ let end = value.length;
153
+ while (end > 0 && value[end - 1] === " " && value[end - 2] !== "\\") end -= 1;
154
+ return value.slice(0, end).replace(/\\ /g, " ");
155
+ }
156
+
157
+ function parseGitignoreContent(content: string): GitignorePattern[] {
158
+ const patterns: GitignorePattern[] = [];
159
+ for (const rawLine of content.split(/\r?\n/)) {
160
+ let line = stripTrailingSpaces(rawLine.trimStart());
161
+ if (!line || line.startsWith("#")) continue;
162
+ let negated = false;
163
+ if (line.startsWith("!")) {
164
+ negated = true;
165
+ line = line.slice(1);
166
+ }
167
+ line = normalizeIgnorePath(line);
168
+ if (!line) continue;
169
+
170
+ const directoryOnly = line.endsWith("/");
171
+ if (directoryOnly) line = stripTrailingSlashes(line);
172
+ const rooted = line.startsWith("/");
173
+ if (rooted) line = stripLeadingSlashes(line);
174
+ if (!line) continue;
175
+
176
+ patterns.push({
177
+ pattern: line,
178
+ negated,
179
+ directoryOnly,
180
+ rooted,
181
+ hasSlash: line.includes("/"),
182
+ });
183
+ }
184
+ return patterns;
185
+ }
186
+
187
+ function expandGitignorePattern(pattern: GitignorePattern): string[] {
188
+ const body = pattern.pattern;
189
+ if (pattern.directoryOnly) {
190
+ if (pattern.rooted || pattern.hasSlash) return [body, `${body}/**`];
191
+ return [body, `${body}/**`, `**/${body}`, `**/${body}/**`];
192
+ }
193
+ if (pattern.rooted || pattern.hasSlash) return [body];
194
+ return [body, `**/${body}`];
195
+ }
196
+
197
+ function matchesGitignorePattern(
198
+ pattern: GitignorePattern,
199
+ relativePath: string,
200
+ isDirectory: boolean,
201
+ ): boolean {
202
+ const candidate = stripLeadingSlashes(normalizeIgnorePath(relativePath));
203
+ if (!candidate) return false;
204
+ const candidates = isDirectory ? [candidate, `${candidate}/`] : [candidate];
205
+ const options = { dot: true, nocase: process.platform === "win32" };
206
+ return expandGitignorePattern(pattern).some((expanded) => {
207
+ if (isDirectory && expanded.endsWith("/**")) {
208
+ const prefix = expanded.slice(0, -3);
209
+ if (candidate === prefix || candidate.startsWith(`${prefix}/`))
210
+ return true;
211
+ }
212
+ return candidates.some((value) => minimatch(value, expanded, options));
213
+ });
214
+ }
215
+
216
+ export function readGitignorePatterns(rootDir: string): GitignorePattern[] {
217
+ const gitignorePath = path.join(rootDir, ".gitignore");
218
+ try {
219
+ return parseGitignoreContent(fs.readFileSync(gitignorePath, "utf-8"));
220
+ } catch {
221
+ return [];
222
+ }
223
+ }
224
+
225
+ function ancestorDirsBetween(rootDir: string, targetDir: string): string[] {
226
+ const relative = path.relative(rootDir, targetDir);
227
+ if (relative.startsWith("..") || path.isAbsolute(relative)) return [];
228
+ const dirs = [rootDir];
229
+ if (!relative) return dirs;
230
+ let current = rootDir;
231
+ for (const segment of relative.split(path.sep).filter(Boolean)) {
232
+ current = path.join(current, segment);
233
+ dirs.push(current);
234
+ }
235
+ return dirs;
236
+ }
237
+
238
+ function buildProjectIgnoreMatcher(
239
+ resolvedRoot: string,
240
+ patterns: GitignorePattern[],
241
+ ): ProjectIgnoreMatcher {
242
+ const nestedCache = new Map<
243
+ string,
244
+ { gitignoreMtimeMs: number; patterns: GitignorePattern[] }
245
+ >();
246
+ const patternsForDir = (dir: string): GitignorePattern[] => {
247
+ if (dir === resolvedRoot) return patterns;
248
+ const gitignoreMtime = gitignoreMtimeMs(dir);
249
+ const cached = nestedCache.get(dir);
250
+ if (cached?.gitignoreMtimeMs === gitignoreMtime) return cached.patterns;
251
+ const nextPatterns = readGitignorePatterns(dir);
252
+ nestedCache.set(dir, {
253
+ gitignoreMtimeMs: gitignoreMtime,
254
+ patterns: nextPatterns,
255
+ });
256
+ return nextPatterns;
257
+ };
258
+
259
+ return {
260
+ rootDir: resolvedRoot,
261
+ patterns,
262
+ isIgnored(filePath: string, isDirectory = false): boolean {
263
+ const resolved = path.resolve(filePath);
264
+ const rootRelative = path.relative(resolvedRoot, resolved);
265
+ if (
266
+ !rootRelative ||
267
+ rootRelative.startsWith("..") ||
268
+ path.isAbsolute(rootRelative)
269
+ ) {
270
+ return false;
271
+ }
272
+
273
+ let ignored = false;
274
+ const patternDirs = ancestorDirsBetween(
275
+ resolvedRoot,
276
+ path.dirname(resolved),
277
+ );
278
+ for (const dir of patternDirs) {
279
+ const dirPatterns = patternsForDir(dir);
280
+ if (dirPatterns.length === 0) continue;
281
+ const relative = path.relative(dir, resolved);
282
+ const normalized = normalizeIgnorePath(relative);
283
+ for (const pattern of dirPatterns) {
284
+ if (!matchesGitignorePattern(pattern, normalized, isDirectory))
285
+ continue;
286
+ ignored = !pattern.negated;
287
+ }
288
+ }
289
+ return ignored;
290
+ },
291
+ };
292
+ }
293
+
294
+ export function createProjectIgnoreMatcher(
295
+ rootDir: string,
296
+ extraPatterns: string[] = [],
297
+ ): ProjectIgnoreMatcher {
298
+ const resolvedRoot = resolveGitIgnoreRoot(rootDir);
299
+ const patterns = [
300
+ ...readGitignorePatterns(resolvedRoot),
301
+ ...parseGitignoreContent(extraPatterns.join("\n")),
302
+ ];
303
+ return buildProjectIgnoreMatcher(resolvedRoot, patterns);
304
+ }
305
+
306
+ const projectIgnoreMatcherCache = new Map<
307
+ string,
308
+ { gitignoreMtimeMs: number; matcher: ProjectIgnoreMatcher }
309
+ >();
310
+
311
+ function gitignoreMtimeMs(rootDir: string): number {
312
+ try {
313
+ return fs.statSync(path.join(rootDir, ".gitignore")).mtimeMs;
314
+ } catch {
315
+ return -1;
316
+ }
317
+ }
318
+
319
+ export function getProjectIgnoreMatcher(rootDir: string): ProjectIgnoreMatcher {
320
+ const resolvedRoot = resolveGitIgnoreRoot(rootDir);
321
+ const gitignoreMtime = gitignoreMtimeMs(resolvedRoot);
322
+ const cached = projectIgnoreMatcherCache.get(resolvedRoot);
323
+ if (cached?.gitignoreMtimeMs === gitignoreMtime) return cached.matcher;
324
+
325
+ const matcher = createProjectIgnoreMatcher(resolvedRoot);
326
+ projectIgnoreMatcherCache.set(resolvedRoot, {
327
+ gitignoreMtimeMs: gitignoreMtime,
328
+ matcher,
329
+ });
330
+ return matcher;
331
+ }
332
+
333
+ export function isPathIgnoredByProject(
334
+ filePath: string,
335
+ rootDir: string,
336
+ isDirectory = false,
337
+ ): boolean {
338
+ return getProjectIgnoreMatcher(rootDir).isIgnored(filePath, isDirectory);
339
+ }
340
+
341
+ export function getProjectIgnoreGlobs(rootDir: string): string[] {
342
+ return readGitignorePatterns(rootDir)
343
+ .filter((pattern) => !pattern.negated)
344
+ .flatMap((pattern) => expandGitignorePattern(pattern));
345
+ }
346
+
347
+ /**
348
+ * Read simple directory-name entries from a root .gitignore.
349
+ *
350
+ * Prefer createProjectIgnoreMatcher() for path-aware gitignore matching. This
351
+ * helper is kept for callers/tests that only need simple directory names.
352
+ */
353
+ export function readGitignoreDirs(rootDir: string): string[] {
354
+ return readGitignorePatterns(rootDir)
355
+ .filter(
356
+ (entry) =>
357
+ !entry.negated &&
358
+ !entry.pattern.includes("*") &&
359
+ !entry.pattern.includes("?") &&
360
+ !entry.pattern.includes("[") &&
361
+ !entry.pattern.includes("/"),
362
+ )
363
+ .map((entry) => entry.pattern);
364
+ }
365
+
366
+ function globToRegExp(glob: string): RegExp {
367
+ const escaped = glob
368
+ .replace(/[.+^${}()|[\]\\]/g, "\\$&")
369
+ .replace(/\*/g, ".*")
370
+ .replace(/\?/g, ".");
371
+ return new RegExp(`^${escaped}$`, "i");
372
+ }
373
+
374
+ /**
375
+ * Match directory name against exclusion patterns.
376
+ * Supports exact names and lightweight glob patterns (for example `*.dSYM`).
377
+ */
378
+ export function isExcludedDirName(
379
+ dirName: string,
380
+ extraPatterns: string[] = [],
381
+ ): boolean {
382
+ const candidate = dirName.trim();
383
+ if (!candidate) return false;
384
+
385
+ const patterns = [...EXCLUDED_DIRS, ...extraPatterns]
386
+ .map((p) => p.trim())
387
+ .filter((p) => p.length > 0);
388
+ const candidateLower = candidate.toLowerCase();
389
+
390
+ for (const pattern of patterns) {
391
+ const patLower = pattern.toLowerCase();
392
+ if (!patLower.includes("*") && !patLower.includes("?")) {
393
+ if (candidateLower === patLower) return true;
394
+ continue;
395
+ }
396
+ if (globToRegExp(pattern).test(candidate)) return true;
397
+ }
398
+
399
+ return false;
400
+ }
401
+
402
+ /**
403
+ * Convert excluded directory names into glob patterns used by scanners.
404
+ */
405
+ export function getExcludedDirGlobs(): string[] {
406
+ return EXCLUDED_DIRS.map((dir) => `**/${dir}/**`);
407
+ }
408
+
409
+ /**
410
+ * Shared Knip ignore patterns derived from central exclusions.
411
+ */
412
+ export function getKnipIgnorePatterns(): string[] {
413
+ return [
414
+ ...getExcludedDirGlobs(),
415
+ "**/*.test.ts",
416
+ "**/*.test.tsx",
417
+ "**/*.test.js",
418
+ "**/*.test.jsx",
419
+ "**/*.spec.ts",
420
+ "**/*.spec.tsx",
421
+ "**/*.spec.js",
422
+ "**/*.spec.jsx",
423
+ "**/*.poc.test.ts",
424
+ "**/*.poc.test.tsx",
425
+ "**/__tests__/**",
426
+ "**/tests/**",
427
+ ];
428
+ }
429
+
430
+ /**
431
+ * Spawn a command and detect whether it modified a file on disk.
432
+ * Returns 1 if the file content changed after the command ran, 0 otherwise.
433
+ * Useful for auto-fix tools (ESLint, Stylelint, RuboCop, etc.).
434
+ */
435
+ export async function detectFileChangedAfterCommand(
436
+ filePath: string,
437
+ command: string,
438
+ args: string[],
439
+ cwd: string,
440
+ ignoreStatuses: number[] = [],
441
+ ): Promise<number> {
442
+ let before = "";
443
+ try {
444
+ before = fs.readFileSync(filePath, "utf-8");
445
+ } catch {
446
+ return 0;
447
+ }
448
+
449
+ const result = await safeSpawnAsync(command, args, {
450
+ timeout: 30000,
451
+ cwd,
452
+ });
453
+ if (result.error) return 0;
454
+ if (result.status !== 0 && !ignoreStatuses.includes(result.status ?? -1)) {
455
+ return 0;
456
+ }
457
+
458
+ try {
459
+ const after = fs.readFileSync(filePath, "utf-8");
460
+ return before !== after ? 1 : 0;
461
+ } catch {
462
+ return 0;
463
+ }
464
+ }
465
+
466
+ /**
467
+ * Check if file path is a test/fixture/mock file.
468
+ * Used by secrets scanner, rate command, and dispatch runners
469
+ * to skip these files (false positives on fake credentials, etc).
470
+ */
471
+ export function isTestFile(filePath: string): boolean {
472
+ const normalized = filePath.replace(/\\/g, "/");
473
+ return (
474
+ normalized.includes(".test.") ||
475
+ normalized.includes(".spec.") ||
476
+ normalized.includes("/test/") ||
477
+ normalized.includes("/tests/") ||
478
+ normalized.includes("__tests__/") ||
479
+ normalized.includes("test-utils") ||
480
+ normalized.startsWith("test-") ||
481
+ normalized.includes(".fixture.") ||
482
+ normalized.includes(".mock.")
483
+ );
484
+ }