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,34 @@
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
+ import { runPreCommitValidations, loadPreCommitContext, parseTaskIdFromBranch } from "../pre-commit-hooks.js";
8
+ async function main() {
9
+ // Get the task ID from the branch name
10
+ const taskId = await parseTaskIdFromBranch();
11
+ if (!taskId) {
12
+ // Not a FORGE branch, allow commit
13
+ process.exit(0);
14
+ }
15
+ // Load validation context from state
16
+ const context = await loadPreCommitContext(taskId);
17
+ // Run validations
18
+ const result = await runPreCommitValidations(context);
19
+ if (!result.isValid) {
20
+ console.error("❌ FORGE Pre-commit Validations Failed:\n");
21
+ for (const error of result.errors) {
22
+ console.error(` - ${error}\n`);
23
+ }
24
+ console.error("Commit blocked. Fix the issues and try again.");
25
+ process.exit(1);
26
+ }
27
+ console.log("✅ FORGE Pre-commit Validations Passed.");
28
+ process.exit(0);
29
+ }
30
+ main().catch((error) => {
31
+ console.error("Pre-commit hook error:", error);
32
+ process.exit(1);
33
+ });
34
+ //# sourceMappingURL=pre-commit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-commit.js","sourceRoot":"","sources":["../../../src/git/hooks/pre-commit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAE9G,KAAK,UAAU,IAAI;IACjB,uCAAuC;IACvC,MAAM,MAAM,GAAG,MAAM,qBAAqB,EAAE,CAAC;IAE7C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,mCAAmC;QACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,qCAAqC;IACrC,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAEnD,kBAAkB;IAClB,MAAM,MAAM,GAAG,MAAM,uBAAuB,CAAC,OAAO,CAAC,CAAC;IAEtD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC1D,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,CAAC,+CAA+C,CAAC,CAAC;QAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;IACtD,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,117 @@
1
+ /**
2
+ * Pre-commit Hooks for FORGE
3
+ *
4
+ * Creates hooks to enforce:
5
+ * - Out-of-scope file detection (agent tried to write outside allowedPaths)
6
+ * - Commit message format validation
7
+ * - Test execution requirement (if tests defined for task)
8
+ * - Contract file validation (if contract referenced)
9
+ *
10
+ * These hooks are installed to .git/hooks/ and run before each commit.
11
+ */
12
+ export interface PreCommitContext {
13
+ taskId?: string;
14
+ allowedPaths?: string[];
15
+ requiredTests?: string[];
16
+ requiredContracts?: string[];
17
+ }
18
+ /**
19
+ * Generate the pre-commit hook script.
20
+ *
21
+ * This shell script is installed to .git/hooks/pre-commit.
22
+ */
23
+ export declare function generatePreCommitScript(): string;
24
+ /**
25
+ * Generate the commit-msg hook script.
26
+ *
27
+ * This shell script is installed to .git/hooks/commit-msg.
28
+ */
29
+ export declare function generateCommitMsgScript(): string;
30
+ /**
31
+ * Install pre-commit hooks to the .git/hooks directory.
32
+ *
33
+ * @param basePath - Root of the FORGE project
34
+ */
35
+ export declare function installHooks(basePath?: string): Promise<void>;
36
+ /**
37
+ * Check if files are within allowed paths.
38
+ *
39
+ * @param files - Files to check
40
+ * @param allowedPaths - Allowed path patterns
41
+ * @returns Validation result
42
+ */
43
+ export declare function checkFileScope(files: string[], allowedPaths: string[]): {
44
+ isValid: boolean;
45
+ outOfScopeFiles: string[];
46
+ };
47
+ /**
48
+ * Get staged files for a commit.
49
+ *
50
+ * @returns Array of staged file paths
51
+ */
52
+ export declare function getStagedFiles(): Promise<string[]>;
53
+ /**
54
+ * Validate that required contracts exist and are valid.
55
+ *
56
+ * @param contracts - Contract file paths to validate
57
+ * @param basePath - Root of the FORGE project
58
+ * @returns Validation result
59
+ */
60
+ export declare function validateContracts(contracts: string[], basePath?: string): Promise<{
61
+ isValid: boolean;
62
+ errors: string[];
63
+ }>;
64
+ /**
65
+ * Run tests and check if they pass.
66
+ *
67
+ * @param testCommands - Test commands to run (e.g., ["npm test -- --grep 'session auth'"])
68
+ * @returns Test result
69
+ */
70
+ export declare function runRequiredTests(testCommands: string[]): Promise<{
71
+ passed: boolean;
72
+ output: string;
73
+ }>;
74
+ /**
75
+ * Run all pre-commit validations.
76
+ *
77
+ * This is the main entry point for the pre-commit hook.
78
+ *
79
+ * @param context - Pre-commit validation context
80
+ * @returns Validation result with errors
81
+ */
82
+ export declare function runPreCommitValidations(context: PreCommitContext): Promise<{
83
+ isValid: boolean;
84
+ errors: string[];
85
+ }>;
86
+ /**
87
+ * Run commit message validation.
88
+ *
89
+ * This is the main entry point for the commit-msg hook.
90
+ *
91
+ * @param message - Commit message to validate
92
+ * @param expectedTaskId - Expected task ID (optional)
93
+ * @returns Validation result
94
+ */
95
+ export declare function runCommitMsgValidation(message: string, expectedTaskId?: string): {
96
+ isValid: boolean;
97
+ errors: string[];
98
+ };
99
+ /**
100
+ * Read pre-commit context from task state.
101
+ *
102
+ * This loads the validation rules from the FORGE state.
103
+ *
104
+ * @param taskId - Task ID to load context for
105
+ * @param basePath - Root of the FORGE project
106
+ * @returns Pre-commit context
107
+ */
108
+ export declare function loadPreCommitContext(taskId: string, basePath?: string): Promise<PreCommitContext>;
109
+ /**
110
+ * Parse task ID from the current branch name.
111
+ *
112
+ * FORGE branches use format: forge/{taskId}
113
+ *
114
+ * @returns Task ID or null
115
+ */
116
+ export declare function parseTaskIdFromBranch(): Promise<string | null>;
117
+ //# sourceMappingURL=pre-commit-hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-commit-hooks.d.ts","sourceRoot":"","sources":["../../src/git/pre-commit-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAahD;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAahD;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,QAAQ,GAAE,MAAoC,GAAG,OAAO,CAAC,IAAI,CAAC,CAehG;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG;IACvE,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B,CAuBA;AAED;;;;GAIG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAGxD;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EAAE,EACnB,QAAQ,GAAE,MAAoC,GAC7C,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAwBjD;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACtE,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAuBD;AAED;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAqCjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,cAAc,CAAC,EAAE,MAAM,GACtB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAOxC;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAAoC,GAC7C,OAAO,CAAC,gBAAgB,CAAC,CAuB3B;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAUpE"}
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Pre-commit Hooks for FORGE
3
+ *
4
+ * Creates hooks to enforce:
5
+ * - Out-of-scope file detection (agent tried to write outside allowedPaths)
6
+ * - Commit message format validation
7
+ * - Test execution requirement (if tests defined for task)
8
+ * - Contract file validation (if contract referenced)
9
+ *
10
+ * These hooks are installed to .git/hooks/ and run before each commit.
11
+ */
12
+ import { writeFile, mkdir } from "node:fs/promises";
13
+ import { join } from "node:path";
14
+ import { execa } from "execa";
15
+ import { validateForPreCommit } from "./commit.js";
16
+ /**
17
+ * Generate the pre-commit hook script.
18
+ *
19
+ * This shell script is installed to .git/hooks/pre-commit.
20
+ */
21
+ export function generatePreCommitScript() {
22
+ return `#!/bin/bash
23
+ # FORGE Pre-commit Hook
24
+ # Auto-generated by FORGE - DO NOT EDIT MANUALLY
25
+
26
+ set -e
27
+
28
+ # Get the root of the git repository
29
+ REPO_ROOT=$(git rev-parse --show-toplevel)
30
+
31
+ # Run the TypeScript pre-commit validator
32
+ node "$REPO_ROOT/dist/git/hooks/pre-commit.js" "$@"
33
+ `;
34
+ }
35
+ /**
36
+ * Generate the commit-msg hook script.
37
+ *
38
+ * This shell script is installed to .git/hooks/commit-msg.
39
+ */
40
+ export function generateCommitMsgScript() {
41
+ return `#!/bin/bash
42
+ # FORGE Commit Message Hook
43
+ # Auto-generated by FORGE - DO NOT EDIT MANUALLY
44
+
45
+ set -e
46
+
47
+ # Get the root of the git repository
48
+ REPO_ROOT=$(git rev-parse --show-toplevel)
49
+
50
+ # Run the TypeScript commit-msg validator
51
+ node "$REPO_ROOT/dist/git/hooks/commit-msg.js" "$1"
52
+ `;
53
+ }
54
+ /**
55
+ * Install pre-commit hooks to the .git/hooks directory.
56
+ *
57
+ * @param basePath - Root of the FORGE project
58
+ */
59
+ export async function installHooks(basePath = "/home/parz/projects/forge") {
60
+ const hooksDir = join(basePath, ".git", "hooks");
61
+ // Ensure hooks directory exists
62
+ await mkdir(hooksDir, { recursive: true });
63
+ // Write pre-commit hook
64
+ const preCommitPath = join(hooksDir, "pre-commit");
65
+ await writeFile(preCommitPath, generatePreCommitScript(), { mode: 0o755 });
66
+ // Write commit-msg hook
67
+ const commitMsgPath = join(hooksDir, "commit-msg");
68
+ await writeFile(commitMsgPath, generateCommitMsgScript(), { mode: 0o755 });
69
+ console.log("FORGE pre-commit hooks installed.");
70
+ }
71
+ /**
72
+ * Check if files are within allowed paths.
73
+ *
74
+ * @param files - Files to check
75
+ * @param allowedPaths - Allowed path patterns
76
+ * @returns Validation result
77
+ */
78
+ export function checkFileScope(files, allowedPaths) {
79
+ const outOfScopeFiles = [];
80
+ for (const file of files) {
81
+ const isAllowed = allowedPaths.some((pattern) => {
82
+ // Simple glob matching - converts gitignore-style patterns to regex
83
+ const regexPattern = pattern
84
+ .replace(/\*\*/g, ".*")
85
+ .replace(/\*/g, "[^/]*")
86
+ .replace(/\?/g, "[^/]");
87
+ const regex = new RegExp(`^${regexPattern}`);
88
+ return regex.test(file);
89
+ });
90
+ if (!isAllowed) {
91
+ outOfScopeFiles.push(file);
92
+ }
93
+ }
94
+ return {
95
+ isValid: outOfScopeFiles.length === 0,
96
+ outOfScopeFiles,
97
+ };
98
+ }
99
+ /**
100
+ * Get staged files for a commit.
101
+ *
102
+ * @returns Array of staged file paths
103
+ */
104
+ export async function getStagedFiles() {
105
+ const { stdout } = await execa("git", ["diff", "--cached", "--name-only", "--diff-filter=ACM"]);
106
+ return stdout.split("\n").filter((f) => f.length > 0);
107
+ }
108
+ /**
109
+ * Validate that required contracts exist and are valid.
110
+ *
111
+ * @param contracts - Contract file paths to validate
112
+ * @param basePath - Root of the FORGE project
113
+ * @returns Validation result
114
+ */
115
+ export async function validateContracts(contracts, basePath = "/home/parz/projects/forge") {
116
+ const errors = [];
117
+ const { readFile } = await import("node:fs/promises");
118
+ for (const contract of contracts) {
119
+ const contractPath = join(basePath, contract);
120
+ try {
121
+ // Check if file exists
122
+ await readFile(contractPath, "utf-8");
123
+ // TODO: Add validation based on contract type
124
+ // - OpenAPI validation for .yaml files
125
+ // - TypeScript type checking for .d.ts files
126
+ // - Zod schema validation
127
+ }
128
+ catch (error) {
129
+ errors.push(`Contract file not found or invalid: ${contract}`);
130
+ }
131
+ }
132
+ return {
133
+ isValid: errors.length === 0,
134
+ errors,
135
+ };
136
+ }
137
+ /**
138
+ * Run tests and check if they pass.
139
+ *
140
+ * @param testCommands - Test commands to run (e.g., ["npm test -- --grep 'session auth'"])
141
+ * @returns Test result
142
+ */
143
+ export async function runRequiredTests(testCommands) {
144
+ const results = [];
145
+ for (const command of testCommands) {
146
+ try {
147
+ const { stdout, stderr } = await execa(command, { shell: true });
148
+ results.push({ passed: true, output: stdout + stderr });
149
+ }
150
+ catch (error) {
151
+ if (error instanceof Error) {
152
+ results.push({ passed: false, output: error.message });
153
+ }
154
+ else {
155
+ results.push({ passed: false, output: "Unknown error" });
156
+ }
157
+ }
158
+ }
159
+ const allPassed = results.every((r) => r.passed);
160
+ const combinedOutput = results.map((r, i) => `Test ${i + 1}:\n${r.output}`).join("\n\n");
161
+ return {
162
+ passed: allPassed,
163
+ output: combinedOutput,
164
+ };
165
+ }
166
+ /**
167
+ * Run all pre-commit validations.
168
+ *
169
+ * This is the main entry point for the pre-commit hook.
170
+ *
171
+ * @param context - Pre-commit validation context
172
+ * @returns Validation result with errors
173
+ */
174
+ export async function runPreCommitValidations(context) {
175
+ const errors = [];
176
+ // 1. Get staged files
177
+ const stagedFiles = await getStagedFiles();
178
+ // 2. Check file scope (if allowedPaths provided)
179
+ if (context.allowedPaths && context.allowedPaths.length > 0) {
180
+ const scopeCheck = checkFileScope(stagedFiles, context.allowedPaths);
181
+ if (!scopeCheck.isValid) {
182
+ errors.push(`Out-of-scope files detected: ${scopeCheck.outOfScopeFiles.join(", ")}\n` +
183
+ `Allowed paths: ${context.allowedPaths.join(", ")}`);
184
+ }
185
+ }
186
+ // 3. Validate contracts (if required)
187
+ if (context.requiredContracts && context.requiredContracts.length > 0) {
188
+ const contractValidation = await validateContracts(context.requiredContracts);
189
+ if (!contractValidation.isValid) {
190
+ errors.push(...contractValidation.errors);
191
+ }
192
+ }
193
+ // 4. Run required tests (if specified)
194
+ if (context.requiredTests && context.requiredTests.length > 0) {
195
+ const testResult = await runRequiredTests(context.requiredTests);
196
+ if (!testResult.passed) {
197
+ errors.push(`Required tests failed:\n${testResult.output}`);
198
+ }
199
+ }
200
+ return {
201
+ isValid: errors.length === 0,
202
+ errors,
203
+ };
204
+ }
205
+ /**
206
+ * Run commit message validation.
207
+ *
208
+ * This is the main entry point for the commit-msg hook.
209
+ *
210
+ * @param message - Commit message to validate
211
+ * @param expectedTaskId - Expected task ID (optional)
212
+ * @returns Validation result
213
+ */
214
+ export function runCommitMsgValidation(message, expectedTaskId) {
215
+ const result = validateForPreCommit(message, expectedTaskId);
216
+ return {
217
+ isValid: result.isValid,
218
+ errors: result.errors,
219
+ };
220
+ }
221
+ /**
222
+ * Read pre-commit context from task state.
223
+ *
224
+ * This loads the validation rules from the FORGE state.
225
+ *
226
+ * @param taskId - Task ID to load context for
227
+ * @param basePath - Root of the FORGE project
228
+ * @returns Pre-commit context
229
+ */
230
+ export async function loadPreCommitContext(taskId, basePath = "/home/parz/projects/forge") {
231
+ const { readFile } = await import("node:fs/promises");
232
+ const statePath = join(basePath, "state", "STATE.json");
233
+ try {
234
+ const stateRaw = await readFile(statePath, "utf-8");
235
+ const state = JSON.parse(stateRaw);
236
+ const task = state.tasks.find((t) => t.id === taskId);
237
+ if (!task) {
238
+ throw new Error(`Task ${taskId} not found in STATE.json`);
239
+ }
240
+ return {
241
+ taskId: task.id,
242
+ allowedPaths: task.allowedPaths,
243
+ requiredTests: task.verify,
244
+ requiredContracts: task.contracts,
245
+ };
246
+ }
247
+ catch (error) {
248
+ // If state doesn't exist, return empty context
249
+ return {};
250
+ }
251
+ }
252
+ /**
253
+ * Parse task ID from the current branch name.
254
+ *
255
+ * FORGE branches use format: forge/{taskId}
256
+ *
257
+ * @returns Task ID or null
258
+ */
259
+ export async function parseTaskIdFromBranch() {
260
+ try {
261
+ const { stdout } = await execa("git", ["branch", "--show-current"]);
262
+ const branch = stdout.trim();
263
+ const match = branch.match(/^forge\/(.+)$/);
264
+ return match ? match[1] : null;
265
+ }
266
+ catch {
267
+ return null;
268
+ }
269
+ }
270
+ //# sourceMappingURL=pre-commit-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-commit-hooks.js","sourceRoot":"","sources":["../../src/git/pre-commit-hooks.ts"],"names":[],"mappings":"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"}