@givolt/i3-composer-agent 1.0.1 → 2.1.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 (238) hide show
  1. package/.agents/plugins/marketplace.json +1 -1
  2. package/.claude/commands/{build.md → i3-build.md} +10 -10
  3. package/.claude/commands/{code-simplify.md → i3-code-simplify.md} +2 -2
  4. package/.claude/commands/{constraints.md → i3-constraints.md} +4 -4
  5. package/.claude/commands/{plan.md → i3-plan.md} +1 -1
  6. package/.claude/commands/{review.md → i3-review.md} +3 -3
  7. package/.claude/commands/{ship.md → i3-ship.md} +4 -4
  8. package/.claude/commands/{spec.md → i3-spec.md} +1 -1
  9. package/.claude/commands/{test.md → i3-test.md} +2 -2
  10. package/.claude/commands/{webperf.md → i3-webperf.md} +1 -1
  11. package/.claude-plugin/marketplace.json +1 -1
  12. package/.claude-plugin/plugin.json +1 -1
  13. package/.codex-plugin/plugin.json +1 -1
  14. package/.gemini/commands/{build.toml → i3-build.toml} +10 -10
  15. package/.gemini/commands/{code-simplify.toml → i3-code-simplify.toml} +2 -2
  16. package/.gemini/commands/{constraints.toml → i3-constraints.toml} +4 -4
  17. package/.gemini/commands/{planning.toml → i3-planning.toml} +1 -1
  18. package/{commands/review.toml → .gemini/commands/i3-review.toml} +3 -3
  19. package/.gemini/commands/{ship.toml → i3-ship.toml} +4 -4
  20. package/.gemini/commands/{spec.toml → i3-spec.toml} +1 -1
  21. package/{commands/test.toml → .gemini/commands/i3-test.toml} +2 -2
  22. package/.gemini/commands/{webperf.toml → i3-webperf.toml} +1 -1
  23. package/README.md +72 -69
  24. package/agents/code-reviewer.md +2 -2
  25. package/agents/security-auditor.md +1 -1
  26. package/agents/test-engineer.md +1 -1
  27. package/agents/web-performance-auditor.md +3 -3
  28. package/bin/agent-targets.json +11 -0
  29. package/bin/asset-fingerprint.cjs +38 -0
  30. package/bin/cleanup-backups.cjs +16 -0
  31. package/bin/i3-composer-agent.cjs +29 -14
  32. package/bin/install.cjs +81 -19
  33. package/bin/native-content.cjs +29 -0
  34. package/bin/wizard.cjs +2 -1
  35. package/commands/{build.toml → i3-build.toml} +10 -10
  36. package/commands/{code-simplify.toml → i3-code-simplify.toml} +2 -2
  37. package/commands/{constraints.toml → i3-constraints.toml} +4 -4
  38. package/commands/{planning.toml → i3-planning.toml} +1 -1
  39. package/{.gemini/commands/review.toml → commands/i3-review.toml} +3 -3
  40. package/commands/{ship.toml → i3-ship.toml} +4 -4
  41. package/commands/{spec.toml → i3-spec.toml} +1 -1
  42. package/{.gemini/commands/test.toml → commands/i3-test.toml} +2 -2
  43. package/commands/{webperf.toml → i3-webperf.toml} +1 -1
  44. package/docs/adoption-guide.md +35 -35
  45. package/docs/agents.md +12 -12
  46. package/docs/antigravity-setup.md +14 -14
  47. package/docs/codebuddy-setup.md +27 -18
  48. package/docs/codex-setup.md +6 -6
  49. package/docs/commandcode-setup.md +5 -5
  50. package/docs/copilot-cli-setup.md +5 -5
  51. package/docs/copilot-setup.md +22 -22
  52. package/docs/cursor-setup.md +22 -22
  53. package/docs/gemini-cli-setup.md +26 -26
  54. package/docs/getting-started.md +36 -38
  55. package/docs/opencode-setup.md +31 -31
  56. package/docs/windsurf-setup.md +7 -7
  57. package/docs/workbuddy-setup.md +92 -0
  58. package/hooks/SDD-CACHE.md +3 -3
  59. package/hooks/SIMPLIFY-IGNORE.md +2 -2
  60. package/hooks/session-start-test.sh +1 -1
  61. package/hooks/session-start.sh +3 -3
  62. package/package.json +36 -20
  63. package/plugin.json +1 -1
  64. package/references/accessibility-checklist.md +1 -1
  65. package/references/definition-of-done.md +7 -7
  66. package/references/observability-checklist.md +3 -3
  67. package/references/orchestration-patterns.md +17 -17
  68. package/references/performance-checklist.md +2 -2
  69. package/references/security-checklist.md +1 -1
  70. package/references/testing-patterns.md +1 -1
  71. package/skills/{api-and-interface-design → i3-api-and-interface-design}/SKILL.md +2 -2
  72. package/skills/{browser-testing-with-devtools → i3-browser-testing-with-devtools}/SKILL.md +1 -1
  73. package/skills/{ci-cd-and-automation → i3-ci-cd-and-automation}/SKILL.md +2 -2
  74. package/skills/{code-review-and-quality → i3-code-review-and-quality}/SKILL.md +5 -5
  75. package/skills/{code-simplification → i3-code-simplification}/SKILL.md +1 -1
  76. package/skills/{constraint-driven-development → i3-constraint-driven-development}/SKILL.md +15 -15
  77. package/skills/{context-engineering → i3-context-engineering}/SKILL.md +1 -1
  78. package/skills/{debugging-and-error-recovery → i3-debugging-and-error-recovery}/SKILL.md +2 -2
  79. package/skills/{deprecation-and-migration → i3-deprecation-and-migration}/SKILL.md +2 -2
  80. package/skills/{documentation-and-adrs → i3-documentation-and-adrs}/SKILL.md +1 -1
  81. package/skills/{doubt-driven-development → i3-doubt-driven-development}/SKILL.md +8 -8
  82. package/skills/{frontend-ui-engineering → i3-frontend-ui-engineering}/SKILL.md +1 -1
  83. package/skills/{git-workflow-and-versioning → i3-git-workflow-and-versioning}/SKILL.md +4 -4
  84. package/skills/{idea-refine → i3-idea-refine}/SKILL.md +2 -2
  85. package/skills/{idea-refine → i3-idea-refine}/scripts/idea-refine.sh +1 -1
  86. package/skills/{incremental-implementation → i3-incremental-implementation}/SKILL.md +3 -3
  87. package/skills/{interview-me → i3-interview-me}/SKILL.md +12 -12
  88. package/skills/{observability-and-instrumentation → i3-observability-and-instrumentation}/SKILL.md +5 -5
  89. package/skills/{performance-optimization → i3-performance-optimization}/SKILL.md +1 -1
  90. package/skills/{performance-optimization → i3-performance-optimization}/references/optimization-patterns.md +1 -1
  91. package/skills/{planning-and-task-breakdown → i3-planning-and-task-breakdown}/SKILL.md +2 -2
  92. package/skills/{security-and-hardening → i3-security-and-hardening}/SKILL.md +3 -3
  93. package/skills/{security-and-hardening → i3-security-and-hardening}/references/hardening-patterns.md +1 -1
  94. package/skills/{shipping-and-launch → i3-shipping-and-launch}/SKILL.md +2 -2
  95. package/skills/{source-driven-development → i3-source-driven-development}/SKILL.md +2 -2
  96. package/skills/{spec-driven-development → i3-spec-driven-development}/SKILL.md +7 -7
  97. package/skills/{test-driven-development → i3-test-driven-development}/SKILL.md +2 -2
  98. package/skills/{using-agent-skills → i3-using-agent-skills}/SKILL.md +67 -67
  99. package/CHANGELOG.md +0 -34
  100. package/NOTICE.md +0 -14
  101. package/docs/advanced-per-agent-configuration.md +0 -70
  102. package/docs/comparison.md +0 -131
  103. package/docs/developer-onboarding.md +0 -116
  104. package/docs/skill-anatomy.md +0 -203
  105. package/evals/README.md +0 -101
  106. package/evals/cases/api-and-interface-design.json +0 -45
  107. package/evals/cases/browser-testing-with-devtools.json +0 -44
  108. package/evals/cases/ci-cd-and-automation.json +0 -45
  109. package/evals/cases/code-review-and-quality.json +0 -49
  110. package/evals/cases/code-simplification.json +0 -45
  111. package/evals/cases/constraint-driven-development.json +0 -79
  112. package/evals/cases/context-engineering.json +0 -44
  113. package/evals/cases/debugging-and-error-recovery.json +0 -58
  114. package/evals/cases/deprecation-and-migration.json +0 -52
  115. package/evals/cases/documentation-and-adrs.json +0 -44
  116. package/evals/cases/doubt-driven-development.json +0 -43
  117. package/evals/cases/frontend-ui-engineering.json +0 -52
  118. package/evals/cases/git-workflow-and-versioning.json +0 -47
  119. package/evals/cases/idea-refine.json +0 -43
  120. package/evals/cases/incremental-implementation.json +0 -57
  121. package/evals/cases/interview-me.json +0 -42
  122. package/evals/cases/observability-and-instrumentation.json +0 -44
  123. package/evals/cases/performance-optimization.json +0 -53
  124. package/evals/cases/planning-and-task-breakdown.json +0 -45
  125. package/evals/cases/security-and-hardening.json +0 -53
  126. package/evals/cases/shipping-and-launch.json +0 -56
  127. package/evals/cases/source-driven-development.json +0 -44
  128. package/evals/cases/spec-driven-development.json +0 -72
  129. package/evals/cases/test-driven-development.json +0 -73
  130. package/evals/cases/using-agent-skills.json +0 -44
  131. package/evals/fixtures/api-and-interface-design/service-brief.md +0 -19
  132. package/evals/fixtures/browser-testing-with-devtools/README.md +0 -5
  133. package/evals/fixtures/browser-testing-with-devtools/index.html +0 -24
  134. package/evals/fixtures/browser-testing-with-devtools/server.js +0 -15
  135. package/evals/fixtures/ci-cd-and-automation/package.json +0 -8
  136. package/evals/fixtures/ci-cd-and-automation/src/slug.js +0 -3
  137. package/evals/fixtures/ci-cd-and-automation/test/slug.test.js +0 -9
  138. package/evals/fixtures/code-review-and-quality/user-search.diff +0 -16
  139. package/evals/fixtures/code-simplification/config-parser.js +0 -46
  140. package/evals/fixtures/code-simplification/config-parser.test.js +0 -15
  141. package/evals/fixtures/context-engineering/context-audit.md +0 -15
  142. package/evals/fixtures/debugging-and-error-recovery/pagination.js +0 -8
  143. package/evals/fixtures/debugging-and-error-recovery/pagination.test.js +0 -9
  144. package/evals/fixtures/debugging-and-error-recovery/time-pressure.md +0 -6
  145. package/evals/fixtures/deprecation-and-migration/api-inventory.md +0 -9
  146. package/evals/fixtures/documentation-and-adrs/decision-context.md +0 -16
  147. package/evals/fixtures/doubt-driven-development/migration-plan.md +0 -19
  148. package/evals/fixtures/frontend-ui-engineering/Button.tsx +0 -7
  149. package/evals/fixtures/frontend-ui-engineering/design-system.md +0 -11
  150. package/evals/fixtures/git-workflow-and-versioning/.eval/working-tree.patch +0 -21
  151. package/evals/fixtures/git-workflow-and-versioning/app.js +0 -7
  152. package/evals/fixtures/git-workflow-and-versioning/app.test.js +0 -9
  153. package/evals/fixtures/incremental-implementation/reports.js +0 -7
  154. package/evals/fixtures/incremental-implementation/reports.test.js +0 -12
  155. package/evals/fixtures/incremental-implementation/tasks/plan.md +0 -8
  156. package/evals/fixtures/incremental-implementation-pressure/draft-export.js +0 -17
  157. package/evals/fixtures/incremental-implementation-pressure/scenario.md +0 -9
  158. package/evals/fixtures/observability-and-instrumentation/operations.md +0 -11
  159. package/evals/fixtures/observability-and-instrumentation/payment-retry.js +0 -14
  160. package/evals/fixtures/performance-optimization/benchmark.js +0 -15
  161. package/evals/fixtures/performance-optimization/products.js +0 -14
  162. package/evals/fixtures/planning-and-task-breakdown/notifications-spec.md +0 -18
  163. package/evals/fixtures/security-and-hardening/webhook.js +0 -11
  164. package/evals/fixtures/security-and-hardening/webhook.test.js +0 -13
  165. package/evals/fixtures/shipping-and-launch/authority-pressure.md +0 -6
  166. package/evals/fixtures/shipping-and-launch/launch-status.md +0 -11
  167. package/evals/fixtures/source-driven-development/framework-task.md +0 -10
  168. package/evals/fixtures/spec-driven-development/billing-brief.md +0 -16
  169. package/evals/fixtures/spec-driven-development-decomposition/portal-brief.md +0 -22
  170. package/evals/fixtures/test-driven-development/BUG.md +0 -10
  171. package/evals/fixtures/test-driven-development/README.md +0 -28
  172. package/evals/fixtures/test-driven-development/package.json +0 -9
  173. package/evals/fixtures/test-driven-development/src/split.js +0 -8
  174. package/evals/fixtures/test-driven-development/test/split.test.js +0 -13
  175. package/evals/fixtures/test-driven-development-ecosystem/README.md +0 -9
  176. package/evals/fixtures/test-driven-development-ecosystem/ledger.py +0 -15
  177. package/evals/fixtures/test-driven-development-ecosystem/test_ledger.py +0 -19
  178. package/evals/fixtures/using-agent-skills/incident.md +0 -6
  179. package/evals/plugin/code-review-fires/graders/off-by-one.md +0 -7
  180. package/evals/plugin/code-review-fires/graders/severity-labels.md +0 -4
  181. package/evals/plugin/code-review-fires/graders/skill-fired.md +0 -5
  182. package/evals/plugin/code-review-fires/prompt.md +0 -31
  183. package/evals/plugin/code-review-stays-quiet/graders/not-fired.md +0 -8
  184. package/evals/plugin/code-review-stays-quiet/graders/tdd-fired.md +0 -6
  185. package/evals/plugin/code-review-stays-quiet/prompt.md +0 -8
  186. package/evals/plugin/code-review-stays-quiet-on-commit-message/graders/not-fired.md +0 -8
  187. package/evals/plugin/code-review-stays-quiet-on-commit-message/prompt.md +0 -25
  188. package/evals/skill-impact.md +0 -6
  189. package/rebrand/INSTALLATION-SPEC.md +0 -46
  190. package/rebrand/MAINTENANCE.md +0 -113
  191. package/rebrand/NOTICE.md +0 -14
  192. package/rebrand/PR-WORKFLOW.md +0 -34
  193. package/rebrand/UNIFICATION-SPEC.md +0 -33
  194. package/rebrand/VALIDATION.md +0 -32
  195. package/rebrand/VERSIONING.md +0 -33
  196. package/rebrand/apply.cjs +0 -194
  197. package/rebrand/brand.json +0 -13
  198. package/rebrand/catalog.cjs +0 -56
  199. package/rebrand/fork-patches.json +0 -12
  200. package/rebrand/overlay/.github/workflows/test-plugin-install.yml +0 -177
  201. package/rebrand/overlay/CHANGELOG.md +0 -34
  202. package/rebrand/overlay/bin/agent-targets.json +0 -726
  203. package/rebrand/overlay/bin/i3-composer-agent.cjs +0 -190
  204. package/rebrand/overlay/bin/install.cjs +0 -164
  205. package/rebrand/overlay/bin/skills-registry.LICENSE +0 -21
  206. package/rebrand/overlay/bin/wizard.cjs +0 -66
  207. package/rebrand/overlay/scripts/validate-brand.cjs +0 -44
  208. package/rebrand/overlay/tests/bundle.test.cjs +0 -85
  209. package/rebrand/overlay/tests/installer.test.cjs +0 -193
  210. package/rebrand/package.template.json +0 -82
  211. package/rebrand/rebrand.sh +0 -4
  212. package/rebrand/record-upstream.cjs +0 -37
  213. package/rebrand/templates/README.md +0 -124
  214. package/rebrand/templates/codebuddy-setup.md +0 -88
  215. package/rebrand/templates/codex-setup.md +0 -45
  216. package/rebrand/tests/pipeline.test.cjs +0 -185
  217. package/rebrand/upstream.json +0 -171
  218. package/scripts/floor-guard-reference-test.js +0 -291
  219. package/scripts/lib/skill-lint-test.js +0 -650
  220. package/scripts/lib/skill-lint.js +0 -584
  221. package/scripts/run-evals-test.js +0 -623
  222. package/scripts/run-evals.js +0 -638
  223. package/scripts/validate-artifact-paths-test.js +0 -179
  224. package/scripts/validate-artifact-paths.js +0 -128
  225. package/scripts/validate-brand.cjs +0 -44
  226. package/scripts/validate-commands-test.js +0 -216
  227. package/scripts/validate-commands.js +0 -222
  228. package/scripts/validate-reference-links-test.js +0 -495
  229. package/scripts/validate-reference-links.js +0 -187
  230. package/scripts/validate-skills.js +0 -69
  231. package/scripts/validate-versions-test.js +0 -32
  232. package/scripts/validate-versions.js +0 -35
  233. package/tests/bundle.test.cjs +0 -85
  234. package/tests/installer.test.cjs +0 -193
  235. /package/skills/{constraint-driven-development → i3-constraint-driven-development}/references/floor-guard.md +0 -0
  236. /package/skills/{idea-refine → i3-idea-refine}/examples.md +0 -0
  237. /package/skills/{idea-refine → i3-idea-refine}/frameworks.md +0 -0
  238. /package/skills/{idea-refine → i3-idea-refine}/refinement-criteria.md +0 -0
@@ -1,185 +0,0 @@
1
- 'use strict';
2
-
3
- const test = require('node:test');
4
- const assert = require('node:assert/strict');
5
- const fs = require('node:fs');
6
- const os = require('node:os');
7
- const path = require('node:path');
8
- const { spawnSync } = require('node:child_process');
9
- const root = path.resolve(__dirname, '../..');
10
- const baselineVersion = require('../upstream.json').upstreamVersion;
11
-
12
- function run(directory, executable, args) {
13
- return spawnSync(executable, args, { cwd: directory, encoding: 'utf8' });
14
- }
15
- function git(directory, args) {
16
- const result = run(directory, 'git', args);
17
- assert.equal(result.status, 0, result.stderr);
18
- return result.stdout.trim();
19
- }
20
- function node(directory, file, args = []) { return run(directory, process.execPath, [file, ...args]); }
21
- function fixture(t, branch = 'release/test-candidate') {
22
- const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'i3-agent-replay-'));
23
- t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
24
- for (const name of ['skills', 'references', 'agents', 'commands', '.claude', '.gemini', '.claude-plugin', '.codex-plugin', '.agents', 'hooks', 'docs', 'scripts', 'evals', 'rebrand', 'LICENSE', 'plugin.json', 'README.md']) {
25
- fs.cpSync(path.join(root, name), path.join(directory, name), { recursive: true, filter: file => !file.includes(`${path.sep}results${path.sep}`) });
26
- }
27
- // Model an upstream source checkout, including when this suite runs in a packed branded bundle.
28
- for (const name of ['plugin.json', '.claude-plugin/plugin.json', '.codex-plugin/plugin.json']) {
29
- const file = path.join(directory, name);
30
- const data = JSON.parse(fs.readFileSync(file, 'utf8'));
31
- data.name = 'agent-skills';
32
- data.version = baselineVersion;
33
- fs.writeFileSync(file, JSON.stringify(data, null, 2) + '\n');
34
- }
35
- git(directory, ['init', '--initial-branch', branch]);
36
- git(directory, ['config', 'user.name', 'Pipeline Test']);
37
- git(directory, ['config', 'user.email', 'pipeline@example.test']);
38
- git(directory, ['add', '.']);
39
- git(directory, ['commit', '-m', 'upstream fixture']);
40
- return directory;
41
- }
42
- function record(directory) {
43
- const result = node(directory, 'rebrand/record-upstream.cjs', ['HEAD']);
44
- assert.equal(result.status, 0, result.stderr);
45
- }
46
- function apply(directory) {
47
- const result = node(directory, 'rebrand/apply.cjs', ['--apply']);
48
- assert.equal(result.status, 0, result.stderr);
49
- }
50
-
51
- test('a source checkout generates a complete, repeatable branded distribution', t => {
52
- const directory = fixture(t);
53
- record(directory);
54
- apply(directory);
55
- const pkg = JSON.parse(fs.readFileSync(path.join(directory, 'package.json'), 'utf8'));
56
- assert.equal(pkg.name, '@givolt/i3-composer-agent');
57
- const brand = JSON.parse(fs.readFileSync(path.join(directory, 'rebrand/brand.json'), 'utf8'));
58
- assert.equal(pkg.version, brand.releaseVersion);
59
- assert.equal(fs.existsSync(path.join(directory, 'bin/i3-composer-agent.cjs')), true);
60
- assert.equal(node(directory, 'scripts/validate-brand.cjs').status, 0);
61
- const check = node(directory, 'rebrand/apply.cjs', ['--check']);
62
- assert.equal(check.status, 0, check.stdout + check.stderr);
63
- });
64
-
65
- test('brand fixes advance independently while preserving upstream provenance', t => {
66
- const directory = fixture(t);
67
- record(directory);
68
- const upstreamFile = path.join(directory, 'rebrand/upstream.json');
69
- const originalUpstream = fs.readFileSync(upstreamFile, 'utf8');
70
- const upstream = JSON.parse(originalUpstream);
71
- const brandFile = path.join(directory, 'rebrand/brand.json');
72
- const brand = JSON.parse(fs.readFileSync(brandFile, 'utf8'));
73
- const releaseVersion = `${Number(upstream.upstreamVersion.split('.')[0]) + 1}.0.1`;
74
- brand.releaseVersion = releaseVersion;
75
- fs.writeFileSync(brandFile, JSON.stringify(brand, null, 2) + '\n');
76
- apply(directory);
77
- const packageFile = path.join(directory, 'package.json');
78
- const originalPackage = fs.readFileSync(packageFile, 'utf8');
79
- const pkg = JSON.parse(originalPackage);
80
- assert.equal(pkg.version, releaseVersion);
81
- assert.equal(pkg.i3ComposerAgent.upstreamVersion, upstream.upstreamVersion);
82
- assert.equal(pkg.i3ComposerAgent.upstreamCommit, upstream.upstreamCommit);
83
- assert.equal(fs.readFileSync(upstreamFile, 'utf8'), originalUpstream);
84
- const releaseLabel = `i3 Composer Agent v${releaseVersion}`;
85
- const upstreamLabel = `Based on agent-skills v${upstream.upstreamVersion}`;
86
- for (const output of [fs.readFileSync(path.join(directory, 'README.md'), 'utf8'), node(directory, 'bin/i3-composer-agent.cjs', ['--help']).stdout]) {
87
- assert.ok(output.includes(releaseLabel), output);
88
- assert.ok(output.includes(upstreamLabel), output);
89
- }
90
- assert.equal(node(directory, 'bin/i3-composer-agent.cjs', ['--version']).stdout.trim(), releaseVersion);
91
- const dryRun = node(directory, 'bin/i3-composer-agent.cjs', ['--extract', '--dry-run', '--dir', directory + '-prepared']);
92
- assert.equal(dryRun.status, 0, dryRun.stderr);
93
- assert.equal(JSON.parse(dryRun.stdout).upstreamVersion, upstream.upstreamVersion);
94
- assert.equal(node(directory, 'scripts/validate-brand.cjs').status, 0);
95
- pkg.i3ComposerAgent.upstreamVersion = releaseVersion;
96
- fs.writeFileSync(packageFile, JSON.stringify(pkg));
97
- assert.notEqual(node(directory, 'scripts/validate-brand.cjs').status, 0);
98
- fs.writeFileSync(packageFile, originalPackage);
99
- assert.equal(node(directory, 'rebrand/apply.cjs', ['--check']).status, 0);
100
- });
101
-
102
- test('writing a brand transform on the protected source branch changes nothing', t => {
103
- const directory = fixture(t, 'agent/source');
104
- const before = fs.readFileSync(path.join(directory, 'plugin.json'));
105
- const result = node(directory, 'rebrand/apply.cjs', ['--apply']);
106
- assert.notEqual(result.status, 0);
107
- assert.match(result.stderr, /source branch/i);
108
- assert.deepEqual(fs.readFileSync(path.join(directory, 'plugin.json')), before);
109
- assert.equal(fs.existsSync(path.join(directory, 'package.json')), false);
110
- });
111
-
112
- test('a reviewed upstream catalog can grow without losing its new skill or command', t => {
113
- const directory = fixture(t);
114
- const skill = path.join(directory, 'skills/upstream-new-skill');
115
- fs.mkdirSync(skill);
116
- fs.writeFileSync(path.join(skill, 'SKILL.md'), '---\nname: upstream-new-skill\ndescription: New upstream capability.\n---\n# Upstream capability\n');
117
- fs.writeFileSync(path.join(directory, '.claude/commands/upstream-new-command.md'), '---\ndescription: Invoke the new upstream capability.\n---\nUse agent-skills:upstream-new-skill.\n');
118
- git(directory, ['add', 'skills', '.claude/commands']);
119
- git(directory, ['commit', '-m', 'new upstream capability']);
120
- record(directory);
121
- apply(directory);
122
- const result = node(directory, 'scripts/validate-brand.cjs');
123
- assert.equal(result.status, 0, result.stderr);
124
- const description = JSON.parse(fs.readFileSync(path.join(directory, '.codex-plugin/plugin.json'), 'utf8')).interface.longDescription;
125
- assert.match(description, /26 engineering skills/);
126
- const readme = fs.readFileSync(path.join(directory, 'README.md'), 'utf8');
127
- assert.match(readme, /upstream-new-skill/);
128
- assert.match(readme, /upstream-new-command/);
129
- });
130
-
131
- test('missing files and altered skill identifiers fail preservation validation', t => {
132
- const directory = fixture(t);
133
- record(directory);
134
- apply(directory);
135
- const file = path.join(directory, 'skills/using-agent-skills/SKILL.md');
136
- const original = fs.readFileSync(file, 'utf8');
137
- fs.writeFileSync(file, original.replace('name: using-agent-skills', 'name: renamed-meta-skill'));
138
- assert.notEqual(node(directory, 'scripts/validate-brand.cjs').status, 0);
139
- fs.writeFileSync(file, original);
140
- fs.rmSync(file);
141
- assert.notEqual(node(directory, 'scripts/validate-brand.cjs').status, 0);
142
- });
143
-
144
- test('checkout line endings do not masquerade as an upstream skill change', t => {
145
- const directory = fixture(t);
146
- record(directory);
147
- const file = path.join(directory, 'skills/using-agent-skills/SKILL.md');
148
- fs.writeFileSync(file, fs.readFileSync(file, 'utf8').replace(/\r?\n/g, '\r\n'));
149
- const script = path.join(directory, 'scripts/validate-versions.js');
150
- fs.writeFileSync(script, fs.readFileSync(script, 'utf8').replace(/\r?\n/g, '\r\n'));
151
- apply(directory);
152
- assert.equal(node(directory, 'scripts/validate-brand.cjs').status, 0);
153
- });
154
-
155
- test('a new upstream package manifest requires an explicit distribution adaptation', t => {
156
- const directory = fixture(t);
157
- record(directory);
158
- fs.writeFileSync(path.join(directory, 'package.json'), '{"name":"agent-skills","dependencies":{"upstream-runtime":"1.0.0"}}\n');
159
- const before = fs.readFileSync(path.join(directory, 'plugin.json'));
160
- const result = node(directory, 'rebrand/apply.cjs', ['--apply']);
161
- assert.notEqual(result.status, 0);
162
- assert.match(result.stderr, /package\.json/);
163
- assert.deepEqual(fs.readFileSync(path.join(directory, 'plugin.json')), before);
164
- });
165
-
166
- test('a distribution without repository CI files remains unchanged by a replay check', t => {
167
- const directory = fixture(t);
168
- record(directory);
169
- apply(directory);
170
- fs.rmSync(path.join(directory, '.github'), { recursive: true, force: true });
171
- const result = node(directory, 'rebrand/apply.cjs', ['--check']);
172
- assert.equal(result.status, 0, result.stdout + result.stderr);
173
- assert.equal(fs.existsSync(path.join(directory, '.github')), false);
174
- });
175
-
176
- test('Finder metadata does not masquerade as an upstream runtime file', t => {
177
- const directory = fixture(t);
178
- record(directory);
179
- fs.writeFileSync(path.join(directory, 'skills/.DS_Store'), 'Finder metadata');
180
- fs.writeFileSync(path.join(directory, 'skills/spec-driven-development/.DS_Store'), 'Finder metadata');
181
- apply(directory);
182
- assert.equal(node(directory, 'scripts/validate-brand.cjs').status, 0);
183
- const result = node(directory, 'rebrand/apply.cjs', ['--check']);
184
- assert.equal(result.status, 0, result.stdout + result.stderr);
185
- });
@@ -1,171 +0,0 @@
1
- {
2
- "upstreamCommit": "1401c8b8030e023baeebb31781a6653fe8e93026",
3
- "upstreamVersion": "0.6.12",
4
- "skills": [
5
- "api-and-interface-design",
6
- "browser-testing-with-devtools",
7
- "ci-cd-and-automation",
8
- "code-review-and-quality",
9
- "code-simplification",
10
- "constraint-driven-development",
11
- "context-engineering",
12
- "debugging-and-error-recovery",
13
- "deprecation-and-migration",
14
- "documentation-and-adrs",
15
- "doubt-driven-development",
16
- "frontend-ui-engineering",
17
- "git-workflow-and-versioning",
18
- "idea-refine",
19
- "incremental-implementation",
20
- "interview-me",
21
- "observability-and-instrumentation",
22
- "performance-optimization",
23
- "planning-and-task-breakdown",
24
- "security-and-hardening",
25
- "shipping-and-launch",
26
- "source-driven-development",
27
- "spec-driven-development",
28
- "test-driven-development",
29
- "using-agent-skills"
30
- ],
31
- "commands": [
32
- "build",
33
- "code-simplify",
34
- "constraints",
35
- "plan",
36
- "review",
37
- "ship",
38
- "spec",
39
- "test",
40
- "webperf"
41
- ],
42
- "personas": [
43
- "code-reviewer",
44
- "security-auditor",
45
- "test-engineer",
46
- "web-performance-auditor"
47
- ],
48
- "references": [
49
- "references/accessibility-checklist.md",
50
- "references/definition-of-done.md",
51
- "references/observability-checklist.md",
52
- "references/orchestration-patterns.md",
53
- "references/performance-checklist.md",
54
- "references/security-checklist.md",
55
- "references/testing-patterns.md"
56
- ],
57
- "runtimeFiles": [
58
- ".agents/plugins/marketplace.json",
59
- ".claude-plugin/marketplace.json",
60
- ".claude-plugin/plugin.json",
61
- ".claude/commands/build.md",
62
- ".claude/commands/code-simplify.md",
63
- ".claude/commands/constraints.md",
64
- ".claude/commands/plan.md",
65
- ".claude/commands/review.md",
66
- ".claude/commands/ship.md",
67
- ".claude/commands/spec.md",
68
- ".claude/commands/test.md",
69
- ".claude/commands/webperf.md",
70
- ".codex-plugin/plugin.json",
71
- ".gemini/commands/build.toml",
72
- ".gemini/commands/code-simplify.toml",
73
- ".gemini/commands/constraints.toml",
74
- ".gemini/commands/planning.toml",
75
- ".gemini/commands/review.toml",
76
- ".gemini/commands/ship.toml",
77
- ".gemini/commands/spec.toml",
78
- ".gemini/commands/test.toml",
79
- ".gemini/commands/webperf.toml",
80
- "LICENSE",
81
- "agents/code-reviewer.md",
82
- "agents/security-auditor.md",
83
- "agents/test-engineer.md",
84
- "agents/web-performance-auditor.md",
85
- "commands/build.toml",
86
- "commands/code-simplify.toml",
87
- "commands/constraints.toml",
88
- "commands/planning.toml",
89
- "commands/review.toml",
90
- "commands/ship.toml",
91
- "commands/spec.toml",
92
- "commands/test.toml",
93
- "commands/webperf.toml",
94
- "hooks/SDD-CACHE.md",
95
- "hooks/SIMPLIFY-IGNORE.md",
96
- "hooks/sdd-cache-post.sh",
97
- "hooks/sdd-cache-pre.sh",
98
- "hooks/sdd-cache-test.sh",
99
- "hooks/session-start-test.sh",
100
- "hooks/session-start.sh",
101
- "hooks/simplify-ignore-test.sh",
102
- "hooks/simplify-ignore.sh",
103
- "plugin.json",
104
- "references/accessibility-checklist.md",
105
- "references/definition-of-done.md",
106
- "references/observability-checklist.md",
107
- "references/orchestration-patterns.md",
108
- "references/performance-checklist.md",
109
- "references/security-checklist.md",
110
- "references/testing-patterns.md",
111
- "skills/api-and-interface-design/SKILL.md",
112
- "skills/browser-testing-with-devtools/SKILL.md",
113
- "skills/ci-cd-and-automation/SKILL.md",
114
- "skills/code-review-and-quality/SKILL.md",
115
- "skills/code-simplification/SKILL.md",
116
- "skills/constraint-driven-development/SKILL.md",
117
- "skills/constraint-driven-development/references/floor-guard.md",
118
- "skills/context-engineering/SKILL.md",
119
- "skills/debugging-and-error-recovery/SKILL.md",
120
- "skills/deprecation-and-migration/SKILL.md",
121
- "skills/documentation-and-adrs/SKILL.md",
122
- "skills/doubt-driven-development/SKILL.md",
123
- "skills/frontend-ui-engineering/SKILL.md",
124
- "skills/git-workflow-and-versioning/SKILL.md",
125
- "skills/idea-refine/SKILL.md",
126
- "skills/idea-refine/examples.md",
127
- "skills/idea-refine/frameworks.md",
128
- "skills/idea-refine/refinement-criteria.md",
129
- "skills/idea-refine/scripts/idea-refine.sh",
130
- "skills/incremental-implementation/SKILL.md",
131
- "skills/interview-me/SKILL.md",
132
- "skills/observability-and-instrumentation/SKILL.md",
133
- "skills/performance-optimization/SKILL.md",
134
- "skills/performance-optimization/references/optimization-patterns.md",
135
- "skills/planning-and-task-breakdown/SKILL.md",
136
- "skills/security-and-hardening/SKILL.md",
137
- "skills/security-and-hardening/references/hardening-patterns.md",
138
- "skills/shipping-and-launch/SKILL.md",
139
- "skills/source-driven-development/SKILL.md",
140
- "skills/spec-driven-development/SKILL.md",
141
- "skills/test-driven-development/SKILL.md",
142
- "skills/using-agent-skills/SKILL.md"
143
- ],
144
- "skillFrontmatter": {
145
- "api-and-interface-design": "44f904d462977e9514f439ac7c057b8691613ba8160360ad9d28b830d3a24001",
146
- "browser-testing-with-devtools": "e235631718d18a0527d00eb718ecece2218bbf205d742632f8197b30c052e96b",
147
- "ci-cd-and-automation": "dd73253ec445a9af27ebeab74404ee7a770919e40ec9db0b34af4fa9ec36bf7c",
148
- "code-review-and-quality": "bf3dda5e08190fcf00175a5053f53550bca91ca32b0a06e4b97cd33e046e8eb7",
149
- "code-simplification": "cee4dc87b4bc95d77fe646d4ab9e66c9a422dd081a833d657d618aaf2967b5a2",
150
- "constraint-driven-development": "0da347bd34b155ab79cad1e0ee80238f3b4b91b1a17ca0fc2f68460c02224194",
151
- "context-engineering": "f4f18514e5eeb162ef9f925dea85af2c72ba79f9b157783a06c39c0bde102d3f",
152
- "debugging-and-error-recovery": "658d96f63d56946214a7ec87be0347c78d6024a18f6481dc9f7310638f403629",
153
- "deprecation-and-migration": "388d5e7e549f1b728213f0f50d91e9ca96210e0cb23fd9fccd30755268dd01f9",
154
- "documentation-and-adrs": "6b2a9d19ebbb81570022a89f09b4810eeb0643a48c698989ee27a224f90bc026",
155
- "doubt-driven-development": "df8954091f08c14b0e91bf3bf330f43d5a8408c1efe697591b7b0e8448251c71",
156
- "frontend-ui-engineering": "323624fe7ec44bdb4fad3c9488e55993119912625fffa20ee5787389da2b600d",
157
- "git-workflow-and-versioning": "dd28469b0f294865dbd20d622a9fee5f05ef87ab1599e973fec6d15a16f76e15",
158
- "idea-refine": "07eedcfcba98c6c8f6985917830c4b3d93d4e17af05a9b2ca1b8cb54226bc1b9",
159
- "incremental-implementation": "d31e04a0d7b07fc7d01e0176aafbba5607f1cfe7a29a634498305d95c2b3bd3b",
160
- "interview-me": "62700902b592a4fa28f6f71f2581d4e1dee412ff288eb156ed97fac3db8b4295",
161
- "observability-and-instrumentation": "652b9724e431bd7cfd4481bbab31bb079eeab2b5f70ebc04cf66743e37028721",
162
- "performance-optimization": "76befb0806caad12322de8fe372d2e984f6e07c393fd8d3658537c92c7e285cf",
163
- "planning-and-task-breakdown": "c3bc139dfa7af82e2d11c7cf461bbf923add7d6494d669da98925f77a7671641",
164
- "security-and-hardening": "981142e38769394e6e7760250f2dd599dff21a370040f3f141c42507f04ea540",
165
- "shipping-and-launch": "02cc76557e581957cb4987a53e03a8d1aa04c72dc735390d52ae4eed3ddeddf9",
166
- "source-driven-development": "233bf9f16f5fe0960c988a5feb2efc475b9b24f9e145d960f8c63e44f4f34fde",
167
- "spec-driven-development": "e21f25e534ffa3e2de9ac08c40f8d1d90cef17ad55702f83301cbc2a297c2dcb",
168
- "test-driven-development": "38f1489687eaa60761522a8e3efaa926b52786b0e1b3c57947a6050c0da340de",
169
- "using-agent-skills": "df5d4f61855ac46da3371bad8c05edb8bc9375ba191acc82b0cca257cfec946c"
170
- }
171
- }
@@ -1,291 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- 'use strict';
4
-
5
- // Contract test for skills/constraint-driven-development/references/floor-guard.md.
6
- // The fenced `js` block is extracted unchanged and run, with real git, against small
7
- // fixtures: each is a fresh repository with one source file, one test file and a
8
- // CONSTRAINTS.md carrying a floor bullet, a coverage minimum, a bundle maximum and an
9
- // Exceptions table. Loosening moves must exit 1, tightening and no-op moves must exit 0.
10
-
11
- const assert = require('node:assert/strict');
12
- const fs = require('node:fs');
13
- const os = require('node:os');
14
- const path = require('node:path');
15
- const { spawnSync } = require('node:child_process');
16
- const { after, before, test } = require('node:test');
17
-
18
- const REFERENCE = path.join(
19
- __dirname, '..', 'skills', 'constraint-driven-development', 'references', 'floor-guard.md',
20
- );
21
- const CONSTRAINTS = [
22
- '# Constraints',
23
- '',
24
- 'Last reviewed: 2026-08-08 by @owner',
25
- '',
26
- '## Floor',
27
- '- No skipped tests.',
28
- '- Latency: p95 under 200 ms and p99 under 900 ms.',
29
- '',
30
- '| Dimension | Rule |',
31
- '|---|---|',
32
- '| Coverage | >= 80% |',
33
- '| Bundle | <= 200 KB |',
34
- '',
35
- '## Exceptions',
36
- '',
37
- '| ID | Rule | Owner | Expires |',
38
- '|---|---|---|---|',
39
- '| W1 | no-explicit-any | @owner | 2026-11-01 |',
40
- '',
41
- ].join('\n');
42
-
43
- let scratch;
44
- let guard;
45
- const sandboxes = [];
46
-
47
- before(() => {
48
- scratch = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-skills-floor-guard-test-'));
49
- const source = fs.readFileSync(REFERENCE, 'utf8');
50
- const match = source.match(/```js\n([\s\S]*?)\n```/);
51
- assert.ok(match, 'floor-guard.md must contain one fenced js block');
52
- guard = path.join(scratch, 'floor-guard.mjs');
53
- fs.writeFileSync(guard, match[1] + '\n');
54
- });
55
-
56
- after(() => {
57
- for (const dir of sandboxes) fs.rmSync(dir, { recursive: true, force: true });
58
- if (scratch) fs.rmSync(scratch, { recursive: true, force: true });
59
- });
60
-
61
- function git(cwd, ...args) {
62
- const result = spawnSync('git', args, {
63
- cwd,
64
- encoding: 'utf8',
65
- env: {
66
- ...process.env,
67
- GIT_AUTHOR_NAME: 'Floor Guard Test',
68
- GIT_AUTHOR_EMAIL: 'floor-guard@example.invalid',
69
- GIT_COMMITTER_NAME: 'Floor Guard Test',
70
- GIT_COMMITTER_EMAIL: 'floor-guard@example.invalid',
71
- GIT_CONFIG_GLOBAL: '/dev/null',
72
- },
73
- });
74
- assert.equal(result.status, 0, `git ${args.join(' ')} failed: ${result.stderr}`);
75
- return result.stdout;
76
- }
77
-
78
- function makeRepo() {
79
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-skills-floor-guard-fixture-'));
80
- sandboxes.push(root);
81
- git(root, 'init', '-q');
82
- fs.writeFileSync(path.join(root, 'app.js'), 'module.exports = 1;\n');
83
- fs.writeFileSync(
84
- path.join(root, 'app.test.js'),
85
- "const assert = require('assert');\nassert.equal(require('./app'), 1);\n",
86
- );
87
- fs.writeFileSync(path.join(root, 'CONSTRAINTS.md'), CONSTRAINTS);
88
- git(root, 'add', '.');
89
- git(root, 'commit', '-qm', 'baseline');
90
- return root;
91
- }
92
-
93
- function editConstraints(root, from, to) {
94
- const file = path.join(root, 'CONSTRAINTS.md');
95
- const text = fs.readFileSync(file, 'utf8');
96
- assert.ok(text.includes(from), `fixture CONSTRAINTS.md must contain ${JSON.stringify(from)}`);
97
- fs.writeFileSync(file, text.replace(from, to));
98
- }
99
-
100
- function commitFile(root, name, text) {
101
- fs.writeFileSync(path.join(root, name), text);
102
- git(root, 'add', name);
103
- git(root, 'commit', '-qm', `add ${name}`);
104
- }
105
-
106
- function runGuard(root, cwd = root) {
107
- return spawnSync(process.execPath, [guard, '--base', 'HEAD'], { cwd, encoding: 'utf8' });
108
- }
109
-
110
- const cases = [
111
- ['unchanged repository is clean', 0, () => {}],
112
- ['a suppression added to a tracked file is a violation', 1, (root) => {
113
- fs.writeFileSync(path.join(root, 'app.js'), '// @ts-ignore\nmodule.exports = 1;\n');
114
- }],
115
- ['a suppression in a new untracked file is a violation', 1, (root) => {
116
- fs.writeFileSync(path.join(root, 'new.js'), '// @ts-ignore\nmodule.exports = 1;\n');
117
- }],
118
- ['a skipped test in a new untracked file is a violation', 1, (root) => {
119
- fs.writeFileSync(path.join(root, 'new.test.js'), "test.skip('regression', () => {});\n");
120
- }],
121
- ['a suppression in a staged new file is a violation', 1, (root) => {
122
- fs.writeFileSync(path.join(root, 'new.js'), '// @ts-ignore\nmodule.exports = 1;\n');
123
- git(root, 'add', '-A');
124
- }],
125
- ['a deleted test file is a violation', 1, (root) => {
126
- fs.unlinkSync(path.join(root, 'app.test.js'));
127
- }],
128
- ['a staged deleted test file is a violation', 1, (root) => {
129
- fs.unlinkSync(path.join(root, 'app.test.js'));
130
- git(root, 'add', '-A');
131
- }],
132
- ['an assertion removed from a surviving test file is a violation', 1, (root) => {
133
- fs.writeFileSync(path.join(root, 'app.test.js'), "const assert = require('assert');\n");
134
- }],
135
- ['lowering a minimum is a violation', 1, (root) => {
136
- editConstraints(root, '| Coverage | >= 80% |', '| Coverage | >= 60% |');
137
- }],
138
- ['raising a minimum is silent', 0, (root) => {
139
- editConstraints(root, '| Coverage | >= 80% |', '| Coverage | >= 90% |');
140
- }],
141
- ['raising a maximum is a violation', 1, (root) => {
142
- editConstraints(root, '| Bundle | <= 200 KB |', '| Bundle | <= 300 KB |');
143
- }],
144
- ['lowering a maximum is silent', 0, (root) => {
145
- editConstraints(root, '| Bundle | <= 200 KB |', '| Bundle | <= 150 KB |');
146
- }],
147
- ['deleting one threshold from a rule is a violation', 1, (root) => {
148
- editConstraints(root, 'p95 under 200 ms and p99 under 900 ms.', 'p95 under 200 ms.');
149
- }],
150
- ['a number inserted before a threshold is silent', 0, (root) => {
151
- editConstraints(root, '| Coverage | >= 80% |', '| Coverage | per ADR 7, >= 80% |');
152
- }],
153
- ['adding a threshold to a rule is silent', 0, (root) => {
154
- editConstraints(root, '| Bundle | <= 200 KB |', '| Bundle | <= 200 KB, <= 60 KB gzipped |');
155
- }],
156
- ['a deleted floor rule is a violation', 1, (root) => {
157
- editConstraints(root, '- No skipped tests.\n', '');
158
- }],
159
- ['a new exception row is a violation', 1, (root) => {
160
- const file = path.join(root, 'CONSTRAINTS.md');
161
- fs.appendFileSync(file, '| W2 | temporary waiver | @owner | 2026-10-01 |\n');
162
- }],
163
- ];
164
-
165
- for (const [name, expectedExit, mutate] of cases) {
166
- test(`floor guard: ${name}`, () => {
167
- const root = makeRepo();
168
- mutate(root);
169
- const result = runGuard(root);
170
- assert.equal(
171
- result.status, expectedExit,
172
- `expected exit ${expectedExit}, got ${result.status}\nstdout: ${result.stdout}\nstderr: ${result.stderr}`,
173
- );
174
- });
175
- }
176
-
177
- test('floor guard: a removed exception row is silent', () => {
178
- const root = makeRepo();
179
- editConstraints(root, '| W1 | no-explicit-any | @owner | 2026-11-01 |\n', '');
180
- const result = runGuard(root);
181
- assert.equal(result.status, 0, result.stderr);
182
- });
183
-
184
- test('floor guard: a missing merge base exits 2, never 0', () => {
185
- const root = makeRepo();
186
- const result = spawnSync(process.execPath, [guard, '--base', 'no-such-ref'], {
187
- cwd: root, encoding: 'utf8',
188
- });
189
- assert.equal(result.status, 2, result.stderr);
190
- });
191
-
192
- test('floor guard: a threshold with no readable direction is reported when it changes', () => {
193
- const root = makeRepo();
194
- editConstraints(root, '| W1 | no-explicit-any | @owner | 2026-11-01 |', '| W1 | no-explicit-any | @owner | 2027-11-01 |');
195
- const result = runGuard(root);
196
- assert.equal(result.status, 1, result.stderr);
197
- assert.match(result.stderr, /threshold-changed/);
198
- });
199
-
200
- test('floor guard: a renamed rule is reported as removed, with a note that its label may have changed', () => {
201
- const root = makeRepo();
202
- editConstraints(root, '| Coverage | >= 80% |', '| Code coverage | >= 80% |');
203
- const result = runGuard(root);
204
- assert.equal(result.status, 1, result.stderr);
205
- assert.match(result.stderr, /\[rule-removed\]/);
206
- assert.match(result.stderr, /label changed/);
207
- });
208
-
209
- test('floor guard: a threshold that loses its direction words is reported as removed, with a note saying so', () => {
210
- const root = makeRepo();
211
- editConstraints(root, '| Coverage | >= 80% |', '| Coverage | 80% |');
212
- const result = runGuard(root);
213
- assert.equal(result.status, 1, result.stderr);
214
- assert.match(result.stderr, /\[threshold-removed\]/);
215
- assert.match(result.stderr, /direction words/);
216
- });
217
-
218
- // Inside a hunk every line is content. An added line that starts with `++` shows in the diff
219
- // as `+++...`, and a removed line that starts with `--` as `---...`: neither is a file header.
220
- test('floor guard: an added line that starts with ++ is still checked', () => {
221
- const root = makeRepo();
222
- fs.writeFileSync(
223
- path.join(root, 'app.js'),
224
- 'let n = 0;\n++n; // eslint-disable-line no-plusplus\nmodule.exports = n;\n',
225
- );
226
- const result = runGuard(root);
227
- assert.equal(result.status, 1, result.stderr);
228
- assert.match(result.stderr, /\[silenced-checker\] app\.js:/);
229
- });
230
-
231
- test('floor guard: an added line that starts with "++ " does not rename the file for later hunks', () => {
232
- const root = makeRepo();
233
- commitFile(root, 'counter.test.js', [
234
- "const assert = require('assert');",
235
- 'let n = 0;',
236
- 'n += 1;',
237
- 'const m = 2;',
238
- 'assert.equal(n, 1);',
239
- 'assert.equal(m, 2);',
240
- '',
241
- ].join('\n'));
242
- const file = path.join(root, 'counter.test.js');
243
- const text = fs.readFileSync(file, 'utf8');
244
- fs.writeFileSync(file, text.replace('n += 1;', '++ n;').replace('assert.equal(m, 2);\n', ''));
245
- const result = runGuard(root);
246
- assert.equal(result.status, 1, result.stderr);
247
- assert.match(result.stderr, /\[assertion-removed\] counter\.test\.js:/);
248
- });
249
-
250
- test('floor guard: a removed line that starts with -- is still checked', () => {
251
- const root = makeRepo();
252
- commitFile(root, 'countdown.test.js', [
253
- "const assert = require('assert');",
254
- 'let n = 1;',
255
- '--n; assert.equal(n, 0);',
256
- '',
257
- ].join('\n'));
258
- const file = path.join(root, 'countdown.test.js');
259
- fs.writeFileSync(file, fs.readFileSync(file, 'utf8').replace('--n; assert.equal(n, 0);\n', ''));
260
- const result = runGuard(root);
261
- assert.equal(result.status, 1, result.stderr);
262
- assert.match(result.stderr, /\[assertion-removed\] countdown\.test\.js:/);
263
- });
264
-
265
- // `git ls-files` lists only the current directory's subtree, relative to it, while `git diff`
266
- // covers the whole tree with paths from the top. Run from a subfolder, the guard has to see the
267
- // same files, under the same names, as it does from the top.
268
- test('floor guard: run from a subfolder, an untracked file outside it is still checked', () => {
269
- const root = makeRepo();
270
- fs.mkdirSync(path.join(root, 'sub'));
271
- fs.writeFileSync(path.join(root, 'new.js'), '// @ts-ignore\nmodule.exports = 1;\n');
272
- const result = runGuard(root, path.join(root, 'sub'));
273
- assert.equal(result.status, 1, result.stderr);
274
- assert.match(result.stderr, /\[silenced-checker\] new\.js:/);
275
- });
276
-
277
- test('floor guard: run from a subfolder, an untracked file inside it is named from the top', () => {
278
- const root = makeRepo();
279
- fs.mkdirSync(path.join(root, 'sub'));
280
- fs.writeFileSync(path.join(root, 'sub', 'new.js'), '// @ts-ignore\nmodule.exports = 1;\n');
281
- const result = runGuard(root, path.join(root, 'sub'));
282
- assert.equal(result.status, 1, result.stderr);
283
- assert.match(result.stderr, /\[silenced-checker\] sub\/new\.js:/);
284
- });
285
-
286
- test('floor guard: outside a git work tree exits 2, never 0', () => {
287
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-skills-floor-guard-no-repo-'));
288
- sandboxes.push(dir);
289
- const result = runGuard(dir);
290
- assert.equal(result.status, 2, result.stderr);
291
- });