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.
Files changed (140) hide show
  1. package/.claude/rules/api-patterns.md +98 -0
  2. package/.claude/rules/security-baseline.md +204 -0
  3. package/.claude/rules/testing-standards.md +177 -0
  4. package/.claude/rules/ui-conventions.md +142 -0
  5. package/README.md +261 -0
  6. package/bin/forge.js +14 -0
  7. package/dist/bin/forge.js +14 -0
  8. package/dist/cli/index.d.ts +22 -0
  9. package/dist/cli/index.d.ts.map +1 -0
  10. package/dist/cli/index.js +116 -0
  11. package/dist/cli/index.js.map +1 -0
  12. package/dist/commands/base.d.ts +31 -0
  13. package/dist/commands/base.d.ts.map +1 -0
  14. package/dist/commands/base.js +31 -0
  15. package/dist/commands/base.js.map +1 -0
  16. package/dist/commands/config.d.ts +14 -0
  17. package/dist/commands/config.d.ts.map +1 -0
  18. package/dist/commands/config.js +175 -0
  19. package/dist/commands/config.js.map +1 -0
  20. package/dist/commands/generate.d.ts +17 -0
  21. package/dist/commands/generate.d.ts.map +1 -0
  22. package/dist/commands/generate.js +159 -0
  23. package/dist/commands/generate.js.map +1 -0
  24. package/dist/commands/help.d.ts +11 -0
  25. package/dist/commands/help.d.ts.map +1 -0
  26. package/dist/commands/help.js +65 -0
  27. package/dist/commands/help.js.map +1 -0
  28. package/dist/commands/index.d.ts +8 -0
  29. package/dist/commands/index.d.ts.map +1 -0
  30. package/dist/commands/index.js +8 -0
  31. package/dist/commands/index.js.map +1 -0
  32. package/dist/commands/init.d.ts +10 -0
  33. package/dist/commands/init.d.ts.map +1 -0
  34. package/dist/commands/init.js +22 -0
  35. package/dist/commands/init.js.map +1 -0
  36. package/dist/commands/status.d.ts +13 -0
  37. package/dist/commands/status.d.ts.map +1 -0
  38. package/dist/commands/status.js +101 -0
  39. package/dist/commands/status.js.map +1 -0
  40. package/dist/commands/stubs.d.ts +14 -0
  41. package/dist/commands/stubs.d.ts.map +1 -0
  42. package/dist/commands/stubs.js +30 -0
  43. package/dist/commands/stubs.js.map +1 -0
  44. package/dist/generators/index.d.ts +11 -0
  45. package/dist/generators/index.d.ts.map +1 -0
  46. package/dist/generators/index.js +10 -0
  47. package/dist/generators/index.js.map +1 -0
  48. package/dist/generators/required-fields.d.ts +74 -0
  49. package/dist/generators/required-fields.d.ts.map +1 -0
  50. package/dist/generators/required-fields.js +179 -0
  51. package/dist/generators/required-fields.js.map +1 -0
  52. package/dist/generators/template-engine.d.ts +65 -0
  53. package/dist/generators/template-engine.d.ts.map +1 -0
  54. package/dist/generators/template-engine.js +209 -0
  55. package/dist/generators/template-engine.js.map +1 -0
  56. package/dist/generators/token-validator.d.ts +51 -0
  57. package/dist/generators/token-validator.d.ts.map +1 -0
  58. package/dist/generators/token-validator.js +141 -0
  59. package/dist/generators/token-validator.js.map +1 -0
  60. package/dist/generators/types.d.ts +433 -0
  61. package/dist/generators/types.d.ts.map +1 -0
  62. package/dist/generators/types.js +5 -0
  63. package/dist/generators/types.js.map +1 -0
  64. package/dist/generators/xml-task-generator.d.ts +67 -0
  65. package/dist/generators/xml-task-generator.d.ts.map +1 -0
  66. package/dist/generators/xml-task-generator.js +297 -0
  67. package/dist/generators/xml-task-generator.js.map +1 -0
  68. package/dist/git/__tests__/worktree.test.d.ts +5 -0
  69. package/dist/git/__tests__/worktree.test.d.ts.map +1 -0
  70. package/dist/git/__tests__/worktree.test.js +121 -0
  71. package/dist/git/__tests__/worktree.test.js.map +1 -0
  72. package/dist/git/codeowners.d.ts +101 -0
  73. package/dist/git/codeowners.d.ts.map +1 -0
  74. package/dist/git/codeowners.js +216 -0
  75. package/dist/git/codeowners.js.map +1 -0
  76. package/dist/git/commit.d.ts +135 -0
  77. package/dist/git/commit.d.ts.map +1 -0
  78. package/dist/git/commit.js +223 -0
  79. package/dist/git/commit.js.map +1 -0
  80. package/dist/git/hooks/commit-msg.d.ts +8 -0
  81. package/dist/git/hooks/commit-msg.d.ts.map +1 -0
  82. package/dist/git/hooks/commit-msg.js +34 -0
  83. package/dist/git/hooks/commit-msg.js.map +1 -0
  84. package/dist/git/hooks/pre-commit.d.ts +8 -0
  85. package/dist/git/hooks/pre-commit.d.ts.map +1 -0
  86. package/dist/git/hooks/pre-commit.js +34 -0
  87. package/dist/git/hooks/pre-commit.js.map +1 -0
  88. package/dist/git/pre-commit-hooks.d.ts +117 -0
  89. package/dist/git/pre-commit-hooks.d.ts.map +1 -0
  90. package/dist/git/pre-commit-hooks.js +270 -0
  91. package/dist/git/pre-commit-hooks.js.map +1 -0
  92. package/dist/git/wipe-protocol.d.ts +281 -0
  93. package/dist/git/wipe-protocol.d.ts.map +1 -0
  94. package/dist/git/wipe-protocol.js +237 -0
  95. package/dist/git/wipe-protocol.js.map +1 -0
  96. package/dist/git/worktree.d.ts +69 -0
  97. package/dist/git/worktree.d.ts.map +1 -0
  98. package/dist/git/worktree.js +202 -0
  99. package/dist/git/worktree.js.map +1 -0
  100. package/dist/scripts/install.d.ts +8 -0
  101. package/dist/scripts/install.d.ts.map +1 -0
  102. package/dist/scripts/install.js +161 -0
  103. package/dist/scripts/install.js.map +1 -0
  104. package/dist/types/config.d.ts +30 -0
  105. package/dist/types/config.d.ts.map +1 -0
  106. package/dist/types/config.js +23 -0
  107. package/dist/types/config.js.map +1 -0
  108. package/dist/types/index.d.ts +6 -0
  109. package/dist/types/index.d.ts.map +1 -0
  110. package/dist/types/index.js +6 -0
  111. package/dist/types/index.js.map +1 -0
  112. package/dist/types/state.d.ts +56 -0
  113. package/dist/types/state.d.ts.map +1 -0
  114. package/dist/types/state.js +6 -0
  115. package/dist/types/state.js.map +1 -0
  116. package/dist/utils/config.d.ts +15 -0
  117. package/dist/utils/config.d.ts.map +1 -0
  118. package/dist/utils/config.js +80 -0
  119. package/dist/utils/config.js.map +1 -0
  120. package/dist/utils/errors.d.ts +25 -0
  121. package/dist/utils/errors.d.ts.map +1 -0
  122. package/dist/utils/errors.js +48 -0
  123. package/dist/utils/errors.js.map +1 -0
  124. package/dist/utils/index.d.ts +11 -0
  125. package/dist/utils/index.d.ts.map +1 -0
  126. package/dist/utils/index.js +9 -0
  127. package/dist/utils/index.js.map +1 -0
  128. package/dist/utils/logger.d.ts +34 -0
  129. package/dist/utils/logger.d.ts.map +1 -0
  130. package/dist/utils/logger.js +73 -0
  131. package/dist/utils/logger.js.map +1 -0
  132. package/dist/utils/state-api.d.ts +128 -0
  133. package/dist/utils/state-api.d.ts.map +1 -0
  134. package/dist/utils/state-api.js +170 -0
  135. package/dist/utils/state-api.js.map +1 -0
  136. package/dist/utils/template-client.d.ts +73 -0
  137. package/dist/utils/template-client.d.ts.map +1 -0
  138. package/dist/utils/template-client.js +151 -0
  139. package/dist/utils/template-client.js.map +1 -0
  140. package/package.json +72 -0
@@ -0,0 +1,297 @@
1
+ /**
2
+ * XML Task Spec Generator
3
+ *
4
+ * Generates XML-formatted task specifications as defined in FORGE Phase II: Plan
5
+ * Each task includes: id, type, owner, name, deps, files, contracts, action, acceptance, verify
6
+ */
7
+ /**
8
+ * XML Task Spec Generator class
9
+ */
10
+ export class XmlTaskGenerator {
11
+ /**
12
+ * Generate a single task spec in XML format
13
+ */
14
+ static generateTask(task) {
15
+ const lines = [];
16
+ lines.push(`<task id="${task.id}" type="${task.type}" owner="${task.owner}">`);
17
+ // Name (required)
18
+ lines.push(` <name>${this.escapeXml(task.name)}</name>`);
19
+ // Dependencies (optional)
20
+ if (task.deps) {
21
+ lines.push(` <deps>${task.deps}</deps>`);
22
+ }
23
+ // Files (optional)
24
+ if (task.files) {
25
+ lines.push(` <files>${task.files}</files>`);
26
+ }
27
+ // Contracts (optional)
28
+ if (task.contracts) {
29
+ lines.push(` <contracts>${task.contracts}</contracts>`);
30
+ }
31
+ // Action (required)
32
+ lines.push(' <action>');
33
+ lines.push(this.indentText(task.action, 4));
34
+ lines.push(' </action>');
35
+ // Acceptance criteria (required, array)
36
+ lines.push(' <acceptance>');
37
+ for (const criterion of task.acceptance) {
38
+ lines.push(` ${this.escapeXml(criterion)}`);
39
+ }
40
+ lines.push(' </acceptance>');
41
+ // Verification command (required)
42
+ lines.push(` <verify>${this.escapeXml(task.verify)}</verify>`);
43
+ lines.push('</task>');
44
+ return lines.join('\n');
45
+ }
46
+ /**
47
+ * Generate multiple task specs
48
+ */
49
+ static generateTasks(tasks) {
50
+ const lines = [
51
+ '<!--',
52
+ ' FORGE Task Specifications',
53
+ ` Generated: ${new Date().toISOString()}`,
54
+ ' Total Tasks: ' + tasks.length,
55
+ '-->',
56
+ '',
57
+ ];
58
+ for (const task of tasks) {
59
+ lines.push(this.generateTask(task));
60
+ lines.push('');
61
+ }
62
+ return lines.join('\n');
63
+ }
64
+ /**
65
+ * Generate task spec with XML declaration
66
+ */
67
+ static generateTaskWithHeader(task) {
68
+ return [
69
+ '<?xml version="1.0" encoding="UTF-8"?>',
70
+ '<!--',
71
+ ' FORGE Task Specification',
72
+ ` Generated: ${new Date().toISOString()}`,
73
+ '-->',
74
+ '',
75
+ this.generateTask(task),
76
+ ].join('\n');
77
+ }
78
+ /**
79
+ * Parse a task spec from XML format
80
+ */
81
+ static parseTask(xmlString) {
82
+ // Simple XML parser for task specs
83
+ // Note: This is a basic parser. For production, use a proper XML parser
84
+ const task = {};
85
+ // Extract task attributes
86
+ const taskMatch = xmlString.match(/<task\s+([^>]+)>/);
87
+ if (taskMatch) {
88
+ const attrs = taskMatch[1];
89
+ const idMatch = attrs.match(/id="([^"]+)"/);
90
+ const typeMatch = attrs.match(/type="([^"]+)"/);
91
+ const ownerMatch = attrs.match(/owner="([^"]+)"/);
92
+ if (idMatch)
93
+ task.id = idMatch[1];
94
+ if (typeMatch)
95
+ task.type = typeMatch[1];
96
+ if (ownerMatch)
97
+ task.owner = ownerMatch[1];
98
+ }
99
+ // Extract elements
100
+ const nameMatch = xmlString.match(/<name>([^<]+)<\/name>/);
101
+ if (nameMatch)
102
+ task.name = this.unescapeXml(nameMatch[1]);
103
+ const depsMatch = xmlString.match(/<deps>([^<]+)<\/deps>/);
104
+ if (depsMatch)
105
+ task.deps = this.unescapeXml(depsMatch[1]);
106
+ const filesMatch = xmlString.match(/<files>([^<]+)<\/files>/);
107
+ if (filesMatch)
108
+ task.files = this.unescapeXml(filesMatch[1]);
109
+ const contractsMatch = xmlString.match(/<contracts>([^<]+)<\/contracts>/);
110
+ if (contractsMatch)
111
+ task.contracts = this.unescapeXml(contractsMatch[1]);
112
+ const actionMatch = xmlString.match(/<action>\s*(.+?)\s*<\/action>/s);
113
+ if (actionMatch)
114
+ task.action = this.unescapeXml(actionMatch[1].trim());
115
+ const verifyMatch = xmlString.match(/<verify>([^<]+)<\/verify>/);
116
+ if (verifyMatch)
117
+ task.verify = this.unescapeXml(verifyMatch[1]);
118
+ // Extract acceptance criteria (multiple lines)
119
+ const acceptanceMatch = xmlString.match(/<acceptance>([\s\S]+?)<\/acceptance>/);
120
+ if (acceptanceMatch) {
121
+ const acceptanceLines = acceptanceMatch[1]
122
+ .split('\n')
123
+ .map((line) => line.trim())
124
+ .filter((line) => line.length > 0 && !line.startsWith('<'))
125
+ .map((line) => this.unescapeXml(line));
126
+ task.acceptance = acceptanceLines;
127
+ }
128
+ // Validate required fields
129
+ if (!task.id || !task.type || !task.owner || !task.name || !task.action || !task.acceptance || !task.verify) {
130
+ throw new Error('Invalid task spec: missing required fields');
131
+ }
132
+ return task;
133
+ }
134
+ /**
135
+ * Validate a task spec structure
136
+ */
137
+ static validateTask(task) {
138
+ const errors = [];
139
+ // Required fields
140
+ if (!task.id) {
141
+ errors.push('Missing required field: id');
142
+ }
143
+ else if (!/^[a-z]+-\d{3}$/.test(task.id)) {
144
+ errors.push('Task ID must follow pattern: {prefix}-{number}, e.g., api-003');
145
+ }
146
+ if (!task.type) {
147
+ errors.push('Missing required field: type');
148
+ }
149
+ else if (!['auto', 'manual'].includes(task.type)) {
150
+ errors.push('Task type must be "auto" or "manual"');
151
+ }
152
+ if (!task.owner) {
153
+ errors.push('Missing required field: owner');
154
+ }
155
+ if (!task.name) {
156
+ errors.push('Missing required field: name');
157
+ }
158
+ else if (task.name.length > 100) {
159
+ errors.push('Task name must be less than 100 characters');
160
+ }
161
+ if (!task.action) {
162
+ errors.push('Missing required field: action');
163
+ }
164
+ else if (task.action.length > 2000) {
165
+ errors.push('Task action must be less than 2000 characters');
166
+ }
167
+ if (!task.acceptance || task.acceptance.length === 0) {
168
+ errors.push('Missing required field: acceptance (must have at least one criterion)');
169
+ }
170
+ else if (task.acceptance.length > 10) {
171
+ errors.push('Task acceptance criteria must not exceed 10 items');
172
+ }
173
+ if (!task.verify) {
174
+ errors.push('Missing required field: verify');
175
+ }
176
+ // Optional fields validation
177
+ if (task.deps && task.deps.length > 200) {
178
+ errors.push('Task dependencies must be less than 200 characters');
179
+ }
180
+ if (task.files && task.files.length > 500) {
181
+ errors.push('Task files must be less than 500 characters');
182
+ }
183
+ if (task.contracts && task.contracts.length > 200) {
184
+ errors.push('Task contracts must be less than 200 characters');
185
+ }
186
+ return {
187
+ valid: errors.length === 0,
188
+ errors,
189
+ };
190
+ }
191
+ /**
192
+ * Escape XML special characters
193
+ */
194
+ static escapeXml(text) {
195
+ return text
196
+ .replace(/&/g, '&amp;')
197
+ .replace(/</g, '&lt;')
198
+ .replace(/>/g, '&gt;')
199
+ .replace(/"/g, '&quot;')
200
+ .replace(/'/g, '&apos;');
201
+ }
202
+ /**
203
+ * Unescape XML special characters
204
+ */
205
+ static unescapeXml(text) {
206
+ return text
207
+ .replace(/&apos;/g, "'")
208
+ .replace(/&quot;/g, '"')
209
+ .replace(/&gt;/g, '>')
210
+ .replace(/&lt;/g, '<')
211
+ .replace(/&amp;/g, '&');
212
+ }
213
+ /**
214
+ * Indent text for XML formatting
215
+ */
216
+ static indentText(text, spaces) {
217
+ const indent = ' '.repeat(spaces);
218
+ return text
219
+ .split('\n')
220
+ .map((line) => indent + line)
221
+ .join('\n');
222
+ }
223
+ /**
224
+ * Create a task spec from a simple object
225
+ */
226
+ static createTask(data) {
227
+ return {
228
+ id: data.id,
229
+ type: data.type,
230
+ owner: data.owner,
231
+ name: data.name,
232
+ deps: data.deps,
233
+ files: data.files,
234
+ contracts: data.contracts,
235
+ action: data.action,
236
+ acceptance: data.acceptance,
237
+ verify: data.verify,
238
+ };
239
+ }
240
+ /**
241
+ * Generate example task specs for reference
242
+ */
243
+ static generateExamples() {
244
+ const examples = [
245
+ {
246
+ id: 'api-003',
247
+ type: 'auto',
248
+ owner: 'backend',
249
+ name: 'Create session authentication endpoint',
250
+ deps: 'api-001, core-002',
251
+ files: 'src/api/auth/sessions.ts, src/api/middleware/auth.ts',
252
+ contracts: 'contracts/auth.openapi.yaml',
253
+ action: `Implement POST /v1/sessions using jose for JWT.
254
+ Validate credentials against users table.
255
+ Return httpOnly cookie with configurable expiry.
256
+ Rate limit: 5 attempts per minute per IP.`,
257
+ acceptance: [
258
+ 'Given valid credentials, POST /v1/sessions returns 200 + Set-Cookie',
259
+ 'Given invalid credentials, returns 401 with generic error',
260
+ 'Given 6th attempt in 1 minute, returns 429',
261
+ ],
262
+ verify: 'npm test -- --grep "session auth"',
263
+ },
264
+ {
265
+ id: 'ui-002',
266
+ type: 'auto',
267
+ owner: 'frontend',
268
+ name: 'Implement login form with validation',
269
+ deps: 'ui-001',
270
+ files: 'src/ui/components/LoginForm.tsx, src/ui/hooks/useAuth.ts',
271
+ contracts: 'contracts/auth.openapi.yaml',
272
+ action: `Create login form component with email/password fields.
273
+ Implement client-side validation.
274
+ Show loading states during submission.
275
+ Display inline error messages.
276
+ Redirect to dashboard on successful login.`,
277
+ acceptance: [
278
+ 'Given user enters invalid email, show inline validation error',
279
+ 'Given user submits valid credentials, redirect to dashboard',
280
+ 'Given login fails, display error message from API',
281
+ 'Given form is submitting, disable submit button and show spinner',
282
+ ],
283
+ verify: 'npm test -- --grep "LoginForm"',
284
+ },
285
+ ];
286
+ return [
287
+ '<?xml version="1.0" encoding="UTF-8"?>',
288
+ '<!--',
289
+ ' FORGE Task Specification Examples',
290
+ ` Generated: ${new Date().toISOString()}`,
291
+ '-->',
292
+ '',
293
+ ...examples.map((task) => this.generateTask(task)),
294
+ ].join('\n\n');
295
+ }
296
+ }
297
+ //# sourceMappingURL=xml-task-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xml-task-generator.js","sourceRoot":"","sources":["../../src/generators/xml-task-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for Git Worktree Management
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=worktree.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.test.d.ts","sourceRoot":"","sources":["../../../src/git/__tests__/worktree.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Tests for Git Worktree Management
3
+ */
4
+ import { describe, it, before, after } from "node:test";
5
+ import assert from "node/assert";
6
+ import { execa } from "execa";
7
+ import { createWorktree, getWorktree, mergeWorktree, cleanupWorktree, listWorktrees, WorktreeError, } from "../worktree.js";
8
+ describe("Git Worktree Management", () => {
9
+ const testTaskId = "test-task-001";
10
+ const testBaseBranch = "main";
11
+ before(async () => {
12
+ // Initialize a test git repository if needed
13
+ try {
14
+ await execa("git", ["status"]);
15
+ }
16
+ catch {
17
+ // Not in a git repo, skip tests
18
+ console.log("Not in a git repository, skipping worktree tests");
19
+ }
20
+ });
21
+ describe("createWorktree", () => {
22
+ it("should create a new worktree with branch forge/{taskId}", async () => {
23
+ const result = await createWorktree({ taskId: testTaskId });
24
+ assert.ok(result.includes(".worktrees"));
25
+ assert.ok(result.includes(testTaskId));
26
+ });
27
+ it("should use custom branch name if provided", async () => {
28
+ const customBranch = "custom-branch";
29
+ const result = await createWorktree({
30
+ taskId: "custom-task",
31
+ branchName: customBranch,
32
+ });
33
+ assert.ok(result.includes("custom-task"));
34
+ });
35
+ it("should throw WorktreeError on failure", async () => {
36
+ try {
37
+ // Try to create duplicate worktree
38
+ await createWorktree({ taskId: testTaskId });
39
+ assert.fail("Should have thrown WorktreeError");
40
+ }
41
+ catch (error) {
42
+ assert.ok(error instanceof WorktreeError);
43
+ }
44
+ });
45
+ });
46
+ describe("getWorktree", () => {
47
+ it("should return worktree info for existing task", async () => {
48
+ const info = await getWorktree(testTaskId);
49
+ assert.ok(info);
50
+ assert.equal(info.taskId, testTaskId);
51
+ assert.ok(info.branchName);
52
+ assert.ok(info.path);
53
+ assert.ok(info.commit);
54
+ });
55
+ it("should return null for non-existent task", async () => {
56
+ const info = await getWorktree("non-existent-task");
57
+ assert.equal(info, null);
58
+ });
59
+ });
60
+ describe("listWorktrees", () => {
61
+ it("should return array of worktree info", async () => {
62
+ const worktrees = await listWorktrees();
63
+ assert.ok(Array.isArray(worktrees));
64
+ assert.ok(worktrees.length > 0);
65
+ assert.ok(worktrees.some((w) => w.taskId === testTaskId));
66
+ });
67
+ it("should only include FORGE worktrees (.worktrees/)", async () => {
68
+ const worktrees = await listWorktrees();
69
+ for (const worktree of worktrees) {
70
+ assert.ok(worktree.path.includes(".worktrees"));
71
+ }
72
+ });
73
+ });
74
+ describe("cleanupWorktree", () => {
75
+ it("should remove an existing worktree", async () => {
76
+ await cleanupWorktree(testTaskId);
77
+ const info = await getWorktree(testTaskId);
78
+ assert.equal(info, null);
79
+ });
80
+ it("should not error when cleaning up non-existent worktree", async () => {
81
+ // Should not throw
82
+ await cleanupWorktree("non-existent-task");
83
+ });
84
+ });
85
+ describe("mergeWorktree", () => {
86
+ it("should merge worktree branch into target branch", async () => {
87
+ // Create a test worktree
88
+ const taskId = "merge-test-001";
89
+ await createWorktree({ taskId });
90
+ // Make a change in the worktree
91
+ // (This would require file operations, simplified here)
92
+ // Merge the worktree
93
+ try {
94
+ await mergeWorktree(taskId, "main");
95
+ }
96
+ catch (error) {
97
+ // Merge might fail if no changes or conflicts, that's ok for test
98
+ assert.ok(error instanceof WorktreeError);
99
+ }
100
+ // Cleanup
101
+ await cleanupWorktree(taskId);
102
+ });
103
+ it("should throw WorktreeError for non-existent worktree", async () => {
104
+ try {
105
+ await mergeWorktree("non-existent-task");
106
+ assert.fail("Should have thrown WorktreeError");
107
+ }
108
+ catch (error) {
109
+ assert.ok(error instanceof WorktreeError);
110
+ }
111
+ });
112
+ });
113
+ after(async () => {
114
+ // Clean up test worktrees
115
+ try {
116
+ await cleanupWorktree(testTaskId);
117
+ }
118
+ catch { }
119
+ });
120
+ });
121
+ //# sourceMappingURL=worktree.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.test.js","sourceRoot":"","sources":["../../../src/git/__tests__/worktree.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Generate .github/CODEOWNERS from task ownership maps.
3
+ *
4
+ * The CODEOWNERS file defines canonical ownership for code paths.
5
+ * GitHub enforces this at merge time - changes require owner approval.
6
+ *
7
+ * Generated format:
8
+ * # Auto-generated by FORGE
9
+ * src/api/** @backend-agent
10
+ * src/ui/** @frontend-agent
11
+ * src/tests/** @qa-agent
12
+ * docs/** @docs-agent
13
+ */
14
+ export interface TaskOwnership {
15
+ id: string;
16
+ ownerRole: string;
17
+ allowedPaths: string[];
18
+ }
19
+ export interface StateForCodeowners {
20
+ tasks: TaskOwnership[];
21
+ }
22
+ /**
23
+ * Generate CODEOWNERS content from task ownership.
24
+ *
25
+ * Aggregates allowedPaths by owner role and formats for GitHub.
26
+ *
27
+ * @param state - FORGE state with task ownership
28
+ * @returns CODEOWNERS file content
29
+ */
30
+ export declare function generateCodeownersContent(state: StateForCodeowners): string;
31
+ /**
32
+ * Write CODEOWNERS file to disk.
33
+ *
34
+ * @param state - FORGE state with task ownership
35
+ * @param basePath - Root of the FORGE project
36
+ * @param forceOverwrite - Whether to overwrite existing file
37
+ * @throws Error if file exists and forceOverwrite is false
38
+ */
39
+ export declare function writeCodeowners(state: StateForCodeowners, basePath?: string, forceOverwrite?: boolean): Promise<void>;
40
+ /**
41
+ * Parse existing CODEOWNERS file.
42
+ *
43
+ * Useful for validating or diffing against generated content.
44
+ *
45
+ * @param content - CODEOWNERS file content
46
+ * @returns Parsed entries
47
+ */
48
+ export interface CodeownersEntry {
49
+ pattern: string;
50
+ owner: string;
51
+ }
52
+ export declare function parseCodeowners(content: string): CodeownersEntry[];
53
+ /**
54
+ * Validate CODEOWNERS entries.
55
+ *
56
+ * Checks for:
57
+ * - Overlapping patterns (conflicting ownership)
58
+ * - Invalid patterns
59
+ * - Missing owners
60
+ *
61
+ * @param entries - Parsed CODEOWNERS entries
62
+ * @returns Validation result with errors
63
+ */
64
+ export interface ValidationError {
65
+ type: "overlap" | "invalid-pattern" | "missing-owner";
66
+ message: string;
67
+ entries?: CodeownersEntry[];
68
+ }
69
+ export declare function validateCodeowners(entries: CodeownersEntry[]): {
70
+ isValid: boolean;
71
+ errors: ValidationError[];
72
+ };
73
+ /**
74
+ * Diff two CODEOWNERS configurations.
75
+ *
76
+ * Useful for showing what would change before regenerating.
77
+ *
78
+ * @param current - Current CODEOWNERS content
79
+ * @param proposed - Proposed CODEOWNERS content
80
+ * @returns Diff with additions, removals, and changes
81
+ */
82
+ export interface CodeownersDiff {
83
+ added: CodeownersEntry[];
84
+ removed: CodeownersEntry[];
85
+ changed: Array<{
86
+ from: CodeownersEntry;
87
+ to: CodeownersEntry;
88
+ }>;
89
+ }
90
+ export declare function diffCodeowners(current: string, proposed: string): CodeownersDiff;
91
+ /**
92
+ * Generate CODEOWNERS from STATE.json file.
93
+ *
94
+ * This is the main entry point for CODEOWNERS generation.
95
+ *
96
+ * @param stateJsonPath - Path to STATE.json
97
+ * @param basePath - Root of the FORGE project
98
+ * @param forceOverwrite - Whether to overwrite existing file
99
+ */
100
+ export declare function generateCodeownersFromState(stateJsonPath: string, basePath?: string, forceOverwrite?: boolean): Promise<void>;
101
+ //# sourceMappingURL=codeowners.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codeowners.d.ts","sourceRoot":"","sources":["../../src/git/codeowners.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAcD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CA+C3E;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,kBAAkB,EACzB,QAAQ,GAAE,MAAoC,EAC9C,cAAc,GAAE,OAAe,GAC9B,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,EAAE,CAqBlE;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,GAAG,iBAAiB,GAAG,eAAe,CAAC;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG;IAC9D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B,CA8CA;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,eAAe,CAAC;QAAC,EAAE,EAAE,eAAe,CAAA;KAAE,CAAC,CAAC;CAChE;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAuDhF;AAED;;;;;;;;GAQG;AACH,wBAAsB,2BAA2B,CAC/C,aAAa,EAAE,MAAM,EACrB,QAAQ,GAAE,MAAoC,EAC9C,cAAc,GAAE,OAAe,GAC9B,OAAO,CAAC,IAAI,CAAC,CAMf"}