peaks-cli 1.0.0 → 1.0.2

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
@@ -7,7 +7,7 @@ Peaks 是一个面向 Claude Code 的全局 CLI 工具和短技能族,用来
7
7
  ## 安装
8
8
 
9
9
  ```bash
10
- npm install -g @peaks/cli
10
+ npm install -g peaks-cli
11
11
  ```
12
12
 
13
13
  安装后可直接使用:
@@ -1,6 +1,10 @@
1
+ import { CommanderError } from 'commander';
1
2
  import { createProgram } from './program.js';
2
3
  import { getErrorMessage } from '../shared/result.js';
3
4
  createProgram().parseAsync(process.argv).catch((error) => {
5
+ if (error instanceof CommanderError && error.code === 'commander.version') {
6
+ return;
7
+ }
4
8
  console.error(JSON.stringify({
5
9
  ok: false,
6
10
  command: 'cli',
@@ -1,11 +1,26 @@
1
1
  import { Command } from 'commander';
2
+ import { CLI_VERSION } from '../shared/version.js';
2
3
  import { registerCoreAndArtifactCommands } from './commands/core-artifact-commands.js';
3
4
  import { registerWorkflowCommands } from './commands/workflow-commands.js';
4
5
  import { registerCapabilityWorkerConfigAndSCCommands } from './commands/capability-worker-config-sc-commands.js';
5
6
  export { printResult } from './cli-helpers.js';
6
7
  export function createProgram(io = { stdout: (text) => console.log(text), stderr: (text) => console.error(text) }) {
7
8
  const program = new Command();
8
- program.name('peaks').description('Peaks CLI and short skill family runtime manager').version('0.1.0').exitOverride();
9
+ program
10
+ .name('peaks')
11
+ .description('Peaks CLI and short skill family runtime manager')
12
+ .configureOutput({
13
+ writeOut: (text) => io.stdout(text.trimEnd()),
14
+ writeErr: (text) => io.stderr(text.trimEnd())
15
+ })
16
+ .version(CLI_VERSION, '-v, --version')
17
+ .option('-V', 'output the version number')
18
+ .action(() => {
19
+ if (program.opts().V) {
20
+ io.stdout(CLI_VERSION);
21
+ }
22
+ })
23
+ .exitOverride();
9
24
  registerCoreAndArtifactCommands(program, io);
10
25
  registerWorkflowCommands(program, io);
11
26
  registerCapabilityWorkerConfigAndSCCommands(program, io);
@@ -0,0 +1 @@
1
+ export declare const CLI_VERSION = "1.0.2";
@@ -0,0 +1 @@
1
+ export const CLI_VERSION = "1.0.2";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "peaks-cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Peaks CLI and short skill family for Claude Code automation.",
5
5
  "author": "SquabbyZ",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -18,13 +18,14 @@
18
18
  "dist/src/**/*.js",
19
19
  "dist/src/**/*.d.ts",
20
20
  "scripts/clean-dist.mjs",
21
+ "scripts/sync-version.mjs",
21
22
  "scripts/install-skills.mjs",
22
23
  "scripts/watch.mjs",
23
24
  "skills/**",
24
25
  "schemas/*.json"
25
26
  ],
26
27
  "scripts": {
27
- "build": "node ./scripts/clean-dist.mjs && tsc -p tsconfig.json",
28
+ "build": "node ./scripts/sync-version.mjs && node ./scripts/clean-dist.mjs && tsc -p tsconfig.json",
28
29
  "prepack": "npm run build",
29
30
  "postinstall": "node ./scripts/install-skills.mjs",
30
31
  "dev": "tsx src/cli/index.ts",
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { existsSync, lstatSync, mkdirSync, readdirSync, realpathSync, symlinkSync } from 'node:fs';
2
+ import { existsSync, lstatSync, mkdirSync, readFileSync, readlinkSync, readdirSync, symlinkSync, unlinkSync, writeFileSync } from 'node:fs';
3
3
  import { homedir } from 'node:os';
4
4
  import { dirname, join, resolve } from 'node:path';
5
5
  import { fileURLToPath, pathToFileURL } from 'node:url';
@@ -12,12 +12,21 @@ function getPathStats(path) {
12
12
  }
13
13
  }
14
14
 
15
- function linksToSamePath(targetPath, sourcePath) {
16
- try {
17
- return realpathSync(targetPath) === realpathSync(sourcePath);
18
- } catch {
19
- return false;
15
+ function isBrokenSymlink(stats, targetPath) {
16
+ return stats.isSymbolicLink() && !existsSync(targetPath);
17
+ }
18
+
19
+ function getManagedTarget(targetPath) {
20
+ const markerPath = `${targetPath}.peaks-managed`;
21
+ if (!existsSync(markerPath)) {
22
+ return null;
20
23
  }
24
+ return readFileSync(markerPath, 'utf8').trim();
25
+ }
26
+
27
+ function markManagedPeaksLink(targetPath, sourcePath) {
28
+ const markerPath = `${targetPath}.peaks-managed`;
29
+ writeFileSync(markerPath, `${sourcePath}\n`, 'utf8');
21
30
  }
22
31
 
23
32
  export function installBundledSkills(options = {}) {
@@ -44,15 +53,22 @@ export function installBundledSkills(options = {}) {
44
53
 
45
54
  const current = getPathStats(targetPath);
46
55
  if (current) {
47
- if (!current.isSymbolicLink() || !linksToSamePath(targetPath, sourcePath)) {
56
+ const managedTarget = getManagedTarget(targetPath);
57
+ if (current.isSymbolicLink() && readlinkSync(targetPath) === sourcePath) {
58
+ installed.push(skillName);
59
+ continue;
60
+ }
61
+ if (isBrokenSymlink(current, targetPath) && managedTarget === readlinkSync(targetPath)) {
62
+ unlinkSync(targetPath);
63
+ unlinkSync(`${targetPath}.peaks-managed`);
64
+ } else {
48
65
  skipped.push(skillName);
49
66
  continue;
50
67
  }
51
- installed.push(skillName);
52
- continue;
53
68
  }
54
69
 
55
70
  symlinkSync(sourcePath, targetPath, process.platform === 'win32' ? 'junction' : 'dir');
71
+ markManagedPeaksLink(targetPath, sourcePath);
56
72
  installed.push(skillName);
57
73
  }
58
74
 
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync, writeFileSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+
5
+ const packageJson = JSON.parse(readFileSync(resolve('package.json'), 'utf8'));
6
+ const version = packageJson.version;
7
+
8
+ if (typeof version !== 'string' || version.length === 0) {
9
+ throw new Error('package.json version must be a non-empty string');
10
+ }
11
+
12
+ writeFileSync(resolve('src/shared/version.ts'), `export const CLI_VERSION = ${JSON.stringify(version)};\n`);