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.
- package/.claude/commands/dev.md +6 -1
- package/.claude/commands/plan.md +59 -14
- package/.claude/commands/premerge.md +10 -0
- package/.claude/commands/review.md +7 -1
- package/.claude/commands/ship.md +95 -47
- package/.claude/commands/status.md +42 -0
- package/.claude/commands/validate.md +7 -1
- package/.claude/commands/verify.md +52 -4
- package/.claude/rules/workflow.md +16 -0
- package/.claude/scripts/greptile-resolve.sh +32 -0
- package/.cline/workflows/dev.md +6 -1
- package/.cline/workflows/plan.md +59 -14
- package/.cline/workflows/premerge.md +10 -0
- package/.cline/workflows/review.md +7 -1
- package/.cline/workflows/ship.md +95 -47
- package/.cline/workflows/status.md +42 -0
- package/.cline/workflows/validate.md +7 -1
- package/.cline/workflows/verify.md +52 -4
- package/.codex/skills/dev/SKILL.md +6 -1
- package/.codex/skills/plan/SKILL.md +59 -14
- package/.codex/skills/premerge/SKILL.md +10 -0
- package/.codex/skills/review/SKILL.md +7 -1
- package/.codex/skills/ship/SKILL.md +95 -47
- package/.codex/skills/status/SKILL.md +42 -0
- package/.codex/skills/validate/SKILL.md +7 -1
- package/.codex/skills/verify/SKILL.md +52 -4
- package/.cursor/commands/dev.md +6 -1
- package/.cursor/commands/plan.md +59 -14
- package/.cursor/commands/premerge.md +10 -0
- package/.cursor/commands/review.md +7 -1
- package/.cursor/commands/ship.md +95 -47
- package/.cursor/commands/status.md +42 -0
- package/.cursor/commands/validate.md +7 -1
- package/.cursor/commands/verify.md +52 -4
- package/.cursorrules +149 -0
- package/.github/prompts/dev.prompt.md +6 -1
- package/.github/prompts/plan.prompt.md +59 -14
- package/.github/prompts/premerge.prompt.md +10 -0
- package/.github/prompts/review.prompt.md +7 -1
- package/.github/prompts/ship.prompt.md +95 -47
- package/.github/prompts/status.prompt.md +42 -0
- package/.github/prompts/validate.prompt.md +7 -1
- package/.github/prompts/verify.prompt.md +52 -4
- package/.kilocode/workflows/dev.md +6 -1
- package/.kilocode/workflows/plan.md +59 -14
- package/.kilocode/workflows/premerge.md +10 -0
- package/.kilocode/workflows/review.md +7 -1
- package/.kilocode/workflows/ship.md +95 -47
- package/.kilocode/workflows/status.md +42 -0
- package/.kilocode/workflows/validate.md +7 -1
- package/.kilocode/workflows/verify.md +52 -4
- package/.opencode/commands/dev.md +6 -1
- package/.opencode/commands/plan.md +59 -14
- package/.opencode/commands/premerge.md +10 -0
- package/.opencode/commands/review.md +7 -1
- package/.opencode/commands/ship.md +95 -47
- package/.opencode/commands/status.md +42 -0
- package/.opencode/commands/validate.md +7 -1
- package/.opencode/commands/verify.md +52 -4
- package/.roo/commands/dev.md +6 -1
- package/.roo/commands/plan.md +59 -14
- package/.roo/commands/premerge.md +10 -0
- package/.roo/commands/review.md +7 -1
- package/.roo/commands/ship.md +95 -47
- package/.roo/commands/status.md +42 -0
- package/.roo/commands/validate.md +7 -1
- package/.roo/commands/verify.md +52 -4
- package/AGENTS.md +97 -0
- package/CLAUDE.md +10 -0
- package/README.md +2 -2
- package/bin/forge-cmd.js +5 -1
- package/bin/forge-preflight.js +15 -2
- package/bin/forge.js +211 -9
- package/docs/ENHANCED_ONBOARDING.md +96 -86
- package/docs/ROADMAP.md +2 -2
- package/docs/TOOLCHAIN.md +23 -0
- package/docs/VALIDATION.md +1 -1
- package/lefthook.yml +11 -0
- package/lib/agents/README.md +46 -1
- package/lib/agents/cline.plugin.json +11 -4
- package/lib/agents/codex.plugin.json +2 -2
- package/lib/agents/copilot.plugin.json +5 -5
- package/lib/agents/cursor.plugin.json +1 -1
- package/lib/agents/kilocode.plugin.json +1 -1
- package/lib/agents/opencode.plugin.json +7 -4
- package/lib/agents/roo.plugin.json +10 -3
- package/lib/agents-config.js +129 -81
- package/lib/codex-skills.js +50 -0
- package/lib/commands/_registry.js +173 -0
- package/lib/commands/clean.js +181 -0
- package/lib/commands/commands-reset.js +147 -0
- package/lib/commands/dev.js +84 -0
- package/lib/commands/plan.js +18 -0
- package/lib/commands/push.js +196 -0
- package/lib/commands/recommend.js +1 -1
- package/lib/commands/setup.js +4295 -0
- package/lib/commands/ship.js +20 -0
- package/lib/commands/status.js +210 -44
- package/lib/commands/sync.js +71 -0
- package/lib/commands/team.js +37 -0
- package/lib/commands/test.js +207 -0
- package/lib/commands/validate.js +13 -0
- package/lib/commands/worktree.js +310 -0
- package/lib/detect-agent.js +38 -8
- package/lib/detection-utils.js +405 -0
- package/lib/docs-command.js +51 -0
- package/lib/docs-copy.js +50 -0
- package/lib/file-utils.js +260 -0
- package/lib/forge-context.js +42 -0
- package/lib/freshness-token.js +148 -0
- package/lib/frontmatter.js +79 -0
- package/lib/greptile-match.js +80 -0
- package/lib/husky-migration.js +113 -12
- package/lib/lefthook-check.js +27 -6
- package/lib/plugin-manager.js +225 -72
- package/lib/project-discovery.js +39 -5
- package/lib/reset.js +309 -0
- package/lib/runtime-health.js +305 -0
- package/lib/shell-utils.js +50 -0
- package/lib/task-ownership.js +117 -0
- package/lib/ui-utils.js +43 -0
- package/lib/validation-utils.js +163 -0
- package/lib/workflow/enforce-stage.js +179 -0
- package/lib/workflow/stages.js +201 -0
- package/lib/workflow/state.js +332 -0
- package/opencode.json +67 -0
- package/package.json +16 -6
- package/scripts/beads-context.sh +165 -22
- package/scripts/beads-context.test.js +5 -1
- package/scripts/check-agents.js +103 -0
- package/scripts/check-forge-token.js +98 -0
- package/scripts/conflict-detect.sh +2 -2
- package/scripts/dep-guard.sh +6 -28
- package/scripts/file-index.sh +117 -23
- package/scripts/forge-team/index.sh +86 -0
- package/scripts/forge-team/lib/agent-prompt.sh +52 -0
- package/scripts/forge-team/lib/claim.sh +256 -0
- package/scripts/forge-team/lib/dashboard.sh +341 -0
- package/scripts/forge-team/lib/epic.sh +332 -0
- package/scripts/forge-team/lib/hooks.sh +253 -0
- package/scripts/forge-team/lib/identity.sh +235 -0
- package/scripts/forge-team/lib/sync-github.sh +317 -0
- package/scripts/forge-team/lib/verify.sh +284 -0
- package/scripts/forge-team/lib/workload.sh +296 -0
- package/scripts/forge-team/tests/agent-prompt.test.sh +72 -0
- package/scripts/forge-team/tests/claim.test.sh +179 -0
- package/scripts/forge-team/tests/dashboard.test.sh +170 -0
- package/scripts/forge-team/tests/dispatcher.test.sh +79 -0
- package/scripts/forge-team/tests/epic.test.sh +176 -0
- package/scripts/forge-team/tests/hooks.test.sh +239 -0
- package/scripts/forge-team/tests/identity.test.sh +176 -0
- package/scripts/forge-team/tests/integration.test.sh +371 -0
- package/scripts/forge-team/tests/sync-github.test.sh +209 -0
- package/scripts/forge-team/tests/verify.test.sh +314 -0
- package/scripts/forge-team/tests/workflow-integration.test.sh +43 -0
- package/scripts/forge-team/tests/workload.test.sh +209 -0
- package/scripts/lib/eval-runner.js +39 -0
- package/scripts/lib/jsonl-lock.sh +48 -0
- package/scripts/lib/sanitize.sh +116 -0
- package/scripts/pr-coordinator.sh +756 -0
- package/scripts/smart-status.sh +58 -21
- package/scripts/sync-commands.js +49 -20
- package/scripts/sync-utils.sh +24 -29
- package/scripts/test.js +18 -1
package/lib/agents/README.md
CHANGED
|
@@ -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
|
-
"
|
|
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":
|
|
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
|
-
"
|
|
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":
|
|
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":
|
|
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":
|
|
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": "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":
|
|
9
|
+
"skills": false,
|
|
10
10
|
"hooks": false
|
|
11
11
|
},
|
|
12
12
|
"directories": {
|
|
13
13
|
"commands": ".opencode/commands",
|
|
14
|
-
"
|
|
14
|
+
"agents": ".opencode/agents"
|
|
15
|
+
},
|
|
16
|
+
"files": {
|
|
17
|
+
"rootConfig": "opencode.json"
|
|
15
18
|
},
|
|
16
19
|
"setup": {
|
|
17
20
|
"copyCommands": true,
|
|
18
|
-
"
|
|
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":
|
|
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
|
package/lib/agents-config.js
CHANGED
|
@@ -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**: \`.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
const
|
|
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
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
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 .
|
|
1059
|
+
* Generate .kilocode/workflows/forge-workflow.md content
|
|
1041
1060
|
*/
|
|
1042
|
-
function
|
|
1061
|
+
function generateKiloWorkflowContent(meta) {
|
|
1043
1062
|
const packageManager = meta.testCommand?.includes('bun') ? 'bun' : 'npm';
|
|
1044
1063
|
|
|
1045
|
-
return
|
|
1064
|
+
return `---
|
|
1065
|
+
description: "Forge workflow for Kilo Code"
|
|
1066
|
+
---
|
|
1046
1067
|
|
|
1047
|
-
|
|
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
|
|
1080
|
+
## Native Kilo Surface
|
|
1058
1081
|
|
|
1059
|
-
Kilo Code
|
|
1060
|
-
-
|
|
1061
|
-
-
|
|
1062
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
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
|
-
|
|
1156
|
+
# Forge Workflow Rules
|
|
1130
1157
|
|
|
1131
|
-
|
|
1132
|
-
-
|
|
1133
|
-
-
|
|
1134
|
-
-
|
|
1135
|
-
-
|
|
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
|
-
##
|
|
1164
|
+
## Environment
|
|
1138
1165
|
|
|
1139
|
-
|
|
1140
|
-
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
+
};
|