continuous-improvement 3.12.3 → 3.15.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.
Files changed (127) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +31 -1
  3. package/LICENSE +21 -21
  4. package/QUICKSTART.md +1 -1
  5. package/README.md +25 -5
  6. package/bin/analyze.sh +161 -161
  7. package/bin/backfill.mjs +19 -19
  8. package/bin/check-doc-runtime-claims.mjs +0 -0
  9. package/bin/check-docs-substrings.mjs +0 -0
  10. package/bin/check-everything-mirror.mjs +0 -0
  11. package/bin/check-routing-targets.mjs +0 -0
  12. package/bin/check-scripts-citation-drift.mjs +0 -0
  13. package/bin/check-skill-count.mjs +32 -1
  14. package/bin/check-skill-law-tag.mjs +0 -0
  15. package/bin/check-skill-mirror.mjs +0 -0
  16. package/bin/check-skill-tiers.mjs +0 -0
  17. package/bin/check-test-imports-only.mjs +1 -1
  18. package/bin/check-third-party-shape.mjs +0 -0
  19. package/bin/check-tool-count.mjs +0 -0
  20. package/bin/companion-preference-status.mjs +0 -0
  21. package/bin/gateguard-clear.mjs +0 -0
  22. package/bin/generate-plugin-manifests.mjs +2 -1
  23. package/bin/harvest-friction.mjs +0 -0
  24. package/bin/hook-stats.mjs +21 -21
  25. package/bin/install.mjs +74 -1
  26. package/bin/lint-transcript.mjs +0 -0
  27. package/bin/mcp-server.mjs +65 -8
  28. package/bin/observe.mjs +0 -0
  29. package/bin/plan-pack.mjs +77 -0
  30. package/bin/pre-commit-block-strays.sh +0 -0
  31. package/bin/refresh-third-party.mjs +0 -0
  32. package/bin/unified-cli.mjs +55 -410
  33. package/commands/continuous-improvement.md +115 -115
  34. package/commands/dashboard.md +56 -56
  35. package/commands/model-forward.md +13 -0
  36. package/commands/production-readiness-review.md +53 -0
  37. package/commands/seven-laws.md +16 -16
  38. package/commands/ship.md +57 -0
  39. package/commands/workspace-surface-audit.md +77 -77
  40. package/hooks/companion-preference.mjs +31 -19
  41. package/hooks/gateguard.mjs +38 -16
  42. package/hooks/goal-drift-stop.mjs +0 -0
  43. package/hooks/hook-pack.mjs +110 -0
  44. package/hooks/observe.sh +0 -0
  45. package/hooks/recall-briefing.mjs +0 -0
  46. package/hooks/route-prompt.mjs +0 -0
  47. package/hooks/session.sh +106 -106
  48. package/hooks/three-section-close.mjs +0 -0
  49. package/instinct-packs/go.json +58 -58
  50. package/instinct-packs/meta.json +16 -16
  51. package/instinct-packs/python.json +58 -58
  52. package/instinct-packs/react.json +58 -58
  53. package/lib/cli-anything.mjs +0 -0
  54. package/lib/gateguard-state.mjs +62 -13
  55. package/lib/goal-drift-gate.mjs +0 -0
  56. package/lib/goal-state.mjs +8 -4
  57. package/lib/hook-pack-gate.mjs +65 -0
  58. package/lib/install-targets.mjs +121 -0
  59. package/lib/observe-event.mjs +0 -0
  60. package/lib/plan-review-packet.mjs +96 -0
  61. package/lib/plugin-metadata.mjs +23 -2
  62. package/lib/pm-marketplace.mjs +0 -0
  63. package/lib/recall-briefing.mjs +0 -0
  64. package/lib/recall-index.mjs +0 -0
  65. package/lib/resolve-home-dir.mjs +0 -0
  66. package/lib/skill-distill.mjs +141 -0
  67. package/lib/skill-tiers.mjs +0 -0
  68. package/llms.txt +2 -2
  69. package/package.json +4 -3
  70. package/plugins/beginner.json +2 -2
  71. package/plugins/continuous-improvement/.claude-plugin/marketplace.json +2 -2
  72. package/plugins/continuous-improvement/.claude-plugin/plugin.json +2 -2
  73. package/plugins/continuous-improvement/LICENSE +21 -21
  74. package/plugins/continuous-improvement/README.md +1 -1
  75. package/plugins/continuous-improvement/bin/backfill.mjs +19 -19
  76. package/plugins/continuous-improvement/bin/gateguard-clear.mjs +0 -0
  77. package/plugins/continuous-improvement/bin/mcp-server.mjs +65 -8
  78. package/plugins/continuous-improvement/bin/observe.mjs +0 -0
  79. package/plugins/continuous-improvement/commands/continuous-improvement.md +115 -115
  80. package/plugins/continuous-improvement/commands/dashboard.md +56 -56
  81. package/plugins/continuous-improvement/commands/model-forward.md +13 -0
  82. package/plugins/continuous-improvement/commands/production-readiness-review.md +53 -0
  83. package/plugins/continuous-improvement/commands/seven-laws.md +16 -16
  84. package/plugins/continuous-improvement/commands/ship.md +57 -0
  85. package/plugins/continuous-improvement/commands/workspace-surface-audit.md +77 -77
  86. package/plugins/continuous-improvement/hooks/companion-preference.mjs +31 -19
  87. package/plugins/continuous-improvement/hooks/gateguard.mjs +38 -16
  88. package/plugins/continuous-improvement/hooks/goal-drift-stop.mjs +0 -0
  89. package/plugins/continuous-improvement/hooks/hook-pack.mjs +110 -0
  90. package/plugins/continuous-improvement/hooks/hooks.json +10 -0
  91. package/plugins/continuous-improvement/hooks/observe.sh +0 -0
  92. package/plugins/continuous-improvement/hooks/recall-briefing.mjs +0 -0
  93. package/plugins/continuous-improvement/hooks/route-prompt.mjs +0 -0
  94. package/plugins/continuous-improvement/hooks/session.sh +106 -106
  95. package/plugins/continuous-improvement/hooks/three-section-close.mjs +0 -0
  96. package/plugins/continuous-improvement/instinct-packs/go.json +58 -58
  97. package/plugins/continuous-improvement/instinct-packs/meta.json +16 -16
  98. package/plugins/continuous-improvement/instinct-packs/python.json +58 -58
  99. package/plugins/continuous-improvement/instinct-packs/react.json +58 -58
  100. package/plugins/continuous-improvement/lib/gateguard-state.mjs +62 -13
  101. package/plugins/continuous-improvement/lib/goal-drift-gate.mjs +0 -0
  102. package/plugins/continuous-improvement/lib/goal-state.mjs +8 -4
  103. package/plugins/continuous-improvement/lib/hook-pack-gate.mjs +65 -0
  104. package/plugins/continuous-improvement/lib/observe-event.mjs +0 -0
  105. package/plugins/continuous-improvement/lib/plugin-metadata.mjs +23 -2
  106. package/plugins/continuous-improvement/lib/recall-briefing.mjs +0 -0
  107. package/plugins/continuous-improvement/lib/recall-index.mjs +0 -0
  108. package/plugins/continuous-improvement/lib/resolve-home-dir.mjs +0 -0
  109. package/plugins/continuous-improvement/lib/skill-distill.mjs +141 -0
  110. package/plugins/continuous-improvement/skills/README.md +1 -1
  111. package/plugins/continuous-improvement/skills/gateguard/SKILL.md +4 -4
  112. package/plugins/continuous-improvement/skills/goal-monitor/SKILL.md +1 -1
  113. package/plugins/continuous-improvement/skills/handoff/SKILL.md +0 -1
  114. package/plugins/continuous-improvement/skills/model-forward/SKILL.md +44 -0
  115. package/plugins/continuous-improvement/skills/tdd-workflow/SKILL.md +411 -411
  116. package/plugins/expert.json +5 -1
  117. package/skills/README.md +4 -2
  118. package/skills/gateguard.md +4 -4
  119. package/skills/goal-monitor.md +1 -1
  120. package/skills/handoff.md +0 -1
  121. package/skills/model-forward.md +44 -0
  122. package/skills/tdd-workflow.md +411 -411
  123. package/lib/compound-engineering.mjs +0 -831
  124. package/lib/pm-skills.mjs +0 -1274
  125. package/lib/unified-plugin.mjs +0 -924
  126. package/plugins/continuous-improvement/skills/para-memory-files/SKILL.md +0 -108
  127. package/skills/para-memory-files.md +0 -108
@@ -7,8 +7,8 @@
7
7
  "plugins": [
8
8
  {
9
9
  "name": "continuous-improvement",
10
- "description": "Makes Claude Code reason harder, recall past corrections, and learn from every session so its competence compounds run over run. The Mulahazah engine turns each fix into a reusable instinct, so a lesson learned once is applied automatically next time no re-teaching. Built on the 7 Laws of AI Agent Discipline (research, plan, verify, reflect, learn) and shipped as 25 bundled skills, instinct-aware hooks, an MCP toolset for recall and reflection, and a GitHub Action transcript linter that feeds real work history back into sharper instincts.",
11
- "version": "3.12.3",
10
+ "description": "The persistent-memory and runtime-discipline layer for Claude Code. It remembers the corrections you already gave, grounds every edit in real facts before it lands, and through the Mulahazah engine turns each fix into a reusable instinct, so a lesson learned once is applied automatically next time with no re-teaching. Built on the 7 Laws of AI Agent Discipline (research, plan, verify, reflect, learn) and shipped as 25 bundled skills, instinct-aware hooks, an MCP toolset for recall and reflection, and a GitHub Action transcript linter that feeds real work history back into sharper instincts.",
11
+ "version": "3.15.0",
12
12
  "source": "./plugins/continuous-improvement",
13
13
  "author": {
14
14
  "name": "naimkatiman"
package/CHANGELOG.md CHANGED
@@ -4,7 +4,37 @@ All notable changes to this skill are documented here.
4
4
 
5
5
  ---
6
6
 
7
- ## [Unreleased]
7
+ ## [3.15.0] — 2026-06-21
8
+
9
+ ### Added
10
+
11
+ - **`/ship` cuts one defect from audit to an open PR** — a single-concern fast path that routes `reconcile` → `tdd-workflow` → `verification-loop` → `commit-push-pr` → `deploy-receipt` for one fix, then stops at PR-open. Never auto-merges or deploys. Command-only; `/release-train` remains the multi-PR path. Plan: `docs/plans/2026-06-17-ship-command.md`. (#246)
12
+ - **`/production-readiness-review` fans a blind multi-agent review into one punch-list** — parallel reviewers across performance, security, UI/UX, and test coverage, each grounding findings in real code/logs/live data, reconciled into a deduplicated, severity-ranked list. Report-only; never fixes, merges, or deploys. Plan: `docs/plans/2026-06-17-production-readiness-review-command.md`. (#247)
13
+ - **`hook-pack` enforces push-to-main and commit-size at the tool boundary** — a warn-default PreToolUse hook (Bash-matched so the non-Bash hot path stays cheap; gateguard stays first) that flags a direct `git push` to a protected branch (`main`/`master`/`release/*`) and a `git commit` staging more than 15 files. Mode `CLAUDE_CI_HOOKPACK_GATE=warn|block|off`; warn never blocks, so zero disruption until you opt into `block`. Pure logic in `lib/hook-pack-gate`. Plan: `docs/plans/2026-06-17-enforcing-hook-pack.md`. (#248)
14
+ - **`/plan-pack` turns a plan doc into a commentable review packet for colleague review** — converts a `docs/plans/` doc into a structured packet a colleague can comment on before implementation. (#244)
15
+ - **How-to-best-use guide** mapping the agentic-engineering workflow to the plugin's skills, commands, and hooks (`docs/using-this-plugin.md`). (#245)
16
+
17
+ ## [3.14.0] — 2026-06-14
18
+
19
+ ### Fixed
20
+
21
+ - **Gateguard clearance cap no longer bleeds across concurrent sessions and self-heals instead of needing a manual `rm`** — the per-session clearance state was keyed on the project hash only, so every Claude session on a repo (sequential or concurrent) shared one 50-file counter that only grew; on a multi-Claude host later sessions inherited a near-full gate, and the "start a new session to reset" message did nothing because a new session resolved to the same file. State is now scoped to `~/.claude/instincts/<projectHash>/sessions/<sessionId>/` (the hook reads `session_id` from stdin; ids are sanitized against path traversal), a 12h TTL self-heals a stale state file to empty on load, and the MCP `ci_gateguard_clear` route accepts a `state_path` so it writes to the session-scoped file. The `MAX_CLEARED_FILES` rogue-loop cap still bounds a single session. Plan: `docs/plans/2026-06-14-gateguard-session-scoped-cap.md`. (#242)
22
+
23
+ ## [3.13.0] — 2026-06-10
24
+
25
+ ### Added
26
+
27
+ - **model-forward ships as a default tier-1 skill** — the standing stance that skills are scaffolding which merges into the model over time; durable core = goal-driven execution + guardrails. (#229)
28
+ - **`distill` turns a verified Workflow run into a draft instinct** — the ultracode-to-memory bridge: a completed multi-agent Workflow's verified trajectory becomes a reviewable instinct draft instead of evaporating with the session. (#226)
29
+
30
+ ### Fixed
31
+
32
+ - **PreToolUse hooks no longer flood every session with `Hook JSON output validation failed — (root): Invalid input` errors (twice per tool call)** — `gateguard.mjs` and `companion-preference.mjs` emitted `{"decision":"allow"}` on every allowed call, which was never schema-valid PreToolUse output (the deprecated `decision` enum is `approve | block`), and current Claude Code clients surface the validation failure instead of silently discarding it. Allow is now empty stdout + exit 0; block uses the documented `hookSpecificOutput.permissionDecision: "deny"` shape. (#230)
33
+ - **goal-state keyword extraction works for Korean goals** — a script-aware minimum keyword length (2 for Hangul tokens, 4 elsewhere) stops Korean goal statements from extracting zero keywords and scoring all work as drift.
34
+
35
+ ### Removed
36
+
37
+ - **`ci` toolkit slimmed to CLI-Anything only — Compound Engineering + PM-Skills removed (breaking)** — the published `ci` command dropped its `compound`, `pm`, `learnings`, and `init`/`workflow`/`research`/`planning`/`execution`/`review` subcommands. Compound Engineering overlapped the Mulahazah instinct engine and PM-Skills overlapped the out-of-band `phuryn/pm-skills` marketplace install, so both were tree-shaken; the vestigial `unified-plugin` orchestrator was deleted and `unified-cli` rewritten as a thin front-end over the retained CLI-Anything library (`ci generate <repo>` / `ci list` / `ci config`). Removes ~4,500 LOC of source + tests; `cli-anything` and the build-critical `pm-marketplace` are unchanged. Plan: `docs/plans/2026-06-08-slim-ci-to-cli-anything.md`.
8
38
 
9
39
  ## [3.12.3] — 2026-06-08
10
40
 
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Naim Katiman
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Naim Katiman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/QUICKSTART.md CHANGED
@@ -130,7 +130,7 @@ Corrections drop instinct confidence. Unused instincts decay. The system self-co
130
130
 
131
131
  ## Expert (npx) — only if you want MCP, hooks, or instinct packs
132
132
 
133
- The Beginner path above is enough for most users. Pick this only if you want the MCP tools (18 of them, including `ci_plan_init` / `ci_plan_status` for `task_plan.md`-style planning), the session hooks that feed Mulahazah, or the starter instinct packs.
133
+ The Beginner path above is enough for most users. Pick this only if you want the MCP tools (19 of them, including `ci_plan_init` / `ci_plan_status` for `task_plan.md`-style planning), the session hooks that feed Mulahazah, or the starter instinct packs.
134
134
 
135
135
  Do not run both paths against the same `~/.claude/` — that produces duplicated state. Pick one and stick with it.
136
136
 
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  <h1 align="center">Claude Code that gets sharper every session</h1>
8
8
 
9
9
  <p align="center">
10
- <b>Reasons deeper. Recalls what it already solved. Verifies before "done". Keeps every lesson.</b>
10
+ <b>Remembers what it already solved. Grounds every edit in facts. Verifies before "done". Carries every lesson into the next session.</b>
11
11
  </p>
12
12
 
13
13
  <p align="center">
@@ -36,7 +36,7 @@ Claude Code is powerful but leaves intelligence on the table: it edits before re
36
36
 
37
37
  1. **Before an edit** — [`gateguard`](skills/gateguard.md) ships as a `PreToolUse` hook (`hooks/gateguard.mjs`) that physically blocks `Edit` / `Write` / `MultiEdit` and destructive `Bash` until the agent presents a fact-list investigation.
38
38
  2. **During work** — bundled skills enforce planning, one-thing-at-a-time execution, TDD ([`tdd-workflow`](skills/tdd-workflow.md)), and a six-phase verification ladder ([`verification-loop`](skills/verification-loop.md)) before "done".
39
- 3. **After work** — `/seven-laws` reflection plus the Mulahazah instinct engine capture lessons so the same mistake does not repeat next session.
39
+ 3. **After work** — `/seven-laws` reflection plus the Mulahazah instinct engine capture lessons, and the opt-in [`recall-briefing`](hooks/recall-briefing.mjs) hook resurfaces the most relevant past fix on the next related prompt, so the same mistake does not repeat next session.
40
40
 
41
41
  Beginner install is two slash commands inside Claude Code (no Node, no bash). Expert install adds MCP tools, observation hooks, instinct packs, and a GitHub Action transcript linter for CI.
42
42
 
@@ -86,7 +86,7 @@ You have used Claude Code (or any agentic coding tool) long enough to recognize
86
86
  | 2 | **No shared language** | The agent uses 20 words where 1 would do; jargon decoded fresh every session; variable names drift from domain terms | Law 2 (Plan), Law 7 (Learn) | [`grill-with-docs`](skills/grill-with-docs.md) (writes & maintains `CONTEXT.md`), [`token-budget-advisor`](skills/token-budget-advisor.md), [`strategic-compact`](skills/strategic-compact.md) |
87
87
  | 3 | **No feedback loop** | The code doesn't work — agent claims "done" without running build, tests, or healthcheck | Law 4 (Verify) | [`tdd-workflow`](skills/tdd-workflow.md), [`verification-loop`](skills/verification-loop.md), [`deploy-receipt`](skills/deploy-receipt.md) |
88
88
  | 4 | **Design rot** | Ball-of-mud accelerates — agent bundles three concerns into one PR, stacks untested changes, ignores prior architectural decisions | Law 2 (Plan), Law 3 (One Thing) | [`superpowers:writing-plans`](https://github.com/obra/superpowers/blob/main/skills/writing-plans/SKILL.md), [`safety-guard`](skills/safety-guard.md), [`worktree-safety`](skills/worktree-safety.md), [`wild-risa-balance`](skills/wild-risa-balance.md) |
89
- | 5 | **Forgotten lessons** | Next session starts from zero — prior corrections, decisions, instincts are lost; the same mistake repeats next week | Law 5 (Reflect), Law 7 (Learn) | [`handoff`](skills/handoff.md), [`para-memory-files`](skills/para-memory-files.md), Mulahazah instinct engine |
89
+ | 5 | **Forgotten lessons** | Next session starts from zero — prior corrections, decisions, instincts are lost; the same mistake repeats next week | Law 5 (Reflect), Law 7 (Learn) | [`handoff`](skills/handoff.md), Mulahazah instinct engine |
90
90
 
91
91
  Three of those alignment + reflection skills (`grill-me`, `grill-with-docs`, `handoff`) are MIT-licensed ports from mattpocock/skills; the rest are continuous-improvement-native. Every failure mode has at least one runtime hook or model-side skill that catches it before it lands in the diff.
92
92
 
@@ -138,7 +138,7 @@ V1 honest limitations: the runtime gate is honor-system once the agent flips `_g
138
138
 
139
139
  ### Expert — adds MCP server, observation hooks, and instinct packs
140
140
 
141
- Pick this if you want the MCP tools (18 of them, including `ci_plan_init` / `ci_plan_status` for `task_plan.md`-style planning), the session hooks that feed Mulahazah, and starter packs.
141
+ Pick this if you want the MCP tools (19 of them, including `ci_plan_init` / `ci_plan_status` for `task_plan.md`-style planning), the session hooks that feed Mulahazah, and starter packs.
142
142
 
143
143
  Preconditions: Node 18 / 20 / 22, plus bash on Windows (Git Bash or WSL — `hooks/observe.sh` is a bash script and silently no-ops without it). **`jq` is no longer required**: as of v3.6.0, `observe.sh` prefers the Node observer (`bin/observe.mjs`) which writes the rich event schema natively without external dependencies. The bash thin-schema path is kept as a two-phase shim, so legacy installs that have not re-run `npx continuous-improvement install` since v3.5.x will still degrade silently without `jq` (`winget install jqlang.jq` on Windows, `brew install jq` on macOS, `apt install jq` on Debian/Ubuntu) — re-running the installer is the cleaner fix and removes the dependency entirely. See [CHANGELOG.md](CHANGELOG.md) `[3.6.0]` for the migration details.
144
144
 
@@ -173,6 +173,26 @@ The framework has documented operator-level modes that change hook behavior with
173
173
  | `CLAUDE_GOAL_DRIFT_GATE` | `goal-drift-stop.mjs` (a `Stop` hook) scores each turn's activity against the `## Goal` in `task_plan.md` and acts on drift. `warn` (default) prints a one-line stderr notice and never blocks; `block` re-prompts a substantive wrap-up that has drifted off-goal so the goal gates the close; `off` disables it. Reads the same observation feed as Mulahazah; fails open on any error. | bash/zsh: `export CLAUDE_GOAL_DRIFT_GATE=block` in `~/.bashrc` / `~/.zshrc`. PowerShell: `$env:CLAUDE_GOAL_DRIFT_GATE='block'` (session) or `[Environment]::SetEnvironmentVariable('CLAUDE_GOAL_DRIFT_GATE','block','User')` (persistent). |
174
174
  | `CLAUDE_RECALL_BRIEFING=1` | `hooks/recall-briefing.mjs` (a UserPromptSubmit hook) makes episodic memory proactive: on the first substantive prompt of a session it searches this project's past observations (BM25) and injects a one-time `<system-reminder>` with the most relevant prior activity, so the agent reuses a past fix instead of re-deriving it. Opt-in and default off; it is an amplifier, never a gate — it cannot block a prompt and fails open. The `ci_recall` MCP tool stays available for explicit, deeper searches. | bash/zsh: `export CLAUDE_RECALL_BRIEFING=1` in `~/.bashrc` / `~/.zshrc`. PowerShell: `$env:CLAUDE_RECALL_BRIEFING=1` (session) or `[Environment]::SetEnvironmentVariable('CLAUDE_RECALL_BRIEFING','1','User')` (persistent). |
175
175
 
176
+ ### Works with other agents
177
+
178
+ Claude Code gets the full install (hooks, MCP server, instinct learning). Every other agent platform can still run the 7 Laws as a rules file — one flag writes the skill text into the file that platform reads, at your project root:
179
+
180
+ ```bash
181
+ npx continuous-improvement install --target gemini,codex
182
+ ```
183
+
184
+ | Target | File written |
185
+ |---|---|
186
+ | `gemini` | `GEMINI.md` (Gemini CLI context file) |
187
+ | `codex` | `AGENTS.md` (agents.md standard — also read by opencode, Jules, Cursor ≥0.50) |
188
+ | `cursor` | `.cursor/rules/continuous-improvement.mdc` (`alwaysApply: true`) |
189
+ | `windsurf` | `.windsurf/rules/continuous-improvement.md` |
190
+ | `zed` | `.rules` |
191
+ | `aider` | `CONVENTIONS.md` + a minimal `.aider.conf.yml` if none exists |
192
+ | `copilot` | `.github/copilot-instructions.md` |
193
+
194
+ Shared files (`GEMINI.md`, `AGENTS.md`, `.rules`, `CONVENTIONS.md`, `copilot-instructions.md`) are merged through a managed marker block — your existing content is preserved and reinstalls are idempotent. Targets can be combined freely (`--target claude,gemini,codex` runs the full Claude Code install plus the rules files).
195
+
176
196
  ---
177
197
 
178
198
  ## The 7 Laws
@@ -299,7 +319,7 @@ Authored end-to-end with `/superpowers` and `/proceed-with-the-recommendation`:
299
319
 
300
320
  - [QUICKSTART.md](QUICKSTART.md) — 2-minute setup
301
321
  - [SKILL.md](SKILL.md) — full 7 Laws spec
302
- - [docs/skills.md](docs/skills.md) — full 25-skill catalog
322
+ - [docs/skills.md](docs/skills.md) — full 26-skill catalog
303
323
  - [examples/](examples/) — bug fix, feature build, refactor walkthroughs
304
324
  - [templates/insights-claude-md.md](templates/insights-claude-md.md) — paste-in CLAUDE.md blocks for verification discipline, environment notes, think-before-acting, and git/deploy workflow (sourced from the 28-day usage report)
305
325
  - [CONTRIBUTING.md](CONTRIBUTING.md) — architecture, repo internals, adding a new skill
package/bin/analyze.sh CHANGED
@@ -1,161 +1,161 @@
1
- #!/usr/bin/env bash
2
- # analyze.sh — Read observations.jsonl, detect patterns, create instinct YAML files
3
- # Runs via /continuous-improvement command. Uses claude CLI with Haiku for cost-efficient analysis.
4
-
5
- set -euo pipefail
6
-
7
- INSTINCTS_DIR="${HOME}/.claude/instincts"
8
-
9
- # ---------------------------------------------------------------------------
10
- # Detect project
11
- # ---------------------------------------------------------------------------
12
- PROJECT_ROOT=""
13
- if [[ -n "${CLAUDE_PROJECT_DIR:-}" && -d "${CLAUDE_PROJECT_DIR}" ]]; then
14
- PROJECT_ROOT="${CLAUDE_PROJECT_DIR}"
15
- fi
16
- if [[ -z "$PROJECT_ROOT" ]]; then
17
- PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
18
- fi
19
- if [[ -z "$PROJECT_ROOT" ]]; then
20
- PROJECT_ROOT="global"
21
- fi
22
-
23
- # Use shasum on macOS, sha256sum on Linux
24
- if command -v sha256sum &>/dev/null; then
25
- PROJECT_HASH="$(printf '%s' "$PROJECT_ROOT" | sha256sum | cut -c1-12)"
26
- elif command -v shasum &>/dev/null; then
27
- PROJECT_HASH="$(printf '%s' "$PROJECT_ROOT" | shasum -a 256 | cut -c1-12)"
28
- else
29
- # Fallback: use project root basename if no hashing available
30
- PROJECT_HASH="$(basename "$PROJECT_ROOT" | tr -cd 'a-zA-Z0-9' | cut -c1-12)"
31
- fi
32
- PROJECT_NAME="$(basename "${PROJECT_ROOT%.git}")"
33
- PROJECT_DIR="${INSTINCTS_DIR}/${PROJECT_HASH}"
34
- OBS_FILE="${PROJECT_DIR}/observations.jsonl"
35
-
36
- # ---------------------------------------------------------------------------
37
- # Check observations exist
38
- # ---------------------------------------------------------------------------
39
- if [[ ! -f "$OBS_FILE" ]] || [[ ! -s "$OBS_FILE" ]]; then
40
- echo "No observations found at ${OBS_FILE}"
41
- echo "Use Claude Code with hooks installed to generate observations."
42
- exit 0
43
- fi
44
-
45
- OBS_COUNT=$(wc -l < "$OBS_FILE")
46
- echo "Found ${OBS_COUNT} observations in ${OBS_FILE}"
47
-
48
- if (( OBS_COUNT < 20 )); then
49
- echo "Need at least 20 observations for meaningful analysis. Keep using Claude Code (${OBS_COUNT}/20)."
50
- exit 0
51
- fi
52
-
53
- # ---------------------------------------------------------------------------
54
- # Read existing instincts to avoid duplicates
55
- # ---------------------------------------------------------------------------
56
- EXISTING_INSTINCTS=""
57
- for f in "${PROJECT_DIR}"/*.yaml "${INSTINCTS_DIR}/global"/*.yaml; do
58
- [[ -f "$f" ]] && EXISTING_INSTINCTS="${EXISTING_INSTINCTS}$(cat "$f")"$'\n'
59
- done
60
-
61
- # ---------------------------------------------------------------------------
62
- # Take last 500 observations
63
- # ---------------------------------------------------------------------------
64
- RECENT_OBS=$(tail -500 "$OBS_FILE")
65
-
66
- # ---------------------------------------------------------------------------
67
- # Build analysis prompt
68
- # ---------------------------------------------------------------------------
69
- ANALYSIS_PROMPT="Analyze these Claude Code session observations and extract behavioral patterns as instinct YAML files.
70
-
71
- OBSERVATIONS (JSONL — each line is a tool call):
72
- ${RECENT_OBS}
73
-
74
- EXISTING INSTINCTS (already learned — do NOT duplicate these):
75
- ${EXISTING_INSTINCTS}
76
-
77
- YOUR TASK:
78
- 1. Look for REPEATED PATTERNS — same tool sequence used 3+ times
79
- 2. Look for ERROR-THEN-FIX sequences — tool fails, next tools fix it
80
- 3. Look for TOOL PREFERENCES — one tool consistently chosen over alternatives
81
- 4. Look for WORKFLOW PATTERNS — consistent ordering of operations
82
- 5. Look for USER CORRECTIONS — user says no/stop/don't after an action
83
-
84
- OUTPUT FORMAT — output ONLY new instincts as YAML blocks, separated by ---:
85
-
86
- id: descriptive-kebab-case-id
87
- trigger: \"when [specific situation]\"
88
- confidence: 0.5
89
- domain: workflow|tooling|testing|patterns
90
- source: observation
91
- scope: project
92
- project_id: ${PROJECT_HASH}
93
- created: \"$(date -u +%Y-%m-%d)\"
94
- last_seen: \"$(date -u +%Y-%m-%d)\"
95
- observation_count: [number of times pattern was seen]
96
- ---
97
- [One sentence describing the specific actionable behavior]
98
-
99
- Rules:
100
- - Only create instincts for patterns seen 3+ times
101
- - Start confidence at 0.5 (suggest level)
102
- - Be specific and actionable (not vague advice)
103
- - Different from existing instincts listed above
104
-
105
- If no new patterns are found, output exactly: NO_NEW_PATTERNS
106
-
107
- Output ONLY the YAML blocks or NO_NEW_PATTERNS. No explanation, no preamble."
108
-
109
- # ---------------------------------------------------------------------------
110
- # Run analysis with Haiku
111
- # ---------------------------------------------------------------------------
112
- echo "Analyzing patterns with Haiku..."
113
- RESULT=$(echo "$ANALYSIS_PROMPT" | claude --model haiku --print -p - 2>/dev/null) || {
114
- echo "Analysis failed — claude CLI error. Try running manually."
115
- exit 1
116
- }
117
-
118
- if [[ "$RESULT" == "NO_NEW_PATTERNS" ]] || [[ -z "$RESULT" ]]; then
119
- echo "No new patterns detected yet. Keep using Claude Code — patterns emerge over time."
120
- exit 0
121
- fi
122
-
123
- # ---------------------------------------------------------------------------
124
- # Write instinct YAML files
125
- # ---------------------------------------------------------------------------
126
- mkdir -p "$PROJECT_DIR"
127
-
128
- NEW_COUNT=0
129
- INSTINCT_ID=""
130
- BLOCK=""
131
-
132
- while IFS= read -r line; do
133
- if [[ "$line" == "---" ]] && [[ -n "$BLOCK" ]]; then
134
- if [[ -n "$INSTINCT_ID" ]]; then
135
- DEST="${PROJECT_DIR}/${INSTINCT_ID}.yaml"
136
- printf '%s\n' "$BLOCK" > "$DEST"
137
- echo " + ${INSTINCT_ID} -> ${DEST}"
138
- NEW_COUNT=$((NEW_COUNT + 1))
139
- fi
140
- INSTINCT_ID=""
141
- BLOCK=""
142
- else
143
- BLOCK="${BLOCK}${line}"$'\n'
144
- if [[ "$line" =~ ^id:\ (.+) ]]; then
145
- INSTINCT_ID="${BASH_REMATCH[1]}"
146
- INSTINCT_ID="${INSTINCT_ID//\"/}"
147
- INSTINCT_ID="${INSTINCT_ID//\'/}"
148
- fi
149
- fi
150
- done <<< "$RESULT"
151
-
152
- # Handle last block
153
- if [[ -n "$INSTINCT_ID" ]] && [[ -n "$BLOCK" ]]; then
154
- DEST="${PROJECT_DIR}/${INSTINCT_ID}.yaml"
155
- printf '%s\n' "$BLOCK" > "$DEST"
156
- echo " + ${INSTINCT_ID} -> ${DEST}"
157
- NEW_COUNT=$((NEW_COUNT + 1))
158
- fi
159
-
160
- echo ""
161
- echo "Created ${NEW_COUNT} new instinct(s) in ${PROJECT_DIR}/"
1
+ #!/usr/bin/env bash
2
+ # analyze.sh — Read observations.jsonl, detect patterns, create instinct YAML files
3
+ # Runs via /continuous-improvement command. Uses claude CLI with Haiku for cost-efficient analysis.
4
+
5
+ set -euo pipefail
6
+
7
+ INSTINCTS_DIR="${HOME}/.claude/instincts"
8
+
9
+ # ---------------------------------------------------------------------------
10
+ # Detect project
11
+ # ---------------------------------------------------------------------------
12
+ PROJECT_ROOT=""
13
+ if [[ -n "${CLAUDE_PROJECT_DIR:-}" && -d "${CLAUDE_PROJECT_DIR}" ]]; then
14
+ PROJECT_ROOT="${CLAUDE_PROJECT_DIR}"
15
+ fi
16
+ if [[ -z "$PROJECT_ROOT" ]]; then
17
+ PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
18
+ fi
19
+ if [[ -z "$PROJECT_ROOT" ]]; then
20
+ PROJECT_ROOT="global"
21
+ fi
22
+
23
+ # Use shasum on macOS, sha256sum on Linux
24
+ if command -v sha256sum &>/dev/null; then
25
+ PROJECT_HASH="$(printf '%s' "$PROJECT_ROOT" | sha256sum | cut -c1-12)"
26
+ elif command -v shasum &>/dev/null; then
27
+ PROJECT_HASH="$(printf '%s' "$PROJECT_ROOT" | shasum -a 256 | cut -c1-12)"
28
+ else
29
+ # Fallback: use project root basename if no hashing available
30
+ PROJECT_HASH="$(basename "$PROJECT_ROOT" | tr -cd 'a-zA-Z0-9' | cut -c1-12)"
31
+ fi
32
+ PROJECT_NAME="$(basename "${PROJECT_ROOT%.git}")"
33
+ PROJECT_DIR="${INSTINCTS_DIR}/${PROJECT_HASH}"
34
+ OBS_FILE="${PROJECT_DIR}/observations.jsonl"
35
+
36
+ # ---------------------------------------------------------------------------
37
+ # Check observations exist
38
+ # ---------------------------------------------------------------------------
39
+ if [[ ! -f "$OBS_FILE" ]] || [[ ! -s "$OBS_FILE" ]]; then
40
+ echo "No observations found at ${OBS_FILE}"
41
+ echo "Use Claude Code with hooks installed to generate observations."
42
+ exit 0
43
+ fi
44
+
45
+ OBS_COUNT=$(wc -l < "$OBS_FILE")
46
+ echo "Found ${OBS_COUNT} observations in ${OBS_FILE}"
47
+
48
+ if (( OBS_COUNT < 20 )); then
49
+ echo "Need at least 20 observations for meaningful analysis. Keep using Claude Code (${OBS_COUNT}/20)."
50
+ exit 0
51
+ fi
52
+
53
+ # ---------------------------------------------------------------------------
54
+ # Read existing instincts to avoid duplicates
55
+ # ---------------------------------------------------------------------------
56
+ EXISTING_INSTINCTS=""
57
+ for f in "${PROJECT_DIR}"/*.yaml "${INSTINCTS_DIR}/global"/*.yaml; do
58
+ [[ -f "$f" ]] && EXISTING_INSTINCTS="${EXISTING_INSTINCTS}$(cat "$f")"$'\n'
59
+ done
60
+
61
+ # ---------------------------------------------------------------------------
62
+ # Take last 500 observations
63
+ # ---------------------------------------------------------------------------
64
+ RECENT_OBS=$(tail -500 "$OBS_FILE")
65
+
66
+ # ---------------------------------------------------------------------------
67
+ # Build analysis prompt
68
+ # ---------------------------------------------------------------------------
69
+ ANALYSIS_PROMPT="Analyze these Claude Code session observations and extract behavioral patterns as instinct YAML files.
70
+
71
+ OBSERVATIONS (JSONL — each line is a tool call):
72
+ ${RECENT_OBS}
73
+
74
+ EXISTING INSTINCTS (already learned — do NOT duplicate these):
75
+ ${EXISTING_INSTINCTS}
76
+
77
+ YOUR TASK:
78
+ 1. Look for REPEATED PATTERNS — same tool sequence used 3+ times
79
+ 2. Look for ERROR-THEN-FIX sequences — tool fails, next tools fix it
80
+ 3. Look for TOOL PREFERENCES — one tool consistently chosen over alternatives
81
+ 4. Look for WORKFLOW PATTERNS — consistent ordering of operations
82
+ 5. Look for USER CORRECTIONS — user says no/stop/don't after an action
83
+
84
+ OUTPUT FORMAT — output ONLY new instincts as YAML blocks, separated by ---:
85
+
86
+ id: descriptive-kebab-case-id
87
+ trigger: \"when [specific situation]\"
88
+ confidence: 0.5
89
+ domain: workflow|tooling|testing|patterns
90
+ source: observation
91
+ scope: project
92
+ project_id: ${PROJECT_HASH}
93
+ created: \"$(date -u +%Y-%m-%d)\"
94
+ last_seen: \"$(date -u +%Y-%m-%d)\"
95
+ observation_count: [number of times pattern was seen]
96
+ ---
97
+ [One sentence describing the specific actionable behavior]
98
+
99
+ Rules:
100
+ - Only create instincts for patterns seen 3+ times
101
+ - Start confidence at 0.5 (suggest level)
102
+ - Be specific and actionable (not vague advice)
103
+ - Different from existing instincts listed above
104
+
105
+ If no new patterns are found, output exactly: NO_NEW_PATTERNS
106
+
107
+ Output ONLY the YAML blocks or NO_NEW_PATTERNS. No explanation, no preamble."
108
+
109
+ # ---------------------------------------------------------------------------
110
+ # Run analysis with Haiku
111
+ # ---------------------------------------------------------------------------
112
+ echo "Analyzing patterns with Haiku..."
113
+ RESULT=$(echo "$ANALYSIS_PROMPT" | claude --model haiku --print -p - 2>/dev/null) || {
114
+ echo "Analysis failed — claude CLI error. Try running manually."
115
+ exit 1
116
+ }
117
+
118
+ if [[ "$RESULT" == "NO_NEW_PATTERNS" ]] || [[ -z "$RESULT" ]]; then
119
+ echo "No new patterns detected yet. Keep using Claude Code — patterns emerge over time."
120
+ exit 0
121
+ fi
122
+
123
+ # ---------------------------------------------------------------------------
124
+ # Write instinct YAML files
125
+ # ---------------------------------------------------------------------------
126
+ mkdir -p "$PROJECT_DIR"
127
+
128
+ NEW_COUNT=0
129
+ INSTINCT_ID=""
130
+ BLOCK=""
131
+
132
+ while IFS= read -r line; do
133
+ if [[ "$line" == "---" ]] && [[ -n "$BLOCK" ]]; then
134
+ if [[ -n "$INSTINCT_ID" ]]; then
135
+ DEST="${PROJECT_DIR}/${INSTINCT_ID}.yaml"
136
+ printf '%s\n' "$BLOCK" > "$DEST"
137
+ echo " + ${INSTINCT_ID} -> ${DEST}"
138
+ NEW_COUNT=$((NEW_COUNT + 1))
139
+ fi
140
+ INSTINCT_ID=""
141
+ BLOCK=""
142
+ else
143
+ BLOCK="${BLOCK}${line}"$'\n'
144
+ if [[ "$line" =~ ^id:\ (.+) ]]; then
145
+ INSTINCT_ID="${BASH_REMATCH[1]}"
146
+ INSTINCT_ID="${INSTINCT_ID//\"/}"
147
+ INSTINCT_ID="${INSTINCT_ID//\'/}"
148
+ fi
149
+ fi
150
+ done <<< "$RESULT"
151
+
152
+ # Handle last block
153
+ if [[ -n "$INSTINCT_ID" ]] && [[ -n "$BLOCK" ]]; then
154
+ DEST="${PROJECT_DIR}/${INSTINCT_ID}.yaml"
155
+ printf '%s\n' "$BLOCK" > "$DEST"
156
+ echo " + ${INSTINCT_ID} -> ${DEST}"
157
+ NEW_COUNT=$((NEW_COUNT + 1))
158
+ fi
159
+
160
+ echo ""
161
+ echo "Created ${NEW_COUNT} new instinct(s) in ${PROJECT_DIR}/"
package/bin/backfill.mjs CHANGED
@@ -27,25 +27,25 @@ const args = process.argv.slice(2);
27
27
  const DRY_RUN = args.includes("--dry-run");
28
28
  const HELP = args.includes("--help") || args.includes("-h");
29
29
  if (HELP) {
30
- console.log(`
31
- backfill — Tag legacy thin-schema observation rows.
32
-
33
- Usage:
34
- npx continuous-improvement backfill Tag rows in place
35
- npx continuous-improvement backfill --dry-run Report counts, write nothing
36
-
37
- What it does:
38
- Walks ~/.claude/instincts/<hash>/observations.jsonl files and adds a
39
- schema field ("thin" or "rich") to every row that lacks one. Thin rows
40
- came from the legacy bash fallback (jq missing) and have no input_summary;
41
- rich rows came from the Node observer and have full tool_input.command /
42
- Edit.file_path / etc.
43
-
44
- Output:
45
- - observations.jsonl rewritten in place (original kept as .bak)
46
- - backfill-summary.json with per-project counts
47
-
48
- Idempotent. Always exits 0 — failures go to stderr only.
30
+ console.log(`
31
+ backfill — Tag legacy thin-schema observation rows.
32
+
33
+ Usage:
34
+ npx continuous-improvement backfill Tag rows in place
35
+ npx continuous-improvement backfill --dry-run Report counts, write nothing
36
+
37
+ What it does:
38
+ Walks ~/.claude/instincts/<hash>/observations.jsonl files and adds a
39
+ schema field ("thin" or "rich") to every row that lacks one. Thin rows
40
+ came from the legacy bash fallback (jq missing) and have no input_summary;
41
+ rich rows came from the Node observer and have full tool_input.command /
42
+ Edit.file_path / etc.
43
+
44
+ Output:
45
+ - observations.jsonl rewritten in place (original kept as .bak)
46
+ - backfill-summary.json with per-project counts
47
+
48
+ Idempotent. Always exits 0 — failures go to stderr only.
49
49
  `);
50
50
  process.exit(0);
51
51
  }
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -24,6 +24,11 @@
24
24
  * - plugins/continuous-improvement/.claude-plugin/plugin.json
25
25
  * - package.json
26
26
  * - llms.txt
27
+ * - .cloudplugin/marketplace.json (hand-maintained, not generator-owned)
28
+ *
29
+ * Stat-block files (count lives in a split HTML stat, not the phrase):
30
+ * - docs/landing/index.html — `<span class="v">N</span><span class="k">Bundled skills</span>`
31
+ * (PR #229 found this surface stale at 25 while every phrase file said 26)
27
32
  *
28
33
  * Usage:
29
34
  * node bin/check-skill-count.mjs # Check the current repo
@@ -42,7 +47,9 @@ const CHECKED_FILES = [
42
47
  "plugins/continuous-improvement/.claude-plugin/plugin.json",
43
48
  "package.json",
44
49
  "llms.txt",
50
+ ".cloudplugin/marketplace.json",
45
51
  ];
52
+ const STAT_CHECKED_FILES = ["docs/landing/index.html"];
46
53
  export function countSkills(repoRoot) {
47
54
  const skillsDir = join(repoRoot, BUNDLE_SKILLS_DIR);
48
55
  const entries = readdirSync(skillsDir);
@@ -75,6 +82,24 @@ function checkFile(repoRoot, relPath, expected) {
75
82
  found: staleMatch ? staleMatch[0] : undefined,
76
83
  };
77
84
  }
85
+ function checkStatFile(repoRoot, relPath, expected) {
86
+ let content;
87
+ try {
88
+ content = readFileSync(join(repoRoot, relPath), "utf8");
89
+ }
90
+ catch {
91
+ return { file: relPath, reason: "missing" };
92
+ }
93
+ const expectedPattern = new RegExp(`class="v">${expected}</span><span class="k">Bundled skills`);
94
+ if (expectedPattern.test(content))
95
+ return null;
96
+ const staleMatch = content.match(/class="v">(\d+)<\/span><span class="k">Bundled skills/);
97
+ return {
98
+ file: relPath,
99
+ reason: staleMatch ? "stale" : "missing",
100
+ found: staleMatch ? `${staleMatch[1]} Bundled skills (stat block)` : undefined,
101
+ };
102
+ }
78
103
  function main() {
79
104
  const repoRoot = argv[2] ?? cwd();
80
105
  const expected = countSkills(repoRoot);
@@ -84,8 +109,14 @@ function main() {
84
109
  if (v)
85
110
  violations.push(v);
86
111
  }
112
+ for (const file of STAT_CHECKED_FILES) {
113
+ const v = checkStatFile(repoRoot, file, expected);
114
+ if (v)
115
+ violations.push(v);
116
+ }
117
+ const totalChecked = CHECKED_FILES.length + STAT_CHECKED_FILES.length;
87
118
  if (violations.length === 0) {
88
- console.log(`OK skill-count: all ${CHECKED_FILES.length} description string(s) state "${expected} bundled skills" (matches skills/ source-of-truth).`);
119
+ console.log(`OK skill-count: all ${totalChecked} description string(s) state "${expected} bundled skills" (matches skills/ source-of-truth).`);
89
120
  exit(0);
90
121
  }
91
122
  console.error(`FAIL skill-count: ${violations.length} description string(s) do not state the actual bundled-skill count of ${expected}.`);
File without changes
File without changes
File without changes