@manhquy/flow-skill 0.1.0-rc.2 → 0.1.0-rc.3

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
@@ -2,7 +2,30 @@
2
2
 
3
3
  All notable changes to `@manhquy/flow-skill`. Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versioning: [SemVer](https://semver.org/).
4
4
 
5
- ## [0.1.0-rc.2] — 2026-07-17 (not yet published — see release command below)
5
+ ## [0.1.0-rc.3] — 2026-07-18
6
+
7
+ Ships the same skill product **v0.22.0** as rc.2, plus pipeline/UX fixes found after the first
8
+ OIDC publish + independent verification.
9
+
10
+ ### Fixed
11
+ - **Nightly registry health false-red:** `scripts/smoke.mjs` ran `npx` from inside
12
+ `npm-wrapper/`, so npx resolved the **local workspace package** instead of the registry
13
+ (`flow-skill: not found`) even when the published package was healthy. Smoke now uses an
14
+ empty temp cwd + `npx --package=… flow-skill`; nightly runs from `$RUNNER_TEMP`.
15
+ - **CI bash-suite Windows cancelled at 15m:** full 33-suite run needs ~20–25m on Windows Git
16
+ Bash (measured run `29630992330` — mid-`test_flow_eval` when cut). `timeout-minutes` is now
17
+ **30 on windows-latest**, 15 elsewhere. `tests/run_all.sh` prints per-suite `wall_s`.
18
+ - **`promote_to`:** early-exit before install/test (no full job burn); input description states
19
+ it is **manual-only** (OIDC cannot `npm dist-tag add` — E401 on run `29556075144`).
20
+
21
+ ### Added
22
+ - Dual-version UX: `--help` shows `flow-skill v<pkg> (ships skill v<skill>)`; JSONL `plan`
23
+ event gains additive `skillVersion`. Unit tests pin values from `package.json` + `SKILL.md`.
24
+
25
+ ### Changed
26
+ - `bin/cli.mjs` git mode `100755` (executable bit in tarball).
27
+
28
+ ## [0.1.0-rc.2] — 2026-07-17 — LIVE (published 2026-07-17, `latest` + `rc` both point here)
6
29
 
7
30
  Ships `skills/flow` v0.22.0 (concierge front-door + standalone native rituals — see the root
8
31
  repo's CHANGELOG.md `## 0.22.0` entry for the full skill-content changelog). This wrapper
@@ -68,10 +91,38 @@ two hardening items found while verifying it all.
68
91
  both `install.sh` and `install.ps1` carry the Antigravity restart/reload hint, and the old
69
92
  hardcoded Claude+Codex-only Done line is gone from both.
70
93
 
71
- ### Release command (operator-gated — not run by this change)
94
+ ### Fixed — CI publish guard (found on the actual first real run of this workflow)
95
+ - `publish-npm-wrapper.yml`'s `Guard — assert no NODE_AUTH_TOKEN present (OIDC only)` step
96
+ **hard-failed every run, including this release's first attempt** (run `29554226397`,
97
+ 2026-07-17). Root-caused via a temporary diagnostic step (added, run 3×, removed same
98
+ session): `NODE_AUTH_TOKEN` is unset right after `actions/checkout@v4` but becomes a real
99
+ short-lived OIDC-exchanged value the instant `actions/setup-node@v4` runs with
100
+ `registry-url` set — that's the current `actions/setup-node@v4` (a moving tag) doing its own
101
+ native npm OIDC handling, not a leaked static secret. The guard's 2026-07-12 design assumed
102
+ the older model where `npm publish` alone performed the OIDC exchange with nothing set
103
+ beforehand; it never matched real `actions/setup-node@v4` behavior and had a 0% pass rate
104
+ since the day it was written. **Removed** — see the workflow file's inline comment for the
105
+ full evidence chain.
106
+ - **npm Trusted Publisher was never actually bound** on npmjs.com for this package (confirmed:
107
+ first real publish attempt after the guard fix still 404'd — `PUT
108
+ .../@manhquy%2fflow-skill — Not found`). The 2026-07-12 runbook flagged this config as `TBD`
109
+ and it was never closed out. Configured now: `owner=manhquydev`, `repo=flow-skill`,
110
+ `workflow=publish-npm-wrapper.yml`, `environment=npm-publish`. `npm publish --provenance`
111
+ now succeeds via pure OIDC — confirmed live, SLSA attestation present.
112
+ - **`npm dist-tag add` does NOT work via OIDC** (confirmed live: `E401 Unable to authenticate`
113
+ even immediately after a successful OIDC-authenticated publish in the same job). npm has not
114
+ extended Trusted Publishing to this endpoint yet (matches
115
+ `plans/reports/researcher-260712-1006-npm-trusted-publisher-first-publish-edge-cases-report.md`
116
+ item #12, "OIDC support in development", no ship date). Promoting `0.1.0-rc.2` to `latest`
117
+ required the same manual Granular-Access-Token-with-Bypass-2FA flow used for the rc.1
118
+ bootstrap publish — see `RELEASE_CHECKLIST.md` for the exact steps and why this account
119
+ (created 2026-07-11, after npm's Sept-2025 TOTP-enrollment cutoff) has no other CLI-auth path
120
+ for write operations.
121
+
122
+ ### Release command (already run for this release)
72
123
  ```
73
- cd npm-wrapper && npm test # confirm green first
74
- git tag npm@0.1.0-rc.2 && git push --tags # triggers .github/workflows/publish-npm-wrapper.yml
124
+ cd npm-wrapper && npm test # confirmed green first
125
+ git tag npm@0.1.0-rc.2 && git push origin npm@0.1.0-rc.2 # triggered the workflow (after the guard fix + TP config above)
75
126
  ```
76
127
 
77
128
  ## [0.1.0-rc.1] — 2026-07-12
package/README.md CHANGED
@@ -10,13 +10,21 @@ One-command installer that copies the [flow](https://github.com/manhquydev/flow-
10
10
  ## Install
11
11
 
12
12
  ```
13
- # Pre-release channel (current — v0.1.0-rc.2)
13
+ # Pre-release channel (current — v0.1.0-rc.3, ships skill v0.22.0)
14
14
  npx @manhquy/flow-skill@rc
15
15
  ```
16
16
 
17
17
  An interactive prompt asks which agents to install to. Pick one or more, confirm, done.
18
18
 
19
- > **RC phase**: pin `@rc` (dist-tag) or a specific version like `@0.1.0-rc.2`. `npx @manhquy/flow-skill@0.1.x` will start working after stable `0.1.0` is published — semver ranges do **not** match pre-release tuples by default. See [SECURITY.md](./SECURITY.md).
19
+ > **RC phase**: pin `@rc` (dist-tag) or a specific version like `@0.1.0-rc.3`. `npx @manhquy/flow-skill@0.1.x` will start working after stable `0.1.0` is published — semver ranges do **not** match pre-release tuples by default. See [SECURITY.md](./SECURITY.md).
20
+ >
21
+ > **`npm i` alone is not enough.** `npm install @manhquy/flow-skill` only adds the installer
22
+ > package to `node_modules`. You must **run** it (`npx @manhquy/flow-skill@rc` or
23
+ > `npx flow-skill` after install) to copy the skill into agent homes.
24
+ >
25
+ > **Two version axes:** package `version` in this folder is the **installer** (e.g. `0.1.0-rc.3`).
26
+ > Skill product version lives in `skills/flow/SKILL.md` (`metadata.version`, e.g. `0.22.0`).
27
+ > `--help` and the JSONL `plan` event expose both (`version` + `skillVersion`).
20
28
 
21
29
  ## Non-interactive
22
30
 
@@ -58,7 +66,7 @@ line tells you exactly what to do for whichever targets you installed:
58
66
  - Claude Code: type `/flow`.
59
67
  - Codex CLI: type `$flow` (restart Codex once to load a new skill).
60
68
  - Antigravity: restart/reload the IDE (or restart `agy`) to load the new skill, then type `/flow`.
61
- - Agents home: restart/reload your tool if it does not auto-detect new skills.
69
+ - Agents home (`~/.agents/skills/`): restart/reload your tool if it does not auto-detect new skills.
62
70
  - Cursor: **install verified, live runner execution not yet independently confirmed** — Cursor
63
71
  has no headless CLI probe available for automated verification (unlike Antigravity's `agy -p`
64
72
  or Codex's `codex exec`); restart/reload Cursor after install and check the Agent panel for
@@ -86,6 +94,8 @@ rm -rf <project>/.claude/skills/flow
86
94
  - **Windows `EBUSY` / `EPERM` mid-install**: an agent (Claude Code, Codex, Antigravity IDE) is holding a file inside the destination. Close the agent and re-run. The installer already retries with 100/300/900 ms backoff before surfacing the error.
87
95
  - **Stale advisory lock**: a prior run crashed. The next run detects the dead PID and reclaims the lock automatically. If it does not (very rare — the recorded PID was recycled by another live process), delete `<parent-of-dest>/.flow-skill.installing.lock`.
88
96
  - **`No matching version found` on `@0.1.x`**: you are trying to install a pre-release version through a stable range. Use `@rc` (dist-tag) or an explicit `@0.1.0-rc.N` until stable `0.1.0` ships.
97
+ - **`No matching version found` on `@0.22.0`**: that is the **skill product** version, not the npm package version. Use `@rc` / `@0.1.0-rc.N` (installer) — skill content version is printed by `--help` as `ships skill v…`.
98
+ - **Installed package but agent has no `/flow`**: `npm i` does not run the installer. Run `npx @manhquy/flow-skill@rc` (or `npx flow-skill` if already installed) and restart the agent.
89
99
  - **Node too old** (`requires Node.js >=22.14.0`): upgrade with your preferred version manager (`nvm install 22`, `fnm install 22`, or Node's official installer). Node 20 reached end-of-life April 2026; npm OIDC Trusted Publishing needs npm >=11.5.1 which bundles with Node 22.14+.
90
100
 
91
101
  ## JSONL contract
@@ -93,7 +103,7 @@ rm -rf <project>/.claude/skills/flow
93
103
  `--json` streams one JSON object per line:
94
104
 
95
105
  ```jsonl
96
- {"event":"plan","version":"0.1.0-rc.1","dryRun":false,"scope":"global","targets":["claude","codex"]}
106
+ {"event":"plan","version":"0.1.0-rc.3","skillVersion":"0.22.0","dryRun":false,"scope":"global","targets":["claude","codex"]}
97
107
  {"event":"install:start","target":"claude","dests":["~/.claude/skills/flow"]}
98
108
  {"event":"install:done","target":"claude","dests":["~/.claude/skills/flow"],"result":"success","error":null,"warnings":[]}
99
109
  {"event":"summary","success":true,"total":2,"attempted":2,"installed":2,"failed":0,"skipped":0,"aborted":false}
@@ -105,7 +115,7 @@ rm -rf <project>/.claude/skills/flow
105
115
 
106
116
  | Event | Required fields | Notes |
107
117
  |---|---|---|
108
- | `plan` | `version` (string), `dryRun` (bool), `scope` (`global`\|`project`), `targets` (string[]) | Always the first event. |
118
+ | `plan` | `version` (string), `dryRun` (bool), `scope` (`global`\|`project`), `targets` (string[]), optional `skillVersion` (string\|null) | Always the first event. `version` = npm package; `skillVersion` = bundled `SKILL.md` product version. |
109
119
  | `install:start` | `target` (string), `dests` (string[]) | One per selected target. |
110
120
  | `install:done` | `target`, `dests`, `result` (`success`\|`failed`), `error` (string\|null), `warnings` (string[]) | Fired after each target. `error` is `null` on success. |
111
121
  | `summary` | `success` (bool), `total`, `attempted`, `installed`, `failed`, `skipped`, `aborted` (bool) | Always the last event. Counts sum: `attempted = installed + failed`; `skipped = total - attempted`. |
package/README_VN.md CHANGED
@@ -110,6 +110,11 @@ Mỗi phiên bản publish có [npm provenance](https://docs.npmjs.com/generatin
110
110
  npm view @manhquy/flow-skill@<version> dist.attestations.provenance
111
111
  ```
112
112
 
113
+ > **Ngoại lệ RC-window**: `v0.1.0-rc.1` được publish thủ công từ máy developer để bootstrap npm
114
+ > Trusted Publisher (TP không thể bind tới package chưa tồn tại) — bản này không có provenance.
115
+ > Từ `v0.1.0-rc.2` trở đi, mọi bản publish đều qua CI workflow với OIDC và có attestation
116
+ > SLSA Build Level 2 đầy đủ.
117
+
113
118
  ## Bảo mật
114
119
 
115
120
  Threat model + WILL/WON'T list + kênh report — xem [SECURITY.md](./SECURITY.md). Tóm tắt: pure Node, không network call, không spawn shell/PowerShell, không postinstall hook, không chạm settings/hooks/MCP config.
package/SECURITY.md CHANGED
@@ -55,7 +55,7 @@ These match the behavior of the upstream `install.sh`; they are documented rathe
55
55
  ```
56
56
  npm view @manhquy/flow-skill@<version> dist.attestations.provenance
57
57
  ```
58
- **`v0.1.0-rc.1` exception**: this bootstrap version was published manually (Trusted Publisher requires the package to already exist before it can bind) and carries no attestation. All subsequent versions publish via CI and are attested. If provenance is a hard requirement for you, wait for `v0.1.0-rc.2` or later.
58
+ **`v0.1.0-rc.1` exception**: this bootstrap version was published manually (Trusted Publisher requires the package to already exist before it can bind) and carries no attestation. `v0.1.0-rc.2` (2026-07-17) is the first version published from CI via OIDC — confirmed live with an SLSA Build Level 2 attestation. All versions from rc.2 onward are attested; if provenance is a hard requirement, pin `@0.1.0-rc.2` or later.
59
59
  - **Publisher account.** npm 2FA `auth-and-writes` is enabled as defense-in-depth for the git + npm identity behind the workflow.
60
60
  - **Pin your version.** During the RC window use `@rc` (dist-tag) or an explicit `@0.1.0-rc.N`. After stable ships, pin `@0.1.x` (or a specific version). `@latest` invites blind updates on a package that writes to your agent home.
61
61
  - **Completeness signal (not tamper detection).** The tarball ships `skills-manifest.json` recording the synced skill's file count + list. The publish workflow re-counts the checked-out tree against this manifest to catch an incomplete sync. It is **not** a supply-chain integrity proof — that role belongs to npm provenance above. `.integrity` SHA-256 sidecar was intentionally not adopted because it would have been generated from the same source it hashed (circular trust).
package/bin/cli.mjs CHANGED
@@ -4,7 +4,7 @@ import { fileURLToPath } from 'node:url';
4
4
  import { join, resolve } from 'node:path';
5
5
  import { existsSync } from 'node:fs';
6
6
 
7
- import { TARGETS, TARGET_NAMES, PKG_VERSION } from '../src/constants.mjs';
7
+ import { TARGETS, TARGET_NAMES, PKG_VERSION, SKILL_VERSION } from '../src/constants.mjs';
8
8
  import { defaultSelection, detectAll } from '../src/detect.mjs';
9
9
  import { renderHelp } from '../src/help.mjs';
10
10
  import { install, installAntigravity } from '../src/installer.mjs';
@@ -288,6 +288,9 @@ async function main() {
288
288
  {
289
289
  event: 'plan',
290
290
  version: PKG_VERSION,
291
+ // Additive: skill product version (SKILL.md). `version` stays the npm package version
292
+ // for back-compat with existing JSONL consumers.
293
+ skillVersion: SKILL_VERSION,
291
294
  dryRun: opts.dryRun,
292
295
  scope,
293
296
  targets: plan.map((p) => p.target),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manhquy/flow-skill",
3
- "version": "0.1.0-rc.2",
3
+ "version": "0.1.0-rc.3",
4
4
  "description": "Install the flow skill (buildflow gated build process) into your coding agent(s) via one npx command",
5
5
  "type": "module",
6
6
  "bin": {
@@ -67,7 +67,7 @@ Linking a trace to an unverified story prints a **pre-close gate** warning.
67
67
  All wiring degrades gracefully: if python is absent or `FLOW_HARNESS_DISABLE=1`, the
68
68
  mechanical engine runs unchanged.
69
69
 
70
- ## Usage signal: accessed_count (read-only, schema 005)
70
+ ## Usage signal: accessed_count (read-only, schema 009 — see Backends re-homing note above)
71
71
  `query decisions|friction|backlog` increment an `accessed_count` on every surfaced row and order
72
72
  output **most-reused-first**, so `recall` floats the knowledge you actually reuse to the top. It is
73
73
  a **read-only ordering signal** — never used to prune, delete, or archive a row. Low count is not
@@ -76,7 +76,7 @@ rare*. Security-class rows (`auth|authoriz|admin|tenan|payment|migrat|valid|secr
76
76
  always sort first and are never deprioritized. The story `matrix` view is intentionally left
77
77
  ordered by id (it is a status table, not recalled knowledge).
78
78
 
79
- ## Usage log: mechanical flight-recorder (schema 006)
79
+ ## Usage log: mechanical flight-recorder (schema 010 — see Backends re-homing note above)
80
80
  Distinct from the curated, agent-authored records above: `flow.sh` itself self-records **every
81
81
  invocation** (no agent action needed) to append-only JSONL — `.flow/events.jsonl` (full, per-project)
82
82
  plus `~/.claude/flow/usage.jsonl` (compact, device-global). Fields: ts/epoch_s, session_id, cycle_id
@@ -93,7 +93,7 @@ stage_from→to, card, project_type, mode, flow_version, tier, host, read_only.
93
93
  - JSONL is the source of truth; `usage_event` is a derived, queryable mirror. Semantic events keep
94
94
  using `trace`/`intervention`/`decision` — the usage log does not duplicate them.
95
95
 
96
- **Closed feedback loop (schema 007).** The recorded data feeds the surfaces where you already act:
96
+ **Closed feedback loop (schema 011 — see Backends re-homing note above).** The recorded data feeds the surfaces where you already act:
97
97
  - `recall` appends a one-line digest (`flow_harness.py usage --summary`): cycles, cycle-time, gate
98
98
  fail-rate, top gate-fail stage — so build history reaches you at stage/card start (silent if no data).
99
99
  - `propose` (`_build_proposals`) emits a backlog proposal when a stage's gate fail-rate ≥ 50% across
@@ -1034,7 +1034,7 @@ def build_parser():
1034
1034
  q1 = pqs.add_parser("matrix"); q1.add_argument("--json", action="store_true"); q1.add_argument("--numeric", action="store_true")
1035
1035
  q2 = pqs.add_parser("backlog"); q2.add_argument("--open", action="store_true"); q2.add_argument("--closed", action="store_true"); q2.add_argument("--json", action="store_true")
1036
1036
  q3 = pqs.add_parser("friction"); q3.add_argument("--json", action="store_true")
1037
- q4 = pqs.add_parser("tools"); q4.add_argument("--responsibility"); q4.add_argument("--json", action="store_true"); q4.add_argument("--summary", action="store_true")
1037
+ q4 = pqs.add_parser("tools"); q4.add_argument("--responsibility"); q4.add_argument("--json", action="store_true")
1038
1038
  q4.add_argument("--capability"); q4.add_argument("--status", choices=D.TOOL_STATUSES)
1039
1039
  q5 = pqs.add_parser("decisions"); q5.add_argument("--json", action="store_true")
1040
1040
 
@@ -2,7 +2,7 @@
2
2
  "source": "../skills/flow",
3
3
  "destRelative": "skills/flow",
4
4
  "fileCount": 74,
5
- "syncedAt": "2026-07-17T04:53:07.141Z",
5
+ "syncedAt": "2026-07-18T07:42:58.153Z",
6
6
  "fileList": [
7
7
  "SKILL.md",
8
8
  "_templates/00-idea.md",
package/src/constants.mjs CHANGED
@@ -72,11 +72,26 @@ export const CLI_NAME = 'flow-skill';
72
72
 
73
73
  // F3 fix: read version from package.json at runtime so `npm version` bumps propagate to the
74
74
  // JSON `plan` event without a hand-edit here.
75
- import { readFileSync } from 'node:fs';
75
+ import { readFileSync, existsSync } from 'node:fs';
76
76
  import { fileURLToPath } from 'node:url';
77
77
  import { dirname, resolve } from 'node:path';
78
78
  const __dirname = dirname(fileURLToPath(import.meta.url));
79
+ const pkgRoot = resolve(__dirname, '..');
79
80
  const pkgJson = JSON.parse(
80
- readFileSync(resolve(__dirname, '..', 'package.json'), 'utf8')
81
+ readFileSync(resolve(pkgRoot, 'package.json'), 'utf8')
81
82
  );
82
83
  export const PKG_VERSION = pkgJson.version;
84
+
85
+ // Skill product version (SKILL.md metadata.version) is a SEPARATE axis from the npm
86
+ // installer package version. Surface both so `npx … --help` / plan events cannot be
87
+ // misread as "stale skill" when the user expected 0.22.x and saw 0.1.0-rc.N.
88
+ function readSkillVersion() {
89
+ const skillMd = resolve(pkgRoot, 'skills', 'flow', 'SKILL.md');
90
+ if (!existsSync(skillMd)) return null;
91
+ const text = readFileSync(skillMd, 'utf8');
92
+ // Frontmatter only — first `version: "x.y.z"` under metadata (or any YAML version line).
93
+ // Indented under `metadata:` in YAML frontmatter (two spaces typical).
94
+ const m = text.match(/^\s*version:\s*["']?([0-9][0-9A-Za-z.+-]*)["']?\s*$/m);
95
+ return m ? m[1] : null;
96
+ }
97
+ export const SKILL_VERSION = readSkillVersion();
package/src/help.mjs CHANGED
@@ -1,16 +1,18 @@
1
- import { CLI_NAME, PKG_VERSION, TARGETS } from './constants.mjs';
1
+ import { CLI_NAME, PKG_VERSION, SKILL_VERSION, TARGETS } from './constants.mjs';
2
2
 
3
3
  export function renderHelp() {
4
4
  const targetRows = TARGETS.map((t) => ` ${t.name.padEnd(12)} ${t.label}`).join('\n');
5
5
  // v0.23 H5 (red-team): derive the count from TARGETS.length so a future target addition can
6
6
  // never again leave a stale hardcoded number in the help text.
7
7
  const targetCount = TARGETS.length;
8
- return `${CLI_NAME} v${PKG_VERSION}
8
+ const skillBit = SKILL_VERSION ? ` (ships skill v${SKILL_VERSION})` : '';
9
+ return `${CLI_NAME} v${PKG_VERSION}${skillBit}
9
10
 
10
11
  Install the flow skill into your coding agent(s).
11
12
 
12
13
  USAGE
13
- npx @manhquy/flow-skill [options]
14
+ npx @manhquy/flow-skill@rc
15
+ # or after stable ships: npx @manhquy/flow-skill
14
16
 
15
17
  OPTIONS
16
18
  -y, --yes Skip prompts; install to default selection (detected + Claude)