cohorte 1.2.3 → 1.2.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/CHANGELOG.md CHANGED
@@ -3,6 +3,23 @@
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.4 — 2026-07-29
7
+
8
+ > **If you installed with `npx cohorte`, this is the release that makes 1.2.3 actually
9
+ > reach you.** Re-run `npx cohorte@latest update --global` (or `update` for a bundled core).
10
+
11
+ - **`npx cohorte install/update` shipped a core missing two scripts.** `bin/cli.js` — the
12
+ port of `install.sh` that `npx` actually runs — copied only `scripts/*.template`, never
13
+ `kanban-move.sh` or `telemetry-send.sh`. Since every caller chains them with `|| true`,
14
+ the result was silent on every npx-installed machine: no kanban card moves, no telemetry
15
+ pings, no error anywhere. The shell installers named both files explicitly and this port
16
+ drifted from them. It now copies by a rule that needs no list to keep in sync.
17
+ - The same port never copied `CHANGELOG.md` into the core either, so `/doctor` and
18
+ `/update-pipeline`'s "What's new" had nothing to read on npx installs. Fixed.
19
+ - CI now dry-runs `bin/cli.js` into a scratch dir and asserts the same postconditions as
20
+ the `install.sh` dry-run. 1.2.3's guard only grepped the two shell installers — it would
21
+ have passed this bug, because the port copies by rule rather than by name.
22
+
6
23
  ## 1.2.3 — 2026-07-29
7
24
 
8
25
  - **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 */ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cohorte",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
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") };