@sabaiway/agent-workflow-kit 1.7.0 → 1.8.0

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
@@ -4,6 +4,36 @@ Semantically versioned ([semver](https://semver.org)), newest first. The `versio
4
4
  is the current release. `upgrade` mode reads a project's `docs/ai/.workflow-version` and applies
5
5
  every `migrations/<version>-<slug>.md` newer than it, in semver order.
6
6
 
7
+ ## 1.8.0 — Stale-version DX: `@latest` everywhere + a no-network never-downgrade gate
8
+
9
+ A returning user ran the headline `npx @sabaiway/agent-workflow-kit init` and it quietly did nothing:
10
+ a bare `npx <pkg> init` (no `@latest`) reuses the npx cache and re-runs an **older cached build** of
11
+ the installer, which exits 0 and reports it "updated" — to the same stale version. This release makes
12
+ that mistake hard to miss while **the installer itself stays 100% network-free** — the only thing
13
+ that ever contacts npm is npx resolving `@latest`, exactly as it already does (the no-phone-home
14
+ principle is preserved; see AD-012):
15
+
16
+ - **`@latest` is the documented default everywhere.** Every prescribing surface (both READMEs, the
17
+ bridge `SKILL.md` files + their bundled mirrors, the installer `--help` / header) now shows
18
+ `npx @sabaiway/agent-workflow-kit@latest init`. A new drift guard
19
+ (`test/init-command-uses-latest.test.mjs`) fails the build if a bare form sneaks back in (historical
20
+ contexts — CHANGELOG / `releases/` / `migrations/` — are exempt).
21
+ - **Never-downgrade gate (no network).** `init` reads the installed skill's version from
22
+ `SKILL.md` **before** writing; if the installed kit is **newer** than the version you ran (the exact
23
+ stale-cache signature), it **refuses** (nonzero) and points at `@latest`, rather than silently
24
+ overwriting a newer install with old code. `--force` overrides. A legacy install with no version
25
+ stamp still upgrades cleanly.
26
+ - **No-op re-run hint.** When `init` refreshes the skill with the *same* version it already had, it
27
+ says so and points at `@latest` — the no-network signal that catches the reported scenario.
28
+ - **In-agent skill** (`SKILL.md`): surfaces a one-line version status (project `docs/ai/.workflow-version`
29
+ vs the lineage head) + routes (bootstrap / upgrade / current), spells out the **two independent
30
+ version axes** (project deployment vs kit freshness — the latter is the npx installer's job, never
31
+ this skill's), and tells you to **restart the session** after refreshing the kit so the new skill
32
+ files load.
33
+
34
+ New users are unaffected (an empty npx cache already fetches `latest`); this targets the returning-user
35
+ trap. No `docs/ai` structural change → the deployment-lineage head stays **`1.3.0`**; no migration.
36
+
7
37
  ## 1.7.0 — Link-only backend auto-setup; bridges bundled in the tarball
8
38
 
9
39
  The optional execution-backend bridges (`codex-cli-bridge` → `codex`, `antigravity-cli-bridge` →
package/README.md CHANGED
@@ -18,7 +18,7 @@ decisions. Works with Claude Code, Codex, Cursor, and any agent that reads `AGEN
18
18
  **One command to start:**
19
19
 
20
20
  ```bash
21
- npx @sabaiway/agent-workflow-kit init
21
+ npx @sabaiway/agent-workflow-kit@latest init
22
22
  ```
23
23
 
24
24
  <sub>This installs the **global skill** — deploying into a project is a separate step ([below](#-install)).</sub>
@@ -134,7 +134,7 @@ Hidden changes how the files are *tracked*, not where agents find them.
134
134
  ### 1. Install the global skill — once per machine
135
135
 
136
136
  ```bash
137
- npx @sabaiway/agent-workflow-kit init
137
+ npx @sabaiway/agent-workflow-kit@latest init
138
138
  ```
139
139
 
140
140
  `init` installs/refreshes the skill at `~/.claude/skills/agent-workflow-kit/` and wires launchers for
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: agent-workflow-kit
3
3
  description: Deploy or upgrade a portable AI-agent memory-and-workflow system in any project. Use when the user wants to bootstrap `docs/ai/` + an entry-point `AGENTS.md` (+ `CLAUDE.md` alias) + cap/archive/index enforcement in a new or existing repo, set up the Memory Map and session protocols, install the docs-rotation pre-commit hook, or run `/agent-workflow-kit` / `/agent-workflow-kit upgrade`. Triggers on phrases like "set up the memory system", "deploy the AI workflow here", "bootstrap docs/ai", "upgrade the workflow".
4
4
  disable-model-invocation: true
5
5
  metadata:
6
- version: '1.7.0'
6
+ version: '1.8.0'
7
7
  ---
8
8
 
9
9
  # agent-workflow-kit
@@ -85,6 +85,22 @@ Pick the mode from the user's invocation. Auto-detect an existing `docs/ai/` to
85
85
  - **`/agent-workflow-kit backends`** — read-only environment check: which optional **execution-backends** (the `codex` / `agy` bridges) are set up vs missing. Never writes, never commits, never runs a subscription CLI.
86
86
  - **`/agent-workflow-kit setup [backend]`** — the **link-only**, opt-in companion to `backends`: place the bundled bridge skill + link its wrappers onto `PATH`. **In-agent only** — `init` (npx) never places bridges. The binary install + the interactive subscription login stay **manual** (it prints the exact commands); idempotent; refuses to clobber a non-symlink; never commits, never runs a subscription CLI.
87
87
 
88
+ ### Version status & the two axes — surface this on every invocation
89
+
90
+ Before acting, read `docs/ai/.workflow-version` (the project's stamp), state a one-line status, then route:
91
+
92
+ - **absent** → bootstrap (a fresh deployment).
93
+ - **stamp < `1.3.0`** (the deployment-lineage head) → `upgrade`.
94
+ - **stamp == `1.3.0`** → already current; only the stamp-independent methodology-slot reconcile may run.
95
+ - **stamp > head / unparseable** → STOP — never-downgrade gate (see *Mode: upgrade* step 2).
96
+
97
+ **Two independent version axes — never conflate them:**
98
+
99
+ 1. **Project deployment** — `docs/ai/.workflow-version` vs the lineage head (`1.3.0`). This is the **only** axis this skill compares.
100
+ 2. **Kit freshness** — this skill's own files vs the published npm package. That is the **npx installer's** job: `npx @sabaiway/agent-workflow-kit@latest init` (it refuses a stale-cache downgrade by comparing the version on disk — **no network**). This skill never checks npm, and the package version (e.g. `1.x`) is **not** the lineage head.
101
+
102
+ **Refreshed the kit but nothing changed?** The skill you are running is whatever was on disk when the session started. After `npx @sabaiway/agent-workflow-kit@latest init` updates `~/.claude/skills/agent-workflow-kit/`, **restart the session** so the agent reloads the new skill files (the slash command + this `SKILL.md`).
103
+
88
104
  ### Mode: bootstrap
89
105
 
90
106
  > Bundled sources below (templates, scripts) live in **this skill's own directory** — `${CLAUDE_SKILL_DIR}/` in Claude Code, or the folder containing this `SKILL.md` in Codex / other agents. Use that as the copy/read source; the working directory is the **target project**, not the skill.
package/bin/install.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // One-shot installer for @sabaiway/agent-workflow-kit.
3
3
  //
4
- // npx @sabaiway/agent-workflow-kit init
4
+ // npx @sabaiway/agent-workflow-kit@latest init
5
5
  //
6
6
  // Copies the kit into the canonical skill home (~/.claude/skills/agent-workflow-kit),
7
7
  // then runs the cross-agent launcher (auto-detects Codex / Devin Desktop — only touches tools
@@ -14,7 +14,11 @@
14
14
  // docs/ai deployment — see README "Use".
15
15
  //
16
16
  // No telemetry, no phone-home: adoption is the npm registry's public, passive per-version
17
- // download numbers (api.npmjs.org/downloads). Nothing here contacts a server.
17
+ // download numbers (api.npmjs.org/downloads). Nothing here contacts a server — including the
18
+ // stale-version defenses below, which compare the version already on disk (the installed SKILL.md)
19
+ // against this runner's own version, never the registry. That is why `@latest` (above) is the
20
+ // documented form: a bare `npx … init` can reuse an OLDER cached build of this installer, so a
21
+ // returning user must bypass the cache to actually upgrade. See decisions.md AD-012.
18
22
  //
19
23
  // Dependency-free, Node >= 18.
20
24
 
@@ -57,6 +61,58 @@ const readVersion = async () => {
57
61
  }
58
62
  };
59
63
 
64
+ // Dependency-free semver: parse the leading `x.y.z` (prerelease/build ignored — kit versions are
65
+ // plain). compareSemver returns -1 | 0 | 1, or null when either side is unparseable (legacy installs
66
+ // predate any version stamp). No `let`: a small functional comparison (AGENTS.md §2.3).
67
+ const parseSemver = (str) => {
68
+ const m = typeof str === 'string' ? str.trim().match(/^(\d+)\.(\d+)\.(\d+)/) : null;
69
+ return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;
70
+ };
71
+
72
+ const compareSemver = (a, b) => {
73
+ const pa = parseSemver(a);
74
+ const pb = parseSemver(b);
75
+ if (!pa || !pb) return null;
76
+ const firstDiff = [0, 1, 2].map((i) => (pa[i] === pb[i] ? 0 : pa[i] < pb[i] ? -1 : 1)).find((c) => c !== 0);
77
+ return firstDiff ?? 0;
78
+ };
79
+
80
+ // Extract the version that is a DIRECT child of the top-level `metadata:` key — never a top-level
81
+ // or deeper-nested decoy `version:` (mirrors the manifest validator's rigor; the kit ships manifest
82
+ // fixtures that probe exactly those decoys). Pure string walk over the frontmatter block, no deps.
83
+ const metadataVersion = (frontmatter) => {
84
+ const lines = frontmatter.split(/\r?\n/);
85
+ const metaIdx = lines.findIndex((l) => /^metadata:[ \t]*$/.test(l));
86
+ if (metaIdx === -1) return null;
87
+ const after = lines.slice(metaIdx + 1);
88
+ const dedent = after.findIndex((l) => /^[^ \t]/.test(l)); // a column-0 line closes the metadata block
89
+ const block = dedent === -1 ? after : after.slice(0, dedent);
90
+ // Direct children share the first child's indent; a nested decoy is MORE indented, so a
91
+ // `<baseIndent>version:` prefix match excludes it. baseIndent is non-empty, so a top-level
92
+ // `version:` (column 0, and before `metadata:` anyway) is excluded too.
93
+ const baseIndent = block.length ? (block[0].match(/^[ \t]*/)?.[0] ?? '') : '';
94
+ const verLine = block.find((l) => l.startsWith(`${baseIndent}version:`));
95
+ return verLine?.match(/version:[ \t]*['"]?(\d+\.\d+\.\d+)['"]?/)?.[1] ?? null;
96
+ };
97
+
98
+ // The installed version is read from the target's SKILL.md frontmatter (`metadata.version`) — the
99
+ // manifest's canonical `detect.installed.file`, present even on legacy installs that predate
100
+ // capability.json. Returns the semver string, or null when ABSENT / has no parseable stamp (legacy
101
+ // → no gate). A SKILL.md that EXISTS but cannot be read is NOT swallowed as "legacy": we fail closed
102
+ // (throw) so the never-downgrade gate can never be silently bypassed (AGENTS.md: no silent failures).
103
+ const readInstalledVersion = async (target) => {
104
+ const skill = resolve(target, 'SKILL.md');
105
+ if (!existsSync(skill)) return null; // absent → new/legacy install, nothing to compare
106
+ const text = await readFile(skill, 'utf8').catch((err) => {
107
+ throw new Error(
108
+ `[agent-workflow-kit] cannot read the installed SKILL.md (${tildify(skill)}): ${err.message}. ` +
109
+ `Refusing to install over an unreadable kit — fix permissions/contents or remove it, then re-run.`,
110
+ );
111
+ });
112
+ const fm = text.match(/^---\r?\n([\s\S]*?)\r?\n---/);
113
+ return fm ? metadataVersion(fm[1]) : null;
114
+ };
115
+
60
116
  // lstat without following symlinks; null when absent. existsSync FOLLOWS symlinks (so a
61
117
  // *dangling* symlink reads as absent) — lstat is what lets the guard catch a dangling dest symlink.
62
118
  const lstatNoFollow = (path) => {
@@ -80,6 +136,7 @@ const parseArgs = (argv) => {
80
136
  version: argv.includes('--version') || argv.includes('-v'),
81
137
  noLaunchers: argv.includes('--no-launchers'),
82
138
  force: argv.includes('--force'),
139
+ allowDowngrade: argv.includes('--allow-downgrade'),
83
140
  dir: dirFlag >= 0 ? argv[dirFlag + 1] : undefined,
84
141
  };
85
142
  };
@@ -94,15 +151,20 @@ const printHelp = (version) => {
94
151
  console.log(`agent-workflow-kit ${version}
95
152
 
96
153
  Usage:
97
- npx @sabaiway/agent-workflow-kit init [--dir <path>] [--no-launchers] [--force]
98
- npx @sabaiway/agent-workflow-kit --version
99
- npx @sabaiway/agent-workflow-kit --help
154
+ npx @sabaiway/agent-workflow-kit@latest init [--dir <path>] [--no-launchers] [--force] [--allow-downgrade]
155
+ npx @sabaiway/agent-workflow-kit@latest --version
156
+ npx @sabaiway/agent-workflow-kit@latest --help
157
+
158
+ Use the @latest form: a bare \`npx … init\` (no @latest) can reuse an OLDER cached
159
+ build of this installer, so a returning user must bypass the npx cache to upgrade.
100
160
 
101
161
  Installs/refreshes the kit at ~/.claude/skills/agent-workflow-kit
102
162
  (override with --dir <path> or AGENT_WORKFLOW_KIT_DIR), then wires any
103
163
  Codex / Devin Desktop you have. --no-launchers skips that wiring; --force replaces a
104
164
  pre-existing non-kit launcher file (backed up first). init is additive — it never
105
- deletes your settings.
165
+ deletes your settings. If the installed kit is newer than the version you ran, init
166
+ refuses (no network — it compares the version on disk) and points you at @latest;
167
+ --allow-downgrade overrides that refusal (distinct from --force, which is launcher-only).
106
168
 
107
169
  After install, invoke the skill in your agent, inside a project:
108
170
  first time in the project -> /agent-workflow-kit
@@ -143,12 +205,46 @@ const main = async () => {
143
205
  console.error(`[agent-workflow-kit] target dir is a symlink — refusing to write through it: ${tildify(target)}`);
144
206
  process.exit(1);
145
207
  }
208
+
209
+ // Stale-cache defenses (no network — version already on disk vs this runner). Read BEFORE any
210
+ // write so a refusal touches nothing. cmp is null on a legacy/unparseable install → no gate.
211
+ const installedVersion = wasPresent ? await readInstalledVersion(target) : null;
212
+ const cmp = installedVersion ? compareSemver(installedVersion, version) : null;
213
+
214
+ // Never-downgrade gate: a bare `npx … init` can run an OLDER cached build of this installer, which
215
+ // would overwrite a NEWER installed skill with old code. Refuse loudly (nonzero) unless the
216
+ // dedicated --allow-downgrade override is passed — surfacing the cache trap instead of silently
217
+ // regressing the install (AGENTS.md: no silent failures). The override is its OWN flag, NOT --force:
218
+ // --force means "replace a foreign launcher file" and is forwarded to the launcher; conflating them
219
+ // would let someone clearing the version gate also clobber launchers by accident.
220
+ if (cmp === 1 && !args.allowDowngrade) {
221
+ console.error(
222
+ `[agent-workflow-kit] refusing to downgrade: the installed kit is v${installedVersion}, but this ` +
223
+ `runner is the OLDER v${version}.\n` +
224
+ ` This is the classic npx cache serving a stale build. To get the newest kit, bypass the cache:\n` +
225
+ ` npx @sabaiway/agent-workflow-kit@latest init\n` +
226
+ ` (or pass --allow-downgrade to overwrite the newer install with v${version} anyway).`,
227
+ );
228
+ process.exit(1);
229
+ }
230
+
146
231
  await mkdir(target, { recursive: true });
147
232
  for (const entry of PAYLOAD.filter((e) => existsSync(resolve(PKG_ROOT, e)))) {
148
233
  copyTreeRefresh(resolve(PKG_ROOT, entry), resolve(target, entry), target);
149
234
  }
150
235
  console.log(`[agent-workflow-kit] ${wasPresent ? 'updated the kit to' : 'installed'} v${version} -> ${tildify(target)}`);
151
236
 
237
+ // No-op re-run: the install just refreshed the skill with the SAME version it already had. For a
238
+ // user who ran `init` expecting an upgrade, that almost always means npx reused a cached build —
239
+ // say so explicitly and point at @latest (the no-network signal that catches the reported scenario).
240
+ if (cmp === 0) {
241
+ console.log(
242
+ `[agent-workflow-kit] note: no version change — the kit was already v${version}. If you expected ` +
243
+ `an update, npx likely served a cached build; re-run bypassing the cache:\n` +
244
+ ` npx @sabaiway/agent-workflow-kit@latest init`,
245
+ );
246
+ }
247
+
152
248
  // Wire non-Claude agents — best-effort; the launcher only touches tools you have.
153
249
  const launcher = resolve(target, 'launchers/install-launchers.sh');
154
250
  if (args.noLaunchers) {
@@ -1,7 +1,7 @@
1
1
  import { describe, it, beforeEach, afterEach } from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { spawnSync } from 'node:child_process';
4
- import { mkdtemp, rm, mkdir, symlink, readdir } from 'node:fs/promises';
4
+ import { mkdtemp, rm, mkdir, symlink, readdir, readFile, writeFile } from 'node:fs/promises';
5
5
  import { existsSync } from 'node:fs';
6
6
  import { tmpdir } from 'node:os';
7
7
  import { dirname, join } from 'node:path';
@@ -9,9 +9,21 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
9
9
 
10
10
  const INSTALLER = join(dirname(fileURLToPath(import.meta.url)), 'install.mjs');
11
11
  const KIT_ROOT = dirname(dirname(INSTALLER));
12
- // --no-launchers so the test never wires Codex/Devin on the host.
13
- const runInstaller = (target) =>
14
- spawnSync(process.execPath, [INSTALLER, '--dir', target, '--no-launchers'], { encoding: 'utf8' });
12
+ // --no-launchers so the test never wires Codex/Devin on the host. `extra` appends flags (e.g. --force).
13
+ const runInstaller = (target, extra = []) =>
14
+ spawnSync(process.execPath, [INSTALLER, '--dir', target, '--no-launchers', ...extra], { encoding: 'utf8' });
15
+
16
+ // Rewrite / read the installed skill's frontmatter version — used to simulate "a newer kit is already
17
+ // installed" (the stale-cache downgrade scenario). The installer reads exactly this field.
18
+ const setInstalledVersion = async (target, v) => {
19
+ const p = join(target, 'SKILL.md');
20
+ const text = await readFile(p, 'utf8');
21
+ await writeFile(p, text.replace(/version:\s*['"]?\d+\.\d+\.\d+['"]?/, `version: '${v}'`));
22
+ };
23
+ const getInstalledVersion = async (target) =>
24
+ (await readFile(join(target, 'SKILL.md'), 'utf8')).match(/version:\s*['"]?(\d+\.\d+\.\d+)['"]?/)?.[1] ?? null;
25
+ const pkgVersion = async () =>
26
+ JSON.parse(await readFile(join(KIT_ROOT, 'package.json'), 'utf8')).version;
15
27
 
16
28
  describe('kit installer — payload + symlink-traversal hardening', () => {
17
29
  let dir;
@@ -82,6 +94,98 @@ describe('kit installer — module hygiene', () => {
82
94
  });
83
95
  });
84
96
 
97
+ describe('kit installer — stale-cache defenses (no network)', () => {
98
+ let dir;
99
+ beforeEach(async () => {
100
+ dir = await mkdtemp(join(tmpdir(), 'aw-kit-stale-'));
101
+ });
102
+ afterEach(async () => {
103
+ await rm(dir, { recursive: true, force: true });
104
+ });
105
+
106
+ it('a no-op re-run (same version) flags the likely npx cache and points at @latest', async () => {
107
+ const target = join(dir, 'agent-workflow-kit');
108
+ assert.equal(runInstaller(target).status, 0); // first install
109
+ const again = runInstaller(target); // second run: installed == running
110
+ assert.equal(again.status, 0, again.stderr);
111
+ assert.match(again.stdout, /no version change/i);
112
+ assert.match(again.stdout, /cache/i);
113
+ assert.match(again.stdout, /@latest/);
114
+ });
115
+
116
+ it('refuses to downgrade when the installed kit is NEWER, and writes nothing', async () => {
117
+ const target = join(dir, 'agent-workflow-kit');
118
+ assert.equal(runInstaller(target).status, 0);
119
+ await setInstalledVersion(target, '99.0.0'); // pretend a newer kit is already installed
120
+ const res = runInstaller(target); // running version < installed → downgrade
121
+ assert.notEqual(res.status, 0);
122
+ assert.match(res.stderr, /downgrade/i);
123
+ assert.match(res.stderr, /@latest/);
124
+ assert.equal(await getInstalledVersion(target), '99.0.0', 'newer install must be left untouched');
125
+ });
126
+
127
+ it('--allow-downgrade overrides the refusal and overwrites with the runner version', async () => {
128
+ const target = join(dir, 'agent-workflow-kit');
129
+ assert.equal(runInstaller(target).status, 0);
130
+ await setInstalledVersion(target, '99.0.0');
131
+ const res = runInstaller(target, ['--allow-downgrade']);
132
+ assert.equal(res.status, 0, res.stderr);
133
+ assert.equal(await getInstalledVersion(target), await pkgVersion());
134
+ });
135
+
136
+ it('--force alone does NOT override the downgrade gate (the override is its own flag)', async () => {
137
+ const target = join(dir, 'agent-workflow-kit');
138
+ assert.equal(runInstaller(target).status, 0);
139
+ await setInstalledVersion(target, '99.0.0');
140
+ const res = runInstaller(target, ['--force']); // launcher-clobber flag, not the gate override
141
+ assert.notEqual(res.status, 0, 'launcher --force must not silently clear the version gate');
142
+ assert.equal(await getInstalledVersion(target), '99.0.0', 'newer install must be left untouched');
143
+ });
144
+
145
+ it('reads the version under `metadata:`, never a top-level / nested decoy `version:`', async () => {
146
+ // A crafted SKILL.md whose REAL metadata.version (0.0.1) is OLDER than the runner, but with decoy
147
+ // `version:` lines that are NEWER. A naive "first version: in frontmatter" read would see 99.0.0
148
+ // and wrongly refuse; the correct read sees 0.0.1 → a normal upgrade (exit 0).
149
+ const target = join(dir, 'agent-workflow-kit');
150
+ await mkdir(target, { recursive: true });
151
+ const decoy = [
152
+ '---',
153
+ "version: '99.0.0'", // top-level decoy (column 0)
154
+ 'name: agent-workflow-kit',
155
+ 'metadata:',
156
+ ' nested:',
157
+ " version: '98.0.0'", // deeper-nested decoy
158
+ " version: '0.0.1'", // the authoritative direct child
159
+ '---',
160
+ '# decoy',
161
+ '',
162
+ ].join('\n');
163
+ await writeFile(join(target, 'SKILL.md'), decoy);
164
+ const res = runInstaller(target);
165
+ assert.equal(res.status, 0, `expected a normal upgrade (read 0.0.1), got: ${res.stderr}`);
166
+ assert.match(res.stdout, /updated the kit to/);
167
+ });
168
+
169
+ it('fails closed (does not silently treat as legacy) when an existing SKILL.md cannot be read', async () => {
170
+ // SKILL.md present but unreadable (a directory → EISDIR on read). The gate must NOT be bypassed:
171
+ // we refuse rather than overwrite a kit whose version we could not determine (no silent failure).
172
+ const target = join(dir, 'agent-workflow-kit');
173
+ await mkdir(join(target, 'SKILL.md'), { recursive: true });
174
+ const res = runInstaller(target);
175
+ assert.notEqual(res.status, 0);
176
+ assert.match(res.stderr, /cannot read the installed SKILL\.md/i);
177
+ });
178
+
179
+ it('a legacy install with no version stamp still upgrades (no false downgrade, no crash)', async () => {
180
+ const target = join(dir, 'agent-workflow-kit');
181
+ await mkdir(target, { recursive: true });
182
+ await writeFile(join(target, 'SKILL.md'), '---\nname: agent-workflow-kit\n---\n# legacy stub\n');
183
+ const res = runInstaller(target);
184
+ assert.equal(res.status, 0, res.stderr);
185
+ assert.match(res.stdout, /updated the kit to/);
186
+ });
187
+ });
188
+
85
189
  describe('kit installer — published tarball bundles the bridges', () => {
86
190
  it('npm pack ships bridges/<name>/ (the execution-backend skill mirrors)', () => {
87
191
  // The real `files` whitelist decides what publishes — assert against `npm pack`, not the source
@@ -150,9 +150,9 @@ checklist, prompt templates, output handling). Essentials:
150
150
  - **`agent-workflow-memory`** (family **context provider**) — if the current project has **no**
151
151
  `AGENTS.md` + `docs/ai/`, `agy` has no per-workspace context to read. The memory substrate creates
152
152
  it. Soft-recommend it (only when the user wants the memory workflow):
153
- `npx @sabaiway/agent-workflow-memory init`, then `/agent-workflow-memory` in the project — or
153
+ `npx @sabaiway/agent-workflow-memory@latest init`, then `/agent-workflow-memory` in the project — or
154
154
  bootstrap the whole family via the **`agent-workflow-kit`** orchestrator
155
- (`npx @sabaiway/agent-workflow-kit init`), which delegates substrate deployment to memory. Never a
155
+ (`npx @sabaiway/agent-workflow-kit@latest init`), which delegates substrate deployment to memory. Never a
156
156
  prerequisite for using `agy`.
157
157
  - **`codex-cli-bridge`** (sibling backend, OpenAI Codex) — recommend **by actual presence**: if
158
158
  `~/.claude/skills/codex-cli-bridge/` exists you have a **second delegated engine** (Codex for
@@ -129,8 +129,8 @@ The wrappers work in any git repo where `codex` is installed and authenticated.
129
129
  - **`agent-workflow-memory`** (family **context provider**) — if the target project has **no**
130
130
  `AGENTS.md` + `docs/ai/`, codex has no root context to read (and the wrappers' preflight will
131
131
  STOP). The memory substrate is what creates that context. Soft-recommend it (only when the user
132
- wants the memory workflow): `npx @sabaiway/agent-workflow-memory init`, or bootstrap the whole
133
- family via the **`agent-workflow-kit`** orchestrator (`npx @sabaiway/agent-workflow-kit init`),
132
+ wants the memory workflow): `npx @sabaiway/agent-workflow-memory@latest init`, or bootstrap the whole
133
+ family via the **`agent-workflow-kit`** orchestrator (`npx @sabaiway/agent-workflow-kit@latest init`),
134
134
  which delegates substrate deployment to memory and injects the workflow methodology. Never a
135
135
  prerequisite.
136
136
 
package/capability.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "schema": 1,
4
4
  "name": "agent-workflow-kit",
5
5
  "kind": "composition-root",
6
- "version": "1.7.0",
6
+ "version": "1.8.0",
7
7
  "provides": [],
8
8
  "roles": {},
9
9
  "detect": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sabaiway/agent-workflow-kit",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Portable, cross-agent memory & workflow for AI coding agents — Claude Code, Codex, Cursor, Devin Desktop. One command deploys an AGENTS.md entry point + docs/ai context with cap/archive/index enforcement into any repo.",
5
5
  "keywords": [
6
6
  "ai-agents",