@produck/agent-toolkit 0.1.3 → 0.1.5

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 CHANGED
@@ -8,76 +8,86 @@ 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
 
17
+ ```bash
16
18
  npm exec --package=@produck/agent-toolkit@latest \
17
19
  agent-toolkit preflight --cwd . --require package.json --ensure-dir logs
20
+ ```
18
21
 
19
22
  Capture long output safely:
20
23
 
24
+ ```bash
21
25
  npm exec --package=@produck/agent-toolkit@latest \
22
26
  agent-toolkit run-capture --cwd . --cmd "npm run test" --out logs/test.log
27
+ ```
23
28
 
24
29
  Summarize captured output:
25
30
 
31
+ ```bash
26
32
  npm exec --package=@produck/agent-toolkit@latest \
27
33
  agent-toolkit summarize-log --file logs/test.log --match "FAIL|ERROR"
34
+ ```
28
35
 
29
36
  Validate commit message format:
30
37
 
38
+ ```bash
31
39
  npm exec --package=@produck/agent-toolkit@latest \
32
40
  agent-toolkit validate-commit-msg --file .git/COMMIT_EDITMSG
41
+ ```
33
42
 
34
- ## Local verification
35
-
36
- From repository root:
37
-
38
- npm --prefix tools/agent-toolkit run verify
39
- npm --prefix tools/agent-toolkit run pack:check
40
-
41
- ## Manual publish
42
-
43
- Lerna-like release flow (recommended):
43
+ Manual per-repository instruction distribution (write .instructions.md):
44
44
 
45
- 0) Interactive mode (TTY):
45
+ ```bash
46
+ npm exec --package=@produck/agent-toolkit@latest \
47
+ agent-toolkit sync-instructions --cwd .
48
+ ```
46
49
 
47
- npm --prefix tools/agent-toolkit run release
50
+ Use organization source file instead of built-in template:
48
51
 
49
- Interactive prompts let you choose:
52
+ ```bash
53
+ npm exec --package=@produck/agent-toolkit@latest \
54
+ agent-toolkit sync-instructions --cwd . \
55
+ --source path/to/org/.instructions.md --force
56
+ ```
50
57
 
51
- - version level: patch/minor/major
52
- - action: dry-run or publish
53
- - vcs mode: commit+tag / commit only / no commit+no tag
58
+ Built-in template location (for review and updates):
54
59
 
55
- Default choices:
60
+ - `templates/default.instructions.md`
61
+ - `templates/help/*.txt`
56
62
 
57
- - patch
58
- - dry-run
59
- - commit + tag
63
+ ## Local verification
60
64
 
61
- Interactive mode handles both:
65
+ From repository root:
62
66
 
63
- - version bump level (patch/minor/major)
64
- - action mode (dry-run or publish)
65
- - auto commit and tag after dry-run
67
+ ```bash
68
+ npm --workspace @produck/agent-toolkit run verify
69
+ npm --workspace @produck/agent-toolkit run pack:check
70
+ ```
66
71
 
67
- Non-interactive flags:
72
+ ## Publishing
68
73
 
69
- - `npm --prefix tools/agent-toolkit run release -- patch --publish`
70
- - `npm --prefix tools/agent-toolkit run release -- patch --no-tag`
71
- - `npm --prefix tools/agent-toolkit run release -- patch --no-commit --no-tag`
74
+ Publishing is centralized at workspace root via lerna, not via
75
+ package-level release scripts.
72
76
 
73
- Note:
77
+ From monorepo root (`produck/.github`):
74
78
 
75
- - Release requires a clean working tree in `tools/agent-toolkit` before start.
79
+ ```bash
80
+ npm run format:check
81
+ npm run test
82
+ npm run publish:dry-run
83
+ npm run publish
84
+ ```
76
85
 
77
- Low-level commands (optional):
86
+ Notes:
78
87
 
79
- npm --prefix tools/agent-toolkit run publish:dry-run
80
- npm --prefix tools/agent-toolkit run publish:latest
88
+ - `publish:dry-run` validates package contents by running `npm pack --dry-run`
89
+ across non-private workspace packages.
90
+ - `publish` runs lerna publish flow from workspace root.
81
91
 
82
92
  ## GitHub workflow
83
93
 
@@ -87,12 +97,20 @@ Repository includes manual workflow:
87
97
 
88
98
  Workflow behavior:
89
99
 
90
- - Always runs verify, pack:check, and publish:dry-run.
100
+ - Always runs verify and pack:check for `@produck/agent-toolkit`.
91
101
  - Does not publish to npm.
92
- - Used as release gate before manual publish.
102
+ - Used as release gate before workspace-level publish.
93
103
 
94
104
  Release policy:
95
105
 
96
106
  - Default organization usage is @latest.
97
- - Run verify and publish:dry-run before publish:latest.
107
+ - Run format:check and test first, then workspace `publish:dry-run` before
108
+ `publish`.
98
109
  - Keep rollback option by republishing previous stable version if needed.
110
+
111
+ Rollback quick steps:
112
+
113
+ 1. Check latest published version:
114
+ `npm view @produck/agent-toolkit version`
115
+ 2. Fix source and rerun workspace publish flow with a new version.
116
+ 3. Push commit and tags.
@@ -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
- console.log([
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
- console.log([
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
- console.log([
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
- console.log([
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
- console.log([
94
- 'Usage:',
95
- ' agent-toolkit validate-commit-msg --file <message-file>',
96
- '',
97
- 'Rules:',
98
- ' - Every line must start with [TAG]',
99
- ' - No empty lines are allowed',
100
- ' - Optional target form: [TAG] <target>: <summary>',
101
- ].join('\n'));
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",
3
+ "version": "0.1.5",
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": "tools/agent-toolkit"
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": "13afa6b9d747360fedf569a619274d90a038c0f3"
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,9 @@
1
+ agent-toolkit commands:
2
+ preflight
3
+ run-capture
4
+ summarize-log
5
+ validate-commit-msg
6
+ sync-instructions
7
+
8
+ Use:
9
+ agent-toolkit <command> --help
@@ -0,0 +1,3 @@
1
+ Usage:
2
+ agent-toolkit preflight [--cwd <dir>] [--require <path>] ...
3
+ [--ensure-dir <path>] ... [--json <file>]
@@ -0,0 +1,3 @@
1
+ Usage:
2
+ agent-toolkit run-capture --out <logFile> --cmd <command>
3
+ [--cwd <directory>] [--meta <metaFile>] [--allow-pipe]
@@ -0,0 +1,3 @@
1
+ Usage:
2
+ agent-toolkit summarize-log --file <logFile>
3
+ [--last <lineCount>] [--match <regex>] [--max <lineCount>]
@@ -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.
@@ -0,0 +1,7 @@
1
+ Usage:
2
+ agent-toolkit validate-commit-msg --file <message-file>
3
+
4
+ Rules:
5
+ - Every line must start with [TAG]
6
+ - No empty lines are allowed
7
+ - Optional target form: [TAG] <target>: <summary>
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);