@logicseek/hello-cc 0.1.1 → 0.1.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/CHANGELOG.md ADDED
@@ -0,0 +1,81 @@
1
+ # Changelog
2
+
3
+ This project keeps one changelog file. Add one section per release, with the
4
+ newest version first. Do not create a new changelog file for every release.
5
+
6
+ Before publishing, run:
7
+
8
+ ```bash
9
+ npm run release:check
10
+ npm run release:notes
11
+ ```
12
+
13
+ Use the output of `npm run release:notes` as the GitHub Release description for
14
+ the current `package.json` version.
15
+
16
+ ## 0.1.2
17
+
18
+ ### Summary
19
+
20
+ hello-cc 0.1.2 tightens the public release surface after the first scoped npm
21
+ publish. It adds a first-class update command, makes uninstall discoverable in
22
+ top-level help, and reorganizes the documentation so the npm package page and
23
+ GitHub release notes have a clear, detailed description of what changed.
24
+
25
+ ### Highlights
26
+
27
+ - Added `hcc update`, which updates the global npm install by running
28
+ `npm install -g @logicseek/hello-cc@latest`.
29
+ - Added `hcc update --tag`, `hcc update --registry`, and `hcc update --dry-run`
30
+ for controlled upgrades and release verification.
31
+ - Made `hcc uninstall` visible in top-level `hcc --help`, matching the README
32
+ and command reference.
33
+ - Kept uninstall behavior conservative: `hcc uninstall` removes hooks and
34
+ shims, while `hcc uninstall --purge --yes` is required to remove project data.
35
+ - Split documentation into a short README, a user guide, command reference, and
36
+ documentation index in both English and Chinese.
37
+ - Restored the Star History chart at the bottom of both README files.
38
+ - Included README-linked package assets in the npm tarball so the package page
39
+ renders the project logo correctly.
40
+
41
+ ### Documentation
42
+
43
+ - `README.md` and `README.zh-CN.md` now focus on product positioning, install
44
+ and maintenance commands, quick start, a basic workflow, and links to docs.
45
+ - `docs/guide.md` and `docs/guide.zh-CN.md` describe practical usage and avoid
46
+ embedding the full command list.
47
+ - `docs/commands.md` and `docs/commands.zh-CN.md` provide the compact command
48
+ reference.
49
+ - `docs/README.md` and `docs/README.zh-CN.md` provide the documentation index.
50
+ - English documentation links now point to English user docs, and Chinese
51
+ documentation links point to Chinese user docs.
52
+
53
+ ### Validation
54
+
55
+ The 0.1.2 release should be validated with:
56
+
57
+ ```bash
58
+ git diff --check
59
+ node --check bin/hcc.mjs
60
+ node --check scripts/regression.mjs
61
+ node --check lib/setup.mjs
62
+ node --check lib/discover.mjs
63
+ npm pack --dry-run --json
64
+ npm publish --dry-run --registry=https://registry.npmjs.org/ --access public
65
+ npm test
66
+ ```
67
+
68
+ The package dry run should include `CHANGELOG.md`, `assets/logo.svg`, and the
69
+ English and Chinese command reference files.
70
+
71
+ The expected full regression marker is:
72
+
73
+ ```text
74
+ FULL_REGRESSION_OK
75
+ ```
76
+
77
+ ### Release Notes Source
78
+
79
+ Use this changelog section as the source for the GitHub Release notes for
80
+ `v0.1.2`. The npm package metadata keeps a short description, while the package
81
+ README and this changelog provide the detailed release description.
package/README.md CHANGED
@@ -37,7 +37,7 @@ doing.
37
37
  - **One console, many projects**: one local Web runtime can switch between
38
38
  registered project roots.
39
39
 
40
- ## Install
40
+ ## Install And Manage
41
41
 
42
42
  Node.js 24 or newer is required.
43
43
 
@@ -48,7 +48,7 @@ npm install -g @logicseek/hello-cc
48
48
  Update an existing global install:
49
49
 
50
50
  ```bash
51
- npm install -g @logicseek/hello-cc@latest
51
+ hcc update
52
52
  ```
53
53
 
54
54
  Or run it without a global install:
@@ -57,6 +57,18 @@ Or run it without a global install:
57
57
  npx @logicseek/hello-cc web
58
58
  ```
59
59
 
60
+ Remove hooks and shims from this machine:
61
+
62
+ ```bash
63
+ hcc uninstall
64
+ ```
65
+
66
+ Remove the global npm package:
67
+
68
+ ```bash
69
+ npm uninstall -g @logicseek/hello-cc
70
+ ```
71
+
60
72
  ## Quick Start
61
73
 
62
74
  Run this inside the project you want agents to share:
@@ -110,12 +122,14 @@ generic session-isolation assumptions.
110
122
 
111
123
  ## Documentation
112
124
 
113
- - [User Guide](docs/guide.md): setup, Web console, commands, workflows, and
114
- environment behavior.
125
+ - [Documentation Index](docs/README.md): all user and implementation docs.
126
+ - [User Guide](docs/guide.md): setup, Web console, workflows, coordination
127
+ semantics, and environment behavior.
128
+ - [Command Reference](docs/commands.md): compact public command list.
129
+ - [Changelog](CHANGELOG.md): release notes for published versions.
115
130
  - [Design Notes](docs/design.md): product boundaries and coordination model.
116
131
  - [Implementation Notes](docs/implementation.md): architecture and internal
117
132
  protocol.
118
- - [中文用户指南](docs/guide.zh-CN.md)
119
133
 
120
134
  ## Testing
121
135
 
@@ -129,3 +143,11 @@ temporary tmux sessions, and a temporary Web runtime to test the main flows.
129
143
  ## License
130
144
 
131
145
  [Apache-2.0](LICENSE)
146
+
147
+ ---
148
+
149
+ <p align="center">
150
+ <a href="https://star-history.com/#Dullne/hello-cc&Date">
151
+ <img src="https://api.star-history.com/svg?repos=Dullne/hello-cc&type=Date" width="600" alt="Star History Chart">
152
+ </a>
153
+ </p>
package/README.zh-CN.md CHANGED
@@ -26,7 +26,7 @@
26
26
  - **resume 友好的稳定身份**:当 provider 暴露 session id 时,恢复会话会映射回稳定 peer。
27
27
  - **一个控制台管理多个项目**:单个本地 Web runtime 可以在多个 project root 之间切换。
28
28
 
29
- ## 安装
29
+ ## 安装和维护
30
30
 
31
31
  需要 Node.js 24 或更新版本。
32
32
 
@@ -37,7 +37,7 @@ npm install -g @logicseek/hello-cc
37
37
  更新已有的全局安装:
38
38
 
39
39
  ```bash
40
- npm install -g @logicseek/hello-cc@latest
40
+ hcc update
41
41
  ```
42
42
 
43
43
  也可以不全局安装,直接运行:
@@ -46,6 +46,18 @@ npm install -g @logicseek/hello-cc@latest
46
46
  npx @logicseek/hello-cc web
47
47
  ```
48
48
 
49
+ 移除本机 hooks 和 shims:
50
+
51
+ ```bash
52
+ hcc uninstall
53
+ ```
54
+
55
+ 移除全局 npm 包:
56
+
57
+ ```bash
58
+ npm uninstall -g @logicseek/hello-cc
59
+ ```
60
+
49
61
  ## 快速开始
50
62
 
51
63
  在需要多个 agent 共享状态的项目中运行:
@@ -95,10 +107,10 @@ hcc task done --id 1 --summary "Done"
95
107
 
96
108
  ## 文档
97
109
 
98
- - [用户指南](docs/guide.zh-CN.md):安装、Web 控制台、常用命令、协作流程和环境变量行为。
99
- - [设计说明](docs/design.md):产品边界和协作模型。
100
- - [实现说明](docs/implementation.md):架构和内部协议。
101
- - [English User Guide](docs/guide.md)
110
+ - [文档目录](docs/README.zh-CN.md):全部用户文档和实现文档入口。
111
+ - [用户指南](docs/guide.zh-CN.md):安装、Web 控制台、协作流程、协作语义和环境变量行为。
112
+ - [命令参考](docs/commands.zh-CN.md):紧凑公共命令清单。
113
+ - [更新日志](CHANGELOG.md):已发布版本的 release notes。
102
114
 
103
115
  ## 测试
104
116
 
@@ -111,3 +123,11 @@ npm test
111
123
  ## License
112
124
 
113
125
  [Apache-2.0](LICENSE)
126
+
127
+ ---
128
+
129
+ <p align="center">
130
+ <a href="https://star-history.com/#Dullne/hello-cc&Date">
131
+ <img src="https://api.star-history.com/svg?repos=Dullne/hello-cc&type=Date" width="600" alt="Star History Chart">
132
+ </a>
133
+ </p>
@@ -0,0 +1,84 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240" width="240" height="240">
2
+ <defs>
3
+ <filter id="outerGlow" x="-10%" y="-10%" width="120%" height="120%">
4
+ <feGaussianBlur stdDeviation="4" result="blur"/>
5
+ <feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
6
+ </filter>
7
+ <radialGradient id="bgGrad" cx="40%" cy="35%" r="70%">
8
+ <stop offset="0%" stop-color="#1a2028"/>
9
+ <stop offset="100%" stop-color="#0a0c0f"/>
10
+ </radialGradient>
11
+ <!-- Text gradient: white → teal, connects wordmark to mesh -->
12
+ <linearGradient id="textGrad" x1="0" y1="0" x2="0" y2="1">
13
+ <stop offset="0%" stop-color="#eef2f6"/>
14
+ <stop offset="100%" stop-color="#40c4aa"/>
15
+ </linearGradient>
16
+ </defs>
17
+
18
+ <!-- Badge -->
19
+ <circle cx="120" cy="120" r="114" fill="url(#bgGrad)" filter="url(#outerGlow)"/>
20
+ <circle cx="120" cy="120" r="113" fill="none" stroke="#303640" stroke-width="1.5"/>
21
+ <circle cx="120" cy="120" r="105" fill="none" stroke="#40c4aa" stroke-width="0.4" opacity="0.25"/>
22
+
23
+ <!--
24
+ Mesh pentagon — center (120, 108), circumradius R=65
25
+ Shifted down 8px from previous (was 100) for visual balance
26
+
27
+ Top: (120, 43)
28
+ Upper-right: (182, 88)
29
+ Lower-right: (158, 161)
30
+ Lower-left: ( 82, 161)
31
+ Upper-left: ( 58, 88)
32
+ -->
33
+
34
+ <!-- Connections -->
35
+ <g stroke="#40c4aa" stroke-width="1.4" opacity="0.20" fill="none">
36
+ <line x1="120" y1="43" x2="182" y2="88"/>
37
+ <line x1="120" y1="43" x2="158" y2="161"/>
38
+ <line x1="120" y1="43" x2="82" y2="161"/>
39
+ <line x1="120" y1="43" x2="58" y2="88"/>
40
+ <line x1="182" y1="88" x2="158" y2="161"/>
41
+ <line x1="182" y1="88" x2="82" y2="161"/>
42
+ <line x1="182" y1="88" x2="58" y2="88"/>
43
+ <line x1="158" y1="161" x2="82" y2="161"/>
44
+ <line x1="158" y1="161" x2="58" y2="88"/>
45
+ <line x1="82" y1="161" x2="58" y2="88"/>
46
+ </g>
47
+
48
+ <!-- Spoke lines from center hub -->
49
+ <g stroke="#40c4aa" stroke-width="0.8" opacity="0.12">
50
+ <line x1="120" y1="108" x2="120" y2="43"/>
51
+ <line x1="120" y1="108" x2="182" y2="88"/>
52
+ <line x1="120" y1="108" x2="158" y2="161"/>
53
+ <line x1="120" y1="108" x2="82" y2="161"/>
54
+ <line x1="120" y1="108" x2="58" y2="88"/>
55
+ </g>
56
+
57
+ <!-- Node halos — all equal (flat peer mesh, no hierarchy) -->
58
+ <circle cx="120" cy="43" r="14" fill="none" stroke="#40c4aa" stroke-width="1" opacity="0.20"/>
59
+ <circle cx="182" cy="88" r="14" fill="none" stroke="#40c4aa" stroke-width="1" opacity="0.20"/>
60
+ <circle cx="158" cy="161" r="14" fill="none" stroke="#40c4aa" stroke-width="1" opacity="0.20"/>
61
+ <circle cx="82" cy="161" r="14" fill="none" stroke="#40c4aa" stroke-width="1" opacity="0.20"/>
62
+ <circle cx="58" cy="88" r="14" fill="none" stroke="#40c4aa" stroke-width="1" opacity="0.20"/>
63
+
64
+ <!-- All 5 nodes — same size, same style -->
65
+ <circle cx="120" cy="43" r="10" fill="#40c4aa" opacity="0.85"/>
66
+ <circle cx="182" cy="88" r="10" fill="#40c4aa" opacity="0.85"/>
67
+ <circle cx="158" cy="161" r="10" fill="#40c4aa" opacity="0.85"/>
68
+ <circle cx="82" cy="161" r="10" fill="#40c4aa" opacity="0.85"/>
69
+ <circle cx="58" cy="88" r="10" fill="#40c4aa" opacity="0.85"/>
70
+
71
+ <!-- Center hub -->
72
+ <circle cx="120" cy="108" r="6" fill="#8ee8d8" opacity="1.0"/>
73
+
74
+ <!-- "hcc" wordmark -->
75
+ <text
76
+ x="120" y="210"
77
+ font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace"
78
+ font-size="30"
79
+ font-weight="700"
80
+ fill="url(#textGrad)"
81
+ text-anchor="middle"
82
+ letter-spacing="5"
83
+ >hcc</text>
84
+ </svg>
package/bin/hcc.mjs CHANGED
@@ -16,9 +16,10 @@ const _libDir = path.resolve(fileURLToPath(import.meta.url), '..', '..', 'lib');
16
16
  async function loadDiscover() { return import(path.join(_libDir, 'discover.mjs')); }
17
17
  async function loadSetup() { return import(path.join(_libDir, 'setup.mjs')); }
18
18
 
19
- const VERSION = '0.1.1';
19
+ const VERSION = '0.1.2';
20
20
  const PRODUCT_NAME = 'hello-cc';
21
21
  const CLI_NAME = 'hcc';
22
+ const NPM_PACKAGE_NAME = '@logicseek/hello-cc';
22
23
  const DEFAULT_LOCK_TTL = 900;
23
24
  const ACTIVE_PEER_TTL = 600;
24
25
  // Directory under .hello-cc/ for optional external PTY buffer files.
@@ -128,6 +129,14 @@ function parseOpts(args, spec = {}) {
128
129
  return opts;
129
130
  }
130
131
 
132
+ function wantsHelp(args) {
133
+ const stop = args.indexOf('--');
134
+ const scan = stop >= 0 ? args.slice(0, stop) : args;
135
+ const index = scan.findIndex((arg) => arg === '--help' || arg === '-h');
136
+ if (index < 0) return false;
137
+ return index <= 1 || !String(scan[index - 1] || '').startsWith('--');
138
+ }
139
+
131
140
  function validateOpts(command, opts, allowed = []) {
132
141
  const allowedSet = new Set(['_', ...allowed]);
133
142
  for (const key of Object.keys(opts)) {
@@ -2289,7 +2298,7 @@ async function cmdPeers(ctx, args) {
2289
2298
 
2290
2299
  async function cmdTask(ctx, args) {
2291
2300
  const sub = args[0];
2292
- if (!sub || sub === '--help' || sub === '-h') return helpTask();
2301
+ if (!sub || wantsHelp(args)) return helpTask();
2293
2302
  if (sub === 'create') return taskCreate(ctx, args.slice(1));
2294
2303
  if (sub === 'list') return taskList(ctx, args.slice(1));
2295
2304
  if (sub === 'claim') return taskClaim(ctx, args.slice(1));
@@ -2467,7 +2476,7 @@ async function taskDone(ctx, args) {
2467
2476
 
2468
2477
  async function cmdMsg(ctx, args) {
2469
2478
  const sub = args[0];
2470
- if (!sub || sub === '--help' || sub === '-h') return helpMsg();
2479
+ if (!sub || wantsHelp(args)) return helpMsg();
2471
2480
  if (sub === 'send') return msgSend(ctx, args.slice(1));
2472
2481
  if (sub === 'inbox') return msgInbox(ctx, args.slice(1));
2473
2482
  if (sub === 'ack') return msgAck(ctx, args.slice(1));
@@ -2598,7 +2607,7 @@ async function cmdInject(ctx, args) {
2598
2607
 
2599
2608
  async function cmdPeer(ctx, args) {
2600
2609
  const sub = args[0];
2601
- if (!sub || sub === '--help' || sub === '-h') return helpPeer();
2610
+ if (!sub || wantsHelp(args)) return helpPeer();
2602
2611
  if (sub === 'list') return peerList(ctx, args.slice(1));
2603
2612
  if (sub === 'start') return peerStart(ctx, args.slice(1));
2604
2613
  if (sub === 'attach') return peerAttach(ctx, args.slice(1));
@@ -2748,7 +2757,7 @@ async function peerStop(ctx, args) {
2748
2757
 
2749
2758
  async function cmdLock(ctx, args) {
2750
2759
  const sub = args[0];
2751
- if (!sub || sub === '--help' || sub === '-h') return helpLock();
2760
+ if (!sub || wantsHelp(args)) return helpLock();
2752
2761
  if (sub === 'acquire') return lockAcquire(ctx, args.slice(1));
2753
2762
  if (sub === 'release') return lockRelease(ctx, args.slice(1));
2754
2763
  if (sub === 'renew') return lockRenew(ctx, args.slice(1));
@@ -2847,7 +2856,7 @@ async function lockList(ctx, args) {
2847
2856
 
2848
2857
  async function cmdHandoff(ctx, args) {
2849
2858
  const sub = args[0];
2850
- if (!sub || sub === '--help' || sub === '-h') return helpHandoff();
2859
+ if (!sub || wantsHelp(args)) return helpHandoff();
2851
2860
  if (sub === 'create') return handoffCreate(ctx, args.slice(1));
2852
2861
  if (sub === 'list') return handoffList(ctx, args.slice(1));
2853
2862
  throw new CliError('BAD_ARGS', `Unknown handoff command: ${sub}`);
@@ -2900,7 +2909,7 @@ async function handoffList(ctx, args) {
2900
2909
 
2901
2910
  async function cmdEvent(ctx, args) {
2902
2911
  const sub = args[0];
2903
- if (!sub || sub === '--help' || sub === '-h') return helpEvent();
2912
+ if (!sub || wantsHelp(args)) return helpEvent();
2904
2913
  if (sub === 'tail') return eventTail(ctx, args.slice(1));
2905
2914
  throw new CliError('BAD_ARGS', `Unknown event command: ${sub}`);
2906
2915
  }
@@ -5539,6 +5548,8 @@ Commands:
5539
5548
  web Start coordination, shims, tmux, and browser console
5540
5549
  up Initialize local coordination only
5541
5550
  down Stop the running hello-cc web runtime
5551
+ update Update the global npm install of hello-cc
5552
+ uninstall Remove hooks, shims, and optional project data
5542
5553
  init Initialize .hello-cc/mesh.db and guidance
5543
5554
  register --peer ID Register or update a peer session identity
5544
5555
  join --peer ID Register this shell and print eval-able env
@@ -5780,6 +5791,24 @@ Stops the web runtime started by hcc web for this project.
5780
5791
  `);
5781
5792
  }
5782
5793
 
5794
+ function helpUpdate() {
5795
+ console.log(`${CLI_NAME} update
5796
+
5797
+ Usage:
5798
+ ${CLI_NAME} update [--tag TAG] [--registry URL] [--dry-run]
5799
+
5800
+ Examples:
5801
+ ${CLI_NAME} update
5802
+ ${CLI_NAME} update --tag latest
5803
+ ${CLI_NAME} update --dry-run
5804
+
5805
+ Updates the global npm install by running:
5806
+ npm install -g ${NPM_PACKAGE_NAME}@TAG
5807
+
5808
+ The default TAG is latest.
5809
+ `);
5810
+ }
5811
+
5783
5812
  function helpWeb() {
5784
5813
  console.log(`${CLI_NAME} web
5785
5814
 
@@ -6103,6 +6132,46 @@ async function cmdSetup(ctx, args) {
6103
6132
  log('\nDone. Run `hcc web` for the default coordinated terminal experience.');
6104
6133
  }
6105
6134
 
6135
+ // ─── hcc update ──────────────────────────────────────────────────────────────
6136
+
6137
+ async function cmdUpdate(ctx, args) {
6138
+ if (args[0] === '--help' || args[0] === '-h') return helpUpdate();
6139
+
6140
+ const opts = parseOpts(args, { booleans: ['dry-run'] });
6141
+ validateOpts('update', opts, ['tag', 'registry', 'dry-run']);
6142
+ const tag = opts.tag || 'latest';
6143
+ if (!/^[A-Za-z0-9._+-]+$/.test(tag)) {
6144
+ throw new CliError('BAD_ARGS', '--tag must be an npm dist-tag or version');
6145
+ }
6146
+
6147
+ const packageSpec = `${NPM_PACKAGE_NAME}@${tag}`;
6148
+ const npmArgs = ['install', '-g', packageSpec];
6149
+ if (opts.registry) npmArgs.push('--registry', opts.registry);
6150
+ const command = shellCommand(['npm', ...npmArgs]);
6151
+ const data = { package: NPM_PACKAGE_NAME, tag, registry: opts.registry || null, command, dry_run: Boolean(opts['dry-run']) };
6152
+
6153
+ if (opts['dry-run']) {
6154
+ printResult(ctx, data, () => `would run: ${command}`);
6155
+ return;
6156
+ }
6157
+
6158
+ const result = spawnSync('npm', npmArgs, {
6159
+ encoding: ctx.json ? 'utf8' : undefined,
6160
+ stdio: ctx.json ? ['ignore', 'pipe', 'pipe'] : 'inherit'
6161
+ });
6162
+ if (result.error) {
6163
+ throw new CliError('UPDATE_FAILED', `npm update command failed: ${result.error.message}`);
6164
+ }
6165
+ if (result.status !== 0) {
6166
+ const output = ctx.json
6167
+ ? [result.stdout, result.stderr].filter(Boolean).join('\n').trim()
6168
+ : '';
6169
+ throw new CliError('UPDATE_FAILED', output || `npm exited with status ${result.status}`);
6170
+ }
6171
+
6172
+ printResult(ctx, data, () => `updated ${packageSpec}`);
6173
+ }
6174
+
6106
6175
  // ─── hcc uninstall ───────────────────────────────────────────────────────────
6107
6176
 
6108
6177
  async function cmdUninstall(ctx, args) {
@@ -6326,6 +6395,7 @@ async function dispatch(ctx, rest) {
6326
6395
  if (command === '--version' || command === 'version') return console.log(VERSION);
6327
6396
  if (command === 'up') return cmdUp(ctx, args);
6328
6397
  if (command === 'down') return cmdDown(ctx, args);
6398
+ if (command === 'update') return cmdUpdate(ctx, args);
6329
6399
  if (command === 'uninstall') return cmdUninstall(ctx, args);
6330
6400
  if (command === 'init') return cmdInit(ctx, args);
6331
6401
  if (command === 'register') return cmdRegister(ctx, args);
package/docs/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # hello-cc Documentation
2
+
3
+ Start with the [project README](../README.md) when you only need the project
4
+ summary and first command. Use these docs when you need more detail.
5
+
6
+ ## User Docs
7
+
8
+ - [User Guide](guide.md): install, start, Web console, coordination semantics,
9
+ workflow, stable peer identity, and environment behavior.
10
+ - [Command Reference](commands.md): compact list of public commands and the
11
+ intended use of each command group.
12
+ - [Changelog](../CHANGELOG.md): release notes for published versions.
13
+ - Release notes: run `npm run release:check` before publishing, and use
14
+ `npm run release:notes` to print the current changelog section for GitHub
15
+ Release notes.
16
+
17
+ ## Design And Implementation
18
+
19
+ - [Design Notes](design.md): product boundary, project boundary, capability
20
+ levels, coordination semantics, and provider-session binding.
21
+ - [Implementation Notes](implementation.md): architecture, protocol, command
22
+ surface, stack, shim behavior, and implementation plan.
@@ -0,0 +1,22 @@
1
+ # hello-cc 文档
2
+
3
+ 只需要项目简介和第一条命令时,先看[仓库 README](../README.zh-CN.md)。
4
+ 需要更多细节时,再看下面的文档。
5
+
6
+ ## 用户文档
7
+
8
+ - [用户指南](guide.zh-CN.md):安装、启动、Web 控制台、协作语义、工作流、稳定
9
+ peer 身份和环境变量行为。
10
+ - [命令参考](commands.zh-CN.md):公共命令的紧凑清单,以及每组命令的用途。
11
+ - [更新日志](../CHANGELOG.md):已发布版本的 release notes。
12
+ - 发行说明:发布前运行 `npm run release:check`,用
13
+ `npm run release:notes` 输出当前版本的 changelog 小节,作为 GitHub
14
+ Release 描述。
15
+
16
+ ## 设计和实现
17
+
18
+ - [设计说明](design.md):产品边界、项目边界、能力层级、协作语义和 provider
19
+ session 绑定。
20
+ - [实现说明](implementation.md):架构、协议、命令面、技术栈、shim 行为和实现计划。
21
+
22
+ 设计和实现文档目前只有英文版。
@@ -0,0 +1,104 @@
1
+ # hello-cc Command Reference
2
+
3
+ Use `hcc --help` for the current top-level command list. Most subcommands also
4
+ accept `--help`, for example `hcc update --help`, `hcc peer --help`, and
5
+ `hcc task --help`.
6
+
7
+ ## Install Maintenance
8
+
9
+ ```text
10
+ hcc update [--tag TAG] [--registry URL] [--dry-run]
11
+ hcc uninstall [--purge --yes]
12
+ ```
13
+
14
+ `hcc update` updates the global npm install. `hcc uninstall` removes local
15
+ hooks and shims; add `--purge --yes` only when you also want to remove the
16
+ current project's `.hello-cc` data and guidance blocks.
17
+
18
+ ## Start And Stop
19
+
20
+ ```text
21
+ hcc web [--host HOST] [--port N] [--token TEXT] [--local] [--no-discover] [--no-guidance]
22
+ hcc down
23
+ hcc up [--no-discover] [--no-guidance]
24
+ ```
25
+
26
+ `hcc web` is the default entry. It initializes coordination, installs hooks and
27
+ shims, starts or reuses the Web console, and returns the terminal to you. Use
28
+ `hcc up` only when you want coordination without the Web console or shims.
29
+
30
+ ## Peers And Status
31
+
32
+ ```text
33
+ hcc peers
34
+ hcc status [--peer ID]
35
+ hcc scan [--register]
36
+ hcc prompt --peer ID [--kind codex|claude|shell|other] [--role ROLE]
37
+ hcc join --peer ID [--kind codex|claude|shell|other] [--role ROLE]
38
+ hcc env --peer ID
39
+ hcc heartbeat [--peer ID] [--renew-locks --ttl 900]
40
+ hcc run --peer ID --kind codex|claude|shell --role ROLE -- COMMAND [ARGS...]
41
+ ```
42
+
43
+ Use these commands to inspect live project state, register terminals, and run a
44
+ CLI with `HCC_PEER`, `HCC_ROOT`, and `HCC_DB` set.
45
+
46
+ ## Browser-Controllable Terminals
47
+
48
+ ```text
49
+ hcc peer list
50
+ hcc peer start PEER [--kind K] [--role R] [--cwd DIR] [--restart-env] -- COMMAND [ARGS...]
51
+ hcc peer start PEER --kind codex --resume SESSION_ID [--restart-env]
52
+ hcc peer start PEER --kind codex --last
53
+ hcc peer start PEER --kind claude --resume SESSION_ID [--restart-env]
54
+ hcc peer start PEER --kind claude --continue
55
+ hcc peer attach PEER [--pane PANE] [--kind K] [--role R] [--cwd DIR]
56
+ hcc peer stop PEER
57
+ hcc inject PEER TEXT [--no-enter]
58
+ ```
59
+
60
+ These commands create or attach tmux-backed terminals that can be viewed and
61
+ controlled from the Web console.
62
+
63
+ ## Messages
64
+
65
+ ```text
66
+ hcc msg send [--from ID] [--to ID|all] --body TEXT [--task N] [--kind note|task|handoff]
67
+ hcc msg inbox [--peer ID] [--wait SEC] [--all] [--limit N]
68
+ hcc msg ack [--peer ID] --id N
69
+ hcc ask PEER MESSAGE [--from ID] [--task N] [--inject]
70
+ hcc broadcast MESSAGE [--from ID] [--task N] [--inject]
71
+ ```
72
+
73
+ Messages are addressed mailbox items. `ask` and `broadcast` also support live
74
+ terminal injection with `--inject`.
75
+
76
+ ## Tasks
77
+
78
+ ```text
79
+ hcc task create --title TEXT [--body TEXT] [--from ID] [--to ID] [--priority N]
80
+ hcc task list [--status S] [--peer ID] [--all]
81
+ hcc task claim [--peer ID] --id N
82
+ hcc task next [--peer ID]
83
+ hcc task update [--peer ID] --id N --status running|review|blocked|done|abandoned [--summary TEXT] [--body TEXT] [--to ID]
84
+ hcc task done [--peer ID] --id N --summary TEXT
85
+ ```
86
+
87
+ Tasks are shared project facts. They remain visible until marked `done` or
88
+ `abandoned`.
89
+
90
+ ## Locks, Handoffs, And Events
91
+
92
+ ```text
93
+ hcc lock acquire [--peer ID] --resource PATH [--task N] [--ttl SEC] [--reason TEXT]
94
+ hcc lock renew [--peer ID] --resource PATH [--ttl SEC]
95
+ hcc lock release [--peer ID] --resource PATH [--force]
96
+ hcc lock list [--all]
97
+ hcc handoff create [--from ID] --summary TEXT [--task N] [--to ID] [--changed-files JSON_OR_CSV] [--tests TEXT] [--risks TEXT]
98
+ hcc handoff list [--task N] [--limit N]
99
+ hcc event tail [--limit N]
100
+ hcc gc [--older-than DAYS] [--yes]
101
+ ```
102
+
103
+ Locks are advisory coordination locks with TTLs. Handoffs preserve the result,
104
+ tests, changed files, and remaining risks when work moves between peers.
@@ -0,0 +1,101 @@
1
+ # hello-cc 命令参考
2
+
3
+ 使用 `hcc --help` 查看当前顶层命令列表。大多数子命令也支持 `--help`,
4
+ 例如 `hcc update --help`、`hcc peer --help` 和 `hcc task --help`。
5
+
6
+ ## 安装维护
7
+
8
+ ```text
9
+ hcc update [--tag TAG] [--registry URL] [--dry-run]
10
+ hcc uninstall [--purge --yes]
11
+ ```
12
+
13
+ `hcc update` 更新全局 npm 安装。`hcc uninstall` 移除本机 hooks 和 shims;
14
+ 只有在确定也要删除当前项目的 `.hello-cc` 数据和指导块时,才加
15
+ `--purge --yes`。
16
+
17
+ ## 启动和停止
18
+
19
+ ```text
20
+ hcc web [--host HOST] [--port N] [--token TEXT] [--local] [--no-discover] [--no-guidance]
21
+ hcc down
22
+ hcc up [--no-discover] [--no-guidance]
23
+ ```
24
+
25
+ `hcc web` 是默认入口。它会初始化协作状态,安装 hooks 和 shims,启动或复用
26
+ Web 控制台,然后把终端还给你。只想使用本地协作、不需要 Web 或 shims 时,
27
+ 再使用 `hcc up`。
28
+
29
+ ## Peers 和状态
30
+
31
+ ```text
32
+ hcc peers
33
+ hcc status [--peer ID]
34
+ hcc scan [--register]
35
+ hcc prompt --peer ID [--kind codex|claude|shell|other] [--role ROLE]
36
+ hcc join --peer ID [--kind codex|claude|shell|other] [--role ROLE]
37
+ hcc env --peer ID
38
+ hcc heartbeat [--peer ID] [--renew-locks --ttl 900]
39
+ hcc run --peer ID --kind codex|claude|shell --role ROLE -- COMMAND [ARGS...]
40
+ ```
41
+
42
+ 这些命令用于查看项目状态、注册终端,以及用 `HCC_PEER`、`HCC_ROOT`、
43
+ `HCC_DB` 环境运行 CLI。
44
+
45
+ ## Web 可控终端
46
+
47
+ ```text
48
+ hcc peer list
49
+ hcc peer start PEER [--kind K] [--role R] [--cwd DIR] [--restart-env] -- COMMAND [ARGS...]
50
+ hcc peer start PEER --kind codex --resume SESSION_ID [--restart-env]
51
+ hcc peer start PEER --kind codex --last
52
+ hcc peer start PEER --kind claude --resume SESSION_ID [--restart-env]
53
+ hcc peer start PEER --kind claude --continue
54
+ hcc peer attach PEER [--pane PANE] [--kind K] [--role R] [--cwd DIR]
55
+ hcc peer stop PEER
56
+ hcc inject PEER TEXT [--no-enter]
57
+ ```
58
+
59
+ 这些命令创建或接入 tmux-backed 终端,让 Web 控制台可以观察和操作它们。
60
+
61
+ ## 消息
62
+
63
+ ```text
64
+ hcc msg send [--from ID] [--to ID|all] --body TEXT [--task N] [--kind note|task|handoff]
65
+ hcc msg inbox [--peer ID] [--wait SEC] [--all] [--limit N]
66
+ hcc msg ack [--peer ID] --id N
67
+ hcc ask PEER MESSAGE [--from ID] [--task N] [--inject]
68
+ hcc broadcast MESSAGE [--from ID] [--task N] [--inject]
69
+ ```
70
+
71
+ 消息是带收件人的邮箱记录。`ask` 和 `broadcast` 加 `--inject` 后,也会把内容
72
+ 实时注入到终端。
73
+
74
+ ## 任务
75
+
76
+ ```text
77
+ hcc task create --title TEXT [--body TEXT] [--from ID] [--to ID] [--priority N]
78
+ hcc task list [--status S] [--peer ID] [--all]
79
+ hcc task claim [--peer ID] --id N
80
+ hcc task next [--peer ID]
81
+ hcc task update [--peer ID] --id N --status running|review|blocked|done|abandoned [--summary TEXT] [--body TEXT] [--to ID]
82
+ hcc task done [--peer ID] --id N --summary TEXT
83
+ ```
84
+
85
+ 任务是项目共享事实。任务会一直可见,直到被标记为 `done` 或 `abandoned`。
86
+
87
+ ## 锁、交接和事件
88
+
89
+ ```text
90
+ hcc lock acquire [--peer ID] --resource PATH [--task N] [--ttl SEC] [--reason TEXT]
91
+ hcc lock renew [--peer ID] --resource PATH [--ttl SEC]
92
+ hcc lock release [--peer ID] --resource PATH [--force]
93
+ hcc lock list [--all]
94
+ hcc handoff create [--from ID] --summary TEXT [--task N] [--to ID] [--changed-files JSON_OR_CSV] [--tests TEXT] [--risks TEXT]
95
+ hcc handoff list [--task N] [--limit N]
96
+ hcc event tail [--limit N]
97
+ hcc gc [--older-than DAYS] [--yes]
98
+ ```
99
+
100
+ 锁是带 TTL 的协作式 advisory lock。交接记录用于保存结果、测试、变更文件和
101
+ 剩余风险,方便工作在多个 peer 之间继续。
package/docs/guide.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # hello-cc User Guide
2
2
 
3
- This guide contains the detailed usage notes that are intentionally kept out of
4
- the short project README.
3
+ This guide covers the practical workflow for installing, starting, and using
4
+ hello-cc. For a compact command list, use the [Command Reference](commands.md).
5
5
 
6
- ## Install And Update
6
+ ## Install, Update, And Uninstall
7
7
 
8
8
  Install hello-cc globally:
9
9
 
@@ -14,11 +14,30 @@ npm install -g @logicseek/hello-cc
14
14
  Update an existing global install:
15
15
 
16
16
  ```bash
17
- npm install -g @logicseek/hello-cc@latest
17
+ hcc update
18
18
  ```
19
19
 
20
- `hcc` does not have a self-update command. `hcc task update` updates a
21
- coordination task, not the installed package.
20
+ `hcc update` runs `npm install -g @logicseek/hello-cc@latest`. Use
21
+ `hcc update --help` to see the available update options. `hcc task update`
22
+ updates a coordination task, not the installed package.
23
+
24
+ Remove hooks and shims from this machine:
25
+
26
+ ```bash
27
+ hcc uninstall
28
+ ```
29
+
30
+ Remove the current project's `.hello-cc` data and guidance blocks too:
31
+
32
+ ```bash
33
+ hcc uninstall --purge --yes
34
+ ```
35
+
36
+ Remove the global npm package:
37
+
38
+ ```bash
39
+ npm uninstall -g @logicseek/hello-cc
40
+ ```
22
41
 
23
42
  ## Default Entry
24
43
 
@@ -222,62 +241,10 @@ Already-open raw terminals cannot be captured or controlled unconditionally
222
241
  unless they started under tmux, screen, or a hello-cc shim. They can still
223
242
  participate in tasks, messages, and locks through hooks and `hcc` commands.
224
243
 
225
- ## Common Commands
244
+ ## Command Reference
226
245
 
227
- ```text
228
- # Default entry
229
- hcc web [--host HOST] [--port N] [--token TEXT] [--local] [--no-discover] [--no-guidance]
230
- hcc down
231
-
232
- # Local coordination without Web
233
- hcc up [--no-discover] [--no-guidance]
234
-
235
- # Peers and status
236
- hcc peers
237
- hcc status [--peer ID]
238
- hcc scan [--register]
239
- hcc prompt --peer ID [--kind codex|claude|shell|other] [--role ROLE]
240
- hcc join --peer ID [--kind codex|claude|shell|other] [--role ROLE]
241
- hcc env --peer ID
242
- hcc heartbeat [--peer ID] [--renew-locks --ttl 900]
243
- hcc run --peer ID --kind codex|claude|shell --role ROLE -- COMMAND [ARGS...]
244
-
245
- # Browser-controllable terminals
246
- hcc peer list
247
- hcc peer start PEER [--kind K] [--role R] [--cwd DIR] [--restart-env] -- COMMAND [ARGS...]
248
- hcc peer start PEER --kind codex --resume SESSION_ID [--restart-env]
249
- hcc peer start PEER --kind codex --last
250
- hcc peer start PEER --kind claude --resume SESSION_ID [--restart-env]
251
- hcc peer start PEER --kind claude --continue
252
- hcc peer attach PEER [--pane PANE] [--kind K] [--role R] [--cwd DIR]
253
- hcc peer stop PEER
254
- hcc inject PEER TEXT [--no-enter]
255
-
256
- # Messages
257
- hcc msg send [--from ID] [--to ID|all] --body TEXT [--task N] [--kind note|task|handoff]
258
- hcc msg inbox [--peer ID] [--wait SEC] [--all] [--limit N]
259
- hcc msg ack [--peer ID] --id N
260
- hcc ask PEER MESSAGE [--from ID] [--task N] [--inject]
261
- hcc broadcast MESSAGE [--from ID] [--task N] [--inject]
262
-
263
- # Tasks
264
- hcc task create --title TEXT [--body TEXT] [--from ID] [--to ID] [--priority N]
265
- hcc task list [--status S] [--peer ID] [--all]
266
- hcc task claim [--peer ID] --id N
267
- hcc task next [--peer ID]
268
- hcc task update [--peer ID] --id N --status running|review|blocked|done|abandoned [--summary TEXT] [--body TEXT] [--to ID]
269
- hcc task done [--peer ID] --id N --summary TEXT
270
-
271
- # Locks and handoffs
272
- hcc lock acquire [--peer ID] --resource PATH [--task N] [--ttl SEC] [--reason TEXT]
273
- hcc lock renew [--peer ID] --resource PATH [--ttl SEC]
274
- hcc lock release [--peer ID] --resource PATH [--force]
275
- hcc lock list [--all]
276
- hcc handoff create [--from ID] --summary TEXT [--task N] [--to ID] [--changed-files JSON_OR_CSV] [--tests TEXT] [--risks TEXT]
277
- hcc handoff list [--task N] [--limit N]
278
- hcc event tail [--limit N]
279
- hcc gc [--older-than DAYS] [--yes]
280
- ```
246
+ Use `hcc --help` for the command list and `hcc <command> --help` for a specific
247
+ command. The maintained summary lives in the [Command Reference](commands.md).
281
248
 
282
249
  ## Stable Peer Identity
283
250
 
@@ -1,8 +1,9 @@
1
1
  # hello-cc 用户指南
2
2
 
3
- 这份文档保存详细使用说明,README 只保留项目入口和快速开始。
3
+ 这份文档说明安装、启动和日常使用流程。紧凑命令清单见
4
+ [命令参考](commands.zh-CN.md)。
4
5
 
5
- ## 安装和更新
6
+ ## 安装、更新和卸载
6
7
 
7
8
  全局安装 hello-cc:
8
9
 
@@ -13,10 +14,29 @@ npm install -g @logicseek/hello-cc
13
14
  更新已有的全局安装:
14
15
 
15
16
  ```bash
16
- npm install -g @logicseek/hello-cc@latest
17
+ hcc update
17
18
  ```
18
19
 
19
- `hcc` 没有自更新命令。`hcc task update` 更新的是协作任务状态,不是安装包版本。
20
+ `hcc update` 会执行 `npm install -g @logicseek/hello-cc@latest`。使用
21
+ `hcc update --help` 可以查看更新选项。`hcc task update` 更新的是协作任务状态,不是安装包版本。
22
+
23
+ 移除本机 hooks 和 shims:
24
+
25
+ ```bash
26
+ hcc uninstall
27
+ ```
28
+
29
+ 同时移除当前项目的 `.hello-cc` 数据和指导块:
30
+
31
+ ```bash
32
+ hcc uninstall --purge --yes
33
+ ```
34
+
35
+ 移除全局 npm 包:
36
+
37
+ ```bash
38
+ npm uninstall -g @logicseek/hello-cc
39
+ ```
20
40
 
21
41
  ## 默认入口
22
42
 
@@ -194,62 +214,10 @@ Web 操作的是 hello-cc 管理的本机 tmux 终端:
194
214
 
195
215
  已经打开的普通 raw 终端不能被无条件捕获或控制,除非它原本就在 tmux、screen 或 hello-cc shim 之下。它仍然可以通过 hooks 和 `hcc` 命令参与任务、消息和锁。
196
216
 
197
- ## 常用命令
217
+ ## 命令参考
198
218
 
199
- ```text
200
- # 默认入口
201
- hcc web [--host HOST] [--port N] [--token TEXT] [--local] [--no-discover] [--no-guidance]
202
- hcc down
203
-
204
- # 本地协调,无 Web
205
- hcc up [--no-discover] [--no-guidance]
206
-
207
- # 对等节点和状态
208
- hcc peers
209
- hcc status [--peer ID]
210
- hcc scan [--register]
211
- hcc prompt --peer ID [--kind codex|claude|shell|other] [--role ROLE]
212
- hcc join --peer ID [--kind codex|claude|shell|other] [--role ROLE]
213
- hcc env --peer ID
214
- hcc heartbeat [--peer ID] [--renew-locks --ttl 900]
215
- hcc run --peer ID --kind codex|claude|shell --role ROLE -- COMMAND [ARGS...]
216
-
217
- # Web 可控终端
218
- hcc peer list
219
- hcc peer start PEER [--kind K] [--role R] [--cwd DIR] [--restart-env] -- COMMAND [ARGS...]
220
- hcc peer start PEER --kind codex --resume SESSION_ID [--restart-env]
221
- hcc peer start PEER --kind codex --last
222
- hcc peer start PEER --kind claude --resume SESSION_ID [--restart-env]
223
- hcc peer start PEER --kind claude --continue
224
- hcc peer attach PEER [--pane PANE] [--kind K] [--role R] [--cwd DIR]
225
- hcc peer stop PEER
226
- hcc inject PEER TEXT [--no-enter]
227
-
228
- # 消息
229
- hcc msg send [--from ID] [--to ID|all] --body TEXT [--task N] [--kind note|task|handoff]
230
- hcc msg inbox [--peer ID] [--wait SEC] [--all] [--limit N]
231
- hcc msg ack [--peer ID] --id N
232
- hcc ask PEER MESSAGE [--from ID] [--task N] [--inject]
233
- hcc broadcast MESSAGE [--from ID] [--task N] [--inject]
234
-
235
- # 任务
236
- hcc task create --title TEXT [--body TEXT] [--from ID] [--to ID] [--priority N]
237
- hcc task list [--status S] [--peer ID] [--all]
238
- hcc task claim [--peer ID] --id N
239
- hcc task next [--peer ID]
240
- hcc task update [--peer ID] --id N --status running|review|blocked|done|abandoned [--summary TEXT] [--body TEXT] [--to ID]
241
- hcc task done [--peer ID] --id N --summary TEXT
242
-
243
- # 锁和交接
244
- hcc lock acquire [--peer ID] --resource PATH [--task N] [--ttl SEC] [--reason TEXT]
245
- hcc lock renew [--peer ID] --resource PATH [--ttl SEC]
246
- hcc lock release [--peer ID] --resource PATH [--force]
247
- hcc lock list [--all]
248
- hcc handoff create [--from ID] --summary TEXT [--task N] [--to ID] [--changed-files JSON_OR_CSV] [--tests TEXT] [--risks TEXT]
249
- hcc handoff list [--task N] [--limit N]
250
- hcc event tail [--limit N]
251
- hcc gc [--older-than DAYS] [--yes]
252
- ```
219
+ 使用 `hcc --help` 查看命令列表,使用 `hcc <command> --help` 查看单个命令。
220
+ 维护中的命令摘要见 [命令参考](commands.zh-CN.md)。
253
221
 
254
222
  ## 稳定 peer 身份
255
223
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logicseek/hello-cc",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Local control plane for coordinating Claude Code, Codex, and other coding CLI sessions.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,8 +11,10 @@
11
11
  "bin/",
12
12
  "lib/",
13
13
  "scripts/",
14
+ "assets/",
14
15
  "README.md",
15
16
  "README.zh-CN.md",
17
+ "CHANGELOG.md",
16
18
  "LICENSE",
17
19
  "docs/"
18
20
  ],
@@ -20,6 +22,8 @@
20
22
  "node": ">=24.0.0"
21
23
  },
22
24
  "scripts": {
25
+ "release:notes": "node ./scripts/release-notes.mjs",
26
+ "release:check": "node ./scripts/release-notes.mjs --check",
23
27
  "smoke": "node ./bin/hcc.mjs --help",
24
28
  "test": "node ./scripts/regression.mjs",
25
29
  "test:regression": "node ./scripts/regression.mjs"
@@ -1124,7 +1124,17 @@ async function downGcPackWorkflow() {
1124
1124
  await stopRuntime();
1125
1125
  await waitFor(() => !fs.existsSync(path.join(root, '.hello-cc', 'runtime.json')), 'runtime cleanup', 5000);
1126
1126
  hcc(['gc', '--older-than', '0', '--yes']);
1127
- run('npm', ['pack', '--dry-run']);
1127
+ const pack = JSON.parse(run('npm', ['pack', '--dry-run', '--json']));
1128
+ const files = new Set(pack[0]?.files?.map((entry) => entry.path) || []);
1129
+ for (const file of ['assets/logo.svg', 'CHANGELOG.md', 'docs/commands.md', 'docs/commands.zh-CN.md']) {
1130
+ if (!files.has(file)) fail(`npm package missing ${file}`);
1131
+ }
1132
+ const releaseCheck = run('npm', ['run', 'release:check']);
1133
+ if (!releaseCheck.includes('release notes ok: 0.1.2')) fail(`release check output wrong:\n${releaseCheck}`);
1134
+ const releaseNotes = run('npm', ['run', 'release:notes']);
1135
+ if (!releaseNotes.includes('## 0.1.2') || !releaseNotes.includes('### Summary')) {
1136
+ fail(`release notes output wrong:\n${releaseNotes}`);
1137
+ }
1128
1138
  }
1129
1139
 
1130
1140
  function oldNameScan() {
@@ -1157,12 +1167,51 @@ function syntaxAndHelp() {
1157
1167
  run(process.execPath, ['--check', path.join(repoRoot, 'lib', 'setup.mjs')]);
1158
1168
  run(process.execPath, ['--check', path.join(repoRoot, 'lib', 'discover.mjs')]);
1159
1169
  const mainHelp = run(process.execPath, [hccBin, '--help']);
1160
- if (mainHelp.includes('setup') || mainHelp.includes('uninstall') || mainHelp.includes('--web-managed')) {
1170
+ if (mainHelp.includes('setup') || mainHelp.includes('--web-managed')) {
1161
1171
  fail(`public help exposes maintenance or removed commands:\n${mainHelp}`);
1162
1172
  }
1173
+ if (!mainHelp.includes(' update Update the global npm install of hello-cc')) {
1174
+ fail(`main help missing update command:\n${mainHelp}`);
1175
+ }
1176
+ if (!mainHelp.includes(' uninstall Remove hooks, shims, and optional project data')) {
1177
+ fail(`main help missing uninstall command:\n${mainHelp}`);
1178
+ }
1179
+ const updateHelp = run(process.execPath, [hccBin, 'update', '--help']);
1180
+ if (!updateHelp.includes('hcc update') || !updateHelp.includes('npm install -g @logicseek/hello-cc@TAG')) {
1181
+ fail(`update help missing expected content:\n${updateHelp}`);
1182
+ }
1183
+ const uninstallHelp = run(process.execPath, [hccBin, 'uninstall', '--help']);
1184
+ if (!uninstallHelp.includes('hcc uninstall') || !uninstallHelp.includes('hcc uninstall [--purge --yes]')) {
1185
+ fail(`uninstall help missing expected content:\n${uninstallHelp}`);
1186
+ }
1187
+ const updateDryRun = run(process.execPath, [hccBin, 'update', '--dry-run']);
1188
+ if (!updateDryRun.includes('would run: npm install -g @logicseek/hello-cc@latest')) {
1189
+ fail(`update dry-run output wrong:\n${updateDryRun}`);
1190
+ }
1191
+ const updateJson = JSON.parse(run(process.execPath, [hccBin, '--json', 'update', '--dry-run', '--tag', '0.1.2']));
1192
+ if (!updateJson.ok || updateJson.data.command !== 'npm install -g @logicseek/hello-cc@0.1.2') {
1193
+ fail(`update json dry-run output wrong:\n${JSON.stringify(updateJson)}`);
1194
+ }
1195
+ const updateBuildJson = JSON.parse(run(process.execPath, [hccBin, '--json', 'update', '--dry-run', '--tag', '1.2.3+build.1']));
1196
+ if (!updateBuildJson.ok || updateBuildJson.data.command !== 'npm install -g @logicseek/hello-cc@1.2.3+build.1') {
1197
+ fail(`update build-metadata dry-run output wrong:\n${JSON.stringify(updateBuildJson)}`);
1198
+ }
1163
1199
  const runHelp = run(process.execPath, [hccBin, 'run', '--help']);
1164
1200
  if (runHelp.includes('--web-managed')) fail(`run help exposes removed --web-managed:\n${runHelp}`);
1165
- if (!run(process.execPath, [hccBin, 'peer', '--help']).includes('peer attach')) fail('peer attach missing from help');
1201
+ const subcommandHelpCases = [
1202
+ ['task', 'done', 'hcc task done'],
1203
+ ['msg', 'ack', 'hcc msg ack'],
1204
+ ['peer', 'attach', 'peer attach'],
1205
+ ['lock', 'release', 'hcc lock release'],
1206
+ ['handoff', 'create', 'hcc handoff create'],
1207
+ ['event', 'tail', 'hcc event tail']
1208
+ ];
1209
+ for (const [group, subcommand, expected] of subcommandHelpCases) {
1210
+ const help = run(process.execPath, [hccBin, group, subcommand, '--help']);
1211
+ if (!help.includes(expected)) {
1212
+ fail(`${group} ${subcommand} help missing expected content:\n${help}`);
1213
+ }
1214
+ }
1166
1215
  const removed = runMaybe(process.execPath, [hccBin, '--root', root, 'run', '--peer', 'bad', '--kind', 'shell', '--web-managed', '--', 'bash']);
1167
1216
  if (removed.status === 0 || !String(removed.stderr || removed.stdout).includes('unknown option --web-managed')) {
1168
1217
  fail(`run --web-managed was not rejected:\n${removed.stdout}\n${removed.stderr}`);
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import process from 'node:process';
6
+
7
+ const repoRoot = path.resolve(import.meta.dirname, '..');
8
+
9
+ function usage() {
10
+ console.log(`release-notes
11
+
12
+ Usage:
13
+ node scripts/release-notes.mjs [--version VERSION] [--check]
14
+
15
+ Reads CHANGELOG.md and prints the section for VERSION. If VERSION is omitted,
16
+ the current package.json version is used.
17
+
18
+ Keep one top-level CHANGELOG.md file. For each release, add a new section:
19
+
20
+ ## 0.1.3
21
+
22
+ The printed section is the source for GitHub Release notes and detailed npm
23
+ package release descriptions.
24
+ `);
25
+ }
26
+
27
+ function readJson(file) {
28
+ return JSON.parse(fs.readFileSync(file, 'utf8'));
29
+ }
30
+
31
+ function parseArgs(argv) {
32
+ const opts = { check: false, help: false, version: null };
33
+ for (let i = 0; i < argv.length; i += 1) {
34
+ const arg = argv[i];
35
+ if (arg === '--help' || arg === '-h') {
36
+ opts.help = true;
37
+ } else if (arg === '--check') {
38
+ opts.check = true;
39
+ } else if (arg === '--version') {
40
+ opts.version = argv[++i];
41
+ if (opts.version === undefined) throw new Error('Missing value for --version');
42
+ } else if (arg.startsWith('--version=')) {
43
+ opts.version = arg.slice('--version='.length);
44
+ } else {
45
+ throw new Error(`Unknown argument: ${arg}`);
46
+ }
47
+ }
48
+ return opts;
49
+ }
50
+
51
+ function releaseSection(markdown, version) {
52
+ const lines = markdown.split(/\r?\n/);
53
+ const heading = `## ${version}`;
54
+ const start = lines.findIndex((line) => line.trim() === heading);
55
+ if (start < 0) return null;
56
+
57
+ let end = lines.length;
58
+ for (let i = start + 1; i < lines.length; i += 1) {
59
+ if (/^##\s+/.test(lines[i])) {
60
+ end = i;
61
+ break;
62
+ }
63
+ }
64
+ return lines.slice(start, end).join('\n').trimEnd();
65
+ }
66
+
67
+ function validateSection(section, version) {
68
+ const problems = [];
69
+ if (!section) {
70
+ problems.push(`CHANGELOG.md is missing section ## ${version}`);
71
+ return problems;
72
+ }
73
+ if (!section.includes('### Summary')) problems.push(`## ${version} is missing ### Summary`);
74
+ if (!section.includes('### Highlights')) problems.push(`## ${version} is missing ### Highlights`);
75
+ if (section.includes('TODO') || section.includes('TBD')) problems.push(`## ${version} still contains TODO/TBD text`);
76
+ const bulletCount = (section.match(/^- /gm) || []).length;
77
+ if (bulletCount < 2) problems.push(`## ${version} should include at least two release-note bullets`);
78
+ return problems;
79
+ }
80
+
81
+ function main() {
82
+ const opts = parseArgs(process.argv.slice(2));
83
+ if (opts.help) {
84
+ usage();
85
+ return;
86
+ }
87
+
88
+ const pkg = readJson(path.join(repoRoot, 'package.json'));
89
+ const version = opts.version || pkg.version;
90
+ const changelog = fs.readFileSync(path.join(repoRoot, 'CHANGELOG.md'), 'utf8');
91
+ const section = releaseSection(changelog, version);
92
+ const problems = validateSection(section, version);
93
+
94
+ if (opts.check) {
95
+ if (problems.length) {
96
+ console.error(problems.join('\n'));
97
+ process.exitCode = 1;
98
+ return;
99
+ }
100
+ console.log(`release notes ok: ${version}`);
101
+ return;
102
+ }
103
+
104
+ if (problems.length) {
105
+ console.error(problems.join('\n'));
106
+ process.exitCode = 1;
107
+ return;
108
+ }
109
+ console.log(section);
110
+ }
111
+
112
+ main();