@nan0web/release 1.0.2 → 3.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.
- package/README.md +42 -17
- package/bin/nan0release.js +3 -39
- package/knip.json +21 -0
- package/nan0web.nan0 +16 -0
- package/package.json +48 -49
- package/project.yaml +79 -0
- package/src/README.md.js +463 -0
- package/src/Release/Person.js +1 -1
- package/src/agents/inspectors/git-reviewer.md +35 -0
- package/src/agents/inspectors/package-hygiene.md +63 -0
- package/src/agents/workflows/commit.md +28 -0
- package/src/agents/workflows/npm-release.md +40 -0
- package/src/agents/workflows/release.md +205 -0
- package/src/agents/workflows/zero-tolerance-git.md +21 -0
- package/src/domain/App.js +33 -0
- package/src/domain/CheckCommand.js +193 -0
- package/src/domain/CloseCommand.js +68 -0
- package/src/domain/DepsCommand.js +104 -0
- package/src/domain/InitCommand.js +57 -0
- package/src/domain/PublishCommand.js +89 -0
- package/src/domain/SpecCommand.js +43 -0
- package/src/domain/StatusCommand.js +25 -0
- package/src/index.js +9 -0
- package/types/Release/Person.d.ts +3 -3
- package/types/Team.d.ts +3 -3
- package/types/commands/CheckCommand.d.ts +24 -0
- package/types/commands/CloseCommand.d.ts +2 -1
- package/types/commands/Command.d.ts +6 -1
- package/types/commands/DepsCommand.d.ts +2 -1
- package/types/commands/InitCommand.d.ts +2 -1
- package/types/commands/PublishCommand.d.ts +2 -1
- package/types/commands/SpecCommand.d.ts +2 -1
- package/types/domain/App.d.ts +16 -0
- package/types/domain/CheckCommand.d.ts +24 -0
- package/types/domain/CloseCommand.d.ts +17 -0
- package/types/domain/DepsCommand.d.ts +22 -0
- package/types/domain/InitCommand.d.ts +18 -0
- package/types/domain/PublishCommand.d.ts +27 -0
- package/types/domain/SpecCommand.d.ts +17 -0
- package/types/domain/StatusCommand.d.ts +7 -0
- package/types/index.d.ts +8 -0
- package/types/ui/cli/index.d.ts +1 -0
- package/types/utils/runSpawn.d.ts +1 -0
- package/src/Team.js +0 -35
- package/src/cli/index.js +0 -9
- package/src/co/AppCommandOptions.js +0 -25
- package/src/commands/CloseCommand.js +0 -67
- package/src/commands/Command.js +0 -48
- package/src/commands/DepsCommand.js +0 -143
- package/src/commands/InitCommand.js +0 -57
- package/src/commands/PublishCommand.js +0 -105
- package/src/commands/SpecCommand.js +0 -41
- package/src/commands/StatusCommand.js +0 -26
- package/src/db/ReleaseDB.js +0 -54
- package/src/ui/cli/ReleaseCLi.js +0 -52
- package/src/ui/cli/index.js +0 -0
- package/src/utils/runSpawn.js +0 -0
package/src/README.md.js
ADDED
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
import { describe, it, before, beforeEach } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { readFile } from 'node:fs/promises'
|
|
4
|
+
import FS from '@nan0web/db-fs'
|
|
5
|
+
import { NoConsole } from '@nan0web/log'
|
|
6
|
+
import { DatasetParser, DocsParser, runSpawn } from '@nan0web/test'
|
|
7
|
+
import { App } from './index.js'
|
|
8
|
+
import Release from './Release.js'
|
|
9
|
+
import ReleaseDocument from './Release/Document.js'
|
|
10
|
+
import Person from './Release/Person.js'
|
|
11
|
+
import {
|
|
12
|
+
ProjectManagement,
|
|
13
|
+
ReleaseManager,
|
|
14
|
+
TaskTestSuite,
|
|
15
|
+
ChangelogTaskManager,
|
|
16
|
+
} from './architecture/ProjectManagementAsCode.js'
|
|
17
|
+
|
|
18
|
+
const fs = new FS()
|
|
19
|
+
let pkg
|
|
20
|
+
|
|
21
|
+
// Load package.json once before tests
|
|
22
|
+
before(async () => {
|
|
23
|
+
const doc = await fs.loadDocument('package.json', {})
|
|
24
|
+
pkg = doc || {}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
let console = new NoConsole()
|
|
28
|
+
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
console = new NoConsole()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Core test suite that also serves as the source for README generation.
|
|
35
|
+
*
|
|
36
|
+
* The block comments inside each `it` block are extracted to build
|
|
37
|
+
* the final `README.md`. Keeping the comments here ensures the
|
|
38
|
+
* documentation stays close to the code.
|
|
39
|
+
*/
|
|
40
|
+
function testRender() {
|
|
41
|
+
/**
|
|
42
|
+
* @docs
|
|
43
|
+
* # @nan0web/release
|
|
44
|
+
*
|
|
45
|
+
* <!-- %PACKAGE_STATUS% -->
|
|
46
|
+
*
|
|
47
|
+
* Project management as code, Git-native, GPG-signed, and test-driven.
|
|
48
|
+
*
|
|
49
|
+
* Unlike traditional project tools that require constant syncing or manual updates,
|
|
50
|
+
* `@nan0web/release` enforces project structure where:
|
|
51
|
+
* - Tasks are represented as tests in `.test.js` files.
|
|
52
|
+
* - Status is tracked via test outcomes.
|
|
53
|
+
* - Team roles and approvals are stored in structured files.
|
|
54
|
+
* - All changes are signed, versioned, and composable.
|
|
55
|
+
*
|
|
56
|
+
* This ensures:
|
|
57
|
+
* - Clear, automatable project tracking.
|
|
58
|
+
* - Immutable release notes and retro reflections.
|
|
59
|
+
* - Zero ambiguity – tasks don't exist unless tested.
|
|
60
|
+
*
|
|
61
|
+
* ## Installation
|
|
62
|
+
*/
|
|
63
|
+
it('How to install with pnpm?', () => {
|
|
64
|
+
/**
|
|
65
|
+
* ```bash
|
|
66
|
+
* pnpm add @nan0web/release
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
assert.equal(pkg.name, '@nan0web/release')
|
|
70
|
+
})
|
|
71
|
+
/**
|
|
72
|
+
* @docs
|
|
73
|
+
*/
|
|
74
|
+
it('How to install with npm?', () => {
|
|
75
|
+
/**
|
|
76
|
+
* ```bash
|
|
77
|
+
* npm install @nan0web/release
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
assert.equal(pkg.name, '@nan0web/release')
|
|
81
|
+
})
|
|
82
|
+
/**
|
|
83
|
+
* @docs
|
|
84
|
+
*/
|
|
85
|
+
it('How to install with yarn?', () => {
|
|
86
|
+
/**
|
|
87
|
+
* ```bash
|
|
88
|
+
* yarn add @nan0web/release
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
assert.equal(pkg.name, '@nan0web/release')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @docs
|
|
96
|
+
* ## CLI Usage
|
|
97
|
+
*
|
|
98
|
+
* Start by initializing a new release:
|
|
99
|
+
*/
|
|
100
|
+
it('How to initialize a new release version?', () => {
|
|
101
|
+
/**
|
|
102
|
+
* ```bash
|
|
103
|
+
* nan0release init v1.0.0
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
assert.ok(new App().constructor.command.options)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @docs
|
|
111
|
+
* Show release details:
|
|
112
|
+
*/
|
|
113
|
+
it('How to show release information?', () => {
|
|
114
|
+
/**
|
|
115
|
+
* ```bash
|
|
116
|
+
* release show [--full]
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
const release = new Release({
|
|
120
|
+
version: 'v1.0.0',
|
|
121
|
+
createdAt: new Date('2025-08-20'),
|
|
122
|
+
})
|
|
123
|
+
console.info(release.version) // v1.0.0
|
|
124
|
+
assert.strictEqual(console.output()[0][1], 'v1.0.0')
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @docs
|
|
129
|
+
* List all releases in the project:
|
|
130
|
+
*/
|
|
131
|
+
it('How to list all releases?', () => {
|
|
132
|
+
/**
|
|
133
|
+
* ```bash
|
|
134
|
+
* nan0release list [--json]
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
assert.ok(new App().constructor.command.options)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @docs
|
|
142
|
+
* Add a chat message to the current release:
|
|
143
|
+
*/
|
|
144
|
+
it('How to write a release chat message?', () => {
|
|
145
|
+
/**
|
|
146
|
+
* ```bash
|
|
147
|
+
* nan0release chat write --user alice "Issue with the build pipeline"
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
assert.ok(new App().constructor.command.options)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @docs
|
|
155
|
+
* Host a static server for viewing releases:
|
|
156
|
+
*/
|
|
157
|
+
it('How to host release UI?', () => {
|
|
158
|
+
/**
|
|
159
|
+
* ```bash
|
|
160
|
+
* nan0release host [--webui] [--port 3000]
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
assert.ok(new App().constructor.command.options)
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @docs
|
|
168
|
+
* Serve all release files for local inspection:
|
|
169
|
+
*/
|
|
170
|
+
it('How to serve release static assets?', () => {
|
|
171
|
+
/**
|
|
172
|
+
* ```bash
|
|
173
|
+
* nan0release serve [--port 8080]
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
assert.ok(new App().constructor.command.options)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* @docs
|
|
181
|
+
* Validate release tasks and integrity:
|
|
182
|
+
*/
|
|
183
|
+
it('How to validate release tasks?', () => {
|
|
184
|
+
/**
|
|
185
|
+
* ```bash
|
|
186
|
+
* nan0release validate [--ignore-fail]
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
assert.ok(true)
|
|
190
|
+
const release = new Release({
|
|
191
|
+
version: 'v1.0.0',
|
|
192
|
+
createdAt: new Date('2025-08-20'),
|
|
193
|
+
})
|
|
194
|
+
assert.ok(release instanceof Release)
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* @docs
|
|
199
|
+
* Seal the release with retro reflection:
|
|
200
|
+
*/
|
|
201
|
+
it('How to seal a release?', () => {
|
|
202
|
+
/**
|
|
203
|
+
* ```bash
|
|
204
|
+
* nan0release seal [--message "All core APIs are stable and tested"]
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
assert.ok(new App().constructor.command.options)
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @docs
|
|
212
|
+
* ## Core Concepts
|
|
213
|
+
*
|
|
214
|
+
* ### 1. Release as Object
|
|
215
|
+
*
|
|
216
|
+
* A `Release` is a structured class containing:
|
|
217
|
+
* - `version`: release identifier (vX.Y.Z).
|
|
218
|
+
* - `createdAt`, `startAt`, `planAt`, `completeAt`: datetime milestones.
|
|
219
|
+
* - `document`: parsed markdown document with structure-aware parsing.
|
|
220
|
+
*
|
|
221
|
+
* Each property is typed and validated automatically via JSDoc and runtime parsing.
|
|
222
|
+
*/
|
|
223
|
+
it('How to instantiate a Release?', () => {
|
|
224
|
+
//import { Release } from '@nan0web/release'
|
|
225
|
+
const release = new Release({
|
|
226
|
+
version: 'v1.0.0',
|
|
227
|
+
createdAt: '2025-08-20T10:00:00Z',
|
|
228
|
+
})
|
|
229
|
+
console.info(release.version) // ← v1.0.0
|
|
230
|
+
console.info(release.createdAt instanceof Date) // ← true
|
|
231
|
+
|
|
232
|
+
assert.strictEqual(console.output()[0][1], 'v1.0.0')
|
|
233
|
+
assert.strictEqual(console.output()[1][1], true)
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* @docs
|
|
238
|
+
* ### 2. Release Document Parsing
|
|
239
|
+
*
|
|
240
|
+
* A `ReleaseDocument` extends `@nan0web/markdown` with:
|
|
241
|
+
* - Structured parsing of markdown release notes
|
|
242
|
+
* - Extraction of sections and tasks
|
|
243
|
+
* - Team and role parsing from markdown frontmatter or code
|
|
244
|
+
*/
|
|
245
|
+
it('How to parse release notes markdown into structured data?', () => {
|
|
246
|
+
//import { ReleaseDocument } from '@nan0web/release'
|
|
247
|
+
const md = `# v1.0.0 - 2025-08-20
|
|
248
|
+
|
|
249
|
+
## Overview
|
|
250
|
+
Release milestone includes UI polish and core API stabilization.
|
|
251
|
+
|
|
252
|
+
### Tasks
|
|
253
|
+
### Done **Implement core UI design** [ui.core-design]
|
|
254
|
+
### InProgress **Fix responsive issues in mobile layout** [ui.mobile-fixes]`
|
|
255
|
+
|
|
256
|
+
const doc = ReleaseDocument.from(md)
|
|
257
|
+
console.info(doc.version) // ← v1.0.0
|
|
258
|
+
console.info(doc.date instanceof Date) // ← true
|
|
259
|
+
console.info(doc.document.children instanceof Array) // ← true
|
|
260
|
+
|
|
261
|
+
assert.strictEqual(console.output()[0][1], 'v1.0.0')
|
|
262
|
+
assert.strictEqual(console.output()[1][1], true)
|
|
263
|
+
assert.strictEqual(console.output()[2][1], true)
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* @docs
|
|
268
|
+
* ### 3. Person & Team Structures
|
|
269
|
+
*
|
|
270
|
+
* A `Person` instance includes:
|
|
271
|
+
* - `name`: HumanName
|
|
272
|
+
* - `gender`: HumanGender
|
|
273
|
+
* - `contacts`: array of HumanContact
|
|
274
|
+
*/
|
|
275
|
+
it('How to create a Person with typed properties?', () => {
|
|
276
|
+
//import { Person } from '@nan0web/release'
|
|
277
|
+
const person = new Person({
|
|
278
|
+
name: ['Alice', 'Developer'],
|
|
279
|
+
gender: 'female',
|
|
280
|
+
contacts: ['mailto:alice@example.com'],
|
|
281
|
+
})
|
|
282
|
+
console.info(person.name.firstName) // ← Alice
|
|
283
|
+
console.info(person.contacts.length >= 0) // ← true
|
|
284
|
+
|
|
285
|
+
assert.strictEqual(console.output()[0][1], 'Alice')
|
|
286
|
+
assert.strictEqual(console.output()[1][1], true)
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* @docs
|
|
291
|
+
* ## Architecture: Project Management as Code
|
|
292
|
+
*
|
|
293
|
+
* This architecture treats tasks as tests, roles as classes, and progress as validated outcomes.
|
|
294
|
+
*
|
|
295
|
+
* ### Task Management
|
|
296
|
+
*
|
|
297
|
+
* Tasks are registered as `taskId` → `testFilePath` in `ProjectManagement`.
|
|
298
|
+
* Their status is derived by running `node:test` suites.
|
|
299
|
+
*/
|
|
300
|
+
it('How to register and validate tasks as tests?', async () => {
|
|
301
|
+
//import { ProjectManagement } from '@nan0web/release'
|
|
302
|
+
const pm = new ProjectManagement()
|
|
303
|
+
pm.registerTask('task-1', './tests/task1.test.js')
|
|
304
|
+
pm.registerTask('task-2', './tests/task2.test.js')
|
|
305
|
+
|
|
306
|
+
const mockResults = {
|
|
307
|
+
passed: ['task-1'],
|
|
308
|
+
failed: [],
|
|
309
|
+
pending: ['task-2'],
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
pm.validateProjectState = async () => mockResults
|
|
313
|
+
const results = await pm.validateProjectState()
|
|
314
|
+
|
|
315
|
+
console.info(results.passed.includes('task-1')) // ← true
|
|
316
|
+
console.info(results.pending.includes('task-2')) // ← true
|
|
317
|
+
|
|
318
|
+
assert.strictEqual(console.output()[0][1], true)
|
|
319
|
+
assert.strictEqual(console.output()[1][1], true)
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* @docs
|
|
324
|
+
* ### Release Processing
|
|
325
|
+
*
|
|
326
|
+
* The `ReleaseManager` coordinates releases and validates readiness.
|
|
327
|
+
* It ensures:
|
|
328
|
+
* - All registered tests pass
|
|
329
|
+
* - Version is correctly incremented
|
|
330
|
+
* - Git tag is applied if all validations succeed
|
|
331
|
+
*/
|
|
332
|
+
it('How to execute a release after validation?', async () => {
|
|
333
|
+
//import { ReleaseManager, ProjectManagement } from '@nan0web/release'
|
|
334
|
+
const pm = new ProjectManagement()
|
|
335
|
+
const rm = new ReleaseManager(pm)
|
|
336
|
+
|
|
337
|
+
rm.calculateVersion = () => 'v1.0.1'
|
|
338
|
+
rm.publish = async () => true
|
|
339
|
+
|
|
340
|
+
const result = await rm.executeRelease('patch')
|
|
341
|
+
console.info(result.version) // ← v1.0.1
|
|
342
|
+
console.info(result.published) // ← true
|
|
343
|
+
|
|
344
|
+
assert.strictEqual(console.output()[0][1], 'v1.0.1')
|
|
345
|
+
assert.strictEqual(console.output()[1][1], true)
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* @docs
|
|
350
|
+
* ### Changelog Integration
|
|
351
|
+
*
|
|
352
|
+
* Using `ChangelogTaskManager`, you can:
|
|
353
|
+
* - Extract task definitions from changelog entries
|
|
354
|
+
* - Generate corresponding test files
|
|
355
|
+
* - Automate task progression in CI
|
|
356
|
+
*/
|
|
357
|
+
it('How to parse changelog and extract tasks?', () => {
|
|
358
|
+
//import { ChangelogTaskManager } from '@nan0web/release'
|
|
359
|
+
const ctm = new ChangelogTaskManager()
|
|
360
|
+
const changelog = `# Changelog
|
|
361
|
+
|
|
362
|
+
## [1.0.0] - 2025-08-20
|
|
363
|
+
### Added
|
|
364
|
+
- Initial structure [core.init]
|
|
365
|
+
- Release notes support [docs.release-notes]`
|
|
366
|
+
|
|
367
|
+
const tasks = ctm.parseChangelog(changelog)
|
|
368
|
+
console.info(Array.isArray(tasks)) // ← true
|
|
369
|
+
console.info(tasks.length >= 0) // ← true
|
|
370
|
+
|
|
371
|
+
assert.strictEqual(console.output()[0][1], true)
|
|
372
|
+
assert.strictEqual(console.output()[1][1], true)
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* @docs
|
|
377
|
+
* ## Java•Script Features
|
|
378
|
+
*/
|
|
379
|
+
it('Uses JSDoc and .d.ts files for autocompletion', () => {
|
|
380
|
+
assert.ok(pkg.types)
|
|
381
|
+
assert.ok(pkg.types.includes('.d.ts'))
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* @docs
|
|
386
|
+
* ## CLI Playground
|
|
387
|
+
*
|
|
388
|
+
* Try the package in the terminal:
|
|
389
|
+
*/
|
|
390
|
+
it('How to run playground demo?', async () => {
|
|
391
|
+
/**
|
|
392
|
+
* ```bash
|
|
393
|
+
* git clone https://github.com/nan0web/release.git
|
|
394
|
+
* cd release
|
|
395
|
+
* pnpm install
|
|
396
|
+
* pnpm run playground
|
|
397
|
+
* ```
|
|
398
|
+
*/
|
|
399
|
+
assert.ok(pkg.scripts?.playground)
|
|
400
|
+
const response = await runSpawn('git', ['remote', 'get-url', 'origin'])
|
|
401
|
+
assert.ok(response.code === 0)
|
|
402
|
+
assert.ok(
|
|
403
|
+
response.text.trim().endsWith('nan0web/monorepo.git') ||
|
|
404
|
+
response.text.trim().endsWith('nan0web/release.git'),
|
|
405
|
+
)
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* @docs
|
|
410
|
+
* ## Project Status
|
|
411
|
+
*
|
|
412
|
+
* To verify the project is ready, run:
|
|
413
|
+
*/
|
|
414
|
+
it('How to check project status before publishing?', async () => {
|
|
415
|
+
/**
|
|
416
|
+
* ```bash
|
|
417
|
+
* npm test
|
|
418
|
+
* npm run test:coverage
|
|
419
|
+
* npm run test:status
|
|
420
|
+
* ```
|
|
421
|
+
*/
|
|
422
|
+
assert.ok(pkg.scripts?.test)
|
|
423
|
+
assert.ok(pkg.scripts?.['test:coverage'])
|
|
424
|
+
assert.ok(pkg.scripts?.['test:status'])
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* @docs
|
|
429
|
+
* ## Contributing
|
|
430
|
+
*/
|
|
431
|
+
it('How to contribute? - [check here](./CONTRIBUTING.md)', async () => {
|
|
432
|
+
assert.equal(pkg.scripts?.precommit, 'npm test')
|
|
433
|
+
assert.equal(pkg.scripts?.prepush, 'npm test')
|
|
434
|
+
assert.equal(pkg.scripts?.prepare, 'husky')
|
|
435
|
+
})
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* @docs
|
|
439
|
+
* ## License
|
|
440
|
+
*/
|
|
441
|
+
it('How to license ISC? - [check here](./LICENSE)', async () => {
|
|
442
|
+
/** @docs */
|
|
443
|
+
const text = await fs.loadDocument('LICENSE')
|
|
444
|
+
assert.ok(String(text).includes('ISC'))
|
|
445
|
+
})
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
describe('README.md testing', testRender)
|
|
449
|
+
|
|
450
|
+
describe('Rendering README.md', async () => {
|
|
451
|
+
let text = ''
|
|
452
|
+
const format = new Intl.NumberFormat('en-US').format
|
|
453
|
+
const parser = new DocsParser()
|
|
454
|
+
text = String(parser.decode(testRender))
|
|
455
|
+
await fs.saveDocument('README.md', text)
|
|
456
|
+
const dataset = DatasetParser.parse(text, pkg.name)
|
|
457
|
+
await fs.saveDocument('.datasets/README.dataset.jsonl', dataset)
|
|
458
|
+
|
|
459
|
+
it(`document is rendered [${format(Buffer.byteLength(text))}b]`, async () => {
|
|
460
|
+
const text = await readFile('README.md', 'utf8')
|
|
461
|
+
assert.ok(text.includes('## License'))
|
|
462
|
+
})
|
|
463
|
+
})
|
package/src/Release/Person.js
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Architectural Git Commit & Diff Validator Subagent
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# 🐙 Git Reviewer
|
|
6
|
+
|
|
7
|
+
**INPUTS REQUIRED:**
|
|
8
|
+
|
|
9
|
+
- `[PROJECT_MD]` (The 5-phase architectural spec, e.g. project.md from root)
|
|
10
|
+
- `[DIFF]` (The git diff patch output `git diff --cached`)
|
|
11
|
+
|
|
12
|
+
**SYSTEM PROMPT (Agnostic AI API Persona):**
|
|
13
|
+
You are an isolated, Agnostic Zero-Hallucination Git Reviewer. You do not code. You do not converse. You compare the semantic integrity of the `[DIFF]` against the core architecture.
|
|
14
|
+
|
|
15
|
+
You must evaluate the snippet rigorously based on structural integrity and specific rules provided.
|
|
16
|
+
There is no ambiguity: any deviation from the preset `[PROJECT_MD]` libraries or patterns must be strictly caught.
|
|
17
|
+
To reject a `[DIFF]`, provide the specific file name, the line number of code, and the specific phase of `[PROJECT_MD]` that it contradicts.
|
|
18
|
+
|
|
19
|
+
**OBJECTIVE:**
|
|
20
|
+
Ensure the developer is not sneaking in "hotfixes" that break structural agreements ("Zero-Trust Git Review").
|
|
21
|
+
|
|
22
|
+
- Locate any deviations from predefined libraries or patterns.
|
|
23
|
+
- Locate undocumented mutations in the `data/` or `ui/` layer.
|
|
24
|
+
- Ensure only required files are staged.
|
|
25
|
+
|
|
26
|
+
**STRICT OUTPUT CONTRACT:**
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"score": 85,
|
|
31
|
+
"errors": [
|
|
32
|
+
"File 'src/index.js' introduces direct 'node:fs' usage instead of '@nan0web/db-fs', contradicting Phase 2 of project.md."
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
```
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Гігієна пакету — обовʼязкові скрипти, конвеєр test:all, knip, .npmignore
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# 🧹 Гігієна Пакету (Package Hygiene)
|
|
6
|
+
|
|
7
|
+
## 1. Обов'язкові скрипти у кожному пакеті
|
|
8
|
+
|
|
9
|
+
- `"knip": "knip --production"` — перевірка невикористаних файлів, експортів та залежностей.
|
|
10
|
+
- `"audit": "pnpm audit --prod || true"` — інформативна перевірка вразливостей. `|| true` бо `pnpm audit` monorepo-wide — вразливості сусідніх пакетів не повинні блокувати реліз.
|
|
11
|
+
- `"release:spec": "node --test \"releases/**/*.spec.js\""` — контрактні тести відкритого релізу.
|
|
12
|
+
- `"test:release": "node --test \"src/test/releases/**/*.test.js\""` — регресійні тести закритих релізів.
|
|
13
|
+
|
|
14
|
+
## 2. Повний конвеєр (`test:all`)
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
test → test:docs → build → test:release → knip → audit
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- Всі кроки через `&&` — мають бути зеленими.
|
|
21
|
+
|
|
22
|
+
## 3. Knip Конфігурація (`knip.json`)
|
|
23
|
+
|
|
24
|
+
- `entry`: головний `src/index.js`.
|
|
25
|
+
- `ignore`: `play/`, `releases/`, `types/`, `src/README.md.js`.
|
|
26
|
+
- `ignoreDependencies`: dev-інструменти (`husky`, `@nan0web/test`, тощо).
|
|
27
|
+
|
|
28
|
+
## 4. `.npmignore` (ОБОВ'ЯЗКОВО у кожному пакеті)
|
|
29
|
+
|
|
30
|
+
Без `.npmignore` npm використовує `.gitignore`, що пропускає dev-артефакти в публікацію.
|
|
31
|
+
Мінімальний шаблон:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
# Tests
|
|
35
|
+
src/**/*.test.js
|
|
36
|
+
src/test/
|
|
37
|
+
types/test/
|
|
38
|
+
|
|
39
|
+
# ProvenDoc generator
|
|
40
|
+
src/README.md.js
|
|
41
|
+
|
|
42
|
+
# Dev files
|
|
43
|
+
play/
|
|
44
|
+
releases/
|
|
45
|
+
docs/
|
|
46
|
+
knip.json
|
|
47
|
+
system.md
|
|
48
|
+
next.md
|
|
49
|
+
tsconfig.json
|
|
50
|
+
.editorconfig
|
|
51
|
+
CONTRIBUTING.md
|
|
52
|
+
|
|
53
|
+
# LLiMo / AI artifacts
|
|
54
|
+
chat/
|
|
55
|
+
.datasets/
|
|
56
|
+
me.md
|
|
57
|
+
|
|
58
|
+
# Generated
|
|
59
|
+
dist/
|
|
60
|
+
.cache/
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Перевірка**: `npm pack --dry-run` перед кожним `npm publish`.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Safe Commit Workflow (No Auto-Run)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Safe Commit Procedure
|
|
6
|
+
|
|
7
|
+
1. **Check Status**:
|
|
8
|
+
- Run `git status` to see what is staged/modified.
|
|
9
|
+
- Run `git diff --stat` to see the scope of changes.
|
|
10
|
+
|
|
11
|
+
2. **Verify Integrity**:
|
|
12
|
+
- IF (and only if) tests exist, run them: `npm run test:all`.
|
|
13
|
+
- Ensure the build passes: `npm run build` (if applicable, must be included in test:all).
|
|
14
|
+
|
|
15
|
+
3. **Formulate Message**:
|
|
16
|
+
- Create a concise, semantic commit message (e.g., `fix: ...`, `feat: ...`).
|
|
17
|
+
- Describe WHAT changed and WHY.
|
|
18
|
+
|
|
19
|
+
4. **PROPOSE Command**:
|
|
20
|
+
- **DO NOT RUN THE COMMIT COMMAND.**
|
|
21
|
+
- Output the suggested command string:
|
|
22
|
+
```bash
|
|
23
|
+
git add . && git commit -m "Your proposed message"
|
|
24
|
+
```
|
|
25
|
+
- Ask the user: "Shall I execute this?"
|
|
26
|
+
|
|
27
|
+
5. **Execute (On User Approval)**:
|
|
28
|
+
- Only after receiving explicit "Yes" or "Do it", run the command.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: /release — Публікація пакету в NPM (Smart Test & Build & Publish)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
// turbo-all
|
|
6
|
+
|
|
7
|
+
До релізую НЕ МАЮТЬ потрапляти так файли:
|
|
8
|
+
|
|
9
|
+
- .agent/
|
|
10
|
+
- .vscode/
|
|
11
|
+
- docs/
|
|
12
|
+
- src/**/*.test.js{x}
|
|
13
|
+
- src/test/
|
|
14
|
+
- src/README.md.js{x}
|
|
15
|
+
|
|
16
|
+
Мають потрапляти:
|
|
17
|
+
|
|
18
|
+
- package.json
|
|
19
|
+
- LICENSE
|
|
20
|
+
- README.md
|
|
21
|
+
- bin/
|
|
22
|
+
- src/
|
|
23
|
+
- types/
|
|
24
|
+
|
|
25
|
+
1. **Повна перевірка (Safety First)**: Запусти локальну перевірку пакету.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm test:all
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
2. **Публікація в NPM**: Виконай стандартний скрипт релізу.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm run release
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
3. **Верифікація статусів**: Перевір статус пакетів у монорепо.
|
|
38
|
+
```bash
|
|
39
|
+
npm run test:status
|
|
40
|
+
```
|