forge-workflow 0.0.5 → 0.0.7

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.
Files changed (164) hide show
  1. package/.claude/commands/dev.md +6 -1
  2. package/.claude/commands/plan.md +59 -14
  3. package/.claude/commands/premerge.md +10 -0
  4. package/.claude/commands/review.md +7 -1
  5. package/.claude/commands/ship.md +95 -47
  6. package/.claude/commands/status.md +42 -0
  7. package/.claude/commands/validate.md +7 -1
  8. package/.claude/commands/verify.md +52 -4
  9. package/.claude/rules/workflow.md +16 -0
  10. package/.claude/scripts/greptile-resolve.sh +32 -0
  11. package/.cline/workflows/dev.md +6 -1
  12. package/.cline/workflows/plan.md +59 -14
  13. package/.cline/workflows/premerge.md +10 -0
  14. package/.cline/workflows/review.md +7 -1
  15. package/.cline/workflows/ship.md +95 -47
  16. package/.cline/workflows/status.md +42 -0
  17. package/.cline/workflows/validate.md +7 -1
  18. package/.cline/workflows/verify.md +52 -4
  19. package/.codex/skills/dev/SKILL.md +6 -1
  20. package/.codex/skills/plan/SKILL.md +59 -14
  21. package/.codex/skills/premerge/SKILL.md +10 -0
  22. package/.codex/skills/review/SKILL.md +7 -1
  23. package/.codex/skills/ship/SKILL.md +95 -47
  24. package/.codex/skills/status/SKILL.md +42 -0
  25. package/.codex/skills/validate/SKILL.md +7 -1
  26. package/.codex/skills/verify/SKILL.md +52 -4
  27. package/.cursor/commands/dev.md +6 -1
  28. package/.cursor/commands/plan.md +59 -14
  29. package/.cursor/commands/premerge.md +10 -0
  30. package/.cursor/commands/review.md +7 -1
  31. package/.cursor/commands/ship.md +95 -47
  32. package/.cursor/commands/status.md +42 -0
  33. package/.cursor/commands/validate.md +7 -1
  34. package/.cursor/commands/verify.md +52 -4
  35. package/.cursorrules +149 -0
  36. package/.github/prompts/dev.prompt.md +6 -1
  37. package/.github/prompts/plan.prompt.md +59 -14
  38. package/.github/prompts/premerge.prompt.md +10 -0
  39. package/.github/prompts/review.prompt.md +7 -1
  40. package/.github/prompts/ship.prompt.md +95 -47
  41. package/.github/prompts/status.prompt.md +42 -0
  42. package/.github/prompts/validate.prompt.md +7 -1
  43. package/.github/prompts/verify.prompt.md +52 -4
  44. package/.kilocode/workflows/dev.md +6 -1
  45. package/.kilocode/workflows/plan.md +59 -14
  46. package/.kilocode/workflows/premerge.md +10 -0
  47. package/.kilocode/workflows/review.md +7 -1
  48. package/.kilocode/workflows/ship.md +95 -47
  49. package/.kilocode/workflows/status.md +42 -0
  50. package/.kilocode/workflows/validate.md +7 -1
  51. package/.kilocode/workflows/verify.md +52 -4
  52. package/.opencode/commands/dev.md +6 -1
  53. package/.opencode/commands/plan.md +59 -14
  54. package/.opencode/commands/premerge.md +10 -0
  55. package/.opencode/commands/review.md +7 -1
  56. package/.opencode/commands/ship.md +95 -47
  57. package/.opencode/commands/status.md +42 -0
  58. package/.opencode/commands/validate.md +7 -1
  59. package/.opencode/commands/verify.md +52 -4
  60. package/.roo/commands/dev.md +6 -1
  61. package/.roo/commands/plan.md +59 -14
  62. package/.roo/commands/premerge.md +10 -0
  63. package/.roo/commands/review.md +7 -1
  64. package/.roo/commands/ship.md +95 -47
  65. package/.roo/commands/status.md +42 -0
  66. package/.roo/commands/validate.md +7 -1
  67. package/.roo/commands/verify.md +52 -4
  68. package/AGENTS.md +97 -0
  69. package/CLAUDE.md +10 -0
  70. package/README.md +2 -2
  71. package/bin/forge-cmd.js +5 -1
  72. package/bin/forge-preflight.js +15 -2
  73. package/bin/forge.js +211 -9
  74. package/docs/ENHANCED_ONBOARDING.md +96 -86
  75. package/docs/ROADMAP.md +2 -2
  76. package/docs/TOOLCHAIN.md +23 -0
  77. package/docs/VALIDATION.md +1 -1
  78. package/lefthook.yml +11 -0
  79. package/lib/agents/README.md +46 -1
  80. package/lib/agents/cline.plugin.json +11 -4
  81. package/lib/agents/codex.plugin.json +2 -2
  82. package/lib/agents/copilot.plugin.json +5 -5
  83. package/lib/agents/cursor.plugin.json +1 -1
  84. package/lib/agents/kilocode.plugin.json +1 -1
  85. package/lib/agents/opencode.plugin.json +7 -4
  86. package/lib/agents/roo.plugin.json +10 -3
  87. package/lib/agents-config.js +129 -81
  88. package/lib/codex-skills.js +50 -0
  89. package/lib/commands/_registry.js +173 -0
  90. package/lib/commands/clean.js +181 -0
  91. package/lib/commands/commands-reset.js +147 -0
  92. package/lib/commands/dev.js +84 -0
  93. package/lib/commands/plan.js +18 -0
  94. package/lib/commands/push.js +196 -0
  95. package/lib/commands/recommend.js +1 -1
  96. package/lib/commands/setup.js +4295 -0
  97. package/lib/commands/ship.js +20 -0
  98. package/lib/commands/status.js +210 -44
  99. package/lib/commands/sync.js +71 -0
  100. package/lib/commands/team.js +37 -0
  101. package/lib/commands/test.js +207 -0
  102. package/lib/commands/validate.js +13 -0
  103. package/lib/commands/worktree.js +310 -0
  104. package/lib/detect-agent.js +38 -8
  105. package/lib/detection-utils.js +405 -0
  106. package/lib/docs-command.js +51 -0
  107. package/lib/docs-copy.js +50 -0
  108. package/lib/file-utils.js +260 -0
  109. package/lib/forge-context.js +42 -0
  110. package/lib/freshness-token.js +148 -0
  111. package/lib/frontmatter.js +79 -0
  112. package/lib/greptile-match.js +80 -0
  113. package/lib/husky-migration.js +113 -12
  114. package/lib/lefthook-check.js +27 -6
  115. package/lib/plugin-manager.js +225 -72
  116. package/lib/project-discovery.js +39 -5
  117. package/lib/reset.js +309 -0
  118. package/lib/runtime-health.js +305 -0
  119. package/lib/shell-utils.js +50 -0
  120. package/lib/task-ownership.js +117 -0
  121. package/lib/ui-utils.js +43 -0
  122. package/lib/validation-utils.js +163 -0
  123. package/lib/workflow/enforce-stage.js +179 -0
  124. package/lib/workflow/stages.js +201 -0
  125. package/lib/workflow/state.js +332 -0
  126. package/opencode.json +67 -0
  127. package/package.json +16 -6
  128. package/scripts/beads-context.sh +165 -22
  129. package/scripts/beads-context.test.js +5 -1
  130. package/scripts/check-agents.js +103 -0
  131. package/scripts/check-forge-token.js +98 -0
  132. package/scripts/conflict-detect.sh +2 -2
  133. package/scripts/dep-guard.sh +6 -28
  134. package/scripts/file-index.sh +117 -23
  135. package/scripts/forge-team/index.sh +86 -0
  136. package/scripts/forge-team/lib/agent-prompt.sh +52 -0
  137. package/scripts/forge-team/lib/claim.sh +256 -0
  138. package/scripts/forge-team/lib/dashboard.sh +341 -0
  139. package/scripts/forge-team/lib/epic.sh +332 -0
  140. package/scripts/forge-team/lib/hooks.sh +253 -0
  141. package/scripts/forge-team/lib/identity.sh +235 -0
  142. package/scripts/forge-team/lib/sync-github.sh +317 -0
  143. package/scripts/forge-team/lib/verify.sh +284 -0
  144. package/scripts/forge-team/lib/workload.sh +296 -0
  145. package/scripts/forge-team/tests/agent-prompt.test.sh +72 -0
  146. package/scripts/forge-team/tests/claim.test.sh +179 -0
  147. package/scripts/forge-team/tests/dashboard.test.sh +170 -0
  148. package/scripts/forge-team/tests/dispatcher.test.sh +79 -0
  149. package/scripts/forge-team/tests/epic.test.sh +176 -0
  150. package/scripts/forge-team/tests/hooks.test.sh +239 -0
  151. package/scripts/forge-team/tests/identity.test.sh +176 -0
  152. package/scripts/forge-team/tests/integration.test.sh +371 -0
  153. package/scripts/forge-team/tests/sync-github.test.sh +209 -0
  154. package/scripts/forge-team/tests/verify.test.sh +314 -0
  155. package/scripts/forge-team/tests/workflow-integration.test.sh +43 -0
  156. package/scripts/forge-team/tests/workload.test.sh +209 -0
  157. package/scripts/lib/eval-runner.js +39 -0
  158. package/scripts/lib/jsonl-lock.sh +48 -0
  159. package/scripts/lib/sanitize.sh +116 -0
  160. package/scripts/pr-coordinator.sh +756 -0
  161. package/scripts/smart-status.sh +58 -21
  162. package/scripts/sync-commands.js +49 -20
  163. package/scripts/sync-utils.sh +24 -29
  164. package/scripts/test.js +18 -1
@@ -23,8 +23,21 @@ Each plugin file must follow this structure:
23
23
  "homepage": "https://...", // OPTIONAL: Agent's homepage URL
24
24
  "capabilities": { // OPTIONAL: Agent capabilities
25
25
  "commands": true, // Supports commands
26
+ "rules": true, // Supports rules/instructions
26
27
  "skills": true, // Supports skills
27
- "hooks": false // Supports git hooks
28
+ "mcp": true, // Supports MCP servers
29
+ "contextMode": true, // Supports context isolation/modes
30
+ "hooks": { // Supports hooks and blocking hooks
31
+ "blocking": false
32
+ }
33
+ },
34
+ "support": { // OPTIONAL: Support quality metadata
35
+ "status": "supported", // first-class | supported | compatibility | deprecated | unsupported
36
+ "surface": "cli-first", // cli-first | editor-native | desktop-app | web-app | terminal-native | hybrid
37
+ "install": {
38
+ "required": true, // Requires installation or setup
39
+ "repairRequired": false // Can be repaired in place instead of reinstalled
40
+ }
28
41
  },
29
42
  "directories": { // REQUIRED: Directory structure (at least one)
30
43
  "commands": ".your-agent/commands",
@@ -58,9 +71,27 @@ Each plugin file must follow this structure:
58
71
  - **description**: Short description of the agent
59
72
  - **homepage**: URL to agent's official website
60
73
  - **capabilities**: Object defining what the agent supports
74
+ - **support**: Support tier and enforcement metadata
61
75
  - **files**: Important configuration file paths
62
76
  - **setup**: Installation and setup instructions
63
77
 
78
+ ### Normalized Capability Metadata
79
+
80
+ `PluginManager` exposes a normalized capability block on each loaded plugin at `normalizedCapabilities`:
81
+
82
+ - `nativeSurface`
83
+ - `supportStatus`
84
+ - `commands`
85
+ - `rules`
86
+ - `skills`
87
+ - `mcp`
88
+ - `contextMode`
89
+ - `hooks.blocking`
90
+ - `install.required`
91
+ - `install.repairRequired`
92
+
93
+ Legacy `capabilities.hooks: true/false` values are still accepted and normalized to `hooks.blocking`.
94
+
64
95
  ## Supported Agents
65
96
 
66
97
  Currently supported AI coding agents:
@@ -122,6 +153,8 @@ The PluginManager automatically validates all plugins on load:
122
153
  - **Type checking**: Fields must have correct types
123
154
  - **Unique IDs**: No duplicate plugin IDs allowed
124
155
  - **JSON syntax**: Files must be valid JSON
156
+ - **Support metadata**: `support.status` must be one of `first-class`, `supported`, `compatibility`, `deprecated`, or `unsupported`
157
+ - **Capability metadata**: `capabilities.hooks.blocking`, `capabilities.mcp`, `capabilities.contextMode`, and the other support flags must be booleans when present
125
158
 
126
159
  Run tests to validate your plugin:
127
160
 
@@ -129,6 +162,17 @@ Run tests to validate your plugin:
129
162
  bun test test/plugins/
130
163
  ```
131
164
 
165
+ ### Parity Drift Validation
166
+
167
+ `node scripts/check-agents.js` now validates more than command sync. It also checks parity-critical support claims:
168
+
169
+ - invalid enforcement metadata under `support` and `capabilities`
170
+ - plugins that claim command support without a Forge sync adapter
171
+ - command directory declarations that do not match the sync adapter output path
172
+ - `rules` or `skills` capabilities declared without a scaffold path in `directories`
173
+
174
+ This is the guardrail for keeping agent support honest as vendor integrations evolve.
175
+
132
176
  ## Community Contributions
133
177
 
134
178
  We welcome community contributions for new AI coding agents!
@@ -191,6 +235,7 @@ Common validation errors:
191
235
  - `missing required field "id"`: Add the id field
192
236
  - `"directories" must be an object`: Ensure directories is an object, not array
193
237
  - `"version" must be a string`: Version must be in "x.y.z" format
238
+ - `"support.status" must be one of ...`: Use a supported status value
194
239
  - `Plugin with ID "x" already exists`: Choose a unique ID
195
240
 
196
241
  ## License
@@ -6,17 +6,24 @@
6
6
  "homepage": "https://github.com/cline/cline",
7
7
  "capabilities": {
8
8
  "commands": true,
9
- "skills": true,
9
+ "skills": false,
10
10
  "hooks": false
11
11
  },
12
12
  "directories": {
13
- "workflows": ".cline/workflows",
14
- "skills": ".cline/skills/forge-workflow"
13
+ "workflows": ".cline/workflows"
15
14
  },
16
15
  "files": {
17
16
  "rootConfig": ".clinerules"
18
17
  },
18
+ "support": {
19
+ "status": "deprecated",
20
+ "surface": "editor-native",
21
+ "install": {
22
+ "required": false,
23
+ "repairRequired": false
24
+ }
25
+ },
19
26
  "setup": {
20
- "createSkill": true
27
+ "copyCommands": true
21
28
  }
22
29
  }
@@ -6,7 +6,7 @@
6
6
  "homepage": "https://github.com/openai/codex",
7
7
  "capabilities": {
8
8
  "commands": true,
9
- "skills": false,
9
+ "skills": true,
10
10
  "hooks": false
11
11
  },
12
12
  "directories": {
@@ -14,6 +14,6 @@
14
14
  },
15
15
  "setup": {
16
16
  "copyRules": false,
17
- "createSkill": false
17
+ "createSkill": true
18
18
  }
19
19
  }
@@ -2,23 +2,23 @@
2
2
  "id": "copilot",
3
3
  "name": "GitHub Copilot",
4
4
  "version": "1.0.0",
5
- "description": "GitHub's AI assistant",
5
+ "description": "GitHub's AI assistant with native instructions and prompts",
6
6
  "homepage": "https://github.com/features/copilot",
7
7
  "capabilities": {
8
8
  "commands": true,
9
- "skills": true,
9
+ "skills": false,
10
10
  "hooks": false
11
11
  },
12
12
  "directories": {
13
13
  "prompts": ".github/prompts",
14
- "instructions": ".github/instructions",
15
- "skills": ".github/skills/forge-workflow"
14
+ "instructions": ".github/instructions"
16
15
  },
17
16
  "files": {
18
17
  "rootConfig": ".github/copilot-instructions.md"
19
18
  },
20
19
  "setup": {
21
20
  "needsConversion": true,
22
- "promptFormat": true
21
+ "promptFormat": true,
22
+ "customSetup": "copilot"
23
23
  }
24
24
  }
@@ -2,7 +2,7 @@
2
2
  "id": "cursor",
3
3
  "name": "Cursor",
4
4
  "version": "1.0.0",
5
- "description": "AI-first code editor",
5
+ "description": "AI-first code editor with native rules and skills",
6
6
  "homepage": "https://cursor.sh",
7
7
  "capabilities": {
8
8
  "commands": true,
@@ -2,7 +2,7 @@
2
2
  "id": "kilocode",
3
3
  "name": "Kilo Code",
4
4
  "version": "1.0.0",
5
- "description": "VS Code extension",
5
+ "description": "VS Code extension with native workflows, rules, and skills",
6
6
  "homepage": "https://marketplace.visualstudio.com/items?itemName=kilo-code",
7
7
  "capabilities": {
8
8
  "commands": true,
@@ -2,19 +2,22 @@
2
2
  "id": "opencode",
3
3
  "name": "OpenCode",
4
4
  "version": "1.0.0",
5
- "description": "Open-source agent",
5
+ "description": "Open-source agent with native config and agent definitions",
6
6
  "homepage": "https://opencode.ai",
7
7
  "capabilities": {
8
8
  "commands": true,
9
- "skills": true,
9
+ "skills": false,
10
10
  "hooks": false
11
11
  },
12
12
  "directories": {
13
13
  "commands": ".opencode/commands",
14
- "skills": ".opencode/skills/forge-workflow"
14
+ "agents": ".opencode/agents"
15
+ },
16
+ "files": {
17
+ "rootConfig": "opencode.json"
15
18
  },
16
19
  "setup": {
17
20
  "copyCommands": true,
18
- "createSkill": true
21
+ "customSetup": "opencode"
19
22
  }
20
23
  }
@@ -6,16 +6,23 @@
6
6
  "homepage": "https://github.com/roocode/roo",
7
7
  "capabilities": {
8
8
  "commands": true,
9
- "skills": true,
9
+ "skills": false,
10
10
  "hooks": false
11
11
  },
12
12
  "directories": {
13
- "commands": ".roo/commands",
14
- "skills": ".roo/skills/forge-workflow"
13
+ "commands": ".roo/commands"
15
14
  },
16
15
  "files": {
17
16
  "rootConfig": ".roorules"
18
17
  },
18
+ "support": {
19
+ "status": "deprecated",
20
+ "surface": "editor-native",
21
+ "install": {
22
+ "required": false,
23
+ "repairRequired": false
24
+ }
25
+ },
19
26
  "setup": {
20
27
  "copyCommands": true,
21
28
  "needsConversion": true
@@ -68,6 +68,25 @@ async function detectProjectMetadata(projectPath) {
68
68
  return meta;
69
69
  }
70
70
 
71
+ /**
72
+ * Write a file unless it already exists, unless overwrite is enabled.
73
+ *
74
+ * @param {string} filePath
75
+ * @param {string} content
76
+ * @param {boolean} overwrite
77
+ * @returns {Promise<void>}
78
+ */
79
+ async function writeIfNeeded(filePath, content, overwrite = false) {
80
+ const exists = await fs.promises.access(filePath).then(() => true).catch(() => false);
81
+ if (!exists || overwrite) {
82
+ await fs.promises.writeFile(filePath, content, 'utf-8');
83
+ }
84
+ }
85
+
86
+ function createConditionalWriter(overwrite) {
87
+ return (filePath, content) => writeIfNeeded(filePath, content, overwrite);
88
+ }
89
+
71
90
  /**
72
91
  * Generate AGENTS.md content
73
92
  * @param {Object} meta - Project metadata
@@ -241,7 +260,7 @@ While this universal AGENTS.md works with all agents, you can optionally enable
241
260
  - **GitHub Copilot**: \`.github/copilot-instructions.md\` + path-specific instructions
242
261
  - **Cursor**: \`.cursor/rules/*.mdc\` + native modes
243
262
  - **OpenCode**: \`opencode.json\` + custom agents
244
- - **Kilo**: \`.kilo.md\` + built-in commands
263
+ - **Kilo**: \`.kilocode/workflows\`, \`.kilocode/rules\`, \`.kilocode/skills\`
245
264
 
246
265
  Generate with: \`bunx forge setup --agent=<name>\`
247
266
 
@@ -277,38 +296,32 @@ async function generateCopilotConfig(projectPath, options = {}) {
277
296
  await fs.promises.mkdir(instructionsDir, { recursive: true });
278
297
  await fs.promises.mkdir(promptsDir, { recursive: true });
279
298
 
280
- // Helper to write file if it doesn't exist or overwrite is true
281
- const writeIfNeeded = async (filePath, content) => {
282
- const exists = await fs.promises.access(filePath).then(() => true).catch(() => false);
283
- if (!exists || overwrite) {
284
- await fs.promises.writeFile(filePath, content, 'utf-8');
285
- }
286
- };
299
+ const writeConfigFile = createConditionalWriter(overwrite);
287
300
 
288
301
  // 1. Create .github/copilot-instructions.md
289
302
  const copilotInstructionsPath = path.join(githubDir, 'copilot-instructions.md');
290
303
  const copilotInstructionsContent = generateCopilotInstructionsContent(projectMeta);
291
- await writeIfNeeded(copilotInstructionsPath, copilotInstructionsContent);
304
+ await writeConfigFile(copilotInstructionsPath, copilotInstructionsContent);
292
305
 
293
306
  // 2. Create .github/instructions/typescript.instructions.md
294
307
  const tsInstructionsPath = path.join(instructionsDir, 'typescript.instructions.md');
295
308
  const tsInstructionsContent = generateTypeScriptInstructionsContent();
296
- await writeIfNeeded(tsInstructionsPath, tsInstructionsContent);
309
+ await writeConfigFile(tsInstructionsPath, tsInstructionsContent);
297
310
 
298
311
  // 3. Create .github/instructions/testing.instructions.md
299
312
  const testInstructionsPath = path.join(instructionsDir, 'testing.instructions.md');
300
313
  const testInstructionsContent = generateTestingInstructionsContent();
301
- await writeIfNeeded(testInstructionsPath, testInstructionsContent);
314
+ await writeConfigFile(testInstructionsPath, testInstructionsContent);
302
315
 
303
316
  // 4. Create .github/prompts/red.prompt.md
304
317
  const redPromptPath = path.join(promptsDir, 'red.prompt.md');
305
318
  const redPromptContent = generateRedPromptContent();
306
- await writeIfNeeded(redPromptPath, redPromptContent);
319
+ await writeConfigFile(redPromptPath, redPromptContent);
307
320
 
308
321
  // 5. Create .github/prompts/green.prompt.md
309
322
  const greenPromptPath = path.join(promptsDir, 'green.prompt.md');
310
323
  const greenPromptContent = generateGreenPromptContent();
311
- await writeIfNeeded(greenPromptPath, greenPromptContent);
324
+ await writeConfigFile(greenPromptPath, greenPromptContent);
312
325
  }
313
326
 
314
327
  /**
@@ -643,33 +656,27 @@ async function generateCursorConfig(projectPath, options = {}) {
643
656
 
644
657
  await fs.promises.mkdir(rulesDir, { recursive: true });
645
658
 
646
- // Helper to write file if it doesn't exist or overwrite is true
647
- const writeIfNeeded = async (filePath, content) => {
648
- const exists = await fs.promises.access(filePath).then(() => true).catch(() => false);
649
- if (!exists || overwrite) {
650
- await fs.promises.writeFile(filePath, content, 'utf-8');
651
- }
652
- };
659
+ const writeConfigFile = createConditionalWriter(overwrite);
653
660
 
654
661
  // 1. Create .cursor/rules/forge-workflow.mdc
655
662
  const workflowPath = path.join(rulesDir, 'forge-workflow.mdc');
656
663
  const workflowContent = generateCursorWorkflowContent(projectMeta);
657
- await writeIfNeeded(workflowPath, workflowContent);
664
+ await writeConfigFile(workflowPath, workflowContent);
658
665
 
659
666
  // 2. Create .cursor/rules/tdd-enforcement.mdc
660
667
  const tddPath = path.join(rulesDir, 'tdd-enforcement.mdc');
661
668
  const tddContent = generateCursorTddContent();
662
- await writeIfNeeded(tddPath, tddContent);
669
+ await writeConfigFile(tddPath, tddContent);
663
670
 
664
671
  // 3. Create .cursor/rules/security-scanning.mdc
665
672
  const securityPath = path.join(rulesDir, 'security-scanning.mdc');
666
673
  const securityContent = generateCursorSecurityContent();
667
- await writeIfNeeded(securityPath, securityContent);
674
+ await writeConfigFile(securityPath, securityContent);
668
675
 
669
676
  // 4. Create .cursor/rules/documentation.mdc
670
677
  const docsPath = path.join(rulesDir, 'documentation.mdc');
671
678
  const docsContent = generateCursorDocumentationContent();
672
- await writeIfNeeded(docsPath, docsContent);
679
+ await writeConfigFile(docsPath, docsContent);
673
680
  }
674
681
 
675
682
  /**
@@ -943,7 +950,7 @@ Update documentation at relevant stages (not deferred to end):
943
950
  - Security considerations (OWASP analysis)
944
951
 
945
952
  ### During /plan (Stage 3)
946
- - Create implementation plan in \`.claude/plans/<feature-slug>.md\`
953
+ - Create implementation plan in \`docs/plans/<feature-slug>.md\`
947
954
  - Document test scenarios
948
955
  - Identify affected files
949
956
 
@@ -1010,7 +1017,7 @@ Update documentation at relevant stages (not deferred to end):
1010
1017
  }
1011
1018
 
1012
1019
  /**
1013
- * Generate Kilo Code configuration file
1020
+ * Generate Kilo Code configuration files
1014
1021
  * @param {string} projectPath - Path to the project root
1015
1022
  * @param {Object} options - Generation options
1016
1023
  * @param {boolean} options.overwrite - Whether to overwrite existing files (default: false)
@@ -1022,29 +1029,45 @@ async function generateKiloConfig(projectPath, options = {}) {
1022
1029
  // Detect project metadata
1023
1030
  const projectMeta = await detectProjectMetadata(projectPath);
1024
1031
 
1025
- const kiloMdPath = path.join(projectPath, '.kilo.md');
1026
-
1027
- // Check if file exists
1028
- const exists = await fs.promises.access(kiloMdPath).then(() => true).catch(() => false);
1029
- if (exists && !overwrite) {
1030
- return; // Don't overwrite
1031
- }
1032
+ const kilocodeDir = path.join(projectPath, '.kilocode');
1033
+ const workflowsDir = path.join(kilocodeDir, 'workflows');
1034
+ const rulesDir = path.join(kilocodeDir, 'rules');
1035
+ const skillsDir = path.join(kilocodeDir, 'skills', 'forge-workflow');
1032
1036
 
1033
- // Generate .kilo.md content (plain markdown, no frontmatter)
1034
- const content = generateKiloMdContent(projectMeta);
1035
-
1036
- await fs.promises.writeFile(kiloMdPath, content, 'utf-8');
1037
+ await fs.promises.mkdir(workflowsDir, { recursive: true });
1038
+ await fs.promises.mkdir(rulesDir, { recursive: true });
1039
+ await fs.promises.mkdir(skillsDir, { recursive: true });
1040
+
1041
+ await writeIfNeeded(
1042
+ path.join(workflowsDir, 'forge-workflow.md'),
1043
+ generateKiloWorkflowContent(projectMeta),
1044
+ overwrite
1045
+ );
1046
+ await writeIfNeeded(
1047
+ path.join(rulesDir, 'workflow.md'),
1048
+ generateKiloRulesContent(projectMeta),
1049
+ overwrite
1050
+ );
1051
+ await writeIfNeeded(
1052
+ path.join(skillsDir, 'SKILL.md'),
1053
+ generateKiloSkillContent(projectMeta),
1054
+ overwrite
1055
+ );
1037
1056
  }
1038
1057
 
1039
1058
  /**
1040
- * Generate .kilo.md content
1059
+ * Generate .kilocode/workflows/forge-workflow.md content
1041
1060
  */
1042
- function generateKiloMdContent(meta) {
1061
+ function generateKiloWorkflowContent(meta) {
1043
1062
  const packageManager = meta.testCommand?.includes('bun') ? 'bun' : 'npm';
1044
1063
 
1045
- return `# Forge Workflow Framework - Kilo Code
1064
+ return `---
1065
+ description: "Forge workflow for Kilo Code"
1066
+ ---
1046
1067
 
1047
- This project uses the **Forge 7-Stage TDD Workflow** with Kilo Code.
1068
+ # Forge Workflow Framework - Kilo Code
1069
+
1070
+ This project uses the **Forge 7-Stage TDD Workflow** with Kilo Code native workflows.
1048
1071
 
1049
1072
  ## Quick Start
1050
1073
 
@@ -1054,12 +1077,12 @@ ${meta.testCommand} # Run tests
1054
1077
  ${meta.buildCommand} # Build project
1055
1078
  \`\`\`
1056
1079
 
1057
- ## Kilo Built-in Commands
1080
+ ## Native Kilo Surface
1058
1081
 
1059
- Kilo Code provides built-in commands:
1060
- - \`/plan\` - Create implementation plans (similar to Forge Stage 3)
1061
- - \`/deploy\` - Deploy to production
1062
- - \`/review\` - Code review assistance
1082
+ Kilo Code uses native workflows, rules, and skills. Forge generates:
1083
+ - \`.kilocode/workflows/forge-workflow.md\`
1084
+ - \`.kilocode/rules/workflow.md\`
1085
+ - \`.kilocode/skills/forge-workflow/SKILL.md\`
1063
1086
 
1064
1087
  These complement the Forge workflow stages below.
1065
1088
 
@@ -1117,36 +1140,67 @@ Final documentation verification
1117
1140
  - Verify all docs updated
1118
1141
  - Check for broken links
1119
1142
  - Validate code examples
1143
+ `;
1144
+ }
1120
1145
 
1121
- ## TDD Requirements
1146
+ /**
1147
+ * Generate .kilocode/rules/workflow.md content
1148
+ */
1149
+ function generateKiloRulesContent(meta) {
1150
+ const packageManager = meta.testCommand?.includes('bun') ? 'bun' : 'npm';
1122
1151
 
1123
- **MANDATORY**:
1124
- - Write test FIRST (RED phase)
1125
- - Implement minimal code to pass (GREEN phase)
1126
- - Refactor and commit (REFACTOR phase)
1127
- - No code changes without corresponding tests
1152
+ return `---
1153
+ description: "Forge workflow rules for Kilo Code"
1154
+ ---
1128
1155
 
1129
- ## Tech Stack
1156
+ # Forge Workflow Rules
1130
1157
 
1131
- ${meta.language ? `- **Language**: ${meta.language}` : '- **Language**: JavaScript'}
1132
- - **Package Manager**: ${packageManager}
1133
- - **Testing**: TDD-first approach
1134
- - **Security**: OWASP Top 10 compliance
1135
- - **Version Control**: Git with conventional commits
1158
+ - Use Forge as the source of truth for stage order and hard stops.
1159
+ - Run \`forge <stage>\` before continuing any workflow stage.
1160
+ - Treat \`.kilocode/workflows\` as the canonical workflow surface.
1161
+ - Keep \`AGENTS.md\` as shared context, not the workflow authority.
1162
+ - If Forge blocks a stage, fix the prerequisite or provide an explicit override payload.
1136
1163
 
1137
- ## Security
1164
+ ## Environment
1138
1165
 
1139
- For every new feature, analyze OWASP Top 10:
1140
- - A01: Broken Access Control
1141
- - A02: Cryptographic Failures
1142
- - A03: Injection
1143
- - A04: Insecure Design
1144
- - A05: Security Misconfiguration
1145
- - A06: Vulnerable and Outdated Components
1146
- - A07: Authentication Failures
1147
- - A08: Software and Data Integrity Failures
1148
- - A09: Security Logging and Monitoring Failures
1149
- - A10: Server-Side Request Forgery (SSRF)
1166
+ - Package manager: ${packageManager}
1167
+ - Language: ${meta.language ? meta.language : 'JavaScript'}
1168
+ `;
1169
+ }
1170
+
1171
+ /**
1172
+ * Generate .kilocode/skills/forge-workflow/SKILL.md content
1173
+ */
1174
+ function generateKiloSkillContent(meta) {
1175
+ const packageManager = meta.testCommand?.includes('bun') ? 'bun' : 'npm';
1176
+
1177
+ return `---
1178
+ name: forge-workflow
1179
+ description: Forge stage adapter for Kilo Code
1180
+ ---
1181
+
1182
+ # Forge Workflow Skill
1183
+
1184
+ Before starting any stage, invoke \`forge <stage>\` so Forge can enforce stage order, prerequisites, and overrides.
1185
+ If Forge blocks the stage, stop and resolve it first.
1186
+
1187
+ ## Workflow Context
1188
+
1189
+ - Package manager: ${packageManager}
1190
+ - Language: ${meta.language ? meta.language : 'JavaScript'}
1191
+ - Canonical workflow surface: \`.kilocode/workflows/forge-workflow.md\`
1192
+ - Shared context: \`AGENTS.md\`
1193
+
1194
+ ## Supported Stages
1195
+
1196
+ - \`/status\`
1197
+ - \`/plan\`
1198
+ - \`/dev\`
1199
+ - \`/validate\`
1200
+ - \`/ship\`
1201
+ - \`/review\`
1202
+ - \`/premerge\`
1203
+ - \`/verify\`
1150
1204
  `;
1151
1205
  }
1152
1206
 
@@ -1168,28 +1222,22 @@ async function generateOpenCodeConfig(projectPath, options = {}) {
1168
1222
  const agentsDir = path.join(opencodeDir, 'agents');
1169
1223
  await fs.promises.mkdir(agentsDir, { recursive: true });
1170
1224
 
1171
- // Helper to write file if it doesn't exist or overwrite is true
1172
- const writeIfNeeded = async (filePath, content) => {
1173
- const exists = await fs.promises.access(filePath).then(() => true).catch(() => false);
1174
- if (!exists || overwrite) {
1175
- await fs.promises.writeFile(filePath, content, 'utf-8');
1176
- }
1177
- };
1225
+ const writeConfigFile = createConditionalWriter(overwrite);
1178
1226
 
1179
1227
  // 1. Create opencode.json
1180
1228
  const opencodeJsonPath = path.join(projectPath, 'opencode.json');
1181
1229
  const opencodeJsonContent = generateOpenCodeJsonContent(projectMeta);
1182
- await writeIfNeeded(opencodeJsonPath, opencodeJsonContent);
1230
+ await writeConfigFile(opencodeJsonPath, opencodeJsonContent);
1183
1231
 
1184
1232
  // 2. Create .opencode/agents/plan-review.md
1185
1233
  const planAgentPath = path.join(agentsDir, 'plan-review.md');
1186
1234
  const planAgentContent = generateOpenCodePlanAgentContent();
1187
- await writeIfNeeded(planAgentPath, planAgentContent);
1235
+ await writeConfigFile(planAgentPath, planAgentContent);
1188
1236
 
1189
1237
  // 3. Create .opencode/agents/tdd-build.md
1190
1238
  const buildAgentPath = path.join(agentsDir, 'tdd-build.md');
1191
1239
  const buildAgentContent = generateOpenCodeBuildAgentContent();
1192
- await writeIfNeeded(buildAgentPath, buildAgentContent);
1240
+ await writeConfigFile(buildAgentPath, buildAgentContent);
1193
1241
  }
1194
1242
 
1195
1243
  /**
@@ -1271,7 +1319,7 @@ Focus on:
1271
1319
  - Research with web search for best practices
1272
1320
  - Document findings in \`docs/plans/<feature-slug>-design.md\`
1273
1321
  - Include security analysis (OWASP Top 10)
1274
- - Create detailed plan in \`.claude/plans/<feature-slug>.md\`
1322
+ - Create detailed plan in \`docs/plans/<feature-slug>.md\`
1275
1323
  - Break down into TDD cycles (RED-GREEN-REFACTOR)
1276
1324
  - Identify files to create/modify
1277
1325
 
@@ -0,0 +1,50 @@
1
+ const fs = require('node:fs');
2
+ const path = require('node:path');
3
+
4
+ function injectForgeAdapter(content, commandName) {
5
+ const adapter = [
6
+ '> Forge stage adapter',
7
+ '',
8
+ `Before executing this workflow, invoke \`forge ${commandName}\` so Forge can enforce stage order, runtime prerequisites, and override rules.`,
9
+ 'If Forge blocks the stage or asks for an explicit override payload, stop and resolve that first.',
10
+ '',
11
+ ].join('\n');
12
+
13
+ const match = content.match(/^(---\r?\n[\s\S]*?\r?\n---\r?\n?)([\s\S]*)$/);
14
+ if (!match) {
15
+ return `${adapter}\n${content}`;
16
+ }
17
+
18
+ return `${match[1]}\n${adapter}${match[2]}`;
19
+ }
20
+
21
+ function listCodexSkillEntries(sourceRoot) {
22
+ const skillsDir = path.join(sourceRoot, '.codex', 'skills');
23
+
24
+ if (!fs.existsSync(skillsDir)) {
25
+ return [];
26
+ }
27
+
28
+ return fs.readdirSync(skillsDir, { withFileTypes: true })
29
+ .filter((entry) => entry.isDirectory())
30
+ .map((entry) => entry.name)
31
+ .sort()
32
+ .map((commandName) => {
33
+ const sourceFile = path.join(skillsDir, commandName, 'SKILL.md');
34
+ if (!fs.existsSync(sourceFile)) {
35
+ return null;
36
+ }
37
+
38
+ return {
39
+ commandName,
40
+ dir: `.codex/skills/${commandName}/`,
41
+ filename: 'SKILL.md',
42
+ content: injectForgeAdapter(fs.readFileSync(sourceFile, 'utf8'), commandName),
43
+ };
44
+ })
45
+ .filter(Boolean);
46
+ }
47
+
48
+ module.exports = {
49
+ listCodexSkillEntries,
50
+ };