compound-workflow 1.6.4 → 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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compound-workflow",
3
- "version": "1.6.4",
3
+ "version": "1.6.5",
4
4
  "description": "Clarify -> plan -> execute -> verify -> capture workflow: commands, skills, and agents for Claude Code",
5
5
  "author": {
6
6
  "name": "Compound Workflow"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compound-workflow",
3
- "version": "1.6.4",
3
+ "version": "1.6.5",
4
4
  "description": "Clarify -> plan -> execute -> verify -> capture workflow for Cursor",
5
5
  "author": {
6
6
  "name": "Compound Workflow"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compound-workflow",
3
- "version": "1.6.4",
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
- function discoverCommands() {
46
- const commandsDir = path.join(agentsRoot, "commands");
47
- const files = walkFiles(commandsDir, (p) => p.endsWith(".md"));
48
- const commands = [];
49
-
50
- for (const fileAbs of files) {
51
- const relWithin = path.relative(commandsDir, fileAbs).replaceAll(path.sep, "/");
52
- const frontmatter = parseFrontmatter(fs.readFileSync(fileAbs, "utf8"));
53
- const id = (frontmatter.invocation || frontmatter.name || path.basename(fileAbs, ".md")).trim();
54
- if (!id) continue;
55
- commands.push({
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
- return commands.sort((a, b) => a.id.localeCompare(b.id));
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
- function discoverAgents() {
66
- const agentDir = path.join(agentsRoot, "agents");
67
- const files = walkFiles(agentDir, (p) => p.endsWith(".md"));
68
- const agents = [];
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 relWithin = path.relative(agentDir, fileAbs).replaceAll(path.sep, "/");
72
- const frontmatter = parseFrontmatter(fs.readFileSync(fileAbs, "utf8"));
73
- const id = (frontmatter.name || path.basename(fileAbs, ".md")).trim();
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
- agents.push({
76
- id,
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: "node_modules/compound-workflow/src/.agents/skills",
144
- commandRoot: "node_modules/compound-workflow/src/.agents/commands",
145
- agentRoot: "node_modules/compound-workflow/src/.agents/agents",
183
+ skillsPath,
184
+ commandRoot,
185
+ agentRoot,
146
186
  commands,
147
187
  agents,
148
188
  };
@@ -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
+ }