@entelligentsia/forgecli 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +138 -0
- package/README.md +177 -38
- package/dist/bin/argv.js +5 -0
- package/dist/bin/argv.js.map +1 -1
- package/dist/bin/forge.js +1 -0
- package/dist/bin/forge.js.map +1 -1
- package/dist/extensions/forgecli/ask-user-tool.d.ts +17 -0
- package/dist/extensions/forgecli/ask-user-tool.js +139 -0
- package/dist/extensions/forgecli/ask-user-tool.js.map +1 -0
- package/dist/extensions/forgecli/forge-commands.d.ts +21 -0
- package/dist/extensions/forgecli/forge-commands.js +141 -0
- package/dist/extensions/forgecli/forge-commands.js.map +1 -1
- package/dist/extensions/forgecli/forge-init.d.ts +26 -0
- package/dist/extensions/forgecli/forge-init.js +948 -0
- package/dist/extensions/forgecli/forge-init.js.map +1 -0
- package/dist/extensions/forgecli/health-check.d.ts +18 -0
- package/dist/extensions/forgecli/health-check.js +154 -0
- package/dist/extensions/forgecli/health-check.js.map +1 -0
- package/dist/extensions/forgecli/hook-dispatcher.d.ts +34 -1
- package/dist/extensions/forgecli/hook-dispatcher.js +237 -3
- package/dist/extensions/forgecli/hook-dispatcher.js.map +1 -1
- package/dist/extensions/forgecli/index.js +28 -11
- package/dist/extensions/forgecli/index.js.map +1 -1
- package/dist/extensions/forgecli/init-context.d.ts +99 -0
- package/dist/extensions/forgecli/init-context.js +163 -0
- package/dist/extensions/forgecli/init-context.js.map +1 -0
- package/dist/extensions/forgecli/init-progress.d.ts +39 -0
- package/dist/extensions/forgecli/init-progress.js +117 -0
- package/dist/extensions/forgecli/init-progress.js.map +1 -0
- package/dist/extensions/forgecli/refresh-kb-links.d.ts +18 -0
- package/dist/extensions/forgecli/refresh-kb-links.js +228 -0
- package/dist/extensions/forgecli/refresh-kb-links.js.map +1 -0
- package/dist/extensions/forgecli/store-validator.d.ts +13 -0
- package/dist/extensions/forgecli/store-validator.js +35 -0
- package/dist/extensions/forgecli/store-validator.js.map +1 -0
- package/dist/extensions/forgecli/transition-guard.d.ts +20 -0
- package/dist/extensions/forgecli/transition-guard.js +125 -0
- package/dist/extensions/forgecli/transition-guard.js.map +1 -0
- package/dist/forge-payload/.base-pack/commands/approve.md +22 -0
- package/dist/forge-payload/.base-pack/commands/collate.md +22 -0
- package/dist/forge-payload/.base-pack/commands/commit.md +22 -0
- package/dist/forge-payload/.base-pack/commands/enhance.md +37 -0
- package/dist/forge-payload/.base-pack/commands/fix-bug.md +22 -0
- package/dist/forge-payload/.base-pack/commands/implement.md +22 -0
- package/dist/forge-payload/.base-pack/commands/plan.md +22 -0
- package/dist/forge-payload/.base-pack/commands/quiz-agent.md +22 -0
- package/dist/forge-payload/.base-pack/commands/retrospective.md +22 -0
- package/dist/forge-payload/.base-pack/commands/review-code.md +22 -0
- package/dist/forge-payload/.base-pack/commands/review-plan.md +22 -0
- package/dist/forge-payload/.base-pack/commands/run-sprint.md +22 -0
- package/dist/forge-payload/.base-pack/commands/run-task.md +22 -0
- package/dist/forge-payload/.base-pack/commands/sprint-intake.md +22 -0
- package/dist/forge-payload/.base-pack/commands/sprint-plan.md +22 -0
- package/dist/forge-payload/.base-pack/commands/validate.md +22 -0
- package/dist/forge-payload/.claude-plugin/plugin.json +15 -0
- package/dist/forge-payload/.init/discovery/discover-database.md +32 -0
- package/dist/forge-payload/.init/discovery/discover-processes.md +31 -0
- package/dist/forge-payload/.init/discovery/discover-routing.md +31 -0
- package/dist/forge-payload/.init/discovery/discover-stack.md +33 -0
- package/dist/forge-payload/.init/discovery/discover-testing.md +34 -0
- package/dist/forge-payload/.init/generation/generate-kb-doc.md +60 -0
- package/dist/forge-payload/.schemas/bug.schema.json +53 -0
- package/dist/forge-payload/.schemas/collation-state.schema.json +16 -0
- package/dist/forge-payload/.schemas/event-sidecar.schema.json +22 -0
- package/dist/forge-payload/.schemas/event.schema.json +32 -0
- package/dist/forge-payload/.schemas/feature.schema.json +22 -0
- package/dist/forge-payload/.schemas/progress-entry.schema.json +16 -0
- package/dist/forge-payload/.schemas/project-context.schema.json +167 -0
- package/dist/forge-payload/.schemas/project-overlay.schema.json +25 -0
- package/dist/forge-payload/.schemas/sprint.schema.json +27 -0
- package/dist/forge-payload/.schemas/structure-versions.schema.json +57 -0
- package/dist/forge-payload/.schemas/task.schema.json +58 -0
- package/dist/forge-payload/.tools/banners.cjs +435 -0
- package/dist/forge-payload/.tools/build-context-pack.cjs +290 -0
- package/dist/forge-payload/.tools/build-init-context.cjs +322 -0
- package/dist/forge-payload/.tools/build-overlay.cjs +326 -0
- package/dist/forge-payload/.tools/build-persona-pack.cjs +226 -0
- package/dist/forge-payload/.tools/collate.cjs +1041 -0
- package/dist/forge-payload/.tools/generation-manifest.cjs +311 -0
- package/dist/forge-payload/.tools/lib/forge-root.cjs +59 -0
- package/dist/forge-payload/.tools/lib/paths.cjs +29 -0
- package/dist/forge-payload/.tools/lib/pricing.cjs +165 -0
- package/dist/forge-payload/.tools/lib/project-root.cjs +32 -0
- package/dist/forge-payload/.tools/lib/result.js +40 -0
- package/dist/forge-payload/.tools/lib/validate.js +131 -0
- package/dist/forge-payload/.tools/manage-config.cjs +340 -0
- package/dist/forge-payload/.tools/manage-versions.cjs +365 -0
- package/dist/forge-payload/.tools/seed-store.cjs +237 -0
- package/dist/forge-payload/.tools/store-cli.cjs +1123 -0
- package/dist/forge-payload/.tools/store.cjs +315 -0
- package/dist/forge-payload/.tools/substitute-placeholders.cjs +625 -0
- package/dist/forge-payload/.tools/validate-store.cjs +522 -0
- package/package.json +1 -1
- /package/dist/forge-payload/{personas → .base-pack/personas}/architect.md +0 -0
- /package/dist/forge-payload/{personas → .base-pack/personas}/bug-fixer.md +0 -0
- /package/dist/forge-payload/{personas → .base-pack/personas}/collator.md +0 -0
- /package/dist/forge-payload/{personas → .base-pack/personas}/engineer.md +0 -0
- /package/dist/forge-payload/{personas → .base-pack/personas}/librarian.md +0 -0
- /package/dist/forge-payload/{personas → .base-pack/personas}/orchestrator.md +0 -0
- /package/dist/forge-payload/{personas → .base-pack/personas}/product-manager.md +0 -0
- /package/dist/forge-payload/{personas → .base-pack/personas}/qa-engineer.md +0 -0
- /package/dist/forge-payload/{personas → .base-pack/personas}/supervisor.md +0 -0
- /package/dist/forge-payload/{skills → .base-pack/skills}/architect-skills.md +0 -0
- /package/dist/forge-payload/{skills → .base-pack/skills}/bug-fixer-skills.md +0 -0
- /package/dist/forge-payload/{skills → .base-pack/skills}/collator-skills.md +0 -0
- /package/dist/forge-payload/{skills → .base-pack/skills}/engineer-skills.md +0 -0
- /package/dist/forge-payload/{skills → .base-pack/skills}/generic-skills.md +0 -0
- /package/dist/forge-payload/{skills → .base-pack/skills}/librarian-skills.md +0 -0
- /package/dist/forge-payload/{skills → .base-pack/skills}/qa-engineer-skills.md +0 -0
- /package/dist/forge-payload/{skills → .base-pack/skills}/store-custodian-skills.md +0 -0
- /package/dist/forge-payload/{skills → .base-pack/skills}/supervisor-skills.md +0 -0
- /package/dist/forge-payload/{templates → .base-pack/templates}/CODE_REVIEW_TEMPLATE.md +0 -0
- /package/dist/forge-payload/{templates → .base-pack/templates}/COST_REPORT_TEMPLATE.md +0 -0
- /package/dist/forge-payload/{templates → .base-pack/templates}/PLAN_REVIEW_TEMPLATE.md +0 -0
- /package/dist/forge-payload/{templates → .base-pack/templates}/PLAN_SUMMARY_TEMPLATE.json +0 -0
- /package/dist/forge-payload/{templates → .base-pack/templates}/PLAN_TEMPLATE.md +0 -0
- /package/dist/forge-payload/{templates → .base-pack/templates}/PROGRESS_TEMPLATE.md +0 -0
- /package/dist/forge-payload/{templates → .base-pack/templates}/RETROSPECTIVE_TEMPLATE.md +0 -0
- /package/dist/forge-payload/{templates → .base-pack/templates}/SPRINT_MANIFEST_TEMPLATE.md +0 -0
- /package/dist/forge-payload/{templates → .base-pack/templates}/SPRINT_REQUIREMENTS_TEMPLATE.md +0 -0
- /package/dist/forge-payload/{templates → .base-pack/templates}/TASK_PROMPT_TEMPLATE.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/_fragments/context-injection.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/_fragments/event-emission-schema.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/_fragments/finalize.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/_fragments/progress-reporting.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/architect_approve.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/architect_review_sprint_completion.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/architect_sprint_intake.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/architect_sprint_plan.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/collator_agent.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/commit_task.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/fix_bug.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/implement_plan.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/migrate_structural.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/orchestrate_task.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/plan_task.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/quiz_agent.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/review_code.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/review_plan.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/run_sprint.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/sprint_retrospective.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/update_implementation.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/update_plan.md +0 -0
- /package/dist/forge-payload/{workflows → .base-pack/workflows}/validate_task.md +0 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// refresh-kb-links.ts — TypeScript port of forge/forge/skills/refresh-kb-links/SKILL.md
|
|
2
|
+
//
|
|
3
|
+
// Scans coding-agent instruction files (CLAUDE.md, AGENTS.md, etc.) and
|
|
4
|
+
// ensures each has up-to-date managed sections linking to the Forge KB and
|
|
5
|
+
// workflows. Called directly by Phase 4 step 4-9 (Tomoshibi) during
|
|
6
|
+
// /forge:init and registered as the /forge:refresh-kb-links command handler.
|
|
7
|
+
//
|
|
8
|
+
// Per PLAN.md sub-decision #5 (F7 fix): TS port is the only valid implementation;
|
|
9
|
+
// forge/forge/skills/refresh-kb-links/SKILL.md is a markdown body with no
|
|
10
|
+
// runnable .cjs entry point.
|
|
11
|
+
//
|
|
12
|
+
// Iron Law 6: no shell-string interpolation.
|
|
13
|
+
// Iron Law 1: reads .forge/config.json — no writes to forge/ source.
|
|
14
|
+
import * as fs from "node:fs";
|
|
15
|
+
import * as path from "node:path";
|
|
16
|
+
// ── Known agent instruction files ─────────────────────────────────────────
|
|
17
|
+
const AGENT_INSTRUCTION_FILES = [
|
|
18
|
+
"CLAUDE.md",
|
|
19
|
+
"AGENTS.md",
|
|
20
|
+
"AGENT.md",
|
|
21
|
+
"GEMINI.md",
|
|
22
|
+
".cursorrules",
|
|
23
|
+
".github/copilot-instructions.md",
|
|
24
|
+
];
|
|
25
|
+
// ── Known workflow files ───────────────────────────────────────────────────
|
|
26
|
+
const WORKFLOW_ENTRIES = [
|
|
27
|
+
{ file: "plan_task.md", label: "Plan", purpose: "Research codebase → implementation plan" },
|
|
28
|
+
{ file: "implement_plan.md", label: "Implement", purpose: "Execute approved plan → code changes" },
|
|
29
|
+
{ file: "fix_bug.md", label: "Fix bug", purpose: "Triage → fix → verify" },
|
|
30
|
+
{
|
|
31
|
+
file: "orchestrate_task.md",
|
|
32
|
+
label: "Run task",
|
|
33
|
+
purpose: "Full task pipeline (plan → implement → review → commit)",
|
|
34
|
+
},
|
|
35
|
+
{ file: "run_sprint.md", label: "Run sprint", purpose: "Full sprint orchestration" },
|
|
36
|
+
{ file: "architect_sprint_plan.md", label: "Sprint plan", purpose: "Sprint planning and task decomposition" },
|
|
37
|
+
{
|
|
38
|
+
file: "architect_sprint_intake.md",
|
|
39
|
+
label: "Sprint intake",
|
|
40
|
+
purpose: "Sprint intake and requirements elicitation",
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
// ── Managed section markers ────────────────────────────────────────────────
|
|
44
|
+
const KB_OPEN_PREFIX = "<!-- forge-kb-links";
|
|
45
|
+
const KB_CLOSE = "<!-- /forge-kb-links -->";
|
|
46
|
+
const WF_OPEN_PREFIX = "<!-- forge-workflow-links";
|
|
47
|
+
const WF_CLOSE = "<!-- /forge-workflow-links -->";
|
|
48
|
+
// ── Content generators ─────────────────────────────────────────────────────
|
|
49
|
+
function buildKbSection(cwd, kbPath) {
|
|
50
|
+
const rows = [
|
|
51
|
+
{ label: "MASTER_INDEX", file: `${kbPath}/MASTER_INDEX.md`, desc: "All sprints, tasks, bugs, and features" },
|
|
52
|
+
{
|
|
53
|
+
label: "Architecture",
|
|
54
|
+
file: `${kbPath}/architecture/INDEX.md`,
|
|
55
|
+
desc: "Stack, processes, database, routing, deployment",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
label: "Business Domain",
|
|
59
|
+
file: `${kbPath}/business-domain/INDEX.md`,
|
|
60
|
+
desc: "Entity model and domain concepts",
|
|
61
|
+
},
|
|
62
|
+
].filter((r) => fs.existsSync(path.join(cwd, r.file)));
|
|
63
|
+
if (rows.length === 0)
|
|
64
|
+
return "";
|
|
65
|
+
const tableRows = rows.map((r) => `| [${r.label}](${r.file}) | ${r.desc} |`).join("\n");
|
|
66
|
+
return [
|
|
67
|
+
`<!-- forge-kb-links: managed by Forge — do not edit manually -->`,
|
|
68
|
+
`## Forge Knowledge Base`,
|
|
69
|
+
``,
|
|
70
|
+
`| Index | Contents |`,
|
|
71
|
+
`|-------|----------|`,
|
|
72
|
+
tableRows,
|
|
73
|
+
``,
|
|
74
|
+
`Personas live in \`.forge/personas/\`.`,
|
|
75
|
+
KB_CLOSE,
|
|
76
|
+
].join("\n");
|
|
77
|
+
}
|
|
78
|
+
function buildWorkflowSection(cwd) {
|
|
79
|
+
const rows = WORKFLOW_ENTRIES.filter((e) => fs.existsSync(path.join(cwd, ".forge", "workflows", e.file)));
|
|
80
|
+
if (rows.length === 0)
|
|
81
|
+
return "";
|
|
82
|
+
const tableRows = rows.map((e) => `| [${e.label}](.forge/workflows/${e.file}) | ${e.purpose} |`).join("\n");
|
|
83
|
+
return [
|
|
84
|
+
`<!-- forge-workflow-links: managed by Forge — do not edit manually -->`,
|
|
85
|
+
`## Forge Workflows`,
|
|
86
|
+
``,
|
|
87
|
+
`| Workflow | Purpose |`,
|
|
88
|
+
`|----------|---------|`,
|
|
89
|
+
tableRows,
|
|
90
|
+
WF_CLOSE,
|
|
91
|
+
].join("\n");
|
|
92
|
+
}
|
|
93
|
+
// ── Section replacement ────────────────────────────────────────────────────
|
|
94
|
+
/**
|
|
95
|
+
* Replace or append a managed section in a file's content.
|
|
96
|
+
* If the section already exists (detected by open-prefix), replaces it.
|
|
97
|
+
* Otherwise, appends it to the end.
|
|
98
|
+
*/
|
|
99
|
+
function upsertSection(content, openPrefix, closeMarker, newSection) {
|
|
100
|
+
if (!newSection)
|
|
101
|
+
return content; // nothing to inject
|
|
102
|
+
// Find existing section
|
|
103
|
+
const openIdx = content.indexOf(openPrefix);
|
|
104
|
+
if (openIdx !== -1) {
|
|
105
|
+
const closeIdx = content.indexOf(closeMarker, openIdx);
|
|
106
|
+
if (closeIdx !== -1) {
|
|
107
|
+
const endIdx = closeIdx + closeMarker.length;
|
|
108
|
+
// Replace existing section
|
|
109
|
+
return content.slice(0, openIdx) + newSection + content.slice(endIdx);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Append at end, ensuring a blank line separator
|
|
113
|
+
const trimmed = content.trimEnd();
|
|
114
|
+
return trimmed + "\n\n" + newSection + "\n";
|
|
115
|
+
}
|
|
116
|
+
// ── Main exported function ─────────────────────────────────────────────────
|
|
117
|
+
/**
|
|
118
|
+
* Run the refresh-kb-links operation on the project at `cwd`.
|
|
119
|
+
*
|
|
120
|
+
* Returns a result record with counts and human-readable messages.
|
|
121
|
+
* Never throws — errors are captured as messages.
|
|
122
|
+
*/
|
|
123
|
+
export async function runRefreshKbLinks(cwd) {
|
|
124
|
+
const result = {
|
|
125
|
+
filesUpdated: 0,
|
|
126
|
+
filesSkipped: 0,
|
|
127
|
+
messages: [],
|
|
128
|
+
};
|
|
129
|
+
// Read kbPath from .forge/config.json
|
|
130
|
+
let kbPath = "engineering";
|
|
131
|
+
try {
|
|
132
|
+
const configRaw = fs.readFileSync(path.join(cwd, ".forge", "config.json"), "utf8");
|
|
133
|
+
const config = JSON.parse(configRaw);
|
|
134
|
+
const paths = config.paths;
|
|
135
|
+
if (paths && typeof paths.engineering === "string" && paths.engineering) {
|
|
136
|
+
kbPath = paths.engineering;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// Config not present — use default kbPath
|
|
141
|
+
}
|
|
142
|
+
const kbSection = buildKbSection(cwd, kbPath);
|
|
143
|
+
const wfSection = buildWorkflowSection(cwd);
|
|
144
|
+
if (!kbSection && !wfSection) {
|
|
145
|
+
result.messages.push("△ refresh-kb-links: no KB or workflow files found to link.");
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
for (const filename of AGENT_INSTRUCTION_FILES) {
|
|
149
|
+
const filePath = path.join(cwd, filename);
|
|
150
|
+
let content;
|
|
151
|
+
try {
|
|
152
|
+
content = fs.readFileSync(filePath, "utf8");
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// File does not exist — skip
|
|
156
|
+
result.filesSkipped++;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
let updated = content;
|
|
160
|
+
if (kbSection) {
|
|
161
|
+
updated = upsertSection(updated, KB_OPEN_PREFIX, KB_CLOSE, kbSection);
|
|
162
|
+
}
|
|
163
|
+
if (wfSection) {
|
|
164
|
+
updated = upsertSection(updated, WF_OPEN_PREFIX, WF_CLOSE, wfSection);
|
|
165
|
+
}
|
|
166
|
+
if (updated !== content) {
|
|
167
|
+
try {
|
|
168
|
+
fs.writeFileSync(filePath, updated, "utf8");
|
|
169
|
+
result.filesUpdated++;
|
|
170
|
+
result.messages.push(`〇 refresh-kb-links: updated ${filename}`);
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
const e = err;
|
|
174
|
+
result.messages.push(`△ refresh-kb-links: failed to write ${filename}: ${e.message ?? "unknown"}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
result.filesSkipped++;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Handle .cursor/rules/*.mdc files
|
|
182
|
+
const cursorRulesDir = path.join(cwd, ".cursor", "rules");
|
|
183
|
+
if (fs.existsSync(cursorRulesDir)) {
|
|
184
|
+
try {
|
|
185
|
+
const mdcFiles = fs.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"));
|
|
186
|
+
for (const mdcFile of mdcFiles) {
|
|
187
|
+
const filePath = path.join(cursorRulesDir, mdcFile);
|
|
188
|
+
let content;
|
|
189
|
+
try {
|
|
190
|
+
content = fs.readFileSync(filePath, "utf8");
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
result.filesSkipped++;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
let updated = content;
|
|
197
|
+
if (kbSection) {
|
|
198
|
+
updated = upsertSection(updated, KB_OPEN_PREFIX, KB_CLOSE, kbSection);
|
|
199
|
+
}
|
|
200
|
+
if (wfSection) {
|
|
201
|
+
updated = upsertSection(updated, WF_OPEN_PREFIX, WF_CLOSE, wfSection);
|
|
202
|
+
}
|
|
203
|
+
if (updated !== content) {
|
|
204
|
+
fs.writeFileSync(filePath, updated, "utf8");
|
|
205
|
+
result.filesUpdated++;
|
|
206
|
+
result.messages.push(`〇 refresh-kb-links: updated .cursor/rules/${mdcFile}`);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
result.filesSkipped++;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
// Skip if unreadable
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
// ── Handler factory ────────────────────────────────────────────────────────
|
|
220
|
+
/**
|
|
221
|
+
* Get a standalone refresh-kb-links handler suitable for direct invocation
|
|
222
|
+
* from Phase 4 step 4-9. Returns a function that takes cwd and calls
|
|
223
|
+
* runRefreshKbLinks.
|
|
224
|
+
*/
|
|
225
|
+
export function getRefreshKbLinksHandler() {
|
|
226
|
+
return runRefreshKbLinks;
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=refresh-kb-links.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh-kb-links.js","sourceRoot":"","sources":["../../../src/extensions/forgecli/refresh-kb-links.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface StoreValidatorResult {
|
|
2
|
+
ok: boolean;
|
|
3
|
+
reason: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Validate a store entity payload by spawning `store-cli.cjs validate`.
|
|
7
|
+
*
|
|
8
|
+
* @param entity Entity type: "task" | "sprint" | "bug" | "event" | …
|
|
9
|
+
* @param payload The raw payload (will be JSON.stringify'd if object; passed as-is if string).
|
|
10
|
+
* @param forgeRoot Absolute path to the Forge plugin root — locates store-cli.cjs.
|
|
11
|
+
* @returns `{ ok: true, reason: "" }` on success, `{ ok: false, reason: <stderr> }` on failure.
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateStoreCLIPayload(entity: string, payload: unknown, forgeRoot: string): StoreValidatorResult;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Store-CLI payload validator — FORGE-S18-T03
|
|
2
|
+
//
|
|
3
|
+
// Spawns `store-cli.cjs validate <entity> '<json>'` synchronously and surfaces
|
|
4
|
+
// any schema error as a structured result. This module is the sole point of
|
|
5
|
+
// contact between hook-dispatcher.ts and store-cli's validation logic.
|
|
6
|
+
//
|
|
7
|
+
// Why spawnSync?
|
|
8
|
+
// pi's tool_call handler is synchronous — the event system does not support
|
|
9
|
+
// async handlers. spawnSync completes before the block result is returned to pi.
|
|
10
|
+
import { spawnSync } from "node:child_process";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
/**
|
|
13
|
+
* Validate a store entity payload by spawning `store-cli.cjs validate`.
|
|
14
|
+
*
|
|
15
|
+
* @param entity Entity type: "task" | "sprint" | "bug" | "event" | …
|
|
16
|
+
* @param payload The raw payload (will be JSON.stringify'd if object; passed as-is if string).
|
|
17
|
+
* @param forgeRoot Absolute path to the Forge plugin root — locates store-cli.cjs.
|
|
18
|
+
* @returns `{ ok: true, reason: "" }` on success, `{ ok: false, reason: <stderr> }` on failure.
|
|
19
|
+
*/
|
|
20
|
+
export function validateStoreCLIPayload(entity, payload, forgeRoot) {
|
|
21
|
+
const storeCliPath = path.join(forgeRoot, "tools", "store-cli.cjs");
|
|
22
|
+
const payloadStr = typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
23
|
+
const result = spawnSync(process.execPath, // node
|
|
24
|
+
[storeCliPath, "validate", entity, payloadStr], { encoding: "utf8", timeout: 10_000 });
|
|
25
|
+
// Non-zero exit code or error signal → validation failed.
|
|
26
|
+
if (result.status !== 0 || result.error) {
|
|
27
|
+
const reason = result.stderr?.trim() ||
|
|
28
|
+
result.error?.message ||
|
|
29
|
+
`store-cli validate exited with code ${String(result.status)}` ||
|
|
30
|
+
"validation failed (no error message)";
|
|
31
|
+
return { ok: false, reason };
|
|
32
|
+
}
|
|
33
|
+
return { ok: true, reason: "" };
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=store-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-validator.js","sourceRoot":"","sources":["../../../src/extensions/forgecli/store-validator.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,uEAAuE;AACvE,EAAE;AACF,iBAAiB;AACjB,8EAA8E;AAC9E,mFAAmF;AAEnF,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAOlC;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAc,EAAE,OAAgB,EAAE,SAAiB;IAC1F,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,eAAe,CAAC,CAAC;IAEpE,MAAM,UAAU,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAEnF,MAAM,MAAM,GAAG,SAAS,CACvB,OAAO,CAAC,QAAQ,EAAE,OAAO;IACzB,CAAC,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,EAC9C,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CACrC,CAAC;IAEF,0DAA0D;IAC1D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACzC,MAAM,MAAM,GACX,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE;YACrB,MAAM,CAAC,KAAK,EAAE,OAAO;YACrB,uCAAuC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;YAC9D,sCAAsC,CAAC;QACxC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC9B,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface TransitionGuardResult {
|
|
2
|
+
allowed: boolean;
|
|
3
|
+
reason: string;
|
|
4
|
+
}
|
|
5
|
+
export interface TransitionGuardInput {
|
|
6
|
+
entity: string;
|
|
7
|
+
entityId: string;
|
|
8
|
+
toStatus: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Check whether a status transition is legal.
|
|
12
|
+
*
|
|
13
|
+
* Fail-open: if the current status cannot be read, returns
|
|
14
|
+
* `{ allowed: true, reason: "lookup-failed" }`. The caller
|
|
15
|
+
* should audit-log this outcome but MUST NOT block the operation.
|
|
16
|
+
*
|
|
17
|
+
* @param input Entity, entity ID, and target status.
|
|
18
|
+
* @param forgeRoot Absolute path to the Forge plugin root.
|
|
19
|
+
*/
|
|
20
|
+
export declare function checkTransition(input: TransitionGuardInput, forgeRoot: string): TransitionGuardResult;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Status-transition guard — FORGE-S18-T03
|
|
2
|
+
//
|
|
3
|
+
// Encodes the legal status-transition table for each entity (task, sprint, bug)
|
|
4
|
+
// and checks whether a proposed transition is allowed.
|
|
5
|
+
//
|
|
6
|
+
// The guard reads the current status from disk via `store-cli read` (spawnSync).
|
|
7
|
+
// Fail-open: if the current-status lookup fails for any reason, the guard returns
|
|
8
|
+
// { allowed: true } and sets reason="lookup-failed". The caller (hook-dispatcher)
|
|
9
|
+
// logs this as "lookup-failed" under FORGE_HOOK_AUDIT=1 but never blocks the
|
|
10
|
+
// operation — a lookup failure must not block a valid operation.
|
|
11
|
+
import { spawnSync } from "node:child_process";
|
|
12
|
+
import * as path from "node:path";
|
|
13
|
+
// ── Legal transition tables ───────────────────────────────────────────────────
|
|
14
|
+
//
|
|
15
|
+
// Derived from task.schema.json, sprint.schema.json, bug.schema.json status enums.
|
|
16
|
+
// Each entry: fromStatus → Set<toStatus>
|
|
17
|
+
const TASK_TRANSITIONS = {
|
|
18
|
+
draft: new Set(["planned", "blocked", "escalated", "abandoned"]),
|
|
19
|
+
planned: new Set(["plan-approved", "plan-revision-required", "blocked", "escalated", "abandoned"]),
|
|
20
|
+
"plan-approved": new Set(["implementing", "blocked", "escalated", "abandoned"]),
|
|
21
|
+
implementing: new Set(["implemented", "code-revision-required", "blocked", "escalated", "abandoned"]),
|
|
22
|
+
implemented: new Set(["review-approved", "blocked", "escalated", "abandoned"]),
|
|
23
|
+
"review-approved": new Set(["approved", "blocked", "escalated", "abandoned"]),
|
|
24
|
+
approved: new Set(["committed", "blocked", "escalated", "abandoned"]),
|
|
25
|
+
"plan-revision-required": new Set(["planned", "blocked", "escalated", "abandoned"]),
|
|
26
|
+
"code-revision-required": new Set(["implementing", "blocked", "escalated", "abandoned"]),
|
|
27
|
+
// Terminal / sink states — can only be re-opened by --force.
|
|
28
|
+
blocked: new Set(["blocked", "escalated", "abandoned"]),
|
|
29
|
+
escalated: new Set(["blocked", "escalated", "abandoned"]),
|
|
30
|
+
abandoned: new Set(["blocked", "escalated", "abandoned"]),
|
|
31
|
+
committed: new Set(["blocked", "escalated", "abandoned"]),
|
|
32
|
+
};
|
|
33
|
+
const SPRINT_TRANSITIONS = {
|
|
34
|
+
planning: new Set(["active", "abandoned"]),
|
|
35
|
+
active: new Set(["completed", "partially-completed", "blocked", "abandoned"]),
|
|
36
|
+
completed: new Set(["retrospective-done"]),
|
|
37
|
+
"partially-completed": new Set(["retrospective-done"]),
|
|
38
|
+
"retrospective-done": new Set([]),
|
|
39
|
+
blocked: new Set(["active", "abandoned"]),
|
|
40
|
+
abandoned: new Set([]),
|
|
41
|
+
};
|
|
42
|
+
const BUG_TRANSITIONS = {
|
|
43
|
+
reported: new Set(["triaged", "abandoned"]),
|
|
44
|
+
triaged: new Set(["in-progress", "abandoned"]),
|
|
45
|
+
"in-progress": new Set(["fixed", "abandoned"]),
|
|
46
|
+
fixed: new Set(["verified"]),
|
|
47
|
+
verified: new Set([]),
|
|
48
|
+
abandoned: new Set([]),
|
|
49
|
+
};
|
|
50
|
+
const ENTITY_TABLES = {
|
|
51
|
+
task: TASK_TRANSITIONS,
|
|
52
|
+
sprint: SPRINT_TRANSITIONS,
|
|
53
|
+
bug: BUG_TRANSITIONS,
|
|
54
|
+
};
|
|
55
|
+
function legalNextStates(entity, fromStatus) {
|
|
56
|
+
const table = ENTITY_TABLES[entity];
|
|
57
|
+
if (!table)
|
|
58
|
+
return [];
|
|
59
|
+
const allowed = table[fromStatus];
|
|
60
|
+
return allowed ? [...allowed] : [];
|
|
61
|
+
}
|
|
62
|
+
// ── Current-status lookup (fail-open) ────────────────────────────────────────
|
|
63
|
+
/**
|
|
64
|
+
* Read the current status of an entity from the store via `store-cli read`.
|
|
65
|
+
* Returns the status string on success, or null on any failure (fail-open).
|
|
66
|
+
*/
|
|
67
|
+
function readCurrentStatus(entity, entityId, forgeRoot) {
|
|
68
|
+
const storeCliPath = path.join(forgeRoot, "tools", "store-cli.cjs");
|
|
69
|
+
try {
|
|
70
|
+
const result = spawnSync(process.execPath, [storeCliPath, "read", entity, entityId], {
|
|
71
|
+
encoding: "utf8",
|
|
72
|
+
timeout: 10_000,
|
|
73
|
+
});
|
|
74
|
+
if (result.status !== 0 || result.error)
|
|
75
|
+
return null;
|
|
76
|
+
const stdout = result.stdout?.trim();
|
|
77
|
+
if (!stdout)
|
|
78
|
+
return null;
|
|
79
|
+
// store-cli read emits JSON; parse and extract the status field.
|
|
80
|
+
const record = JSON.parse(stdout);
|
|
81
|
+
const status = record.status;
|
|
82
|
+
return typeof status === "string" ? status : null;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Any parse error or subprocess error → fail-open.
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check whether a status transition is legal.
|
|
91
|
+
*
|
|
92
|
+
* Fail-open: if the current status cannot be read, returns
|
|
93
|
+
* `{ allowed: true, reason: "lookup-failed" }`. The caller
|
|
94
|
+
* should audit-log this outcome but MUST NOT block the operation.
|
|
95
|
+
*
|
|
96
|
+
* @param input Entity, entity ID, and target status.
|
|
97
|
+
* @param forgeRoot Absolute path to the Forge plugin root.
|
|
98
|
+
*/
|
|
99
|
+
export function checkTransition(input, forgeRoot) {
|
|
100
|
+
const { entity, entityId, toStatus } = input;
|
|
101
|
+
// Lookup current status — fail-open on any error.
|
|
102
|
+
const fromStatus = readCurrentStatus(entity, entityId, forgeRoot);
|
|
103
|
+
if (fromStatus === null) {
|
|
104
|
+
return {
|
|
105
|
+
allowed: true,
|
|
106
|
+
reason: "lookup-failed",
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const table = ENTITY_TABLES[entity];
|
|
110
|
+
if (!table) {
|
|
111
|
+
// Unknown entity type — allow through (future-proofing).
|
|
112
|
+
return { allowed: true, reason: "" };
|
|
113
|
+
}
|
|
114
|
+
const allowed = table[fromStatus]?.has(toStatus) ?? false;
|
|
115
|
+
if (allowed) {
|
|
116
|
+
return { allowed: true, reason: "" };
|
|
117
|
+
}
|
|
118
|
+
const legal = legalNextStates(entity, fromStatus);
|
|
119
|
+
const legalStr = legal.length > 0 ? legal.join(", ") : "(none)";
|
|
120
|
+
return {
|
|
121
|
+
allowed: false,
|
|
122
|
+
reason: `${fromStatus} → ${toStatus} is not a legal transition for ${entity}. Legal next states from ${fromStatus}: ${legalStr}.`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=transition-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transition-guard.js","sourceRoot":"","sources":["../../../src/extensions/forgecli/transition-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: approve
|
|
3
|
+
description: Final architect approval gate for a completed task
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /{{PREFIX}}:approve
|
|
7
|
+
|
|
8
|
+
Read the approve workflow and follow it.
|
|
9
|
+
|
|
10
|
+
## Locate the Forge plugin
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
FORGE_ROOT: !`echo "${CLAUDE_PLUGIN_ROOT}"`
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Execute
|
|
17
|
+
|
|
18
|
+
Read `.forge/workflows/architect_approve.md` and follow it.
|
|
19
|
+
|
|
20
|
+
## Arguments
|
|
21
|
+
|
|
22
|
+
$ARGUMENTS
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: collate
|
|
3
|
+
description: Regenerate KB documents from the JSON store
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /{{PREFIX}}:collate
|
|
7
|
+
|
|
8
|
+
Read the collate workflow and follow it.
|
|
9
|
+
|
|
10
|
+
## Locate the Forge plugin
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
FORGE_ROOT: !`echo "${CLAUDE_PLUGIN_ROOT}"`
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Execute
|
|
17
|
+
|
|
18
|
+
Read `.forge/workflows/collator_agent.md` and follow it.
|
|
19
|
+
|
|
20
|
+
## Arguments
|
|
21
|
+
|
|
22
|
+
$ARGUMENTS
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: commit
|
|
3
|
+
description: Stage and commit completed task artifacts
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /{{PREFIX}}:commit
|
|
7
|
+
|
|
8
|
+
Read the commit workflow and follow it.
|
|
9
|
+
|
|
10
|
+
## Locate the Forge plugin
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
FORGE_ROOT: !`echo "${CLAUDE_PLUGIN_ROOT}"`
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Execute
|
|
17
|
+
|
|
18
|
+
Read `.forge/workflows/commit_task.md` and follow it.
|
|
19
|
+
|
|
20
|
+
## Arguments
|
|
21
|
+
|
|
22
|
+
$ARGUMENTS
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: enhance
|
|
3
|
+
description: Progressive project-specific enrichment of structural elements
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /{{PREFIX}}:enhance
|
|
7
|
+
|
|
8
|
+
Run the enhancement agent to enrich structural elements with project-specific knowledge.
|
|
9
|
+
|
|
10
|
+
## Locate the Forge plugin
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
FORGE_ROOT: !`echo "${CLAUDE_PLUGIN_ROOT}"`
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Purpose
|
|
17
|
+
|
|
18
|
+
The enhancement agent observes the project and enriches structural elements
|
|
19
|
+
over time. It makes absolutely essential minimal modifications, preferring
|
|
20
|
+
runtime mix-in (KB references, `{{placeholder}}` substitution, `project-context.json`)
|
|
21
|
+
over modifying base artifacts.
|
|
22
|
+
|
|
23
|
+
## Behavior
|
|
24
|
+
|
|
25
|
+
1. Read `structure-versions.json` to determine current overlay level
|
|
26
|
+
2. Read `project-context.json` for current project specifics
|
|
27
|
+
3. Read KB changes since last enhancement
|
|
28
|
+
4. Scan codebase for patterns discovered since last enhancement
|
|
29
|
+
5. Compare current `.forge/` artifacts against base-pack baseline
|
|
30
|
+
6. For each artifact, determine what project-specific enrichment is warranted
|
|
31
|
+
7. Apply the minimal modification principle
|
|
32
|
+
8. Propose diffs (Phase 2+) or auto-apply (Phase 1)
|
|
33
|
+
9. Create new overlay version in `structure-versions.json` if needed
|
|
34
|
+
|
|
35
|
+
## Arguments
|
|
36
|
+
|
|
37
|
+
$ARGUMENTS
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fix-bug
|
|
3
|
+
description: Triage, diagnose, and fix a bug
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /{{PREFIX}}:fix-bug
|
|
7
|
+
|
|
8
|
+
Read the fix-bug workflow and follow it.
|
|
9
|
+
|
|
10
|
+
## Locate the Forge plugin
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
FORGE_ROOT: !`echo "${CLAUDE_PLUGIN_ROOT}"`
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Execute
|
|
17
|
+
|
|
18
|
+
Read `.forge/workflows/fix_bug.md` and follow it.
|
|
19
|
+
|
|
20
|
+
## Arguments
|
|
21
|
+
|
|
22
|
+
$ARGUMENTS
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: implement
|
|
3
|
+
description: Execute the approved implementation plan for a task
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /{{PREFIX}}:implement
|
|
7
|
+
|
|
8
|
+
Read the implement workflow and follow it.
|
|
9
|
+
|
|
10
|
+
## Locate the Forge plugin
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
FORGE_ROOT: !`echo "${CLAUDE_PLUGIN_ROOT}"`
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Execute
|
|
17
|
+
|
|
18
|
+
Read `.forge/workflows/implement_plan.md` and follow it.
|
|
19
|
+
|
|
20
|
+
## Arguments
|
|
21
|
+
|
|
22
|
+
$ARGUMENTS
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plan
|
|
3
|
+
description: Design and document the implementation plan for a task
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /{{PREFIX}}:plan
|
|
7
|
+
|
|
8
|
+
Read the plan workflow and follow it.
|
|
9
|
+
|
|
10
|
+
## Locate the Forge plugin
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
FORGE_ROOT: !`echo "${CLAUDE_PLUGIN_ROOT}"`
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Execute
|
|
17
|
+
|
|
18
|
+
Read `.forge/workflows/plan_task.md` and follow it.
|
|
19
|
+
|
|
20
|
+
## Arguments
|
|
21
|
+
|
|
22
|
+
$ARGUMENTS
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: quiz-agent
|
|
3
|
+
description: Verify an agent has loaded and understood the project knowledge base
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /{{PREFIX}}:quiz-agent
|
|
7
|
+
|
|
8
|
+
Read the quiz-agent workflow and follow it.
|
|
9
|
+
|
|
10
|
+
## Locate the Forge plugin
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
FORGE_ROOT: !`echo "${CLAUDE_PLUGIN_ROOT}"`
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Execute
|
|
17
|
+
|
|
18
|
+
Read `.forge/workflows/quiz_agent.md` and follow it.
|
|
19
|
+
|
|
20
|
+
## Arguments
|
|
21
|
+
|
|
22
|
+
$ARGUMENTS
|