ultimate-pi 0.18.1 → 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 (284) 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/.pi/PACKAGING.md +4 -4
  5. package/.pi/SYSTEM.md +54 -120
  6. package/.pi/agents/harness/incident-recorder.md +0 -1
  7. package/.pi/agents/harness/planning/decompose.md +0 -2
  8. package/.pi/agents/harness/planning/execution-plan-author.md +0 -2
  9. package/.pi/agents/harness/planning/hypothesis-validator.md +0 -2
  10. package/.pi/agents/harness/planning/hypothesis.md +0 -2
  11. package/.pi/agents/harness/planning/implementation-researcher.md +0 -2
  12. package/.pi/agents/harness/planning/plan-adversary.md +0 -2
  13. package/.pi/agents/harness/planning/plan-evaluator.md +1 -3
  14. package/.pi/agents/harness/planning/planning-context.md +0 -2
  15. package/.pi/agents/harness/planning/review-integrator.md +0 -2
  16. package/.pi/agents/harness/planning/sprint-contract-auditor.md +0 -2
  17. package/.pi/agents/harness/planning/stack-researcher.md +0 -2
  18. package/.pi/agents/harness/reviewing/adversary.md +0 -2
  19. package/.pi/agents/harness/reviewing/evaluator.md +0 -2
  20. package/.pi/agents/harness/reviewing/tie-breaker.md +0 -2
  21. package/.pi/agents/harness/running/executor.md +0 -2
  22. package/.pi/agents/harness/sentrux-bootstrap.md +0 -1
  23. package/.pi/agents/harness/sentrux-steward.md +0 -2
  24. package/.pi/agents/harness/trace-librarian.md +0 -1
  25. package/.pi/extensions/00-posthog-network-bootstrap.ts +1 -1
  26. package/.pi/extensions/agt-kill-switch.ts +57 -0
  27. package/.pi/extensions/agt-prompt-guard.ts +32 -0
  28. package/.pi/extensions/custom-footer.ts +46 -145
  29. package/.pi/extensions/custom-header.ts +1 -1
  30. package/.pi/extensions/custom-system-prompt.ts +1 -1
  31. package/.pi/extensions/debate-orchestrator.ts +6 -6
  32. package/.pi/extensions/harness-ask-user.ts +7 -7
  33. package/.pi/extensions/harness-debate-tools.ts +26 -42
  34. package/.pi/extensions/harness-lens.ts +94 -0
  35. package/.pi/extensions/harness-plan-approval.ts +11 -11
  36. package/.pi/extensions/harness-run-context.ts +1070 -876
  37. package/.pi/extensions/harness-subagent-governance.ts +8 -0
  38. package/.pi/extensions/harness-subagent-submit.ts +34 -163
  39. package/.pi/extensions/harness-subagents.ts +3 -3
  40. package/.pi/extensions/harness-telemetry.ts +2 -2
  41. package/.pi/extensions/harness-web-tools.ts +2 -2
  42. package/.pi/extensions/policy-gate.ts +25 -5
  43. package/.pi/extensions/sentrux-rules-sync.ts +1 -1
  44. package/.pi/extensions/subagent-governance.ts +92 -0
  45. package/.pi/extensions/trace-recorder.ts +1 -1
  46. package/.pi/extensions/{ultimate-pi-vcc.ts → vcc-compaction.ts} +1 -1
  47. package/.pi/harness/README.md +6 -2
  48. package/.pi/harness/agents.manifest.json +22 -25
  49. package/.pi/harness/agents.policy.yaml +275 -0
  50. package/.pi/harness/docs/adrs/0030-inhouse-vcc-compaction.md +1 -1
  51. package/.pi/harness/docs/adrs/0035-plan-phase-review-gate.md +1 -1
  52. package/.pi/harness/docs/adrs/0045-harness-lens-minimal-contract.md +49 -0
  53. package/.pi/harness/docs/adrs/0046-agt-policy-engine.md +51 -0
  54. package/.pi/harness/docs/adrs/0047-agt-layered-security.md +39 -0
  55. package/.pi/harness/docs/adrs/0048-tool-call-hook-order.md +25 -0
  56. package/.pi/harness/docs/adrs/0049-agents-policy-manifest.md +36 -0
  57. package/.pi/harness/docs/adrs/README.md +5 -0
  58. package/.pi/harness/evolution/README.md +1 -2
  59. package/.pi/harness/examples/agents.policy.project.yaml +19 -0
  60. package/.pi/harness/examples/policies/custom-deny-bash.yaml +9 -0
  61. package/.pi/harness/policies/bash-denylists.yaml +5 -0
  62. package/.pi/harness/policies/defaults.yaml +51 -0
  63. package/.pi/harness/policies/orchestrator.yaml +18 -0
  64. package/.pi/harness/policies/phases.yaml +10 -0
  65. package/.pi/harness/policies/roles.yaml +5 -0
  66. package/.pi/harness/policies/web-guard.yaml +5 -0
  67. package/.pi/harness/policies/workflow-sequences.yaml +9 -0
  68. package/.pi/harness/sentrux/architecture.manifest.json +26 -4
  69. package/.pi/harness/specs/observation.schema.json +2 -1
  70. package/.pi/lib/agents-policy.d.mts +70 -0
  71. package/.pi/lib/agents-policy.mjs +325 -0
  72. package/.pi/lib/agents-policy.ts +19 -0
  73. package/.pi/lib/agt/audit-run-sink.ts +52 -0
  74. package/.pi/lib/agt/build-evaluation-context.ts +285 -0
  75. package/.pi/lib/agt/config.ts +28 -0
  76. package/.pi/lib/agt/delegation.ts +69 -0
  77. package/.pi/lib/agt/evaluate-policy.ts +56 -0
  78. package/.pi/lib/agt/identity-registry.ts +41 -0
  79. package/.pi/lib/agt/index.ts +55 -0
  80. package/.pi/lib/agt/kill-switch-state.ts +11 -0
  81. package/.pi/lib/agt/legacy-evaluate.ts +101 -0
  82. package/.pi/lib/agt/policy-engine.ts +154 -0
  83. package/.pi/lib/agt/rings.ts +21 -0
  84. package/.pi/lib/agt/sre-hooks.ts +45 -0
  85. package/.pi/lib/agt/trust-run-store.ts +26 -0
  86. package/.pi/lib/agt/workflow-history.ts +29 -0
  87. package/.pi/lib/agt-governance-active.ts +14 -0
  88. package/.pi/lib/agt-tool-guard.ts +78 -0
  89. package/.pi/lib/ask-user/dialog.ts +314 -0
  90. package/.pi/{extensions/lib → lib}/debate-bus-core.ts +10 -10
  91. package/.pi/{extensions/lib → lib}/debate-bus-state.ts +1 -1
  92. package/.pi/{extensions/lib → lib}/extension-load-guard.ts +13 -2
  93. package/.pi/lib/harness-agt-tool-guard.ts +5 -0
  94. package/.pi/{extensions/lib → lib}/harness-artifact-gate.ts +1 -1
  95. package/.pi/lib/harness-debate-core-deps.ts +14 -0
  96. package/.pi/lib/harness-debate-workflow-deps.ts +43 -0
  97. package/.pi/lib/harness-lens/.gitattributes +1 -0
  98. package/.pi/lib/harness-lens/clients/edit-autopatch.ts +88 -0
  99. package/.pi/lib/harness-lens/clients/file-kinds.ts +380 -0
  100. package/.pi/lib/harness-lens/clients/file-time.ts +215 -0
  101. package/.pi/lib/harness-lens/clients/file-utils.ts +484 -0
  102. package/.pi/lib/harness-lens/clients/format-service.ts +276 -0
  103. package/.pi/lib/harness-lens/clients/formatters.ts +1000 -0
  104. package/.pi/lib/harness-lens/clients/git-guard.ts +31 -0
  105. package/.pi/lib/harness-lens/clients/indent-retarget.ts +90 -0
  106. package/.pi/lib/harness-lens/clients/installer/index.ts +2368 -0
  107. package/.pi/lib/harness-lens/clients/latency-logger.ts +80 -0
  108. package/.pi/lib/harness-lens/clients/lens-config.ts +43 -0
  109. package/.pi/lib/harness-lens/clients/lens-events.ts +164 -0
  110. package/.pi/lib/harness-lens/clients/lsp/aggregation.ts +91 -0
  111. package/.pi/lib/harness-lens/clients/lsp/client.ts +1466 -0
  112. package/.pi/lib/harness-lens/clients/lsp/config.ts +216 -0
  113. package/.pi/lib/harness-lens/clients/lsp/edits.ts +297 -0
  114. package/.pi/lib/harness-lens/clients/lsp/index.ts +1355 -0
  115. package/.pi/lib/harness-lens/clients/lsp/interactive-install.ts +424 -0
  116. package/.pi/lib/harness-lens/clients/lsp/language.ts +223 -0
  117. package/.pi/lib/harness-lens/clients/lsp/launch.ts +939 -0
  118. package/.pi/lib/harness-lens/clients/lsp/lsp-index.ts +11 -0
  119. package/.pi/lib/harness-lens/clients/lsp/path-utils.ts +12 -0
  120. package/.pi/lib/harness-lens/clients/lsp/server-strategies.ts +81 -0
  121. package/.pi/lib/harness-lens/clients/lsp/server.ts +1971 -0
  122. package/.pi/lib/harness-lens/clients/path-utils.ts +182 -0
  123. package/.pi/lib/harness-lens/clients/pipeline.ts +360 -0
  124. package/.pi/lib/harness-lens/clients/project-profile.ts +117 -0
  125. package/.pi/lib/harness-lens/clients/runtime-agent-end.ts +112 -0
  126. package/.pi/lib/harness-lens/clients/runtime-config.ts +33 -0
  127. package/.pi/lib/harness-lens/clients/runtime-coordinator.ts +186 -0
  128. package/.pi/lib/harness-lens/clients/runtime-tool-result.ts +171 -0
  129. package/.pi/lib/harness-lens/clients/safe-spawn.ts +339 -0
  130. package/.pi/lib/harness-lens/clients/secrets-scanner.ts +214 -0
  131. package/.pi/lib/harness-lens/clients/tool-policy.ts +2072 -0
  132. package/.pi/lib/harness-lens/clients/types.ts +59 -0
  133. package/.pi/lib/harness-lens/clients/widget-state.ts +283 -0
  134. package/.pi/lib/harness-lens/index.ts +532 -0
  135. package/.pi/lib/harness-lens/tools/lsp-diagnostics.ts +706 -0
  136. package/.pi/lib/harness-lens/tools/lsp-navigation.ts +1246 -0
  137. package/.pi/{extensions/lib → lib}/harness-posthog.ts +3 -0
  138. package/.pi/lib/harness-run-context-responses.ts +9 -0
  139. package/.pi/lib/harness-run-context.ts +0 -2
  140. package/.pi/{extensions/lib/spawn-policy.ts → lib/harness-spawn-policy.ts} +1 -0
  141. package/.pi/{extensions/lib → lib}/harness-spawn-topology.ts +1 -1
  142. package/.pi/lib/harness-subagent-auth.ts +51 -0
  143. package/.pi/{extensions/lib → lib}/harness-subagent-precheck.ts +10 -7
  144. package/.pi/{extensions/lib → lib}/harness-subagent-submit-pipeline.ts +3 -3
  145. package/.pi/lib/harness-subagent-submit-register.ts +163 -0
  146. package/.pi/{extensions/lib → lib}/harness-subagent-submit-registry.ts +1 -37
  147. package/.pi/{extensions/lib → lib}/harness-subagents-bridge.ts +53 -14
  148. package/.pi/{extensions/lib → lib}/harness-subprocess-bootstrap.ts +1 -1
  149. package/.pi/{extensions/lib → lib}/plan-approval/create-plan.ts +2 -2
  150. package/.pi/{extensions/lib → lib}/plan-approval/format-plan.ts +2 -2
  151. package/.pi/{extensions/lib → lib}/plan-approval/plan-review.ts +162 -201
  152. package/.pi/{extensions/lib → lib}/plan-approval/render.ts +1 -1
  153. package/.pi/{extensions/lib → lib}/plan-approval/resolve-disk.ts +2 -2
  154. package/.pi/{extensions/lib → lib}/plan-approval/types.ts +1 -1
  155. package/.pi/{extensions/lib → lib}/plan-approval/validate.ts +3 -3
  156. package/.pi/{extensions/lib → lib}/plan-debate-envelope.ts +1 -1
  157. package/.pi/{extensions/lib → lib}/plan-debate-gate.ts +1 -1
  158. package/.pi/{extensions/lib → lib}/plan-debate-lane.ts +1 -4
  159. package/.pi/{extensions/lib → lib}/plan-messenger.ts +1 -1
  160. package/.pi/prompts/harness-plan.md +1 -1
  161. package/.pi/prompts/harness-setup.md +37 -64
  162. package/.pi/scripts/README.md +2 -5
  163. package/.pi/scripts/generate-agents-policy-yaml.mjs +148 -0
  164. package/.pi/scripts/harness-agents-manifest.mjs +60 -3
  165. package/.pi/scripts/harness-agt-doctor.ts +36 -0
  166. package/.pi/scripts/harness-cli-verify.sh +9 -2
  167. package/.pi/scripts/harness-verify.mjs +113 -39
  168. package/.pi/scripts/harness-web-policy-guard.mjs +2 -2
  169. package/.pi/scripts/validate-plan-dag.mjs +65 -74
  170. package/.pi/scripts/vendor-pi-vcc-settings.stub.ts +2 -2
  171. package/.pi/scripts/vendor-sync-pi-vcc.sh +1 -1
  172. package/.pi/skills/architecture/broker-domain/SKILL.md +65 -0
  173. package/.pi/skills/architecture/cqrs/SKILL.md +63 -0
  174. package/.pi/skills/architecture/event-driven/SKILL.md +60 -0
  175. package/.pi/skills/architecture/hexagonal-ports-adapters/SKILL.md +66 -0
  176. package/.pi/skills/architecture/layered/SKILL.md +68 -0
  177. package/.pi/skills/architecture/microkernel/SKILL.md +62 -0
  178. package/.pi/skills/architecture/microservices/SKILL.md +64 -0
  179. package/.pi/skills/architecture/modular-monolith/SKILL.md +65 -0
  180. package/.pi/skills/architecture/orchestration-driven-soa/SKILL.md +61 -0
  181. package/.pi/skills/architecture/pipeline/SKILL.md +63 -0
  182. package/.pi/skills/architecture/service-based/SKILL.md +64 -0
  183. package/.pi/skills/architecture/service-mesh/SKILL.md +60 -0
  184. package/.pi/skills/architecture/space-based/SKILL.md +60 -0
  185. package/.pi/skills/ast-grep/SKILL.md +40 -321
  186. package/.pi/skills/delivery/debugging-discipline/SKILL.md +36 -0
  187. package/.pi/skills/delivery/documentation-update/SKILL.md +33 -0
  188. package/.pi/skills/delivery/requirements-to-implementation/SKILL.md +34 -0
  189. package/.pi/skills/delivery/risk-based-verification/SKILL.md +43 -0
  190. package/.pi/skills/delivery/tradeoff-analysis/SKILL.md +34 -0
  191. package/.pi/skills/engineering/api-contract-design/SKILL.md +38 -0
  192. package/.pi/skills/engineering/cohesion-coupling/SKILL.md +43 -0
  193. package/.pi/skills/engineering/complexity-control/SKILL.md +31 -0
  194. package/.pi/skills/engineering/defensive-programming/SKILL.md +38 -0
  195. package/.pi/skills/engineering/dependency-management/SKILL.md +29 -0
  196. package/.pi/skills/engineering/domain-modeling/SKILL.md +32 -0
  197. package/.pi/skills/engineering/error-handling/SKILL.md +37 -0
  198. package/.pi/skills/engineering/legacy-code-seams/SKILL.md +35 -0
  199. package/.pi/skills/engineering/naming-and-intent/SKILL.md +29 -0
  200. package/.pi/skills/engineering/refactoring-safe-evolution/SKILL.md +35 -0
  201. package/.pi/skills/engineering/routine-function-design/SKILL.md +34 -0
  202. package/.pi/skills/engineering/small-change-discipline/SKILL.md +35 -0
  203. package/.pi/skills/lsp-navigation/SKILL.md +89 -0
  204. package/.pi/skills/quality/code-review-self-check/SKILL.md +35 -0
  205. package/.pi/skills/quality/privacy-data-handling/SKILL.md +26 -0
  206. package/.pi/skills/quality/security-review/SKILL.md +34 -0
  207. package/.pi/skills/quality/test-strategy/SKILL.md +33 -0
  208. package/.pi/skills/quality/testability-design/SKILL.md +33 -0
  209. package/.pi/skills/systems/concurrency-safety/SKILL.md +32 -0
  210. package/.pi/skills/systems/data-modeling-migrations/SKILL.md +31 -0
  211. package/.pi/skills/systems/observability-instrumentation/SKILL.md +32 -0
  212. package/.pi/skills/systems/performance-measurement/SKILL.md +35 -0
  213. package/.pi/skills/systems/reliability-design/SKILL.md +32 -0
  214. package/.sentrux/rules.toml +20 -4
  215. package/AGENTS.md +5 -0
  216. package/CHANGELOG.md +14 -0
  217. package/README.md +3 -12
  218. package/THIRD_PARTY_NOTICES.md +12 -21
  219. package/package.json +15 -7
  220. package/vendor/pi-subagents/src/agents.ts +45 -1
  221. package/vendor/pi-subagents/src/subagents.ts +866 -811
  222. package/vendor/pi-vcc/src/core/brief.ts +68 -99
  223. package/vendor/pi-vcc/src/core/settings.ts +2 -2
  224. package/.agents/skills/caveman/SKILL.md +0 -67
  225. package/.pi/agents/harness/meta-optimizer.md +0 -36
  226. package/.pi/extensions/lib/ask-user/dialog.ts +0 -260
  227. package/.pi/extensions/lib/harness-subagent-auth.ts +0 -207
  228. package/.pi/extensions/lib/harness-subagent-policy.ts +0 -236
  229. package/.pi/extensions/pi-model-router-harness.ts +0 -42
  230. package/.pi/harness/evolution/meta-optimizer.mjs +0 -99
  231. package/.pi/harness/specs/router-tuning-proposal.schema.json +0 -114
  232. package/.pi/model-router.example.json +0 -36
  233. package/.pi/prompts/harness-critic.md +0 -10
  234. package/.pi/prompts/harness-eval.md +0 -10
  235. package/.pi/prompts/harness-router-tune.md +0 -52
  236. package/.pi/scripts/harness-generate-model-router.mjs +0 -327
  237. package/.pi/scripts/harness-model-router-routing.test.mjs +0 -97
  238. package/.pi/scripts/harness-sync-model-router.mjs +0 -97
  239. package/.pi/scripts/vendor-sync-pi-model-router.sh +0 -47
  240. package/vendor/pi-model-router/.prettierignore +0 -4
  241. package/vendor/pi-model-router/.prettierrc +0 -5
  242. package/vendor/pi-model-router/AGENTS.md +0 -39
  243. package/vendor/pi-model-router/LICENSE +0 -21
  244. package/vendor/pi-model-router/README.md +0 -99
  245. package/vendor/pi-model-router/UPSTREAM_PIN.md +0 -10
  246. package/vendor/pi-model-router/docs/ARCHITECTURE.md +0 -54
  247. package/vendor/pi-model-router/extensions/commands.ts +0 -720
  248. package/vendor/pi-model-router/extensions/config.ts +0 -348
  249. package/vendor/pi-model-router/extensions/constants.ts +0 -1
  250. package/vendor/pi-model-router/extensions/index.ts +0 -478
  251. package/vendor/pi-model-router/extensions/provider.ts +0 -580
  252. package/vendor/pi-model-router/extensions/routing.ts +0 -564
  253. package/vendor/pi-model-router/extensions/state.ts +0 -52
  254. package/vendor/pi-model-router/extensions/types.ts +0 -95
  255. package/vendor/pi-model-router/extensions/ui.ts +0 -144
  256. package/vendor/pi-model-router/model-router.example.json +0 -48
  257. package/vendor/pi-model-router/package.json +0 -48
  258. package/vendor/pi-model-router/tsconfig.json +0 -16
  259. /package/.pi/{prompts → harness/docs}/planning-rubrics.md +0 -0
  260. /package/.pi/{extensions/lib → lib}/ask-user/fallback.ts +0 -0
  261. /package/.pi/{extensions/lib → lib}/ask-user/render.ts +0 -0
  262. /package/.pi/{extensions/lib → lib}/ask-user/schema.ts +0 -0
  263. /package/.pi/{extensions/lib → lib}/ask-user/types.ts +0 -0
  264. /package/.pi/{extensions/lib → lib}/ask-user/validate-core.mjs +0 -0
  265. /package/.pi/{extensions/lib → lib}/ask-user/validate.ts +0 -0
  266. /package/.pi/{extensions/lib → lib}/harness-cocoindex-refresh.ts +0 -0
  267. /package/.pi/{extensions/lib → lib}/harness-paths.ts +0 -0
  268. /package/.pi/{extensions/lib → lib}/harness-spawn-budget.ts +0 -0
  269. /package/.pi/{extensions/lib → lib}/harness-vcc-settings.ts +0 -0
  270. /package/.pi/{extensions/lib → lib}/harness-web/run-cli.ts +0 -0
  271. /package/.pi/{extensions/lib → lib}/plan-approval/dialog.ts +0 -0
  272. /package/.pi/{extensions/lib → lib}/plan-approval/schema.ts +0 -0
  273. /package/.pi/{extensions/lib → lib}/plan-approval-readiness.ts +0 -0
  274. /package/.pi/{extensions/lib → lib}/plan-debate-eligibility.ts +0 -0
  275. /package/.pi/{extensions/lib → lib}/plan-debate-focus.ts +0 -0
  276. /package/.pi/{extensions/lib → lib}/plan-debate-id.ts +0 -0
  277. /package/.pi/{extensions/lib → lib}/plan-debate-lanes.ts +0 -0
  278. /package/.pi/{extensions/lib → lib}/plan-debate-round-status.ts +0 -0
  279. /package/.pi/{extensions/lib → lib}/plan-debate-write-guard.ts +0 -0
  280. /package/.pi/{extensions/lib → lib}/plan-review-gate.ts +0 -0
  281. /package/.pi/{extensions/lib → lib}/plan-review-integrator-rules.ts +0 -0
  282. /package/.pi/{extensions/lib → lib}/plan-scope-guard.ts +0 -0
  283. /package/.pi/{extensions/lib → lib}/posthog-client.ts +0 -0
  284. /package/.pi/{extensions/lib → lib}/posthog-node.d.ts +0 -0
@@ -1,207 +0,0 @@
1
- /**
2
- * Resolve concrete LLM credentials for harness subagent subprocesses.
3
- *
4
- * Parent sessions often use `router/<profile>` (pi-model-router). Subagents run with
5
- * `--no-extensions`, so they cannot use the logical router provider — they need
6
- * a real provider/model plus that provider's API key.
7
- *
8
- * Session-locked routing: subprocess model is chosen once from agent system prompt
9
- * complexity (same analysis as parent session lock), not from per-turn parent tier.
10
- */
11
-
12
- import { existsSync, readFileSync } from "node:fs";
13
- import { join } from "node:path";
14
- import { resolveTierFromPrompt } from "../../../vendor/pi-model-router/extensions/routing.js";
15
- import type {
16
- RouterProfile,
17
- RouterTier,
18
- RoutingRule,
19
- } from "../../../vendor/pi-model-router/extensions/types.js";
20
- import type { AgentConfig } from "../../../vendor/pi-subagents/src/agents.js";
21
-
22
- const ROUTER_SENTINEL_KEY = "pi-model-router";
23
- const SENTINEL_API_KEYS = new Set([ROUTER_SENTINEL_KEY, "<authenticated>"]);
24
-
25
- interface ModelRouterJson {
26
- defaultProfile?: string;
27
- phaseBias?: number;
28
- rules?: RoutingRule[];
29
- profiles?: Record<string, RouterProfile>;
30
- }
31
-
32
- export function isUsableApiKey(key: string | undefined): key is string {
33
- return Boolean(key && !SENTINEL_API_KEYS.has(key));
34
- }
35
-
36
- export function parseModelRef(
37
- ref: string,
38
- ): { provider: string; modelId: string } | null {
39
- const slash = ref.indexOf("/");
40
- if (slash <= 0) return null;
41
- const provider = ref.slice(0, slash).trim();
42
- const modelId = ref.slice(slash + 1).trim();
43
- if (!provider || !modelId) return null;
44
- return { provider, modelId };
45
- }
46
-
47
- /** Planning subagents that should prefer low/medium router tier for latency. */
48
- const ROUTINE_PLANNING_AGENT_PATHS = new Set([
49
- "harness/planning/plan-evaluator",
50
- "harness/planning/plan-adversary",
51
- "harness/planning/review-integrator",
52
- "harness/planning/hypothesis-validator",
53
- "harness/planning/sprint-contract-auditor",
54
- "harness/planning/planning-context",
55
- "harness/planning/decompose",
56
- "harness/planning/hypothesis",
57
- "harness/planning/stack-research",
58
- "harness/planning/plan-validator",
59
- ]);
60
-
61
- export function isRoutinePlanningAgent(agentName: string): boolean {
62
- return ROUTINE_PLANNING_AGENT_PATHS.has(agentName);
63
- }
64
-
65
- export function thinkingToRouterTier(
66
- thinking?: string,
67
- agentName?: string,
68
- ): RouterTier {
69
- if (agentName && isRoutinePlanningAgent(agentName)) {
70
- if (thinking === "high" || thinking === "xhigh") return "medium";
71
- return "low";
72
- }
73
- if (thinking === "high" || thinking === "xhigh") return "high";
74
- if (thinking === "off" || thinking === "minimal" || thinking === "low") {
75
- return "low";
76
- }
77
- return "medium";
78
- }
79
-
80
- function loadModelRouterConfig(cwd: string): ModelRouterJson | undefined {
81
- const path = join(cwd, ".pi", "model-router.json");
82
- if (!existsSync(path)) return undefined;
83
- try {
84
- return JSON.parse(readFileSync(path, "utf8")) as ModelRouterJson;
85
- } catch {
86
- return undefined;
87
- }
88
- }
89
-
90
- function resolveRouterProfileEntry(
91
- config: ModelRouterJson,
92
- profileId: string,
93
- ): { profileId: string; profile: RouterProfile } | undefined {
94
- const profiles = config.profiles;
95
- if (!profiles) return undefined;
96
- const candidates = [
97
- profileId,
98
- config.defaultProfile ?? "auto",
99
- "auto",
100
- "opencode-go",
101
- ];
102
- const seen = new Set<string>();
103
- for (const id of candidates) {
104
- if (!id || seen.has(id)) continue;
105
- seen.add(id);
106
- const profile = profiles[id];
107
- if (profile?.high?.model && profile.medium?.model && profile.low?.model) {
108
- return { profileId: id, profile };
109
- }
110
- }
111
- return undefined;
112
- }
113
-
114
- /** Tier from agent system prompt (+ optional task line) for session model lock. */
115
- export function resolveSubagentRouterTier(
116
- cwd: string,
117
- profileId: string,
118
- agent: AgentConfig,
119
- taskSnippet?: string,
120
- ): RouterTier {
121
- const config = loadModelRouterConfig(cwd);
122
- if (config) {
123
- const entry = resolveRouterProfileEntry(config, profileId);
124
- if (entry) {
125
- return resolveTierFromPrompt(
126
- agent.systemPrompt ?? "",
127
- taskSnippet?.trim() ?? "",
128
- entry.profileId,
129
- entry.profile,
130
- config.rules,
131
- config.phaseBias ?? 0.5,
132
- );
133
- }
134
- }
135
- return thinkingToRouterTier(agent.thinking, agent.name);
136
- }
137
-
138
- /** Map router profile tier → concrete `provider/model` from `.pi/model-router.json`. */
139
- export function resolveRouterConcreteModelRef(
140
- cwd: string,
141
- profileId: string,
142
- tier: RouterTier,
143
- ): string | undefined {
144
- const path = join(cwd, ".pi", "model-router.json");
145
- if (!existsSync(path)) return undefined;
146
- const raw = loadModelRouterConfig(cwd);
147
- if (!raw) return undefined;
148
- const entry = resolveRouterProfileEntry(raw, profileId);
149
- const model = entry?.profile[tier]?.model;
150
- return typeof model === "string" && model.includes("/") ? model : undefined;
151
- }
152
-
153
- export interface ConcreteSubagentModel {
154
- modelRef: string;
155
- provider: string;
156
- modelId: string;
157
- routerProfile?: string;
158
- routerTier?: RouterTier;
159
- }
160
-
161
- /**
162
- * Pick the subprocess model ref before resolving API keys.
163
- * Never returns `router/*` — always a concrete provider.
164
- */
165
- export function resolveConcreteSubagentModel(
166
- cwd: string,
167
- parentModel: { provider: string; id: string } | undefined,
168
- agent: AgentConfig,
169
- taskSnippet?: string,
170
- ): ConcreteSubagentModel | undefined {
171
- if (agent.model && !agent.model.startsWith("router/")) {
172
- const parsed = parseModelRef(agent.model);
173
- if (parsed) {
174
- return { modelRef: agent.model, ...parsed };
175
- }
176
- }
177
-
178
- const parentIsRouter = parentModel?.provider === "router";
179
- const agentIsRouter = Boolean(agent.model?.startsWith("router/"));
180
-
181
- if (!parentIsRouter && !agentIsRouter) {
182
- if (parentModel && parentModel.provider !== "router") {
183
- return {
184
- modelRef: `${parentModel.provider}/${parentModel.id}`,
185
- provider: parentModel.provider,
186
- modelId: parentModel.id,
187
- };
188
- }
189
- return undefined;
190
- }
191
-
192
- const profileId =
193
- agentIsRouter && agent.model
194
- ? agent.model.slice("router/".length)
195
- : (parentModel?.id ?? "auto");
196
- const tier = resolveSubagentRouterTier(cwd, profileId, agent, taskSnippet);
197
- const concrete = resolveRouterConcreteModelRef(cwd, profileId, tier);
198
- if (!concrete) return undefined;
199
- const parsed = parseModelRef(concrete);
200
- if (!parsed || parsed.provider === "router") return undefined;
201
- return {
202
- modelRef: concrete,
203
- ...parsed,
204
- routerProfile: profileId,
205
- routerTier: tier,
206
- };
207
- }
@@ -1,236 +0,0 @@
1
- /**
2
- * Per-agent tool policy for harness/* subagents (defense in depth with frontmatter).
3
- */
4
-
5
- import {
6
- evaluateContextModeMutation,
7
- isMutatingBash,
8
- } from "../../lib/harness-context-mode-policy.js";
9
- import type { HarnessPhase } from "../../lib/harness-run-context.js";
10
- import {
11
- isSubmitToolName,
12
- SUBMIT_TOOLS_BY_AGENT,
13
- } from "./harness-subagent-submit-registry.js";
14
- import {
15
- evaluateSubagentToolCall,
16
- type ToolCallDecision,
17
- } from "./spawn-policy.js";
18
-
19
- export type HarnessAgentKind =
20
- | "planner"
21
- | "executor"
22
- | "evaluator"
23
- | "adversary"
24
- | "tie_breaker"
25
- | "meta"
26
- | "trace"
27
- | "incident"
28
- | "other";
29
-
30
- const MUTATING_TOOLS = new Set(["write", "edit"]);
31
-
32
- /** Planning agents must use submit_* → canonical artifacts/*.yaml, not JSON dumps. */
33
- const PLANNING_ARTIFACT_JSON_WRITE = /artifacts\/[^\s'"`;]+\.json\b/i;
34
-
35
- const PLANNING_BASH_DENY_PATTERNS = [
36
- /\bgraphify\s+update\b/i,
37
- /\bgraphify\s+extract\b/i,
38
- /\bgraphify\s+install\b/i,
39
- /\bccc\s+(index|init|reset|daemon)\b/i,
40
- /\bccc\s+search\b.*--refresh/i,
41
- /\bpip\s+install\b/i,
42
- /\buv\s+tool\s+install\b/i,
43
- /\bnpm\s+install\b/i,
44
- /\bnpm\s+install\b.*cocoindex/i,
45
- /\buv\s+tool\s+install\b.*cocoindex/i,
46
- ];
47
-
48
- const READ_ONLY_KINDS = new Set<HarnessAgentKind>([
49
- "planner",
50
- "evaluator",
51
- "adversary",
52
- "tie_breaker",
53
- "trace",
54
- "incident",
55
- "meta",
56
- ]);
57
-
58
- export function isHarnessPlanningAgent(agentType: string): boolean {
59
- const id = agentType.replace(/^harness\//, "");
60
- return id.startsWith("planning/");
61
- }
62
-
63
- export function classifyHarnessAgent(agentType: string): HarnessAgentKind {
64
- const id = agentType.replace(/^harness\//, "");
65
- if (id.startsWith("planning/")) {
66
- return "planner";
67
- }
68
- switch (id) {
69
- case "running/executor":
70
- return "executor";
71
- case "reviewing/evaluator":
72
- return "evaluator";
73
- case "reviewing/adversary":
74
- return "adversary";
75
- case "reviewing/tie-breaker":
76
- return "tie_breaker";
77
- case "meta-optimizer":
78
- return "meta";
79
- case "trace-librarian":
80
- return "trace";
81
- case "incident-recorder":
82
- return "incident";
83
- default:
84
- return agentType.startsWith("harness/") ? "other" : "other";
85
- }
86
- }
87
-
88
- export function isHarnessPackageAgent(agentType: string): boolean {
89
- return agentType.startsWith("harness/");
90
- }
91
-
92
- export function evaluateHarnessSubagentToolCall(
93
- toolName: string,
94
- input: Record<string, unknown> | undefined,
95
- agentType: string,
96
- ): ToolCallDecision {
97
- const base = evaluateSubagentToolCall(toolName, agentType);
98
- if (base.action === "block") {
99
- return base;
100
- }
101
-
102
- if (!isHarnessPackageAgent(agentType)) {
103
- if (
104
- isSubmitToolName(toolName) &&
105
- process.env.PI_HARNESS_SUBPROCESS !== "1"
106
- ) {
107
- return {
108
- action: "block",
109
- reason:
110
- "harness-subagent-policy: submit_* tools are subprocess-only; parent orchestrator must use harness_artifact_ready and write_harness_yaml for merges.",
111
- };
112
- }
113
- return { action: "allow" };
114
- }
115
-
116
- if (isSubmitToolName(toolName)) {
117
- if (process.env.PI_HARNESS_SUBPROCESS !== "1") {
118
- return {
119
- action: "block",
120
- reason:
121
- "harness-subagent-policy: submit_* tools are not available in the parent harness session.",
122
- };
123
- }
124
- if (toolName === "submit_human_required") {
125
- const kind = classifyHarnessAgent(agentType);
126
- if (kind === "executor") {
127
- return {
128
- action: "block",
129
- reason:
130
- "submit_human_required is not available for harness/running/executor.",
131
- };
132
- }
133
- return { action: "allow" };
134
- }
135
- const allowed = SUBMIT_TOOLS_BY_AGENT[agentType];
136
- if (!allowed?.has(toolName)) {
137
- return {
138
- action: "block",
139
- reason: `harness-subagent-policy: ${toolName} is not allowed for ${agentType}.`,
140
- };
141
- }
142
- return { action: "allow" };
143
- }
144
-
145
- const kind = classifyHarnessAgent(agentType);
146
- if (!READ_ONLY_KINDS.has(kind)) {
147
- return { action: "allow" };
148
- }
149
-
150
- if (toolName === "create_plan" || toolName === "approve_plan") {
151
- return {
152
- action: "block",
153
- reason: `harness-subagent-policy: ${toolName} is parent-orchestrator only (not available in subagents).`,
154
- };
155
- }
156
-
157
- if (MUTATING_TOOLS.has(toolName)) {
158
- return {
159
- action: "block",
160
- reason: `harness-subagent-policy: ${toolName} blocked for harness/${kind} (read-only phase agent).`,
161
- };
162
- }
163
-
164
- if (toolName === "bash") {
165
- const command = String(input?.command ?? "");
166
- if (
167
- kind === "planner" &&
168
- command &&
169
- PLANNING_ARTIFACT_JSON_WRITE.test(command)
170
- ) {
171
- return {
172
- action: "block",
173
- reason:
174
- "harness-subagent-policy: artifacts must be YAML only — use submit_* (e.g. submit_hypothesis_brief → artifacts/hypothesis.yaml), not bash writes to .json.",
175
- };
176
- }
177
- if (command && isMutatingBash(command)) {
178
- return {
179
- action: "block",
180
- reason: `harness-subagent-policy: mutating bash blocked for harness/${kind}.`,
181
- };
182
- }
183
- if (
184
- command &&
185
- isHarnessPlanningAgent(agentType) &&
186
- PLANNING_BASH_DENY_PATTERNS.some((p) => p.test(command))
187
- ) {
188
- return {
189
- action: "block",
190
- reason:
191
- "harness-subagent-policy: planning scouts may use read-only graphify/sg/ccc commands only.",
192
- };
193
- }
194
- }
195
-
196
- const ctxPhase =
197
- (harnessSubagentPhaseHint(agentType) as HarnessPhase | null) ?? "plan";
198
- const ctxDecision = evaluateContextModeMutation(
199
- toolName,
200
- input ?? {},
201
- ctxPhase,
202
- { aborted: false, readOnlyAgent: true },
203
- );
204
- if (ctxDecision.blocked) {
205
- return {
206
- action: "block",
207
- reason: ctxDecision.reason.replace(
208
- /^policy-gate:/,
209
- "harness-subagent-policy:",
210
- ),
211
- };
212
- }
213
-
214
- return { action: "allow" };
215
- }
216
-
217
- export { isSubmitToolName } from "./harness-subagent-submit-registry.js";
218
-
219
- export function harnessSubagentPhaseHint(agentType: string): string | null {
220
- if (isHarnessPlanningAgent(agentType)) {
221
- return "plan";
222
- }
223
- const kind = classifyHarnessAgent(agentType);
224
- switch (kind) {
225
- case "planner":
226
- return "plan";
227
- case "executor":
228
- return "execute";
229
- case "evaluator":
230
- return "evaluate";
231
- case "adversary":
232
- return "adversary";
233
- default:
234
- return null;
235
- }
236
- }
@@ -1,42 +0,0 @@
1
- /**
2
- * Vendored [pi-model-router](https://github.com/yeliu84/pi-model-router), gated behind
3
- * a project-local `.pi/model-router.json` from `/harness-setup` so the extension
4
- * (and built-in fallback tiers) never load before harness bootstrap.
5
- */
6
-
7
- import { existsSync, readFileSync } from "node:fs";
8
- import { join } from "node:path";
9
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
10
- import vendorModelRouter from "../../vendor/pi-model-router/extensions/index.js";
11
-
12
- function isHarnessRouterReady(cwd: string): boolean {
13
- const path = join(cwd, ".pi", "model-router.json");
14
- if (!existsSync(path)) {
15
- return false;
16
- }
17
- try {
18
- const data: unknown = JSON.parse(readFileSync(path, "utf8"));
19
- if (typeof data !== "object" || data === null) {
20
- return false;
21
- }
22
- const profiles = (data as { profiles?: unknown }).profiles;
23
- return (
24
- typeof profiles === "object" &&
25
- profiles !== null &&
26
- Object.keys(profiles).length > 0
27
- );
28
- } catch {
29
- return false;
30
- }
31
- }
32
-
33
- export default function piModelRouterHarness(pi: ExtensionAPI) {
34
- const cwd = process.cwd();
35
- if (!isHarnessRouterReady(cwd)) {
36
- console.warn(
37
- "[ultimate-pi] Model router disabled until `.pi/model-router.json` exists (generate via /harness-setup Step 3.5).",
38
- );
39
- return;
40
- }
41
- vendorModelRouter(pi);
42
- }
@@ -1,99 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * meta-optimizer — read harness JSONL index and emit tuning proposals (no LLM).
4
- */
5
-
6
- import { readFile, readdir } from "node:fs/promises";
7
- import { join, dirname } from "node:path";
8
- import { fileURLToPath } from "node:url";
9
-
10
- const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
11
- const RUNS = join(ROOT, ".pi", "harness", "runs");
12
- const OUT = join(ROOT, ".pi", "harness", "router", "proposals", "meta-optimizer-proposal.json");
13
-
14
- async function loadIndexLines() {
15
- const indexPath = join(RUNS, "index.jsonl");
16
- try {
17
- const raw = await readFile(indexPath, "utf-8");
18
- return raw
19
- .trim()
20
- .split("\n")
21
- .filter(Boolean)
22
- .map((line) => JSON.parse(line));
23
- } catch {
24
- return [];
25
- }
26
- }
27
-
28
- async function countEventTypes(runId) {
29
- const eventsPath = join(RUNS, runId, "events.jsonl");
30
- try {
31
- const raw = await readFile(eventsPath, "utf-8");
32
- const counts = {};
33
- for (const line of raw.trim().split("\n").filter(Boolean)) {
34
- const row = JSON.parse(line);
35
- const t = row.type ?? "unknown";
36
- counts[t] = (counts[t] ?? 0) + 1;
37
- }
38
- return counts;
39
- } catch {
40
- return {};
41
- }
42
- }
43
-
44
- async function main() {
45
- const index = await loadIndexLines();
46
- const recent = index.slice(-20);
47
- let totalToolSpans = 0;
48
- let runs = 0;
49
- const policyHints = [];
50
-
51
- for (const row of recent) {
52
- const runId = row.run_id;
53
- if (!runId) continue;
54
- runs += 1;
55
- try {
56
- const trace = JSON.parse(
57
- await readFile(join(RUNS, runId, "trace.json"), "utf-8"),
58
- );
59
- totalToolSpans += trace.tool_span_count ?? trace.tool_spans?.length ?? 0;
60
- } catch {
61
- /* skip */
62
- }
63
- const events = await countEventTypes(runId);
64
- if ((events.tool_result ?? 0) > 50) {
65
- policyHints.push({
66
- run_id: runId,
67
- hint: "High tool volume; consider stricter phase caps or router to smaller model for plan phase.",
68
- });
69
- }
70
- }
71
-
72
- const avgTools = runs > 0 ? totalToolSpans / runs : 0;
73
- const proposal = {
74
- schema_version: "1.0.0",
75
- generated_at: new Date().toISOString(),
76
- source: "meta-optimizer",
77
- sample_runs: runs,
78
- avg_tool_spans_per_run: avgTools,
79
- router_hints: policyHints,
80
- recommendation:
81
- avgTools > 30
82
- ? "Consider lowering execute-phase tool budget or enabling HARNESS_BUDGET_HARD_STOP."
83
- : "No automatic router change; metrics within nominal band.",
84
- };
85
-
86
- await import("node:fs/promises").then(({ mkdir, writeFile }) =>
87
- mkdir(dirname(OUT), { recursive: true }).then(() =>
88
- writeFile(OUT, `${JSON.stringify(proposal, null, 2)}\n`),
89
- ),
90
- );
91
-
92
- console.log(JSON.stringify(proposal, null, 2));
93
- console.log(`\nWrote ${OUT}`);
94
- }
95
-
96
- main().catch((err) => {
97
- console.error(err);
98
- process.exit(1);
99
- });
@@ -1,114 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://ultimate-pi.local/.pi/harness/specs/router-tuning-proposal.schema.json",
4
- "title": "RouterTuningProposal",
5
- "description": "Evidence-gated, approval-required proposal for model-router updates.",
6
- "type": "object",
7
- "additionalProperties": false,
8
- "required": [
9
- "schema_version",
10
- "proposal_id",
11
- "created_at",
12
- "router_path",
13
- "base_router_sha256",
14
- "candidate_router_sha256",
15
- "evidence",
16
- "status",
17
- "approval",
18
- "candidate_router"
19
- ],
20
- "properties": {
21
- "schema_version": {
22
- "type": "string",
23
- "const": "1.0.0"
24
- },
25
- "proposal_id": {
26
- "type": "string",
27
- "minLength": 1
28
- },
29
- "created_at": {
30
- "type": "string",
31
- "minLength": 1
32
- },
33
- "router_path": {
34
- "type": "string",
35
- "const": ".pi/model-router.json"
36
- },
37
- "base_router_sha256": {
38
- "type": "string",
39
- "pattern": "^[a-f0-9]{64}$"
40
- },
41
- "candidate_router_sha256": {
42
- "type": "string",
43
- "pattern": "^[a-f0-9]{64}$"
44
- },
45
- "status": {
46
- "type": "string",
47
- "enum": ["proposed", "approved_applied", "rejected"]
48
- },
49
- "evidence": {
50
- "type": "object",
51
- "additionalProperties": false,
52
- "required": [
53
- "sample_count",
54
- "min_sample_count",
55
- "success_rate_delta",
56
- "cost_per_task_delta",
57
- "regression_guard_passed",
58
- "trace_refs"
59
- ],
60
- "properties": {
61
- "sample_count": {
62
- "type": "integer",
63
- "minimum": 1
64
- },
65
- "min_sample_count": {
66
- "type": "integer",
67
- "minimum": 1
68
- },
69
- "success_rate_delta": {
70
- "type": "number"
71
- },
72
- "cost_per_task_delta": {
73
- "type": "number"
74
- },
75
- "regression_guard_passed": {
76
- "type": "boolean"
77
- },
78
- "trace_refs": {
79
- "type": "array",
80
- "items": {
81
- "type": "string",
82
- "minLength": 1
83
- }
84
- },
85
- "notes": {
86
- "type": "string"
87
- }
88
- }
89
- },
90
- "approval": {
91
- "type": "object",
92
- "additionalProperties": false,
93
- "required": ["required", "approved_by", "approved_at", "justification"],
94
- "properties": {
95
- "required": {
96
- "type": "boolean",
97
- "const": true
98
- },
99
- "approved_by": {
100
- "type": ["string", "null"]
101
- },
102
- "approved_at": {
103
- "type": ["string", "null"]
104
- },
105
- "justification": {
106
- "type": ["string", "null"]
107
- }
108
- }
109
- },
110
- "candidate_router": {
111
- "type": "object"
112
- }
113
- }
114
- }