compound-workflow 0.1.1
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/marketplace.json +11 -0
- package/.claude-plugin/plugin.json +12 -0
- package/.cursor-plugin/plugin.json +12 -0
- package/README.md +155 -0
- package/package.json +22 -0
- package/scripts/install-cli.mjs +313 -0
- package/scripts/sync-into-repo.sh +103 -0
- package/src/.agents/agents/research/best-practices-researcher.md +132 -0
- package/src/.agents/agents/research/framework-docs-researcher.md +134 -0
- package/src/.agents/agents/research/git-history-analyzer.md +62 -0
- package/src/.agents/agents/research/learnings-researcher.md +288 -0
- package/src/.agents/agents/research/repo-research-analyst.md +146 -0
- package/src/.agents/agents/review/agent-native-reviewer.md +299 -0
- package/src/.agents/agents/workflow/bug-reproduction-validator.md +87 -0
- package/src/.agents/agents/workflow/lint.md +20 -0
- package/src/.agents/agents/workflow/spec-flow-analyzer.md +149 -0
- package/src/.agents/commands/assess.md +60 -0
- package/src/.agents/commands/install.md +53 -0
- package/src/.agents/commands/metrics.md +59 -0
- package/src/.agents/commands/setup.md +9 -0
- package/src/.agents/commands/sync.md +9 -0
- package/src/.agents/commands/test-browser.md +393 -0
- package/src/.agents/commands/workflow/brainstorm.md +252 -0
- package/src/.agents/commands/workflow/compound.md +142 -0
- package/src/.agents/commands/workflow/plan.md +737 -0
- package/src/.agents/commands/workflow/review-v2.md +148 -0
- package/src/.agents/commands/workflow/review.md +110 -0
- package/src/.agents/commands/workflow/triage.md +54 -0
- package/src/.agents/commands/workflow/work.md +439 -0
- package/src/.agents/references/README.md +12 -0
- package/src/.agents/references/standards/README.md +9 -0
- package/src/.agents/scripts/self-check.mjs +227 -0
- package/src/.agents/scripts/sync-opencode.mjs +355 -0
- package/src/.agents/skills/agent-browser/SKILL.md +223 -0
- package/src/.agents/skills/audit-traceability/SKILL.md +260 -0
- package/src/.agents/skills/brainstorming/SKILL.md +250 -0
- package/src/.agents/skills/compound-docs/SKILL.md +533 -0
- package/src/.agents/skills/compound-docs/assets/critical-pattern-template.md +34 -0
- package/src/.agents/skills/compound-docs/assets/resolution-template.md +97 -0
- package/src/.agents/skills/compound-docs/references/yaml-schema.md +87 -0
- package/src/.agents/skills/compound-docs/schema.project.yaml +18 -0
- package/src/.agents/skills/compound-docs/schema.yaml +119 -0
- package/src/.agents/skills/data-foundations/SKILL.md +185 -0
- package/src/.agents/skills/document-review/SKILL.md +108 -0
- package/src/.agents/skills/file-todos/SKILL.md +177 -0
- package/src/.agents/skills/file-todos/assets/todo-template.md +106 -0
- package/src/.agents/skills/financial-workflow-integrity/SKILL.md +423 -0
- package/src/.agents/skills/git-worktree/SKILL.md +268 -0
- package/src/.agents/skills/pii-protection-prisma/SKILL.md +629 -0
- package/src/.agents/skills/process-metrics/SKILL.md +46 -0
- package/src/.agents/skills/process-metrics/assets/daily-template.md +37 -0
- package/src/.agents/skills/process-metrics/assets/monthly-template.md +21 -0
- package/src/.agents/skills/process-metrics/assets/weekly-template.md +25 -0
- package/src/.agents/skills/technical-review/SKILL.md +83 -0
- package/src/AGENTS.md +213 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "compound-workflow",
|
|
3
|
+
"owner": { "name": "Compound Workflow" },
|
|
4
|
+
"plugins": [
|
|
5
|
+
{
|
|
6
|
+
"name": "compound-workflow",
|
|
7
|
+
"source": ".",
|
|
8
|
+
"description": "Clarify → plan → execute → verify → capture workflow. Commands, skills, and agents for structured development."
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "compound-workflow",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Clarify → plan → execute → verify → capture workflow: commands, skills, and agents for Claude Code",
|
|
5
|
+
"author": { "name": "Compound Workflow" },
|
|
6
|
+
"keywords": ["workflow", "planning", "agents", "skills", "commands"],
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": "https://github.com/your-org/compound-workflow",
|
|
9
|
+
"commands": "./src/.agents/commands",
|
|
10
|
+
"agents": "./src/.agents/agents",
|
|
11
|
+
"skills": "./src/.agents/skills"
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "compound-workflow",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Clarify → plan → execute → verify → capture workflow: commands, skills, and agents for Cursor, Claude, and OpenCode",
|
|
5
|
+
"author": { "name": "Compound Workflow" },
|
|
6
|
+
"keywords": ["workflow", "cursor", "claude", "opencode", "agents", "planning"],
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": { "type": "git", "url": "https://github.com/your-org/compound-workflow" },
|
|
9
|
+
"skills": "src/.agents/skills",
|
|
10
|
+
"agents": "src/.agents/agents",
|
|
11
|
+
"commands": "src/.agents/commands"
|
|
12
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Compound Workflow (.agents)
|
|
2
|
+
|
|
3
|
+
A portable, command-first workflow: **clarify → plan → execute → verify → capture**. Commands are the public API; skills and agents are composable internals.
|
|
4
|
+
|
|
5
|
+
It reduces delivery failures from **unclear intent**, **weak verification**, and **lost context**. Use it when you want structured cycles without ad-hoc tooling.
|
|
6
|
+
|
|
7
|
+
*This template and README are continually refined during development.*
|
|
8
|
+
|
|
9
|
+
Inspired by [Compound Engineering](https://every.to/guides/compound-engineering) (Every) — the AI-native philosophy that each unit of work should compound into the next.
|
|
10
|
+
|
|
11
|
+
Runtime assets live in `src/.agents/` and `src/AGENTS.md`. **Cursor/Claude:** load via plugin. **OpenCode:** install the npm package and run Install once.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Get started
|
|
16
|
+
|
|
17
|
+
**One action:** In your project (with compound-workflow as a dependency), run **Install**—either the `/install` command in Cursor/Claude or:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install compound-workflow
|
|
21
|
+
npx compound-workflow install
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Optional: `--dry-run` (preview), `--root /path/to/project`, `--no-config` (skip Repo Config Block reminder).
|
|
25
|
+
|
|
26
|
+
Install writes `opencode.json` (OpenCode loads from the package), merges `AGENTS.md` (preserves your Repo Config Block), creates standard dirs, and reminds you to set the Repo Config Block in `AGENTS.md` if needed. No copy; Cursor/Claude use the plugin; OpenCode reads from `node_modules/compound-workflow`.
|
|
27
|
+
|
|
28
|
+
**Cursor / Claude:** Add the compound-workflow plugin (from this repo or marketplace). Then in any repo you can run `/install` or use the CLI above.
|
|
29
|
+
|
|
30
|
+
**Legacy (clone inside repo):** If you cloned this repo inside a host repo and need to copy files without npm, use `./scripts/sync-into-repo.sh` (copy only; does not update opencode.json). Prefer the npm + Install flow above.
|
|
31
|
+
|
|
32
|
+
To update to a new release, see [Updating compound-workflow](#updating-compound-workflow).
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Updating compound-workflow
|
|
37
|
+
|
|
38
|
+
- **Cursor / Claude (plugin):** Update via the editor’s plugin/marketplace (check for updates or reinstall). If installed from repo, pull latest and reload the plugin. No per-project step; the plugin loads commands/skills from its installed source.
|
|
39
|
+
- **OpenCode / npm:** Run `npm update compound-workflow` (or bump the version in `package.json` and `npm install`), then run **Install** again: `/install` or `npx compound-workflow install`. This refreshes `opencode.json`, merges the latest `AGENTS.md` template, and ensures dirs exist; Repo Config Block is preserved.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Workflow at a glance
|
|
44
|
+
|
|
45
|
+
Clarify what to build → plan how (fidelity + confidence) → execute via todos → triage and review → capture learnings → log and assess.
|
|
46
|
+
|
|
47
|
+
```mermaid
|
|
48
|
+
flowchart LR
|
|
49
|
+
A[brainstorm] --> B[plan] --> C[work] --> D[triage] --> E[review] --> F[compound] --> G[metrics]
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Step-by-step: intent and commands
|
|
55
|
+
|
|
56
|
+
| Step | Intent | Command | Output / note |
|
|
57
|
+
|------|--------|---------|---------------|
|
|
58
|
+
| Clarify what to build | Dialogue only; no code | `/workflow:brainstorm [topic]` | `docs/brainstorms/` |
|
|
59
|
+
| Define how (fidelity + confidence) | Plan only; no code | `/workflow:plan [description or brainstorm path]` | `docs/plans/` |
|
|
60
|
+
| Execute | File-based todos; risk-tier testing; no auto-ship | `/workflow:work <plan-path>` | `todos/` |
|
|
61
|
+
| Ready the queue | Priority and dependencies for pending todos | `/workflow:triage` | — |
|
|
62
|
+
| Validate quality | Evidence-based review; no fixes by default | `/workflow:review [PR, branch, or current]` | pass / pass-with-notes / fail |
|
|
63
|
+
| Capture learnings | One solution doc for future use | `/workflow:compound [context]` | `docs/solutions/` |
|
|
64
|
+
| Log and improve | Session log + optional aggregate review | `/metrics` + `/assess weekly 7` (or monthly) | `docs/metrics/daily/`, weekly/monthly |
|
|
65
|
+
|
|
66
|
+
#### 1. Clarify (brainstorm)
|
|
67
|
+
|
|
68
|
+
**Intent:** Dialogue only; no code. **Command:** `/workflow:brainstorm [topic]`. **Output:** `docs/brainstorms/`.
|
|
69
|
+
|
|
70
|
+
#### 2. Define how (plan)
|
|
71
|
+
|
|
72
|
+
**Intent:** Plan only; no code; fidelity + confidence. **Command:** `/workflow:plan [description or brainstorm path]`. **Output:** `docs/plans/`.
|
|
73
|
+
|
|
74
|
+
#### 3. Execute (work)
|
|
75
|
+
|
|
76
|
+
**Intent:** File-based todos; risk-tier testing; no auto-ship. **Command:** `/workflow:work <plan-path>`. **Output:** `todos/`.
|
|
77
|
+
|
|
78
|
+
#### 4. Ready the queue (triage)
|
|
79
|
+
|
|
80
|
+
**Intent:** Priority and dependencies for pending todos. **Command:** `/workflow:triage`. **Output:** —.
|
|
81
|
+
|
|
82
|
+
#### 5. Validate quality (review)
|
|
83
|
+
|
|
84
|
+
**Intent:** Evidence-based review; no fixes by default. **Command:** `/workflow:review [PR|branch|current]`. **Output:** pass / pass-with-notes / fail.
|
|
85
|
+
|
|
86
|
+
#### 6. Capture learnings (compound)
|
|
87
|
+
|
|
88
|
+
**Intent:** One solution doc for future use. **Command:** `/workflow:compound [context]`. **Output:** `docs/solutions/`.
|
|
89
|
+
|
|
90
|
+
#### 7. Log and improve
|
|
91
|
+
|
|
92
|
+
**Intent:** Session log + optional aggregate review. **Command:** `/metrics` + `/assess weekly 7` (or monthly). **Output:** `docs/metrics/daily/`, weekly/monthly.
|
|
93
|
+
|
|
94
|
+
**Optional QA:** **`/test-browser [PR|branch|current]`** — Browser validation on affected pages via **agent-browser CLI only** (not MCP). Install: `npm install -g agent-browser` then `agent-browser install`. See [src/.agents/commands/test-browser.md](src/.agents/commands/test-browser.md).
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Command reference
|
|
99
|
+
|
|
100
|
+
**Onboarding:** `/install` — one action: writes opencode.json, merges AGENTS.md, creates dirs, preserves Repo Config Block. Run `npx compound-workflow install` in the project (requires `npm install compound-workflow`). Re-run after `npm update compound-workflow` to refresh config; see [Updating compound-workflow](#updating-compound-workflow).
|
|
101
|
+
|
|
102
|
+
**Core workflow:** See [Step-by-step](#step-by-step-intent-and-commands) above.
|
|
103
|
+
|
|
104
|
+
**QA:** `/test-browser [PR|branch|current]` — browser checks on affected routes (agent-browser CLI only).
|
|
105
|
+
|
|
106
|
+
**Improvement:** `/metrics [plan|todo|pr|solution|label]` — log session to `docs/metrics/daily/` and assess. `/assess [daily|weekly|monthly] [count]` — aggregate metrics and optional summary files.
|
|
107
|
+
|
|
108
|
+
**Experimental:** `/workflow:review-v2 [PR|branch|current]` — interactive snippet review; output-only (no GitHub publish).
|
|
109
|
+
|
|
110
|
+
Full detail: [src/AGENTS.md](src/AGENTS.md), [src/.agents/commands/](src/.agents/commands/).
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Artifacts
|
|
115
|
+
|
|
116
|
+
- **Brainstorms:** `docs/brainstorms/YYYY-MM-DD-<topic>-brainstorm.md`
|
|
117
|
+
- **Plans:** `docs/plans/YYYY-MM-DD-<type>-<slug>-plan.md`
|
|
118
|
+
- **Todos:** `todos/{id}-{status}-{priority}-{slug}.md`
|
|
119
|
+
- **Solutions:** `docs/solutions/<category>/YYYY-MM-DD-<module-slug>-<symptom-slug>.md`
|
|
120
|
+
- **Metrics:** `docs/metrics/daily/YYYY-MM-DD.md`, `docs/metrics/weekly/YYYY-WW.md`, `docs/metrics/monthly/YYYY-MM.md`
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## How it works (internals)
|
|
125
|
+
|
|
126
|
+
Commands are the public API. Skills and agents are invoked by commands; you don’t call them directly.
|
|
127
|
+
|
|
128
|
+
- **Workflow skills:** `brainstorming`, `file-todos`, `compound-docs`, `document-review`, `technical-review`, `git-worktree`, `agent-browser`, `process-metrics`.
|
|
129
|
+
- **Guardrail standards:** `data-foundations`, `pii-protection-prisma`, `financial-workflow-integrity`, `audit-traceability` — applied when work touches multi-tenant data, PII, money, or audit.
|
|
130
|
+
- **Agents:** Used by plan, review, and work for research, lint, and validation (e.g. `repo-research-analyst`, `learnings-researcher`, `git-history-analyzer`, `agent-native-reviewer`).
|
|
131
|
+
|
|
132
|
+
Full “when to use what” and reference standards: [src/AGENTS.md](src/AGENTS.md).
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Guardrails
|
|
137
|
+
|
|
138
|
+
- **No auto-ship:** `/workflow:work` and `/workflow:review` do not commit, push, or create PRs by default.
|
|
139
|
+
|
|
140
|
+
- **Brainstorm and plan do not write code.** Output is documents only.
|
|
141
|
+
|
|
142
|
+
- Add a separate shipping command if you want automated commit/PR and quality gates.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Configuration and optional bits
|
|
147
|
+
|
|
148
|
+
**Repo configuration:** Commands read a **Repo Config Block** (YAML) in `AGENTS.md` for `default_branch`, `dev_server_url`, `test_command`, etc. Run **`/install`** once; then edit `AGENTS.md` to set the Repo Config Block.
|
|
149
|
+
|
|
150
|
+
**agent-browser:** `/test-browser` uses the agent-browser CLI only. Install: `npm install -g agent-browser` then `agent-browser install`. See [src/.agents/commands/test-browser.md](src/.agents/commands/test-browser.md).
|
|
151
|
+
|
|
152
|
+
**Source of truth**
|
|
153
|
+
|
|
154
|
+
- Workflows and commands: [src/.agents/](src/.agents/)
|
|
155
|
+
- Principles and skill index: [src/AGENTS.md](src/AGENTS.md)
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "compound-workflow",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Clarify → plan → execute → verify → capture. One Install action for Cursor, Claude, and OpenCode.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/your-org/compound-workflow.git"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"compound-workflow": "scripts/install-cli.mjs"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"src",
|
|
15
|
+
"scripts",
|
|
16
|
+
".cursor-plugin",
|
|
17
|
+
".claude-plugin"
|
|
18
|
+
],
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=18"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* compound-workflow install
|
|
4
|
+
* One action: opencode.json (load from package) + AGENTS.md merge + dirs + Repo Config Block.
|
|
5
|
+
* Run from project: npx compound-workflow install [--root <dir>] [--dry-run] [--no-config]
|
|
6
|
+
*/
|
|
7
|
+
import fs from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
|
|
11
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
|
|
13
|
+
function usage(exitCode = 0) {
|
|
14
|
+
const msg = `
|
|
15
|
+
Usage:
|
|
16
|
+
npx compound-workflow install [--root <projectDir>] [--dry-run] [--no-config]
|
|
17
|
+
|
|
18
|
+
One action: writes opencode.json (loads from package), merges AGENTS.md, creates dirs,
|
|
19
|
+
and prompts for Repo Config Block (unless --no-config).
|
|
20
|
+
|
|
21
|
+
--root <dir> Project directory (default: cwd)
|
|
22
|
+
--dry-run Print planned changes only
|
|
23
|
+
--no-config Skip Repo Config Block prompt (only write opencode.json + AGENTS.md + dirs)
|
|
24
|
+
`;
|
|
25
|
+
(exitCode === 0 ? console.log : console.error)(msg.trimStart());
|
|
26
|
+
process.exit(exitCode);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function parseArgs(argv) {
|
|
30
|
+
const out = { root: process.cwd(), dryRun: false, noConfig: false };
|
|
31
|
+
for (let i = 2; i < argv.length; i++) {
|
|
32
|
+
const a = argv[i];
|
|
33
|
+
if (a === "--dry-run") out.dryRun = true;
|
|
34
|
+
else if (a === "--no-config") out.noConfig = true;
|
|
35
|
+
else if (a === "--root") {
|
|
36
|
+
const v = argv[i + 1];
|
|
37
|
+
if (!v) usage(1);
|
|
38
|
+
out.root = v;
|
|
39
|
+
i++;
|
|
40
|
+
} else if (a === "-h" || a === "--help") usage(0);
|
|
41
|
+
else if (a && a !== "install" && !a.startsWith("-")) usage(1);
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function realpathSafe(p) {
|
|
47
|
+
try {
|
|
48
|
+
return fs.realpathSync(p);
|
|
49
|
+
} catch {
|
|
50
|
+
return path.resolve(p);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const packageRoot = realpathSafe(path.join(__dirname, ".."));
|
|
55
|
+
const packageAgents = path.join(packageRoot, "src", ".agents");
|
|
56
|
+
const PKG_PREFIX = "node_modules/compound-workflow";
|
|
57
|
+
|
|
58
|
+
function walkFiles(dirAbs, predicate) {
|
|
59
|
+
const out = [];
|
|
60
|
+
const stack = [dirAbs];
|
|
61
|
+
while (stack.length) {
|
|
62
|
+
const cur = stack.pop();
|
|
63
|
+
let entries;
|
|
64
|
+
try {
|
|
65
|
+
entries = fs.readdirSync(cur, { withFileTypes: true });
|
|
66
|
+
} catch {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
for (const e of entries) {
|
|
70
|
+
const p = path.join(cur, e.name);
|
|
71
|
+
if (e.isDirectory()) stack.push(p);
|
|
72
|
+
else if (e.isFile() && predicate(p)) out.push(p);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
out.sort();
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function parseFrontmatter(md) {
|
|
80
|
+
if (!md.startsWith("---\n") && !md.startsWith("---\r\n")) return {};
|
|
81
|
+
const end = md.indexOf("\n---", 4);
|
|
82
|
+
if (end === -1) return {};
|
|
83
|
+
const block = md.slice(4, end + 1);
|
|
84
|
+
const out = {};
|
|
85
|
+
for (const line of block.split(/\r?\n/)) {
|
|
86
|
+
const m = line.match(/^([A-Za-z0-9_-]+):\s*(.*)\s*$/);
|
|
87
|
+
if (!m) continue;
|
|
88
|
+
let v = (m[2] ?? "").replace(/^"(.*)"$/, "$1").replace(/^'(.*)'$/, "$1");
|
|
89
|
+
out[m[1]] = v;
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function discoverCommands(agentsRoot) {
|
|
95
|
+
const commandsDir = path.join(agentsRoot, "commands");
|
|
96
|
+
const files = walkFiles(commandsDir, (p) => p.endsWith(".md"));
|
|
97
|
+
const map = new Map();
|
|
98
|
+
for (const fileAbs of files) {
|
|
99
|
+
const rel = path.relative(packageRoot, fileAbs).replaceAll(path.sep, "/");
|
|
100
|
+
const md = fs.readFileSync(fileAbs, "utf8");
|
|
101
|
+
const fm = parseFrontmatter(md);
|
|
102
|
+
const id = (fm.invocation || fm.name || path.basename(fileAbs, ".md")).trim();
|
|
103
|
+
const description = (fm.description || id).trim();
|
|
104
|
+
if (!id) continue;
|
|
105
|
+
const pkgRel = `${PKG_PREFIX}/${rel}`;
|
|
106
|
+
map.set(id, { id, rel: pkgRel, description });
|
|
107
|
+
}
|
|
108
|
+
return map;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function discoverAgents(agentsRoot) {
|
|
112
|
+
const agentsDir = path.join(agentsRoot, "agents");
|
|
113
|
+
const files = walkFiles(agentsDir, (p) => p.endsWith(".md"));
|
|
114
|
+
const map = new Map();
|
|
115
|
+
for (const fileAbs of files) {
|
|
116
|
+
const rel = path.relative(packageRoot, fileAbs).replaceAll(path.sep, "/");
|
|
117
|
+
const md = fs.readFileSync(fileAbs, "utf8");
|
|
118
|
+
const fm = parseFrontmatter(md);
|
|
119
|
+
const id = (fm.name || path.basename(fileAbs, ".md")).trim();
|
|
120
|
+
const description = (fm.description || id).trim();
|
|
121
|
+
if (!id) continue;
|
|
122
|
+
const pkgRel = `${PKG_PREFIX}/${rel}`;
|
|
123
|
+
map.set(id, { id, rel: pkgRel, description });
|
|
124
|
+
}
|
|
125
|
+
return map;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function ensureObject(v) {
|
|
129
|
+
return v && typeof v === "object" && !Array.isArray(v) ? v : {};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function stripJsonc(input) {
|
|
133
|
+
let out = "";
|
|
134
|
+
let i = 0;
|
|
135
|
+
let inStr = false,
|
|
136
|
+
strQuote = "",
|
|
137
|
+
escape = false;
|
|
138
|
+
while (i < input.length) {
|
|
139
|
+
const c = input[i];
|
|
140
|
+
const n = input[i + 1];
|
|
141
|
+
if (inStr) {
|
|
142
|
+
out += c;
|
|
143
|
+
if (escape) escape = false;
|
|
144
|
+
else if (c === "\\") escape = true;
|
|
145
|
+
else if (c === strQuote) inStr = false;
|
|
146
|
+
i++;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (c === '"' || c === "'") {
|
|
150
|
+
inStr = true;
|
|
151
|
+
strQuote = c;
|
|
152
|
+
out += c;
|
|
153
|
+
i++;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (c === "/" && n === "/") {
|
|
157
|
+
while (i < input.length && input[i] !== "\n") i++;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (c === "/" && n === "*") {
|
|
161
|
+
i += 2;
|
|
162
|
+
while (i < input.length && !(input[i] === "*" && input[i + 1] === "/")) i++;
|
|
163
|
+
i += 2;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
out += c;
|
|
167
|
+
i++;
|
|
168
|
+
}
|
|
169
|
+
return out;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function readJsonMaybe(fileAbs) {
|
|
173
|
+
if (!fs.existsSync(fileAbs)) return null;
|
|
174
|
+
const raw = fs.readFileSync(fileAbs, "utf8");
|
|
175
|
+
return JSON.parse(stripJsonc(raw));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function writeOpenCodeJson(targetRoot, dryRun) {
|
|
179
|
+
const opencodeAbs = path.join(targetRoot, "opencode.json");
|
|
180
|
+
const existing = readJsonMaybe(opencodeAbs) ?? {};
|
|
181
|
+
const next = structuredClone(existing);
|
|
182
|
+
|
|
183
|
+
next.$schema = next.$schema || "https://opencode.ai/config.json";
|
|
184
|
+
next.skills = ensureObject(next.skills);
|
|
185
|
+
const skillsPath = `${PKG_PREFIX}/src/.agents/skills`;
|
|
186
|
+
if (!Array.isArray(next.skills.paths)) next.skills.paths = [];
|
|
187
|
+
if (!next.skills.paths.includes(skillsPath)) next.skills.paths.unshift(skillsPath);
|
|
188
|
+
next.command = ensureObject(next.command);
|
|
189
|
+
next.agent = ensureObject(next.agent);
|
|
190
|
+
|
|
191
|
+
const commands = discoverCommands(packageAgents);
|
|
192
|
+
const agents = discoverAgents(packageAgents);
|
|
193
|
+
|
|
194
|
+
for (const [id, cmd] of commands) {
|
|
195
|
+
next.command[id] = {
|
|
196
|
+
...ensureObject(next.command[id]),
|
|
197
|
+
description: cmd.description,
|
|
198
|
+
agent: "build",
|
|
199
|
+
template: `@AGENTS.md\n@${cmd.rel}\nArguments: $ARGUMENTS\n`,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
for (const [id, ag] of agents) {
|
|
203
|
+
next.agent[id] = {
|
|
204
|
+
...ensureObject(next.agent[id]),
|
|
205
|
+
description: ag.description,
|
|
206
|
+
mode: "subagent",
|
|
207
|
+
prompt: `{file:${ag.rel}}`,
|
|
208
|
+
permission: { ...ensureObject(next.agent[id]?.permission), edit: "deny" },
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const out = JSON.stringify(next, null, 2) + "\n";
|
|
213
|
+
if (dryRun) {
|
|
214
|
+
console.log("[dry-run] Would write opencode.json:", opencodeAbs);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
fs.writeFileSync(opencodeAbs, out, "utf8");
|
|
218
|
+
console.log("Wrote:", opencodeAbs);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function extractRepoConfigBlock(md) {
|
|
222
|
+
const match = md.match(/(### Repo Config Block[^\n]*\n)?\s*```yaml\n([\s\S]*?)```/);
|
|
223
|
+
if (!match) return { block: null, rest: md };
|
|
224
|
+
const full = match[0];
|
|
225
|
+
const block = match[2].trim();
|
|
226
|
+
const rest = md.replace(full, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
227
|
+
return { block, rest };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function mergeAgentsMd(templateMd, existingMd) {
|
|
231
|
+
const { block: existingBlock, rest: existingRest } = existingMd
|
|
232
|
+
? extractRepoConfigBlock(existingMd)
|
|
233
|
+
: { block: null, rest: "" };
|
|
234
|
+
const { block: _tplBlock, rest: templateRest } = extractRepoConfigBlock(templateMd);
|
|
235
|
+
let out = templateRest;
|
|
236
|
+
if (existingBlock) {
|
|
237
|
+
const repoSection =
|
|
238
|
+
"### Repo Config Block (Optional)\n\n```yaml\n" + existingBlock + "\n```\n";
|
|
239
|
+
if (!out.includes("### Repo Config Block")) {
|
|
240
|
+
out = out.replace("## Repo Configuration (Optional)", "## Repo Configuration (Optional)\n\n" + repoSection);
|
|
241
|
+
} else {
|
|
242
|
+
out = out.replace(/### Repo Config Block[^\n]*\n\s*```yaml\n[\s\S]*?```/, repoSection);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return out;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function writeAgentsMd(targetRoot, dryRun) {
|
|
249
|
+
const templatePath = path.join(packageRoot, "src", "AGENTS.md");
|
|
250
|
+
const targetPath = path.join(targetRoot, "AGENTS.md");
|
|
251
|
+
const templateMd = fs.readFileSync(templatePath, "utf8");
|
|
252
|
+
const existingMd = fs.existsSync(targetPath) ? fs.readFileSync(targetPath, "utf8") : null;
|
|
253
|
+
const merged = mergeAgentsMd(templateMd, existingMd);
|
|
254
|
+
if (dryRun) {
|
|
255
|
+
console.log("[dry-run] Would write AGENTS.md:", targetPath);
|
|
256
|
+
return merged;
|
|
257
|
+
}
|
|
258
|
+
fs.writeFileSync(targetPath, merged, "utf8");
|
|
259
|
+
console.log("Wrote:", targetPath);
|
|
260
|
+
return merged;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const DIRS = [
|
|
264
|
+
"docs/brainstorms",
|
|
265
|
+
"docs/plans",
|
|
266
|
+
"docs/solutions",
|
|
267
|
+
"docs/metrics/daily",
|
|
268
|
+
"docs/metrics/weekly",
|
|
269
|
+
"docs/metrics/monthly",
|
|
270
|
+
"todos",
|
|
271
|
+
];
|
|
272
|
+
|
|
273
|
+
function ensureDirs(targetRoot, dryRun) {
|
|
274
|
+
for (const d of DIRS) {
|
|
275
|
+
const abs = path.join(targetRoot, d);
|
|
276
|
+
if (dryRun && !fs.existsSync(abs)) console.log("[dry-run] Would create:", d);
|
|
277
|
+
else if (!fs.existsSync(abs)) {
|
|
278
|
+
fs.mkdirSync(abs, { recursive: true });
|
|
279
|
+
console.log("Created:", d);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function main() {
|
|
285
|
+
const args = parseArgs(process.argv);
|
|
286
|
+
const targetRoot = realpathSafe(args.root);
|
|
287
|
+
|
|
288
|
+
if (!fs.existsSync(packageAgents)) {
|
|
289
|
+
console.error("Error: package agents dir not found:", packageAgents);
|
|
290
|
+
process.exit(2);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const pkgInTarget = path.join(targetRoot, "node_modules", "compound-workflow");
|
|
294
|
+
if (!fs.existsSync(pkgInTarget) && !args.dryRun) {
|
|
295
|
+
console.error("Error: compound-workflow not found in project. Run: npm install compound-workflow");
|
|
296
|
+
process.exit(2);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
console.log("Target root:", targetRoot);
|
|
300
|
+
console.log("Package root:", packageRoot);
|
|
301
|
+
|
|
302
|
+
writeOpenCodeJson(targetRoot, args.dryRun);
|
|
303
|
+
writeAgentsMd(targetRoot, args.dryRun);
|
|
304
|
+
ensureDirs(targetRoot, args.dryRun);
|
|
305
|
+
|
|
306
|
+
if (!args.noConfig && !args.dryRun && process.stdin.isTTY) {
|
|
307
|
+
console.log("\nRepo Config: edit AGENTS.md to set default_branch, test_command, lint_command, dev_server_url.");
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
console.log("\nDone. Run opencode debug config to verify.");
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
main();
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# LEGACY: Prefer "npm install compound-workflow" + "npx compound-workflow install" in the project.
|
|
3
|
+
# Copy src/.agents and src/AGENTS.md from this compound-workflow repo into a host repo.
|
|
4
|
+
# Does not update opencode.json; run Install (npx compound-workflow install) in the project for that.
|
|
5
|
+
set -e
|
|
6
|
+
CLONE_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
7
|
+
DRY_RUN=0
|
|
8
|
+
FORCE=0
|
|
9
|
+
TARGET=""
|
|
10
|
+
|
|
11
|
+
usage() {
|
|
12
|
+
cat <<'EOF'
|
|
13
|
+
Usage:
|
|
14
|
+
./scripts/sync-into-repo.sh [--dry-run] [--force] [target_dir]
|
|
15
|
+
|
|
16
|
+
Copies:
|
|
17
|
+
- src/.agents -> <target_dir>/.agents
|
|
18
|
+
- src/AGENTS.md -> <target_dir>/AGENTS.md (only if missing)
|
|
19
|
+
|
|
20
|
+
Notes:
|
|
21
|
+
- Replaces <target_dir>/.agents (prevents .agents/.agents nesting)
|
|
22
|
+
- Prints absolute paths before writing
|
|
23
|
+
- Refuses non-git targets unless --force
|
|
24
|
+
EOF
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
while [[ $# -gt 0 ]]; do
|
|
28
|
+
case "$1" in
|
|
29
|
+
--dry-run)
|
|
30
|
+
DRY_RUN=1
|
|
31
|
+
shift
|
|
32
|
+
;;
|
|
33
|
+
--force)
|
|
34
|
+
FORCE=1
|
|
35
|
+
shift
|
|
36
|
+
;;
|
|
37
|
+
-h|--help)
|
|
38
|
+
usage
|
|
39
|
+
exit 0
|
|
40
|
+
;;
|
|
41
|
+
*)
|
|
42
|
+
if [[ -z "$TARGET" ]]; then
|
|
43
|
+
TARGET="$1"
|
|
44
|
+
shift
|
|
45
|
+
else
|
|
46
|
+
echo "Error: unexpected argument: $1" >&2
|
|
47
|
+
usage >&2
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
;;
|
|
51
|
+
esac
|
|
52
|
+
done
|
|
53
|
+
|
|
54
|
+
TARGET="${TARGET:-$(dirname "$CLONE_ROOT")}"
|
|
55
|
+
if [[ ! -d "$CLONE_ROOT/src/.agents" || ! -f "$CLONE_ROOT/src/AGENTS.md" ]]; then
|
|
56
|
+
echo "Error: $CLONE_ROOT is not a compound-workflow clone (missing src/.agents or src/AGENTS.md)" >&2
|
|
57
|
+
exit 1
|
|
58
|
+
fi
|
|
59
|
+
if [[ ! -d "$TARGET" ]]; then
|
|
60
|
+
echo "Error: target is not a directory: $TARGET" >&2
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
TARGET_ABS="$(cd "$TARGET" && pwd)"
|
|
64
|
+
# Host marker validation (escape hatch: --force)
|
|
65
|
+
if [[ "$FORCE" -ne 1 && ! -d "$TARGET_ABS/.git" ]]; then
|
|
66
|
+
echo "Error: target does not look like a git repo (missing .git): $TARGET_ABS" >&2
|
|
67
|
+
echo "Hint: pass --force if you really want to sync into a non-git directory." >&2
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
# Refuse obvious template targets (escape hatch: --force)
|
|
71
|
+
if [[ "$FORCE" -ne 1 && -d "$TARGET_ABS/src/.agents" && -f "$TARGET_ABS/src/AGENTS.md" ]]; then
|
|
72
|
+
echo "Error: target looks like a compound-workflow template repo (has src/.agents + src/AGENTS.md): $TARGET_ABS" >&2
|
|
73
|
+
echo "Refusing to sync into a template repo. Pass --force to override." >&2
|
|
74
|
+
exit 1
|
|
75
|
+
fi
|
|
76
|
+
# Avoid copying into our own src
|
|
77
|
+
if [[ "$TARGET_ABS" == "$(cd "$CLONE_ROOT/src" 2>/dev/null && pwd)" ]] || [[ "$TARGET_ABS" == "$CLONE_ROOT/src" ]]; then
|
|
78
|
+
echo "Error: target must not be the clone's src directory" >&2
|
|
79
|
+
exit 1
|
|
80
|
+
fi
|
|
81
|
+
echo "Resolved target: $TARGET_ABS"
|
|
82
|
+
echo "Planned writes:"
|
|
83
|
+
echo " - $TARGET_ABS/.agents (replace)"
|
|
84
|
+
if [[ ! -f "$TARGET_ABS/AGENTS.md" ]]; then
|
|
85
|
+
echo " - $TARGET_ABS/AGENTS.md (create)"
|
|
86
|
+
else
|
|
87
|
+
echo " - $TARGET_ABS/AGENTS.md (skip; already exists)"
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
if [[ "$DRY_RUN" -eq 1 ]]; then
|
|
91
|
+
echo "Dry-run: no changes made."
|
|
92
|
+
exit 0
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
echo "Copying into $TARGET_ABS ..."
|
|
96
|
+
rm -rf "$TARGET_ABS/.agents"
|
|
97
|
+
cp -R "$CLONE_ROOT/src/.agents" "$TARGET_ABS/.agents"
|
|
98
|
+
if [[ ! -f "$TARGET_ABS/AGENTS.md" ]]; then
|
|
99
|
+
cp "$CLONE_ROOT/src/AGENTS.md" "$TARGET_ABS/AGENTS.md"
|
|
100
|
+
else
|
|
101
|
+
echo "AGENTS.md already exists; skipped copy. Run Install (npx compound-workflow install) in the project to merge template with host AGENTS.md."
|
|
102
|
+
fi
|
|
103
|
+
echo "Done. Run Install in the project (npx compound-workflow install) to configure opencode.json and AGENTS.md, or run /install in Cursor."
|