@sabaiway/agent-workflow-kit 5.6.0 → 5.7.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 (42) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +1 -1
  3. package/SKILL.md +1 -1
  4. package/capability.json +1 -1
  5. package/package.json +1 -1
  6. package/references/hooks/gate-approve.mjs +7 -1
  7. package/references/modes/doc-parity.md +1 -1
  8. package/references/modes/gates.md +16 -3
  9. package/references/modes/recommendations.md +3 -0
  10. package/references/modes/review-state.md +1 -1
  11. package/references/modes/setup.md +18 -2
  12. package/references/modes/upgrade.md +38 -18
  13. package/references/scripts/migrate-gates-branches.test.mjs +146 -1
  14. package/references/scripts/migrate-gates.mjs +295 -60
  15. package/references/scripts/migrate-gates.test.mjs +206 -14
  16. package/references/shared/deploy-tail.md +1 -1
  17. package/references/templates/gates.json +1 -1
  18. package/tools/ack-write.mjs +20 -11
  19. package/tools/atomic-write.mjs +71 -18
  20. package/tools/checker-claim.mjs +100 -0
  21. package/tools/coverage-producer.mjs +43 -6
  22. package/tools/direct-run.mjs +76 -0
  23. package/tools/doc-parity.mjs +34 -3
  24. package/tools/engine-source.mjs +12 -8
  25. package/tools/ensure-configs.mjs +141 -0
  26. package/tools/ensure-ops.mjs +284 -0
  27. package/tools/ensure-vocabulary.mjs +71 -0
  28. package/tools/gates-declaration.mjs +23 -10
  29. package/tools/gates-init.mjs +6 -3
  30. package/tools/hide-footprint.mjs +21 -3
  31. package/tools/lens-region.mjs +74 -23
  32. package/tools/orchestration-config.mjs +5 -3
  33. package/tools/orchestration-write.mjs +7 -0
  34. package/tools/recommendations.mjs +315 -66
  35. package/tools/refresh-parity.mjs +263 -0
  36. package/tools/run-gates.mjs +8 -5
  37. package/tools/setup-backends.mjs +88 -77
  38. package/tools/source-size-check.mjs +6 -16
  39. package/tools/source-size-core.mjs +7 -1
  40. package/tools/source-size-gate-cmd.mjs +18 -46
  41. package/tools/tracked-tree-census.mjs +102 -0
  42. package/tools/upgrade-runlist.mjs +92 -0
@@ -10,10 +10,13 @@ import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, readdirSync, lstat
10
10
  import { tmpdir } from 'node:os';
11
11
  import { join } from 'node:path';
12
12
  import { spawnSync } from 'node:child_process';
13
- import { UNIT_TESTS_COVERAGE_FLAGS, RETIRED_STORE_BASENAMES, main } from './migrate-gates.mjs';
13
+ import { CHECKER_CLAIM, UNIT_TESTS_COVERAGE_FLAGS, RETIRED_STORE_BASENAMES, checkerClaimTool, classifyCheckerClaim, main } from './migrate-gates.mjs';
14
14
 
15
+ // Both core checks exist as real files — canonicity is a realpath anchor, so a check whose file is
16
+ // absent resolves to nothing and is no claim at all (the fail-closed answer run-gates gives too).
15
17
  const KIT_TOOLS = mkdtempSync(join(tmpdir(), 'migrate-branches-kit-'));
16
18
  writeFileSync(join(KIT_TOOLS, 'coverage-check.mjs'), '// the installed checker the migration points at\n');
19
+ writeFileSync(join(KIT_TOOLS, 'review-state.mjs'), '// the installed review-state check\n');
17
20
 
18
21
  const mkProject = (gates) => {
19
22
  const root = mkdtempSync(join(tmpdir(), 'migrate-branches-'));
@@ -34,6 +37,8 @@ const CHECKER = { id: 'coverage-check', title: 'CC', cmd: `node "${join(KIT_TOOL
34
37
  const REVIEW_STATE = { id: 'review-state', title: 'RS', cmd: `node "${join(KIT_TOOLS, 'review-state.mjs')}" --check` };
35
38
  const LEGACY = { id: 'review-ledger', title: 'L', cmd: 'node "/kit/tools/review-ledger.mjs" --check' };
36
39
  const UNIT = { id: 'unit-tests', title: 'U', cmd: 'node --test tools/*.test.mjs' };
40
+ // A suite the closed producer world cannot express, declaring itself with the optional marker.
41
+ const MARKED_SUITE = { id: 'suite', title: 'S', cmd: 'pnpm vitest run --coverage', lcovProducer: true };
37
42
 
38
43
  describe('migrate-gates — refusal and no-op branches', () => {
39
44
  it('--help prints the contract and exits 0', () => {
@@ -141,6 +146,146 @@ describe('migrate-gates — refusal and no-op branches', () => {
141
146
  rmSync(root, { recursive: true, force: true });
142
147
  });
143
148
 
149
+ it('a marker-carrying entry survives an apply UNCHANGED — the loader is lenient, the writer opaque', () => {
150
+ // The declaration this tool rewrites may carry keys it knows nothing about. The loader accepts
151
+ // any `{ gates: [...] }` shape and the writer re-serializes the ENTRY, not a reconstruction of
152
+ // it, so an upgrade over a marker-carrying deployment never silently drops the claim.
153
+ const root = mkProject([LEGACY, MARKED_SUITE, REVIEW_STATE]);
154
+ const io = quiet();
155
+ assert.equal(main(['--cwd', root, '--kit-tools', KIT_TOOLS, '--apply'], io), 0, io.err.join('\n'));
156
+ const raw = readFileSync(join(root, 'docs', 'ai', 'gates.json'), 'utf8');
157
+ const written = JSON.parse(raw).gates;
158
+ assert.deepEqual(written.map((g) => g.id), ['suite', 'review-state', 'coverage-check'], 'the checker is ADDED over a marker-claimed producer');
159
+ assert.deepEqual(written[0], MARKED_SUITE, 'the marked entry round-trips key for key');
160
+ assert.match(raw, /"lcovProducer": true/, 'and the marker is really in the written bytes');
161
+ assert.doesNotMatch(io.out.join('\n'), /WARNING/, 'nothing is withheld over a declared producer');
162
+ rmSync(root, { recursive: true, force: true });
163
+ });
164
+
165
+ it('a marker on the CHECKER ITSELF never self-pairs — the declared pair stays INERT', () => {
166
+ // The producer question is POSITIONAL: the checker always ends up last, so it can never be its
167
+ // own producer. Asking it over the whole kept set would let this declaration certify itself
168
+ // into final-run-capability with nothing writing the lcov.
169
+ const root = mkProject([{ id: 'lint', title: 'L', cmd: 'eslint .' }, REVIEW_STATE, { ...CHECKER, lcovProducer: true }]);
170
+ const io = quiet();
171
+ assert.equal(main(['--cwd', root, '--kit-tools', KIT_TOOLS], io), 0, io.err.join('\n'));
172
+ const text = io.out.join('\n');
173
+ assert.match(text, /INERT/, 'the dead pair is named');
174
+ assert.doesNotMatch(text, /already final-run-capable/, 'and never claimed capable');
175
+ rmSync(root, { recursive: true, force: true });
176
+ });
177
+
178
+ it('a MARKED unit-tests entry is a zero-diff keep — never extended, never reported customized', () => {
179
+ // Both arms the marker settles at once: `npm test` is a cmd this tool cannot verify (customized
180
+ // without the marker), and rewriting a cmd whose owner declared it the producer would change
181
+ // bytes the byte-exact hook approval binds.
182
+ const marked = { id: 'unit-tests', title: 'U', cmd: 'npm test', lcovProducer: true };
183
+ const root = mkProject([marked, REVIEW_STATE]);
184
+ const io = quiet();
185
+ assert.equal(main(['--cwd', root, '--kit-tools', KIT_TOOLS], io), 0, io.err.join('\n'));
186
+ const text = io.out.join('\n');
187
+ assert.match(text, /ADD coverage-check/, 'the claimed producer unlocks the checker');
188
+ assert.doesNotMatch(text, /EXTEND unit-tests/, 'a claimed producer cmd is never rewritten');
189
+ assert.doesNotMatch(text, /CUSTOMIZED/, 'nor reported as a cmd the tool cannot verify');
190
+ rmSync(root, { recursive: true, force: true });
191
+
192
+ // The SAME entry unmarked is the customized/withheld path — the marker is what settles it.
193
+ const bare = mkProject([{ id: 'unit-tests', title: 'U', cmd: 'npm test' }, REVIEW_STATE]);
194
+ const io2 = quiet();
195
+ assert.equal(main(['--cwd', bare, '--kit-tools', KIT_TOOLS], io2), 0, io2.err.join('\n'));
196
+ const text2 = io2.out.join('\n');
197
+ assert.match(text2, /CUSTOMIZED/);
198
+ assert.doesNotMatch(text2, /ADD coverage-check/, 'the checker stays withheld with no producer');
199
+ rmSync(bare, { recursive: true, force: true });
200
+ });
201
+
202
+ it('a marker over an UNRUNNABLE cmd never unlocks the checker — the lenient loader has no validator', () => {
203
+ // This tool accepts any `{ gates: [...] }` shape, so an entry the strict validator would refuse
204
+ // reaches the plan builder intact. A marker on such an entry must not make the migration ADD the
205
+ // canonical checker: the result would be the dead pair the withhold exists to prevent, and the
206
+ // written declaration would then fail run-gates outright.
207
+ for (const cmd of [' ', 'echo a\nrm -rf b']) {
208
+ const root = mkProject([{ id: 'suite', title: 'S', cmd, lcovProducer: true }, REVIEW_STATE]);
209
+ const io = quiet();
210
+ assert.equal(main(['--cwd', root, '--kit-tools', KIT_TOOLS], io), 0, io.err.join('\n'));
211
+ const text = io.out.join('\n');
212
+ assert.doesNotMatch(text, /ADD coverage-check/, `an unrunnable cmd must not unlock the checker: ${JSON.stringify(cmd)}`);
213
+ assert.match(text, /WARNING: the canonical coverage-check gate was NOT added/, 'and the withhold is stated');
214
+ rmSync(root, { recursive: true, force: true });
215
+ }
216
+ });
217
+
218
+ it('a marker on a DUPLICATE canonical checker never produces for the other — nor claims capability', () => {
219
+ // `--final` accepts exactly ONE canonical checker, and a checker cannot write the lcov it reads.
220
+ // Excluding only the LAST checker row from the producer search let a marker on the first one pair
221
+ // with the second, and the preview then called the result final-run-capable over a declaration
222
+ // --final rejects outright, with nothing writing the file.
223
+ const root = mkProject([{ ...CHECKER, id: 'coverage-check', lcovProducer: true }, REVIEW_STATE, { ...CHECKER, id: 'coverage-check-2' }]);
224
+ const io = quiet();
225
+ assert.equal(main(['--cwd', root, '--kit-tools', KIT_TOOLS], io), 0, io.err.join('\n'));
226
+ const text = io.out.join('\n');
227
+ assert.doesNotMatch(text, /already final-run-capable/, 'two checkers are never a final-run-capable result');
228
+ assert.match(text, /2 declared gates are the canonical coverage checker/, 'the duplication is NAMED');
229
+ assert.match(text, /INERT/, 'and the pair is still reported inert — nothing writes the lcov');
230
+ rmSync(root, { recursive: true, force: true });
231
+ });
232
+
233
+ it('the tool-claim twin RUNS in this module — three outcomes, fail-closed on the unresolvable', () => {
234
+ // The text drift guard (beside the kit's own copy) proves the two owners are byte-equal; it
235
+ // cannot prove this copy WORKS, because the region is byte-equal inside a DIFFERENT host with
236
+ // different imports. Executing it here is what proves the twin resolves everything it uses.
237
+ const canonical = join(KIT_TOOLS, 'coverage-check.mjs');
238
+ const root = mkProject([]);
239
+ try {
240
+ const elsewhere = join(root, 'vendor-coverage-check.mjs');
241
+ writeFileSync(elsewhere, '// a vendored copy\n');
242
+ const tool = checkerClaimTool('coverage-check.mjs', canonical);
243
+ assert.equal(classifyCheckerClaim(tool, `node "${canonical}" --check`, KIT_TOOLS), CHECKER_CLAIM.CANONICAL);
244
+ const vendored = checkerClaimTool('vendor-coverage-check.mjs', canonical);
245
+ assert.equal(classifyCheckerClaim(vendored, `node "${elsewhere}" --check`, KIT_TOOLS), CHECKER_CLAIM.ELSEWHERE);
246
+ assert.equal(classifyCheckerClaim(tool, `node "${canonical}" --check || true`, KIT_TOOLS), CHECKER_CLAIM.NOT_THE_TOOL, 'a masked form is no claim');
247
+ assert.equal(classifyCheckerClaim(tool, `node "${join(KIT_TOOLS, 'nowhere', 'coverage-check.mjs')}" --check`, KIT_TOOLS), CHECKER_CLAIM.NOT_THE_TOOL, 'unresolvable fails closed');
248
+ assert.equal(classifyCheckerClaim(tool, 'node $(pwd)/coverage-check.mjs --check', KIT_TOOLS), CHECKER_CLAIM.NOT_THE_TOOL, 'a shell-active bare token is no claim');
249
+ } finally {
250
+ rmSync(root, { recursive: true, force: true }); // every other case here cleans up; this one held its root only for a path
251
+ }
252
+ });
253
+
254
+ it('a VENDORED deployment previews at exit 0 and its --apply writes ZERO bytes', () => {
255
+ // The upgrade path this fixes: every preview AND every apply over a deployment that declared the
256
+ // checker through its own vendored copy used to exit 1 on an id collision, so such a deployment
257
+ // could not be upgraded at all.
258
+ const vendoredTools = mkdtempSync(join(tmpdir(), 'migrate-branches-vendored-'));
259
+ writeFileSync(join(vendoredTools, 'coverage-check.mjs'), '// a vendored copy of the checker\n');
260
+ const vendored = { id: 'coverage-check', title: 'CC', cmd: `node "${join(vendoredTools, 'coverage-check.mjs')}" --check` };
261
+ const root = mkProject([UNIT_DONE, REVIEW_STATE, vendored]);
262
+ const before = readFileSync(join(root, 'docs', 'ai', 'gates.json'), 'utf8');
263
+
264
+ const io = quiet();
265
+ assert.equal(main(['--cwd', root, '--kit-tools', KIT_TOOLS], io), 0, io.err.join('\n'));
266
+ const preview = io.out.join('\n');
267
+ assert.match(preview, /VERIFY \(preserved exactly as declared\): coverage-check/);
268
+ assert.doesNotMatch(preview, /ADD coverage-check/, 'nothing is added over a checker that is already declared');
269
+ assert.doesNotMatch(io.err.join('\n'), /id collision/, 'a vendored copy is not a squatter');
270
+
271
+ const io2 = quiet();
272
+ assert.equal(main(['--cwd', root, '--kit-tools', KIT_TOOLS, '--apply'], io2), 0, io2.err.join('\n'));
273
+ assert.equal(readFileSync(join(root, 'docs', 'ai', 'gates.json'), 'utf8'), before, 'the apply is a ZERO-DIFF write');
274
+ assert.match(io2.out.join('\n'), /NOT final-run-capable/, 'and the withheld claim survives the no-op apply');
275
+ rmSync(vendoredTools, { recursive: true, force: true });
276
+ rmSync(root, { recursive: true, force: true });
277
+ });
278
+
279
+ it('a vendored copy named by a RELATIVE path resolves against the PROJECT root, as the runner resolves it', () => {
280
+ const root = mkProject([UNIT_DONE, REVIEW_STATE, { id: 'coverage-check', title: 'CC', cmd: 'node "vendor/coverage-check.mjs" --check' }]);
281
+ mkdirSync(join(root, 'vendor'), { recursive: true });
282
+ writeFileSync(join(root, 'vendor', 'coverage-check.mjs'), '// a vendored copy inside the project\n');
283
+ const io = quiet();
284
+ assert.equal(main(['--cwd', root, '--kit-tools', KIT_TOOLS], io), 0, io.err.join('\n'));
285
+ assert.match(io.out.join('\n'), /VERIFY \(preserved exactly as declared\): coverage-check/, 'a relative token is resolved, not dismissed');
286
+ rmSync(root, { recursive: true, force: true });
287
+ });
288
+
144
289
  it('an un-unlinkable retired store is reported LOUDLY and never fails the migration', () => {
145
290
  const root = mkProject([LEGACY, UNIT]);
146
291
  spawnSync('git', ['init', '-q'], { cwd: root, encoding: 'utf8' });