@webpresso/agent-kit 3.1.30 → 3.2.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.

Potentially problematic release.


This version of @webpresso/agent-kit might be problematic. Click here for more details.

Files changed (257) hide show
  1. package/README.md +53 -15
  2. package/bin/_run.js +179 -19
  3. package/catalog/AGENTS.md.tpl +3 -3
  4. package/catalog/agent/agents/implementer.md +45 -0
  5. package/catalog/agent/rules/parallel-orchestration-quota.md +100 -0
  6. package/catalog/agent/rules/pre-implementation.md +28 -1
  7. package/catalog/agent/rules/supported-agent-clis.md +9 -0
  8. package/catalog/agent/rules/typescript-version.md +50 -0
  9. package/catalog/agent/skills/codex/SKILL.md +25 -1
  10. package/catalog/agent/skills/verify/SKILL.md +4 -2
  11. package/catalog/docs/templates/blueprint.md +1 -1
  12. package/dist/esm/audit/agents.js +1 -0
  13. package/dist/esm/audit/blueprint-lifecycle-sql.d.ts +12 -0
  14. package/dist/esm/audit/blueprint-lifecycle-sql.js +23 -2
  15. package/dist/esm/audit/blueprint-pr-coverage.js +4 -0
  16. package/dist/esm/audit/ci-guardrails-wiring.d.ts +22 -0
  17. package/dist/esm/audit/ci-guardrails-wiring.js +90 -0
  18. package/dist/esm/audit/ci-test-perf.js +30 -0
  19. package/dist/esm/audit/command-surface.js +4 -2
  20. package/dist/esm/audit/host-substitution-risk.d.ts +2 -0
  21. package/dist/esm/audit/host-substitution-risk.js +256 -0
  22. package/dist/esm/audit/registry.d.ts +4 -4
  23. package/dist/esm/audit/registry.js +8 -1
  24. package/dist/esm/audit/toolchain-isolation.js +1 -2
  25. package/dist/esm/audit/typescript-version.d.ts +2 -0
  26. package/dist/esm/audit/typescript-version.js +123 -0
  27. package/dist/esm/blueprint/core/parser.js +43 -1
  28. package/dist/esm/blueprint/core/validation/criteria.d.ts +14 -0
  29. package/dist/esm/blueprint/core/validation/criteria.js +41 -2
  30. package/dist/esm/blueprint/core/validation/state.js +25 -14
  31. package/dist/esm/blueprint/db/migrations/run.js +4 -2
  32. package/dist/esm/blueprint/lifecycle/audit.d.ts +20 -0
  33. package/dist/esm/blueprint/lifecycle/audit.js +65 -10
  34. package/dist/esm/blueprint/lifecycle/canonicalize.d.ts +6 -0
  35. package/dist/esm/blueprint/lifecycle/canonicalize.js +135 -0
  36. package/dist/esm/blueprint/lifecycle/local.d.ts +2 -1
  37. package/dist/esm/blueprint/lifecycle/local.js +19 -3
  38. package/dist/esm/blueprint/lifecycle/review-provenance.js +36 -11
  39. package/dist/esm/blueprint/service/BlueprintCreationService.d.ts +1 -0
  40. package/dist/esm/blueprint/service/BlueprintCreationService.js +53 -4
  41. package/dist/esm/blueprint/service/blueprint-tech-debt-links.js +16 -2
  42. package/dist/esm/blueprint/trust/command-runner.d.ts +26 -0
  43. package/dist/esm/blueprint/trust/command-runner.js +148 -0
  44. package/dist/esm/blueprint/trust/gates.d.ts +7 -0
  45. package/dist/esm/blueprint/trust/gates.js +20 -0
  46. package/dist/esm/blueprint/trust/promotion.d.ts +8 -0
  47. package/dist/esm/blueprint/trust/promotion.js +62 -112
  48. package/dist/esm/blueprint/trust/scaffold.d.ts +19 -0
  49. package/dist/esm/blueprint/trust/scaffold.js +64 -0
  50. package/dist/esm/blueprint/trust/validator.d.ts +1 -0
  51. package/dist/esm/blueprint/trust/validator.js +7 -1
  52. package/dist/esm/blueprint/utils/archive.js +27 -5
  53. package/dist/esm/blueprint/utils/document-paths.d.ts +18 -0
  54. package/dist/esm/blueprint/utils/document-paths.js +45 -12
  55. package/dist/esm/build/cli-mcp-parity.js +10 -0
  56. package/dist/esm/cli/bundle/commands/blueprint.d.ts +1 -0
  57. package/dist/esm/cli/bundle/commands/blueprint.js +1 -0
  58. package/dist/esm/cli/cli.d.ts +1 -1
  59. package/dist/esm/cli/cli.js +34 -0
  60. package/dist/esm/cli/commands/agent-launch.d.ts +6 -1
  61. package/dist/esm/cli/commands/agent-launch.js +82 -4
  62. package/dist/esm/cli/commands/audit-core.d.ts +1 -1
  63. package/dist/esm/cli/commands/audit-core.js +8 -1
  64. package/dist/esm/cli/commands/audit.js +17 -5
  65. package/dist/esm/cli/commands/blueprint/execution.js +18 -6
  66. package/dist/esm/cli/commands/blueprint/mutations.js +59 -40
  67. package/dist/esm/cli/commands/blueprint/router-dispatch.d.ts +2 -1
  68. package/dist/esm/cli/commands/blueprint/router-dispatch.js +20 -1
  69. package/dist/esm/cli/commands/blueprint/router-output.d.ts +21 -0
  70. package/dist/esm/cli/commands/blueprint/router-output.js +48 -17
  71. package/dist/esm/cli/commands/blueprint/router.d.ts +7 -0
  72. package/dist/esm/cli/commands/blueprint/router.js +13 -1
  73. package/dist/esm/cli/commands/ci-preflight.d.ts +13 -2
  74. package/dist/esm/cli/commands/ci-preflight.js +6 -3
  75. package/dist/esm/cli/commands/compile.js +5 -31
  76. package/dist/esm/cli/commands/dash/delivery-status.d.ts +1 -0
  77. package/dist/esm/cli/commands/dash/delivery-status.js +11 -4
  78. package/dist/esm/cli/commands/doctor.js +5 -0
  79. package/dist/esm/cli/commands/hook.d.ts +5 -0
  80. package/dist/esm/cli/commands/hook.js +15 -9
  81. package/dist/esm/cli/commands/init/config.js +2 -2
  82. package/dist/esm/cli/commands/init/convergence-apply.d.ts +24 -0
  83. package/dist/esm/cli/commands/init/convergence-apply.js +221 -0
  84. package/dist/esm/cli/commands/init/convergence-state.d.ts +13 -0
  85. package/dist/esm/cli/commands/init/convergence-state.js +54 -0
  86. package/dist/esm/cli/commands/init/convergence.d.ts +23 -0
  87. package/dist/esm/cli/commands/init/convergence.js +57 -0
  88. package/dist/esm/cli/commands/init/git-convergence.d.ts +19 -0
  89. package/dist/esm/cli/commands/init/git-convergence.js +168 -0
  90. package/dist/esm/cli/commands/init/gitignore-patcher.js +2 -0
  91. package/dist/esm/cli/commands/init/grok-privacy-smoke.d.ts +52 -0
  92. package/dist/esm/cli/commands/init/grok-privacy-smoke.js +91 -0
  93. package/dist/esm/cli/commands/init/host-native-proof.d.ts +18 -0
  94. package/dist/esm/cli/commands/init/host-native-proof.js +88 -0
  95. package/dist/esm/cli/commands/init/host-visibility.d.ts +2 -2
  96. package/dist/esm/cli/commands/init/host-visibility.js +94 -5
  97. package/dist/esm/cli/commands/init/index.d.ts +1 -0
  98. package/dist/esm/cli/commands/init/index.js +326 -173
  99. package/dist/esm/cli/commands/init/mcp-spec.d.ts +57 -0
  100. package/dist/esm/cli/commands/init/mcp-spec.js +273 -0
  101. package/dist/esm/cli/commands/init/merge.d.ts +1 -0
  102. package/dist/esm/cli/commands/init/merge.js +30 -1
  103. package/dist/esm/cli/commands/init/plugin-cache-prune.d.ts +0 -3
  104. package/dist/esm/cli/commands/init/plugin-cache-prune.js +0 -1
  105. package/dist/esm/cli/commands/init/scaffold-agents-md.d.ts +1 -1
  106. package/dist/esm/cli/commands/init/scaffold-agents-md.js +9 -3
  107. package/dist/esm/cli/commands/init/scaffold-base-kit.d.ts +11 -0
  108. package/dist/esm/cli/commands/init/scaffold-base-kit.js +56 -1
  109. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.d.ts +14 -8
  110. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.js +41 -24
  111. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.d.ts +2 -0
  112. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.js +51 -23
  113. package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.d.ts +12 -31
  114. package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.js +288 -202
  115. package/dist/esm/cli/commands/init/scaffolders/file-transaction.d.ts +7 -0
  116. package/dist/esm/cli/commands/init/scaffolders/file-transaction.js +58 -0
  117. package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.d.ts +38 -0
  118. package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.js +73 -0
  119. package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.d.ts +21 -0
  120. package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.js +559 -63
  121. package/dist/esm/cli/commands/init/untracked-collision.d.ts +14 -0
  122. package/dist/esm/cli/commands/init/untracked-collision.js +42 -0
  123. package/dist/esm/cli/commands/opencode-rotate.d.ts +49 -0
  124. package/dist/esm/cli/commands/opencode-rotate.js +135 -0
  125. package/dist/esm/cli/commands/public-readiness.d.ts +11 -0
  126. package/dist/esm/cli/commands/public-readiness.js +42 -0
  127. package/dist/esm/cli/commands/review.d.ts +35 -3
  128. package/dist/esm/cli/commands/review.js +729 -209
  129. package/dist/esm/cli/commands/run-wait.d.ts +2 -0
  130. package/dist/esm/cli/commands/run-wait.js +122 -0
  131. package/dist/esm/cli/commands/setup-help.js +1 -1
  132. package/dist/esm/cli/commands/setup-repair-help.js +1 -1
  133. package/dist/esm/cli/commands/worktree/router-dispatch.js +13 -8
  134. package/dist/esm/cli/direct-provider-launch.js +9 -5
  135. package/dist/esm/cli/optional-tool-freshness.d.ts +27 -0
  136. package/dist/esm/cli/optional-tool-freshness.js +219 -9
  137. package/dist/esm/daemon/domains/git-actions.d.ts +29 -0
  138. package/dist/esm/daemon/domains/git-actions.js +136 -0
  139. package/dist/esm/daemon/domains/run-registry-interop.d.ts +16 -0
  140. package/dist/esm/daemon/domains/run-registry-interop.js +45 -0
  141. package/dist/esm/daemon/domains/sessions-search.d.ts +11 -0
  142. package/dist/esm/daemon/domains/sessions-search.js +29 -0
  143. package/dist/esm/daemon/handlers/blueprints-handlers.d.ts +5 -0
  144. package/dist/esm/daemon/handlers/blueprints-handlers.js +36 -0
  145. package/dist/esm/daemon/handlers/deploy-handlers.d.ts +6 -0
  146. package/dist/esm/daemon/handlers/deploy-handlers.js +5 -0
  147. package/dist/esm/daemon/handlers/fleet-handlers.d.ts +15 -0
  148. package/dist/esm/daemon/handlers/fleet-handlers.js +91 -0
  149. package/dist/esm/daemon/handlers/git-handlers.d.ts +6 -0
  150. package/dist/esm/daemon/handlers/git-handlers.js +27 -0
  151. package/dist/esm/daemon/handlers/product.d.ts +7 -0
  152. package/dist/esm/daemon/handlers/product.js +10 -119
  153. package/dist/esm/daemon/handlers/sessions-handlers.d.ts +12 -0
  154. package/dist/esm/daemon/handlers/sessions-handlers.js +31 -0
  155. package/dist/esm/daemon/handlers/shared.d.ts +5 -0
  156. package/dist/esm/daemon/handlers/shared.js +16 -0
  157. package/dist/esm/daemon/methods.d.ts +8 -1
  158. package/dist/esm/daemon/methods.js +7 -0
  159. package/dist/esm/daemon/protocol/contract.d.ts +43 -0
  160. package/dist/esm/daemon/protocol/contract.js +26 -0
  161. package/dist/esm/daemon/protocol/index.d.ts +1 -1
  162. package/dist/esm/daemon/protocol/index.js +1 -1
  163. package/dist/esm/hooks/__conformance__/matrix.d.ts +6 -0
  164. package/dist/esm/hooks/__conformance__/matrix.js +137 -0
  165. package/dist/esm/hooks/conformance/batch.js +5 -0
  166. package/dist/esm/hooks/doctor.d.ts +3 -3
  167. package/dist/esm/hooks/doctor.js +30 -15
  168. package/dist/esm/hooks/permission-request/index.js +9 -3
  169. package/dist/esm/hooks/permission-request/policy.d.ts +9 -0
  170. package/dist/esm/hooks/permission-request/policy.js +13 -0
  171. package/dist/esm/hooks/pretool-guard/dev-routing.d.ts +9 -0
  172. package/dist/esm/hooks/pretool-guard/dev-routing.js +41 -5
  173. package/dist/esm/hooks/pretool-guard/logger.d.ts +7 -0
  174. package/dist/esm/hooks/pretool-guard/logger.js +16 -0
  175. package/dist/esm/hooks/pretool-guard/runner.d.ts +6 -0
  176. package/dist/esm/hooks/pretool-guard/runner.js +68 -16
  177. package/dist/esm/hooks/pretool-guard/validators/blueprint.js +30 -10
  178. package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.js +54 -0
  179. package/dist/esm/hooks/pretool-guard/validators/index.d.ts +7 -0
  180. package/dist/esm/hooks/pretool-guard/validators/index.js +21 -0
  181. package/dist/esm/hooks/pretool-guard/validators/path-contract.d.ts +19 -0
  182. package/dist/esm/hooks/pretool-guard/validators/path-contract.js +25 -8
  183. package/dist/esm/hooks/shared/guard-outcome.d.ts +149 -0
  184. package/dist/esm/hooks/shared/guard-outcome.js +215 -0
  185. package/dist/esm/hooks/shared/hook-bootstrap.d.ts +26 -0
  186. package/dist/esm/hooks/shared/hook-bootstrap.js +64 -1
  187. package/dist/esm/hooks/shared/types.d.ts +8 -5
  188. package/dist/esm/hooks/shared/types.js +23 -8
  189. package/dist/esm/hooks/stop/qa-changed-files.d.ts +11 -0
  190. package/dist/esm/hooks/stop/qa-changed-files.js +74 -0
  191. package/dist/esm/mcp/blueprint/_shared/lifecycle.js +14 -1
  192. package/dist/esm/mcp/blueprint/handlers/document-mutations.js +78 -4
  193. package/dist/esm/mcp/blueprint/handlers/review-log.js +8 -1
  194. package/dist/esm/mcp/blueprint/handlers/task-advance.js +113 -54
  195. package/dist/esm/mcp/blueprint/handlers/task-verify.js +39 -19
  196. package/dist/esm/mcp/blueprint/registration.js +3 -2
  197. package/dist/esm/mcp/server.d.ts +1 -0
  198. package/dist/esm/mcp/server.js +27 -0
  199. package/dist/esm/mcp/tools/_names.d.ts +1 -1
  200. package/dist/esm/mcp/tools/_names.js +5 -0
  201. package/dist/esm/mcp/tools/_registry.js +10 -0
  202. package/dist/esm/mcp/tools/_shared/audit-kinds.d.ts +1 -1
  203. package/dist/esm/mcp/tools/_shared/result.js +44 -1
  204. package/dist/esm/mcp/tools/audit.d.ts +4 -1
  205. package/dist/esm/mcp/tools/audit.js +30 -0
  206. package/dist/esm/mcp/tools/audits.d.ts +3 -0
  207. package/dist/esm/mcp/tools/ci-preflight.d.ts +50 -0
  208. package/dist/esm/mcp/tools/ci-preflight.js +183 -0
  209. package/dist/esm/mcp/tools/pr-upsert.js +39 -1
  210. package/dist/esm/mcp/tools/review-run.d.ts +28 -0
  211. package/dist/esm/mcp/tools/review-run.js +216 -0
  212. package/dist/esm/mcp/tools/run-wait.d.ts +86 -0
  213. package/dist/esm/mcp/tools/run-wait.js +593 -0
  214. package/dist/esm/mcp/tools/session-id.d.ts +3 -0
  215. package/dist/esm/mcp/tools/session-id.js +45 -0
  216. package/dist/esm/mcp/tools/session-info.d.ts +3 -0
  217. package/dist/esm/mcp/tools/session-info.js +49 -0
  218. package/dist/esm/output-transforms/audit.d.ts +23 -0
  219. package/dist/esm/output-transforms/audit.js +47 -0
  220. package/dist/esm/output-transforms/index.js +2 -0
  221. package/dist/esm/review/authority.js +13 -5
  222. package/dist/esm/review/availability.d.ts +22 -0
  223. package/dist/esm/review/availability.js +107 -20
  224. package/dist/esm/review/delivery-verifier.d.ts +27 -0
  225. package/dist/esm/review/delivery-verifier.js +115 -0
  226. package/dist/esm/review/events.d.ts +3 -2
  227. package/dist/esm/review/events.js +23 -3
  228. package/dist/esm/review/execution/adapters.js +26 -9
  229. package/dist/esm/review/execution/output-policy.d.ts +2 -0
  230. package/dist/esm/review/execution/output-policy.js +12 -0
  231. package/dist/esm/review/execution/review-checkout.js +87 -6
  232. package/dist/esm/review/execution/supervisor.js +5 -0
  233. package/dist/esm/review/execution/types.d.ts +8 -0
  234. package/dist/esm/review/opencode-account.d.ts +24 -0
  235. package/dist/esm/review/opencode-account.js +68 -0
  236. package/dist/esm/review/opencode-auth.d.ts +33 -0
  237. package/dist/esm/review/opencode-auth.js +79 -0
  238. package/dist/esm/review/subject.d.ts +12 -0
  239. package/dist/esm/review/subject.js +74 -22
  240. package/dist/esm/runtime/opencode-account-materializer.d.ts +34 -0
  241. package/dist/esm/runtime/opencode-account-materializer.js +33 -0
  242. package/dist/esm/status/snapshot.js +30 -19
  243. package/dist/esm/test/duration-sequencer.d.ts +20 -0
  244. package/dist/esm/test/duration-sequencer.js +54 -0
  245. package/dist/esm/test/shard-durations.json +922 -0
  246. package/dist/esm/test/worker-budget.d.ts +6 -0
  247. package/dist/esm/test/worker-budget.js +59 -1
  248. package/dist/esm/test-helpers/global-setup.d.ts +1 -1
  249. package/dist/esm/test-helpers/global-setup.js +68 -24
  250. package/dist/esm/ultragoal/service.d.ts +7 -0
  251. package/dist/esm/ultragoal/service.js +42 -2
  252. package/dist/esm/utils/write-json-file.js +3 -1
  253. package/dist/esm/worktrees/codex-project-trust.d.ts +15 -0
  254. package/dist/esm/worktrees/codex-project-trust.js +56 -0
  255. package/dist/esm/worktrees/registry.d.ts +8 -0
  256. package/dist/esm/worktrees/registry.js +18 -3
  257. package/package.json +16 -13
@@ -1,11 +1,13 @@
1
1
  import path from "node:path";
2
2
  import { z } from "zod";
3
3
  import { evaluateApprovalReviewers } from "#lifecycle/audit.js";
4
+ import { collectV2ReviewProvenance } from "#lifecycle/review-provenance.js";
4
5
  import { evaluateRequiredChecks } from "#mcp/tools/_shared/required-checks.js";
5
6
  import { redactText } from "#mcp/tools/_shared/redact.js";
6
7
  import { runCommand } from "#mcp/tools/_shared/run-command.js";
7
8
  import { readReviewAuthorityAtRef } from "#review/authority.js";
8
9
  import { resolveBlueprintRoot } from "#utils/blueprint-root.js";
10
+ import { parseBlueprintDocumentRelativePath } from "#utils/document-paths.js";
9
11
  export const statusLevelSchema = z.enum(["ready", "blocked", "partial", "unknown"]);
10
12
  export const requiredCheckEvaluationSchema = z.object({
11
13
  total: z.number().int().nonnegative(),
@@ -80,6 +82,11 @@ export const wpStatusSnapshotSchema = z.object({
80
82
  });
81
83
  const DEFAULT_TIMEOUT_MS = 30_000;
82
84
  const DEFAULT_MAX_OUTPUT_BYTES = 64_000;
85
+ // `gh pr view --json` includes the PR `body`, which alone can exceed the small
86
+ // caller diagnostic budget (GitHub bodies run to tens of KB). Parse that JSON
87
+ // against a generous semantic budget so mergeability/checks/blueprint-linkage
88
+ // fields are never lost to truncation; diagnostics keep the small caller budget.
89
+ const PR_VIEW_SEMANTIC_MAX_OUTPUT_BYTES = 1_048_576;
83
90
  const DISCLOSURE_FIELDS = [
84
91
  "Execution model(s)",
85
92
  "Planning/refinement model(s)",
@@ -115,8 +122,8 @@ async function probe(cwd, command, args, options = {}) {
115
122
  cwd,
116
123
  timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
117
124
  });
125
+ const maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
118
126
  if ("error" in outcome) {
119
- const maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
120
127
  return {
121
128
  passed: false,
122
129
  semanticStdout: "",
@@ -125,11 +132,11 @@ async function probe(cwd, command, args, options = {}) {
125
132
  missingBinary: outcome.error.code === "ENOENT",
126
133
  };
127
134
  }
128
- const maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
135
+ const semanticMaxOutputBytes = options.semanticMaxOutputBytes ?? maxOutputBytes;
129
136
  return {
130
137
  passed: outcome.exitCode === 0,
131
- semanticStdout: clipBytes(outcome.stdout, maxOutputBytes),
132
- semanticTruncated: Buffer.byteLength(outcome.stdout, "utf8") > maxOutputBytes,
138
+ semanticStdout: clipBytes(outcome.stdout, semanticMaxOutputBytes),
139
+ semanticTruncated: Buffer.byteLength(outcome.stdout, "utf8") > semanticMaxOutputBytes,
133
140
  stdout: clipDiagnostic(outcome.stdout, maxOutputBytes),
134
141
  stderr: clipDiagnostic(outcome.stderr, maxOutputBytes),
135
142
  exitCode: outcome.exitCode,
@@ -307,33 +314,29 @@ function selectBlueprintFile(projectRoot, pr) {
307
314
  const prefix = `${root}/`;
308
315
  if (!file.path.startsWith(prefix))
309
316
  continue;
310
- const segments = file.path.slice(prefix.length).split("/");
311
- if (segments.length < 3 ||
312
- segments.at(-1) !== "_overview.md" ||
313
- segments.some((segment) => segment.length === 0 || segment === "." || segment === "..")) {
314
- continue;
315
- }
316
- const stableSlug = segments.slice(1, -1).join("/");
317
- if (stableSlug)
318
- return [{ ...file, stableSlug }];
317
+ const parsed = parseBlueprintDocumentRelativePath(file.path.slice(prefix.length));
318
+ if (parsed)
319
+ return [{ ...file, stableSlug: parsed.slug }];
319
320
  }
320
321
  return [];
321
322
  });
322
323
  const priority = (file) => file.changeType === "ADDED" ? 0 : file.changeType === "RENAMED" ? 1 : 2;
323
324
  return candidates.toSorted((left, right) => priority(left) - priority(right))[0];
324
325
  }
325
- function resolveBlueprintEvidence(cwd, projectRoot, pr, targetHash) {
326
+ function resolveBlueprintEvidence(projectRoot, pr, targetHash) {
326
327
  const blueprintFile = selectBlueprintFile(projectRoot, pr);
327
328
  if (!blueprintFile || !targetHash)
328
329
  return undefined;
329
330
  try {
330
- const authority = readReviewAuthorityAtRef(cwd, targetHash, blueprintFile.stableSlug, "delivery");
331
+ const authority = readReviewAuthorityAtRef(projectRoot, targetHash, blueprintFile.stableSlug, "delivery");
331
332
  if (authority.blueprintPath !== blueprintFile.path)
332
333
  return undefined;
334
+ const approvals = collectV2ReviewProvenance(path.resolve(projectRoot, blueprintFile.path), "delivery", targetHash);
333
335
  return {
334
336
  path: blueprintFile.path,
335
337
  lifecycle: authority.lifecycle,
336
- approvalsSatisfied: evaluateApprovalReviewers(authority.approvals.map((approval) => approval.reviewer)).satisfied,
338
+ approvalsSatisfied: evaluateApprovalReviewers(approvals.map((approval) => approval.reviewer))
339
+ .satisfied,
337
340
  };
338
341
  }
339
342
  catch {
@@ -582,7 +585,10 @@ export async function buildStatusSnapshot(options = {}) {
582
585
  "files",
583
586
  ].join(",");
584
587
  const [view, checksProbe] = await Promise.all([
585
- probe(cwd, "gh", ["pr", "view", ...selector, "--json", fields], probeOptions),
588
+ probe(cwd, "gh", ["pr", "view", ...selector, "--json", fields], {
589
+ ...probeOptions,
590
+ semanticMaxOutputBytes: PR_VIEW_SEMANTIC_MAX_OUTPUT_BYTES,
591
+ }),
586
592
  probe(cwd, "gh", ["pr", "checks", ...selector, "--required", "--json", "name,state,bucket,link,description"], probeOptions),
587
593
  ]);
588
594
  pr = view.passed ? parseJsonObject(view.semanticStdout) : undefined;
@@ -599,7 +605,7 @@ export async function buildStatusSnapshot(options = {}) {
599
605
  readGreptileComments(cwd, pr, probeOptions),
600
606
  ])
601
607
  : [{ complete: false, warning: "PR metadata unavailable." }, { comments: [] }];
602
- const blueprint = resolveBlueprintEvidence(cwd, firstLine(topLevel.semanticStdout) ?? cwd, pr, localHead);
608
+ const blueprint = resolveBlueprintEvidence(firstLine(topLevel.semanticStdout) ?? cwd, pr, localHead);
603
609
  const readiness = evaluatePrReadiness({
604
610
  localHead,
605
611
  dirtyWorktree,
@@ -649,9 +655,14 @@ export async function buildStatusSnapshot(options = {}) {
649
655
  threadsComplete: threads.complete,
650
656
  greptile: classifyGreptile(checks ?? [], greptileComments.comments, stringField(pr?.headRefOid)),
651
657
  };
658
+ // `body` is fully consumed above (release-evidence + disclosure via
659
+ // `evaluatePrReadiness`, blueprint linkage via `resolveBlueprintEvidence`),
660
+ // so drop it from the emitted metadata to keep the payload from re-ballooning
661
+ // to the size that truncated the parse in the first place.
662
+ const { body: _body, ...metadataWithoutBody } = pr ?? {};
652
663
  context.pr = {
653
664
  selector: selector[0],
654
- metadata: pr,
665
+ metadata: pr ? metadataWithoutBody : undefined,
655
666
  checks: readiness.checks
656
667
  ? { ...readiness.checks, checks: [...readiness.checks.checks] }
657
668
  : undefined,
@@ -0,0 +1,20 @@
1
+ import { BaseSequencer, type TestSpecification } from "vitest/node";
2
+ export declare function weightFor(project: string, relativePath: string): number;
3
+ interface WeightedSpec {
4
+ readonly spec: TestSpecification;
5
+ readonly weight: number;
6
+ readonly key: string;
7
+ }
8
+ /**
9
+ * Deterministic greedy LPT partition of `specs` into `count` bins. Files are
10
+ * sorted heaviest-first (ties broken by path so the order is stable across
11
+ * every shard job), then each is placed into the currently-lightest bin (ties
12
+ * broken by lowest bin index). Returns all bins in index order.
13
+ *
14
+ * Exported for the contract test; the sequencer only needs one bin.
15
+ */
16
+ export declare function partitionByDuration(specs: readonly WeightedSpec[], count: number): readonly (readonly WeightedSpec[])[];
17
+ export declare class DurationSequencer extends BaseSequencer {
18
+ shard(files: TestSpecification[]): Promise<TestSpecification[]>;
19
+ }
20
+ export {};
@@ -0,0 +1,54 @@
1
+ import { relative } from "node:path";
2
+ import { BaseSequencer } from "vitest/node";
3
+ import rawSnapshot from "./shard-durations.json" with { type: "json" };
4
+ const snapshot = rawSnapshot;
5
+ // A generated snapshot always carries a positive defaultWeight; clamp to 1 only
6
+ // to keep LPT well-defined if the JSON is ever hand-truncated to nothing.
7
+ const DEFAULT_WEIGHT = snapshot.defaultWeight > 0 ? snapshot.defaultWeight : 1;
8
+ export function weightFor(project, relativePath) {
9
+ return snapshot.durations[project]?.[relativePath] ?? DEFAULT_WEIGHT;
10
+ }
11
+ /**
12
+ * Deterministic greedy LPT partition of `specs` into `count` bins. Files are
13
+ * sorted heaviest-first (ties broken by path so the order is stable across
14
+ * every shard job), then each is placed into the currently-lightest bin (ties
15
+ * broken by lowest bin index). Returns all bins in index order.
16
+ *
17
+ * Exported for the contract test; the sequencer only needs one bin.
18
+ */
19
+ export function partitionByDuration(specs, count) {
20
+ const bins = Array.from({ length: count }, () => []);
21
+ const loads = Array.from({ length: count }, () => 0);
22
+ const ordered = [...specs].sort((a, b) => b.weight !== a.weight ? b.weight - a.weight : a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
23
+ for (const item of ordered) {
24
+ let target = 0;
25
+ let targetLoad = loads[0] ?? 0;
26
+ for (let i = 1; i < count; i += 1) {
27
+ const load = loads[i] ?? 0;
28
+ if (load < targetLoad) {
29
+ target = i;
30
+ targetLoad = load;
31
+ }
32
+ }
33
+ // target is always in [0, count): bins/loads were sized to `count`.
34
+ (bins[target] ??= []).push(item);
35
+ loads[target] = targetLoad + item.weight;
36
+ }
37
+ return bins;
38
+ }
39
+ export class DurationSequencer extends BaseSequencer {
40
+ async shard(files) {
41
+ const { config } = this.ctx;
42
+ // No --shard (serial lane, local full runs): nothing to partition.
43
+ if (!config.shard)
44
+ return files;
45
+ const { index, count } = config.shard;
46
+ const weighted = files.map((spec) => {
47
+ const key = relative(config.root, spec.moduleId);
48
+ return { spec, key, weight: weightFor(spec.project.name, key) };
49
+ });
50
+ const bins = partitionByDuration(weighted, count);
51
+ // index is 1-based in [1, count]; the bin is always present.
52
+ return (bins[index - 1] ?? []).map((item) => item.spec);
53
+ }
54
+ }