@produck/agent-toolkit 0.1.3 → 0.1.4
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 -14
- package/bin/agent-toolkit.mjs +101 -34
- package/package.json +7 -8
- package/templates/default.instructions.md +21 -0
- package/templates/help/main.txt +9 -0
- package/templates/help/preflight.txt +3 -0
- package/templates/help/run-capture.txt +3 -0
- package/templates/help/summarize-log.txt +3 -0
- package/templates/help/sync-instructions.txt +8 -0
- package/templates/help/validate-commit-msg.txt +7 -0
- package/bin/release.mjs +0 -271
package/README.md
CHANGED
|
@@ -8,43 +8,60 @@ Central CLI toolkit for organization-level AI execution workflows.
|
|
|
8
8
|
- agent-toolkit run-capture
|
|
9
9
|
- agent-toolkit summarize-log
|
|
10
10
|
- agent-toolkit validate-commit-msg
|
|
11
|
+
- agent-toolkit sync-instructions
|
|
11
12
|
|
|
12
13
|
## Examples
|
|
13
14
|
|
|
14
15
|
Run preflight checks:
|
|
15
16
|
|
|
16
17
|
npm exec --package=@produck/agent-toolkit@latest \
|
|
17
|
-
|
|
18
|
+
agent-toolkit preflight --cwd . --require package.json --ensure-dir logs
|
|
18
19
|
|
|
19
20
|
Capture long output safely:
|
|
20
21
|
|
|
21
22
|
npm exec --package=@produck/agent-toolkit@latest \
|
|
22
|
-
|
|
23
|
+
agent-toolkit run-capture --cwd . --cmd "npm run test" --out logs/test.log
|
|
23
24
|
|
|
24
25
|
Summarize captured output:
|
|
25
26
|
|
|
26
27
|
npm exec --package=@produck/agent-toolkit@latest \
|
|
27
|
-
|
|
28
|
+
agent-toolkit summarize-log --file logs/test.log --match "FAIL|ERROR"
|
|
28
29
|
|
|
29
30
|
Validate commit message format:
|
|
30
31
|
|
|
31
32
|
npm exec --package=@produck/agent-toolkit@latest \
|
|
32
|
-
|
|
33
|
+
agent-toolkit validate-commit-msg --file .git/COMMIT_EDITMSG
|
|
34
|
+
|
|
35
|
+
Manual per-repository instruction distribution (write .instructions.md):
|
|
36
|
+
|
|
37
|
+
npm exec --package=@produck/agent-toolkit@latest \
|
|
38
|
+
agent-toolkit sync-instructions --cwd .
|
|
39
|
+
|
|
40
|
+
Use organization source file instead of built-in template:
|
|
41
|
+
|
|
42
|
+
npm exec --package=@produck/agent-toolkit@latest \
|
|
43
|
+
agent-toolkit sync-instructions --cwd . \
|
|
44
|
+
--source path/to/org/.instructions.md --force
|
|
45
|
+
|
|
46
|
+
Built-in template location (for review and updates):
|
|
47
|
+
|
|
48
|
+
- `templates/default.instructions.md`
|
|
49
|
+
- `templates/help/*.txt`
|
|
33
50
|
|
|
34
51
|
## Local verification
|
|
35
52
|
|
|
36
53
|
From repository root:
|
|
37
54
|
|
|
38
|
-
npm --
|
|
39
|
-
npm --
|
|
55
|
+
npm --workspace @produck/agent-toolkit run verify
|
|
56
|
+
npm --workspace @produck/agent-toolkit run pack:check
|
|
40
57
|
|
|
41
58
|
## Manual publish
|
|
42
59
|
|
|
43
60
|
Lerna-like release flow (recommended):
|
|
44
61
|
|
|
45
|
-
0
|
|
62
|
+
0. Interactive mode (TTY):
|
|
46
63
|
|
|
47
|
-
npm --
|
|
64
|
+
npm --workspace @produck/agent-toolkit run release
|
|
48
65
|
|
|
49
66
|
Interactive prompts let you choose:
|
|
50
67
|
|
|
@@ -66,18 +83,22 @@ Interactive mode handles both:
|
|
|
66
83
|
|
|
67
84
|
Non-interactive flags:
|
|
68
85
|
|
|
69
|
-
- `npm --
|
|
70
|
-
- `npm --
|
|
71
|
-
- `npm --
|
|
86
|
+
- `npm --workspace @produck/agent-toolkit run release -- patch --publish`
|
|
87
|
+
- `npm --workspace @produck/agent-toolkit run release -- patch --no-tag`
|
|
88
|
+
- `npm --workspace @produck/agent-toolkit run release -- patch --no-commit --no-tag`
|
|
72
89
|
|
|
73
90
|
Note:
|
|
74
91
|
|
|
75
|
-
- Release requires a clean working tree in `
|
|
92
|
+
- Release requires a clean working tree in `packages/agent-toolkit` before
|
|
93
|
+
start.
|
|
94
|
+
- After release success, push commit and tags:
|
|
95
|
+
- `git -C d:/workspace/PRODUCK/.github push`
|
|
96
|
+
- `git -C d:/workspace/PRODUCK/.github push --tags`
|
|
76
97
|
|
|
77
98
|
Low-level commands (optional):
|
|
78
99
|
|
|
79
|
-
npm --
|
|
80
|
-
npm --
|
|
100
|
+
npm --workspace @produck/agent-toolkit run publish:dry-run
|
|
101
|
+
npm --workspace @produck/agent-toolkit run publish:latest
|
|
81
102
|
|
|
82
103
|
## GitHub workflow
|
|
83
104
|
|
|
@@ -96,3 +117,10 @@ Release policy:
|
|
|
96
117
|
- Default organization usage is @latest.
|
|
97
118
|
- Run verify and publish:dry-run before publish:latest.
|
|
98
119
|
- Keep rollback option by republishing previous stable version if needed.
|
|
120
|
+
|
|
121
|
+
Rollback quick steps:
|
|
122
|
+
|
|
123
|
+
1. Check latest published version:
|
|
124
|
+
`npm view @produck/agent-toolkit version`
|
|
125
|
+
2. Fix source and run release again with a new version.
|
|
126
|
+
3. Push commit and tags.
|
package/bin/agent-toolkit.mjs
CHANGED
|
@@ -1,10 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
4
5
|
import { spawn } from 'node:child_process';
|
|
5
6
|
|
|
6
7
|
const ALLOWED_TAGS = ['INIT', 'ADD', 'REMOVE', 'FIX', 'REFACTOR', 'UPGRADE'];
|
|
7
8
|
const ALLOWED_TARGETS = ['docs', 'test', 'ci', 'deps', 'api', 'schema', 'infra'];
|
|
9
|
+
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const TEMPLATE_ROOT = path.resolve(SCRIPT_DIR, '../templates');
|
|
11
|
+
const DEFAULT_INSTRUCTIONS_TEMPLATE_PATH = path.resolve(TEMPLATE_ROOT, 'default.instructions.md');
|
|
12
|
+
|
|
13
|
+
function loadTemplateFile(relativePath) {
|
|
14
|
+
const templatePath = path.resolve(TEMPLATE_ROOT, relativePath);
|
|
15
|
+
if (!fs.existsSync(templatePath)) {
|
|
16
|
+
console.error(`Template file not found: ${templatePath}`);
|
|
17
|
+
process.exit(2);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return fs.readFileSync(templatePath, 'utf8');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function printTemplate(relativePath) {
|
|
24
|
+
let content = loadTemplateFile(relativePath);
|
|
25
|
+
if (!content.endsWith('\n')) {
|
|
26
|
+
content = `${content}\n`;
|
|
27
|
+
}
|
|
28
|
+
process.stdout.write(content);
|
|
29
|
+
}
|
|
8
30
|
|
|
9
31
|
function parseCommonArgs(argv) {
|
|
10
32
|
const positional = [];
|
|
@@ -53,52 +75,35 @@ function hasFlag(options, key) {
|
|
|
53
75
|
}
|
|
54
76
|
|
|
55
77
|
function printMainHelp() {
|
|
56
|
-
|
|
57
|
-
'agent-toolkit commands:',
|
|
58
|
-
' preflight',
|
|
59
|
-
' run-capture',
|
|
60
|
-
' summarize-log',
|
|
61
|
-
' validate-commit-msg',
|
|
62
|
-
'',
|
|
63
|
-
'Use:',
|
|
64
|
-
' agent-toolkit <command> --help',
|
|
65
|
-
].join('\n'));
|
|
78
|
+
printTemplate('help/main.txt');
|
|
66
79
|
}
|
|
67
80
|
|
|
68
81
|
function printPreflightHelp() {
|
|
69
|
-
|
|
70
|
-
'Usage:',
|
|
71
|
-
' agent-toolkit preflight [--cwd <dir>] [--require <path>] ...',
|
|
72
|
-
' [--ensure-dir <path>] ... [--json <file>]',
|
|
73
|
-
].join('\n'));
|
|
82
|
+
printTemplate('help/preflight.txt');
|
|
74
83
|
}
|
|
75
84
|
|
|
76
85
|
function printRunCaptureHelp() {
|
|
77
|
-
|
|
78
|
-
'Usage:',
|
|
79
|
-
' agent-toolkit run-capture --out <logFile> --cmd <command>',
|
|
80
|
-
' [--cwd <directory>] [--meta <metaFile>] [--allow-pipe]',
|
|
81
|
-
].join('\n'));
|
|
86
|
+
printTemplate('help/run-capture.txt');
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
function printSummarizeHelp() {
|
|
85
|
-
|
|
86
|
-
'Usage:',
|
|
87
|
-
' agent-toolkit summarize-log --file <logFile>',
|
|
88
|
-
' [--last <lineCount>] [--match <regex>] [--max <lineCount>]',
|
|
89
|
-
].join('\n'));
|
|
90
|
+
printTemplate('help/summarize-log.txt');
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
function printValidateHelp() {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
printTemplate('help/validate-commit-msg.txt');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function printSyncInstructionsHelp() {
|
|
98
|
+
printTemplate('help/sync-instructions.txt');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function loadDefaultInstructionsTemplate() {
|
|
102
|
+
let content = loadTemplateFile('default.instructions.md');
|
|
103
|
+
if (!content.endsWith('\n')) {
|
|
104
|
+
content = `${content}\n`;
|
|
105
|
+
}
|
|
106
|
+
return content;
|
|
102
107
|
}
|
|
103
108
|
|
|
104
109
|
function runPreflight(options) {
|
|
@@ -357,6 +362,59 @@ function runValidateCommitMsg(options) {
|
|
|
357
362
|
console.log('Commit message validation passed');
|
|
358
363
|
}
|
|
359
364
|
|
|
365
|
+
function runSyncInstructions(options) {
|
|
366
|
+
const cwd = path.resolve(getSingle(options, '--cwd', process.cwd()));
|
|
367
|
+
const outArg = getSingle(options, '--out', '.instructions.md');
|
|
368
|
+
const sourceArg = getSingle(options, '--source', '');
|
|
369
|
+
const force = hasFlag(options, '--force');
|
|
370
|
+
const dryRun = hasFlag(options, '--dry-run');
|
|
371
|
+
|
|
372
|
+
if (!fs.existsSync(cwd)) {
|
|
373
|
+
console.error(`CWD does not exist: ${cwd}`);
|
|
374
|
+
process.exit(2);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const outPath = path.resolve(cwd, outArg);
|
|
378
|
+
let content = loadDefaultInstructionsTemplate();
|
|
379
|
+
|
|
380
|
+
if (sourceArg) {
|
|
381
|
+
const sourcePath = path.resolve(cwd, sourceArg);
|
|
382
|
+
if (!fs.existsSync(sourcePath)) {
|
|
383
|
+
console.error(`Source file does not exist: ${sourcePath}`);
|
|
384
|
+
process.exit(2);
|
|
385
|
+
}
|
|
386
|
+
content = fs.readFileSync(sourcePath, 'utf8');
|
|
387
|
+
if (!content.endsWith('\n')) {
|
|
388
|
+
content = `${content}\n`;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const exists = fs.existsSync(outPath);
|
|
393
|
+
if (exists && !force) {
|
|
394
|
+
console.error(`Target already exists: ${outPath}`);
|
|
395
|
+
console.error('Use --force to overwrite.');
|
|
396
|
+
process.exit(2);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const report = {
|
|
400
|
+
cwd,
|
|
401
|
+
outPath,
|
|
402
|
+
source: sourceArg ? path.resolve(cwd, sourceArg) : DEFAULT_INSTRUCTIONS_TEMPLATE_PATH,
|
|
403
|
+
exists,
|
|
404
|
+
overwritten: exists && force,
|
|
405
|
+
dryRun,
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
if (dryRun) {
|
|
409
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
410
|
+
process.exit(0);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
414
|
+
fs.writeFileSync(outPath, content, 'utf8');
|
|
415
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
416
|
+
}
|
|
417
|
+
|
|
360
418
|
function main() {
|
|
361
419
|
const parsed = parseCommonArgs(process.argv.slice(2));
|
|
362
420
|
const command = parsed.positional[0] || '';
|
|
@@ -384,6 +442,10 @@ function main() {
|
|
|
384
442
|
printValidateHelp();
|
|
385
443
|
process.exit(0);
|
|
386
444
|
}
|
|
445
|
+
if (command === 'sync-instructions') {
|
|
446
|
+
printSyncInstructionsHelp();
|
|
447
|
+
process.exit(0);
|
|
448
|
+
}
|
|
387
449
|
}
|
|
388
450
|
|
|
389
451
|
if (command === 'preflight') {
|
|
@@ -406,6 +468,11 @@ function main() {
|
|
|
406
468
|
return;
|
|
407
469
|
}
|
|
408
470
|
|
|
471
|
+
if (command === 'sync-instructions') {
|
|
472
|
+
runSyncInstructions(options);
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
|
|
409
476
|
console.error(`Unknown command: ${command}`);
|
|
410
477
|
printMainHelp();
|
|
411
478
|
process.exit(2);
|
package/package.json
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@produck/agent-toolkit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Central CLI toolkit for organization AI execution workflows",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/produck/.github.git",
|
|
9
|
-
"directory": "
|
|
9
|
+
"directory": "packages/agent-toolkit"
|
|
10
10
|
},
|
|
11
11
|
"bin": {
|
|
12
12
|
"agent-toolkit": "bin/agent-toolkit.mjs"
|
|
13
13
|
},
|
|
14
14
|
"scripts": {
|
|
15
15
|
"verify": "node ./bin/agent-toolkit.mjs --help && node ./bin/agent-toolkit.mjs preflight --cwd . --require package.json",
|
|
16
|
-
"pack:check": "npm pack --dry-run"
|
|
17
|
-
"publish:dry-run": "npm publish --dry-run --access public",
|
|
18
|
-
"publish:latest": "npm publish --access public",
|
|
19
|
-
"release": "node ./bin/release.mjs"
|
|
16
|
+
"pack:check": "npm pack --dry-run"
|
|
20
17
|
},
|
|
21
18
|
"files": [
|
|
22
|
-
"bin"
|
|
19
|
+
"bin",
|
|
20
|
+
"templates"
|
|
23
21
|
],
|
|
24
22
|
"publishConfig": {
|
|
25
23
|
"access": "public"
|
|
@@ -27,5 +25,6 @@
|
|
|
27
25
|
"engines": {
|
|
28
26
|
"node": ">=18.0.0"
|
|
29
27
|
},
|
|
30
|
-
"license": "MIT"
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"gitHead": "a2e293bea6a90e6fcbf9d0df03ba4fdf3a13ef00"
|
|
31
30
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Organization Collaboration Instructions
|
|
2
|
+
|
|
3
|
+
This repository follows organization-level AI and engineering rules.
|
|
4
|
+
|
|
5
|
+
## Required Rules
|
|
6
|
+
|
|
7
|
+
- Commit message format must follow bracketed TAG policy.
|
|
8
|
+
- Keep root .editorconfig aligned with organization baseline:
|
|
9
|
+
- If missing, create from organization sample.
|
|
10
|
+
- If present, add missing required keys only (minimal merge).
|
|
11
|
+
- Repository owners generate and own eslint.config.mjs.
|
|
12
|
+
- AI must not rewrite full eslint config; only add missing
|
|
13
|
+
@produck/eslint-rules integration as minimal patch.
|
|
14
|
+
- Repository-specific ESLint overrides must layer on top of
|
|
15
|
+
@produck/eslint-rules.
|
|
16
|
+
|
|
17
|
+
## References
|
|
18
|
+
|
|
19
|
+
- docs/ai-collaboration.md
|
|
20
|
+
- docs/commit-convention.md
|
|
21
|
+
- docs/nodejs-initialization.md
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Usage:
|
|
2
|
+
agent-toolkit sync-instructions [--cwd <dir>] [--out <file>]
|
|
3
|
+
[--source <file>] [--force] [--dry-run]
|
|
4
|
+
|
|
5
|
+
Behavior:
|
|
6
|
+
- Writes organization instruction entrypoint template to target file.
|
|
7
|
+
- Defaults to <cwd>/.instructions.md when --out is not provided.
|
|
8
|
+
- If target exists, command fails unless --force is set.
|
package/bin/release.mjs
DELETED
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { spawnSync } from 'node:child_process';
|
|
5
|
-
import readline from 'node:readline/promises';
|
|
6
|
-
|
|
7
|
-
const LEVELS = new Set(['patch', 'minor', 'major']);
|
|
8
|
-
|
|
9
|
-
function usage() {
|
|
10
|
-
console.log([
|
|
11
|
-
'Usage:',
|
|
12
|
-
' node ./bin/release.mjs',
|
|
13
|
-
' node ./bin/release.mjs <patch|minor|major> [--publish] [--no-commit] [--no-tag]',
|
|
14
|
-
' node ./bin/release.mjs --interactive',
|
|
15
|
-
'',
|
|
16
|
-
'Behavior:',
|
|
17
|
-
' 1) bump version (no git tag)',
|
|
18
|
-
' 2) run verify',
|
|
19
|
-
' 3) run publish:dry-run',
|
|
20
|
-
' 4) auto commit version change (default)',
|
|
21
|
-
' 5) auto create git tag (default)',
|
|
22
|
-
' 6) optionally publish latest when --publish is set',
|
|
23
|
-
'',
|
|
24
|
-
'Interactive mode defaults:',
|
|
25
|
-
' - release level: patch',
|
|
26
|
-
' - publish mode: dry-run',
|
|
27
|
-
' - auto commit: enabled',
|
|
28
|
-
' - auto tag: enabled',
|
|
29
|
-
].join('\n'));
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function runNpm(args) {
|
|
33
|
-
const result = spawnSync('npm', args, {
|
|
34
|
-
stdio: 'inherit',
|
|
35
|
-
cwd: process.cwd(),
|
|
36
|
-
shell: true,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
if (result.error) {
|
|
40
|
-
console.error(`[release] failed to run npm ${args.join(' ')}:`);
|
|
41
|
-
console.error(result.error.message);
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (result.status !== 0) {
|
|
46
|
-
process.exit(result.status ?? 1);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function runGit(args) {
|
|
51
|
-
const result = spawnSync('git', args, {
|
|
52
|
-
stdio: 'inherit',
|
|
53
|
-
cwd: process.cwd(),
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
if (result.error) {
|
|
57
|
-
console.error(`[release] failed to run git ${args.join(' ')}:`);
|
|
58
|
-
console.error(result.error.message);
|
|
59
|
-
process.exit(1);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (result.status !== 0) {
|
|
63
|
-
process.exit(result.status ?? 1);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function getDirtyFiles() {
|
|
68
|
-
const result = spawnSync('git', ['status', '--porcelain'], {
|
|
69
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
70
|
-
cwd: process.cwd(),
|
|
71
|
-
encoding: 'utf8',
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
if (result.error || result.status !== 0) {
|
|
75
|
-
console.error('[release] unable to check git status');
|
|
76
|
-
process.exit(1);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return result.stdout
|
|
80
|
-
.split(/\r?\n/)
|
|
81
|
-
.map((line) => line.trim())
|
|
82
|
-
.filter((line) => line.length > 0);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function ensureReleaseWorkspaceClean() {
|
|
86
|
-
const dirty = getDirtyFiles();
|
|
87
|
-
if (dirty.length === 0) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
console.error('[release] working tree is not clean before release:');
|
|
92
|
-
for (const line of dirty) {
|
|
93
|
-
console.error(` ${line}`);
|
|
94
|
-
}
|
|
95
|
-
console.error('[release] commit/stash changes and retry');
|
|
96
|
-
process.exit(2);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function commitAndTag(version, shouldCommit, shouldTag) {
|
|
100
|
-
if (shouldCommit) {
|
|
101
|
-
const message = `[UPGRADE] <infra>: release @produck/agent-toolkit ${version}`;
|
|
102
|
-
console.log(`[release] commit version bump: ${message}`);
|
|
103
|
-
runGit(['add', 'package.json']);
|
|
104
|
-
runGit(['commit', '-m', message]);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (shouldTag) {
|
|
108
|
-
const tag = `agent-toolkit-v${version}`;
|
|
109
|
-
console.log(`[release] create tag: ${tag}`);
|
|
110
|
-
runGit(['tag', '-a', tag, '-m', `[UPGRADE] <infra>: tag ${tag}`]);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function bumpPreview(version, level) {
|
|
115
|
-
const parts = version.split('.').map((v) => Number(v));
|
|
116
|
-
if (parts.length !== 3 || parts.some((v) => Number.isNaN(v))) {
|
|
117
|
-
return `unknown (${version})`;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const [major, minor, patch] = parts;
|
|
121
|
-
if (level === 'patch') {
|
|
122
|
-
return `${major}.${minor}.${patch + 1}`;
|
|
123
|
-
}
|
|
124
|
-
if (level === 'minor') {
|
|
125
|
-
return `${major}.${minor + 1}.0`;
|
|
126
|
-
}
|
|
127
|
-
return `${major + 1}.0.0`;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async function askInteractive(currentVersion) {
|
|
131
|
-
const rl = readline.createInterface({
|
|
132
|
-
input: process.stdin,
|
|
133
|
-
output: process.stdout,
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
console.log(`[release] current version: ${currentVersion}`);
|
|
138
|
-
console.log('[release] select release level:');
|
|
139
|
-
console.log(` 1) patch (default) -> ${bumpPreview(currentVersion, 'patch')}`);
|
|
140
|
-
console.log(` 2) minor -> ${bumpPreview(currentVersion, 'minor')}`);
|
|
141
|
-
console.log(` 3) major -> ${bumpPreview(currentVersion, 'major')}`);
|
|
142
|
-
|
|
143
|
-
const levelAnswer = (
|
|
144
|
-
await rl.question('Choose level [1/2/3] (default: 1): ')
|
|
145
|
-
).trim();
|
|
146
|
-
|
|
147
|
-
let level = 'patch';
|
|
148
|
-
if (levelAnswer === '2') {
|
|
149
|
-
level = 'minor';
|
|
150
|
-
} else if (levelAnswer === '3') {
|
|
151
|
-
level = 'major';
|
|
152
|
-
} else if (levelAnswer && levelAnswer !== '1') {
|
|
153
|
-
console.error(`Invalid level choice: ${levelAnswer}`);
|
|
154
|
-
process.exit(2);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
console.log('[release] select publish mode:');
|
|
158
|
-
console.log(' 1) dry-run only (default)');
|
|
159
|
-
console.log(' 2) publish latest after dry-run');
|
|
160
|
-
|
|
161
|
-
const publishAnswer = (
|
|
162
|
-
await rl.question('Choose mode [1/2] (default: 1): ')
|
|
163
|
-
).trim();
|
|
164
|
-
|
|
165
|
-
let shouldPublish = false;
|
|
166
|
-
if (publishAnswer === '2') {
|
|
167
|
-
shouldPublish = true;
|
|
168
|
-
} else if (publishAnswer && publishAnswer !== '1') {
|
|
169
|
-
console.error(`Invalid publish choice: ${publishAnswer}`);
|
|
170
|
-
process.exit(2);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
console.log('[release] auto commit and tag settings:');
|
|
174
|
-
console.log(' 1) commit + tag (default)');
|
|
175
|
-
console.log(' 2) commit only');
|
|
176
|
-
console.log(' 3) no commit, no tag');
|
|
177
|
-
|
|
178
|
-
const vcsAnswer = (
|
|
179
|
-
await rl.question('Choose vcs mode [1/2/3] (default: 1): ')
|
|
180
|
-
).trim();
|
|
181
|
-
|
|
182
|
-
let shouldCommit = true;
|
|
183
|
-
let shouldTag = true;
|
|
184
|
-
if (vcsAnswer === '2') {
|
|
185
|
-
shouldCommit = true;
|
|
186
|
-
shouldTag = false;
|
|
187
|
-
} else if (vcsAnswer === '3') {
|
|
188
|
-
shouldCommit = false;
|
|
189
|
-
shouldTag = false;
|
|
190
|
-
} else if (vcsAnswer && vcsAnswer !== '1') {
|
|
191
|
-
console.error(`Invalid vcs choice: ${vcsAnswer}`);
|
|
192
|
-
process.exit(2);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return { level, shouldPublish, shouldCommit, shouldTag };
|
|
196
|
-
} finally {
|
|
197
|
-
rl.close();
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function runRelease(level, shouldPublish, shouldCommit, shouldTag) {
|
|
202
|
-
if (!LEVELS.has(level)) {
|
|
203
|
-
console.error(`Invalid release level: ${level}`);
|
|
204
|
-
usage();
|
|
205
|
-
process.exit(2);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
ensureReleaseWorkspaceClean();
|
|
209
|
-
|
|
210
|
-
const pkgFile = path.resolve('package.json');
|
|
211
|
-
const before = JSON.parse(fs.readFileSync(pkgFile, 'utf8')).version;
|
|
212
|
-
|
|
213
|
-
console.log(`[release] bump version: ${level}`);
|
|
214
|
-
runNpm(['version', level, '--no-git-tag-version']);
|
|
215
|
-
|
|
216
|
-
const after = JSON.parse(fs.readFileSync(pkgFile, 'utf8')).version;
|
|
217
|
-
console.log(`[release] version ${before} -> ${after}`);
|
|
218
|
-
|
|
219
|
-
console.log('[release] verify toolkit');
|
|
220
|
-
runNpm(['run', 'verify']);
|
|
221
|
-
|
|
222
|
-
console.log('[release] publish dry-run');
|
|
223
|
-
runNpm(['run', 'publish:dry-run']);
|
|
224
|
-
|
|
225
|
-
commitAndTag(after, shouldCommit, shouldTag);
|
|
226
|
-
|
|
227
|
-
if (shouldPublish) {
|
|
228
|
-
console.log('[release] publish latest');
|
|
229
|
-
runNpm(['run', 'publish:latest']);
|
|
230
|
-
} else {
|
|
231
|
-
console.log('[release] publish skipped (interactive default: dry-run)');
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const args = process.argv.slice(2);
|
|
236
|
-
if (args.includes('--help') || args.includes('-h')) {
|
|
237
|
-
usage();
|
|
238
|
-
process.exit(0);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
const interactiveRequested = args.length === 0 || args.includes('--interactive');
|
|
242
|
-
if (interactiveRequested) {
|
|
243
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
244
|
-
console.error('Interactive mode requires a TTY.');
|
|
245
|
-
usage();
|
|
246
|
-
process.exit(2);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const pkgFile = path.resolve('package.json');
|
|
250
|
-
const currentVersion = JSON.parse(fs.readFileSync(pkgFile, 'utf8')).version;
|
|
251
|
-
const interactive = await askInteractive(currentVersion);
|
|
252
|
-
runRelease(
|
|
253
|
-
interactive.level,
|
|
254
|
-
interactive.shouldPublish,
|
|
255
|
-
interactive.shouldCommit,
|
|
256
|
-
interactive.shouldTag
|
|
257
|
-
);
|
|
258
|
-
process.exit(0);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const level = args[0];
|
|
262
|
-
const shouldPublish = args.includes('--publish');
|
|
263
|
-
const shouldCommit = !args.includes('--no-commit');
|
|
264
|
-
const shouldTag = !args.includes('--no-tag');
|
|
265
|
-
|
|
266
|
-
if (shouldTag && !shouldCommit) {
|
|
267
|
-
console.error('[release] --no-commit cannot be combined with tag enabled');
|
|
268
|
-
process.exit(2);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
runRelease(level, shouldPublish, shouldCommit, shouldTag);
|