incitaciones 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -39,13 +39,10 @@ cd incitaciones
39
39
  **Install options:**
40
40
 
41
41
  ```bash
42
- ./install.sh --bundle essentials # Core prompts only
43
- ./install.sh --bundle planning # Planning workflows
44
- ./install.sh --bundle reviews # Review prompts
45
- ./install.sh --bundle documentation # Documentation tools
42
+ ./install.sh --bundle essentials # Core prompts only (see all 8 bundles: --list)
43
+ ./install.sh --list # Show available prompts and bundles
46
44
  ./install.sh --format commands # Legacy flat-file format for other tools
47
45
  ./install.sh --disable-model-invocation # Require explicit /skill:name usage
48
- ./install.sh --list # Show available prompts
49
46
  ./install.sh --help # Show all options
50
47
  ```
51
48
 
@@ -83,12 +80,12 @@ pi install git:github.com/charly-vibes/incitaciones
83
80
  pi install .
84
81
  ```
85
82
 
86
- The repository includes checked-in pi package resources under `pi-package/`, and the generation step can refresh them when content changes:
83
+ The npm package ships generated pi package resources under `pi-package/`. The directory is **gitignored, not checked in** — CI regenerates it during npm publish (`npm-publish.yml` runs `scripts/generate-pi-resources.mjs` before `npm publish`), so there is nothing to commit. Locally, the pre-push hook runs `just validate-pi-package`, which regenerates and verifies the resources match the manifest:
87
84
 
88
85
  - `pi-package/skills/` — Agent Skills with pi-compatible frontmatter
89
86
  - `pi-package/prompts/` — prompt templates for slash-command shortcuts
90
87
 
91
- After changing distilled content or manifest entries, run `just generate-pi-resources` and commit the updated `pi-package/` files.
88
+ After changing distilled content or manifest entries, you don't need to touch `pi-package/` — it is regenerated and validated automatically (CI on publish, pre-push hook locally). To preview the generated resources manually, run `just generate-pi-resources`.
92
89
 
93
90
  ### Publishing a new version
94
91
 
@@ -31,11 +31,12 @@ Pick the entry level from the request:
31
31
  - Before gathering evidence for any map (and again before rendering), read `references/zoom-levels.md` — per-level evidence collection commands and text rendering formats.
32
32
  - Before any health check or when the user asks about "health", "smells", or refactoring targets, read `references/smell-signatures.md` — anti-pattern proxies, evidence requirements, severity ratings.
33
33
  - Before writing the final output, read `references/report-template.md` — output structure per mode.
34
- - When the user asks for an HTML export or a shareable version of the report, read the "Optional HTML Export" section at the end of `references/report-template.md`.
34
+ - When the user asks for an HTML export or a shareable version of the report, read the "Optional HTML Export" section at the end of `references/report-template.md`; when the request spans multiple reports (batch), also read its "Batch export" section.
35
35
 
36
36
  ## Zoom Discipline
37
37
 
38
- - Offer adjacent levels as follow-ups; never dump all three maps unrequested.
38
+ - Offer adjacent levels as follow-ups; never dump all three maps unrequested. An explicit batch request ("all reports", "map every module") is a user request — the offer-don't-dump rule applies to unprompted follow-ups only (batch procedure in `references/report-template.md`, "Batch export" section).
39
+ - Re-verify every embedded count and fan-in/fan-out number against a fresh command run immediately before writing each report (one consolidated pass per batch is fine) — counts gathered early in a long session drift.
39
40
  - Every claim carries a file reference (`path`, or `path:line` for specific symbols).
40
41
  - State dependency direction explicitly (A → B); never "related to".
41
42
  - Distinguish observed evidence from inference; label inference explicitly.
@@ -48,4 +49,4 @@ Pick the entry level from the request:
48
49
  - Prefer structural facts over narrative: dependency direction, counts, boundaries.
49
50
  - Health-check findings follow the evidence format in `references/smell-signatures.md` (pattern, evidence, quantity, severity) — never unanchored opinions.
50
51
  - Maps are diff-able artifacts: tables and Mermaid, not prose walls.
51
- - HTML export is derived output, produced only on request; the markdown report remains the artifact of record.
52
+ - HTML export is derived output, produced only on request; the markdown report remains the artifact of record. Exports live in `docs/cartography/` as a self-contained directory (index + shared assets); see the "Optional HTML Export" section of `references/report-template.md`.
@@ -60,16 +60,67 @@ One finding block per pattern (format in `smell-signatures.md`), ordered by seve
60
60
 
61
61
  **Adjacent levels offered** — one line each, e.g. "meso map of ledger available on request".
62
62
 
63
+ ## Batch export
64
+
65
+ An explicit batch request ("generate all the reports", "map every module") is a user request — Zoom Discipline's offer-don't-dump rule applies to unprompted follow-ups only.
66
+
67
+ - Enumerate targets from the module inventory. Confirm the list once when it exceeds 3 targets or the scope is ambiguous; proceed unless corrected.
68
+ - One markdown per target in `docs/cartography/` — each the artifact of record for its target. For each, re-verify counts immediately before writing (Zoom Discipline).
69
+ - Include a health report only if the batch request names health/smells.
70
+ - A target too large for one pass: skip it, mark it as "offered — too large for one pass" in the final summary and, when HTML export is part of the batch, in `index.html`. Do not stop the batch to ask.
71
+ - Superseded artifacts from older exports (old-format HTML pages, render scripts): regenerate in place, recommend deleting the superseded script/pages, and never index stale-format files.
72
+ - When HTML export is part of the batch request or separately requested, HTML pages and `index.html` follow the Optional HTML Export section (regenerate the index once at the end, covering all reports).
73
+
63
74
  ## Optional HTML Export
64
75
 
65
- Produce only on request ("export as HTML", "shareable report"). The markdown report is the source of truth; the HTML file is a derived, regenerable view — never hand-edit it, regenerate it from the markdown.
76
+ Produce only on request ("export as HTML", "shareable report"). The markdown report is the source of truth; the HTML files are a derived, regenerable view — never hand-edit them, regenerate them from the markdown.
77
+
78
+ The export is a **self-contained directory**: all pages plus shared assets under one folder, opening correctly via `file://`, offline, with no server, CDN at view time, or build step. JavaScript is permitted only as a local vendored asset (see Diagrams).
79
+
80
+ ### Output directory
81
+
82
+ - All exports live in `docs/cartography/` (create directories as needed). If `docs/` does not already exist in the repo, confirm once with the user before creating it.
83
+ - Pages reference assets with relative paths (`assets/...`), never absolute or remote URLs.
84
+
85
+ ### Files
86
+
87
+ - One page per report: `cartography-<level>-<target>.html` (e.g. `cartography-meso-payments-billing.html`; slugify the target with hyphens, no dots or spaces). The zoom level in the name prevents exports of different levels overwriting each other. Re-exporting the same level+target overwrites the previous file — intended; there is no history.
88
+ - `index.html` — regenerated on every export; never hand-maintained.
89
+ - `assets/mermaid.min.js` — vendored Mermaid v9.4.3 IIFE build, shared by all pages.
90
+
91
+ ### Index
92
+
93
+ Regenerate `index.html` on every export from what is on disk plus what is known this session:
94
+
95
+ - Scan `docs/cartography/*.html` (excluding `index.html`), group entries by zoom level (macro / meso / micro / health), sorted alphabetically.
96
+ - Each entry links to the page and shows its target plus a one-line scope taken from the report header.
97
+ - Also list markdown reports known to this session (the artifact of record), linked with a repo-relative path from the HTML location. Do not invent paths for reports you cannot locate.
98
+ - The template must handle N=1 (a single entry) without looking broken.
99
+ - Deterministic: sorted, no timestamps, no generator metadata.
100
+
101
+ ### Navigation
102
+
103
+ - Every page (including `index.html`) has a plain nav header: `← Index` plus links to parent-context and adjacent-level pages when they exist (meso → its macro page; micro → its macro/meso parent). Relative links only.
104
+ - Static links only — no interactivity. Do not evolve the export into an application — no servers, frameworks, or interactive controls. If live interaction is requested, note it is out of scope for this skill.
105
+
106
+ ### Diagrams
107
+
108
+ - Render Mermaid client-side with the vendored local asset: `<script src="assets/mermaid.min.js"></script>` plus `<pre class="mermaid">` blocks. Use only the v9.x IIFE build (global `mermaid`); v10+ is ESM-only and is blocked by CORS under `file://`.
109
+ - Asset acquisition: on the first export, download `mermaid.min.js` v9.4.3 into `assets/` if absent (e.g. from jsDelivr); reuse thereafter. If the download fails (offline machine), still emit all pages — diagrams degrade to their source in a styled `<pre>` and the report footer notes "diagrams show source; rerun the export with network access to enable rendering". Never fail the whole export because of assets.
110
+ - Every diagram keeps its Mermaid source in `<details><pre class="mermaid-source">` as the no-JS fallback, so nothing is ever blank.
111
+ - Prose stays pre-rendered HTML — do not client-render markdown. The markdown report remains the artifact of record.
112
+
113
+ ### Handoff
114
+
115
+ - Final step of any export (including the first): tell the user to open `docs/cartography/index.html` directly in a browser — `file://` works with no server; diagram rendering is guaranteed by the Diagrams section.
116
+ - Never start a server for static reports unless the user explicitly asks.
66
117
 
67
- Produce ONE self-contained file, `cartography-<level>-<target>.html` (e.g. `cartography-meso-payments-billing.html`; slugify the target with hyphens), next to the markdown report — or, if no report file was written this session, ask the user where to save it (default `docs/`). The zoom level in the name prevents exports of different levels overwriting each other.
118
+ ### Invariants
68
119
 
69
- - **Self-contained:** one inline `<style>` block. No CDN, no external CSS/JS/fonts, no build step, no server. Must open correctly offline.
70
- - **No JavaScript:** diagrams render as styled `<pre>` blocks (text diagrams) or inline SVG producible without new dependencies. Keep the Mermaid source in the file (e.g. `<pre class="mermaid-source">`) so the diagram stays manipulable.
120
+ - **Write HTML directly:** no render scripts, build pipelines, or new dependencies (pandoc etc.) — even in batch mode. The regeneration path is re-running this skill, not a committed pipeline; exception only on explicit user request (note the dependency caveat in the reply).
71
121
  - **Mirror, don't redesign:** same sections, same order, same content as the markdown report. The HTML adds presentation only (readable typography; `prefers-color-scheme` support optional).
72
122
  - **Deterministic:** stable section order, no timestamps, no generator metadata.
73
123
  - **Size guard:** render large reports as-is; never paginate, collapse, or add interactivity.
124
+ - **Commit-able:** reports and `assets/` are self-contained and offline-safe; suggest committing them, never silently gitignore.
74
125
 
75
- Do not evolve the export into an application — no servers, frameworks, or interactive controls. If live interaction is requested, note it is out of scope for this skill.
126
+ Decision record: diagrams use a vendored local Mermaid v9.4.3 IIFE; prose is pre-rendered. Rationale: offline rendering, `file://` compatibility, no ESM/CORS issues. Render scripts and build pipelines are banned because agent-regeneration keeps the navigation/diagram/index guarantees that build scripts historically dropped (wai cartography batch, 2026-09-01: a pandoc pipeline produced 12 pages with zero cross-links and unrendered diagrams).
@@ -32,6 +32,17 @@ Manage `~/.whisper/` — a global, tiered knowledge directory that accumulates o
32
32
 
33
33
  **Worktree slot rule:** `basename $(git rev-parse --git-common-dir 2>/dev/null)` (the `.git` worktree dir name), or `basename $(pwd)` when not in a worktree.
34
34
 
35
+ **Canonical repo key rule — derive it, never invent it:**
36
+
37
+ ```bash
38
+ repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|http://||;s|ssh://||;s|git@||;s|:|/|g;s|\.git$||')
39
+ [ -z "$repo_url" ] && repo_url="local/$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
40
+ ```
41
+
42
+ `git@cv:org/repo.git` → `cv/org/repo`; `https://github.com/u/r` → `github.com/u/r`; no remote → `local/<repo-name>`. Colons always become slashes (keeps keys path-safe). The same key must come out of the same repo on every machine.
43
+
44
+ If a directory keyed some other way already exists for this repo (bare name like `genesis/`, owner-only like `charly-vibes/`, alias host with a colon like `cv:charly-vibes/`), do **not** add a fourth variant — route new knowledge into the canonical key and offer `/w consolidate` to migrate the legacy one.
45
+
35
46
  ## Knowledge Routing
36
47
 
37
48
  When a session learns something worth keeping, route it by scope:
@@ -47,6 +58,7 @@ When a session learns something worth keeping, route it by scope:
47
58
  **Rules:**
48
59
  - **No secrets anywhere.** Never write tokens, keys, passwords, or PII into `~/.whisper/`.
49
60
  - **Extend, don't duplicate.** Append to or correct an existing note rather than creating a new one that says the same thing.
61
+ - **One repo, one key.** If more than one `repos/` directory belongs to the same repo, write into the canonical key and propose `/w consolidate` — never create a new variant.
50
62
  - **Search first.** Before creating a new entry, check if one already exists for the same topic.
51
63
  - If `bd` is not available, everything falls back to `~/.whisper/` files — there's no beads-backed alternative.
52
64
 
@@ -61,6 +73,7 @@ Determine mode from how the skill is triggered:
61
73
  | `/w check` or called by `renew` | **check** |
62
74
  | `/w link [<path>]` or "link plan" | **link** |
63
75
  | `/w decommission` | **decommission** |
76
+ | `/w consolidate` or "dedupe whisper repos" | **consolidate** |
64
77
 
65
78
  See each reference file for the full procedure:
66
79
 
@@ -69,6 +82,7 @@ See each reference file for the full procedure:
69
82
  - `references/status.md`
70
83
  - `references/link.md`
71
84
  - `references/decommission.md`
85
+ - `references/consolidate.md`
72
86
 
73
87
  ## Rules
74
88
 
@@ -6,7 +6,8 @@ Validate the workspace before starting work. Detects stale branch slots and work
6
6
 
7
7
  1. Get repo URL and branch slug:
8
8
  ```bash
9
- repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|git@||;s|\.git$||')
9
+ repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|http://||;s|ssh://||;s|git@||;s|:|/|g;s|\.git$||')
10
+ [ -z "$repo_url" ] && repo_url="local/$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
10
11
  branch=$(git rev-parse --abbrev-ref HEAD)
11
12
  branch_slug=$(echo "$branch" | sed 's|/|--|g')
12
13
  context_path=~/.whisper/repos/"${repo_url}"/branches/"${branch_slug}"/context.md
@@ -0,0 +1,41 @@
1
+ # Consolidate
2
+
3
+ Merge duplicate `~/.whisper/repos/` directories for the same repo into the single canonical key. One repo, one key.
4
+
5
+ ## Why
6
+
7
+ Older sessions keyed repos inconsistently — bare repo name (`genesis/`), owner dir (`charly-vibes/`), ssh-alias host with a colon (`cv:charly-vibes/`), full URL in the wrong shape. The same repo's knowledge ends up scattered across several trees, so `check` and `status` miss notes that exist. Consolidation restores the invariant; the canonical key derivation is defined in SKILL.md.
8
+
9
+ ## Steps
10
+
11
+ 1. **Inventory candidates** — non-canonical top-level entries. Canonical = at least 2 slashes and no colon in the first segment; also flag alias-host dirs (`<alias>:<owner>`):
12
+
13
+ ```bash
14
+ for d in ~/.whisper/repos/*/; do echo "${d#$HOME/.whisper/repos/}"; done
15
+ ```
16
+ A key is a candidate if it has 0 or 1 slashes, or contains `:`.
17
+
18
+ 2. **Derive the canonical target per candidate** — check the actual repo's remote:
19
+
20
+ ```bash
21
+ cd <repo checkout> && git remote get-url origin | sed 's|https://||;s|http://||;s|ssh://||;s|git@||;s|:|/|g;s|\.git$||'
22
+ ```
23
+ If no checkout is reachable for a candidate, leave it in place and report it — never guess the mapping from the name alone.
24
+
25
+ 3. **Produce a migration table and WAIT for approval** — one row per candidate: old key → canonical key, files found, merge conflicts detected. The user must explicitly approve before anything moves. If running non-interactively, output the plan and stop.
26
+
27
+ 4. **Merge per file on approval:**
28
+ - `env.md` — append the candidate's content under a `## Migrated from <old-key>` heading; merge only verbatim-identical lines.
29
+ - `branches/<slug>/*` — if the canonical tree has the same slug, append notes with a provenance heading; otherwise `mv` the whole branch slot into `branches/`.
30
+ - `worktrees/<name>/*` — same rule as branch slots.
31
+ - Never overwrite an existing file silently. Never delete a file.
32
+
33
+ 5. **Clean up** — remove candidate directories only if they are now empty (`rmdir -p --ignore-fail-on-non-empty`). Anything left behind is reported, not deleted.
34
+
35
+ 6. **Verify** — re-run the candidate scan (step 1): nothing non-canonical remains, or every remaining entry is accounted for with a reason. Run the `check` flow for the current repo and confirm it resolves to the canonical tree.
36
+
37
+ ## Rules
38
+
39
+ - Provenance headings are mandatory — the user must be able to trace every merged block back to its original location.
40
+ - `git mv` nothing: `~/.whisper/` is not a git repository. Plain `mv`/append only.
41
+ - If two candidates map to the same canonical key (e.g. `charly-vibes/genesis` and `genesis/`), consolidate them sequentially and re-scan between rounds.
@@ -8,7 +8,8 @@ Safely wind down a worktree or branch: defer open work under the branch epic, re
8
8
 
9
9
  2. Get repo URL and branch slug:
10
10
  ```bash
11
- repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|git@||;s|\.git$||')
11
+ repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|http://||;s|ssh://||;s|git@||;s|:|/|g;s|\.git$||')
12
+ [ -z "$repo_url" ] && repo_url="local/$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
12
13
  branch=$(git rev-parse --abbrev-ref HEAD)
13
14
  branch_slug=$(echo "$branch" | sed 's|/|--|g')
14
15
  branch_dir=~/.whisper/repos/"${repo_url}"/branches/"${branch_slug}"
@@ -20,7 +20,8 @@ Create `~/.whisper/` and the current workspace slot.
20
20
 
21
21
  3. Compute the repo path and branch slug:
22
22
  ```bash
23
- repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|git@||;s|\.git$||')
23
+ repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|http://||;s|ssh://||;s|git@||;s|:|/|g;s|\.git$||')
24
+ [ -z "$repo_url" ] && repo_url="local/$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
24
25
  branch=$(git rev-parse --abbrev-ref HEAD)
25
26
  branch_slug=$(echo "$branch" | sed 's|/|--|g')
26
27
  ```
@@ -10,7 +10,8 @@ This mode is self-contained — it does NOT require `create-plan` to have been u
10
10
 
11
11
  2. Get repo URL and branch slug:
12
12
  ```bash
13
- repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|git@||;s|\.git$||')
13
+ repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|http://||;s|ssh://||;s|git@||;s|:|/|g;s|\.git$||')
14
+ [ -z "$repo_url" ] && repo_url="local/$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
14
15
  branch=$(git rev-parse --abbrev-ref HEAD)
15
16
  branch_slug=$(echo "$branch" | sed 's|/|--|g')
16
17
  branch_dir=~/.whisper/repos/"${repo_url}"/branches/"${branch_slug}"
@@ -6,7 +6,8 @@ Show the state of the current workspace.
6
6
 
7
7
  1. Get repo URL and branch slug:
8
8
  ```bash
9
- repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|git@||;s|\.git$||')
9
+ repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|http://||;s|ssh://||;s|git@||;s|:|/|g;s|\.git$||')
10
+ [ -z "$repo_url" ] && repo_url="local/$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
10
11
  branch=$(git rev-parse --abbrev-ref HEAD)
11
12
  branch_slug=$(echo "$branch" | sed 's|/|--|g')
12
13
  context_path=~/.whisper/repos/"${repo_url}"/branches/"${branch_slug}"/context.md
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incitaciones",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Reusable prompts and skills for CLI LLM tools, with native pi package support.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -37,11 +37,12 @@ Pick the entry level from the request:
37
37
  - Before gathering evidence for any map (and again before rendering), read `references/zoom-levels.md` — per-level evidence collection commands and text rendering formats.
38
38
  - Before any health check or when the user asks about "health", "smells", or refactoring targets, read `references/smell-signatures.md` — anti-pattern proxies, evidence requirements, severity ratings.
39
39
  - Before writing the final output, read `references/report-template.md` — output structure per mode.
40
- - When the user asks for an HTML export or a shareable version of the report, read the "Optional HTML Export" section at the end of `references/report-template.md`.
40
+ - When the user asks for an HTML export or a shareable version of the report, read the "Optional HTML Export" section at the end of `references/report-template.md`; when the request spans multiple reports (batch), also read its "Batch export" section.
41
41
 
42
42
  ## Zoom Discipline
43
43
 
44
- - Offer adjacent levels as follow-ups; never dump all three maps unrequested.
44
+ - Offer adjacent levels as follow-ups; never dump all three maps unrequested. An explicit batch request ("all reports", "map every module") is a user request — the offer-don't-dump rule applies to unprompted follow-ups only (batch procedure in `references/report-template.md`, "Batch export" section).
45
+ - Re-verify every embedded count and fan-in/fan-out number against a fresh command run immediately before writing each report (one consolidated pass per batch is fine) — counts gathered early in a long session drift.
45
46
  - Every claim carries a file reference (`path`, or `path:line` for specific symbols).
46
47
  - State dependency direction explicitly (A → B); never "related to".
47
48
  - Distinguish observed evidence from inference; label inference explicitly.
@@ -54,4 +55,4 @@ Pick the entry level from the request:
54
55
  - Prefer structural facts over narrative: dependency direction, counts, boundaries.
55
56
  - Health-check findings follow the evidence format in `references/smell-signatures.md` (pattern, evidence, quantity, severity) — never unanchored opinions.
56
57
  - Maps are diff-able artifacts: tables and Mermaid, not prose walls.
57
- - HTML export is derived output, produced only on request; the markdown report remains the artifact of record.
58
+ - HTML export is derived output, produced only on request; the markdown report remains the artifact of record. Exports live in `docs/cartography/` as a self-contained directory (index + shared assets); see the "Optional HTML Export" section of `references/report-template.md`.
@@ -60,16 +60,67 @@ One finding block per pattern (format in `smell-signatures.md`), ordered by seve
60
60
 
61
61
  **Adjacent levels offered** — one line each, e.g. "meso map of ledger available on request".
62
62
 
63
+ ## Batch export
64
+
65
+ An explicit batch request ("generate all the reports", "map every module") is a user request — Zoom Discipline's offer-don't-dump rule applies to unprompted follow-ups only.
66
+
67
+ - Enumerate targets from the module inventory. Confirm the list once when it exceeds 3 targets or the scope is ambiguous; proceed unless corrected.
68
+ - One markdown per target in `docs/cartography/` — each the artifact of record for its target. For each, re-verify counts immediately before writing (Zoom Discipline).
69
+ - Include a health report only if the batch request names health/smells.
70
+ - A target too large for one pass: skip it, mark it as "offered — too large for one pass" in the final summary and, when HTML export is part of the batch, in `index.html`. Do not stop the batch to ask.
71
+ - Superseded artifacts from older exports (old-format HTML pages, render scripts): regenerate in place, recommend deleting the superseded script/pages, and never index stale-format files.
72
+ - When HTML export is part of the batch request or separately requested, HTML pages and `index.html` follow the Optional HTML Export section (regenerate the index once at the end, covering all reports).
73
+
63
74
  ## Optional HTML Export
64
75
 
65
- Produce only on request ("export as HTML", "shareable report"). The markdown report is the source of truth; the HTML file is a derived, regenerable view — never hand-edit it, regenerate it from the markdown.
76
+ Produce only on request ("export as HTML", "shareable report"). The markdown report is the source of truth; the HTML files are a derived, regenerable view — never hand-edit them, regenerate them from the markdown.
77
+
78
+ The export is a **self-contained directory**: all pages plus shared assets under one folder, opening correctly via `file://`, offline, with no server, CDN at view time, or build step. JavaScript is permitted only as a local vendored asset (see Diagrams).
79
+
80
+ ### Output directory
81
+
82
+ - All exports live in `docs/cartography/` (create directories as needed). If `docs/` does not already exist in the repo, confirm once with the user before creating it.
83
+ - Pages reference assets with relative paths (`assets/...`), never absolute or remote URLs.
84
+
85
+ ### Files
86
+
87
+ - One page per report: `cartography-<level>-<target>.html` (e.g. `cartography-meso-payments-billing.html`; slugify the target with hyphens, no dots or spaces). The zoom level in the name prevents exports of different levels overwriting each other. Re-exporting the same level+target overwrites the previous file — intended; there is no history.
88
+ - `index.html` — regenerated on every export; never hand-maintained.
89
+ - `assets/mermaid.min.js` — vendored Mermaid v9.4.3 IIFE build, shared by all pages.
90
+
91
+ ### Index
92
+
93
+ Regenerate `index.html` on every export from what is on disk plus what is known this session:
94
+
95
+ - Scan `docs/cartography/*.html` (excluding `index.html`), group entries by zoom level (macro / meso / micro / health), sorted alphabetically.
96
+ - Each entry links to the page and shows its target plus a one-line scope taken from the report header.
97
+ - Also list markdown reports known to this session (the artifact of record), linked with a repo-relative path from the HTML location. Do not invent paths for reports you cannot locate.
98
+ - The template must handle N=1 (a single entry) without looking broken.
99
+ - Deterministic: sorted, no timestamps, no generator metadata.
100
+
101
+ ### Navigation
102
+
103
+ - Every page (including `index.html`) has a plain nav header: `← Index` plus links to parent-context and adjacent-level pages when they exist (meso → its macro page; micro → its macro/meso parent). Relative links only.
104
+ - Static links only — no interactivity. Do not evolve the export into an application — no servers, frameworks, or interactive controls. If live interaction is requested, note it is out of scope for this skill.
105
+
106
+ ### Diagrams
107
+
108
+ - Render Mermaid client-side with the vendored local asset: `<script src="assets/mermaid.min.js"></script>` plus `<pre class="mermaid">` blocks. Use only the v9.x IIFE build (global `mermaid`); v10+ is ESM-only and is blocked by CORS under `file://`.
109
+ - Asset acquisition: on the first export, download `mermaid.min.js` v9.4.3 into `assets/` if absent (e.g. from jsDelivr); reuse thereafter. If the download fails (offline machine), still emit all pages — diagrams degrade to their source in a styled `<pre>` and the report footer notes "diagrams show source; rerun the export with network access to enable rendering". Never fail the whole export because of assets.
110
+ - Every diagram keeps its Mermaid source in `<details><pre class="mermaid-source">` as the no-JS fallback, so nothing is ever blank.
111
+ - Prose stays pre-rendered HTML — do not client-render markdown. The markdown report remains the artifact of record.
112
+
113
+ ### Handoff
114
+
115
+ - Final step of any export (including the first): tell the user to open `docs/cartography/index.html` directly in a browser — `file://` works with no server; diagram rendering is guaranteed by the Diagrams section.
116
+ - Never start a server for static reports unless the user explicitly asks.
66
117
 
67
- Produce ONE self-contained file, `cartography-<level>-<target>.html` (e.g. `cartography-meso-payments-billing.html`; slugify the target with hyphens), next to the markdown report — or, if no report file was written this session, ask the user where to save it (default `docs/`). The zoom level in the name prevents exports of different levels overwriting each other.
118
+ ### Invariants
68
119
 
69
- - **Self-contained:** one inline `<style>` block. No CDN, no external CSS/JS/fonts, no build step, no server. Must open correctly offline.
70
- - **No JavaScript:** diagrams render as styled `<pre>` blocks (text diagrams) or inline SVG producible without new dependencies. Keep the Mermaid source in the file (e.g. `<pre class="mermaid-source">`) so the diagram stays manipulable.
120
+ - **Write HTML directly:** no render scripts, build pipelines, or new dependencies (pandoc etc.) — even in batch mode. The regeneration path is re-running this skill, not a committed pipeline; exception only on explicit user request (note the dependency caveat in the reply).
71
121
  - **Mirror, don't redesign:** same sections, same order, same content as the markdown report. The HTML adds presentation only (readable typography; `prefers-color-scheme` support optional).
72
122
  - **Deterministic:** stable section order, no timestamps, no generator metadata.
73
123
  - **Size guard:** render large reports as-is; never paginate, collapse, or add interactivity.
124
+ - **Commit-able:** reports and `assets/` are self-contained and offline-safe; suggest committing them, never silently gitignore.
74
125
 
75
- Do not evolve the export into an application — no servers, frameworks, or interactive controls. If live interaction is requested, note it is out of scope for this skill.
126
+ Decision record: diagrams use a vendored local Mermaid v9.4.3 IIFE; prose is pre-rendered. Rationale: offline rendering, `file://` compatibility, no ESM/CORS issues. Render scripts and build pipelines are banned because agent-regeneration keeps the navigation/diagram/index guarantees that build scripts historically dropped (wai cartography batch, 2026-09-01: a pandoc pipeline produced 12 pages with zero cross-links and unrendered diagrams).
@@ -38,6 +38,17 @@ Manage `~/.whisper/` — a global, tiered knowledge directory that accumulates o
38
38
 
39
39
  **Worktree slot rule:** `basename $(git rev-parse --git-common-dir 2>/dev/null)` (the `.git` worktree dir name), or `basename $(pwd)` when not in a worktree.
40
40
 
41
+ **Canonical repo key rule — derive it, never invent it:**
42
+
43
+ ```bash
44
+ repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|http://||;s|ssh://||;s|git@||;s|:|/|g;s|\.git$||')
45
+ [ -z "$repo_url" ] && repo_url="local/$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
46
+ ```
47
+
48
+ `git@cv:org/repo.git` → `cv/org/repo`; `https://github.com/u/r` → `github.com/u/r`; no remote → `local/<repo-name>`. Colons always become slashes (keeps keys path-safe). The same key must come out of the same repo on every machine.
49
+
50
+ If a directory keyed some other way already exists for this repo (bare name like `genesis/`, owner-only like `charly-vibes/`, alias host with a colon like `cv:charly-vibes/`), do **not** add a fourth variant — route new knowledge into the canonical key and offer `/w consolidate` to migrate the legacy one.
51
+
41
52
  ## Knowledge Routing
42
53
 
43
54
  When a session learns something worth keeping, route it by scope:
@@ -53,6 +64,7 @@ When a session learns something worth keeping, route it by scope:
53
64
  **Rules:**
54
65
  - **No secrets anywhere.** Never write tokens, keys, passwords, or PII into `~/.whisper/`.
55
66
  - **Extend, don't duplicate.** Append to or correct an existing note rather than creating a new one that says the same thing.
67
+ - **One repo, one key.** If more than one `repos/` directory belongs to the same repo, write into the canonical key and propose `/w consolidate` — never create a new variant.
56
68
  - **Search first.** Before creating a new entry, check if one already exists for the same topic.
57
69
  - If `bd` is not available, everything falls back to `~/.whisper/` files — there's no beads-backed alternative.
58
70
 
@@ -67,6 +79,7 @@ Determine mode from how the skill is triggered:
67
79
  | `/w check` or called by `renew` | **check** |
68
80
  | `/w link [<path>]` or "link plan" | **link** |
69
81
  | `/w decommission` | **decommission** |
82
+ | `/w consolidate` or "dedupe whisper repos" | **consolidate** |
70
83
 
71
84
  See each reference file for the full procedure:
72
85
 
@@ -75,6 +88,7 @@ See each reference file for the full procedure:
75
88
  - `references/status.md`
76
89
  - `references/link.md`
77
90
  - `references/decommission.md`
91
+ - `references/consolidate.md`
78
92
 
79
93
  ## Rules
80
94
 
@@ -6,7 +6,8 @@ Validate the workspace before starting work. Detects stale branch slots and work
6
6
 
7
7
  1. Get repo URL and branch slug:
8
8
  ```bash
9
- repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|git@||;s|\.git$||')
9
+ repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|http://||;s|ssh://||;s|git@||;s|:|/|g;s|\.git$||')
10
+ [ -z "$repo_url" ] && repo_url="local/$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
10
11
  branch=$(git rev-parse --abbrev-ref HEAD)
11
12
  branch_slug=$(echo "$branch" | sed 's|/|--|g')
12
13
  context_path=~/.whisper/repos/"${repo_url}"/branches/"${branch_slug}"/context.md
@@ -0,0 +1,41 @@
1
+ # Consolidate
2
+
3
+ Merge duplicate `~/.whisper/repos/` directories for the same repo into the single canonical key. One repo, one key.
4
+
5
+ ## Why
6
+
7
+ Older sessions keyed repos inconsistently — bare repo name (`genesis/`), owner dir (`charly-vibes/`), ssh-alias host with a colon (`cv:charly-vibes/`), full URL in the wrong shape. The same repo's knowledge ends up scattered across several trees, so `check` and `status` miss notes that exist. Consolidation restores the invariant; the canonical key derivation is defined in SKILL.md.
8
+
9
+ ## Steps
10
+
11
+ 1. **Inventory candidates** — non-canonical top-level entries. Canonical = at least 2 slashes and no colon in the first segment; also flag alias-host dirs (`<alias>:<owner>`):
12
+
13
+ ```bash
14
+ for d in ~/.whisper/repos/*/; do echo "${d#$HOME/.whisper/repos/}"; done
15
+ ```
16
+ A key is a candidate if it has 0 or 1 slashes, or contains `:`.
17
+
18
+ 2. **Derive the canonical target per candidate** — check the actual repo's remote:
19
+
20
+ ```bash
21
+ cd <repo checkout> && git remote get-url origin | sed 's|https://||;s|http://||;s|ssh://||;s|git@||;s|:|/|g;s|\.git$||'
22
+ ```
23
+ If no checkout is reachable for a candidate, leave it in place and report it — never guess the mapping from the name alone.
24
+
25
+ 3. **Produce a migration table and WAIT for approval** — one row per candidate: old key → canonical key, files found, merge conflicts detected. The user must explicitly approve before anything moves. If running non-interactively, output the plan and stop.
26
+
27
+ 4. **Merge per file on approval:**
28
+ - `env.md` — append the candidate's content under a `## Migrated from <old-key>` heading; merge only verbatim-identical lines.
29
+ - `branches/<slug>/*` — if the canonical tree has the same slug, append notes with a provenance heading; otherwise `mv` the whole branch slot into `branches/`.
30
+ - `worktrees/<name>/*` — same rule as branch slots.
31
+ - Never overwrite an existing file silently. Never delete a file.
32
+
33
+ 5. **Clean up** — remove candidate directories only if they are now empty (`rmdir -p --ignore-fail-on-non-empty`). Anything left behind is reported, not deleted.
34
+
35
+ 6. **Verify** — re-run the candidate scan (step 1): nothing non-canonical remains, or every remaining entry is accounted for with a reason. Run the `check` flow for the current repo and confirm it resolves to the canonical tree.
36
+
37
+ ## Rules
38
+
39
+ - Provenance headings are mandatory — the user must be able to trace every merged block back to its original location.
40
+ - `git mv` nothing: `~/.whisper/` is not a git repository. Plain `mv`/append only.
41
+ - If two candidates map to the same canonical key (e.g. `charly-vibes/genesis` and `genesis/`), consolidate them sequentially and re-scan between rounds.
@@ -8,7 +8,8 @@ Safely wind down a worktree or branch: defer open work under the branch epic, re
8
8
 
9
9
  2. Get repo URL and branch slug:
10
10
  ```bash
11
- repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|git@||;s|\.git$||')
11
+ repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|http://||;s|ssh://||;s|git@||;s|:|/|g;s|\.git$||')
12
+ [ -z "$repo_url" ] && repo_url="local/$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
12
13
  branch=$(git rev-parse --abbrev-ref HEAD)
13
14
  branch_slug=$(echo "$branch" | sed 's|/|--|g')
14
15
  branch_dir=~/.whisper/repos/"${repo_url}"/branches/"${branch_slug}"
@@ -20,7 +20,8 @@ Create `~/.whisper/` and the current workspace slot.
20
20
 
21
21
  3. Compute the repo path and branch slug:
22
22
  ```bash
23
- repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|git@||;s|\.git$||')
23
+ repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|http://||;s|ssh://||;s|git@||;s|:|/|g;s|\.git$||')
24
+ [ -z "$repo_url" ] && repo_url="local/$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
24
25
  branch=$(git rev-parse --abbrev-ref HEAD)
25
26
  branch_slug=$(echo "$branch" | sed 's|/|--|g')
26
27
  ```
@@ -10,7 +10,8 @@ This mode is self-contained — it does NOT require `create-plan` to have been u
10
10
 
11
11
  2. Get repo URL and branch slug:
12
12
  ```bash
13
- repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|git@||;s|\.git$||')
13
+ repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|http://||;s|ssh://||;s|git@||;s|:|/|g;s|\.git$||')
14
+ [ -z "$repo_url" ] && repo_url="local/$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
14
15
  branch=$(git rev-parse --abbrev-ref HEAD)
15
16
  branch_slug=$(echo "$branch" | sed 's|/|--|g')
16
17
  branch_dir=~/.whisper/repos/"${repo_url}"/branches/"${branch_slug}"
@@ -6,7 +6,8 @@ Show the state of the current workspace.
6
6
 
7
7
  1. Get repo URL and branch slug:
8
8
  ```bash
9
- repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|git@||;s|\.git$||')
9
+ repo_url=$(git remote get-url origin 2>/dev/null | sed 's|https://||;s|http://||;s|ssh://||;s|git@||;s|:|/|g;s|\.git$||')
10
+ [ -z "$repo_url" ] && repo_url="local/$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
10
11
  branch=$(git rev-parse --abbrev-ref HEAD)
11
12
  branch_slug=$(echo "$branch" | sed 's|/|--|g')
12
13
  context_path=~/.whisper/repos/"${repo_url}"/branches/"${branch_slug}"/context.md