cohorte 1.2.3 → 1.2.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/CHANGELOG.md CHANGED
@@ -3,6 +3,32 @@
3
3
  Entries are shown by `/update-pipeline` ("What's new") after a core refresh. Keep them short,
4
4
  user-facing, most recent first. One `## <version> — <YYYY-MM-DD>` section per release.
5
5
 
6
+ ## 1.2.5 — 2026-07-29
7
+
8
+ - **`.claude/pipeline.json`'s `core_version` never updated on global installs.** The installer
9
+ bumps it in bundled mode, but a global core is shared — it cannot know which repos point at
10
+ it, so nothing bumped the field and it drifted forever. Repos running a current core were
11
+ still claiming `1.0.0`. `/update-pipeline` now syncs the pointer in both modes.
12
+ - `/doctor` no longer reports that drift as a broken install: a global-mode pointer lagging the
13
+ VERSION file is ⚠️ with the one-command fix, not ❌. The core was never the problem.
14
+
15
+ ## 1.2.4 — 2026-07-29
16
+
17
+ > **If you installed with `npx cohorte`, this is the release that makes 1.2.3 actually
18
+ > reach you.** Re-run `npx cohorte@latest update --global` (or `update` for a bundled core).
19
+
20
+ - **`npx cohorte install/update` shipped a core missing two scripts.** `bin/cli.js` — the
21
+ port of `install.sh` that `npx` actually runs — copied only `scripts/*.template`, never
22
+ `kanban-move.sh` or `telemetry-send.sh`. Since every caller chains them with `|| true`,
23
+ the result was silent on every npx-installed machine: no kanban card moves, no telemetry
24
+ pings, no error anywhere. The shell installers named both files explicitly and this port
25
+ drifted from them. It now copies by a rule that needs no list to keep in sync.
26
+ - The same port never copied `CHANGELOG.md` into the core either, so `/doctor` and
27
+ `/update-pipeline`'s "What's new" had nothing to read on npx installs. Fixed.
28
+ - CI now dry-runs `bin/cli.js` into a scratch dir and asserts the same postconditions as
29
+ the `install.sh` dry-run. 1.2.3's guard only grepped the two shell installers — it would
30
+ have passed this bug, because the port copies by rule rather than by name.
31
+
6
32
  ## 1.2.3 — 2026-07-29
7
33
 
8
34
  - **Telemetry now covers the whole funnel.** Only `/build` was actually pinging; `/smoke`,
package/bin/cli.js CHANGED
@@ -102,13 +102,31 @@ function copyCore() {
102
102
  for (const f of ['PIPELINE.template.md', 'SCHEMA.md', 'cohorte.config.template.yaml']) {
103
103
  fs.copyFileSync(path.join(src, 'profile', f), path.join(pipelineDir, f));
104
104
  }
105
- for (const f of fs.readdirSync(path.join(src, 'scripts'))) {
106
- if (f.endsWith('.template')) {
107
- fs.copyFileSync(path.join(src, 'scripts', f), path.join(pipelineDir, 'scripts', f));
105
+ // Copy the *.template files AND the shipped executables (kanban-move.sh,
106
+ // telemetry-send.sh). Until 1.2.4 this loop took only `.template`, so every
107
+ // `npx cohorte install/update` produced a core missing both scripts — and since
108
+ // every caller chains them with `|| true`, the result was silent: no kanban card
109
+ // moves, no telemetry pings, no error. The shell installers named them explicitly
110
+ // and this port drifted. The rule below needs no list to keep in sync: a `<x>.sh`
111
+ // with an `<x>.sh.template` sibling is rendered per-project by /init-pipeline, so
112
+ // only the template ships; every other `.sh` is a shipped executable.
113
+ const scriptFiles = fs.readdirSync(path.join(src, 'scripts'));
114
+ for (const f of scriptFiles) {
115
+ const isTemplate = f.endsWith('.template');
116
+ const isShipped = f.endsWith('.sh') && !scriptFiles.includes(`${f}.template`);
117
+ if (!isTemplate && !isShipped) continue;
118
+ const target = path.join(pipelineDir, 'scripts', f);
119
+ fs.copyFileSync(path.join(src, 'scripts', f), target);
120
+ if (isShipped && process.platform !== 'win32') {
121
+ try { fs.chmodSync(target, 0o755); } catch { /* optional */ }
108
122
  }
109
123
  }
110
124
  fs.copyFileSync(path.join(src, 'core', 'agents', 'implementer.template.md'),
111
125
  path.join(pipelineDir, 'implementer.template.md'));
126
+ // /doctor reads this to tell the human what they're missing; the shell installers
127
+ // have always copied it, this port never did.
128
+ const changelog = path.join(src, 'CHANGELOG.md');
129
+ if (fs.existsSync(changelog)) fs.copyFileSync(changelog, path.join(pipelineDir, 'CHANGELOG.md'));
112
130
  fs.writeFileSync(path.join(pipelineDir, 'VERSION'), VERSION + '\n');
113
131
  if (process.platform !== 'win32') {
114
132
  try { fs.chmodSync(path.join(dest, 'hooks', 'gate.py'), 0o755); } catch { /* optional */ }
@@ -14,8 +14,10 @@ fix only with the human's go-ahead (or hand them the command).
14
14
 
15
15
  1. **Core & pointer.** A core exists (`~/.claude/pipeline/VERSION` global, and/or
16
16
  `.claude/pipeline/VERSION` bundled); `.claude/pipeline.json` names a mode + `core_version`
17
- coherent with the VERSION file. Compare against `npm view cohorte version` behind
18
- suggest `/update-pipeline`. Read `pipeline/CHANGELOG.md` for what they're missing. The router
17
+ coherent with the VERSION file. A **global**-mode pointer lagging the VERSION file is ⚠️, not ❌:
18
+ nothing bumped that field before 1.2.5, so the core itself is fine and only the pointer is stale
19
+ ⇒ fix by running `/update-pipeline` (§3 syncs it now), or by editing the one field. Compare
20
+ against `npm view cohorte version` — behind ⇒ suggest `/update-pipeline`. Read `pipeline/CHANGELOG.md` for what they're missing. The router
19
21
  commands' step files are present — `templates/steps/init-pipeline/` non-empty (a router whose
20
22
  `templates/steps/<cmd>/` dir is missing is a partial/stale install ⇒
21
23
  re-run install/update). **Shipped scripts present and executable** in `<core>/pipeline/scripts/`:
@@ -51,7 +51,14 @@ the human's choices — so `/init-pipeline` never needs re-running for an upgrad
51
51
  ## 3. Report old → new
52
52
 
53
53
  Re-read the VERSION file(s) and print `old → new`. If unchanged, say the core was already up to date.
54
- For a bundled repo, note that `.claude/pipeline.json`'s `core_version` was bumped and should be committed.
54
+
55
+ **Sync the pointer — in BOTH modes.** If this repo has a `.claude/pipeline.json` whose `core_version`
56
+ differs from the core you just installed, rewrite that one field (leave every other field untouched)
57
+ and tell the human to commit it. In **bundled** mode the installer already did it; in **global** mode
58
+ **nothing does** — the installer refreshes one shared core and cannot know which repos point at it,
59
+ so before 1.2.5 the field simply drifted forever (a repo on a current core still claiming `1.0.0`).
60
+ `/doctor` check 1 requires the pointer to be coherent with the VERSION file, so a drifted field reads
61
+ as a broken install when nothing is broken.
55
62
 
56
63
  Then print **What's new**: read the installed `<core>/pipeline/CHANGELOG.md` and show the entries
57
64
  between the old and new versions (most recent first). File absent ⇒ the old core predates 0.1.14 —
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cohorte",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "description": "Portable, stack-agnostic multi-agent development pipeline for Claude Code — install the core, run /init-pipeline, and it adapts to your project's stack.",
5
5
  "bin": {
6
6
  "cohorte": "bin/cli.js"
@@ -130,9 +130,13 @@ for (const f of readdirSync(join(root, "core/commands"))) {
130
130
  }
131
131
 
132
132
  // ── shipped scripts ─────────────────────────────────────────────────────────
133
- // Every scripts/*.sh must be copied by BOTH installers. Callers chain these with
134
- // `|| true`, so one the installer forgets is a silent no-op forever — no kanban
133
+ // Every scripts/*.sh must be copied by BOTH shell installers. Callers chain these
134
+ // with `|| true`, so one an installer forgets is a silent no-op forever — no kanban
135
135
  // card moves, no telemetry ping, no error. CI is the only place this is loud.
136
+ // The third installer, bin/cli.js (what `npx cohorte` runs), copies by rule rather
137
+ // than by name, so grepping for filenames can't see it — ci.yml dry-runs it into a
138
+ // scratch HOME and asserts the same postconditions instead. Both are needed: this
139
+ // check catches a forgotten name, that one catches a drifted rule.
136
140
  // A `<name>.sh` with a `<name>.sh.template` sibling is a locally-rendered artifact
137
141
  // (this repo dogfoods its own /init-pipeline), not a core asset — skip those.
138
142
  const installers = { "install.sh": read("install.sh"), "install.ps1": read("install.ps1") };