@hanzlaa/rcode 3.4.33 → 3.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/AGENTS.md +6 -6
- package/CONTRIBUTING.md +2 -0
- package/LICENSE +21 -0
- package/README.md +66 -403
- package/cli/doctor.js +87 -1
- package/cli/install.js +122 -31
- package/cli/lib/schemas.cjs +318 -0
- package/cli/postinstall.js +19 -3
- package/dist/rcode.js +316 -23
- package/package.json +14 -4
- package/rihal/agents/rihal-cross-platform-auditor.md +1 -1
- package/rihal/agents/rihal-dep-auditor.md +1 -1
- package/rihal/agents/rihal-docs-auditor.md +3 -145
- package/rihal/agents/rihal-i18n-auditor.md +1 -1
- package/rihal/agents/rihal-nyquist-auditor.md +4 -156
- package/rihal/agents/rihal-observability-auditor.md +1 -1
- package/rihal/bin/rihal-hooks.cjs +394 -4
- package/rihal/bin/rihal-tools.cjs +891 -24
- package/rihal/commands/create-prd.md +18 -0
- package/rihal/commands/execute-milestone.md +18 -0
- package/rihal/commands/plan-milestone.md +18 -0
- package/rihal/commands/scaffold-milestone.md +18 -0
- package/rihal/commands/scaffold-skill.md +18 -0
- package/rihal/references/REFERENCES_INDEX.md +49 -7
- package/rihal/references/agent-contracts.md +10 -0
- package/rihal/references/design-tokens.md +98 -0
- package/rihal/references/docs-auditor-playbook.md +148 -0
- package/rihal/references/git-preflight.md +117 -0
- package/rihal/references/iterative-retrieval.md +85 -0
- package/rihal/references/nyquist-auditor-playbook.md +157 -0
- package/rihal/references/workstream-flag.md +2 -2
- package/rihal/skills/actions/1-analysis/rihal-prfaq/SKILL.md +9 -0
- package/rihal/skills/actions/4-implementation/rihal-checkpoint-preview/SKILL.md +9 -0
- package/rihal/skills/actions/4-implementation/rihal-ci/SKILL.md +4 -0
- package/rihal/skills/actions/4-implementation/rihal-code-review/steps/step-02-review.md +2 -2
- package/rihal/skills/actions/4-implementation/rihal-harden/SKILL.md +4 -0
- package/rihal/skills/actions/4-implementation/rihal-migrate/SKILL.md +4 -0
- package/rihal/skills/agents/haitham-frontend/SKILL.md +2 -0
- package/rihal/templates/settings-hooks.json +39 -0
- package/rihal/workflows/check-todos.md +4 -0
- package/rihal/workflows/code-review-fix.md +4 -3
- package/rihal/workflows/code-review.md +1 -1
- package/rihal/workflows/debug.md +1 -1
- package/rihal/workflows/dev-story.md +4 -0
- package/rihal/workflows/diff.md +2 -2
- package/rihal/workflows/do.md +16 -8
- package/rihal/workflows/docs-update.md +2 -2
- package/rihal/workflows/enable-hooks.md +6 -1
- package/rihal/workflows/execute-milestone.md +139 -0
- package/rihal/workflows/execute-regression-gates.md +1 -1
- package/rihal/workflows/execute-sprint.md +54 -2
- package/rihal/workflows/execute-verify-phase-goal.md +31 -4
- package/rihal/workflows/execute-waves.md +33 -5
- package/rihal/workflows/execute.md +40 -6
- package/rihal/workflows/help.md +1 -1
- package/rihal/workflows/import.md +1 -1
- package/rihal/workflows/lens-audit.md +39 -23
- package/rihal/workflows/list-workspaces.md +1 -1
- package/rihal/workflows/map-codebase.md +4 -4
- package/rihal/workflows/new-milestone.md +18 -1
- package/rihal/workflows/new-project-research.md +53 -1
- package/rihal/workflows/new-workspace.md +1 -1
- package/rihal/workflows/plan-milestone.md +105 -0
- package/rihal/workflows/plan-research-validation.md +1 -1
- package/rihal/workflows/plan-spawn-planner.md +1 -1
- package/rihal/workflows/plan.md +31 -3
- package/rihal/workflows/plant-seed.md +6 -0
- package/rihal/workflows/quick.md +11 -5
- package/rihal/workflows/research-phase.md +24 -0
- package/rihal/workflows/scaffold-milestone.md +60 -0
- package/rihal/workflows/scaffold-skill.md +137 -0
- package/rihal/workflows/scan.md +1 -1
- package/rihal/workflows/session-report.md +43 -3
- package/rihal/workflows/verify-work.md +3 -3
- package/server/dashboard.js +154 -5
- package/server/lib/html/client/agents-data.js +27 -0
- package/server/lib/html/client/app.js +15 -0
- package/server/lib/html/client/components/App.js +211 -0
- package/server/lib/html/client/components/OrchPanel.js +293 -0
- package/server/lib/html/client/components/Sidebar.js +73 -0
- package/server/lib/html/client/components/Topbar.js +53 -0
- package/server/lib/html/client/components/XtermPanel.js +220 -0
- package/server/lib/html/client/components/shared.js +330 -0
- package/server/lib/html/client/icons-client.js +85 -0
- package/server/lib/html/client/orchestrator.js +279 -0
- package/server/lib/html/client/preact.js +34 -0
- package/server/lib/html/client/store.js +91 -0
- package/server/lib/html/client/util.js +186 -0
- package/server/lib/html/client/views/AgentsView.js +83 -0
- package/server/lib/html/client/views/DecisionsView.js +102 -0
- package/server/lib/html/client/views/FilesView.js +223 -0
- package/server/lib/html/client/views/KanbanView.js +236 -0
- package/server/lib/html/client/views/MemoryView.js +157 -0
- package/server/lib/html/client/views/MilestonesView.js +136 -0
- package/server/lib/html/client/views/OrchestrationView.js +167 -0
- package/server/lib/html/client/views/OverviewView.js +221 -0
- package/server/lib/html/client/views/PhasesView.js +184 -0
- package/server/lib/html/client/views/RoadmapView.js +238 -0
- package/server/lib/html/client/views/SprintsView.js +178 -0
- package/server/lib/html/client/views/TasksView.js +148 -0
- package/server/lib/html/client.js +42 -1064
- package/server/lib/html/css.js +2266 -466
- package/server/lib/html/icons.js +68 -0
- package/server/lib/html/shell.js +16 -210
- package/server/lib/scanner.js +109 -0
- package/server/orchestrator.js +362 -0
package/dist/rcode.js
CHANGED
|
@@ -15217,7 +15217,7 @@ var require_install = __commonJS({
|
|
|
15217
15217
|
var bold = (s) => pc.bold(s);
|
|
15218
15218
|
var PACKAGE_ROOT2 = path2.resolve(__dirname, "..");
|
|
15219
15219
|
var SOURCE_ROOT = path2.join(PACKAGE_ROOT2, "rihal");
|
|
15220
|
-
var SUPPORTED_IDES = Object.freeze(["claude", "cursor", "gemini", "vscode", "antigravity"]);
|
|
15220
|
+
var SUPPORTED_IDES = Object.freeze(["claude", "cursor", "gemini", "vscode", "antigravity", "windsurf"]);
|
|
15221
15221
|
var ConfigSchema = z.object({
|
|
15222
15222
|
user_name: z.string().min(1),
|
|
15223
15223
|
project_name: z.string().min(1),
|
|
@@ -15394,12 +15394,13 @@ var require_install = __commonJS({
|
|
|
15394
15394
|
console.log(lines.join("\n"));
|
|
15395
15395
|
}
|
|
15396
15396
|
function detectIdeSignals(target) {
|
|
15397
|
-
const signals = { claude: false, cursor: false, gemini: false, vscode: false, antigravity: false };
|
|
15397
|
+
const signals = { claude: false, cursor: false, gemini: false, vscode: false, antigravity: false, windsurf: false };
|
|
15398
15398
|
if (fs2.existsSync(path2.join(target, ".claude"))) signals.claude = true;
|
|
15399
15399
|
if (fs2.existsSync(path2.join(target, ".cursor"))) signals.cursor = true;
|
|
15400
15400
|
if (fs2.existsSync(path2.join(target, ".gemini"))) signals.gemini = true;
|
|
15401
15401
|
if (fs2.existsSync(path2.join(target, ".vscode"))) signals.vscode = true;
|
|
15402
15402
|
if (fs2.existsSync(path2.join(target, ".antigravity"))) signals.antigravity = true;
|
|
15403
|
+
if (fs2.existsSync(path2.join(target, ".windsurf"))) signals.windsurf = true;
|
|
15403
15404
|
const home = os.homedir();
|
|
15404
15405
|
if (fs2.existsSync(path2.join(home, ".claude"))) signals.claude = true;
|
|
15405
15406
|
if (fs2.existsSync(path2.join(home, ".cursor"))) signals.cursor = true;
|
|
@@ -15408,9 +15409,12 @@ var require_install = __commonJS({
|
|
|
15408
15409
|
if (fs2.existsSync(path2.join(home, ".vscode"))) signals.vscode = true;
|
|
15409
15410
|
if (fs2.existsSync(path2.join(home, ".config", "Code"))) signals.vscode = true;
|
|
15410
15411
|
if (fs2.existsSync(path2.join(home, ".antigravity"))) signals.antigravity = true;
|
|
15412
|
+
if (fs2.existsSync(path2.join(home, ".windsurf"))) signals.windsurf = true;
|
|
15413
|
+
if (fs2.existsSync(path2.join(home, ".codeium", "windsurf"))) signals.windsurf = true;
|
|
15411
15414
|
if (process.env.CURSOR_TRACE_ID || /cursor/i.test(process.env.TERM_PROGRAM || "")) signals.cursor = true;
|
|
15412
15415
|
if (process.env.CLAUDECODE === "1" || process.env.CLAUDE_CODE_ENTRYPOINT) signals.claude = true;
|
|
15413
15416
|
if (process.env.VSCODE_PID || /vscode/i.test(process.env.TERM_PROGRAM || "")) signals.vscode = true;
|
|
15417
|
+
if (/windsurf/i.test(process.env.TERM_PROGRAM || "")) signals.windsurf = true;
|
|
15414
15418
|
return signals;
|
|
15415
15419
|
}
|
|
15416
15420
|
async function resolveIde(opts) {
|
|
@@ -15530,7 +15534,7 @@ Installs (IDE-specific):
|
|
|
15530
15534
|
case "vscode":
|
|
15531
15535
|
return {
|
|
15532
15536
|
agentsDir: path2.join(target, ".claude", "agents"),
|
|
15533
|
-
commandsDir: path2.join(target, ".claude", "commands"
|
|
15537
|
+
commandsDir: path2.join(target, ".claude", "commands"),
|
|
15534
15538
|
workflowsDir: path2.join(target, ".rihal", "workflows"),
|
|
15535
15539
|
referencesDir: path2.join(target, ".rihal", "references"),
|
|
15536
15540
|
binDir: path2.join(target, ".rihal", "bin"),
|
|
@@ -15544,8 +15548,16 @@ Installs (IDE-specific):
|
|
|
15544
15548
|
referencesDir: path2.join(target, ".rihal", "references"),
|
|
15545
15549
|
binDir: path2.join(target, ".rihal", "bin")
|
|
15546
15550
|
};
|
|
15551
|
+
case "windsurf":
|
|
15552
|
+
return {
|
|
15553
|
+
agentsDir: path2.join(target, ".windsurf", "rules", "rihal", "agents"),
|
|
15554
|
+
commandsDir: path2.join(target, ".windsurf", "rules", "rihal", "commands"),
|
|
15555
|
+
workflowsDir: path2.join(target, ".rihal", "workflows"),
|
|
15556
|
+
referencesDir: path2.join(target, ".rihal", "references"),
|
|
15557
|
+
binDir: path2.join(target, ".rihal", "bin")
|
|
15558
|
+
};
|
|
15547
15559
|
default:
|
|
15548
|
-
throw new Error(`Unknown IDE: ${ide}. Supported:
|
|
15560
|
+
throw new Error(`Unknown IDE: ${ide}. Supported: ${SUPPORTED_IDES.join(", ")}`);
|
|
15549
15561
|
}
|
|
15550
15562
|
}
|
|
15551
15563
|
function walkFiles(dir, extraIgnore = []) {
|
|
@@ -15944,6 +15956,34 @@ ${BLOCK}`, { mode: 493 });
|
|
|
15944
15956
|
}
|
|
15945
15957
|
return { frontmatter: fm, body };
|
|
15946
15958
|
}
|
|
15959
|
+
function migrateVscodeCommandsLayout(target) {
|
|
15960
|
+
const legacyDir = path2.join(target, ".claude", "commands", "rihal");
|
|
15961
|
+
const newRoot = path2.join(target, ".claude", "commands");
|
|
15962
|
+
if (!fs2.existsSync(legacyDir) || !fs2.statSync(legacyDir).isDirectory()) {
|
|
15963
|
+
return { moved: 0, removed_dir: false };
|
|
15964
|
+
}
|
|
15965
|
+
let moved = 0;
|
|
15966
|
+
for (const entry of fs2.readdirSync(legacyDir)) {
|
|
15967
|
+
const src = path2.join(legacyDir, entry);
|
|
15968
|
+
if (!fs2.statSync(src).isFile() || !entry.endsWith(".md")) continue;
|
|
15969
|
+
const baseName = path2.basename(entry, ".md");
|
|
15970
|
+
const targetName = baseName.startsWith("rihal-") ? entry : `rihal-${entry}`;
|
|
15971
|
+
const dst = path2.join(newRoot, targetName);
|
|
15972
|
+
if (fs2.existsSync(dst)) {
|
|
15973
|
+
fs2.unlinkSync(src);
|
|
15974
|
+
continue;
|
|
15975
|
+
}
|
|
15976
|
+
fs2.renameSync(src, dst);
|
|
15977
|
+
moved++;
|
|
15978
|
+
}
|
|
15979
|
+
let removedDir = false;
|
|
15980
|
+
try {
|
|
15981
|
+
fs2.rmdirSync(legacyDir);
|
|
15982
|
+
removedDir = true;
|
|
15983
|
+
} catch (_) {
|
|
15984
|
+
}
|
|
15985
|
+
return { moved, removed_dir: removedDir };
|
|
15986
|
+
}
|
|
15947
15987
|
function buildInstallPlan(ide = "claude", target = process.cwd()) {
|
|
15948
15988
|
if (Array.isArray(ide)) {
|
|
15949
15989
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -15957,19 +15997,6 @@ ${BLOCK}`, { mode: 493 });
|
|
|
15957
15997
|
}
|
|
15958
15998
|
}
|
|
15959
15999
|
}
|
|
15960
|
-
if (ide.includes("claude") && ide.includes("vscode")) {
|
|
15961
|
-
const claudeCommandRels = new Set(
|
|
15962
|
-
merged.filter((e) => e.ide === "claude" && e.rel.split(path2.sep).join("/").startsWith(".claude/commands/")).map((e) => path2.basename(e.rel, ".md").replace(/^rihal-/, ""))
|
|
15963
|
-
);
|
|
15964
|
-
return merged.filter((e) => {
|
|
15965
|
-
const rel = e.rel.split(path2.sep).join("/");
|
|
15966
|
-
if (e.ide === "vscode" && rel.startsWith(".claude/commands/rihal/")) {
|
|
15967
|
-
const baseName = path2.basename(e.rel, path2.extname(e.rel));
|
|
15968
|
-
return !claudeCommandRels.has(baseName);
|
|
15969
|
-
}
|
|
15970
|
-
return true;
|
|
15971
|
-
});
|
|
15972
|
-
}
|
|
15973
16000
|
return merged;
|
|
15974
16001
|
}
|
|
15975
16002
|
const plan = [];
|
|
@@ -16007,7 +16034,7 @@ ${BLOCK}`, { mode: 493 });
|
|
|
16007
16034
|
const rel = path2.relative(path2.join(SOURCE_ROOT, "commands"), f);
|
|
16008
16035
|
const ext = ide === "cursor" ? ".mdc" : ".md";
|
|
16009
16036
|
const baseName = path2.basename(f, ".md");
|
|
16010
|
-
const outName = ide === "claude" ? `rihal-${baseName}${ext}` : baseName + ext;
|
|
16037
|
+
const outName = ide === "claude" || ide === "vscode" ? `rihal-${baseName}${ext}` : baseName + ext;
|
|
16011
16038
|
plan.push({ src: f, rel: path2.join(relCommands, path2.dirname(rel), outName), ide, cursor: ide === "cursor" });
|
|
16012
16039
|
}
|
|
16013
16040
|
const agentRulesDir = path2.join(target, ".rihal", "agents-rules");
|
|
@@ -16476,6 +16503,12 @@ ${BLOCK}`, { mode: 493 });
|
|
|
16476
16503
|
return 1;
|
|
16477
16504
|
}
|
|
16478
16505
|
}
|
|
16506
|
+
if (Array.isArray(opts.ides) && opts.ides.includes("vscode") || opts.ide === "vscode") {
|
|
16507
|
+
const migrated = migrateVscodeCommandsLayout(opts.target);
|
|
16508
|
+
if (migrated.moved > 0) {
|
|
16509
|
+
console.log(` \u21BB Migrated ${migrated.moved} legacy vscode-layout command(s) to .claude/commands/rihal-{name}.md`);
|
|
16510
|
+
}
|
|
16511
|
+
}
|
|
16479
16512
|
const fullPlan = buildInstallPlan(opts.ides, opts.target);
|
|
16480
16513
|
const plan = filterPlanByModules(fullPlan, opts.modules);
|
|
16481
16514
|
if (plan.length === 0) {
|
|
@@ -16521,6 +16554,7 @@ ${BLOCK}`, { mode: 493 });
|
|
|
16521
16554
|
let copied = 0;
|
|
16522
16555
|
let skipped = 0;
|
|
16523
16556
|
let preserved = 0;
|
|
16557
|
+
let updated = 0;
|
|
16524
16558
|
const preservedFiles = [];
|
|
16525
16559
|
const preservedDiffs = [];
|
|
16526
16560
|
const conflictedFiles = [];
|
|
@@ -16618,6 +16652,7 @@ ${BLOCK}`, { mode: 493 });
|
|
|
16618
16652
|
fs2.writeFileSync(c.destPath, c.sourceContent, "utf8");
|
|
16619
16653
|
applied++;
|
|
16620
16654
|
}
|
|
16655
|
+
updated += applied;
|
|
16621
16656
|
console.log(" " + ok(`Applied v${readPackageVersion()} to ${applied} file${applied === 1 ? "" : "s"}.`));
|
|
16622
16657
|
} else if (action === "review") {
|
|
16623
16658
|
let applied = 0, kept = 0;
|
|
@@ -16664,6 +16699,7 @@ ${BLOCK}`, { mode: 493 });
|
|
|
16664
16699
|
kept++;
|
|
16665
16700
|
}
|
|
16666
16701
|
}
|
|
16702
|
+
updated += applied;
|
|
16667
16703
|
console.log(" " + ok(`Review complete: ${applied} applied, ${kept} kept local.`));
|
|
16668
16704
|
} else {
|
|
16669
16705
|
console.log(" " + dim(`${conflictedFiles.length} file${conflictedFiles.length === 1 ? "" : "s"} kept local. Re-run with --force-overwrite or 'rcode update' anytime.`));
|
|
@@ -16673,6 +16709,10 @@ ${BLOCK}`, { mode: 493 });
|
|
|
16673
16709
|
}
|
|
16674
16710
|
console.log("");
|
|
16675
16711
|
}
|
|
16712
|
+
if (updated > 0) {
|
|
16713
|
+
console.log(" " + ok(`Total this run: ${copied} installed \xB7 ${updated} updated \xB7 ${preserved + skipped} unchanged.`));
|
|
16714
|
+
console.log("");
|
|
16715
|
+
}
|
|
16676
16716
|
if (opts.global) {
|
|
16677
16717
|
const configDir2 = path2.join(opts.target, ".rihal", "_config");
|
|
16678
16718
|
ensureDir(configDir2);
|
|
@@ -16766,8 +16806,8 @@ ${BLOCK}`, { mode: 493 });
|
|
|
16766
16806
|
const match = before.match(re);
|
|
16767
16807
|
const currentInFile = match ? match[1] === "true" : null;
|
|
16768
16808
|
if (match && currentInFile !== desired) {
|
|
16769
|
-
const
|
|
16770
|
-
writeFileAtomic(configPath,
|
|
16809
|
+
const updated2 = before.replace(re, `commit_planning: ${desired}`);
|
|
16810
|
+
writeFileAtomic(configPath, updated2);
|
|
16771
16811
|
console.log(" " + dim(`Updated commit_planning in config.yaml (${currentInFile} \u2192 ${desired}) \u2014 closes #685.`));
|
|
16772
16812
|
} else if (!match) {
|
|
16773
16813
|
const appended = before.replace(/\n*$/, "") + `
|
|
@@ -16951,14 +16991,14 @@ commit_planning: ${desired}
|
|
|
16951
16991
|
const homeCommands = path2.join(os.homedir(), ".claude/commands");
|
|
16952
16992
|
const homeSkills = path2.join(os.homedir(), ".claude/skills");
|
|
16953
16993
|
if (agentCount === 0 && fs2.existsSync(homeAgents)) {
|
|
16954
|
-
const n = fs2.readdirSync(homeAgents).filter((f) => f.startsWith("rihal-") && f.endsWith(".md")).length;
|
|
16994
|
+
const n = fs2.readdirSync(homeAgents).filter((f) => (f.startsWith("rihal-") || f.startsWith("rcode-")) && f.endsWith(".md")).length;
|
|
16955
16995
|
if (n > 0) {
|
|
16956
16996
|
agentCount = n;
|
|
16957
16997
|
agentsFromGlobal = true;
|
|
16958
16998
|
}
|
|
16959
16999
|
}
|
|
16960
17000
|
if (commandCount === 0 && fs2.existsSync(homeCommands)) {
|
|
16961
|
-
const n = fs2.readdirSync(homeCommands).filter((f) => f.startsWith("rihal-") && f.endsWith(".md")).length;
|
|
17001
|
+
const n = fs2.readdirSync(homeCommands).filter((f) => (f.startsWith("rihal-") || f.startsWith("rcode-")) && f.endsWith(".md")).length;
|
|
16962
17002
|
if (n > 0) {
|
|
16963
17003
|
commandCount = n;
|
|
16964
17004
|
commandsFromGlobal = true;
|
|
@@ -16999,6 +17039,12 @@ commit_planning: ${desired}
|
|
|
16999
17039
|
console.log(" /rihal-do # interactive command picker");
|
|
17000
17040
|
console.log(" /rihal-council <q> # multi-agent strategic answer");
|
|
17001
17041
|
console.log("");
|
|
17042
|
+
if (opts.global || opts.noPrompt) {
|
|
17043
|
+
console.log(` ${dim("Configure interactively (one-time, per project):")}`);
|
|
17044
|
+
console.log(` ${dim("rcode install # pick IDE + planning policy for THIS project")}`);
|
|
17045
|
+
console.log(` ${dim("rcode config # adjust defaults later")}`);
|
|
17046
|
+
console.log("");
|
|
17047
|
+
}
|
|
17002
17048
|
console.log(dim(" Refresh anytime:"));
|
|
17003
17049
|
console.log(dim(" npx @hanzlaa/rcode@latest install # pull the latest rcode + brain"));
|
|
17004
17050
|
console.log(dim(` /rihal-update v${version} # pin rcode to a specific version`));
|
|
@@ -17252,6 +17298,8 @@ commit_planning: ${desired}
|
|
|
17252
17298
|
module2.exports.buildInstallPlan = buildInstallPlan;
|
|
17253
17299
|
module2.exports.install = install;
|
|
17254
17300
|
module2.exports.SUPPORTED_IDES = SUPPORTED_IDES;
|
|
17301
|
+
module2.exports.migrateVscodeCommandsLayout = migrateVscodeCommandsLayout;
|
|
17302
|
+
module2.exports.getPathsForIde = getPathsForIde;
|
|
17255
17303
|
}
|
|
17256
17304
|
});
|
|
17257
17305
|
|
|
@@ -19144,6 +19192,193 @@ var require_memory_bank = __commonJS({
|
|
|
19144
19192
|
}
|
|
19145
19193
|
});
|
|
19146
19194
|
|
|
19195
|
+
// cli/lib/schemas.cjs
|
|
19196
|
+
var require_schemas = __commonJS({
|
|
19197
|
+
"cli/lib/schemas.cjs"(exports2, module2) {
|
|
19198
|
+
var { z } = require_zod();
|
|
19199
|
+
function parseFrontmatter(text) {
|
|
19200
|
+
if (typeof text !== "string" || !text.startsWith("---\n")) {
|
|
19201
|
+
return { frontmatter: {}, body: text || "" };
|
|
19202
|
+
}
|
|
19203
|
+
const end = text.indexOf("\n---\n", 4);
|
|
19204
|
+
if (end === -1) return { frontmatter: {}, body: text };
|
|
19205
|
+
const block = text.slice(4, end);
|
|
19206
|
+
const body = text.slice(end + 5);
|
|
19207
|
+
const fm = {};
|
|
19208
|
+
const lines = block.split("\n");
|
|
19209
|
+
let i = 0;
|
|
19210
|
+
while (i < lines.length) {
|
|
19211
|
+
const raw = lines[i];
|
|
19212
|
+
if (!raw.trim() || raw.trim().startsWith("#")) {
|
|
19213
|
+
i++;
|
|
19214
|
+
continue;
|
|
19215
|
+
}
|
|
19216
|
+
const m = raw.match(/^([A-Za-z0-9_-]+):(.*)$/);
|
|
19217
|
+
if (!m) {
|
|
19218
|
+
i++;
|
|
19219
|
+
continue;
|
|
19220
|
+
}
|
|
19221
|
+
const key = m[1].trim();
|
|
19222
|
+
let inline = m[2].trim();
|
|
19223
|
+
inline = inline.replace(/\s+#.*$/, "").trim();
|
|
19224
|
+
if (inline === ">" || inline === "|" || inline === ">-" || inline === "|-") {
|
|
19225
|
+
const collected = [];
|
|
19226
|
+
i++;
|
|
19227
|
+
while (i < lines.length) {
|
|
19228
|
+
const cont = lines[i];
|
|
19229
|
+
if (cont.trim() === "") {
|
|
19230
|
+
collected.push("");
|
|
19231
|
+
i++;
|
|
19232
|
+
continue;
|
|
19233
|
+
}
|
|
19234
|
+
if (/^\s/.test(cont)) {
|
|
19235
|
+
collected.push(cont.trim());
|
|
19236
|
+
i++;
|
|
19237
|
+
continue;
|
|
19238
|
+
}
|
|
19239
|
+
break;
|
|
19240
|
+
}
|
|
19241
|
+
fm[key] = collected.join(" ").replace(/\s+/g, " ").trim();
|
|
19242
|
+
continue;
|
|
19243
|
+
}
|
|
19244
|
+
if (inline === "") {
|
|
19245
|
+
const items = [];
|
|
19246
|
+
let j = i + 1;
|
|
19247
|
+
while (j < lines.length) {
|
|
19248
|
+
const cont = lines[j];
|
|
19249
|
+
if (cont.trim() === "" || cont.trim().startsWith("#")) {
|
|
19250
|
+
j++;
|
|
19251
|
+
continue;
|
|
19252
|
+
}
|
|
19253
|
+
const li = cont.match(/^\s+-\s+(.*)$/);
|
|
19254
|
+
if (!li) break;
|
|
19255
|
+
let v = li[1].trim();
|
|
19256
|
+
if (v.startsWith('"') && v.endsWith('"')) v = v.slice(1, -1);
|
|
19257
|
+
if (v.startsWith("'") && v.endsWith("'")) v = v.slice(1, -1);
|
|
19258
|
+
items.push(v);
|
|
19259
|
+
j++;
|
|
19260
|
+
}
|
|
19261
|
+
if (items.length) {
|
|
19262
|
+
fm[key] = items;
|
|
19263
|
+
i = j;
|
|
19264
|
+
continue;
|
|
19265
|
+
}
|
|
19266
|
+
fm[key] = "";
|
|
19267
|
+
i++;
|
|
19268
|
+
continue;
|
|
19269
|
+
}
|
|
19270
|
+
if (inline.startsWith('"') && inline.endsWith('"')) inline = inline.slice(1, -1);
|
|
19271
|
+
if (inline.startsWith("'") && inline.endsWith("'")) inline = inline.slice(1, -1);
|
|
19272
|
+
fm[key] = inline;
|
|
19273
|
+
i++;
|
|
19274
|
+
}
|
|
19275
|
+
return { frontmatter: fm, body };
|
|
19276
|
+
}
|
|
19277
|
+
function countTriggerPhrases(fm) {
|
|
19278
|
+
const desc = typeof fm.description === "string" ? fm.description : "";
|
|
19279
|
+
const quoted = desc.match(/"[^"]+"/g) || [];
|
|
19280
|
+
if (quoted.length > 0) return quoted.length;
|
|
19281
|
+
if (Array.isArray(fm.triggers)) {
|
|
19282
|
+
return fm.triggers.filter((t) => typeof t === "string" && t.trim()).length;
|
|
19283
|
+
}
|
|
19284
|
+
if (typeof fm.triggers === "string" && fm.triggers.trim()) {
|
|
19285
|
+
return fm.triggers.split(",").map((s) => s.trim()).filter(Boolean).length;
|
|
19286
|
+
}
|
|
19287
|
+
return 0;
|
|
19288
|
+
}
|
|
19289
|
+
var skillFrontmatterSchema = z.object({
|
|
19290
|
+
name: z.string().min(1, "name is required"),
|
|
19291
|
+
description: z.string().min(1, "description is required")
|
|
19292
|
+
});
|
|
19293
|
+
var NEGATIVE_BOUNDARY_RE = /not for|do not|does not|don't|never\b|audit-only|negative/i;
|
|
19294
|
+
function validateSkillFrontmatter(obj, body = "") {
|
|
19295
|
+
const errors = [];
|
|
19296
|
+
const warnings = [];
|
|
19297
|
+
const parsed = skillFrontmatterSchema.safeParse(obj || {});
|
|
19298
|
+
if (!parsed.success) {
|
|
19299
|
+
for (const issue of parsed.error.issues) {
|
|
19300
|
+
const field = issue.path.length ? issue.path.join(".") : "(root)";
|
|
19301
|
+
errors.push(`${field}: ${issue.message}`);
|
|
19302
|
+
}
|
|
19303
|
+
}
|
|
19304
|
+
if (obj && typeof obj === "object") {
|
|
19305
|
+
const count = countTriggerPhrases(obj);
|
|
19306
|
+
if (count < 5) {
|
|
19307
|
+
errors.push(`too few trigger phrases: found ${count}, need at least 5`);
|
|
19308
|
+
} else if (count > 12) {
|
|
19309
|
+
warnings.push(`many trigger phrases: found ${count}, recommended max is 12`);
|
|
19310
|
+
}
|
|
19311
|
+
const desc = typeof obj.description === "string" ? obj.description : "";
|
|
19312
|
+
const bodyText = typeof body === "string" ? body : "";
|
|
19313
|
+
const hasBoundary = NEGATIVE_BOUNDARY_RE.test(desc) || /##[^\n]*\bnot\b/i.test(bodyText) || /\bdo not (use|include)\b/i.test(bodyText) || /\bdon't touch\b/i.test(bodyText);
|
|
19314
|
+
if (!hasBoundary) {
|
|
19315
|
+
errors.push(
|
|
19316
|
+
'missing negative-boundary clause (e.g. "Do NOT use for: ..." in the description or a "## Do NOT use" section)'
|
|
19317
|
+
);
|
|
19318
|
+
}
|
|
19319
|
+
}
|
|
19320
|
+
return { ok: errors.length === 0, errors, warnings };
|
|
19321
|
+
}
|
|
19322
|
+
var agentFrontmatterSchema = z.object({
|
|
19323
|
+
name: z.string().min(1, "name is required").refine((v) => v.startsWith("rihal-"), 'name must start with the "rihal-" prefix'),
|
|
19324
|
+
description: z.string().min(1, "description is required"),
|
|
19325
|
+
color: z.string().min(1, "color is required")
|
|
19326
|
+
});
|
|
19327
|
+
function validateAgentFrontmatter(obj) {
|
|
19328
|
+
const errors = [];
|
|
19329
|
+
const parsed = agentFrontmatterSchema.safeParse(obj || {});
|
|
19330
|
+
if (!parsed.success) {
|
|
19331
|
+
for (const issue of parsed.error.issues) {
|
|
19332
|
+
const field = issue.path.length ? issue.path.join(".") : "(root)";
|
|
19333
|
+
errors.push(`${field}: ${issue.message}`);
|
|
19334
|
+
}
|
|
19335
|
+
}
|
|
19336
|
+
if (obj && typeof obj === "object") {
|
|
19337
|
+
const tools = obj.tools;
|
|
19338
|
+
const hasTools = Array.isArray(tools) ? tools.length > 0 : typeof tools === "string" && tools.trim().length > 0;
|
|
19339
|
+
if (!hasTools) {
|
|
19340
|
+
errors.push("tools is required (comma-separated string or array)");
|
|
19341
|
+
}
|
|
19342
|
+
} else {
|
|
19343
|
+
errors.push("tools is required (comma-separated string or array)");
|
|
19344
|
+
}
|
|
19345
|
+
return { ok: errors.length === 0, errors };
|
|
19346
|
+
}
|
|
19347
|
+
var stateSchema = z.object({
|
|
19348
|
+
version: z.union([z.string(), z.number()]),
|
|
19349
|
+
project: z.string().min(1),
|
|
19350
|
+
phases: z.array(z.any()),
|
|
19351
|
+
schema_version: z.number(),
|
|
19352
|
+
current_phase: z.union([z.string(), z.number()]).optional(),
|
|
19353
|
+
current_plan: z.union([z.string(), z.number()]).optional(),
|
|
19354
|
+
current_sprint: z.union([z.string(), z.number()]).nullable().optional(),
|
|
19355
|
+
velocity_history: z.array(z.any()).optional(),
|
|
19356
|
+
milestones: z.array(z.any()).optional()
|
|
19357
|
+
}).passthrough();
|
|
19358
|
+
function validateState(obj) {
|
|
19359
|
+
const errors = [];
|
|
19360
|
+
const parsed = stateSchema.safeParse(obj || {});
|
|
19361
|
+
if (!parsed.success) {
|
|
19362
|
+
for (const issue of parsed.error.issues) {
|
|
19363
|
+
const where = issue.path.length ? issue.path.join(".") : "(root)";
|
|
19364
|
+
errors.push(`${where}: ${issue.message}`);
|
|
19365
|
+
}
|
|
19366
|
+
}
|
|
19367
|
+
return { ok: errors.length === 0, errors };
|
|
19368
|
+
}
|
|
19369
|
+
module2.exports = {
|
|
19370
|
+
parseFrontmatter,
|
|
19371
|
+
countTriggerPhrases,
|
|
19372
|
+
skillFrontmatterSchema,
|
|
19373
|
+
agentFrontmatterSchema,
|
|
19374
|
+
stateSchema,
|
|
19375
|
+
validateSkillFrontmatter,
|
|
19376
|
+
validateAgentFrontmatter,
|
|
19377
|
+
validateState
|
|
19378
|
+
};
|
|
19379
|
+
}
|
|
19380
|
+
});
|
|
19381
|
+
|
|
19147
19382
|
// cli/doctor.js
|
|
19148
19383
|
var require_doctor = __commonJS({
|
|
19149
19384
|
"cli/doctor.js"(exports2, module2) {
|
|
@@ -19152,6 +19387,11 @@ var require_doctor = __commonJS({
|
|
|
19152
19387
|
var { spawnSync } = require("child_process");
|
|
19153
19388
|
var { verifyInstall, formatReport } = require_manifest();
|
|
19154
19389
|
var { checkStaleness } = require_memory_bank();
|
|
19390
|
+
var {
|
|
19391
|
+
parseFrontmatter,
|
|
19392
|
+
validateSkillFrontmatter,
|
|
19393
|
+
validateAgentFrontmatter
|
|
19394
|
+
} = require_schemas();
|
|
19155
19395
|
function findSkillFiles(dir) {
|
|
19156
19396
|
const results = [];
|
|
19157
19397
|
if (!fs2.existsSync(dir)) return results;
|
|
@@ -19165,6 +19405,10 @@ var require_doctor = __commonJS({
|
|
|
19165
19405
|
}
|
|
19166
19406
|
return results;
|
|
19167
19407
|
}
|
|
19408
|
+
function findAgentFiles(dir) {
|
|
19409
|
+
if (!fs2.existsSync(dir)) return [];
|
|
19410
|
+
return fs2.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".md")).map((e) => path2.join(dir, e.name));
|
|
19411
|
+
}
|
|
19168
19412
|
function checkCompliance(filePath) {
|
|
19169
19413
|
const content = fs2.readFileSync(filePath, "utf8");
|
|
19170
19414
|
const missing = [];
|
|
@@ -19347,6 +19591,52 @@ var require_doctor = __commonJS({
|
|
|
19347
19591
|
}
|
|
19348
19592
|
return failing;
|
|
19349
19593
|
}
|
|
19594
|
+
function runSchemaValidation(packageRoot) {
|
|
19595
|
+
const skillDirs = [
|
|
19596
|
+
path2.join(packageRoot, "rihal/skills/agents"),
|
|
19597
|
+
path2.join(packageRoot, "rihal/skills/actions")
|
|
19598
|
+
];
|
|
19599
|
+
let totalSkills = 0;
|
|
19600
|
+
let totalAgents = 0;
|
|
19601
|
+
let failing = 0;
|
|
19602
|
+
let warned = 0;
|
|
19603
|
+
for (const dir of skillDirs) {
|
|
19604
|
+
for (const file of findSkillFiles(dir)) {
|
|
19605
|
+
totalSkills++;
|
|
19606
|
+
const { frontmatter, body } = parseFrontmatter(fs2.readFileSync(file, "utf8"));
|
|
19607
|
+
const result = validateSkillFrontmatter(frontmatter, body);
|
|
19608
|
+
const rel = path2.relative(packageRoot, file);
|
|
19609
|
+
if (!result.ok) {
|
|
19610
|
+
failing++;
|
|
19611
|
+
console.log(` \u2717 ${rel}`);
|
|
19612
|
+
for (const err of result.errors) console.log(` ${err}`);
|
|
19613
|
+
}
|
|
19614
|
+
if (result.warnings && result.warnings.length > 0) {
|
|
19615
|
+
warned++;
|
|
19616
|
+
for (const w of result.warnings) console.log(` \u26A0 ${rel}: ${w}`);
|
|
19617
|
+
}
|
|
19618
|
+
}
|
|
19619
|
+
}
|
|
19620
|
+
for (const file of findAgentFiles(path2.join(packageRoot, "rihal/agents"))) {
|
|
19621
|
+
totalAgents++;
|
|
19622
|
+
const { frontmatter } = parseFrontmatter(fs2.readFileSync(file, "utf8"));
|
|
19623
|
+
const result = validateAgentFrontmatter(frontmatter);
|
|
19624
|
+
if (!result.ok) {
|
|
19625
|
+
failing++;
|
|
19626
|
+
const rel = path2.relative(packageRoot, file);
|
|
19627
|
+
console.log(` \u2717 ${rel}`);
|
|
19628
|
+
for (const err of result.errors) console.log(` ${err}`);
|
|
19629
|
+
}
|
|
19630
|
+
}
|
|
19631
|
+
if (failing === 0) {
|
|
19632
|
+
console.log(
|
|
19633
|
+
` \u2713 ${totalSkills} skill + ${totalAgents} agent frontmatter blocks pass schema validation` + (warned > 0 ? ` (${warned} with advisory warnings)` : "")
|
|
19634
|
+
);
|
|
19635
|
+
} else {
|
|
19636
|
+
console.log(` \u2717 ${failing} artifact(s) failed schema validation`);
|
|
19637
|
+
}
|
|
19638
|
+
return failing;
|
|
19639
|
+
}
|
|
19350
19640
|
function checkDuplicateInstalls() {
|
|
19351
19641
|
const os = require("os");
|
|
19352
19642
|
const home = os.homedir();
|
|
@@ -19421,7 +19711,10 @@ Duplicate installations:`);
|
|
|
19421
19711
|
console.log(`
|
|
19422
19712
|
Package compliance:`);
|
|
19423
19713
|
const complianceFailures = runCompliance(packageRoot);
|
|
19424
|
-
|
|
19714
|
+
console.log(`
|
|
19715
|
+
Artifact schema validation:`);
|
|
19716
|
+
const schemaFailures = runSchemaValidation(packageRoot);
|
|
19717
|
+
const totalFailures = preflightFailures + complianceFailures + duplicateFailures + schemaFailures;
|
|
19425
19718
|
console.log();
|
|
19426
19719
|
if (totalFailures === 0) {
|
|
19427
19720
|
console.log(`\u2705 All checks passed.`);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzlaa/rcode",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "rcode — the
|
|
3
|
+
"version": "3.6.0",
|
|
4
|
+
"description": "rcode — the AI team that never forgets. Persistent memory, specialist agents, and slash commands for AI IDEs. Works in Claude Code, Cursor, Gemini, VS Code, and Antigravity.",
|
|
5
5
|
"main": "cli/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"rcode": "dist/rcode.js",
|
|
@@ -40,13 +40,17 @@
|
|
|
40
40
|
"arabic",
|
|
41
41
|
"ai-methodology",
|
|
42
42
|
"team-simulation",
|
|
43
|
-
"orchestration"
|
|
43
|
+
"orchestration",
|
|
44
|
+
"memory-bank",
|
|
45
|
+
"cursor",
|
|
46
|
+
"planning",
|
|
47
|
+
"subagents"
|
|
44
48
|
],
|
|
45
49
|
"author": {
|
|
46
50
|
"name": "Hanzla Habib",
|
|
47
51
|
"url": "https://github.com/hanzlahabib"
|
|
48
52
|
},
|
|
49
|
-
"license": "
|
|
53
|
+
"license": "MIT",
|
|
50
54
|
"repository": {
|
|
51
55
|
"type": "git",
|
|
52
56
|
"url": "https://github.com/hanzlahabib/rihal-code.git"
|
|
@@ -70,5 +74,11 @@
|
|
|
70
74
|
},
|
|
71
75
|
"publishConfig": {
|
|
72
76
|
"access": "public"
|
|
77
|
+
},
|
|
78
|
+
"dependencies": {
|
|
79
|
+
"ws": "^8.20.1"
|
|
80
|
+
},
|
|
81
|
+
"optionalDependencies": {
|
|
82
|
+
"@lydell/node-pty": "1.2.0-beta.12"
|
|
73
83
|
}
|
|
74
84
|
}
|