@pareto4/pp-core 1.13.0 → 1.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/.claude-plugin/plugin.json +3 -3
  2. package/README.md +26 -9
  3. package/agents/pp-code-reviewer.md +2 -1
  4. package/agents/pp-debug-session-manager.md +9 -6
  5. package/agents/pp-executor.md +10 -13
  6. package/agents/pp-plan-checker.md +4 -4
  7. package/agents/pp-planner.md +23 -9
  8. package/agents/pp-vault-reviewer.md +244 -21
  9. package/agents/pp-verifier.md +7 -3
  10. package/bin/install.js +10 -3
  11. package/commands/pp-execute-phase.md +1 -3
  12. package/commands/pp-ns-review.md +1 -1
  13. package/commands/pp-plan-phase.md +1 -2
  14. package/commands/pp-vault-review.md +5 -3
  15. package/commands/pp-verify-work.md +1 -2
  16. package/gemini-extension.json +1 -1
  17. package/hooks/dist/pp-check-update.js +0 -0
  18. package/hooks/dist/pp-cursor-session-start.js +1 -1
  19. package/hooks/dist/pp-statusline.js +1 -1
  20. package/hooks/dist/pp-update-banner.js +0 -0
  21. package/hooks/pp-check-update.js +0 -0
  22. package/hooks/pp-cursor-session-start.js +1 -1
  23. package/hooks/pp-statusline.js +1 -1
  24. package/hooks/pp-update-banner.js +0 -0
  25. package/package.json +14 -19
  26. package/pareto-skills/_shared/create-project-board.sh +0 -0
  27. package/pareto-skills/pp-project-setup/SKILL.md +1 -1
  28. package/pp-core/bin/check-latest-version.cjs +0 -0
  29. package/pp-core/bin/detect-build-commands.sh +2 -2
  30. package/pp-core/bin/lib/capability-activation.cjs +83 -9
  31. package/pp-core/bin/lib/capability-registry.cjs +396 -82
  32. package/pp-core/bin/lib/capability-state.cjs +160 -4
  33. package/pp-core/bin/lib/capability-writer.cjs +19 -5
  34. package/pp-core/bin/lib/check-command-router.cjs +3334 -946
  35. package/pp-core/bin/lib/clusters.cjs +3 -0
  36. package/pp-core/bin/lib/command-aliases.cjs +0 -35
  37. package/pp-core/bin/lib/commands.cjs +9 -4
  38. package/pp-core/bin/lib/compose-bindings.cjs +251 -88
  39. package/pp-core/bin/lib/config-loader.cjs +7 -103
  40. package/pp-core/bin/lib/config-schema.cjs +1 -1
  41. package/pp-core/bin/lib/config.cjs +154 -62
  42. package/pp-core/bin/lib/decisions.cjs +4 -4
  43. package/pp-core/bin/lib/discovery-vault-check.cjs +246 -0
  44. package/pp-core/bin/lib/frontmatter.cjs +1 -38
  45. package/pp-core/bin/lib/git-base-branch.cjs +13 -11
  46. package/pp-core/bin/lib/git-provider.cjs +4 -4
  47. package/pp-core/bin/lib/init-command-router.cjs +5 -8
  48. package/pp-core/bin/lib/init-contract.cjs +648 -738
  49. package/pp-core/bin/lib/init-interactive.cjs +76 -4
  50. package/pp-core/bin/lib/init.cjs +24 -51
  51. package/pp-core/bin/lib/install-profiles.cjs +1 -1
  52. package/pp-core/bin/lib/io.cjs +8 -0
  53. package/pp-core/bin/lib/loop-resolver.cjs +189 -129
  54. package/pp-core/bin/lib/org-profile.cjs +469 -152
  55. package/pp-core/bin/lib/package-identity.cjs +3 -3
  56. package/pp-core/bin/lib/phase-command-router.cjs +1 -29
  57. package/pp-core/bin/lib/phase-scope.cjs +1 -1
  58. package/pp-core/bin/lib/phase.cjs +11 -253
  59. package/pp-core/bin/lib/platform-bindings.cjs +40 -19
  60. package/pp-core/bin/lib/practices-review-check.cjs +15 -9
  61. package/pp-core/bin/lib/profile-output.cjs +1 -1
  62. package/pp-core/bin/lib/shell-command-projection.cjs +104 -1
  63. package/pp-core/bin/lib/state.cjs +11 -85
  64. package/pp-core/bin/lib/template.cjs +1 -1
  65. package/pp-core/bin/lib/vault-audit.cjs +650 -126
  66. package/pp-core/bin/lib/vault-command-router.cjs +2604 -367
  67. package/pp-core/bin/lib/vault-coordinates.cjs +13 -4
  68. package/pp-core/bin/lib/vault-index.cjs +699 -0
  69. package/pp-core/bin/lib/vault-mode.cjs +235 -0
  70. package/pp-core/bin/lib/vault-practices.cjs +139 -72
  71. package/pp-core/bin/lib/vault-review.cjs +194 -451
  72. package/pp-core/bin/lib/vault-seal.cjs +1936 -0
  73. package/pp-core/bin/lib/vault-standards.cjs +1505 -0
  74. package/pp-core/bin/lib/vault-trace.cjs +607 -254
  75. package/pp-core/bin/lib/vault-update.cjs +9 -33
  76. package/pp-core/bin/lib/vault-write-back.cjs +70 -42
  77. package/pp-core/bin/lib/vault.cjs +2734 -920
  78. package/pp-core/bin/lib/verify.cjs +0 -11
  79. package/pp-core/bin/portable-timeout.sh +1 -1
  80. package/pp-core/bin/pp-tools.cjs +184 -54
  81. package/pp-core/bin/shared/config-defaults.manifest.json +0 -7
  82. package/pp-core/bin/shared/config-schema.manifest.json +0 -3
  83. package/pp-core/bin/shared/model-catalog.json +2 -2
  84. package/pp-core/bin/verify-reapply-patches.cjs +0 -0
  85. package/pp-core/org-profile.json +26 -0
  86. package/pp-core/references/autonomous-best-effort.md +8 -7
  87. package/pp-core/references/loop-hook-dispatch.md +0 -25
  88. package/pp-core/references/planner-gap-closure.md +0 -1
  89. package/pp-core/references/planner-tdd.md +0 -1
  90. package/pp-core/references/planner-vault-practices.md +17 -34
  91. package/pp-core/references/planner-vault-standards.md +320 -0
  92. package/pp-core/references/planning-config.md +0 -8
  93. package/pp-core/references/practice-arithmetic-contract.md +121 -0
  94. package/pp-core/references/tdd.md +0 -1
  95. package/pp-core/references/verifier-practice-verdicts.md +263 -0
  96. package/pp-core/templates/README.md +1 -0
  97. package/pp-core/templates/VAULT-REVIEW.md +202 -0
  98. package/pp-core/templates/phase-prompt.md +2 -6
  99. package/pp-core/templates/practices/README.md +20 -23
  100. package/pp-core/workflows/_runtime-launcher.snippet.sh +0 -0
  101. package/pp-core/workflows/add-tests.md +55 -4
  102. package/pp-core/workflows/audit-fix.md +63 -2
  103. package/pp-core/workflows/audit-milestone.md +1 -1
  104. package/pp-core/workflows/autonomous.md +85 -11
  105. package/pp-core/workflows/check-todos.md +13 -2
  106. package/pp-core/workflows/code-review-fix.md +59 -3
  107. package/pp-core/workflows/code-review.md +10 -1
  108. package/pp-core/workflows/complete-milestone.md +1 -1
  109. package/pp-core/workflows/debug.md +54 -4
  110. package/pp-core/workflows/discovery-sprint/prefill.md +19 -7
  111. package/pp-core/workflows/discovery-sprint/prototype.md +46 -49
  112. package/pp-core/workflows/discovery-sprint/session-13-gates.md +2 -0
  113. package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +1 -3
  114. package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +1 -3
  115. package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +1 -3
  116. package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +20 -24
  117. package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +1 -3
  118. package/pp-core/workflows/discovery-sprint/sessions/06-security.md +1 -3
  119. package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +1 -3
  120. package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +1 -3
  121. package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +1 -3
  122. package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +1 -6
  123. package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +1 -3
  124. package/pp-core/workflows/discovery-sprint/sessions/12-delivery-model.md +1 -3
  125. package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +1 -3
  126. package/pp-core/workflows/discovery-sprint/templates/context-template.md +1 -1
  127. package/pp-core/workflows/discovery-sprint/vault-context.md +213 -0
  128. package/pp-core/workflows/discovery-sprint.md +7 -3
  129. package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +4 -4
  130. package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +43 -1
  131. package/pp-core/workflows/discovery-to-build.md +10 -2
  132. package/pp-core/workflows/discuss-phase.md +3 -10
  133. package/pp-core/workflows/execute-phase/steps/check-query-gate.md +329 -0
  134. package/pp-core/workflows/execute-phase/steps/client-context-gate.md +3 -2
  135. package/pp-core/workflows/execute-phase/steps/cross-ai-delegation.md +1 -1
  136. package/pp-core/workflows/execute-phase/steps/execute-pre-dispatch.md +98 -0
  137. package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
  138. package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +6 -8
  139. package/pp-core/workflows/execute-phase/steps/vault-fetch.md +115 -14
  140. package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +322 -20
  141. package/pp-core/workflows/execute-phase/steps/verifier-practice-payload.md +165 -0
  142. package/pp-core/workflows/execute-phase/steps/verify-post-gate.md +163 -0
  143. package/pp-core/workflows/execute-phase.md +155 -128
  144. package/pp-core/workflows/execute-plan.md +56 -6
  145. package/pp-core/workflows/fast.md +53 -4
  146. package/pp-core/workflows/help/modes/full.md +3 -3
  147. package/pp-core/workflows/init/steps/client-context-capture.md +101 -0
  148. package/pp-core/workflows/init/steps/gitlab-provisioning.md +130 -0
  149. package/pp-core/workflows/init/steps/project-md-deferral-narration.md +66 -0
  150. package/pp-core/workflows/init/steps/reachability-outcome.md +70 -0
  151. package/pp-core/workflows/init.md +232 -272
  152. package/pp-core/workflows/new-project.md +31 -23
  153. package/pp-core/workflows/plan-phase.md +98 -45
  154. package/pp-core/workflows/quick.md +117 -3
  155. package/pp-core/workflows/secure-phase.md +1 -1
  156. package/pp-core/workflows/ship.md +57 -28
  157. package/pp-core/workflows/undo.md +1 -1
  158. package/pp-core/workflows/update.md +3 -3
  159. package/pp-core/workflows/validate-phase.md +58 -3
  160. package/pp-core/workflows/vault-review.md +282 -22
  161. package/pp-core/workflows/verify-work.md +12 -14
  162. package/scripts/changeset/cli.cjs +6 -5
  163. package/scripts/changeset/lint.cjs +0 -0
  164. package/scripts/changeset/new.cjs +33 -50
  165. package/scripts/dev-env.cjs +25 -85
  166. package/scripts/gen-capability-registry.cjs +199 -11
  167. package/scripts/gen-practice-arithmetic-contract.cjs +412 -0
  168. package/scripts/lib/allowlist-ratchet.cjs +1 -103
  169. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -2
  170. package/scripts/lint-docs-required.cjs +0 -0
  171. package/scripts/lint-pr-check-project-dir.cjs +1 -3
  172. package/scripts/lint-test-file-count.allowlist.json +12 -10
  173. package/scripts/practice-arithmetic-contract.allow.json +35 -0
  174. package/scripts/prompt-injection-scan.sh +22 -17
  175. package/scripts/record-vault-mode-golden.cjs +89 -0
  176. package/scripts/release-channel.cjs +0 -0
  177. package/scripts/sync-manifest-versions.cjs +5 -4
  178. package/scripts/sync-rulesets.sh +1 -1
  179. package/scripts/update-size-baseline.cjs +30 -274
  180. package/scripts/vault-calibrate.cjs +996 -0
  181. package/scripts/verify-opengsd-sweep.cjs +3 -5
  182. package/scripts/workflow-size.cjs +9 -61
  183. package/pp-core/bin/lib/dispatch-plan.cjs +0 -483
  184. package/pp-core/bin/lib/install-run.cjs +0 -536
  185. package/pp-core/bin/lib/loop-gates.cjs +0 -213
  186. package/pp-core/bin/lib/phase-manifest.cjs +0 -527
  187. package/pp-core/bin/lib/phase-tier.cjs +0 -480
  188. package/pp-core/bin/lib/plan-graph.cjs +0 -368
  189. package/pp-core/references/executor-vault-trace.md +0 -47
  190. package/pp-core/references/planner-plan-graph.md +0 -66
  191. package/pp-core/workflows/discovery-sprint/vault-fetch.md +0 -37
  192. package/pp-core/workflows/execute-phase/steps/checkpoint-handling.md +0 -45
  193. package/pp-core/workflows/execute-phase/steps/install-run.md +0 -29
  194. package/pp-core/workflows/execute-phase/steps/phase-close-rebaseline.md +0 -23
  195. package/pp-core/workflows/execute-phase/steps/serial-group-dispatch.md +0 -73
  196. package/pp-core/workflows/execute-phase/steps/vault-door-gate.md +0 -19
  197. package/pp-core/workflows/plan-phase/steps/phase-tier.md +0 -43
  198. package/scripts/lib/size-budget.cjs +0 -311
  199. package/scripts/lint-neutrality-names.cjs +0 -694
  200. package/scripts/lint-org-coordinates.allowlist.json +0 -35
  201. package/scripts/lint-org-coordinates.cjs +0 -426
@@ -4,309 +4,65 @@
4
4
  /**
5
5
  * @file update-size-baseline.cjs
6
6
  *
7
- * Regenerates the committed per-file size baselines
8
- * (`tests/workflow-size-baseline.json`, `tests/agent-size-baseline.json`) from
9
- * the current files.
7
+ * Regenerates the committed per-file workflow size baseline
8
+ * (`tests/workflow-size-baseline.json`) from the current workflow files.
10
9
  *
11
- * Workflow size budget policy (2026-10-11; per commit since pack 9): the guards
12
- * allow each commit a small DELTA BUDGET (config size_budget.*, see
13
- * scripts/lib/size-budget.cjs), so plans never run this script. It runs once per
14
- * phase, in the phase's closing commit (`--reason "phase NN close"`, from
15
- * execute-phase), and otherwise only when one commit must grow past the budget.
16
- * Because a raise is the review record of growth, RAISING any entry requires a
17
- * reason:
10
+ * Run via `npm run size:baseline` whenever a workflow file legitimately grows
11
+ * or shrinks. Growth must still be justified in the PR; this script only
12
+ * records the new reality so the CI guard (issue #1074) can diff against it.
18
13
  *
19
- * npm run size:baseline # lower / add / remove only
20
- * npm run size:baseline -- --reason "<why>" # also allowed to raise
21
- *
22
- * Without `--reason`, a run that would raise any entry is REFUSED: it exits
23
- * non-zero and writes nothing (neither baseline). With a reason, every raise is
24
- * recorded in the baseline file's `_rebaselines` array (newest last) as
25
- * `{ date, reason, deltas: [{ file, from, to, delta }] }` — the committed
26
- * review record of a deliberate growth.
27
- *
28
- * Idempotent: running it twice with no file changes produces no diff (a run
29
- * with nothing to raise never appends a `_rebaselines` entry).
14
+ * Idempotent: running it twice with no file changes produces no diff.
30
15
  */
31
16
 
32
17
  const fs = require('fs');
33
18
  const path = require('path');
34
- const { measureMdFiles, measureMdTree, WORKFLOWS_DIR } = require('./workflow-size.cjs');
19
+ const { measureMdFiles, WORKFLOWS_DIR } = require('./workflow-size.cjs');
35
20
 
36
21
  const BASELINE_PATH = path.join(__dirname, '..', 'tests', 'workflow-size-baseline.json');
37
22
  const AGENTS_DIR = path.join(__dirname, '..', 'agents');
38
23
  const AGENT_BASELINE_PATH = path.join(__dirname, '..', 'tests', 'agent-size-baseline.json');
39
- const isPpAgent = (f) => f.startsWith('pp-');
40
-
41
- /** Key of the raise log inside a baseline file. Never a measured filename. */
42
- const REBASELINES_KEY = '_rebaselines';
43
-
44
- /**
45
- * Split a parsed baseline file into its size entries and its raise log.
46
- * Size entries are the numeric values; metadata keys (`_rebaselines`) are not
47
- * sizes and must never reach a guard as one.
48
- *
49
- * @param {object|null} raw - Parsed baseline JSON (null when absent).
50
- * @returns {{ sizes: Object<string, number>, rebaselines: Array<object> }}
51
- */
52
- function splitBaseline(raw) {
53
- const sizes = {};
54
- let rebaselines = [];
55
- if (raw && typeof raw === 'object') {
56
- for (const [key, value] of Object.entries(raw)) {
57
- if (key === REBASELINES_KEY) rebaselines = value;
58
- else sizes[key] = value;
59
- }
60
- }
61
- return { sizes, rebaselines };
62
- }
63
-
64
- /**
65
- * Read and parse a baseline file; `null` when it does not exist.
66
- *
67
- * @param {string} filePath
68
- * @returns {object|null}
69
- */
70
- function readBaseline(filePath) {
71
- let text;
72
- try {
73
- text = fs.readFileSync(filePath, 'utf-8');
74
- } catch (err) {
75
- if (err.code === 'ENOENT') return null;
76
- throw err;
77
- }
78
- return JSON.parse(text);
79
- }
24
+ const isGsdAgent = (f) => f.startsWith('pp-');
80
25
 
81
26
  /**
82
- * Serialize to the on-disk baseline format: size keys sorted, then the
83
- * `_rebaselines` log last; 2-space indent, trailing newline (a stable,
84
- * minimal-diff artifact).
27
+ * Serialize a size map to the on-disk baseline format: keys sorted, 2-space
28
+ * indent, trailing newline (so the file is a stable, minimal-diff artifact).
85
29
  *
86
30
  * @param {Object<string, number>} sizes
87
- * @param {Array<object>} [rebaselines]
88
31
  * @returns {string}
89
32
  */
90
- function serializeBaseline(sizes, rebaselines = []) {
33
+ function serializeBaseline(sizes) {
91
34
  const sorted = {};
92
35
  for (const key of Object.keys(sizes).sort()) sorted[key] = sizes[key];
93
- sorted[REBASELINES_KEY] = rebaselines;
94
36
  return JSON.stringify(sorted, null, 2) + '\n';
95
37
  }
96
38
 
97
39
  /**
98
- * Classify the difference between an old and a new size map.
99
- *
100
- * @param {Object<string, number>} oldSizes
101
- * @param {Object<string, number>} newSizes
102
- * @returns {{ raised: Array<{file:string,from:number,to:number,delta:number}>,
103
- * lowered: Array<{file:string,from:number,to:number,delta:number}>,
104
- * added: string[], removed: string[] }}
105
- */
106
- function diffSizes(oldSizes, newSizes) {
107
- const raised = [];
108
- const lowered = [];
109
- const added = [];
110
- for (const file of Object.keys(newSizes).sort()) {
111
- if (!(file in oldSizes)) {
112
- added.push(file);
113
- continue;
114
- }
115
- const from = oldSizes[file];
116
- const to = newSizes[file];
117
- if (to > from) raised.push({ file, from, to, delta: to - from });
118
- else if (to < from) lowered.push({ file, from, to, delta: from - to });
119
- }
120
- const removed = Object.keys(oldSizes).filter((f) => !(f in newSizes)).sort();
121
- return { raised, lowered, added, removed };
122
- }
123
-
124
- /**
125
- * Validate a `_rebaselines` log. Returns a list of problems (empty = valid).
126
- * Every entry must carry an ISO date, a non-empty reason and a non-empty list
127
- * of positive deltas whose arithmetic holds; dates must be non-decreasing
128
- * (newest last).
129
- *
130
- * @param {unknown} log
131
- * @returns {string[]}
132
- */
133
- function validateRebaselineLog(log) {
134
- if (!Array.isArray(log)) return [`${REBASELINES_KEY} must be an array, got ${JSON.stringify(log)}`];
135
- const problems = [];
136
- const isSize = (n) => Number.isInteger(n) && n >= 0;
137
- let prevDate = '';
138
- log.forEach((entry, i) => {
139
- const at = `${REBASELINES_KEY}[${i}]`;
140
- if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
141
- problems.push(`${at} must be an object`);
142
- return;
143
- }
144
- if (typeof entry.date !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(entry.date)) {
145
- problems.push(`${at}.date must be YYYY-MM-DD, got ${JSON.stringify(entry.date)}`);
146
- } else {
147
- if (entry.date < prevDate) problems.push(`${at}.date ${entry.date} is older than the entry before it (newest must be last)`);
148
- prevDate = entry.date;
149
- }
150
- if (typeof entry.reason !== 'string' || entry.reason.trim() === '') {
151
- problems.push(`${at}.reason must be a non-empty string`);
152
- }
153
- if (!Array.isArray(entry.deltas) || entry.deltas.length === 0) {
154
- problems.push(`${at}.deltas must be a non-empty array`);
155
- return;
156
- }
157
- entry.deltas.forEach((d, j) => {
158
- const dat = `${at}.deltas[${j}]`;
159
- if (!d || typeof d.file !== 'string' || d.file === '') problems.push(`${dat}.file must be a non-empty string`);
160
- if (!d || !isSize(d.from) || !isSize(d.to)) problems.push(`${dat}.from/.to must be non-negative integers`);
161
- else if (!Number.isInteger(d.delta) || d.delta <= 0 || d.delta !== d.to - d.from) {
162
- problems.push(`${dat}.delta must be the positive difference to - from (${d.to - d.from}), got ${JSON.stringify(d.delta)}`);
163
- }
164
- });
165
- });
166
- return problems;
167
- }
168
-
169
- /**
170
- * Compute (but do not write) a regenerated baseline.
40
+ * Write a baseline file from the measured `.md` sizes in a directory.
171
41
  *
172
42
  * @param {object} [opts]
173
43
  * @param {string} [opts.dir] - Directory to measure (default: workflows).
174
- * @param {string} [opts.outPath] - Baseline file (default: workflow baseline).
175
- * @param {function(string): boolean} [opts.predicate] - File filter.
176
- * @param {function(string, function): Object<string, number>} [opts.measure] -
177
- * Measurer (default: recursive `measureMdTree`; agents pass `measureMdFiles`).
178
- * @param {string} [opts.reason] - Justification; required to raise any entry.
179
- * @param {string} [opts.today] - Date stamp for a raise (default: today, UTC).
180
- * @returns {{ outPath: string, refused: boolean, count: number, content: string|null,
181
- * change: ReturnType<typeof diffSizes> }}
44
+ * @param {string} [opts.outPath] - Baseline file to write (default: workflow).
45
+ * @param {function(string): boolean} [opts.predicate] - Filename filter.
46
+ * @returns {{ outPath: string, count: number, content: string }}
182
47
  */
183
- function planBaseline({
184
- dir = WORKFLOWS_DIR,
185
- outPath = BASELINE_PATH,
186
- predicate,
187
- measure = measureMdTree,
188
- reason,
189
- today = new Date().toISOString().slice(0, 10),
190
- } = {}) {
191
- const sizes = measure(dir, predicate);
192
- const { sizes: oldSizes, rebaselines: oldLog } = splitBaseline(readBaseline(outPath));
193
- const change = diffSizes(oldSizes, sizes);
194
- const count = Object.keys(sizes).length;
195
- const hasReason = typeof reason === 'string' && reason.trim() !== '';
196
- if (change.raised.length > 0 && !hasReason) {
197
- return { outPath, refused: true, count, content: null, change };
198
- }
199
- const log = Array.isArray(oldLog) ? [...oldLog] : [];
200
- if (change.raised.length > 0) {
201
- log.push({ date: today, reason: reason.trim(), deltas: change.raised });
202
- }
203
- return { outPath, refused: false, count, content: serializeBaseline(sizes, log), change };
204
- }
205
-
206
- /**
207
- * Regenerate one baseline file. A refused plan (a raise without a reason)
208
- * writes nothing.
209
- *
210
- * @param {Parameters<typeof planBaseline>[0]} [opts]
211
- * @returns {ReturnType<typeof planBaseline>}
212
- */
213
- function generateBaseline(opts = {}) {
214
- const plan = planBaseline(opts);
215
- if (!plan.refused) fs.writeFileSync(plan.outPath, plan.content);
216
- return plan;
217
- }
218
-
219
- /**
220
- * Parse CLI arguments: only `--reason <text>` / `--reason=<text>`.
221
- *
222
- * @param {string[]} argv
223
- * @returns {{ reason?: string }}
224
- */
225
- function parseArgs(argv) {
226
- const out = {};
227
- for (let i = 0; i < argv.length; i++) {
228
- const arg = argv[i];
229
- if (arg === '--reason') {
230
- out.reason = argv[++i];
231
- if (out.reason === undefined) throw new Error('--reason needs a value');
232
- } else if (arg.startsWith('--reason=')) {
233
- out.reason = arg.slice('--reason='.length);
234
- } else {
235
- throw new Error(`unknown argument: ${arg} (only --reason "<text>" is accepted)`);
236
- }
237
- }
238
- if (out.reason !== undefined && out.reason.trim() === '') throw new Error('--reason must not be empty');
239
- return out;
48
+ function generateBaseline({ dir = WORKFLOWS_DIR, outPath = BASELINE_PATH, predicate } = {}) {
49
+ const sizes = measureMdFiles(dir, predicate);
50
+ const content = serializeBaseline(sizes);
51
+ fs.writeFileSync(outPath, content);
52
+ return { outPath, count: Object.keys(sizes).length, content };
240
53
  }
241
54
 
242
- const TARGETS = [
243
- { label: 'workflow', dir: WORKFLOWS_DIR, outPath: BASELINE_PATH, measure: measureMdTree },
244
- { label: 'agent', dir: AGENTS_DIR, outPath: AGENT_BASELINE_PATH, predicate: isPpAgent, measure: measureMdFiles },
245
- ];
246
-
247
- /**
248
- * CLI entry. Plans every target first and writes only when none is refused,
249
- * so a refusal leaves BOTH baselines untouched.
250
- *
251
- * @param {string[]} argv
252
- * @param {object} [io]
253
- * @param {Array<object>} [io.targets]
254
- * @param {string} [io.today]
255
- * @param {NodeJS.WritableStream} [io.stdout]
256
- * @param {NodeJS.WritableStream} [io.stderr]
257
- * @returns {number} exit code
258
- */
259
- function main(argv, { targets = TARGETS, today, stdout = process.stdout, stderr = process.stderr } = {}) {
260
- let args;
261
- try {
262
- args = parseArgs(argv);
263
- } catch (err) {
264
- stderr.write(`size:baseline: ${err.message}\n`);
265
- return 2;
266
- }
267
- const plans = targets.map((t) => ({ t, plan: planBaseline({ ...t, reason: args.reason, today }) }));
268
- const refused = plans.filter((p) => p.plan.refused);
269
- if (refused.length > 0) {
270
- const lines = refused.flatMap(({ t, plan }) =>
271
- plan.change.raised.map((r) => ` - ${t.label}: ${r.file}: ${r.from} → ${r.to} (+${r.delta})`)
272
- );
273
- stderr.write(
274
- 'size:baseline: REFUSED — this run would RAISE baseline entries, which needs a reason:\n' +
275
- `${lines.join('\n')}\n` +
276
- 'Shrink the file(s), or re-run with: npm run size:baseline -- --reason "<why this growth is needed>"\n' +
277
- 'Nothing was written.\n'
278
- );
279
- return 1;
280
- }
281
- for (const { t, plan } of plans) {
282
- fs.writeFileSync(plan.outPath, plan.content);
283
- const c = plan.change;
284
- stdout.write(
285
- `Wrote ${plan.count} ${t.label} sizes to ${path.relative(process.cwd(), plan.outPath)} ` +
286
- `(raised ${c.raised.length}, lowered ${c.lowered.length}, added ${c.added.length}, removed ${c.removed.length})\n`
55
+ if (require.main === module) {
56
+ const targets = [
57
+ { label: 'workflow', dir: WORKFLOWS_DIR, outPath: BASELINE_PATH },
58
+ { label: 'agent', dir: AGENTS_DIR, outPath: AGENT_BASELINE_PATH, predicate: isGsdAgent },
59
+ ];
60
+ for (const t of targets) {
61
+ const { outPath, count } = generateBaseline(t);
62
+ process.stdout.write(
63
+ `Wrote ${count} ${t.label} sizes to ${path.relative(process.cwd(), outPath)}\n`
287
64
  );
288
65
  }
289
- if (args.reason !== undefined && plans.every((p) => p.plan.change.raised.length === 0)) {
290
- stdout.write('Note: nothing was raised, so --reason was not recorded.\n');
291
- }
292
- return 0;
293
- }
294
-
295
- if (require.main === module) {
296
- process.exitCode = main(process.argv.slice(2));
297
66
  }
298
67
 
299
- module.exports = {
300
- generateBaseline,
301
- planBaseline,
302
- serializeBaseline,
303
- splitBaseline,
304
- readBaseline,
305
- diffSizes,
306
- validateRebaselineLog,
307
- parseArgs,
308
- main,
309
- REBASELINES_KEY,
310
- BASELINE_PATH,
311
- AGENT_BASELINE_PATH,
312
- };
68
+ module.exports = { generateBaseline, serializeBaseline, BASELINE_PATH, AGENT_BASELINE_PATH };