compound-workflow 1.6.3 → 1.6.5
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/.claude-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/package.json +2 -1
- package/scripts/generate-platform-artifacts.mjs +75 -35
- package/src/.agents/commands/workflow/brainstorm.md +2 -0
- package/src/.agents/commands/workflow/compound.md +11 -7
- package/src/.agents/commands/workflow/plan.md +5 -1
- package/src/.agents/commands/workflow/review.md +2 -0
- package/src/.agents/commands/workflow/tech-review.md +2 -0
- package/src/.agents/commands/workflow/triage.md +2 -0
- package/src/.agents/commands/workflow/work.md +2 -0
- package/src/.agents/registry.json +48 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compound-workflow",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.5",
|
|
4
4
|
"description": "Clarify → plan → execute → verify → capture. One Install action for Cursor, Claude, and OpenCode.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
20
|
"postinstall": "node scripts/postinstall.mjs",
|
|
21
|
+
"prepublishOnly": "npm run generate:artifacts",
|
|
21
22
|
"generate:artifacts": "node scripts/generate-platform-artifacts.mjs",
|
|
22
23
|
"check:artifacts": "node scripts/generate-platform-artifacts.mjs --check",
|
|
23
24
|
"check:version-parity": "node scripts/check-version-parity.mjs",
|
|
@@ -7,6 +7,14 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
7
7
|
const repoRoot = path.resolve(__dirname, "..");
|
|
8
8
|
const agentsRoot = path.join(repoRoot, "src", ".agents");
|
|
9
9
|
|
|
10
|
+
function loadRegistry() {
|
|
11
|
+
const registryPath = path.join(agentsRoot, "registry.json");
|
|
12
|
+
if (!fs.existsSync(registryPath)) {
|
|
13
|
+
throw new Error(`Registry not found at ${registryPath}`);
|
|
14
|
+
}
|
|
15
|
+
return JSON.parse(fs.readFileSync(registryPath, "utf8"));
|
|
16
|
+
}
|
|
17
|
+
|
|
10
18
|
function walkFiles(dirAbs, predicate) {
|
|
11
19
|
const out = [];
|
|
12
20
|
const stack = [dirAbs];
|
|
@@ -42,44 +50,64 @@ function parseFrontmatter(md) {
|
|
|
42
50
|
return out;
|
|
43
51
|
}
|
|
44
52
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
id,
|
|
57
|
-
description: (frontmatter.description || id).trim(),
|
|
58
|
-
rel: relWithin,
|
|
59
|
-
});
|
|
53
|
+
/**
|
|
54
|
+
* Resolve id from frontmatter and config. idFrom = list of frontmatter keys; idFallback = "basename" | "dirname".
|
|
55
|
+
*/
|
|
56
|
+
function resolveId(frontmatter, fileAbs, dirAbs, config) {
|
|
57
|
+
for (const key of config.idFrom || []) {
|
|
58
|
+
if (key === "dirname") {
|
|
59
|
+
const relDir = path.relative(dirAbs, path.dirname(fileAbs));
|
|
60
|
+
return (relDir ? relDir.replaceAll(path.sep, "/") : path.basename(path.dirname(fileAbs))).trim();
|
|
61
|
+
}
|
|
62
|
+
const v = frontmatter[key];
|
|
63
|
+
if (typeof v === "string" && v.trim()) return v.trim();
|
|
60
64
|
}
|
|
65
|
+
if (config.idFallback === "basename") return path.basename(fileAbs, ".md").trim();
|
|
66
|
+
if (config.idFallback === "dirname") return path.basename(path.dirname(fileAbs)).trim();
|
|
67
|
+
return path.basename(fileAbs, ".md").trim();
|
|
68
|
+
}
|
|
61
69
|
|
|
62
|
-
|
|
70
|
+
function resolveDescription(frontmatter, config, id) {
|
|
71
|
+
const key = config.descriptionFrom;
|
|
72
|
+
if (key && frontmatter[key] != null) return String(frontmatter[key]).trim();
|
|
73
|
+
if (config.descriptionFallback === "id") return id || "";
|
|
74
|
+
return id || "";
|
|
63
75
|
}
|
|
64
76
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Discover assets of one type from registry config. Returns array of { id, description, rel }.
|
|
79
|
+
*/
|
|
80
|
+
function discoverByType(agentsRootAbs, typeKey, config) {
|
|
81
|
+
const dirAbs = path.join(agentsRootAbs, config.dir);
|
|
82
|
+
if (!fs.existsSync(dirAbs)) return [];
|
|
83
|
+
|
|
84
|
+
let files = [];
|
|
85
|
+
if (config.glob === "**/*.md") {
|
|
86
|
+
files = walkFiles(dirAbs, (p) => p.endsWith(".md"));
|
|
87
|
+
} else if (config.glob === "*/SKILL.md") {
|
|
88
|
+
const entries = fs.readdirSync(dirAbs, { withFileTypes: true });
|
|
89
|
+
for (const e of entries) {
|
|
90
|
+
if (e.isDirectory()) {
|
|
91
|
+
const skillMd = path.join(dirAbs, e.name, "SKILL.md");
|
|
92
|
+
if (fs.existsSync(skillMd)) files.push(skillMd);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
files.sort();
|
|
96
|
+
} else {
|
|
97
|
+
files = walkFiles(dirAbs, (p) => p.endsWith(".md"));
|
|
98
|
+
}
|
|
69
99
|
|
|
100
|
+
const out = [];
|
|
70
101
|
for (const fileAbs of files) {
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
const
|
|
102
|
+
const rel = path.relative(dirAbs, fileAbs).replaceAll(path.sep, "/");
|
|
103
|
+
const raw = fs.readFileSync(fileAbs, "utf8");
|
|
104
|
+
const frontmatter = parseFrontmatter(raw);
|
|
105
|
+
const id = resolveId(frontmatter, fileAbs, dirAbs, config);
|
|
74
106
|
if (!id) continue;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
description: (frontmatter.description || id).trim(),
|
|
78
|
-
rel: relWithin,
|
|
79
|
-
});
|
|
107
|
+
const description = resolveDescription(frontmatter, config, id);
|
|
108
|
+
out.push({ id, description, rel });
|
|
80
109
|
}
|
|
81
|
-
|
|
82
|
-
return agents.sort((a, b) => a.id.localeCompare(b.id));
|
|
110
|
+
return out.sort((a, b) => a.id.localeCompare(b.id));
|
|
83
111
|
}
|
|
84
112
|
|
|
85
113
|
function normalizeRepoUrl(repoValue) {
|
|
@@ -105,13 +133,25 @@ function writeJson(absPath, value, checkOnly, changed) {
|
|
|
105
133
|
|
|
106
134
|
function main() {
|
|
107
135
|
const checkOnly = process.argv.includes("--check");
|
|
136
|
+
const registry = loadRegistry();
|
|
137
|
+
const roots = registry.roots?.consumer || {};
|
|
138
|
+
const assetTypes = registry.assetTypes || {};
|
|
139
|
+
|
|
140
|
+
const commands =
|
|
141
|
+
assetTypes.command != null
|
|
142
|
+
? discoverByType(agentsRoot, "command", assetTypes.command)
|
|
143
|
+
: [];
|
|
144
|
+
const agents =
|
|
145
|
+
assetTypes.agent != null ? discoverByType(agentsRoot, "agent", assetTypes.agent) : [];
|
|
108
146
|
|
|
109
147
|
const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, "package.json"), "utf8"));
|
|
110
148
|
const repositoryUrl = normalizeRepoUrl(pkg.repository);
|
|
111
|
-
const commands = discoverCommands();
|
|
112
|
-
const agents = discoverAgents();
|
|
113
149
|
const changed = [];
|
|
114
150
|
|
|
151
|
+
const commandRoot = roots.commands || "node_modules/compound-workflow/src/.agents/commands";
|
|
152
|
+
const agentRoot = roots.agents || "node_modules/compound-workflow/src/.agents/agents";
|
|
153
|
+
const skillsPath = roots.skills || "node_modules/compound-workflow/src/.agents/skills";
|
|
154
|
+
|
|
115
155
|
const claudePlugin = {
|
|
116
156
|
name: pkg.name,
|
|
117
157
|
version: pkg.version,
|
|
@@ -140,9 +180,9 @@ function main() {
|
|
|
140
180
|
|
|
141
181
|
const openCodeManaged = {
|
|
142
182
|
$schema: "https://opencode.ai/config.json",
|
|
143
|
-
skillsPath
|
|
144
|
-
commandRoot
|
|
145
|
-
agentRoot
|
|
183
|
+
skillsPath,
|
|
184
|
+
commandRoot,
|
|
185
|
+
agentRoot,
|
|
146
186
|
commands,
|
|
147
187
|
agents,
|
|
148
188
|
};
|
|
@@ -18,6 +18,8 @@ it.
|
|
|
18
18
|
discussion-first facilitation (one-question-then-prompts), approach
|
|
19
19
|
exploration patterns, and YAGNI principles.
|
|
20
20
|
|
|
21
|
+
It is critical that you follow this workflow in order; do not skip or shortcut steps.
|
|
22
|
+
|
|
21
23
|
## Guardrails
|
|
22
24
|
|
|
23
25
|
- Do not write or modify application code.
|
|
@@ -27,6 +27,8 @@ Do not create drafts, notes, or intermediate files.
|
|
|
27
27
|
After the primary solution doc is written, optional post-capture actions (by explicit user choice) may update other references (e.g. patterns indexes).
|
|
28
28
|
</critical_requirement>
|
|
29
29
|
|
|
30
|
+
It is critical that you follow this workflow in order; do not skip or shortcut steps.
|
|
31
|
+
|
|
30
32
|
## Usage
|
|
31
33
|
|
|
32
34
|
```bash
|
|
@@ -49,14 +51,16 @@ After the primary solution doc is written, optional post-capture actions (by exp
|
|
|
49
51
|
- **Implementation insight:** For feature work, confirm implementation is complete and there is a reusable learning or pattern to capture (no "problem solved" requirement for this path).
|
|
50
52
|
- If critical context is missing, ask targeted questions and wait. Then **invoke the `compound-docs` skill** (it defines required fields, validation gates, and template).
|
|
51
53
|
|
|
52
|
-
### 2.
|
|
54
|
+
### 2. Required research (before write)
|
|
55
|
+
|
|
56
|
+
Research is required and must run in subagents. Do not perform research in-context. Run all research via Task (subagent). If the environment cannot run the Task, state that and perform a minimal in-context fallback, then proceed to capture.
|
|
53
57
|
|
|
54
|
-
Run only agents that exist in this `.agents` workspace. **
|
|
58
|
+
Run only agents that exist in this `.agents` workspace. **Research is read-only**—it informs the doc content but must not write files.
|
|
55
59
|
|
|
56
|
-
-
|
|
57
|
-
-
|
|
60
|
+
- **Required:** `Task learnings-researcher(<symptom/module/root cause keywords>)` (related docs).
|
|
61
|
+
- **Conditional** (when the topic warrants, e.g. framework usage or cross-cutting patterns): `Task best-practices-researcher(<topic>)`, `Task framework-docs-researcher(<topic>)`. When run, these must also run as Tasks.
|
|
58
62
|
|
|
59
|
-
Complete
|
|
63
|
+
Complete research before assembly. Report which enrichments ran (required: learnings-researcher; conditional: best-practices, framework-docs) and which were skipped.
|
|
60
64
|
|
|
61
65
|
### 3. Capture
|
|
62
66
|
|
|
@@ -105,14 +109,14 @@ User may optionally run `document-review` on the created doc. If the repo has do
|
|
|
105
109
|
|
|
106
110
|
## Success output (shape)
|
|
107
111
|
|
|
108
|
-
Report which
|
|
112
|
+
Report which enrichments ran (required: learnings-researcher; conditional: best-practices, framework-docs) and which were skipped. Then output the path of the created file. Present the **`compound-docs` decision menu** (see skill) and wait for user choice—do not substitute a shorter custom menu.
|
|
109
113
|
|
|
110
114
|
Example summary (generic, portable):
|
|
111
115
|
|
|
112
116
|
```
|
|
113
117
|
✓ Documentation complete
|
|
114
118
|
|
|
115
|
-
|
|
119
|
+
Enrichments: learnings-researcher (required) ran|skipped; best-practices ran|skipped; framework-docs ran|skipped
|
|
116
120
|
|
|
117
121
|
File created: docs/solutions/<category>/YYYY-MM-DD-<module-slug>-<symptom-slug>.md
|
|
118
122
|
|
|
@@ -15,6 +15,8 @@ Transform feature descriptions, bug reports, or improvement ideas into well-stru
|
|
|
15
15
|
|
|
16
16
|
Contract precedence: if this command conflicts with other workflow docs, follow `docs/principles/workflow-baseline-principles.md`, then `src/AGENTS.md`, then this command.
|
|
17
17
|
|
|
18
|
+
It is critical that you follow this workflow in order; do not skip or shortcut steps.
|
|
19
|
+
|
|
18
20
|
This workflow MUST choose a planning fidelity and confidence level before final plan construction:
|
|
19
21
|
|
|
20
22
|
- Fidelity: `Low | Medium | High`
|
|
@@ -833,7 +835,7 @@ Write the complete plan file to `docs/plans/YYYY-MM-DD-<type>-<slug>-plan.md`. T
|
|
|
833
835
|
|
|
834
836
|
Confirm: "Plan written to docs/plans/[filename]"
|
|
835
837
|
|
|
836
|
-
**
|
|
838
|
+
**Technical review (required when Fidelity is Medium or High):** After writing the plan file, if the declared **Fidelity is Medium or High**, you **must** run technical review—it is not optional. Run **Task planning-technical-reviewer(plan_path)** using the plan path just written. Do not perform technical review in-context unless the environment cannot run the Task; if you fall back, state "planning-technical-reviewer unavailable; running direct technical review (degraded bias resistance)" and then load the `technical-review` skill and run it in-context. If Fidelity is Low, skip this step; the user can still choose "Technical review" from Post-Generation Options or call `/workflow:tech-review` later.
|
|
837
839
|
|
|
838
840
|
**Non-interactive mode:** When the invocation is non-interactive (e.g., `workflow:plan` run by automation, CI, or with an explicit non-interactive flag/convention), skip AskQuestion calls and do not present Post-Generation Options. For determinism, the repo should define the flag or convention (e.g., in `AGENTS.md` Repo Config Block or a documented env var). Still **declare** Fidelity, Confidence, Solution scope, Spike evaluation, Spikes needed, Research mode, and Open questions in the required announcement format before writing the plan. Use these defaults when user input is unavailable: fidelity = Medium, confidence = Medium, solution_scope = full_remediation, spike evaluation = not-required unless risky-work triggers are present, spikes needed = n/a when spike evaluation is not required, research mode = local + external for Medium/High risk topics else local only. Proceed directly to writing the plan file and then exit or return the plan path as output.
|
|
839
841
|
|
|
@@ -863,6 +865,8 @@ Examples:
|
|
|
863
865
|
|
|
864
866
|
## Post-Generation Options
|
|
865
867
|
|
|
868
|
+
Technical review (above) is required for Medium/High fidelity and must be run via subagent when available.
|
|
869
|
+
|
|
866
870
|
After writing the plan file, use **AskQuestion** to present these options:
|
|
867
871
|
|
|
868
872
|
**Question:** "Plan ready at `docs/plans/YYYY-MM-DD-<type>-<slug>-plan.md`. What would you like to do next?"
|
|
@@ -13,6 +13,8 @@ Contract precedence: if this command conflicts with other workflow docs, follow
|
|
|
13
13
|
|
|
14
14
|
**If the user provides a document path** (e.g. a plan or spec): redirect to the `technical-review` skill for technical correctness (no edits), and/or the `document-review` skill to refine the document. This command does not review documents.
|
|
15
15
|
|
|
16
|
+
It is critical that you follow this workflow in order; do not skip or shortcut steps.
|
|
17
|
+
|
|
16
18
|
Guardrails (unless explicitly requested):
|
|
17
19
|
|
|
18
20
|
- Do not modify code or documents
|
|
@@ -11,6 +11,8 @@ Run technical review on a feature approach or plan document. Checks technical al
|
|
|
11
11
|
|
|
12
12
|
Contract precedence: if this command conflicts with other workflow docs, follow `docs/principles/workflow-baseline-principles.md`, then `src/AGENTS.md`, then this command.
|
|
13
13
|
|
|
14
|
+
It is critical that you follow this workflow in order; do not skip or shortcut steps.
|
|
15
|
+
|
|
14
16
|
## Inputs
|
|
15
17
|
|
|
16
18
|
- **Plan path (optional):** `$ARGUMENTS` — path to the plan file (e.g. `docs/plans/YYYY-MM-DD-<type>-<slug>-plan.md`).
|
|
@@ -16,6 +16,8 @@ Output of this command is the only executable queue for `/workflow:work`.
|
|
|
16
16
|
|
|
17
17
|
Contract precedence: if this command conflicts with other workflow docs, follow `docs/principles/workflow-baseline-principles.md`, then `src/AGENTS.md`, then this command.
|
|
18
18
|
|
|
19
|
+
It is critical that you follow this workflow in order; do not skip or shortcut steps.
|
|
20
|
+
|
|
19
21
|
## Inputs
|
|
20
22
|
|
|
21
23
|
- Default: triage all active todos under `todos/` (`pending` + `ready`)
|
|
@@ -15,6 +15,8 @@ This command takes a plan file and executes it systematically. The focus is on c
|
|
|
15
15
|
|
|
16
16
|
Contract precedence: if this command conflicts with other workflow docs, follow `docs/principles/workflow-baseline-principles.md`, then `src/AGENTS.md`, then this command.
|
|
17
17
|
|
|
18
|
+
It is critical that you follow this workflow in order; do not skip or shortcut steps.
|
|
19
|
+
|
|
18
20
|
Non-goals (unless explicitly requested):
|
|
19
21
|
|
|
20
22
|
- Creating commits
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://compound-workflow.dev/registry.schema.json",
|
|
3
|
+
"roots": {
|
|
4
|
+
"package": {
|
|
5
|
+
"commands": "src/.agents/commands",
|
|
6
|
+
"agents": "src/.agents/agents",
|
|
7
|
+
"skills": "src/.agents/skills",
|
|
8
|
+
"references": "src/.agents/references"
|
|
9
|
+
},
|
|
10
|
+
"consumer": {
|
|
11
|
+
"commands": "node_modules/compound-workflow/src/.agents/commands",
|
|
12
|
+
"agents": "node_modules/compound-workflow/src/.agents/agents",
|
|
13
|
+
"skills": "node_modules/compound-workflow/src/.agents/skills",
|
|
14
|
+
"references": "node_modules/compound-workflow/src/.agents/references"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"assetTypes": {
|
|
18
|
+
"command": {
|
|
19
|
+
"dir": "commands",
|
|
20
|
+
"glob": "**/*.md",
|
|
21
|
+
"idFrom": ["invocation", "name"],
|
|
22
|
+
"idFallback": "basename",
|
|
23
|
+
"descriptionFrom": "description",
|
|
24
|
+
"descriptionFallback": "id",
|
|
25
|
+
"output": ["opencode.command", "plugin.commands"]
|
|
26
|
+
},
|
|
27
|
+
"agent": {
|
|
28
|
+
"dir": "agents",
|
|
29
|
+
"glob": "**/*.md",
|
|
30
|
+
"idFrom": ["name"],
|
|
31
|
+
"idFallback": "basename",
|
|
32
|
+
"descriptionFrom": "description",
|
|
33
|
+
"descriptionFallback": "id",
|
|
34
|
+
"output": ["opencode.agent", "plugin.agents"]
|
|
35
|
+
},
|
|
36
|
+
"skill": {
|
|
37
|
+
"dir": "skills",
|
|
38
|
+
"glob": "*/SKILL.md",
|
|
39
|
+
"idFrom": ["dirname"],
|
|
40
|
+
"output": ["opencode.skillsPath", "plugin.skills"]
|
|
41
|
+
},
|
|
42
|
+
"reference": {
|
|
43
|
+
"dir": "references",
|
|
44
|
+
"glob": "**/*.md",
|
|
45
|
+
"output": ["path"]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|