forge-cc 0.1.40 → 1.0.0

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 (72) hide show
  1. package/README.md +454 -338
  2. package/dist/cli.js +194 -906
  3. package/dist/cli.js.map +1 -1
  4. package/dist/config/loader.d.ts +1 -1
  5. package/dist/config/loader.js +49 -56
  6. package/dist/config/loader.js.map +1 -1
  7. package/dist/config/schema.d.ts +37 -125
  8. package/dist/config/schema.js +13 -28
  9. package/dist/config/schema.js.map +1 -1
  10. package/dist/doctor.d.ts +10 -0
  11. package/dist/doctor.js +148 -0
  12. package/dist/doctor.js.map +1 -0
  13. package/dist/gates/index.d.ts +14 -12
  14. package/dist/gates/index.js +53 -105
  15. package/dist/gates/index.js.map +1 -1
  16. package/dist/gates/lint-gate.d.ts +2 -2
  17. package/dist/gates/lint-gate.js +60 -66
  18. package/dist/gates/lint-gate.js.map +1 -1
  19. package/dist/gates/tests-gate.d.ts +2 -4
  20. package/dist/gates/tests-gate.js +75 -203
  21. package/dist/gates/tests-gate.js.map +1 -1
  22. package/dist/gates/types-gate.d.ts +2 -2
  23. package/dist/gates/types-gate.js +53 -59
  24. package/dist/gates/types-gate.js.map +1 -1
  25. package/dist/go/linear-sync-cli.js +13 -4
  26. package/dist/go/linear-sync-cli.js.map +1 -1
  27. package/dist/go/linear-sync.d.ts +1 -0
  28. package/dist/go/linear-sync.js +67 -4
  29. package/dist/go/linear-sync.js.map +1 -1
  30. package/dist/linear/client.d.ts +34 -105
  31. package/dist/linear/client.js +85 -365
  32. package/dist/linear/client.js.map +1 -1
  33. package/dist/linear/issues.d.ts +3 -1
  34. package/dist/linear/issues.js +14 -2
  35. package/dist/linear/issues.js.map +1 -1
  36. package/dist/linear/projects.js +3 -2
  37. package/dist/linear/projects.js.map +1 -1
  38. package/dist/linear/sync.d.ts +15 -0
  39. package/dist/linear/sync.js +102 -0
  40. package/dist/linear/sync.js.map +1 -0
  41. package/dist/runner/loop.d.ts +4 -0
  42. package/dist/runner/loop.js +168 -0
  43. package/dist/runner/loop.js.map +1 -0
  44. package/dist/runner/prompt.d.ts +14 -0
  45. package/dist/runner/prompt.js +59 -0
  46. package/dist/runner/prompt.js.map +1 -0
  47. package/dist/runner/update.d.ts +1 -0
  48. package/dist/runner/update.js +72 -0
  49. package/dist/runner/update.js.map +1 -0
  50. package/dist/server.d.ts +6 -2
  51. package/dist/server.js +43 -101
  52. package/dist/server.js.map +1 -1
  53. package/dist/setup.d.ts +5 -0
  54. package/dist/setup.js +208 -0
  55. package/dist/setup.js.map +1 -0
  56. package/dist/state/cache.d.ts +3 -0
  57. package/dist/state/cache.js +23 -0
  58. package/dist/state/cache.js.map +1 -0
  59. package/dist/state/status.d.ts +66 -0
  60. package/dist/state/status.js +96 -0
  61. package/dist/state/status.js.map +1 -0
  62. package/dist/types.d.ts +46 -114
  63. package/dist/worktree/manager.d.ts +6 -103
  64. package/dist/worktree/manager.js +25 -296
  65. package/dist/worktree/manager.js.map +1 -1
  66. package/hooks/pre-commit-verify.js +109 -109
  67. package/package.json +3 -2
  68. package/skills/forge-go.md +583 -575
  69. package/skills/forge-setup.md +149 -388
  70. package/skills/forge-spec.md +367 -342
  71. package/skills/forge-triage.md +179 -133
  72. package/skills/forge-update.md +87 -93
@@ -1,109 +1,109 @@
1
- #!/usr/bin/env node
2
-
3
- import { readFileSync, existsSync } from "node:fs";
4
- import { join } from "node:path";
5
- import { execSync } from "node:child_process";
6
-
7
- // Read hook input from stdin
8
- let input = "";
9
- process.stdin.setEncoding("utf-8");
10
- process.stdin.on("data", (chunk) => {
11
- input += chunk;
12
- });
13
- process.stdin.on("end", () => {
14
- try {
15
- const hookData = JSON.parse(input);
16
- const result = checkPreCommit(hookData);
17
- console.log(JSON.stringify(result));
18
- } catch {
19
- // On any error, allow (don't block the user's work)
20
- console.log(JSON.stringify({ decision: "allow" }));
21
- }
22
- });
23
-
24
- function checkPreCommit(hookData) {
25
- // Only intercept Bash calls with "git commit" in the command
26
- if (hookData.tool_name !== "Bash") {
27
- return { decision: "allow" };
28
- }
29
-
30
- const command = hookData.tool_input?.command ?? "";
31
- if (!command.includes("git commit")) {
32
- return { decision: "allow" };
33
- }
34
-
35
- const projectDir = process.cwd();
36
-
37
- // Check 1: Wrong branch protection
38
- let branch = "unknown";
39
- try {
40
- branch = execSync("git branch --show-current", {
41
- encoding: "utf-8",
42
- }).trim();
43
- if (branch === "main" || branch === "master") {
44
- return {
45
- decision: "block",
46
- reason: `Forge: Cannot commit directly to ${branch}. Create a feature branch first.`,
47
- };
48
- }
49
- } catch {
50
- // Can't determine branch — allow
51
- }
52
-
53
- // Check 2: Verify cache exists — per-branch first, fall back to legacy path
54
- const slug = branch.replace(/\//g, "-").toLowerCase();
55
- const perBranchCachePath = join(projectDir, ".forge", "verify-cache", `${slug}.json`);
56
- const legacyCachePath = join(projectDir, ".forge", "last-verify.json");
57
- const cachePath = existsSync(perBranchCachePath)
58
- ? perBranchCachePath
59
- : legacyCachePath;
60
- if (!existsSync(cachePath)) {
61
- return {
62
- decision: "block",
63
- reason:
64
- "Forge: No verification found. Run `npx forge verify` before committing.",
65
- };
66
- }
67
-
68
- try {
69
- const cache = JSON.parse(readFileSync(cachePath, "utf-8"));
70
-
71
- // Check 3: Did verification pass?
72
- if (!cache.passed) {
73
- return {
74
- decision: "block",
75
- reason:
76
- "Forge: Last verification FAILED. Fix errors and run `npx forge verify` again.",
77
- };
78
- }
79
-
80
- // Check 4: Is it fresh? (default 10 minutes = 600000ms)
81
- let freshness = 600_000;
82
- const configPath = join(projectDir, ".forge.json");
83
- if (existsSync(configPath)) {
84
- try {
85
- const config = JSON.parse(readFileSync(configPath, "utf-8"));
86
- if (config.verifyFreshness) freshness = config.verifyFreshness;
87
- } catch {
88
- /* use default */
89
- }
90
- }
91
-
92
- const age = Date.now() - new Date(cache.timestamp).getTime();
93
- if (age > freshness) {
94
- const ageMin = Math.round(age / 60_000);
95
- return {
96
- decision: "block",
97
- reason: `Forge: Verification is stale (${ageMin}min old). Run \`npx forge verify\` again.`,
98
- };
99
- }
100
-
101
- return { decision: "allow" };
102
- } catch {
103
- return {
104
- decision: "block",
105
- reason:
106
- "Forge: Could not read verification cache. Run `npx forge verify`.",
107
- };
108
- }
109
- }
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync, existsSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { execSync } from "node:child_process";
6
+
7
+ // Read hook input from stdin
8
+ let input = "";
9
+ process.stdin.setEncoding("utf-8");
10
+ process.stdin.on("data", (chunk) => {
11
+ input += chunk;
12
+ });
13
+ process.stdin.on("end", () => {
14
+ try {
15
+ const hookData = JSON.parse(input);
16
+ const result = checkPreCommit(hookData);
17
+ console.log(JSON.stringify(result));
18
+ } catch {
19
+ // On any error, allow (don't block the user's work)
20
+ console.log(JSON.stringify({ decision: "allow" }));
21
+ }
22
+ });
23
+
24
+ function checkPreCommit(hookData) {
25
+ // Only intercept Bash calls with "git commit" in the command
26
+ if (hookData.tool_name !== "Bash") {
27
+ return { decision: "allow" };
28
+ }
29
+
30
+ const command = hookData.tool_input?.command ?? "";
31
+ if (!command.includes("git commit")) {
32
+ return { decision: "allow" };
33
+ }
34
+
35
+ const projectDir = process.cwd();
36
+
37
+ // Check 1: Wrong branch protection
38
+ let branch = "unknown";
39
+ try {
40
+ branch = execSync("git branch --show-current", {
41
+ encoding: "utf-8",
42
+ }).trim();
43
+ if (branch === "main" || branch === "master") {
44
+ return {
45
+ decision: "block",
46
+ reason: `Forge: Cannot commit directly to ${branch}. Create a feature branch first.`,
47
+ };
48
+ }
49
+ } catch {
50
+ // Can't determine branch — allow
51
+ }
52
+
53
+ // Check 2: Verify cache exists — per-branch first, fall back to legacy path
54
+ const slug = branch.replace(/\//g, "-").toLowerCase();
55
+ const perBranchCachePath = join(projectDir, ".forge", "verify-cache", `${slug}.json`);
56
+ const legacyCachePath = join(projectDir, ".forge", "last-verify.json");
57
+ const cachePath = existsSync(perBranchCachePath)
58
+ ? perBranchCachePath
59
+ : legacyCachePath;
60
+ if (!existsSync(cachePath)) {
61
+ return {
62
+ decision: "block",
63
+ reason:
64
+ "Forge: No verification found. Run `npx forge verify` before committing.",
65
+ };
66
+ }
67
+
68
+ try {
69
+ const cache = JSON.parse(readFileSync(cachePath, "utf-8"));
70
+
71
+ // Check 3: Did verification pass? (v2 format: cache.result === 'PASSED')
72
+ if (cache.result !== 'PASSED') {
73
+ return {
74
+ decision: "block",
75
+ reason:
76
+ "Forge: Last verification FAILED. Fix errors and run `npx forge verify` again.",
77
+ };
78
+ }
79
+
80
+ // Check 4: Is it fresh? (default 10 minutes = 600000ms)
81
+ let freshness = 600_000;
82
+ const configPath = join(projectDir, ".forge.json");
83
+ if (existsSync(configPath)) {
84
+ try {
85
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
86
+ if (config.verifyFreshness) freshness = config.verifyFreshness;
87
+ } catch {
88
+ /* use default */
89
+ }
90
+ }
91
+
92
+ const age = Date.now() - new Date(cache.timestamp).getTime();
93
+ if (age > freshness) {
94
+ const ageMin = Math.round(age / 60_000);
95
+ return {
96
+ decision: "block",
97
+ reason: `Forge: Verification is stale (${ageMin}min old). Run \`npx forge verify\` again.`,
98
+ };
99
+ }
100
+
101
+ return { decision: "allow" };
102
+ } catch {
103
+ return {
104
+ decision: "block",
105
+ reason:
106
+ "Forge: Could not read verification cache. Run `npx forge verify`.",
107
+ };
108
+ }
109
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "forge-cc",
3
- "version": "0.1.40",
4
- "description": "Pre-PR verification harness for Claude Code agents — gate runner + CLI + MCP server",
3
+ "version": "1.0.0",
4
+ "description": "Forge verification harness for Claude Code agents",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": "Troy Hoffman",
@@ -50,6 +50,7 @@
50
50
  "prepublishOnly": "npm run build"
51
51
  },
52
52
  "dependencies": {
53
+ "@linear/sdk": "^75.0.0",
53
54
  "@modelcontextprotocol/sdk": "^1.12.0",
54
55
  "commander": "^13.0.0",
55
56
  "zod": "^3.24.0"