forge-dev-framework 1.0.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/rules/api-patterns.md +98 -0
- package/.claude/rules/security-baseline.md +204 -0
- package/.claude/rules/testing-standards.md +177 -0
- package/.claude/rules/ui-conventions.md +142 -0
- package/README.md +261 -0
- package/bin/forge.js +14 -0
- package/dist/bin/forge.js +14 -0
- package/dist/cli/index.d.ts +22 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +116 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/base.d.ts +31 -0
- package/dist/commands/base.d.ts.map +1 -0
- package/dist/commands/base.js +31 -0
- package/dist/commands/base.js.map +1 -0
- package/dist/commands/config.d.ts +14 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +175 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/generate.d.ts +17 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +159 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/help.d.ts +11 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +65 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/index.d.ts +8 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +8 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +10 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +22 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/status.d.ts +13 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +101 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stubs.d.ts +14 -0
- package/dist/commands/stubs.d.ts.map +1 -0
- package/dist/commands/stubs.js +30 -0
- package/dist/commands/stubs.js.map +1 -0
- package/dist/generators/index.d.ts +11 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +10 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/generators/required-fields.d.ts +74 -0
- package/dist/generators/required-fields.d.ts.map +1 -0
- package/dist/generators/required-fields.js +179 -0
- package/dist/generators/required-fields.js.map +1 -0
- package/dist/generators/template-engine.d.ts +65 -0
- package/dist/generators/template-engine.d.ts.map +1 -0
- package/dist/generators/template-engine.js +209 -0
- package/dist/generators/template-engine.js.map +1 -0
- package/dist/generators/token-validator.d.ts +51 -0
- package/dist/generators/token-validator.d.ts.map +1 -0
- package/dist/generators/token-validator.js +141 -0
- package/dist/generators/token-validator.js.map +1 -0
- package/dist/generators/types.d.ts +433 -0
- package/dist/generators/types.d.ts.map +1 -0
- package/dist/generators/types.js +5 -0
- package/dist/generators/types.js.map +1 -0
- package/dist/generators/xml-task-generator.d.ts +67 -0
- package/dist/generators/xml-task-generator.d.ts.map +1 -0
- package/dist/generators/xml-task-generator.js +297 -0
- package/dist/generators/xml-task-generator.js.map +1 -0
- package/dist/git/__tests__/worktree.test.d.ts +5 -0
- package/dist/git/__tests__/worktree.test.d.ts.map +1 -0
- package/dist/git/__tests__/worktree.test.js +121 -0
- package/dist/git/__tests__/worktree.test.js.map +1 -0
- package/dist/git/codeowners.d.ts +101 -0
- package/dist/git/codeowners.d.ts.map +1 -0
- package/dist/git/codeowners.js +216 -0
- package/dist/git/codeowners.js.map +1 -0
- package/dist/git/commit.d.ts +135 -0
- package/dist/git/commit.d.ts.map +1 -0
- package/dist/git/commit.js +223 -0
- package/dist/git/commit.js.map +1 -0
- package/dist/git/hooks/commit-msg.d.ts +8 -0
- package/dist/git/hooks/commit-msg.d.ts.map +1 -0
- package/dist/git/hooks/commit-msg.js +34 -0
- package/dist/git/hooks/commit-msg.js.map +1 -0
- package/dist/git/hooks/pre-commit.d.ts +8 -0
- package/dist/git/hooks/pre-commit.d.ts.map +1 -0
- package/dist/git/hooks/pre-commit.js +34 -0
- package/dist/git/hooks/pre-commit.js.map +1 -0
- package/dist/git/pre-commit-hooks.d.ts +117 -0
- package/dist/git/pre-commit-hooks.d.ts.map +1 -0
- package/dist/git/pre-commit-hooks.js +270 -0
- package/dist/git/pre-commit-hooks.js.map +1 -0
- package/dist/git/wipe-protocol.d.ts +281 -0
- package/dist/git/wipe-protocol.d.ts.map +1 -0
- package/dist/git/wipe-protocol.js +237 -0
- package/dist/git/wipe-protocol.js.map +1 -0
- package/dist/git/worktree.d.ts +69 -0
- package/dist/git/worktree.d.ts.map +1 -0
- package/dist/git/worktree.js +202 -0
- package/dist/git/worktree.js.map +1 -0
- package/dist/scripts/install.d.ts +8 -0
- package/dist/scripts/install.d.ts.map +1 -0
- package/dist/scripts/install.js +161 -0
- package/dist/scripts/install.js.map +1 -0
- package/dist/types/config.d.ts +30 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +23 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/state.d.ts +56 -0
- package/dist/types/state.d.ts.map +1 -0
- package/dist/types/state.js +6 -0
- package/dist/types/state.js.map +1 -0
- package/dist/utils/config.d.ts +15 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +80 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/errors.d.ts +25 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +48 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/index.d.ts +11 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +34 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +73 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/state-api.d.ts +128 -0
- package/dist/utils/state-api.d.ts.map +1 -0
- package/dist/utils/state-api.js +170 -0
- package/dist/utils/state-api.js.map +1 -0
- package/dist/utils/template-client.d.ts +73 -0
- package/dist/utils/template-client.d.ts.map +1 -0
- package/dist/utils/template-client.js +151 -0
- package/dist/utils/template-client.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Worktree Management for FORGE
|
|
3
|
+
*
|
|
4
|
+
* Implements isolated worktree strategy for parallel agent execution.
|
|
5
|
+
* Each task gets its own worktree to prevent merge conflicts during development.
|
|
6
|
+
*
|
|
7
|
+
* Commands (from FORGE spec):
|
|
8
|
+
* - git worktree add .worktrees/{taskId} -b forge/{taskId}
|
|
9
|
+
* - git worktree remove .worktrees/{taskId}
|
|
10
|
+
*/
|
|
11
|
+
import { execa } from "execa";
|
|
12
|
+
export class WorktreeError extends Error {
|
|
13
|
+
code;
|
|
14
|
+
constructor(message, code) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.name = "WorktreeError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Create a new git worktree for a task.
|
|
22
|
+
*
|
|
23
|
+
* Creates a branch `forge/{taskId}` and checks it out into `.worktrees/{taskId}`.
|
|
24
|
+
* This gives each agent an isolated filesystem to work in.
|
|
25
|
+
*
|
|
26
|
+
* @param options - Task identification and branch configuration
|
|
27
|
+
* @returns Path to the new worktree
|
|
28
|
+
* @throws WorktreeError if worktree creation fails
|
|
29
|
+
*/
|
|
30
|
+
export async function createWorktree(options) {
|
|
31
|
+
const { taskId, branchName = `forge/${taskId}`, baseBranch = "main" } = options;
|
|
32
|
+
const worktreePath = `.worktrees/${taskId}`;
|
|
33
|
+
try {
|
|
34
|
+
// Create the .worktrees directory if it doesn't exist
|
|
35
|
+
await execa("mkdir", ["-p", ".worktrees"]);
|
|
36
|
+
// Create the worktree with a new branch
|
|
37
|
+
await execa("git", ["worktree", "add", "-b", branchName, worktreePath, baseBranch]);
|
|
38
|
+
return worktreePath;
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
if (error instanceof Error) {
|
|
42
|
+
throw new WorktreeError(`Failed to create worktree for task ${taskId}: ${error.message}`, error.code);
|
|
43
|
+
}
|
|
44
|
+
throw new WorktreeError(`Failed to create worktree for task ${taskId}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get information about a worktree.
|
|
49
|
+
*
|
|
50
|
+
* @param taskId - Task ID to look up
|
|
51
|
+
* @returns Worktree information or null if not found
|
|
52
|
+
*/
|
|
53
|
+
export async function getWorktree(taskId) {
|
|
54
|
+
try {
|
|
55
|
+
const { stdout } = await execa("git", ["worktree", "list", "--porcelain"]);
|
|
56
|
+
const lines = stdout.split("\n");
|
|
57
|
+
let currentPath = null;
|
|
58
|
+
let currentBranch = null;
|
|
59
|
+
let currentCommit = null;
|
|
60
|
+
for (const line of lines) {
|
|
61
|
+
if (line.startsWith("worktree ")) {
|
|
62
|
+
// Check if this is our target worktree
|
|
63
|
+
const path = line.slice("worktree ".length);
|
|
64
|
+
if (path.endsWith(`.worktrees/${taskId}`) || path.endsWith(`.worktrees/${taskId}/`)) {
|
|
65
|
+
currentPath = path;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (currentPath && line.startsWith("branch ")) {
|
|
69
|
+
currentBranch = line.slice("branch ".length).replace("refs/heads/", "");
|
|
70
|
+
}
|
|
71
|
+
else if (currentPath && line.startsWith("commit ")) {
|
|
72
|
+
currentCommit = line.slice("commit ".length);
|
|
73
|
+
}
|
|
74
|
+
else if (line === "") {
|
|
75
|
+
// End of a worktree block
|
|
76
|
+
if (currentPath && currentBranch && currentCommit) {
|
|
77
|
+
return {
|
|
78
|
+
taskId,
|
|
79
|
+
branchName: currentBranch,
|
|
80
|
+
path: currentPath,
|
|
81
|
+
commit: currentCommit,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Reset
|
|
85
|
+
currentPath = null;
|
|
86
|
+
currentBranch = null;
|
|
87
|
+
currentCommit = null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
throw new WorktreeError(`Failed to get worktree info for task ${taskId}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Merge a worktree's branch back into the base branch.
|
|
98
|
+
*
|
|
99
|
+
* Should only be called after CI passes. The worktree is removed after merge.
|
|
100
|
+
*
|
|
101
|
+
* @param taskId - Task ID whose branch to merge
|
|
102
|
+
* @param targetBranch - Branch to merge into (default: main)
|
|
103
|
+
* @throws WorktreeError if merge fails or has conflicts
|
|
104
|
+
*/
|
|
105
|
+
export async function mergeWorktree(taskId, targetBranch = "main") {
|
|
106
|
+
const worktree = await getWorktree(taskId);
|
|
107
|
+
if (!worktree) {
|
|
108
|
+
throw new WorktreeError(`Worktree for task ${taskId} not found`);
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
// Checkout the target branch in the main repository
|
|
112
|
+
await execa("git", ["checkout", targetBranch]);
|
|
113
|
+
// Merge the worktree branch
|
|
114
|
+
const branchName = worktree.branchName;
|
|
115
|
+
await execa("git", ["merge", "--no-ff", branchName, "-m", `Merge ${branchName} into ${targetBranch}`]);
|
|
116
|
+
// Clean up the worktree after successful merge
|
|
117
|
+
await cleanupWorktree(taskId);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
if (error instanceof Error) {
|
|
121
|
+
throw new WorktreeError(`Failed to merge worktree for task ${taskId}: ${error.message}`, error.code);
|
|
122
|
+
}
|
|
123
|
+
throw new WorktreeError(`Failed to merge worktree for task ${taskId}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Remove a worktree.
|
|
128
|
+
*
|
|
129
|
+
* Safely removes the worktree after cleaning up any uncommitted changes.
|
|
130
|
+
*
|
|
131
|
+
* @param taskId - Task ID whose worktree to remove
|
|
132
|
+
* @throws WorktreeError if removal fails
|
|
133
|
+
*/
|
|
134
|
+
export async function cleanupWorktree(taskId) {
|
|
135
|
+
const worktree = await getWorktree(taskId);
|
|
136
|
+
if (!worktree) {
|
|
137
|
+
// Already cleaned up, nothing to do
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
// Remove the worktree
|
|
142
|
+
await execa("git", ["worktree", "remove", worktree.path]);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
if (error instanceof Error) {
|
|
146
|
+
throw new WorktreeError(`Failed to cleanup worktree for task ${taskId}: ${error.message}`, error.code);
|
|
147
|
+
}
|
|
148
|
+
throw new WorktreeError(`Failed to cleanup worktree for task ${taskId}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* List all FORGE worktrees.
|
|
153
|
+
*
|
|
154
|
+
* @returns Array of worktree information for all active tasks
|
|
155
|
+
*/
|
|
156
|
+
export async function listWorktrees() {
|
|
157
|
+
try {
|
|
158
|
+
const { stdout } = await execa("git", ["worktree", "list", "--porcelain"]);
|
|
159
|
+
const lines = stdout.split("\n");
|
|
160
|
+
const worktrees = [];
|
|
161
|
+
let currentPath = null;
|
|
162
|
+
let currentBranch = null;
|
|
163
|
+
let currentCommit = null;
|
|
164
|
+
for (const line of lines) {
|
|
165
|
+
if (line.startsWith("worktree ")) {
|
|
166
|
+
const path = line.slice("worktree ".length);
|
|
167
|
+
// Only include FORGE worktrees
|
|
168
|
+
if (path.includes(".worktrees/")) {
|
|
169
|
+
currentPath = path;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else if (currentPath && line.startsWith("branch ")) {
|
|
173
|
+
currentBranch = line.slice("branch ".length).replace("refs/heads/", "");
|
|
174
|
+
}
|
|
175
|
+
else if (currentPath && line.startsWith("commit ")) {
|
|
176
|
+
currentCommit = line.slice("commit ".length);
|
|
177
|
+
}
|
|
178
|
+
else if (line === "") {
|
|
179
|
+
// End of a worktree block
|
|
180
|
+
if (currentPath && currentBranch && currentCommit) {
|
|
181
|
+
// Extract taskId from path
|
|
182
|
+
const taskId = currentPath.match(/\.worktrees\/([^/]+)/)?.[1] || "unknown";
|
|
183
|
+
worktrees.push({
|
|
184
|
+
taskId,
|
|
185
|
+
branchName: currentBranch,
|
|
186
|
+
path: currentPath,
|
|
187
|
+
commit: currentCommit,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
// Reset
|
|
191
|
+
currentPath = null;
|
|
192
|
+
currentBranch = null;
|
|
193
|
+
currentCommit = null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return worktrees;
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
throw new WorktreeError("Failed to list worktrees");
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=worktree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/git/worktree.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* FORGE Installation Script
|
|
4
|
+
* Copies command definitions to global or project .claude folder
|
|
5
|
+
* Run automatically via npm postinstall or manually with: node dist/scripts/install.js
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/scripts/install.ts"],"names":[],"mappings":";AAEA;;;;GAIG"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* FORGE Installation Script
|
|
4
|
+
* Copies command definitions to global or project .claude folder
|
|
5
|
+
* Run automatically via npm postinstall or manually with: node dist/scripts/install.js
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'fs/promises';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import { dirname } from 'path';
|
|
11
|
+
import { existsSync } from 'fs';
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = dirname(__filename);
|
|
14
|
+
/**
|
|
15
|
+
* Detect if current directory is a FORGE project
|
|
16
|
+
*/
|
|
17
|
+
async function isForgeProject(cwd) {
|
|
18
|
+
const claudeMdPath = path.join(cwd, 'CLAUDE.md');
|
|
19
|
+
const stateDirPath = path.join(cwd, 'state');
|
|
20
|
+
try {
|
|
21
|
+
const [claudeExists, stateExists] = await Promise.all([
|
|
22
|
+
fs.access(claudeMdPath).then(() => true).catch(() => false),
|
|
23
|
+
fs.access(stateDirPath).then(() => true).catch(() => false),
|
|
24
|
+
]);
|
|
25
|
+
return claudeExists && stateExists;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Copy command files from source to target
|
|
33
|
+
*/
|
|
34
|
+
async function copyCommands(sourceDir, targetDir, verbose = false) {
|
|
35
|
+
const log = (msg) => {
|
|
36
|
+
if (verbose)
|
|
37
|
+
console.log(` ${msg}`);
|
|
38
|
+
};
|
|
39
|
+
// Remove existing directory if it exists
|
|
40
|
+
try {
|
|
41
|
+
await fs.rm(targetDir, { recursive: true, force: true });
|
|
42
|
+
log('Removed existing directory');
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Directory doesn't exist, that's fine
|
|
46
|
+
}
|
|
47
|
+
// Create target directory
|
|
48
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
49
|
+
log(`Created directory: ${targetDir}`);
|
|
50
|
+
// Copy all files
|
|
51
|
+
const files = await fs.readdir(sourceDir);
|
|
52
|
+
let copiedCount = 0;
|
|
53
|
+
for (const file of files) {
|
|
54
|
+
if (file.endsWith('.md')) {
|
|
55
|
+
const sourcePath = path.join(sourceDir, file);
|
|
56
|
+
const targetPath = path.join(targetDir, file);
|
|
57
|
+
await fs.copyFile(sourcePath, targetPath);
|
|
58
|
+
copiedCount++;
|
|
59
|
+
log(`Copied: ${file}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return copiedCount;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Main installation function
|
|
66
|
+
*/
|
|
67
|
+
async function install(options = {}) {
|
|
68
|
+
const { verbose = false, mode = 'auto' } = options;
|
|
69
|
+
// Determine paths
|
|
70
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || '.';
|
|
71
|
+
const cwd = process.cwd();
|
|
72
|
+
const globalCommandsDir = path.join(homeDir, '.claude', 'commands', 'forge');
|
|
73
|
+
const projectCommandsDir = path.join(cwd, '.claude', 'commands', 'forge');
|
|
74
|
+
// Determine installation mode
|
|
75
|
+
let installMode = mode;
|
|
76
|
+
let targetDir;
|
|
77
|
+
if (mode === 'auto') {
|
|
78
|
+
// Auto-detect: check if we're in a FORGE project
|
|
79
|
+
const inForgeProject = await isForgeProject(cwd);
|
|
80
|
+
if (inForgeProject) {
|
|
81
|
+
installMode = 'project';
|
|
82
|
+
targetDir = projectCommandsDir;
|
|
83
|
+
console.log('ℹ FORGE project detected - installing to project .claude folder');
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
installMode = 'global';
|
|
87
|
+
targetDir = globalCommandsDir;
|
|
88
|
+
console.log('ℹ No FORGE project detected - installing to global .claude folder');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (mode === 'global') {
|
|
92
|
+
targetDir = globalCommandsDir;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
targetDir = projectCommandsDir;
|
|
96
|
+
}
|
|
97
|
+
// Get package directory (where npm installed the package)
|
|
98
|
+
const packageDir = path.join(__dirname, '..');
|
|
99
|
+
// Try different source paths (for both installed and dev modes)
|
|
100
|
+
const possibleSources = [
|
|
101
|
+
path.join(packageDir, '..', '.claude', 'commands', 'forge'), // Installed
|
|
102
|
+
path.join(cwd, '.claude', 'commands', 'forge'), // Dev
|
|
103
|
+
path.join(process.cwd(), '.claude', 'commands', 'forge'), // Alternative
|
|
104
|
+
];
|
|
105
|
+
let sourceCommandsDir = null;
|
|
106
|
+
for (const sourcePath of possibleSources) {
|
|
107
|
+
if (existsSync(sourcePath)) {
|
|
108
|
+
sourceCommandsDir = sourcePath;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (!sourceCommandsDir) {
|
|
113
|
+
console.error('✗ Commands directory not found');
|
|
114
|
+
console.log('ℹ If developing, run: npm run build');
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
const log = (msg) => {
|
|
118
|
+
if (verbose)
|
|
119
|
+
console.log(` ${msg}`);
|
|
120
|
+
};
|
|
121
|
+
const success = (msg) => console.log(`✓ ${msg}`);
|
|
122
|
+
const error = (msg) => console.error(`✗ ${msg}`);
|
|
123
|
+
try {
|
|
124
|
+
log(`Mode: ${installMode}`);
|
|
125
|
+
log(`Source: ${sourceCommandsDir}`);
|
|
126
|
+
log(`Target: ${targetDir}`);
|
|
127
|
+
const copiedCount = await copyCommands(sourceCommandsDir, targetDir, verbose);
|
|
128
|
+
success(`FORGE commands installed (${installMode} mode)`);
|
|
129
|
+
console.log(` ${copiedCount} command files copied`);
|
|
130
|
+
if (installMode === 'global') {
|
|
131
|
+
console.log('');
|
|
132
|
+
console.log('Available commands:');
|
|
133
|
+
console.log(' /forge:new-project Initialize a new FORGE project');
|
|
134
|
+
console.log(' /forge:init Initialize FORGE in current directory');
|
|
135
|
+
console.log(' /forge:status Show project progress');
|
|
136
|
+
console.log(' /forge:discuss Capture phase context');
|
|
137
|
+
console.log(' /forge:plan Generate task breakdown');
|
|
138
|
+
console.log(' /forge:execute Execute phase with agent teams');
|
|
139
|
+
console.log(' /forge:help Show all commands');
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
console.log('');
|
|
143
|
+
console.log('ℹ Project-level installation complete');
|
|
144
|
+
console.log('ℹ Commands available in this project only');
|
|
145
|
+
}
|
|
146
|
+
console.log('');
|
|
147
|
+
console.log('Documentation: https://github.com/Alzarak/forge');
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
error(`Installation failed: ${err}`);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Parse CLI arguments
|
|
155
|
+
const args = process.argv.slice(2);
|
|
156
|
+
const verbose = args.includes('--verbose') || args.includes('-v');
|
|
157
|
+
const modeArg = args.find(arg => arg.startsWith('--mode='));
|
|
158
|
+
const mode = modeArg ? modeArg.split('=')[1] : 'auto';
|
|
159
|
+
// Run installation
|
|
160
|
+
await install({ verbose, mode });
|
|
161
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/scripts/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FORGE Configuration Types
|
|
3
|
+
* Based on .planning/forge.config.json schema
|
|
4
|
+
*/
|
|
5
|
+
export type ForgeMode = 'yolo' | 'interactive';
|
|
6
|
+
export type ForgeDepth = 'quick' | 'standard' | 'comprehensive';
|
|
7
|
+
export type GitStrategy = 'none' | 'worktree' | 'branch';
|
|
8
|
+
export type AgentProfile = 'quality' | 'balanced' | 'budget';
|
|
9
|
+
export interface WorkflowConfig {
|
|
10
|
+
research: boolean;
|
|
11
|
+
planCheck: boolean;
|
|
12
|
+
tribunal: boolean;
|
|
13
|
+
contractFirst: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface GitConfig {
|
|
16
|
+
strategy: GitStrategy;
|
|
17
|
+
branchTemplate: string;
|
|
18
|
+
squashOnShip: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface ForgeConfig {
|
|
21
|
+
mode: ForgeMode;
|
|
22
|
+
depth: ForgeDepth;
|
|
23
|
+
maxTeammates: number;
|
|
24
|
+
taskLimit: number;
|
|
25
|
+
agentProfile: AgentProfile;
|
|
26
|
+
workflow: WorkflowConfig;
|
|
27
|
+
git: GitConfig;
|
|
28
|
+
}
|
|
29
|
+
export declare const DEFAULT_CONFIG: ForgeConfig;
|
|
30
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,aAAa,CAAC;AAC/C,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,eAAe,CAAC;AAChE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAC;AACzD,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE7D,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,WAAW,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAE1B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,UAAU,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAGlB,YAAY,EAAE,YAAY,CAAC;IAG3B,QAAQ,EAAE,cAAc,CAAC;IAGzB,GAAG,EAAE,SAAS,CAAC;CAChB;AAED,eAAO,MAAM,cAAc,EAAE,WAiB5B,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FORGE Configuration Types
|
|
3
|
+
* Based on .planning/forge.config.json schema
|
|
4
|
+
*/
|
|
5
|
+
export const DEFAULT_CONFIG = {
|
|
6
|
+
mode: 'interactive',
|
|
7
|
+
depth: 'standard',
|
|
8
|
+
maxTeammates: 4,
|
|
9
|
+
taskLimit: 6,
|
|
10
|
+
agentProfile: 'balanced',
|
|
11
|
+
workflow: {
|
|
12
|
+
research: true,
|
|
13
|
+
planCheck: true,
|
|
14
|
+
tribunal: true,
|
|
15
|
+
contractFirst: true,
|
|
16
|
+
},
|
|
17
|
+
git: {
|
|
18
|
+
strategy: 'worktree',
|
|
19
|
+
branchTemplate: 'forge/{taskId}-{slug}',
|
|
20
|
+
squashOnShip: true,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqCH,MAAM,CAAC,MAAM,cAAc,GAAgB;IACzC,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,UAAU;IACjB,YAAY,EAAE,CAAC;IACf,SAAS,EAAE,CAAC;IACZ,YAAY,EAAE,UAAU;IACxB,QAAQ,EAAE;QACR,QAAQ,EAAE,IAAI;QACd,SAAS,EAAE,IAAI;QACf,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,IAAI;KACpB;IACD,GAAG,EAAE;QACH,QAAQ,EAAE,UAAU;QACpB,cAAc,EAAE,uBAAuB;QACvC,YAAY,EAAE,IAAI;KACnB;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FORGE State Types
|
|
3
|
+
* Based on state/STATE.json schema
|
|
4
|
+
*/
|
|
5
|
+
export type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'blocked';
|
|
6
|
+
export type EventType = 'TASK_STARTED' | 'TASK_COMPLETED' | 'TASK_BLOCKED' | 'REQUEST_CONTRACT' | 'CONTRACT_PUBLISHED' | 'REVIEW_FINDING' | 'REVIEW_RESOLVED';
|
|
7
|
+
export interface Task {
|
|
8
|
+
id: string;
|
|
9
|
+
title: string;
|
|
10
|
+
ownerRole: string;
|
|
11
|
+
status: TaskStatus;
|
|
12
|
+
deps: string[];
|
|
13
|
+
allowedPaths: string[];
|
|
14
|
+
acceptance: string[];
|
|
15
|
+
verify: string[];
|
|
16
|
+
commit: string | null;
|
|
17
|
+
requests: string[];
|
|
18
|
+
priority: number;
|
|
19
|
+
}
|
|
20
|
+
export interface Contract {
|
|
21
|
+
id: string;
|
|
22
|
+
path: string;
|
|
23
|
+
version: string;
|
|
24
|
+
publishedBy: string;
|
|
25
|
+
consumers: string[];
|
|
26
|
+
}
|
|
27
|
+
export interface ProjectState {
|
|
28
|
+
name: string;
|
|
29
|
+
status: string;
|
|
30
|
+
currentMilestone: string;
|
|
31
|
+
currentPhase: number;
|
|
32
|
+
}
|
|
33
|
+
export interface EventPayload {
|
|
34
|
+
[key: string]: any;
|
|
35
|
+
commitHash?: string;
|
|
36
|
+
filesChanged?: string[];
|
|
37
|
+
testsRun?: number;
|
|
38
|
+
testsPassed?: number;
|
|
39
|
+
reason?: string;
|
|
40
|
+
findings?: any[];
|
|
41
|
+
}
|
|
42
|
+
export interface StateEvent {
|
|
43
|
+
eventId: string;
|
|
44
|
+
timestamp: string;
|
|
45
|
+
taskId: string;
|
|
46
|
+
actor: string;
|
|
47
|
+
type: EventType;
|
|
48
|
+
payload: EventPayload;
|
|
49
|
+
}
|
|
50
|
+
export interface ForgeState {
|
|
51
|
+
project: ProjectState;
|
|
52
|
+
tasks: Task[];
|
|
53
|
+
contracts: Contract[];
|
|
54
|
+
eventsPointer: string;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/types/state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,SAAS,CAAC;AAC7E,MAAM,MAAM,SAAS,GACjB,cAAc,GACd,gBAAgB,GAChB,cAAc,GACd,kBAAkB,GAClB,oBAAoB,GACpB,gBAAgB,GAChB,iBAAiB,CAAC;AAEtB,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,YAAY,CAAC;IACtB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/types/state.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ForgeConfig } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Load FORGE configuration from .planning/forge.config.json
|
|
4
|
+
* Falls back to defaults if config doesn't exist
|
|
5
|
+
*/
|
|
6
|
+
export declare function loadConfig(projectRoot?: string): ForgeConfig;
|
|
7
|
+
/**
|
|
8
|
+
* Save FORGE configuration to .planning/forge.config.json
|
|
9
|
+
*/
|
|
10
|
+
export declare function saveConfig(config: ForgeConfig, projectRoot?: string): void;
|
|
11
|
+
/**
|
|
12
|
+
* Validate configuration values
|
|
13
|
+
*/
|
|
14
|
+
export declare function validateConfig(config: Partial<ForgeConfig>): string[];
|
|
15
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAkB,MAAM,mBAAmB,CAAC;AAIhE;;;GAGG;AACH,wBAAgB,UAAU,CAAC,WAAW,GAAE,MAAsB,GAAG,WAAW,CA8B3E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,GAAE,MAAsB,GAAG,IAAI,CAczF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,EAAE,CA4BrE"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { DEFAULT_CONFIG } from '../types/index.js';
|
|
4
|
+
const CONFIG_PATH = '.planning/forge.config.json';
|
|
5
|
+
/**
|
|
6
|
+
* Load FORGE configuration from .planning/forge.config.json
|
|
7
|
+
* Falls back to defaults if config doesn't exist
|
|
8
|
+
*/
|
|
9
|
+
export function loadConfig(projectRoot = process.cwd()) {
|
|
10
|
+
const configPath = path.join(projectRoot, CONFIG_PATH);
|
|
11
|
+
if (!fs.existsSync(configPath)) {
|
|
12
|
+
return DEFAULT_CONFIG;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const configContent = fs.readFileSync(configPath, 'utf-8');
|
|
16
|
+
const config = JSON.parse(configContent);
|
|
17
|
+
// Merge with defaults to ensure all fields exist
|
|
18
|
+
return {
|
|
19
|
+
mode: config.mode ?? DEFAULT_CONFIG.mode,
|
|
20
|
+
depth: config.depth ?? DEFAULT_CONFIG.depth,
|
|
21
|
+
maxTeammates: config.maxTeammates ?? DEFAULT_CONFIG.maxTeammates,
|
|
22
|
+
taskLimit: config.taskLimit ?? DEFAULT_CONFIG.taskLimit,
|
|
23
|
+
agentProfile: config.agentProfile ?? DEFAULT_CONFIG.agentProfile,
|
|
24
|
+
workflow: {
|
|
25
|
+
...DEFAULT_CONFIG.workflow,
|
|
26
|
+
...config.workflow,
|
|
27
|
+
},
|
|
28
|
+
git: {
|
|
29
|
+
...DEFAULT_CONFIG.git,
|
|
30
|
+
...config.git,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
throw new Error(`Failed to load config from ${configPath}: ${error}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Save FORGE configuration to .planning/forge.config.json
|
|
40
|
+
*/
|
|
41
|
+
export function saveConfig(config, projectRoot = process.cwd()) {
|
|
42
|
+
const configDir = path.join(projectRoot, '.planning');
|
|
43
|
+
const configPath = path.join(configDir, 'forge.config.json');
|
|
44
|
+
// Ensure .planning directory exists
|
|
45
|
+
if (!fs.existsSync(configDir)) {
|
|
46
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
throw new Error(`Failed to save config to ${configPath}: ${error}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Validate configuration values
|
|
57
|
+
*/
|
|
58
|
+
export function validateConfig(config) {
|
|
59
|
+
const errors = [];
|
|
60
|
+
if (config.mode && !['yolo', 'interactive'].includes(config.mode)) {
|
|
61
|
+
errors.push(`Invalid mode: ${config.mode}. Must be 'yolo' or 'interactive'.`);
|
|
62
|
+
}
|
|
63
|
+
if (config.depth && !['quick', 'standard', 'comprehensive'].includes(config.depth)) {
|
|
64
|
+
errors.push(`Invalid depth: ${config.depth}. Must be 'quick', 'standard', or 'comprehensive'.`);
|
|
65
|
+
}
|
|
66
|
+
if (config.maxTeammates !== undefined && (config.maxTeammates < 2 || config.maxTeammates > 6)) {
|
|
67
|
+
errors.push(`maxTeammates must be between 2 and 6. Got: ${config.maxTeammates}`);
|
|
68
|
+
}
|
|
69
|
+
if (config.taskLimit !== undefined && (config.taskLimit < 3 || config.taskLimit > 8)) {
|
|
70
|
+
errors.push(`taskLimit must be between 3 and 8. Got: ${config.taskLimit}`);
|
|
71
|
+
}
|
|
72
|
+
if (config.agentProfile && !['quality', 'balanced', 'budget'].includes(config.agentProfile)) {
|
|
73
|
+
errors.push(`Invalid agentProfile: ${config.agentProfile}. Must be 'quality', 'balanced', or 'budget'.`);
|
|
74
|
+
}
|
|
75
|
+
if (config.git?.strategy && !['none', 'worktree', 'branch'].includes(config.git.strategy)) {
|
|
76
|
+
errors.push(`Invalid git.strategy: ${config.git.strategy}. Must be 'none', 'worktree', or 'branch'.`);
|
|
77
|
+
}
|
|
78
|
+
return errors;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=config.js.map
|