@sabaiway/agent-workflow-kit 1.17.0 → 1.18.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 +27 -0
- package/README.md +2 -1
- package/SKILL.md +37 -7
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/templates/orchestration.json +8 -3
- package/tools/commands.mjs +7 -0
- package/tools/family-registry.mjs +3 -1
- package/tools/inject-methodology.mjs +90 -16
- package/tools/orchestration-config.mjs +297 -0
- package/tools/orchestration-write.mjs +97 -0
- package/tools/procedures.mjs +17 -102
- package/tools/set-recipe.mjs +217 -0
- package/tools/setup-backends.mjs +71 -5
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,33 @@ 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.18.0 — Agent-writable orchestration config (`set-recipe`), version-aware setup, durable session contracts (kit)
|
|
8
|
+
|
|
9
|
+
A **feature** release. The per-project recipe config (`docs/ai/orchestration.json`) is no longer
|
|
10
|
+
hand-edit-only: a new **`set-recipe`** writer turns plain-language intent into a validated, previewed,
|
|
11
|
+
atomic write — and `setup` now surfaces bridge versions and proactively offers to set the review recipe
|
|
12
|
+
when a backend becomes ready. The deployment-lineage head stays **`1.3.0`** (no `docs/ai` structural
|
|
13
|
+
change, no migration); the kit **package** version is a separate axis.
|
|
14
|
+
|
|
15
|
+
- **`/agent-workflow-kit set-recipe` (new WRITER).** The agent maps plain language → explicit
|
|
16
|
+
`--set <activity>.<slot>=<recipe>` / `--unset <activity>.<slot>` ops; the kit validates → merges →
|
|
17
|
+
**previews by default** → writes only on `--write`. Split modules: `tools/orchestration-config.mjs`
|
|
18
|
+
(schema/read/pure — the shared slot-recipe validity table + `parseOp` / `applySetOps` /
|
|
19
|
+
`serializeConfig` / the canonical-refresh helpers) and `tools/orchestration-write.mjs` (the **only**
|
|
20
|
+
fs-writer — deployment gate, exclusive-create temp + rename, symlink/TOCTOU-safe, last-writer-wins).
|
|
21
|
+
`procedures` never imports the writer → the read-only invariant is **structural**. Renamed from the
|
|
22
|
+
planned `orchestrate` (it never *runs* a recipe). Hand-editing the file stays fully supported.
|
|
23
|
+
- **Setup surfaces versions + closes the loop.** Each skill line shows the bridge version (`(vX)` for a
|
|
24
|
+
fresh place / equal refresh, `(vOld → vNew)` on a bump, never `vnull → …`); a closing pointer at
|
|
25
|
+
`/agent-workflow-kit status`; and — re-detecting AFTER apply — a proactive `set-recipe` offer for
|
|
26
|
+
**both** `plan-authoring.review` and `plan-execution.review` when a review backend just became ready.
|
|
27
|
+
- **Canonical-refresh reaches the filled base.** `inject-methodology` refreshes a filled pointer slot to
|
|
28
|
+
the current engine canon when its content matches a known-prior fragment (a customization is preserved
|
|
29
|
+
+ advised); the `_README` refresh reuses the same `refreshIfCanonical` helper, and the upgrade
|
|
30
|
+
config-ensure is now seed-**or-refresh**.
|
|
31
|
+
- **Docs.** New `### Mode: set-recipe`; `procedures` / `velocity` / README no longer say the config is
|
|
32
|
+
"never written for you". Tarball **72 → 75** (three new `tools/*.mjs`).
|
|
33
|
+
|
|
7
34
|
## 1.17.0 — Hardened Codex bridge: quality-first delegation, clean capture, enforced git-write boundary (kit)
|
|
8
35
|
|
|
9
36
|
A **feature** release. The bundled `codex-cli-bridge` (`bridges/codex-cli-bridge/`) is overhauled to
|
package/README.md
CHANGED
|
@@ -223,7 +223,8 @@ command is printed).
|
|
|
223
223
|
| `/agent-workflow-kit setup [backend]` | opt-in, any time | **link-only** auto-setup of a bridge: places the bundled bridge skill (only into an absent / empty / managed dir — never overwrites an unmanaged one) + links its wrappers onto `PATH` via managed symlinks (idempotent; refuses to clobber a non-symlink; try `--dry-run` to preview). The binary install + the one-time subscription login stay **manual**: it prints the exact **login** command and points the binary install at each bridge's `setup/README.md`. POSIX wrappers — on Windows use WSL. Never commits, never runs a subscription CLI. |
|
|
224
224
|
| `/agent-workflow-kit status` | any time | **read-only** single view of **versions + deployment + settings + bridges**: which members (kit / memory / engine / the two bridges) are installed and at what version (with an honest "installed on this machine" note when one is behind) and — in a project — what's deployed (`docs/ai`, the version stamps, and the **visibility**: visible / hidden / unclear), plus your settings (orchestration recipes, attribution, velocity) and the bridges' readiness. The two version axes (package number vs deployment-structure head) stay decoupled. Never writes, never commits, never runs a subscription CLI. |
|
|
225
225
|
| `/agent-workflow-kit recipes` | any time | **read-only** orchestration advisor: presents four named recipes for composing the bridges into plan → execute → review — **Solo / Reviewed / Council / Delegated** — plans + recommends one for your environment (degrading with a stated reason when a backend isn't ready), and offers the choice. The orchestrator runs it via the bridge skills and **always commits**; the kit never executes a recipe, never runs a subscription CLI, never commits. |
|
|
226
|
-
| `/agent-workflow-kit procedures <activity>` | any time | **read-only** activity-procedures advisor: prints a named activity's ordered steps (`plan-authoring` / `plan-execution`) read **live** from the engine, plus the **resolved recipe per slot** from your
|
|
226
|
+
| `/agent-workflow-kit procedures <activity>` | any time | **read-only** activity-procedures advisor: prints a named activity's ordered steps (`plan-authoring` / `plan-execution`) read **live** from the engine, plus the **resolved recipe per slot** from your `docs/ai/orchestration.json` (agent-writable via `set-recipe`, or hand-edited) + backend readiness (default Reviewed when a backend is ready, Council on request, slot-aware incl. Delegated). `--override <slot>=<recipe>` adjusts one slot per run. Composes with `recipes`; never writes, never commits, never runs a subscription CLI. |
|
|
227
|
+
| `/agent-workflow-kit set-recipe` | any time | **config writer** for `docs/ai/orchestration.json`: tell the agent your preference in plain language and it maps it to explicit `--set <activity>.<slot>=<recipe>` / `--unset` ops; the kit validates, **previews by default**, and writes only on `--write` (deployment-gated, atomic, symlink/TOCTOU-safe), resolving the effective recipe vs live readiness. Writes **only** that file — **never runs a backend, never commits**; hand-editing stays fully supported. |
|
|
227
228
|
| `/agent-workflow-kit uninstall` | opt-in, any time | **guarded teardown** — the inverse of `init` / `setup`. Removes only what's **provably ours** (managed skill dirs + bridge wrappers; in a project, the hidden-mode git-ignore block it added + the pre-commit hook it installed); **never deletes** your `docs/ai` / `AGENTS.md` (prints the exact `rm` to run by hand) or your `.claude/settings.json` (prints an **edit** — remove the attribution key, review any velocity `permissions.*` — never an `rm`). Always `--dry-run` first; preflight-then-mutate; never commits. |
|
|
228
229
|
| `/agent-workflow-kit velocity` | Claude Code · opt-in | **onboarding velocity profile** — seeds a fixed, audited **read-only** allowlist into `.claude/settings.json` so routine read-only commands stop idling on approval prompts while you're away; opt-in `acceptEdits`; plus a **read-only advisory** of likely project gate commands to add by hand. Writes **only** `.claude/settings.json` — **never** allowlists commit/push/publish, never writes `settings.local.json`, never commits. A seeded entry is a **trust posture, not a sandbox** (a redirection/command-substitution residual remains, closed by a deferred hook); a direct commit/push/publish still asks. `--dry-run` first. |
|
|
229
230
|
|
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.
|
|
6
|
+
version: '1.18.0'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# agent-workflow-kit
|
|
@@ -107,7 +107,8 @@ Pick the mode from the user's invocation. Auto-detect an existing `docs/ai/` to
|
|
|
107
107
|
- **`/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.
|
|
108
108
|
- **`/agent-workflow-kit status`** — read-only view of the **whole family**: which members (kit / memory / engine / the two bridges) are installed, at what version, and — in a project — what is deployed (`docs/ai`, the version stamps, the hidden-mode fence). Never writes, never commits, never runs a subscription CLI.
|
|
109
109
|
- **`/agent-workflow-kit recipes`** — read-only **orchestration advisor**: present the four recipes (Solo / Reviewed / Council / Delegated) over the bridges' role vocabulary, plan + recommend one for the current environment, and offer the choice. **The orchestrator executes the chosen recipe via the bridge skills and always commits** — the kit only surfaces/selects/plans it; it never executes a recipe, never runs a subscription CLI, never commits.
|
|
110
|
-
- **`/agent-workflow-kit procedures <activity>`** — read-only **activity-procedures advisor**: print the ordered steps of a named activity (`plan-authoring` / `plan-execution`) read **live** from the installed engine (`references/procedures.md`), and the **resolved effective recipe per slot** from the per-project `docs/ai/orchestration.json` (
|
|
110
|
+
- **`/agent-workflow-kit procedures <activity>`** — read-only **activity-procedures advisor**: print the ordered steps of a named activity (`plan-authoring` / `plan-execution`) read **live** from the installed engine (`references/procedures.md`), and the **resolved effective recipe per slot** from the per-project `docs/ai/orchestration.json` (strict JSON; agent-writable via `set-recipe` or hand-edit) + backend readiness (default = Reviewed when a backend is ready, Council on request, slot-aware incl. Delegated; graceful default vs loud override degradation). A per-run `--override <slot>=<recipe>` overrides one slot. Composes with `recipes` (which stays read-only); never writes, never commits, never runs a subscription CLI.
|
|
111
|
+
- **`/agent-workflow-kit set-recipe`** — the **config writer** for `docs/ai/orchestration.json`: turn the user's plain language into explicit `--set <activity>.<slot>=<recipe>` / `--unset` ops; the kit validates, merges, **previews by default**, and writes only on `--write` (deployment-gated, atomic, symlink/TOCTOU-safe). Resolves the effective recipe vs live readiness (degradation honesty on both paths). **Writes only `docs/ai/orchestration.json`; never runs a backend, never commits.** Hand-editing the file stays fully supported.
|
|
111
112
|
- **`/agent-workflow-kit uninstall`** — the **guarded teardown** companion to `init`/`setup`. Removes what they placed — installed skill dirs + the bridge wrappers — and, in a project, reverses the hidden-mode fence + the marker pre-commit hook. **Never deletes user-authored content**: it prints the exact `rm` for `docs/ai` / `AGENTS.md` and an **edit** for `.claude/settings.json` (the `includeCoAuthoredBy` key + any velocity `permissions.*`), for you to run by hand. `--dry-run` first, always; preflight-then-mutate; never commits.
|
|
112
113
|
- **`/agent-workflow-kit velocity`** — opt-in onboarding **velocity profile**: seed a fixed, audited **read-only** Claude Code allowlist into `.claude/settings.json` so routine read-only commands stop idling on approval prompts; opt-in `acceptEdits`; plus a **read-only advisory** of likely project gate commands to add by hand. **Writes only `.claude/settings.json`, never allowlists commit/push/publish, never writes `settings.local.json`, never commits.** `--dry-run` first.
|
|
113
114
|
|
|
@@ -283,9 +284,9 @@ Fill strategy:
|
|
|
283
284
|
|
|
284
285
|
**Hidden-mode footprint reconcile — stamp-independent, same gate, BEFORE the equal-head short-circuit (D9 / AD-014).** A deployment does not record whether it chose `hidden`, so first **infer visibility**: `node ${CLAUDE_SKILL_DIR}/tools/hide-footprint.mjs --dir <project> --reconcile --dry-run` (writes **zero bytes**). It reports one of — **visible** (the entry point is tracked) → nothing to do; **ambiguous** (untracked but not ignored — could be a fresh uncommitted repo, or a hide that broke) → **ASK** the user which it is, never guess; **hidden** → re-run without `--dry-run` to migrate any older **machine-global** hide to the **project-local** `.git/info/exclude` (one managed block; folds in the legacy `.claude/skills/` line), idempotently (a clean re-run is zero-diff). Handle its surfaced paths exactly as bootstrap step 9 (already-committed → show `git rm --cached`, ask before `--include`; generic-name present file → ask; **leftover machine-wide ignore block → ASK before `--remove-global`**, default keep + report). No Node on the agent host / Windows → as step 9. This runs on **every** hidden upgrade, like the methodology slot — no lineage-head bump, no migration file.
|
|
285
286
|
|
|
286
|
-
**Orchestration config ensure — stamp-independent, same gate, BEFORE the equal-head short-circuit.** Ensure `docs/ai/orchestration.json` exists
|
|
287
|
+
**Orchestration config ensure (seed-or-refresh) — stamp-independent, same gate, BEFORE the equal-head short-circuit.** Ensure `docs/ai/orchestration.json` exists **and its onboarding note is current**: **create it from the template if missing**; **if it already exists, preserve every activity/slot the user set, and refresh ONLY the `_README` note when the existing one still matches a known prior canonical** — the tested `refreshIfCanonical` / `refreshReadme` in `tools/orchestration-config.mjs` is the source of truth for that decision (normalize CRLF/whitespace before comparing; a *customized* `_README` is preserved verbatim; a *malformed* existing config is **preserved + a loud warning**, never clobbered or silently skipped). The current note points at `/agent-workflow-kit set-recipe` (the config is now agent-writable — no more "never written for you"). **The refresh helper is kit-owned** — in the **delegated** path memory only seeds/preserves the file (memory upgrade step 2) and the **kit** then applies the `_README` refresh; in the **fallback** path the kit seeds-or-refreshes directly from `${CLAUDE_SKILL_DIR}/references/templates/orchestration.json`. (Memory stays standalone — it never depends on this helper.) Like the pointer slots + the footprint reconcile, this reaches an equal-head (`1.3.0`) deployment **without a lineage-head bump or a migration file** (it is a `.json`, inherently outside the docs cap-validator). Report it in the step 4 / step 8 success report (config *seeded* / *note refreshed* / *already current* / *customized — preserved*).
|
|
287
288
|
4. **Equal-head exit — a real successful-exit report, not a bare stop.** If the stamp **equals** the head, the lineage is up to date — but step 3 (the methodology-slot **and** hidden-mode footprint reconciles) ran first and may have changed things, so this is a proper exit report, not a no-op:
|
|
288
|
-
- **Report step 3's outcome in plain language** — for **each** pointer (workflow-methodology and orchestration-recipes) whether it was *added*, was *already present* (nothing changed), or was *skipped because the entry point is over its line limit* (the cap-refusal soft-skip from step 3, with its reason); whether the `docs/ai/orchestration.json` config was *seeded*
|
|
289
|
+
- **Report step 3's outcome in plain language** — for **each** pointer (workflow-methodology and orchestration-recipes) whether it was *added*, was *already present* (nothing changed), or was *skipped because the entry point is over its line limit* (the cap-refusal soft-skip from step 3, with its reason); whether the `docs/ai/orchestration.json` config was *seeded* (created from the template), had its onboarding note *refreshed*, was *already current*, or carried a *customized note that was preserved* (a user edit is never clobbered); and, for a hidden deployment, whether the hidden-mode footprint was *moved to project-local*, was *already project-local* (nothing changed), or needed a question (ambiguous visibility / a leftover machine-wide block). Plain wording only — never the reconcile/slot/anchor/marker terms (Gotcha: never leak kit internals).
|
|
289
290
|
- **Name the version axis so the package number isn't mistaken for a newer release.** When you state the deployment is up to date, say it is current at the **deployment-lineage head** (`1.3.0`) and add one plain line: this head versions the deployed `docs/ai` structure and is a **separate axis** from the kit **package** version published on npm/GitHub (the larger number users see on the repo/npm page). A packaging-only release can bump that package version **without** moving the head — the head advances only when the deployed `docs/ai` structure changes — so an equal-head report is **not** a stale deployment even though GitHub shows a higher package number. (This is the only place the two axes meet the user in `upgrade`; surfacing it here prevents the recurring "but GitHub shows a higher version" confusion.)
|
|
290
291
|
- **Print the report footer** in the canonical order (version block → one-line backend-status line → welcome mat — the shared contracts above; rendered from the helpers, same host-can't-run skip-with-reason). The welcome mat closes on **one** caveat-aware next step (a behind member first, else `setup` / `recipes` / `velocity`).
|
|
291
292
|
- **Then ask before committing — never auto-commit.** If step 3 added the slot (or anything else changed), report it and ask. If step 3 was a pure zero-diff no-op and nothing else changed, say **"already up to date"** and still print the read-only version block + backend line.
|
|
@@ -320,6 +321,11 @@ For each backend it:
|
|
|
320
321
|
2. **Links its wrappers** (`codex-exec` / `codex-review`; `agy-run`) onto `--bindir` via **managed symlinks** — replacing only a symlink that already points at our source. A non-symlink or a foreign symlink → **STOP**; it **preflights every target first**, so a conflict on one wrapper makes **zero** changes. If `--bindir` is not on `PATH`, it prints the one-line `export PATH=…` to add — it never edits a shell rc.
|
|
321
322
|
3. **Guides the manual, secret-bearing steps it will NOT automate** — the binary install (each bridge's `setup/README.md` §1) and the one-time interactive subscription login (`codex login` / `agy`) — printing the exact command for whichever axis is still missing (axis-aware: it can ask for both the CLI and the login at once).
|
|
322
323
|
|
|
324
|
+
**Close-the-loop output (surface both, localized).** The tool prints, after the per-backend report:
|
|
325
|
+
- a **bridge version** on each skill line — `(vX)` for a fresh place / equal refresh, `(vOld → vNew)` when a refresh bumps the bridge (never `vnull → …`);
|
|
326
|
+
- a **status pointer** — the full family + deployment version view lives in `/agent-workflow-kit status`;
|
|
327
|
+
- a **proactive recipe offer** when a setup just made a review backend ready (re-detected AFTER apply, so it reflects the real new state): it prints `/agent-workflow-kit set-recipe --set plan-authoring.review=<depth>` **and** `…plan-execution.review=<depth>` (Council when both are ready, else Reviewed). Relay it in plain language: offer to set the review recipe for **both** planning and execution review (preview first; you'll write it via *Mode: set-recipe*, or they can hand-edit) — never offer only `plan-execution`. Ask if the scope is unclear.
|
|
328
|
+
|
|
323
329
|
**Windows:** the wrappers are POSIX `.sh`; on `win32` it reports *unsupported — use WSL* and mutates nothing.
|
|
324
330
|
|
|
325
331
|
**Exit codes:** `0` = done / already set up / only manual steps remain (guidance is never a failure); **non-zero** = a STOP (a dir/symlink it refuses to clobber), a bad argument, a missing bundle, or a native fs error (the underlying reason is preserved in the message).
|
|
@@ -371,7 +377,7 @@ The two v1 activities (canon in the **installed engine**, `references/procedures
|
|
|
371
377
|
|
|
372
378
|
Run **`node ${CLAUDE_SKILL_DIR}/tools/procedures.mjs <activity> [--override <slot>=<recipe>]… [--json]`**. It reads the activity's steps live from the engine and prints them **verbatim**, then the **resolved effective recipe per slot** from the per-project config + the read-only backend detector:
|
|
373
379
|
|
|
374
|
-
1. **Config = `docs/ai/orchestration.json`** — strict JSON, **hand-edited** (the kit reads + validates it; `recipes`
|
|
380
|
+
1. **Config = `docs/ai/orchestration.json`** — strict JSON, **agent-writable via `/agent-workflow-kit set-recipe` (Mode: set-recipe) OR hand-edited** (the kit reads + validates it; `procedures`/`recipes` stay read-only — the writer is `set-recipe`). Shape: `{ "<activity>": { "<slot>": "<recipe>" } }`; all slots optional (an absent slot → its computed default, stated); an optional `"_README"` string is allowed + ignored. `review` accepts `solo|reviewed|council`; `execute` accepts `solo|delegated`. Seeded by `init` (a user-editable template) — see *Mode: bootstrap*.
|
|
375
381
|
2. **Default resolution (config silent):** `review` → Reviewed if any review-capable backend is `ready`, else Solo (never Council by default); `execute` → Solo (Delegated is opt-in). **Degradation:** a config/computed default degrades **gracefully with a stated reason** (Council → Reviewed → Solo; Delegated → Solo); a per-run **`--override <slot>=<recipe>`** that can't be satisfied degrades **loudly** (a flagged warning, so you tell the user) — but is **still exit 0** (a valid request that gracefully degraded).
|
|
376
382
|
3. **Exit codes:** `0` success; `2` usage (unknown `<activity>` / bad `--override` — a bare `--override <recipe>`, an unknown slot, an invalid recipe-for-slot, or a duplicate slot); `1` config error (malformed / schema-invalid / unreadable `orchestration.json`) **or** engine error (the installed engine is absent / invalid / **too old** to ship `references/procedures.md` — upgrade it with `npx @sabaiway/agent-workflow-engine@latest init`). A `1`/`2` failure is loud (`path: reason`), never a silent fallback.
|
|
377
383
|
|
|
@@ -379,6 +385,30 @@ Run **`node ${CLAUDE_SKILL_DIR}/tools/procedures.mjs <activity> [--override <slo
|
|
|
379
385
|
|
|
380
386
|
**Invariants:** read-only · never writes · never commits · never runs a subscription CLI · the deterministic resolution is the kit's, the recipe execution is the orchestrator's.
|
|
381
387
|
|
|
388
|
+
### Mode: set-recipe
|
|
389
|
+
|
|
390
|
+
The **config writer** for `docs/ai/orchestration.json` — the answer to *"set my standing recipe preference without hand-editing JSON."* **Division of labor (AD-025):** YOU turn the user's plain language into explicit ops; the KIT does the deterministic validate → merge → preview → write. It **previews by default** (writes nothing); `--write` applies. It **never runs a backend and never commits**. Hand-editing `docs/ai/orchestration.json` stays fully supported — this is an offered convenience, never a lock.
|
|
391
|
+
|
|
392
|
+
**Map the user's plain language → explicit ops** (the kit ships no NL parser; it performs no `all`-magic, so you expand scope explicitly, asking when unclear):
|
|
393
|
+
|
|
394
|
+
| user says (RU/EN) | op | scope |
|
|
395
|
+
|---|---|---|
|
|
396
|
+
| "оба ревьюят" / "both review" | `--set <activity>.review=council` | **disambiguate**: which activity? If both, pass `--set plan-authoring.review=council --set plan-execution.review=council`. |
|
|
397
|
+
| "один ревьюер" / "one reviewer" | `--set <activity>.review=reviewed` | per the named activity, else ask |
|
|
398
|
+
| "делегируй исполнение" / "delegate execution" | `--set plan-execution.execute=delegated` | execution only |
|
|
399
|
+
| "верни как было / сам" / "revert / do it myself" | `--unset <activity>.<slot>` | the named slot → its computed default |
|
|
400
|
+
|
|
401
|
+
Run **`node ${CLAUDE_SKILL_DIR}/tools/set-recipe.mjs [--set <activity>.<slot>=<recipe>]… [--unset <activity>.<slot>]… [--write] [--json]`**:
|
|
402
|
+
|
|
403
|
+
1. **Grammar — always fully-qualified `<activity>.<slot>`** (the kit never guesses the activity; a bare `review=council` is rejected). `review` accepts `solo|reviewed|council`; `execute` accepts `solo|delegated`. Activities/slots: `plan-authoring.review`, `plan-execution.execute`, `plan-execution.review`.
|
|
404
|
+
2. **Preview by default** — prints `current → proposed` for the **changed** slots only, plus the **effective recipe resolved against live backend readiness** (degradation stated honestly, e.g. *council requested, 1 ready reviewer → runs reviewed until a 2nd backend is ready*). It writes **nothing**. Re-run with **`--write`** to apply (same effective/degradation note — a direct `--write` is never quieter than the preview). `--unset` returns a slot to its computed default (reverting needs no hand-edit either). A no-op `--set` (slot already equals) writes nothing and never re-seeds the onboarding note.
|
|
405
|
+
3. **`--write`** applies via a hardened, atomic write (deployment-gated — refuses to scatter a config into a repo with no `docs/ai`; exclusive-create temp + rename; symlink/TOCTOU-safe; last-writer-wins). It preserves the onboarding note + every untouched slot, normalizing to canonical 2-space JSON.
|
|
406
|
+
4. **Exit codes:** `0` success (an explicit recipe that gracefully degrades is still `0`); `2` usage (a bare/duplicate op, or `--write` with no ops); `1` config error (malformed/unreadable config — the file is left **untouched**, never clobbered) or a write STOP (no deployment / a symlinked config). A `1`/`2` failure is loud; on a malformed config, offer to show the parse error so you can help the user fix the JSON.
|
|
407
|
+
|
|
408
|
+
Output is **English/structured** — **localize it to the user's conversational language** when you narrate. Surface the effective-recipe/degradation note plainly.
|
|
409
|
+
|
|
410
|
+
**Invariants:** writer (writes only `docs/ai/orchestration.json`) · never commits · never runs a subscription CLI · previews by default · degradation honesty on preview AND `--write` · hand-edit stays first-class.
|
|
411
|
+
|
|
382
412
|
### Mode: uninstall
|
|
383
413
|
|
|
384
414
|
The **guarded teardown** — the inverse of `init` (the kit + engine skills) + `setup` (the bridges) + a hidden deploy. **In-agent, opt-in**, and built around one hard rule: **it never deletes user-authored content.** Run **`--dry-run` first, always**, show the user the classified plan in plain language, get explicit consent, then re-run with `--yes`. It **never commits**.
|
|
@@ -411,7 +441,7 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/velocity-profile.mjs [--dry-run | --apply] [
|
|
|
411
441
|
- **"Keep per-edit approval prompts (recommended)"** — seed only the read-only allowlist; file edits still prompt.
|
|
412
442
|
- **"Auto-accept file edits (`defaultMode: acceptEdits`)"** — present the honest FULL posture: it auto-applies Edit/Write AND auto-runs `mkdir`/`touch`/`mv`/`cp` in the working dir, is paired with the read-only allowlist, and — stated plainly — a settings-level allow rule is a **trust posture, not a sandbox**: a read-only entry can still write a file via output redirection, and (Claude Code's allow rules do not inspect command substitution) could in principle run another command via `cmd $(…)`. velocity **never adds `commit`/`push`/`publish` as allow rules** — so a direct `git push` still ASKs — but that same redirection/substitution residual means they are not *fully* closed until the deferred PreToolUse hook (family backlog). Note also that a `defaultMode` in `settings.local.json` would override this project-level write (local > project), since velocity writes only `.claude/settings.json`.
|
|
413
443
|
3. **Only on an explicit yes**, re-run with `--apply` (add `--accept-edits` only if they chose the second option). It merges-don't-clobber (preserves `includeCoAuthoredBy`, every key, and existing allow entries) and writes **only** `.claude/settings.json`.
|
|
414
|
-
4. **Surface delegation-readiness, read-only.** If they want a step run Delegated,
|
|
444
|
+
4. **Surface delegation-readiness, read-only.** If they want a step run Delegated, set it with `/agent-workflow-kit set-recipe --set plan-execution.execute=delegated` (*Mode: set-recipe*) or by hand-editing `docs/ai/orchestration.json`; **velocity itself never writes the orchestration config.**
|
|
415
445
|
|
|
416
446
|
**Invariants:** creates `.claude/` if absent and writes **only** `.claude/settings.json` (no other file); **never** allowlists commit/push/publish; **never** writes `settings.local.json`; never commits; opt-in `acceptEdits`, never silent.
|
|
417
447
|
|
|
@@ -491,6 +521,6 @@ Deploy these into `AGENTS.md`; remove rows that don't apply to the stack.
|
|
|
491
521
|
- [`references/scripts/`](references/scripts/) — the Node enforcement scripts (caps + staleness + index-freshness gate, 3-tier archive, hook installer) and their unit tests.
|
|
492
522
|
- [`migrations/`](migrations/) — per-version upgrade steps; see `migrations/README.md`.
|
|
493
523
|
- [`launchers/`](launchers/) — run the bootstrapper from non-Claude agents (`SKILL.md` is a native Codex skill; a Devin Desktop workflow launcher + install script). See `launchers/README.md`.
|
|
494
|
-
- [`tools/`](tools/) — the family-wide tooling the kit **owns and ships**: `manifest/{schema.md,validate.mjs}` (the `capability.json` schema + the validator the kit runs as the memory detector, and root CI invokes), `commands.mjs` (the canonical **command catalog** + the pure `routeInvocation` router behind `/agent-workflow-kit help` and the safe unknown-invocation routing rule — one source of truth for the command surface, drift-guarded against the `### Mode:` headers), `delegation.mjs` (the executable delegate/fallback decision + hand-off plan), `inject-methodology.mjs` + `engine-source.mjs` (the bounded **two-slot** reconciliation — ensure-slot / inject-if-empty / cap for the `workflow:methodology` **and** `workflow:orchestration` pointers; both fragments read **live** from the installed `agent-workflow-engine` via `engine-source.mjs` (`deps.rel` selects which) — the family's one source of truth, no bundled mirror; fail-loud when the engine is needed but absent, orchestration soft-skipped when it would bust the cap), `detect-backends.mjs` (the read-only **backend detector** behind `/agent-workflow-kit backends`, plus the axis-aware `guideFor`; exports the readiness consts the planner reuses), `recipes.mjs` (the read-only **recipe planner** behind `/agent-workflow-kit recipes` — `RECIPES` / `planRecipe` / `recommendRecipe` over the bridges' role vocabulary, drift-guarded against `provides`/`cost`/`quota` + an engine↔kit recipe-name parity guard; pure, never runs a subscription CLI; also exports the pure `ACTIVITIES` / `resolveActivityRecipe` activity-procedures resolver), `procedures.mjs` (the read-only **activity-procedures advisor** behind `/agent-workflow-kit procedures` — reads `references/procedures.md` live from the engine via `engine-source.mjs`, reads + validates the
|
|
524
|
+
- [`tools/`](tools/) — the family-wide tooling the kit **owns and ships**: `manifest/{schema.md,validate.mjs}` (the `capability.json` schema + the validator the kit runs as the memory detector, and root CI invokes), `commands.mjs` (the canonical **command catalog** + the pure `routeInvocation` router behind `/agent-workflow-kit help` and the safe unknown-invocation routing rule — one source of truth for the command surface, drift-guarded against the `### Mode:` headers), `delegation.mjs` (the executable delegate/fallback decision + hand-off plan), `inject-methodology.mjs` + `engine-source.mjs` (the bounded **two-slot** reconciliation — ensure-slot / inject-if-empty / cap for the `workflow:methodology` **and** `workflow:orchestration` pointers; both fragments read **live** from the installed `agent-workflow-engine` via `engine-source.mjs` (`deps.rel` selects which) — the family's one source of truth, no bundled mirror; fail-loud when the engine is needed but absent, orchestration soft-skipped when it would bust the cap), `detect-backends.mjs` (the read-only **backend detector** behind `/agent-workflow-kit backends`, plus the axis-aware `guideFor`; exports the readiness consts the planner reuses), `recipes.mjs` (the read-only **recipe planner** behind `/agent-workflow-kit recipes` — `RECIPES` / `planRecipe` / `recommendRecipe` over the bridges' role vocabulary, drift-guarded against `provides`/`cost`/`quota` + an engine↔kit recipe-name parity guard; pure, never runs a subscription CLI; also exports the pure `ACTIVITIES` / `resolveActivityRecipe` activity-procedures resolver), `procedures.mjs` (the read-only **activity-procedures advisor** behind `/agent-workflow-kit procedures` — reads `references/procedures.md` live from the engine via `engine-source.mjs`, reads + validates the agent-writable `docs/ai/orchestration.json` via `orchestration-config.mjs`, and prints the steps + the resolved effective recipe per slot; drift-guarded activity/slot table vs the canon; read-only, never imports the writer, never runs a subscription CLI), `orchestration-config.mjs` (the config **schema/read/pure-transform core** — `loadConfig`/`validateConfig`/the shared slot-recipe validity + `parseOp`/`applySetOps`/`serializeConfig`/the canonical-refresh helpers; no fs writes), `orchestration-write.mjs` (the **only** config fs-writer — a deployment-gated, atomic, symlink/TOCTOU-safe `writeConfig`; imported by `set-recipe` alone, never by `procedures`), `set-recipe.mjs` (the **config writer** behind `/agent-workflow-kit set-recipe` — validate → merge → preview-by-default → write; never runs a backend, never commits), `setup-backends.mjs` (the **link-only** backend setup behind `/agent-workflow-kit setup` — place the bundled bridge + link wrappers), `fs-safe.mjs` (the shared symlink-traversal-safe copy/link/**remove/unlink** primitives that `setup-backends`, the npx installer, and the uninstaller use), `known-footprint.mjs` + `hide-footprint.mjs` (the **hidden-mode** registry + the single hide-writer behind step 9 / the upgrade reconcile — one managed block in the **project-local** `.git/info/exclude` covering the full AI/agent footprint; pinned by `known-footprint.test.mjs` drift-guard + `hide-footprint.test.mjs` / `.integration.test.mjs`), `family-registry.mjs` (the **unified family registry** behind `/agent-workflow-kit status` — aggregates every member's `capability.json`; pinned by a `family-registry.test.mjs` drift-guard), `uninstall.mjs` (the **guarded teardown** behind `/agent-workflow-kit uninstall` — classify each surface, preflight-then-mutate, never delete user-authored content), and `release-scan.mjs` (the attribution-off release gate). The bundled bridge skill mirrors live under [`bridges/`](bridges/) (byte-identical to the repo-root bridges, pinned by `test/bridges-mirror.test.mjs`). See [`tools/manifest/schema.md`](tools/manifest/schema.md).
|
|
495
525
|
- [`capability.json`](capability.json) — the kit's own `agent-workflow` family manifest (`kind: composition-root`).
|
|
496
526
|
- [`CHANGELOG.md`](CHANGELOG.md) — version history of this kernel.
|
package/capability.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sabaiway/agent-workflow-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.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",
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_README": "Per-project orchestration config: the recipe used at each step (slot) of each named activity.
|
|
3
|
-
"plan-authoring": {
|
|
4
|
-
|
|
2
|
+
"_README": "Per-project orchestration config: the recipe used at each step (slot) of each named activity. Easiest: tell the agent in plain language and run the `set-recipe` writer — it interprets your intent, previews the change, and writes valid JSON for you. You can still hand-edit this file directly whenever you prefer; that option never goes away. Each activity is configured independently (e.g. plan-authoring, plan-execution), and so is each slot within it. A slot's value is a recipe: a 'review' slot accepts solo | reviewed | council (you self-review / one backend reviews / both review and you synthesize); an 'execute' slot accepts solo | delegated (you implement / a backend runs a bounded sub-task). The default below is 'solo' everywhere — no execution backend required. Raise a slot to reviewed or council for a second opinion, or to delegated to hand off execution; those need an execution backend set up first. Remove a slot's line (or run `set-recipe --unset <activity>.<slot>`) to fall back to the computed default (reviewed when a review backend is ready, otherwise solo). Run the read-only procedures advisor to see an activity's steps plus the recipe resolved for your environment. Strict JSON — no comments.",
|
|
3
|
+
"plan-authoring": {
|
|
4
|
+
"review": "solo"
|
|
5
|
+
},
|
|
6
|
+
"plan-execution": {
|
|
7
|
+
"execute": "solo",
|
|
8
|
+
"review": "solo"
|
|
9
|
+
}
|
|
5
10
|
}
|
package/tools/commands.mjs
CHANGED
|
@@ -115,6 +115,13 @@ const CATALOG = [
|
|
|
115
115
|
kind: READ_ONLY,
|
|
116
116
|
oneLine: 'Show a named activity’s steps and which recipe applies at each stage here.',
|
|
117
117
|
},
|
|
118
|
+
{
|
|
119
|
+
key: 'set-recipe',
|
|
120
|
+
invocation: invocationOf('set-recipe'),
|
|
121
|
+
group: 'Orchestrate',
|
|
122
|
+
kind: WRITER,
|
|
123
|
+
oneLine: 'Set the orchestration recipe for an activity from plain language — previews the change, then writes the config when you confirm.',
|
|
124
|
+
},
|
|
118
125
|
];
|
|
119
126
|
|
|
120
127
|
// Deep-freeze: freeze the array AND every entry, so the catalog is genuinely immutable at runtime
|
|
@@ -25,7 +25,9 @@ import { validateManifest, readAuthoritativeVersion, UNSUPPORTED, INVALID } from
|
|
|
25
25
|
import { START_MARKER, excludePath, inferVisibility } from './hide-footprint.mjs';
|
|
26
26
|
import { readEngineFragment, ORCHESTRATION_FRAGMENT_REL, PROCEDURES_FRAGMENT_REL } from './engine-source.mjs';
|
|
27
27
|
import { ACTIVITIES, resolveActivityRecipe } from './recipes.mjs';
|
|
28
|
-
|
|
28
|
+
// The config reader lives in orchestration-config.mjs (the single config contract). The read-only status
|
|
29
|
+
// settings-survey reuses THIS reader (one strict-JSON + loud-on-malformed contract), not a second copy.
|
|
30
|
+
import { loadConfig } from './orchestration-config.mjs';
|
|
29
31
|
// The deployment-lineage head + the shared settings readers are reused from velocity-profile so the
|
|
30
32
|
// `--json` envelope/settings-survey has ONE implementation each, never a drifting copy:
|
|
31
33
|
// EXPECTED_WORKFLOW_VERSION — the head literal (drift-guarded vs memory LINEAGE_HEAD)
|
|
@@ -18,6 +18,14 @@
|
|
|
18
18
|
// STOP loudly (never a silent fallback) when the engine is needed but absent/invalid.
|
|
19
19
|
//
|
|
20
20
|
// Pure string functions (testable with byte-preservation fixtures); dependency-free, Node >= 18.
|
|
21
|
+
//
|
|
22
|
+
// Canonical-refresh (AD-025): a slot filled BEFORE a clause existed is normally preserved verbatim
|
|
23
|
+
// (reconcile only fills an EMPTY slot). To push a NEW canonical clause to the EXISTING filled base
|
|
24
|
+
// without clobbering a user's customization, reconcileMarkerSlot also REFRESHES a filled slot — but
|
|
25
|
+
// ONLY when its content normalize-matches a KNOWN PRIOR canonical fragment (drift-guarded, append-only
|
|
26
|
+
// per descriptor). A customized slot never matches → preserved verbatim + a read-only upgrade advisory.
|
|
27
|
+
|
|
28
|
+
import { normalizeCanonical } from './orchestration-config.mjs';
|
|
21
29
|
|
|
22
30
|
export const START_MARKER = '<!-- workflow:methodology:start -->';
|
|
23
31
|
export const END_MARKER = '<!-- workflow:methodology:end -->';
|
|
@@ -57,11 +65,29 @@ export const ORCH_ANCHOR = new RegExp(`^.*${escapeRegExp(END_MARKER)}.*$`, 'm');
|
|
|
57
65
|
export const EMPTY_SLOT = `${START_MARKER}\n${END_MARKER}`;
|
|
58
66
|
export const ORCH_EMPTY_SLOT = `${ORCH_START_MARKER}\n${ORCH_END_MARKER}`;
|
|
59
67
|
|
|
68
|
+
// ── known-prior canonical fragments (drift-guarded, APPEND-ONLY per slot) ───────
|
|
69
|
+
// The EXACT content a PREVIOUS release's engine fragment shipped (what a filled slot would carry today).
|
|
70
|
+
// reconcileMarkerSlot refreshes a filled slot to the current engine fragment IFF its content
|
|
71
|
+
// normalize-matches one of these — so the install base gains a new clause without clobbering a
|
|
72
|
+
// customization (which never matches). Any release that CHANGES an engine fragment must FIRST append the
|
|
73
|
+
// OUTGOING content here, so the immediately-previous deployments still match (a drift-guard test pins
|
|
74
|
+
// current-minus-one → new). NEVER edit an existing entry — only append.
|
|
75
|
+
export const KNOWN_PRIOR_METHODOLOGY_SLOT = [
|
|
76
|
+
// v1.3.0 — pre-communication-contract methodology pointer (procedures route, no §1.9 clause).
|
|
77
|
+
'> **Workflow methodology** — plan → execute → review. Plans are ephemeral `docs/plans/*.md` (gitignored, **never committed**); every Plan ends with a mandatory **Phase: Cleanup**; series order lives in `docs/plans/queue.md`. Full vocabulary, lifecycle, and the plan-then-execute split live in the project\'s **planning skill** (it overrides the generic `writing-plans`); summary in `docs/ai/agent_rules.md` §5. Named activities (plan-authoring, plan-execution) have procedures — see `/agent-workflow-kit procedures <activity>` for the steps + resolved recipe.',
|
|
78
|
+
];
|
|
79
|
+
export const KNOWN_PRIOR_ORCH_SLOT = [
|
|
80
|
+
// v1.3.0 — pre-read-at-start orchestration pointer (recipes vocabulary, no orchestration.json clause).
|
|
81
|
+
'> **Orchestration recipes** — compose plan → execute → review with a named recipe: **Solo** (no backend), **Reviewed** (one backend reviews), **Council** (both review, you synthesize), **Delegated** (a backend executes a bounded sub-task); the orchestrator always commits, a backend is never autonomous. Pick + plan one for this environment with `/agent-workflow-kit recipes` (read-only); the deployed how/why lives in your `docs/ai/` workflow docs.',
|
|
82
|
+
];
|
|
83
|
+
|
|
60
84
|
// A slot descriptor bundles everything the generic engine needs to operate on ONE marker pair.
|
|
61
85
|
// `leadingBlank` controls whether the inserted empty pair gets a blank separator line above it — the
|
|
62
86
|
// methodology insert keeps it (readability), the orchestration insert omits it to save a cap line
|
|
63
|
-
// (the pair already sits right under the methodology block).
|
|
64
|
-
|
|
87
|
+
// (the pair already sits right under the methodology block). `knownPriorCanonicals` drives the refresh;
|
|
88
|
+
// `upgradeSignature` + `upgradeAdvice` drive the read-only advisory for a CUSTOMIZED (non-matching) slot
|
|
89
|
+
// that predates the current clause.
|
|
90
|
+
export const METHODOLOGY_DESCRIPTOR = {
|
|
65
91
|
startMarker: START_MARKER,
|
|
66
92
|
endMarker: END_MARKER,
|
|
67
93
|
anchor: METHODOLOGY_ANCHOR,
|
|
@@ -69,6 +95,10 @@ const METHODOLOGY_DESCRIPTOR = {
|
|
|
69
95
|
leadingBlank: true,
|
|
70
96
|
markerName: 'methodology',
|
|
71
97
|
anchorLabel: 'methodology anchor (the "Read it before any code change." Session-Protocols line)',
|
|
98
|
+
knownPriorCanonicals: KNOWN_PRIOR_METHODOLOGY_SLOT,
|
|
99
|
+
upgradeSignature: 'Communication',
|
|
100
|
+
upgradeAdvice:
|
|
101
|
+
'the workflow-methodology pointer predates the communication-contract clause (deliver the artifact inline, lead with the result) — refresh it to the current canon, or add the clause by hand; the contract still applies.',
|
|
72
102
|
};
|
|
73
103
|
export const ORCHESTRATION_DESCRIPTOR = {
|
|
74
104
|
startMarker: ORCH_START_MARKER,
|
|
@@ -78,6 +108,10 @@ export const ORCHESTRATION_DESCRIPTOR = {
|
|
|
78
108
|
leadingBlank: false,
|
|
79
109
|
markerName: 'orchestration',
|
|
80
110
|
anchorLabel: 'orchestration anchor (the methodology end-marker line)',
|
|
111
|
+
knownPriorCanonicals: KNOWN_PRIOR_ORCH_SLOT,
|
|
112
|
+
upgradeSignature: '/agent-workflow-kit set-recipe',
|
|
113
|
+
upgradeAdvice:
|
|
114
|
+
'the orchestration-recipes pointer predates the read-at-start clause — add "read `docs/ai/orchestration.json` at session start; set it with /agent-workflow-kit set-recipe", or set your preference now with /agent-workflow-kit set-recipe.',
|
|
81
115
|
};
|
|
82
116
|
|
|
83
117
|
// ── generic marker-slot engine (descriptor-parameterized) ──────────────────────
|
|
@@ -160,16 +194,27 @@ export const ensureMarkerSlot = (text, descriptor) => {
|
|
|
160
194
|
// Bootstrap/upgrade reconciliation policy (pure): ensure the slot exists, then fill it ONLY IF it
|
|
161
195
|
// is empty (a filled/customized slot is preserved verbatim), enforcing the line cap — all as one step
|
|
162
196
|
// the CLI commits with a single atomic write. On ANY error the INPUT bytes are returned unchanged.
|
|
163
|
-
// reconciled-inserted
|
|
164
|
-
// reconciled-filled
|
|
165
|
-
//
|
|
166
|
-
//
|
|
197
|
+
// reconciled-inserted — slot was absent, inserted at the anchor, then filled.
|
|
198
|
+
// reconciled-filled — slot existed but was empty, now filled.
|
|
199
|
+
// reconciled-refreshed — slot was filled with a KNOWN PRIOR canonical → replaced with `fragment`.
|
|
200
|
+
// present-filled — slot already carried CUSTOM content → preserved verbatim.
|
|
201
|
+
// error — malformed slot, 0/>1 anchors, or cap exceeded → input unchanged.
|
|
167
202
|
export const reconcileMarkerSlot = (text, descriptor, fragment, { maxLines } = {}) => {
|
|
168
203
|
const ensured = ensureMarkerSlot(text, descriptor);
|
|
169
204
|
if (ensured.status === 'error') return { status: 'error', text, error: ensured.error };
|
|
170
205
|
const current = extractMarkerSlot(ensured.text, descriptor);
|
|
171
206
|
const isEmpty = current == null || current.trim() === '';
|
|
172
207
|
if (!isEmpty) {
|
|
208
|
+
// Canonical-refresh: a slot whose content normalize-matches a known prior canonical is STALE — replace
|
|
209
|
+
// it with the current `fragment`. A customized slot never matches → preserved verbatim. (`fragment`
|
|
210
|
+
// is empty for a customized slot — main() only sources it when markerSlotNeedsFill is true.)
|
|
211
|
+
const priors = descriptor.knownPriorCanonicals ?? [];
|
|
212
|
+
const matchesPrior = fragment && fragment.trim() !== '' && priors.some((p) => normalizeCanonical(p) === normalizeCanonical(current));
|
|
213
|
+
if (matchesPrior) {
|
|
214
|
+
const injected = injectIntoSlot(ensured.text, descriptor, fragment, { maxLines });
|
|
215
|
+
if (injected.status !== 'injected') return { status: 'error', text, error: injected.error };
|
|
216
|
+
return { status: 'reconciled-refreshed', text: injected.text };
|
|
217
|
+
}
|
|
173
218
|
if (maxLines != null && lineCount(ensured.text) > maxLines) {
|
|
174
219
|
return { status: 'error', text, error: `AGENTS.md is ${lineCount(ensured.text)} lines (cap ${maxLines}) — trim the file (a customized ${descriptor.markerName} slot must still fit the cap)` };
|
|
175
220
|
}
|
|
@@ -189,7 +234,11 @@ export const markerSlotNeedsFill = (text, descriptor) => {
|
|
|
189
234
|
const ensured = ensureMarkerSlot(text, descriptor);
|
|
190
235
|
if (ensured.status === 'error') return false;
|
|
191
236
|
const current = extractMarkerSlot(ensured.text, descriptor);
|
|
192
|
-
|
|
237
|
+
if (current == null || current.trim() === '') return true; // empty → fill
|
|
238
|
+
// filled-but-STALE (content matches a known prior canonical) → needs a refresh, so main() must
|
|
239
|
+
// re-source the fragment. A customized slot doesn't match → no source needed (preserved verbatim).
|
|
240
|
+
const priors = descriptor.knownPriorCanonicals ?? [];
|
|
241
|
+
return priors.some((p) => normalizeCanonical(p) === normalizeCanonical(current));
|
|
193
242
|
};
|
|
194
243
|
|
|
195
244
|
// ── methodology-slot exports (delegate to the generic engine, byte-for-byte) ────
|
|
@@ -217,6 +266,19 @@ export const methodologyProceduresHint = (text) => {
|
|
|
217
266
|
return `the methodology pointer has no procedures route — add "${PROCEDURES_POINTER} <activity>" for auto-discovery; the activity procedures are reachable now via ${PROCEDURES_POINTER}.`;
|
|
218
267
|
};
|
|
219
268
|
|
|
269
|
+
// Generic read-only upgrade advisory (AD-025; the §1.6a/§1.9 reach to CUSTOMIZED filled slots): a slot
|
|
270
|
+
// that is present + FILLED but lacks the descriptor's current-canon `upgradeSignature` (and so could not
|
|
271
|
+
// be canonical-refreshed — its content is customized) gets a one-line note the upgrade flow surfaces.
|
|
272
|
+
// Returns null for an absent / empty / malformed slot, or one that already carries the signature. Pure;
|
|
273
|
+
// never edits the file (a customization is never rewritten — only the user decides).
|
|
274
|
+
export const markerSlotUpgradeHint = (text, descriptor) => {
|
|
275
|
+
if (!descriptor.upgradeSignature) return null;
|
|
276
|
+
const content = extractMarkerSlot(text, descriptor);
|
|
277
|
+
if (content == null || content.trim() === '') return null; // only a FILLED slot
|
|
278
|
+
if (content.includes(descriptor.upgradeSignature)) return null; // already carries the current clause
|
|
279
|
+
return descriptor.upgradeAdvice;
|
|
280
|
+
};
|
|
281
|
+
|
|
220
282
|
// A cap-refusal is a SOFT, reported skip (distinct from a malformed/anchor STOP) — keyed off the
|
|
221
283
|
// stable "(cap N)" substring both cap messages carry, so the dual-slot reconcile can skip the
|
|
222
284
|
// orchestration pointer (loud) while keeping the methodology fill, instead of aborting both.
|
|
@@ -317,18 +379,23 @@ const main = async (argv) => {
|
|
|
317
379
|
console.error(`[inject-methodology] reconcile refused — ${methResult.error}`);
|
|
318
380
|
process.exit(1);
|
|
319
381
|
}
|
|
320
|
-
const afterMeth = methResult.text; // === text when the methodology slot was already filled
|
|
382
|
+
const afterMeth = methResult.text; // === text when the methodology slot was already filled (custom)
|
|
321
383
|
const describeMeth = {
|
|
322
384
|
'reconciled-inserted': 'inserted the workflow-methodology pointer at the Session-Protocols anchor and filled it',
|
|
323
385
|
'reconciled-filled': 'filled the empty workflow-methodology pointer',
|
|
386
|
+
'reconciled-refreshed': 'refreshed the workflow-methodology pointer to the current canon',
|
|
324
387
|
'present-filled': 'workflow-methodology pointer already present',
|
|
325
388
|
}[methResult.status];
|
|
326
|
-
// Read-only upgrade
|
|
327
|
-
//
|
|
328
|
-
//
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
if (
|
|
389
|
+
// Read-only upgrade advisories for a CUSTOMIZED methodology pointer that reconcile preserved verbatim
|
|
390
|
+
// (a refreshed/filled/inserted slot already carries the current canon, so it gets none): the AD-019
|
|
391
|
+
// procedures route AND the §1.9 communication-contract clause. No mutation — reported notes only.
|
|
392
|
+
const notes = [];
|
|
393
|
+
if (methResult.status === 'present-filled') {
|
|
394
|
+
const p = methodologyProceduresHint(afterMeth); if (p) notes.push(p);
|
|
395
|
+
const u = markerSlotUpgradeHint(afterMeth, METHODOLOGY_DESCRIPTOR); if (u) notes.push(u);
|
|
396
|
+
}
|
|
397
|
+
const reportNotes = () => {
|
|
398
|
+
for (const n of notes) console.log(`[inject-methodology] note: ${n}`);
|
|
332
399
|
};
|
|
333
400
|
|
|
334
401
|
// ── Explicit [fragment.md] binds methodology ONLY → skip the orchestration reconcile ──
|
|
@@ -374,8 +441,15 @@ const main = async (argv) => {
|
|
|
374
441
|
describeOrch = {
|
|
375
442
|
'reconciled-inserted': 'inserted the orchestration-recipes pointer below it and filled it',
|
|
376
443
|
'reconciled-filled': 'filled the empty orchestration-recipes pointer',
|
|
444
|
+
'reconciled-refreshed': 'refreshed the orchestration-recipes pointer to the current canon',
|
|
377
445
|
'present-filled': 'orchestration-recipes pointer already present',
|
|
378
446
|
}[orchResult.status];
|
|
447
|
+
// §1.6a advisory: a CUSTOMIZED orchestration pointer preserved verbatim, lacking the read-at-start
|
|
448
|
+
// clause, gets a read-only nudge (a refreshed/filled slot already carries it).
|
|
449
|
+
if (orchResult.status === 'present-filled') {
|
|
450
|
+
const u = markerSlotUpgradeHint(finalText, ORCHESTRATION_DESCRIPTOR);
|
|
451
|
+
if (u) notes.push(u);
|
|
452
|
+
}
|
|
379
453
|
}
|
|
380
454
|
}
|
|
381
455
|
|
|
@@ -384,12 +458,12 @@ const main = async (argv) => {
|
|
|
384
458
|
// Byte-unchanged. Still report a cap-skip (it is not "nothing to do" — a pointer was withheld).
|
|
385
459
|
if (orchSkipped) console.log(`[inject-methodology] reconcile: ${describeMeth}; ${describeOrch}.`);
|
|
386
460
|
else console.log('[inject-methodology] reconcile: both pointers already present and filled — nothing to do (zero-diff).');
|
|
387
|
-
|
|
461
|
+
reportNotes();
|
|
388
462
|
return;
|
|
389
463
|
}
|
|
390
464
|
await writeAtomic(finalText);
|
|
391
465
|
console.log(`[inject-methodology] reconcile: ${describeMeth}; ${describeOrch}.`);
|
|
392
|
-
|
|
466
|
+
reportNotes();
|
|
393
467
|
return;
|
|
394
468
|
}
|
|
395
469
|
|