@hanzlaa/rcode 2.5.0 → 2.6.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/cli/uninstall.js +62 -2
- package/dist/rcode.js +37 -2
- package/package.json +1 -1
- package/rihal/workflows/init.md +10 -0
- package/rihal/workflows/scan.md +160 -8
package/cli/uninstall.js
CHANGED
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
* --editor=claude|cursor|windsurf|antigravity|all Limit scope
|
|
18
18
|
* --keep-state Never touch .rihal/
|
|
19
19
|
* --delete-state Also delete .rihal/ (skip prompt)
|
|
20
|
+
* --purge / --all Wipe everything — editor files,
|
|
21
|
+
* .rihal/, .planning/, gitignore block.
|
|
22
|
+
* Use when you want /rihal:init to
|
|
23
|
+
* report "fresh" on next install.
|
|
20
24
|
* --yes / -y Skip the main confirmation
|
|
21
25
|
*/
|
|
22
26
|
|
|
@@ -32,6 +36,7 @@ function parseArgs(args) {
|
|
|
32
36
|
keepState: false, // if true, never delete .rihal/
|
|
33
37
|
deleteState: false, // if true, delete .rihal/ without prompting
|
|
34
38
|
yes: false, // skip the main confirmation
|
|
39
|
+
purge: false, // wipe everything: editor files + .rihal/ + .planning/ + gitignore block
|
|
35
40
|
};
|
|
36
41
|
for (const arg of args) {
|
|
37
42
|
if (arg.startsWith('--editor=')) {
|
|
@@ -42,6 +47,11 @@ function parseArgs(args) {
|
|
|
42
47
|
opts.deleteState = true;
|
|
43
48
|
} else if (arg === '--yes' || arg === '-y') {
|
|
44
49
|
opts.yes = true;
|
|
50
|
+
} else if (arg === '--purge' || arg === '--all') {
|
|
51
|
+
// --purge implies --delete-state and removes .planning/ + gitignore block.
|
|
52
|
+
// Use this when you want a clean slate so /rihal:init reports "fresh" next time.
|
|
53
|
+
opts.purge = true;
|
|
54
|
+
opts.deleteState = true;
|
|
45
55
|
}
|
|
46
56
|
}
|
|
47
57
|
return opts;
|
|
@@ -365,9 +375,14 @@ async function runUninstall(args) {
|
|
|
365
375
|
console.log();
|
|
366
376
|
|
|
367
377
|
// Fast path: is Rihal Code installed here at all? Check our own marker
|
|
368
|
-
// (.rihal/config.
|
|
378
|
+
// (.rihal/config.yaml) + any editor install trace. If nothing, exit cleanly
|
|
369
379
|
// with a clear message so users don't wonder "did it work?"
|
|
370
|
-
|
|
380
|
+
// (Was checking config.json — a long-standing typo since the installer
|
|
381
|
+
// writes config.yaml. The check still worked thanks to the editor-files
|
|
382
|
+
// fallback, but a project with .rihal/ and no editor files would falsely
|
|
383
|
+
// report "not installed".)
|
|
384
|
+
const hasConfig = fs.existsSync(path.join(cwd, '.rihal/config.yaml'))
|
|
385
|
+
|| fs.existsSync(path.join(cwd, '.rihal/config.json'));
|
|
371
386
|
const hasAnyEditorFiles =
|
|
372
387
|
fs.existsSync(path.join(cwd, '.claude/skills')) ||
|
|
373
388
|
fs.existsSync(path.join(cwd, '.cursor/rules')) ||
|
|
@@ -565,9 +580,14 @@ async function runUninstall(args) {
|
|
|
565
580
|
if (!opts.deleteState && !opts.keepState && !opts.yes) {
|
|
566
581
|
console.log();
|
|
567
582
|
console.log(`⚠️ The .rihal/ state directory contains your project data:`);
|
|
583
|
+
console.log(` - config.yaml, state.json, RIHLA.md`);
|
|
568
584
|
console.log(` - phases, decisions, progress, artifacts, context`);
|
|
569
585
|
console.log(` - ${plan.stateDir.files} files total`);
|
|
570
586
|
console.log();
|
|
587
|
+
console.log(` If you keep it: /rihal:init will report "already configured"`);
|
|
588
|
+
console.log(` and reuse your existing config + history on next install.`);
|
|
589
|
+
console.log(` If you delete it: next install starts fresh — no carry-over.`);
|
|
590
|
+
console.log();
|
|
571
591
|
shouldDeleteState = await askConfirm(
|
|
572
592
|
`Also delete .rihal/ state? This is destructive and cannot be undone. [y/N] `,
|
|
573
593
|
{ default: 'n' },
|
|
@@ -582,11 +602,51 @@ async function runUninstall(args) {
|
|
|
582
602
|
}
|
|
583
603
|
}
|
|
584
604
|
|
|
605
|
+
// --purge: also wipe .planning/ artifacts and the rcode .gitignore block.
|
|
606
|
+
// Without this, "uninstall + reinstall" carries forward stale phases /
|
|
607
|
+
// sprints / SUMMARY files even after .rihal/ is gone.
|
|
608
|
+
if (opts.purge) {
|
|
609
|
+
const planningDir = path.join(cwd, '.planning');
|
|
610
|
+
if (fs.existsSync(planningDir)) {
|
|
611
|
+
fs.rmSync(planningDir, { recursive: true, force: true });
|
|
612
|
+
console.log(` ✓ removed .planning/ (--purge)`);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// Strip the rcode-managed block from .gitignore. The installer writes
|
|
616
|
+
// a fenced block; we remove it cleanly without touching user lines.
|
|
617
|
+
const gitignorePath = path.join(cwd, '.gitignore');
|
|
618
|
+
if (fs.existsSync(gitignorePath)) {
|
|
619
|
+
try {
|
|
620
|
+
const before = fs.readFileSync(gitignorePath, 'utf8');
|
|
621
|
+
// Match either fenced markers or the legacy "# rcode" header through to
|
|
622
|
+
// the next blank line — both shapes the installer has used historically.
|
|
623
|
+
const stripped = before
|
|
624
|
+
.replace(/\n?# >>> rihal-code >>>[\s\S]*?# <<< rihal-code <<<\n?/g, '\n')
|
|
625
|
+
.replace(/\n?# rcode[\s\S]*?(?=\n\n|\n$|$)/g, '\n')
|
|
626
|
+
.replace(/\n{3,}/g, '\n\n');
|
|
627
|
+
if (stripped !== before) {
|
|
628
|
+
fs.writeFileSync(gitignorePath, stripped);
|
|
629
|
+
console.log(` ✓ stripped rcode block from .gitignore (--purge)`);
|
|
630
|
+
}
|
|
631
|
+
} catch (err) {
|
|
632
|
+
console.log(` ⚠ could not strip .gitignore block: ${err.message}`);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
585
637
|
console.log(`\n✅ Uninstall complete. Removed ${removed} files.`);
|
|
586
638
|
if (backup.ok) {
|
|
587
639
|
console.log(` Backup: ${backup.path} (restore with: tar -xzf ${backup.path})`);
|
|
588
640
|
}
|
|
589
641
|
|
|
642
|
+
// Hint about the purge flag if the user kept state — closes the user's
|
|
643
|
+
// most common confusion: "I uninstalled but /rihal:init still says configured."
|
|
644
|
+
if (plan.stateDir && fs.existsSync(path.join(cwd, '.rihal'))) {
|
|
645
|
+
console.log();
|
|
646
|
+
console.log(`ℹ .rihal/ state was preserved. /rihal:init will detect this on reinstall.`);
|
|
647
|
+
console.log(` For a fully clean slate next time, use: rcode uninstall --purge`);
|
|
648
|
+
}
|
|
649
|
+
|
|
590
650
|
// Hint about reinstalling
|
|
591
651
|
console.log(`\nTo reinstall later:`);
|
|
592
652
|
console.log(` rcode install`);
|
package/dist/rcode.js
CHANGED
|
@@ -17865,8 +17865,10 @@ var require_uninstall = __commonJS({
|
|
|
17865
17865
|
// if true, never delete .rihal/
|
|
17866
17866
|
deleteState: false,
|
|
17867
17867
|
// if true, delete .rihal/ without prompting
|
|
17868
|
-
yes: false
|
|
17868
|
+
yes: false,
|
|
17869
17869
|
// skip the main confirmation
|
|
17870
|
+
purge: false
|
|
17871
|
+
// wipe everything: editor files + .rihal/ + .planning/ + gitignore block
|
|
17870
17872
|
};
|
|
17871
17873
|
for (const arg of args) {
|
|
17872
17874
|
if (arg.startsWith("--editor=")) {
|
|
@@ -17877,6 +17879,9 @@ var require_uninstall = __commonJS({
|
|
|
17877
17879
|
opts.deleteState = true;
|
|
17878
17880
|
} else if (arg === "--yes" || arg === "-y") {
|
|
17879
17881
|
opts.yes = true;
|
|
17882
|
+
} else if (arg === "--purge" || arg === "--all") {
|
|
17883
|
+
opts.purge = true;
|
|
17884
|
+
opts.deleteState = true;
|
|
17880
17885
|
}
|
|
17881
17886
|
}
|
|
17882
17887
|
return opts;
|
|
@@ -18109,7 +18114,7 @@ var require_uninstall = __commonJS({
|
|
|
18109
18114
|
console.log(` Project: ${cwd}`);
|
|
18110
18115
|
console.log(` Scope: ${editors.join(", ")}`);
|
|
18111
18116
|
console.log();
|
|
18112
|
-
const hasConfig = fs2.existsSync(path2.join(cwd, ".rihal/config.json"));
|
|
18117
|
+
const hasConfig = fs2.existsSync(path2.join(cwd, ".rihal/config.yaml")) || fs2.existsSync(path2.join(cwd, ".rihal/config.json"));
|
|
18113
18118
|
const hasAnyEditorFiles = fs2.existsSync(path2.join(cwd, ".claude/skills")) || fs2.existsSync(path2.join(cwd, ".cursor/rules")) || fs2.existsSync(path2.join(cwd, ".windsurf/rules")) || fs2.existsSync(path2.join(cwd, ".antigravity/agents"));
|
|
18114
18119
|
if (!hasConfig && !hasAnyEditorFiles) {
|
|
18115
18120
|
console.log(`
|
|
@@ -18274,9 +18279,14 @@ var require_uninstall = __commonJS({
|
|
|
18274
18279
|
if (!opts.deleteState && !opts.keepState && !opts.yes) {
|
|
18275
18280
|
console.log();
|
|
18276
18281
|
console.log(`\u26A0\uFE0F The .rihal/ state directory contains your project data:`);
|
|
18282
|
+
console.log(` - config.yaml, state.json, RIHLA.md`);
|
|
18277
18283
|
console.log(` - phases, decisions, progress, artifacts, context`);
|
|
18278
18284
|
console.log(` - ${plan.stateDir.files} files total`);
|
|
18279
18285
|
console.log();
|
|
18286
|
+
console.log(` If you keep it: /rihal:init will report "already configured"`);
|
|
18287
|
+
console.log(` and reuse your existing config + history on next install.`);
|
|
18288
|
+
console.log(` If you delete it: next install starts fresh \u2014 no carry-over.`);
|
|
18289
|
+
console.log();
|
|
18280
18290
|
shouldDeleteState = await askConfirm(
|
|
18281
18291
|
`Also delete .rihal/ state? This is destructive and cannot be undone. [y/N] `,
|
|
18282
18292
|
{ default: "n" }
|
|
@@ -18289,11 +18299,36 @@ var require_uninstall = __commonJS({
|
|
|
18289
18299
|
console.log(` \u2139 kept .rihal/ state directory (your project data is preserved)`);
|
|
18290
18300
|
}
|
|
18291
18301
|
}
|
|
18302
|
+
if (opts.purge) {
|
|
18303
|
+
const planningDir = path2.join(cwd, ".planning");
|
|
18304
|
+
if (fs2.existsSync(planningDir)) {
|
|
18305
|
+
fs2.rmSync(planningDir, { recursive: true, force: true });
|
|
18306
|
+
console.log(` \u2713 removed .planning/ (--purge)`);
|
|
18307
|
+
}
|
|
18308
|
+
const gitignorePath = path2.join(cwd, ".gitignore");
|
|
18309
|
+
if (fs2.existsSync(gitignorePath)) {
|
|
18310
|
+
try {
|
|
18311
|
+
const before = fs2.readFileSync(gitignorePath, "utf8");
|
|
18312
|
+
const stripped = before.replace(/\n?# >>> rihal-code >>>[\s\S]*?# <<< rihal-code <<<\n?/g, "\n").replace(/\n?# rcode[\s\S]*?(?=\n\n|\n$|$)/g, "\n").replace(/\n{3,}/g, "\n\n");
|
|
18313
|
+
if (stripped !== before) {
|
|
18314
|
+
fs2.writeFileSync(gitignorePath, stripped);
|
|
18315
|
+
console.log(` \u2713 stripped rcode block from .gitignore (--purge)`);
|
|
18316
|
+
}
|
|
18317
|
+
} catch (err) {
|
|
18318
|
+
console.log(` \u26A0 could not strip .gitignore block: ${err.message}`);
|
|
18319
|
+
}
|
|
18320
|
+
}
|
|
18321
|
+
}
|
|
18292
18322
|
console.log(`
|
|
18293
18323
|
\u2705 Uninstall complete. Removed ${removed} files.`);
|
|
18294
18324
|
if (backup.ok) {
|
|
18295
18325
|
console.log(` Backup: ${backup.path} (restore with: tar -xzf ${backup.path})`);
|
|
18296
18326
|
}
|
|
18327
|
+
if (plan.stateDir && fs2.existsSync(path2.join(cwd, ".rihal"))) {
|
|
18328
|
+
console.log();
|
|
18329
|
+
console.log(`\u2139 .rihal/ state was preserved. /rihal:init will detect this on reinstall.`);
|
|
18330
|
+
console.log(` For a fully clean slate next time, use: rcode uninstall --purge`);
|
|
18331
|
+
}
|
|
18297
18332
|
console.log(`
|
|
18298
18333
|
To reinstall later:`);
|
|
18299
18334
|
console.log(` rcode install`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzlaa/rcode",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Rihal Code (rcode) — installable context-brain for Rihalians. 43 agents, 99 slash commands, 56 skills, pullable Rihal standards. Unified install for Claude Code, Cursor, and Gemini.",
|
|
5
5
|
"main": "cli/index.js",
|
|
6
6
|
"bin": {
|
package/rihal/workflows/init.md
CHANGED
|
@@ -128,6 +128,16 @@ test -f .rihal/state.json || node .rihal/bin/rihal-tools.cjs state init --projec
|
|
|
128
128
|
|
|
129
129
|
If the project has code (from Step 1 detection), produce `.rihal/RIHLA.md`. This is the journey baseline — a lightweight snapshot, not a full audit. Use `/rihal:map-codebase` or `/rihal:scan` later for deep analysis.
|
|
130
130
|
|
|
131
|
+
**Memory-bank refresh on `--reset`.** When `--reset` is passed AND `.planning/codebase/` already contains docs from a previous scan, also chain to `/rihal:scan --refresh --focus tech+arch` immediately after writing RIHLA.md. The refresh path:
|
|
132
|
+
|
|
133
|
+
- Captures pre-state (commits since last doc mtime, manifest hashes, top-level dirs).
|
|
134
|
+
- Briefs the user on what changed since the last scan.
|
|
135
|
+
- Overwrites the docs and appends an entry to `.planning/codebase/CHANGELOG.md`.
|
|
136
|
+
|
|
137
|
+
Skip the chain if `--skip-scan` is set, no existing docs are present (nothing stale to refresh), or the user passes `--no-refresh`.
|
|
138
|
+
|
|
139
|
+
This makes init+reset a true memory-bank refresh — RIHLA baseline updated, codebase docs reconciled with current code, CHANGELOG entry written.
|
|
140
|
+
|
|
131
141
|
Gather (parallel reads, all bounded):
|
|
132
142
|
|
|
133
143
|
```bash
|
package/rihal/workflows/scan.md
CHANGED
|
@@ -20,7 +20,7 @@ If `$ARGUMENTS` is empty or contains only `--help` or `-h`:
|
|
|
20
20
|
|
|
21
21
|
**Usage:**
|
|
22
22
|
```
|
|
23
|
-
/rihal:scan [--focus tech|arch|quality|concerns|tech+arch]
|
|
23
|
+
/rihal:scan [--focus tech|arch|quality|concerns|tech+arch] [--refresh] [--reset]
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
**Examples:**
|
|
@@ -28,8 +28,20 @@ If `$ARGUMENTS` is empty or contains only `--help` or `-h`:
|
|
|
28
28
|
/rihal:scan --focus tech
|
|
29
29
|
/rihal:scan --focus arch
|
|
30
30
|
/rihal:scan --focus tech+arch
|
|
31
|
+
/rihal:scan --refresh # auto-update stale docs, brief diff, log to CHANGELOG.md
|
|
32
|
+
/rihal:scan --reset --focus tech+arch # silent overwrite (CI / autonomous)
|
|
31
33
|
```
|
|
32
34
|
|
|
35
|
+
**Refresh flag — memory-bank pattern.** When `--refresh` is passed AND existing docs are present, the orchestrator:
|
|
36
|
+
|
|
37
|
+
1. Captures a *pre-state snapshot* (top-level dirs, manifests, dep counts, file counts, git HEAD).
|
|
38
|
+
2. Reads the oldest existing target doc's mtime — anchor for "changes since last scan".
|
|
39
|
+
3. Runs git log + dir diff + manifest diff against that anchor.
|
|
40
|
+
4. Spawns Dalil with the diff context, instructs him to overwrite docs AND prepend a "Changes since last scan" section to each.
|
|
41
|
+
5. Appends a structured entry to `.planning/codebase/CHANGELOG.md` with the brief.
|
|
42
|
+
|
|
43
|
+
This is the canonical way to keep the memory bank fresh without losing the audit trail of what changed and why.
|
|
44
|
+
|
|
33
45
|
<process>
|
|
34
46
|
|
|
35
47
|
## Focus-to-Document Mapping
|
|
@@ -48,7 +60,11 @@ Parse the user's input for `--focus <area>`. Default to `tech+arch` if not speci
|
|
|
48
60
|
|
|
49
61
|
Validate that the focus is one of: `tech`, `arch`, `quality`, `concerns`, `tech+arch`.
|
|
50
62
|
|
|
51
|
-
|
|
63
|
+
Also parse:
|
|
64
|
+
- `--refresh` → auto-update mode (briefs the user on what changed, then overwrites)
|
|
65
|
+
- `--reset` → silent overwrite (no prompt, no brief — for CI / autonomous chains)
|
|
66
|
+
|
|
67
|
+
If invalid focus:
|
|
52
68
|
```
|
|
53
69
|
Unknown focus area: "{input}". Valid options: tech, arch, quality, concerns, tech+arch
|
|
54
70
|
```
|
|
@@ -68,16 +84,83 @@ For each target document, check if it already exists in `.planning/codebase/`:
|
|
|
68
84
|
ls -la .planning/codebase/{DOCUMENT}.md 2>/dev/null
|
|
69
85
|
```
|
|
70
86
|
|
|
71
|
-
|
|
87
|
+
**Three modes:**
|
|
88
|
+
|
|
89
|
+
### 2a — Refresh mode (`--refresh` flag)
|
|
90
|
+
|
|
91
|
+
Skip the [y/N] prompt. Instead, run the diff analysis in Step 2c and proceed to dispatch with refresh context.
|
|
92
|
+
|
|
93
|
+
### 2b — Reset mode (`--reset` flag)
|
|
94
|
+
|
|
95
|
+
Silent overwrite. No prompt, no brief, no CHANGELOG entry. Use only for CI or chained autonomous workflows.
|
|
96
|
+
|
|
97
|
+
### 2c — Default mode (no flag)
|
|
98
|
+
|
|
99
|
+
If any target doc exists, show their mod dates AND age in days, AND a one-line activity hint, then ask:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# For each existing doc, compute relative age:
|
|
103
|
+
for DOC in {document_list}; do
|
|
104
|
+
if [ -f ".planning/codebase/$DOC" ]; then
|
|
105
|
+
MTIME=$(stat -c %Y ".planning/codebase/$DOC" 2>/dev/null || stat -f %m ".planning/codebase/$DOC" 2>/dev/null)
|
|
106
|
+
NOW=$(date +%s)
|
|
107
|
+
AGE_DAYS=$(( (NOW - MTIME) / 86400 ))
|
|
108
|
+
COMMITS_SINCE=$(git log --oneline --since="@$MTIME" 2>/dev/null | wc -l | tr -d ' ')
|
|
109
|
+
echo " - $DOC ({date}, ${AGE_DAYS}d ago, ${COMMITS_SINCE} commits since)"
|
|
110
|
+
fi
|
|
111
|
+
done
|
|
112
|
+
```
|
|
113
|
+
|
|
72
114
|
```
|
|
73
115
|
Existing documents found:
|
|
74
|
-
- STACK.md
|
|
75
|
-
- INTEGRATIONS.md
|
|
116
|
+
- STACK.md (2026-03-22, 35d ago, 14 commits since)
|
|
117
|
+
- INTEGRATIONS.md (2026-03-22, 35d ago, 14 commits since)
|
|
118
|
+
|
|
119
|
+
These docs are stale. Three options:
|
|
120
|
+
[Y] Refresh — analyze what changed, briefly explain, then overwrite + log to CHANGELOG.md
|
|
121
|
+
[o] Overwrite blind — skip the diff brief, just rebuild
|
|
122
|
+
[n] Keep as-is, exit
|
|
123
|
+
```
|
|
76
124
|
|
|
77
|
-
|
|
125
|
+
Map the answer:
|
|
126
|
+
- `Y` / `y` / empty → set internal mode to **refresh**, continue to Step 2d
|
|
127
|
+
- `o` → set mode to **reset**, continue to Step 4
|
|
128
|
+
- `n` / `no` → exit
|
|
129
|
+
|
|
130
|
+
## Step 2d — Pre-state capture (refresh mode only)
|
|
131
|
+
|
|
132
|
+
Before dispatching Dalil, capture a structured snapshot for diff comparison. Fire each command and save the output verbatim — it goes into the dispatch prompt and the CHANGELOG entry.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Anchor mtime — oldest existing target doc
|
|
136
|
+
ANCHOR_TS=$(for DOC in {document_list}; do
|
|
137
|
+
[ -f ".planning/codebase/$DOC" ] && stat -c %Y ".planning/codebase/$DOC" 2>/dev/null || stat -f %m ".planning/codebase/$DOC" 2>/dev/null
|
|
138
|
+
done | sort -n | head -1)
|
|
139
|
+
ANCHOR_DATE=$(date -d "@$ANCHOR_TS" -u +%Y-%m-%d 2>/dev/null || date -r "$ANCHOR_TS" -u +%Y-%m-%d 2>/dev/null)
|
|
140
|
+
|
|
141
|
+
# Commits since anchor
|
|
142
|
+
echo "=== COMMITS SINCE $ANCHOR_DATE ==="
|
|
143
|
+
git log --oneline --since="@$ANCHOR_TS" 2>/dev/null | head -50
|
|
144
|
+
|
|
145
|
+
# Top-level dir set
|
|
146
|
+
echo "=== TOP-LEVEL DIRS ==="
|
|
147
|
+
find . -maxdepth 1 -type d -not -name '.git' -not -name 'node_modules' -not -name '.next' -not -name 'dist' -not -name '.venv' -not -name '__pycache__' | sort
|
|
148
|
+
|
|
149
|
+
# Manifest hashes (changed if deps shifted)
|
|
150
|
+
echo "=== MANIFEST HASHES ==="
|
|
151
|
+
for M in package.json pnpm-lock.yaml pyproject.toml requirements.txt Cargo.toml go.mod; do
|
|
152
|
+
[ -f "$M" ] && echo "$M $(sha256sum "$M" 2>/dev/null | awk '{print $1}' || shasum -a 256 "$M" | awk '{print $1}')"
|
|
153
|
+
done
|
|
154
|
+
|
|
155
|
+
# Source file count by language
|
|
156
|
+
echo "=== SOURCE FILE COUNTS ==="
|
|
157
|
+
for EXT in py ts tsx js jsx go rs rb; do
|
|
158
|
+
COUNT=$(find . -name "*.$EXT" -not -path '*/node_modules/*' -not -path '*/.venv/*' -not -path '*/dist/*' 2>/dev/null | wc -l | tr -d ' ')
|
|
159
|
+
[ "$COUNT" -gt 0 ] && echo "*.$EXT $COUNT"
|
|
160
|
+
done
|
|
78
161
|
```
|
|
79
162
|
|
|
80
|
-
|
|
163
|
+
Store this entire output as `$PRE_STATE` for the dispatch prompt.
|
|
81
164
|
|
|
82
165
|
## Step 3: Create output directory
|
|
83
166
|
|
|
@@ -121,7 +204,9 @@ Always first-person. Always include the deliverable path. If a topic phrase isn'
|
|
|
121
204
|
|
|
122
205
|
## Step 5: Spawn mapper agent
|
|
123
206
|
|
|
124
|
-
Spawn a single `rihal-codebase-mapper` agent. Pass the persona instructions in the prompt so the agent's own response opens in-character
|
|
207
|
+
Spawn a single `rihal-codebase-mapper` agent. Pass the persona instructions in the prompt so the agent's own response opens in-character.
|
|
208
|
+
|
|
209
|
+
**Base prompt (always sent):**
|
|
125
210
|
|
|
126
211
|
```
|
|
127
212
|
Task(
|
|
@@ -144,6 +229,35 @@ Task(
|
|
|
144
229
|
)
|
|
145
230
|
```
|
|
146
231
|
|
|
232
|
+
**Refresh-mode addendum (append to the prompt above when mode === "refresh"):**
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
REFRESH MODE — this is NOT a first scan. Existing docs are present and stale.
|
|
236
|
+
|
|
237
|
+
Anchor date (last scan): {ANCHOR_DATE}
|
|
238
|
+
Pre-state snapshot (verbatim from orchestrator):
|
|
239
|
+
{PRE_STATE}
|
|
240
|
+
|
|
241
|
+
Additional requirements for refresh runs:
|
|
242
|
+
1. After the Scan Scope section in EACH document, insert a section titled
|
|
243
|
+
'## Changes since last scan ({ANCHOR_DATE} → today)' that lists, in bullets:
|
|
244
|
+
- new files / removed files relevant to this doc's focus
|
|
245
|
+
- new dependencies / removed dependencies (for STACK.md / INTEGRATIONS.md)
|
|
246
|
+
- new modules / removed modules (for ARCHITECTURE.md / STRUCTURE.md)
|
|
247
|
+
- new TODO/FIXME or eliminated ones (for CONCERNS.md)
|
|
248
|
+
- 3-7 most-important commit subjects from the pre-state COMMITS list
|
|
249
|
+
that materially shaped the current state
|
|
250
|
+
2. The body of each document must reflect CURRENT state — not a diff. The
|
|
251
|
+
'Changes since last scan' section is the ONLY place where pre-state and
|
|
252
|
+
diff narrative belongs.
|
|
253
|
+
3. Include a final line in your return summary:
|
|
254
|
+
'Brief: {one-paragraph plain-English summary of the most important changes
|
|
255
|
+
since last scan, suitable for posting to CHANGELOG.md}'
|
|
256
|
+
The orchestrator extracts this verbatim.
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
When refresh mode is active, also include `topic_keyword` (if any) and the resolved focus in the prompt as before.
|
|
260
|
+
|
|
147
261
|
## Step 6: Announce return (persona-driven)
|
|
148
262
|
|
|
149
263
|
When the agent returns, print the RETURNED banner per `.rihal/references/dispatch-banner.md`. Filled-in template:
|
|
@@ -184,6 +298,44 @@ If the document is missing its Scan Scope section, do NOT print the success bann
|
|
|
184
298
|
|
|
185
299
|
Until the next `Task()` dispatch, answer follow-up questions about the scan AS Dalil — first-person, sign with `— Dalil`. If the user asks something outside Dalil's scope (e.g. strategy, planning, code editing), hand off explicitly per the dispatch-banner spec and print a fresh DISPATCH banner for the new persona.
|
|
186
300
|
|
|
301
|
+
## Step 6.5: Append to CHANGELOG.md (refresh mode only)
|
|
302
|
+
|
|
303
|
+
When mode === "refresh", extract Dalil's `Brief:` line from his RETURNED summary and append a structured entry to `.planning/codebase/CHANGELOG.md`. Create the file if missing. Use the Read tool first if updating, then Edit/Write — never blind-overwrite a file with prior entries.
|
|
304
|
+
|
|
305
|
+
**Entry format:**
|
|
306
|
+
|
|
307
|
+
```markdown
|
|
308
|
+
## {today's ISO date} — refresh
|
|
309
|
+
|
|
310
|
+
**Anchor:** {ANCHOR_DATE} ({age in days} days ago)
|
|
311
|
+
**Focus:** {focus}
|
|
312
|
+
**Commits since anchor:** {count}
|
|
313
|
+
**Docs touched:** {comma-separated list}
|
|
314
|
+
|
|
315
|
+
{Dalil's Brief: line, verbatim, formatted as a paragraph}
|
|
316
|
+
|
|
317
|
+
**Top-level signals:**
|
|
318
|
+
- Source roots: {comma-separated list of dirs from PRE_STATE}
|
|
319
|
+
- Languages: {detected mix}
|
|
320
|
+
- Manifest changes: {hash diff summary, e.g. "package.json: changed", "pyproject.toml: unchanged"}
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Insert at the TOP of the file body (newest-first), under any pre-existing `# Changelog — Codebase Memory Bank` H1. If the file doesn't exist, write it with this header:
|
|
326
|
+
|
|
327
|
+
```markdown
|
|
328
|
+
# Changelog — Codebase Memory Bank
|
|
329
|
+
|
|
330
|
+
This file tracks structural changes between scans. Each entry is auto-written by `/rihal:scan --refresh`. Newest entries first.
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
{first entry here}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
This file is **read by future `/rihal:scan --refresh` runs** as additional anchor context — the memory bank is self-improving across scans.
|
|
338
|
+
|
|
187
339
|
## Step 7: Final cue (orchestrator-level, after RETURNED banner)
|
|
188
340
|
|
|
189
341
|
The RETURNED banner above is Dalil's voice. After it, the orchestrator may add ONE neutral cue line if the user might want a deeper scan:
|