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,216 @@
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
+ import { writeFile, mkdir } from "node:fs/promises";
15
+ import { join } from "node:path";
16
+ // Role to GitHub username/team mapping
17
+ // In production, this would come from config
18
+ const ROLE_TO_OWNER = {
19
+ backend: "@backend-agent",
20
+ frontend: "@frontend-agent",
21
+ qa: "@qa-agent",
22
+ docs: "@docs-agent",
23
+ devops: "@devops-agent",
24
+ architect: "@architect",
25
+ "team-lead": "@team-lead",
26
+ };
27
+ /**
28
+ * Generate CODEOWNERS content from task ownership.
29
+ *
30
+ * Aggregates allowedPaths by owner role and formats for GitHub.
31
+ *
32
+ * @param state - FORGE state with task ownership
33
+ * @returns CODEOWNERS file content
34
+ */
35
+ export function generateCodeownersContent(state) {
36
+ const lines = [];
37
+ // Header
38
+ lines.push("# Auto-generated by FORGE");
39
+ lines.push("# DO NOT EDIT MANually - Regenerate with forge generate-codeowners");
40
+ lines.push("");
41
+ // Aggregate paths by owner role
42
+ const pathsByOwner = new Map();
43
+ for (const task of state.tasks) {
44
+ const owner = ROLE_TO_OWNER[task.ownerRole] || `@${task.ownerRole}`;
45
+ if (!pathsByOwner.has(owner)) {
46
+ pathsByOwner.set(owner, new Set());
47
+ }
48
+ const ownerPaths = pathsByOwner.get(owner);
49
+ for (const path of task.allowedPaths) {
50
+ ownerPaths.add(path);
51
+ }
52
+ }
53
+ // Format: sorted by owner, then by path
54
+ const sortedOwners = Array.from(pathsByOwner.entries()).sort((a, b) => a[0].localeCompare(b[0]));
55
+ for (const [owner, paths] of sortedOwners) {
56
+ // Sort paths for consistency
57
+ const sortedPaths = Array.from(paths).sort();
58
+ for (const path of sortedPaths) {
59
+ // Ensure path is in gitignore-style format
60
+ const gitPath = path.startsWith("/") ? path.slice(1) : path;
61
+ lines.push(`${gitPath} ${owner}`);
62
+ }
63
+ lines.push(""); // Blank line between owners
64
+ }
65
+ // Add default fallback (team-lead owns everything else)
66
+ lines.push(`# Default fallback`);
67
+ lines.push(`* ${ROLE_TO_OWNER["team-lead"] || "@team-lead"}`);
68
+ return lines.join("\n");
69
+ }
70
+ /**
71
+ * Write CODEOWNERS file to disk.
72
+ *
73
+ * @param state - FORGE state with task ownership
74
+ * @param basePath - Root of the FORGE project
75
+ * @param forceOverwrite - Whether to overwrite existing file
76
+ * @throws Error if file exists and forceOverwrite is false
77
+ */
78
+ export async function writeCodeowners(state, basePath = "/home/parz/projects/forge", forceOverwrite = false) {
79
+ const codeownersPath = join(basePath, ".github", "CODEOWNERS");
80
+ // Check if file exists
81
+ try {
82
+ await writeFile(codeownersPath, "", { flag: "rx" });
83
+ if (!forceOverwrite) {
84
+ throw new Error("CODEOWNERS file already exists. Use forceOverwrite=true to replace it.");
85
+ }
86
+ }
87
+ catch {
88
+ // File doesn't exist, which is fine
89
+ }
90
+ // Ensure .github directory exists
91
+ await mkdir(join(basePath, ".github"), { recursive: true });
92
+ // Generate content
93
+ const content = generateCodeownersContent(state);
94
+ // Write file
95
+ await writeFile(codeownersPath, content, "utf-8");
96
+ }
97
+ export function parseCodeowners(content) {
98
+ const entries = [];
99
+ const lines = content.split("\n");
100
+ for (const line of lines) {
101
+ const trimmed = line.trim();
102
+ // Skip comments and empty lines
103
+ if (!trimmed || trimmed.startsWith("#")) {
104
+ continue;
105
+ }
106
+ // Parse "pattern owner"
107
+ const parts = trimmed.split(/\s+/);
108
+ if (parts.length >= 2) {
109
+ const [pattern, owner] = parts;
110
+ entries.push({ pattern, owner });
111
+ }
112
+ }
113
+ return entries;
114
+ }
115
+ export function validateCodeowners(entries) {
116
+ const errors = [];
117
+ // Check for invalid patterns (basic validation)
118
+ for (const entry of entries) {
119
+ try {
120
+ // Convert gitignore pattern to regex for basic validation
121
+ const regexPattern = entry.pattern
122
+ .replace(/\*\*/g, ".*")
123
+ .replace(/\*/g, "[^/]*")
124
+ .replace(/\?/g, "[^/]");
125
+ new RegExp(regexPattern);
126
+ }
127
+ catch {
128
+ errors.push({
129
+ type: "invalid-pattern",
130
+ message: `Invalid pattern: ${entry.pattern}`,
131
+ entries: [entry],
132
+ });
133
+ }
134
+ // Check for missing owner
135
+ if (!entry.owner || !entry.owner.startsWith("@")) {
136
+ errors.push({
137
+ type: "missing-owner",
138
+ message: `Missing or invalid owner for pattern: ${entry.pattern}`,
139
+ entries: [entry],
140
+ });
141
+ }
142
+ }
143
+ // Check for overlapping patterns (same file owned by different roles)
144
+ // This is a simplified check - real validation would need path matching
145
+ const byOwner = new Map();
146
+ for (const entry of entries) {
147
+ if (!byOwner.has(entry.owner)) {
148
+ byOwner.set(entry.owner, []);
149
+ }
150
+ byOwner.get(entry.owner).push(entry.pattern);
151
+ }
152
+ // TODO: Add sophisticated overlap detection
153
+ return {
154
+ isValid: errors.length === 0,
155
+ errors,
156
+ };
157
+ }
158
+ export function diffCodeowners(current, proposed) {
159
+ const currentEntries = parseCodeowners(current);
160
+ const proposedEntries = parseCodeowners(proposed);
161
+ // Create maps for easy comparison
162
+ const currentMap = new Map();
163
+ const proposedMap = new Map();
164
+ for (const entry of currentEntries) {
165
+ const key = `${entry.pattern}|${entry.owner}`;
166
+ currentMap.set(key, entry);
167
+ }
168
+ for (const entry of proposedEntries) {
169
+ const key = `${entry.pattern}|${entry.owner}`;
170
+ proposedMap.set(key, entry);
171
+ }
172
+ // Find differences
173
+ const added = [];
174
+ const removed = [];
175
+ const changed = [];
176
+ // Check for removed and changed entries
177
+ for (const [key, entry] of currentMap) {
178
+ const pattern = entry.pattern;
179
+ // Find if this pattern exists in proposed with different owner
180
+ const proposedWithSamePattern = Array.from(proposedMap.values()).find((e) => e.pattern === pattern);
181
+ if (!proposedWithSamePattern) {
182
+ removed.push(entry);
183
+ }
184
+ else if (proposedWithSamePattern.owner !== entry.owner) {
185
+ changed.push({ from: entry, to: proposedWithSamePattern });
186
+ }
187
+ }
188
+ // Check for added entries
189
+ for (const [key, entry] of proposedMap) {
190
+ if (!currentMap.has(key)) {
191
+ const pattern = entry.pattern;
192
+ const currentWithSamePattern = Array.from(currentMap.values()).find((e) => e.pattern === pattern);
193
+ // Only add if it's truly new, not a change (already captured above)
194
+ if (!currentWithSamePattern) {
195
+ added.push(entry);
196
+ }
197
+ }
198
+ }
199
+ return { added, removed, changed };
200
+ }
201
+ /**
202
+ * Generate CODEOWNERS from STATE.json file.
203
+ *
204
+ * This is the main entry point for CODEOWNERS generation.
205
+ *
206
+ * @param stateJsonPath - Path to STATE.json
207
+ * @param basePath - Root of the FORGE project
208
+ * @param forceOverwrite - Whether to overwrite existing file
209
+ */
210
+ export async function generateCodeownersFromState(stateJsonPath, basePath = "/home/parz/projects/forge", forceOverwrite = false) {
211
+ const { readFile } = await import("node:fs/promises");
212
+ const stateRaw = await readFile(stateJsonPath, "utf-8");
213
+ const state = JSON.parse(stateRaw);
214
+ await writeCodeowners(state, basePath, forceOverwrite);
215
+ }
216
+ //# sourceMappingURL=codeowners.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codeowners.js","sourceRoot":"","sources":["../../src/git/codeowners.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Atomic Commit Enforcement for FORGE
3
+ *
4
+ * Enforces conventional commit format with task ID in scope:
5
+ * type(scope): description
6
+ *
7
+ * Examples:
8
+ * - feat(api-003): implement session authentication
9
+ * - fix(ui-002): resolve login form validation bug
10
+ * - test(core-001): add database integration tests
11
+ * - docs(readme): update installation instructions
12
+ *
13
+ * Rules:
14
+ * - Every task = one commit
15
+ * - Commit message MUST include task ID in scope
16
+ * - Pre-commit hooks validate format
17
+ * - Reject commits that don't match pattern
18
+ */
19
+ import { z } from "zod";
20
+ export declare const CommitType: z.ZodEnum<["feat", "fix", "docs", "style", "refactor", "perf", "test", "chore", "revert"]>;
21
+ export type CommitType = z.infer<typeof CommitType>;
22
+ export declare class CommitFormatError extends Error {
23
+ readonly commitMessage: string;
24
+ constructor(message: string, commitMessage: string);
25
+ }
26
+ /**
27
+ * Parsed commit message components.
28
+ */
29
+ export interface ParsedCommit {
30
+ type: CommitType;
31
+ scope: string;
32
+ description: string;
33
+ }
34
+ /**
35
+ * Parse a commit message into its components.
36
+ *
37
+ * @param message - The commit message to parse
38
+ * @returns Parsed commit components
39
+ * @throws CommitFormatError if format is invalid
40
+ */
41
+ export declare function parseCommitMessage(message: string): ParsedCommit;
42
+ /**
43
+ * Format a commit message from components.
44
+ *
45
+ * @param type - Commit type
46
+ * @param scope - Task ID (e.g., api-003)
47
+ * @param description - Commit description
48
+ * @returns Formatted commit message
49
+ */
50
+ export declare function formatCommitMessage(type: CommitType, scope: string, description: string): string;
51
+ /**
52
+ * Validate a commit message against FORGE standards.
53
+ *
54
+ * @param message - The commit message to validate
55
+ * @returns True if valid
56
+ * @throws CommitFormatError if invalid
57
+ */
58
+ export declare function validateCommitMessage(message: string): boolean;
59
+ /**
60
+ * Check if a commit message is for a specific task.
61
+ *
62
+ * @param message - The commit message
63
+ * @param taskId - The task ID to check
64
+ * @returns True if the commit is for the specified task
65
+ */
66
+ export declare function isCommitForTask(message: string, taskId: string): boolean;
67
+ /**
68
+ * Extract task ID from a commit message.
69
+ *
70
+ * @param message - The commit message
71
+ * @returns Task ID or null if format is invalid
72
+ */
73
+ export declare function extractTaskId(message: string): string | null;
74
+ /**
75
+ * Commit message options for formatting.
76
+ */
77
+ export interface CommitMessageOptions {
78
+ type: CommitType;
79
+ taskId: string;
80
+ description: string;
81
+ body?: string;
82
+ footer?: string;
83
+ }
84
+ /**
85
+ * Create a full commit message with optional body and footer.
86
+ *
87
+ * @param options - Commit message components
88
+ * @returns Formatted commit message
89
+ */
90
+ export declare function createCommitMessage(options: CommitMessageOptions): string;
91
+ /**
92
+ * Batch validate multiple commit messages.
93
+ *
94
+ * Useful for pre-commit hooks that check all staged commits.
95
+ *
96
+ * @param messages - Array of commit messages
97
+ * @returns Object with validation results
98
+ */
99
+ export declare function validateCommitMessages(messages: string[]): {
100
+ valid: boolean;
101
+ errors: Array<{
102
+ message: string;
103
+ error: string;
104
+ }>;
105
+ };
106
+ /**
107
+ * Generate a commit message from task information.
108
+ *
109
+ * This is a helper for agents to generate properly formatted commits.
110
+ *
111
+ * @param taskId - The task ID
112
+ * @param taskTitle - The task title (will be converted to description)
113
+ * @param type - Commit type (defaults to "feat")
114
+ * @returns Formatted commit message
115
+ */
116
+ export declare function generateCommitFromTask(taskId: string, taskTitle: string, type?: CommitType): string;
117
+ /**
118
+ * Commit validation result for pre-commit hooks.
119
+ */
120
+ export interface CommitValidationResult {
121
+ isValid: boolean;
122
+ taskId: string | null;
123
+ errors: string[];
124
+ }
125
+ /**
126
+ * Validate a commit for pre-commit hook usage.
127
+ *
128
+ * This is the main entry point for pre-commit hooks.
129
+ *
130
+ * @param message - The commit message to validate
131
+ * @param expectedTaskId - Optional expected task ID
132
+ * @returns Validation result
133
+ */
134
+ export declare function validateForPreCommit(message: string, expectedTaskId?: string): CommitValidationResult;
135
+ //# sourceMappingURL=commit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit.d.ts","sourceRoot":"","sources":["../../src/git/commit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,UAAU,4FAUrB,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAMpD,qBAAa,iBAAkB,SAAQ,KAAK;aACG,aAAa,EAAE,MAAM;gBAAtD,OAAO,EAAE,MAAM,EAAkB,aAAa,EAAE,MAAM;CAInE;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAuChE;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,MAAM,CAER;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAG9D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAOxE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO5D;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAczE;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG;IAC1D,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD,CAoBA;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,UAAmB,GACxB,MAAM,CAMR;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,cAAc,CAAC,EAAE,MAAM,GACtB,sBAAsB,CA2BxB"}
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Atomic Commit Enforcement for FORGE
3
+ *
4
+ * Enforces conventional commit format with task ID in scope:
5
+ * type(scope): description
6
+ *
7
+ * Examples:
8
+ * - feat(api-003): implement session authentication
9
+ * - fix(ui-002): resolve login form validation bug
10
+ * - test(core-001): add database integration tests
11
+ * - docs(readme): update installation instructions
12
+ *
13
+ * Rules:
14
+ * - Every task = one commit
15
+ * - Commit message MUST include task ID in scope
16
+ * - Pre-commit hooks validate format
17
+ * - Reject commits that don't match pattern
18
+ */
19
+ import { z } from "zod";
20
+ // Conventional commit types
21
+ export const CommitType = z.enum([
22
+ "feat",
23
+ "fix",
24
+ "docs",
25
+ "style",
26
+ "refactor",
27
+ "perf",
28
+ "test",
29
+ "chore",
30
+ "revert",
31
+ ]);
32
+ // Commit message format: type(scope): description
33
+ // Scope MUST be a task ID (e.g., api-003, ui-002)
34
+ const COMMIT_PATTERN = /^([a-z]+)\(([a-z]+-[0-9]+)\):\s+(.+)$/;
35
+ export class CommitFormatError extends Error {
36
+ commitMessage;
37
+ constructor(message, commitMessage) {
38
+ super(message);
39
+ this.commitMessage = commitMessage;
40
+ this.name = "CommitFormatError";
41
+ }
42
+ }
43
+ /**
44
+ * Parse a commit message into its components.
45
+ *
46
+ * @param message - The commit message to parse
47
+ * @returns Parsed commit components
48
+ * @throws CommitFormatError if format is invalid
49
+ */
50
+ export function parseCommitMessage(message) {
51
+ const match = message.match(COMMIT_PATTERN);
52
+ if (!match) {
53
+ throw new CommitFormatError(`Commit message must follow format "type(scope): description". Got: "${message}"`, message);
54
+ }
55
+ const [, typeRaw, scope, description] = match;
56
+ // Validate commit type
57
+ const typeResult = CommitType.safeParse(typeRaw);
58
+ if (!typeResult.success) {
59
+ throw new CommitFormatError(`Invalid commit type "${typeRaw}". Must be one of: ${CommitType.options.join(", ")}`, message);
60
+ }
61
+ // Validate scope format (task ID: domain-number)
62
+ if (!/^[a-z]+-[0-9]+$/.test(scope)) {
63
+ throw new CommitFormatError(`Invalid scope "${scope}". Scope must be a task ID in format "domain-number" (e.g., api-003)`, message);
64
+ }
65
+ // Validate description is not empty
66
+ if (!description || description.trim().length === 0) {
67
+ throw new CommitFormatError(`Commit description cannot be empty`, message);
68
+ }
69
+ return {
70
+ type: typeResult.data,
71
+ scope,
72
+ description,
73
+ };
74
+ }
75
+ /**
76
+ * Format a commit message from components.
77
+ *
78
+ * @param type - Commit type
79
+ * @param scope - Task ID (e.g., api-003)
80
+ * @param description - Commit description
81
+ * @returns Formatted commit message
82
+ */
83
+ export function formatCommitMessage(type, scope, description) {
84
+ return `${type}(${scope}): ${description}`;
85
+ }
86
+ /**
87
+ * Validate a commit message against FORGE standards.
88
+ *
89
+ * @param message - The commit message to validate
90
+ * @returns True if valid
91
+ * @throws CommitFormatError if invalid
92
+ */
93
+ export function validateCommitMessage(message) {
94
+ parseCommitMessage(message);
95
+ return true;
96
+ }
97
+ /**
98
+ * Check if a commit message is for a specific task.
99
+ *
100
+ * @param message - The commit message
101
+ * @param taskId - The task ID to check
102
+ * @returns True if the commit is for the specified task
103
+ */
104
+ export function isCommitForTask(message, taskId) {
105
+ try {
106
+ const parsed = parseCommitMessage(message);
107
+ return parsed.scope === taskId;
108
+ }
109
+ catch {
110
+ return false;
111
+ }
112
+ }
113
+ /**
114
+ * Extract task ID from a commit message.
115
+ *
116
+ * @param message - The commit message
117
+ * @returns Task ID or null if format is invalid
118
+ */
119
+ export function extractTaskId(message) {
120
+ try {
121
+ const parsed = parseCommitMessage(message);
122
+ return parsed.scope;
123
+ }
124
+ catch {
125
+ return null;
126
+ }
127
+ }
128
+ /**
129
+ * Create a full commit message with optional body and footer.
130
+ *
131
+ * @param options - Commit message components
132
+ * @returns Formatted commit message
133
+ */
134
+ export function createCommitMessage(options) {
135
+ const { type, taskId, description, body, footer } = options;
136
+ let message = formatCommitMessage(type, taskId, description);
137
+ if (body) {
138
+ message += `\n\n${body}`;
139
+ }
140
+ if (footer) {
141
+ message += `\n\n${footer}`;
142
+ }
143
+ return message;
144
+ }
145
+ /**
146
+ * Batch validate multiple commit messages.
147
+ *
148
+ * Useful for pre-commit hooks that check all staged commits.
149
+ *
150
+ * @param messages - Array of commit messages
151
+ * @returns Object with validation results
152
+ */
153
+ export function validateCommitMessages(messages) {
154
+ const errors = [];
155
+ for (const message of messages) {
156
+ try {
157
+ validateCommitMessage(message);
158
+ }
159
+ catch (error) {
160
+ if (error instanceof CommitFormatError) {
161
+ errors.push({
162
+ message,
163
+ error: error.message,
164
+ });
165
+ }
166
+ }
167
+ }
168
+ return {
169
+ valid: errors.length === 0,
170
+ errors,
171
+ };
172
+ }
173
+ /**
174
+ * Generate a commit message from task information.
175
+ *
176
+ * This is a helper for agents to generate properly formatted commits.
177
+ *
178
+ * @param taskId - The task ID
179
+ * @param taskTitle - The task title (will be converted to description)
180
+ * @param type - Commit type (defaults to "feat")
181
+ * @returns Formatted commit message
182
+ */
183
+ export function generateCommitFromTask(taskId, taskTitle, type = "feat") {
184
+ // Convert task title to commit description
185
+ // Lowercase first letter if it's capitalized
186
+ const description = taskTitle.charAt(0).toLowerCase() + taskTitle.slice(1);
187
+ return formatCommitMessage(type, taskId, description);
188
+ }
189
+ /**
190
+ * Validate a commit for pre-commit hook usage.
191
+ *
192
+ * This is the main entry point for pre-commit hooks.
193
+ *
194
+ * @param message - The commit message to validate
195
+ * @param expectedTaskId - Optional expected task ID
196
+ * @returns Validation result
197
+ */
198
+ export function validateForPreCommit(message, expectedTaskId) {
199
+ const errors = [];
200
+ let taskId = null;
201
+ try {
202
+ const parsed = parseCommitMessage(message);
203
+ taskId = parsed.scope;
204
+ // If expected task ID is provided, check for match
205
+ if (expectedTaskId && parsed.scope !== expectedTaskId) {
206
+ errors.push(`Commit scope "${parsed.scope}" does not match expected task ID "${expectedTaskId}"`);
207
+ }
208
+ }
209
+ catch (error) {
210
+ if (error instanceof CommitFormatError) {
211
+ errors.push(error.message);
212
+ }
213
+ else {
214
+ errors.push("Unknown validation error");
215
+ }
216
+ }
217
+ return {
218
+ isValid: errors.length === 0,
219
+ taskId,
220
+ errors,
221
+ };
222
+ }
223
+ //# sourceMappingURL=commit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit.js","sourceRoot":"","sources":["../../src/git/commit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Commit Message Hook Implementation
3
+ *
4
+ * This is the TypeScript file that the shell hook calls.
5
+ * It validates the commit message format.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=commit-msg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit-msg.d.ts","sourceRoot":"","sources":["../../../src/git/hooks/commit-msg.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Commit Message Hook Implementation
3
+ *
4
+ * This is the TypeScript file that the shell hook calls.
5
+ * It validates the commit message format.
6
+ */
7
+ import { readFileSync } from "node:fs";
8
+ import { runCommitMsgValidation } from "../pre-commit-hooks.js";
9
+ async function main() {
10
+ // Get commit message from the temp file (git passes it as first arg)
11
+ const commitMsgFile = process.argv[2];
12
+ if (!commitMsgFile) {
13
+ console.error("Usage: commit-msg <commit-message-file>");
14
+ process.exit(1);
15
+ }
16
+ const commitMessage = readFileSync(commitMsgFile, "utf-8").trim();
17
+ // Validate commit message
18
+ const result = runCommitMsgValidation(commitMessage);
19
+ if (!result.isValid) {
20
+ console.error("❌ FORGE Commit Message Validation Failed:\n");
21
+ for (const error of result.errors) {
22
+ console.error(` - ${error}\n`);
23
+ }
24
+ console.error("Commit message must follow format: type(scope): description\n" +
25
+ "Example: feat(api-003): implement session authentication");
26
+ process.exit(1);
27
+ }
28
+ process.exit(0);
29
+ }
30
+ main().catch((error) => {
31
+ console.error("Commit-msg hook error:", error);
32
+ process.exit(1);
33
+ });
34
+ //# sourceMappingURL=commit-msg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit-msg.js","sourceRoot":"","sources":["../../../src/git/hooks/commit-msg.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,KAAK,UAAU,IAAI;IACjB,qEAAqE;IACrE,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEtC,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,aAAa,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IAElE,0BAA0B;IAC1B,MAAM,MAAM,GAAG,sBAAsB,CAAC,aAAa,CAAC,CAAC;IAErD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAC7D,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClC,OAAO,CAAC,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,CAAC,KAAK,CACX,+DAA+D;YAC7D,0DAA0D,CAC7D,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Pre-commit Hook Implementation
3
+ *
4
+ * This is the TypeScript file that the shell hook calls.
5
+ * It runs all pre-commit validations and blocks commits that fail.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=pre-commit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-commit.d.ts","sourceRoot":"","sources":["../../../src/git/hooks/pre-commit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}