@nerviq/cli 1.29.0 → 1.30.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 (93) hide show
  1. package/CHANGELOG.md +1764 -1493
  2. package/README.md +568 -538
  3. package/SECURITY.md +78 -82
  4. package/bin/cli.js +2838 -2558
  5. package/docs/api-reference.md +356 -356
  6. package/docs/audit-fix.md +109 -0
  7. package/docs/autofix.md +3 -62
  8. package/docs/getting-started.md +1 -1
  9. package/docs/index.html +592 -592
  10. package/docs/integration-contracts.md +287 -287
  11. package/docs/maintenance.md +128 -128
  12. package/docs/new-platform-guide.md +202 -202
  13. package/docs/release-process.md +63 -0
  14. package/docs/shallow-risk.md +244 -244
  15. package/docs/why-nerviq.md +82 -82
  16. package/package.json +75 -67
  17. package/sdk/README.md +12 -3
  18. package/sdk/examples/langchain-integration.md +128 -0
  19. package/sdk/examples/self-governing-agent.js +135 -0
  20. package/sdk/index.d.ts +115 -0
  21. package/sdk/index.js +94 -0
  22. package/sdk/package.json +11 -0
  23. package/src/activity.js +13 -0
  24. package/src/aider/activity.js +226 -226
  25. package/src/aider/context.js +162 -162
  26. package/src/aider/freshness.js +123 -123
  27. package/src/aider/techniques.js +3465 -3465
  28. package/src/audit/layers.js +180 -180
  29. package/src/audit.js +1133 -1032
  30. package/src/auto-suggest.js +9 -2
  31. package/src/behavioral-drift.js +37 -2
  32. package/src/benchmark.js +299 -299
  33. package/src/codex/activity.js +324 -324
  34. package/src/codex/freshness.js +149 -142
  35. package/src/codex/techniques.js +4895 -4895
  36. package/src/context.js +326 -326
  37. package/src/continuous-ops.js +11 -1
  38. package/src/convert.js +340 -340
  39. package/src/copilot/config-parser.js +280 -280
  40. package/src/copilot/context.js +218 -218
  41. package/src/copilot/freshness.js +184 -177
  42. package/src/copilot/patch.js +238 -238
  43. package/src/copilot/techniques.js +3578 -3578
  44. package/src/cursor/freshness.js +194 -194
  45. package/src/cursor/patch.js +243 -243
  46. package/src/cursor/techniques.js +3735 -3735
  47. package/src/doctor.js +201 -201
  48. package/src/fix-engine.js +511 -8
  49. package/src/formatters/csv.js +86 -86
  50. package/src/formatters/junit.js +123 -123
  51. package/src/formatters/markdown.js +164 -164
  52. package/src/formatters/otel.js +151 -151
  53. package/src/freshness.js +163 -156
  54. package/src/gemini/activity.js +402 -402
  55. package/src/gemini/context.js +290 -290
  56. package/src/gemini/freshness.js +188 -188
  57. package/src/gemini/patch.js +229 -229
  58. package/src/gemini/techniques.js +3811 -3811
  59. package/src/governance.js +533 -533
  60. package/src/harmony/audit.js +306 -306
  61. package/src/i18n.js +63 -63
  62. package/src/insights.js +119 -119
  63. package/src/integrations.js +134 -134
  64. package/src/locales/en.json +33 -33
  65. package/src/locales/es.json +33 -33
  66. package/src/migrate.js +354 -354
  67. package/src/opencode/activity.js +286 -286
  68. package/src/opencode/freshness.js +137 -137
  69. package/src/opencode/techniques.js +3450 -3450
  70. package/src/safe-glyph.js +97 -0
  71. package/src/setup/analysis.js +12 -12
  72. package/src/setup.js +13 -6
  73. package/src/shallow-risk/index.js +113 -56
  74. package/src/shallow-risk/patterns/agent-config-cross-platform-drift.js +51 -50
  75. package/src/shallow-risk/patterns/agent-config-dangerous-autoapprove.js +47 -46
  76. package/src/shallow-risk/patterns/agent-config-deprecated-keys.js +47 -46
  77. package/src/shallow-risk/patterns/agent-config-framework-version-mismatch.js +138 -0
  78. package/src/shallow-risk/patterns/agent-config-missing-file.js +318 -317
  79. package/src/shallow-risk/patterns/agent-config-script-not-in-package-json.js +108 -0
  80. package/src/shallow-risk/patterns/agent-config-secret-literal.js +52 -49
  81. package/src/shallow-risk/patterns/agent-config-stack-contradiction.js +35 -34
  82. package/src/shallow-risk/patterns/hook-script-missing.js +71 -70
  83. package/src/shallow-risk/patterns/mcp-server-no-allowlist.js +53 -52
  84. package/src/shallow-risk/shared.js +653 -648
  85. package/src/source-urls.js +295 -295
  86. package/src/state-paths.js +85 -85
  87. package/src/supplemental-checks.js +805 -805
  88. package/src/telemetry.js +160 -160
  89. package/src/watch.js +46 -0
  90. package/src/windsurf/context.js +359 -359
  91. package/src/windsurf/freshness.js +194 -194
  92. package/src/windsurf/patch.js +231 -231
  93. package/src/windsurf/techniques.js +3779 -3779
@@ -1,202 +1,202 @@
1
- # New Platform Onboarding Guide
2
-
3
- How to add a new AI coding platform to Nerviq.
4
-
5
- ## Overview
6
-
7
- Each platform in Nerviq follows a standardized structure with 14 source modules, dedicated tests, research documentation, and integration points. This guide walks through every step required to bring a new platform from zero to full parity.
8
-
9
- ## Prerequisites
10
-
11
- - Access to the platform's official documentation
12
- - A test project configured for the platform
13
- - Familiarity with Nerviq's audit engine (`src/audit.js`)
14
-
15
- ## Step 1: Research Phase
16
-
17
- Before writing code, produce the research deliverables:
18
-
19
- 1. **Platform Research Doc** — `research/{platform}-platform-research-v1-YYYY-MM-DD.md`
20
- - Architecture, config file formats, CLI commands, extension points
21
- - Minimum 5 queries from different angles (Anthropic research protocol)
22
- - Confidence levels for every claim
23
-
24
- 2. **Gap Matrix** — `research/nerviq-{platform}-full-gap-matrix-YYYY-MM-DD.md`
25
- - Compare platform capabilities against Claude Code baseline
26
- - Identify all gaps and parity opportunities
27
-
28
- 3. **Build Plan** — `research/nerviq-for-{platform}-build-plan-v3-final-YYYY-MM-DD.md`
29
- - Phased implementation plan with deliverables per phase
30
- - Dependencies and risk assessment
31
-
32
- 4. **Parity Closure Plan** — `research/nerviq-{platform}-parity-closure-plan-v1-YYYY-MM-DD.md`
33
- - Specific steps to close each identified gap
34
-
35
- ## Step 2: Create Platform Source Modules
36
-
37
- Create the directory `src/{platform}/` with these 14 required modules:
38
-
39
- | # | File | Purpose |
40
- |---|------|---------|
41
- | 1 | `techniques.js` | Check definitions (id, name, check function, impact, category, fix) |
42
- | 2 | `config-parser.js` | Parse platform-specific config files |
43
- | 3 | `context.js` | `{Platform}ProjectContext` class with `is{Platform}Repo(dir)` detection |
44
- | 4 | `setup.js` | Generate starter config files for the platform |
45
- | 5 | `plans.js` | Proposal generation and application logic |
46
- | 6 | `governance.js` | Permission profiles, policy packs, governance rules |
47
- | 7 | `interactive.js` | Step-by-step guided wizard for the platform |
48
- | 8 | `deep-review.js` | AI-powered config review (opt-in) |
49
- | 9 | `freshness.js` | Freshness checks for platform-specific configs |
50
- | 10 | `domain-packs.js` | Domain-specific check packs (React, Python, etc.) |
51
- | 11 | `mcp-packs.js` | MCP server integration packs |
52
- | 12 | `activity.js` | Snapshot and activity tracking |
53
- | 13 | `patch.js` | Config patching and migration helpers |
54
- | 14 | `premium.js` | Premium/advanced checks |
55
-
56
- ### Module template
57
-
58
- Each `techniques.js` must export an array of check objects:
59
-
60
- ```js
61
- module.exports = [
62
- {
63
- key: '{platform}ConfigExists',
64
- name: '{Platform} config file exists',
65
- category: 'Memory & Context',
66
- impact: 'critical',
67
- check: (dir) => {
68
- const fs = require('fs');
69
- return fs.existsSync(`${dir}/.{platform}-config`);
70
- },
71
- fix: 'Create a .{platform}-config file in the project root.',
72
- sourceUrl: 'https://docs.{platform}.dev/config',
73
- confidence: 0.9,
74
- },
75
- // ... more checks
76
- ];
77
- ```
78
-
79
- Each `context.js` must export a class with static detection:
80
-
81
- ```js
82
- class {Platform}ProjectContext {
83
- static is{Platform}Repo(dir) {
84
- const fs = require('fs');
85
- return fs.existsSync(`${dir}/.{platform}-config`);
86
- }
87
- }
88
- module.exports = { {Platform}ProjectContext };
89
- ```
90
-
91
- ## Step 3: Create Test Files
92
-
93
- | File | Purpose |
94
- |------|---------|
95
- | `test/{platform}.test.js` | Unit tests for all 14 modules |
96
- | `test/{platform}-check-matrix.js` | Matrix test: every check runs against fixtures |
97
- | `test/{platform}-golden-matrix.js` | Golden file test: audit output matches expected |
98
- | `test/{platform}-fixtures.js` | Test fixture generator |
99
-
100
- ### Check matrix template
101
-
102
- The check matrix ensures every technique key in `techniques.js` is exercised:
103
-
104
- ```js
105
- const techniques = require('../src/{platform}/techniques');
106
- const allKeys = techniques.map(t => t.key);
107
-
108
- for (const key of allKeys) {
109
- // Verify check function exists and returns boolean
110
- const technique = techniques.find(t => t.key === key);
111
- const result = technique.check(fixtureDir);
112
- assert(typeof result === 'boolean', `${key} must return boolean`);
113
- }
114
- ```
115
-
116
- ## Step 4: Integration Points
117
-
118
- ### 4a. Register in `src/audit.js`
119
-
120
- Add platform detection and technique loading:
121
-
122
- ```js
123
- // In the platform resolution logic
124
- if (platform === '{platform}') {
125
- techniques = require('./{platform}/techniques');
126
- }
127
- ```
128
-
129
- ### 4b. Register in `src/public-api.js`
130
-
131
- Add to `PLATFORM_ORDER` and `PLATFORM_DETECTORS`:
132
-
133
- ```js
134
- const { {Platform}ProjectContext } = require('./{platform}/context');
135
-
136
- // In PLATFORM_ORDER array:
137
- '{platform}',
138
-
139
- // In PLATFORM_DETECTORS object:
140
- {platform}: (dir) => {Platform}ProjectContext.is{Platform}Repo(dir),
141
- ```
142
-
143
- ### 4c. Register in `src/catalog.js`
144
-
145
- Ensure `generateCatalog()` includes the new platform's techniques.
146
-
147
- ### 4d. Register in `bin/cli.js`
148
-
149
- Add platform validation in the CLI argument parser (the platform check near line 363).
150
-
151
- ### 4e. Register in Harmony
152
-
153
- Add to `PLATFORM_AUDIT_MAP` in `src/harmony/audit.js`:
154
-
155
- ```js
156
- {platform}: '{platform}',
157
- ```
158
-
159
- ### 4f. Update `action.yml`
160
-
161
- Add platform to the GitHub Action inputs if needed.
162
-
163
- ## Step 5: Documentation
164
-
165
- - Update `README.md` platform table
166
- - Update `CHANGELOG.md` with the new platform entry
167
- - Add platform to `package.json` keywords
168
- - Update `docs/ARCHITECTURE.md` if it references platform list
169
-
170
- ## 17-Point Deliverables Checklist
171
-
172
- Use this checklist to track completion. All items must be done before the platform is considered fully supported.
173
-
174
- - [ ] 1. Platform research document
175
- - [ ] 2. Gap matrix vs Claude Code baseline
176
- - [ ] 3. Build plan (v3 final)
177
- - [ ] 4. Parity closure plan
178
- - [ ] 5. `src/{platform}/techniques.js` — all checks with sourceUrl + confidence
179
- - [ ] 6. `src/{platform}/config-parser.js`
180
- - [ ] 7. `src/{platform}/context.js` — with `is{Platform}Repo()` detection
181
- - [ ] 8. `src/{platform}/setup.js`
182
- - [ ] 9. `src/{platform}/plans.js`
183
- - [ ] 10. `src/{platform}/governance.js`
184
- - [ ] 11. Remaining 8 modules (interactive, deep-review, freshness, domain-packs, mcp-packs, activity, patch, premium)
185
- - [ ] 12. `test/{platform}.test.js`
186
- - [ ] 13. `test/{platform}-check-matrix.js`
187
- - [ ] 14. `test/{platform}-golden-matrix.js`
188
- - [ ] 15. Integration in audit.js, public-api.js, catalog.js, cli.js
189
- - [ ] 16. Harmony integration
190
- - [ ] 17. README, CHANGELOG, and documentation updates
191
-
192
- ## Quality Gates
193
-
194
- Before merging a new platform:
195
-
196
- 1. All check-matrix tests pass: `node test/{platform}-check-matrix.js`
197
- 2. All golden-matrix tests pass: `node test/{platform}-golden-matrix.js`
198
- 3. Jest tests pass: `npx jest test/{platform}.test.js`
199
- 4. Platform appears in `nerviq catalog` output
200
- 5. `nerviq audit --platform {platform}` runs successfully on a real project
201
- 6. Harmony audit includes the new platform
202
- 7. Every technique has `sourceUrl` and `confidence >= 0.7`
1
+ # New Platform Onboarding Guide
2
+
3
+ How to add a new AI coding platform to Nerviq.
4
+
5
+ ## Overview
6
+
7
+ Each platform in Nerviq follows a standardized structure with 14 source modules, dedicated tests, research documentation, and integration points. This guide walks through every step required to bring a new platform from zero to full parity.
8
+
9
+ ## Prerequisites
10
+
11
+ - Access to the platform's official documentation
12
+ - A test project configured for the platform
13
+ - Familiarity with Nerviq's audit engine (`src/audit.js`)
14
+
15
+ ## Step 1: Research Phase
16
+
17
+ Before writing code, produce the research deliverables:
18
+
19
+ 1. **Platform Research Doc** — `research/{platform}-platform-research-v1-YYYY-MM-DD.md`
20
+ - Architecture, config file formats, CLI commands, extension points
21
+ - Minimum 5 queries from different angles (Anthropic research protocol)
22
+ - Confidence levels for every claim
23
+
24
+ 2. **Gap Matrix** — `research/nerviq-{platform}-full-gap-matrix-YYYY-MM-DD.md`
25
+ - Compare platform capabilities against Claude Code baseline
26
+ - Identify all gaps and parity opportunities
27
+
28
+ 3. **Build Plan** — `research/nerviq-for-{platform}-build-plan-v3-final-YYYY-MM-DD.md`
29
+ - Phased implementation plan with deliverables per phase
30
+ - Dependencies and risk assessment
31
+
32
+ 4. **Parity Closure Plan** — `research/nerviq-{platform}-parity-closure-plan-v1-YYYY-MM-DD.md`
33
+ - Specific steps to close each identified gap
34
+
35
+ ## Step 2: Create Platform Source Modules
36
+
37
+ Create the directory `src/{platform}/` with these 14 required modules:
38
+
39
+ | # | File | Purpose |
40
+ |---|------|---------|
41
+ | 1 | `techniques.js` | Check definitions (id, name, check function, impact, category, fix) |
42
+ | 2 | `config-parser.js` | Parse platform-specific config files |
43
+ | 3 | `context.js` | `{Platform}ProjectContext` class with `is{Platform}Repo(dir)` detection |
44
+ | 4 | `setup.js` | Generate starter config files for the platform |
45
+ | 5 | `plans.js` | Proposal generation and application logic |
46
+ | 6 | `governance.js` | Permission profiles, policy packs, governance rules |
47
+ | 7 | `interactive.js` | Step-by-step guided wizard for the platform |
48
+ | 8 | `deep-review.js` | AI-powered config review (opt-in) |
49
+ | 9 | `freshness.js` | Freshness checks for platform-specific configs |
50
+ | 10 | `domain-packs.js` | Domain-specific check packs (React, Python, etc.) |
51
+ | 11 | `mcp-packs.js` | MCP server integration packs |
52
+ | 12 | `activity.js` | Snapshot and activity tracking |
53
+ | 13 | `patch.js` | Config patching and migration helpers |
54
+ | 14 | `premium.js` | Premium/advanced checks |
55
+
56
+ ### Module template
57
+
58
+ Each `techniques.js` must export an array of check objects:
59
+
60
+ ```js
61
+ module.exports = [
62
+ {
63
+ key: '{platform}ConfigExists',
64
+ name: '{Platform} config file exists',
65
+ category: 'Memory & Context',
66
+ impact: 'critical',
67
+ check: (dir) => {
68
+ const fs = require('fs');
69
+ return fs.existsSync(`${dir}/.{platform}-config`);
70
+ },
71
+ fix: 'Create a .{platform}-config file in the project root.',
72
+ sourceUrl: 'https://docs.{platform}.dev/config',
73
+ confidence: 0.9,
74
+ },
75
+ // ... more checks
76
+ ];
77
+ ```
78
+
79
+ Each `context.js` must export a class with static detection:
80
+
81
+ ```js
82
+ class {Platform}ProjectContext {
83
+ static is{Platform}Repo(dir) {
84
+ const fs = require('fs');
85
+ return fs.existsSync(`${dir}/.{platform}-config`);
86
+ }
87
+ }
88
+ module.exports = { {Platform}ProjectContext };
89
+ ```
90
+
91
+ ## Step 3: Create Test Files
92
+
93
+ | File | Purpose |
94
+ |------|---------|
95
+ | `test/{platform}.test.js` | Unit tests for all 14 modules |
96
+ | `test/{platform}-check-matrix.js` | Matrix test: every check runs against fixtures |
97
+ | `test/{platform}-golden-matrix.js` | Golden file test: audit output matches expected |
98
+ | `test/{platform}-fixtures.js` | Test fixture generator |
99
+
100
+ ### Check matrix template
101
+
102
+ The check matrix ensures every technique key in `techniques.js` is exercised:
103
+
104
+ ```js
105
+ const techniques = require('../src/{platform}/techniques');
106
+ const allKeys = techniques.map(t => t.key);
107
+
108
+ for (const key of allKeys) {
109
+ // Verify check function exists and returns boolean
110
+ const technique = techniques.find(t => t.key === key);
111
+ const result = technique.check(fixtureDir);
112
+ assert(typeof result === 'boolean', `${key} must return boolean`);
113
+ }
114
+ ```
115
+
116
+ ## Step 4: Integration Points
117
+
118
+ ### 4a. Register in `src/audit.js`
119
+
120
+ Add platform detection and technique loading:
121
+
122
+ ```js
123
+ // In the platform resolution logic
124
+ if (platform === '{platform}') {
125
+ techniques = require('./{platform}/techniques');
126
+ }
127
+ ```
128
+
129
+ ### 4b. Register in `src/public-api.js`
130
+
131
+ Add to `PLATFORM_ORDER` and `PLATFORM_DETECTORS`:
132
+
133
+ ```js
134
+ const { {Platform}ProjectContext } = require('./{platform}/context');
135
+
136
+ // In PLATFORM_ORDER array:
137
+ '{platform}',
138
+
139
+ // In PLATFORM_DETECTORS object:
140
+ {platform}: (dir) => {Platform}ProjectContext.is{Platform}Repo(dir),
141
+ ```
142
+
143
+ ### 4c. Register in `src/catalog.js`
144
+
145
+ Ensure `generateCatalog()` includes the new platform's techniques.
146
+
147
+ ### 4d. Register in `bin/cli.js`
148
+
149
+ Add platform validation in the CLI argument parser (the platform check near line 363).
150
+
151
+ ### 4e. Register in Harmony
152
+
153
+ Add to `PLATFORM_AUDIT_MAP` in `src/harmony/audit.js`:
154
+
155
+ ```js
156
+ {platform}: '{platform}',
157
+ ```
158
+
159
+ ### 4f. Update `action.yml`
160
+
161
+ Add platform to the GitHub Action inputs if needed.
162
+
163
+ ## Step 5: Documentation
164
+
165
+ - Update `README.md` platform table
166
+ - Update `CHANGELOG.md` with the new platform entry
167
+ - Add platform to `package.json` keywords
168
+ - Update `docs/ARCHITECTURE.md` if it references platform list
169
+
170
+ ## 17-Point Deliverables Checklist
171
+
172
+ Use this checklist to track completion. All items must be done before the platform is considered fully supported.
173
+
174
+ - [ ] 1. Platform research document
175
+ - [ ] 2. Gap matrix vs Claude Code baseline
176
+ - [ ] 3. Build plan (v3 final)
177
+ - [ ] 4. Parity closure plan
178
+ - [ ] 5. `src/{platform}/techniques.js` — all checks with sourceUrl + confidence
179
+ - [ ] 6. `src/{platform}/config-parser.js`
180
+ - [ ] 7. `src/{platform}/context.js` — with `is{Platform}Repo()` detection
181
+ - [ ] 8. `src/{platform}/setup.js`
182
+ - [ ] 9. `src/{platform}/plans.js`
183
+ - [ ] 10. `src/{platform}/governance.js`
184
+ - [ ] 11. Remaining 8 modules (interactive, deep-review, freshness, domain-packs, mcp-packs, activity, patch, premium)
185
+ - [ ] 12. `test/{platform}.test.js`
186
+ - [ ] 13. `test/{platform}-check-matrix.js`
187
+ - [ ] 14. `test/{platform}-golden-matrix.js`
188
+ - [ ] 15. Integration in audit.js, public-api.js, catalog.js, cli.js
189
+ - [ ] 16. Harmony integration
190
+ - [ ] 17. README, CHANGELOG, and documentation updates
191
+
192
+ ## Quality Gates
193
+
194
+ Before merging a new platform:
195
+
196
+ 1. All check-matrix tests pass: `node test/{platform}-check-matrix.js`
197
+ 2. All golden-matrix tests pass: `node test/{platform}-golden-matrix.js`
198
+ 3. Jest tests pass: `npx jest test/{platform}.test.js`
199
+ 4. Platform appears in `nerviq catalog` output
200
+ 5. `nerviq audit --platform {platform}` runs successfully on a real project
201
+ 6. Harmony audit includes the new platform
202
+ 7. Every technique has `sourceUrl` and `confidence >= 0.7`
@@ -0,0 +1,63 @@
1
+ # Release Process
2
+
3
+ This is the canonical publish path for `@nerviq/cli`.
4
+
5
+ ## Rule
6
+
7
+ Do not publish from a local workstation.
8
+
9
+ The supported path is a human-triggered GitHub Actions workflow that publishes
10
+ from `main` with npm provenance attestation.
11
+
12
+ ## Canonical flow
13
+
14
+ 1. Make sure `package.json`, `release-metadata.json`, and `CHANGELOG.md` all
15
+ reflect the intended version.
16
+ 2. Push the release commit to `main`.
17
+ 3. Trigger the publish workflow manually:
18
+
19
+ ```bash
20
+ gh workflow run publish.yml -f version=X.Y.Z
21
+ ```
22
+
23
+ 4. Approve the `npm-publish` environment when GitHub requests manual approval.
24
+ 5. Let the workflow run the release gates and publish to npm with provenance.
25
+
26
+ ## What `publish.yml` does
27
+
28
+ The workflow runs on `workflow_dispatch` only and publishes only from `main`.
29
+
30
+ Before `npm publish`, it runs:
31
+
32
+ - `node tools/pre-publish.js --ci --expected-version X.Y.Z --skip-tests --skip-metadata`
33
+ - `npx jest`
34
+ - `npm run verify:release-metadata -- --site-url https://nerviq.net`
35
+
36
+ If those pass, it publishes with:
37
+
38
+ ```bash
39
+ npm publish --provenance --access public
40
+ ```
41
+
42
+ The publish job uses:
43
+
44
+ - `id-token: write` for npm provenance attestation
45
+ - `NODE_AUTH_TOKEN` from the `NPM_TOKEN` repository secret
46
+ - the `npm-publish` GitHub environment for manual approval
47
+
48
+ ## Why this replaced local publish
49
+
50
+ This workflow is the safest publish path because it:
51
+
52
+ - publishes from the exact commit already on `main`
53
+ - uses a clean runner instead of a potentially stale local clone
54
+ - enforces version, changelog, and metadata alignment
55
+ - produces npm provenance attestation automatically
56
+ - keeps approval and publishing in one auditable workflow
57
+
58
+ ## Notes
59
+
60
+ - `tools/pre-publish.js` still exists for local preflight and CI reuse, but it
61
+ is no longer the canonical way to publish from a laptop.
62
+ - `ci.yml` no longer publishes on tags. Publishing is intentionally separated
63
+ into `publish.yml` so the human can choose when a release goes live.