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,281 @@
1
+ /**
2
+ * The Wipe Protocol - Context Hygiene for FORGE
3
+ *
4
+ * Treats agent context as ephemeral, git as persistent.
5
+ *
6
+ * Lifecycle:
7
+ * 1. Hydrate — Agent starts, reads CLAUDE.md + STATE.json + assigned task + contracts
8
+ * 2. Execute — Agent writes code, runs tests within its domain
9
+ * 3. Commit — Atomic git commit linked to task ID
10
+ * 4. Terminate — Session ends, context wiped
11
+ * 5. Reincarnate — Next task starts with fresh context, reads NEW git state
12
+ */
13
+ import { z } from "zod";
14
+ export declare const TaskSchema: z.ZodObject<{
15
+ id: z.ZodString;
16
+ title: z.ZodString;
17
+ ownerRole: z.ZodString;
18
+ status: z.ZodEnum<["pending", "in_progress", "completed", "blocked"]>;
19
+ deps: z.ZodArray<z.ZodString, "many">;
20
+ allowedPaths: z.ZodArray<z.ZodString, "many">;
21
+ acceptance: z.ZodArray<z.ZodString, "many">;
22
+ verify: z.ZodArray<z.ZodString, "many">;
23
+ commit: z.ZodNullable<z.ZodString>;
24
+ requests: z.ZodArray<z.ZodString, "many">;
25
+ priority: z.ZodNumber;
26
+ }, "strip", z.ZodTypeAny, {
27
+ status: "pending" | "in_progress" | "completed" | "blocked";
28
+ allowedPaths: string[];
29
+ commit: string | null;
30
+ id: string;
31
+ title: string;
32
+ ownerRole: string;
33
+ deps: string[];
34
+ acceptance: string[];
35
+ verify: string[];
36
+ requests: string[];
37
+ priority: number;
38
+ }, {
39
+ status: "pending" | "in_progress" | "completed" | "blocked";
40
+ allowedPaths: string[];
41
+ commit: string | null;
42
+ id: string;
43
+ title: string;
44
+ ownerRole: string;
45
+ deps: string[];
46
+ acceptance: string[];
47
+ verify: string[];
48
+ requests: string[];
49
+ priority: number;
50
+ }>;
51
+ export type Task = z.infer<typeof TaskSchema>;
52
+ export declare const StateSchema: z.ZodObject<{
53
+ project: z.ZodObject<{
54
+ name: z.ZodString;
55
+ status: z.ZodString;
56
+ currentMilestone: z.ZodString;
57
+ currentPhase: z.ZodNumber;
58
+ }, "strip", z.ZodTypeAny, {
59
+ status: string;
60
+ name: string;
61
+ currentMilestone: string;
62
+ currentPhase: number;
63
+ }, {
64
+ status: string;
65
+ name: string;
66
+ currentMilestone: string;
67
+ currentPhase: number;
68
+ }>;
69
+ tasks: z.ZodArray<z.ZodObject<{
70
+ id: z.ZodString;
71
+ title: z.ZodString;
72
+ ownerRole: z.ZodString;
73
+ status: z.ZodEnum<["pending", "in_progress", "completed", "blocked"]>;
74
+ deps: z.ZodArray<z.ZodString, "many">;
75
+ allowedPaths: z.ZodArray<z.ZodString, "many">;
76
+ acceptance: z.ZodArray<z.ZodString, "many">;
77
+ verify: z.ZodArray<z.ZodString, "many">;
78
+ commit: z.ZodNullable<z.ZodString>;
79
+ requests: z.ZodArray<z.ZodString, "many">;
80
+ priority: z.ZodNumber;
81
+ }, "strip", z.ZodTypeAny, {
82
+ status: "pending" | "in_progress" | "completed" | "blocked";
83
+ allowedPaths: string[];
84
+ commit: string | null;
85
+ id: string;
86
+ title: string;
87
+ ownerRole: string;
88
+ deps: string[];
89
+ acceptance: string[];
90
+ verify: string[];
91
+ requests: string[];
92
+ priority: number;
93
+ }, {
94
+ status: "pending" | "in_progress" | "completed" | "blocked";
95
+ allowedPaths: string[];
96
+ commit: string | null;
97
+ id: string;
98
+ title: string;
99
+ ownerRole: string;
100
+ deps: string[];
101
+ acceptance: string[];
102
+ verify: string[];
103
+ requests: string[];
104
+ priority: number;
105
+ }>, "many">;
106
+ contracts: z.ZodArray<z.ZodObject<{
107
+ id: z.ZodString;
108
+ path: z.ZodString;
109
+ version: z.ZodString;
110
+ publishedBy: z.ZodString;
111
+ consumers: z.ZodArray<z.ZodString, "many">;
112
+ }, "strip", z.ZodTypeAny, {
113
+ path: string;
114
+ id: string;
115
+ version: string;
116
+ publishedBy: string;
117
+ consumers: string[];
118
+ }, {
119
+ path: string;
120
+ id: string;
121
+ version: string;
122
+ publishedBy: string;
123
+ consumers: string[];
124
+ }>, "many">;
125
+ eventsPointer: z.ZodString;
126
+ }, "strip", z.ZodTypeAny, {
127
+ project: {
128
+ status: string;
129
+ name: string;
130
+ currentMilestone: string;
131
+ currentPhase: number;
132
+ };
133
+ tasks: {
134
+ status: "pending" | "in_progress" | "completed" | "blocked";
135
+ allowedPaths: string[];
136
+ commit: string | null;
137
+ id: string;
138
+ title: string;
139
+ ownerRole: string;
140
+ deps: string[];
141
+ acceptance: string[];
142
+ verify: string[];
143
+ requests: string[];
144
+ priority: number;
145
+ }[];
146
+ contracts: {
147
+ path: string;
148
+ id: string;
149
+ version: string;
150
+ publishedBy: string;
151
+ consumers: string[];
152
+ }[];
153
+ eventsPointer: string;
154
+ }, {
155
+ project: {
156
+ status: string;
157
+ name: string;
158
+ currentMilestone: string;
159
+ currentPhase: number;
160
+ };
161
+ tasks: {
162
+ status: "pending" | "in_progress" | "completed" | "blocked";
163
+ allowedPaths: string[];
164
+ commit: string | null;
165
+ id: string;
166
+ title: string;
167
+ ownerRole: string;
168
+ deps: string[];
169
+ acceptance: string[];
170
+ verify: string[];
171
+ requests: string[];
172
+ priority: number;
173
+ }[];
174
+ contracts: {
175
+ path: string;
176
+ id: string;
177
+ version: string;
178
+ publishedBy: string;
179
+ consumers: string[];
180
+ }[];
181
+ eventsPointer: string;
182
+ }>;
183
+ export type State = z.infer<typeof StateSchema>;
184
+ export interface HydrateContext {
185
+ claudeRules: string;
186
+ state: State;
187
+ task: Task;
188
+ contracts: Map<string, string>;
189
+ }
190
+ /**
191
+ * Phase 1: Hydrate
192
+ *
193
+ * Agent starts. Reads all necessary context from the repository.
194
+ * This is the ONLY state the agent receives - no conversation history.
195
+ *
196
+ * @param taskId - The task ID to hydrate for
197
+ * @param basePath - Root of the FORGE project
198
+ * @returns Hydration context with all necessary artifacts
199
+ */
200
+ export declare function hydrate(taskId: string, basePath?: string): Promise<HydrateContext>;
201
+ /**
202
+ * Phase 2: Execute
203
+ *
204
+ * Agent writes code, runs tests within its domain.
205
+ * This is where the actual work happens.
206
+ *
207
+ * Note: This function is a placeholder - the actual execution
208
+ * is done by the agent teammate. We just provide the isolation
209
+ * context (worktree) and validation (allowedPaths).
210
+ *
211
+ * @param taskId - The task ID being executed
212
+ * @param basePath - Root of the FORGE project
213
+ * @returns Path to the worktree for execution
214
+ */
215
+ export declare function execute(taskId: string, basePath?: string): Promise<string>;
216
+ /**
217
+ * Validate that files are within allowed paths for a task.
218
+ *
219
+ * Enforces the CODEOWNERS boundary - agents can only write
220
+ * within their assigned domain.
221
+ *
222
+ * @param files - Files to validate
223
+ * @param allowedPaths - Allowed path patterns
224
+ * @throws Error if any file is out of scope
225
+ */
226
+ export declare function validateScope(files: string[], allowedPaths: string[]): void;
227
+ /**
228
+ * Phase 3: Commit
229
+ *
230
+ * Atomic git commit linked to task ID.
231
+ * Every task MUST result in exactly one commit.
232
+ *
233
+ * Format: type(scope): description
234
+ * Example: feat(api-003): implement session authentication
235
+ *
236
+ * @param taskId - The task ID
237
+ * @param message - Commit message (will be formatted)
238
+ * @param basePath - Root of the FORGE project
239
+ * @returns The commit hash
240
+ */
241
+ export declare function commitTask(taskId: string, message: string, basePath?: string): Promise<string>;
242
+ /**
243
+ * Phase 4: Terminate
244
+ *
245
+ * Session ends. Context is wiped clean.
246
+ * The agent's conversation history is discarded.
247
+ *
248
+ * Note: In Agent Teams, this happens naturally when the agent
249
+ * exits. We just need to ensure the worktree is cleaned up.
250
+ *
251
+ * @param taskId - The task ID
252
+ * @param keepWorktree - Whether to keep the worktree (for debugging)
253
+ */
254
+ export declare function terminate(taskId: string, keepWorktree?: boolean): Promise<void>;
255
+ /**
256
+ * Phase 5: Reincarnate
257
+ *
258
+ * Next task starts with fresh context, reading the NEW git state.
259
+ *
260
+ * This happens naturally when a new agent spawns - they start
261
+ * with a fresh context window and hydrate() to read current state.
262
+ *
263
+ * @param nextTaskId - The next task ID to work on
264
+ * @param basePath - Root of the FORGE project
265
+ * @returns Hydration context for the next task
266
+ */
267
+ export declare function reincarnate(nextTaskId: string, basePath?: string): Promise<HydrateContext>;
268
+ /**
269
+ * Execute the full Wipe Protocol lifecycle for a task.
270
+ *
271
+ * This is the main entry point that orchestrates all phases.
272
+ * Note that phases 2 (execute) and 4 (terminate) happen
273
+ * externally - this just sets up and tears down.
274
+ *
275
+ * @param taskId - The task ID to execute
276
+ * @param workCallback - Async function that does the actual work
277
+ * @param basePath - Root of the FORGE project
278
+ * @returns Commit hash from the completed task
279
+ */
280
+ export declare function runWipeProtocol(taskId: string, workCallback: (worktreePath: string) => Promise<string>, basePath?: string): Promise<string>;
281
+ //# sourceMappingURL=wipe-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wipe-protocol.d.ts","sourceRoot":"","sources":["../../src/git/wipe-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYrB,CAAC;AAEH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkBtB,CAAC;AAEH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,KAAK,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;;;;;;;;;GASG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAoC,GAAG,OAAO,CAAC,cAAc,CAAC,CAoCrH;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAoC,GAAG,OAAO,CAAC,MAAM,CAAC,CAY7G;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAgB3E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,MAAoC,GAC7C,OAAO,CAAC,MAAM,CAAC,CAmBjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5F;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,QAAQ,GAAE,MAAoC,GAC7C,OAAO,CAAC,cAAc,CAAC,CAGzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EACvD,QAAQ,GAAE,MAAoC,GAC7C,OAAO,CAAC,MAAM,CAAC,CAuBjB"}
@@ -0,0 +1,237 @@
1
+ /**
2
+ * The Wipe Protocol - Context Hygiene for FORGE
3
+ *
4
+ * Treats agent context as ephemeral, git as persistent.
5
+ *
6
+ * Lifecycle:
7
+ * 1. Hydrate — Agent starts, reads CLAUDE.md + STATE.json + assigned task + contracts
8
+ * 2. Execute — Agent writes code, runs tests within its domain
9
+ * 3. Commit — Atomic git commit linked to task ID
10
+ * 4. Terminate — Session ends, context wiped
11
+ * 5. Reincarnate — Next task starts with fresh context, reads NEW git state
12
+ */
13
+ import { readFile } from "node:fs/promises";
14
+ import { join } from "node:path";
15
+ import { z } from "zod";
16
+ import { createWorktree, getWorktree, cleanupWorktree } from "./worktree.js";
17
+ // Schemas for FORGE artifacts
18
+ export const TaskSchema = z.object({
19
+ id: z.string(),
20
+ title: z.string(),
21
+ ownerRole: z.string(),
22
+ status: z.enum(["pending", "in_progress", "completed", "blocked"]),
23
+ deps: z.array(z.string()),
24
+ allowedPaths: z.array(z.string()),
25
+ acceptance: z.array(z.string()),
26
+ verify: z.array(z.string()),
27
+ commit: z.string().nullable(),
28
+ requests: z.array(z.string()),
29
+ priority: z.number(),
30
+ });
31
+ export const StateSchema = z.object({
32
+ project: z.object({
33
+ name: z.string(),
34
+ status: z.string(),
35
+ currentMilestone: z.string(),
36
+ currentPhase: z.number(),
37
+ }),
38
+ tasks: z.array(TaskSchema),
39
+ contracts: z.array(z.object({
40
+ id: z.string(),
41
+ path: z.string(),
42
+ version: z.string(),
43
+ publishedBy: z.string(),
44
+ consumers: z.array(z.string()),
45
+ })),
46
+ eventsPointer: z.string(),
47
+ });
48
+ /**
49
+ * Phase 1: Hydrate
50
+ *
51
+ * Agent starts. Reads all necessary context from the repository.
52
+ * This is the ONLY state the agent receives - no conversation history.
53
+ *
54
+ * @param taskId - The task ID to hydrate for
55
+ * @param basePath - Root of the FORGE project
56
+ * @returns Hydration context with all necessary artifacts
57
+ */
58
+ export async function hydrate(taskId, basePath = "/home/parz/projects/forge") {
59
+ // Read STATE.json to get task information
60
+ const statePath = join(basePath, "state", "STATE.json");
61
+ const stateRaw = await readFile(statePath, "utf-8");
62
+ const state = StateSchema.parse(JSON.parse(stateRaw));
63
+ // Find the assigned task
64
+ const task = state.tasks.find((t) => t.id === taskId);
65
+ if (!task) {
66
+ throw new Error(`Task ${taskId} not found in STATE.json`);
67
+ }
68
+ // Read CLAUDE.md - the project constitution
69
+ const claudePath = join(basePath, "CLAUDE.md");
70
+ let claudeRules = "";
71
+ try {
72
+ claudeRules = await readFile(claudePath, "utf-8");
73
+ }
74
+ catch {
75
+ // CLAUDE.md might not exist yet in early phases
76
+ claudeRules = "# CLAUDE.md\n\nNo project rules defined yet.";
77
+ }
78
+ // Read contract files referenced by the task
79
+ const contracts = new Map();
80
+ const contractsPath = join(basePath, "contracts");
81
+ // If task references specific contracts, load them
82
+ // This would be populated from task.contracts field
83
+ // For now, we just check if contracts directory exists
84
+ return {
85
+ claudeRules,
86
+ state,
87
+ task,
88
+ contracts,
89
+ };
90
+ }
91
+ /**
92
+ * Phase 2: Execute
93
+ *
94
+ * Agent writes code, runs tests within its domain.
95
+ * This is where the actual work happens.
96
+ *
97
+ * Note: This function is a placeholder - the actual execution
98
+ * is done by the agent teammate. We just provide the isolation
99
+ * context (worktree) and validation (allowedPaths).
100
+ *
101
+ * @param taskId - The task ID being executed
102
+ * @param basePath - Root of the FORGE project
103
+ * @returns Path to the worktree for execution
104
+ */
105
+ export async function execute(taskId, basePath = "/home/parz/projects/forge") {
106
+ // Check if worktree already exists (resuming from pause)
107
+ const existing = await getWorktree(taskId);
108
+ if (existing) {
109
+ return existing.path;
110
+ }
111
+ // Create new worktree for this task
112
+ const worktreePath = await createWorktree({ taskId });
113
+ // Return absolute path to worktree
114
+ return join(basePath, worktreePath);
115
+ }
116
+ /**
117
+ * Validate that files are within allowed paths for a task.
118
+ *
119
+ * Enforces the CODEOWNERS boundary - agents can only write
120
+ * within their assigned domain.
121
+ *
122
+ * @param files - Files to validate
123
+ * @param allowedPaths - Allowed path patterns
124
+ * @throws Error if any file is out of scope
125
+ */
126
+ export function validateScope(files, allowedPaths) {
127
+ for (const file of files) {
128
+ const isAllowed = allowedPaths.some((pattern) => {
129
+ // Simple glob matching - converts gitignore-style patterns to regex
130
+ const regexPattern = pattern
131
+ .replace(/\*\*/g, ".*")
132
+ .replace(/\*/g, "[^/]*")
133
+ .replace(/\?/g, "[^/]");
134
+ const regex = new RegExp(`^${regexPattern}`);
135
+ return regex.test(file);
136
+ });
137
+ if (!isAllowed) {
138
+ throw new Error(`File ${file} is outside allowed paths: ${allowedPaths.join(", ")}`);
139
+ }
140
+ }
141
+ }
142
+ /**
143
+ * Phase 3: Commit
144
+ *
145
+ * Atomic git commit linked to task ID.
146
+ * Every task MUST result in exactly one commit.
147
+ *
148
+ * Format: type(scope): description
149
+ * Example: feat(api-003): implement session authentication
150
+ *
151
+ * @param taskId - The task ID
152
+ * @param message - Commit message (will be formatted)
153
+ * @param basePath - Root of the FORGE project
154
+ * @returns The commit hash
155
+ */
156
+ export async function commitTask(taskId, message, basePath = "/home/parz/projects/forge") {
157
+ const { execa } = await import("execa");
158
+ // Format the commit message to include task ID
159
+ const formattedMessage = message.includes(taskId)
160
+ ? message
161
+ : `feat(${taskId}): ${message}`;
162
+ // Stage all changes in the worktree
163
+ await execa("git", ["add", "-A"], { cwd: join(basePath, `.worktrees/${taskId}`) });
164
+ // Commit with formatted message
165
+ const { stdout } = await execa("git", ["commit", "-m", formattedMessage], {
166
+ cwd: join(basePath, `.worktrees/${taskId}`),
167
+ });
168
+ // Extract commit hash from output
169
+ const commitHash = stdout.match(/\[([a-f0-9]+)\]/)?.[1] || "";
170
+ return commitHash;
171
+ }
172
+ /**
173
+ * Phase 4: Terminate
174
+ *
175
+ * Session ends. Context is wiped clean.
176
+ * The agent's conversation history is discarded.
177
+ *
178
+ * Note: In Agent Teams, this happens naturally when the agent
179
+ * exits. We just need to ensure the worktree is cleaned up.
180
+ *
181
+ * @param taskId - The task ID
182
+ * @param keepWorktree - Whether to keep the worktree (for debugging)
183
+ */
184
+ export async function terminate(taskId, keepWorktree = false) {
185
+ if (!keepWorktree) {
186
+ await cleanupWorktree(taskId);
187
+ }
188
+ }
189
+ /**
190
+ * Phase 5: Reincarnate
191
+ *
192
+ * Next task starts with fresh context, reading the NEW git state.
193
+ *
194
+ * This happens naturally when a new agent spawns - they start
195
+ * with a fresh context window and hydrate() to read current state.
196
+ *
197
+ * @param nextTaskId - The next task ID to work on
198
+ * @param basePath - Root of the FORGE project
199
+ * @returns Hydration context for the next task
200
+ */
201
+ export async function reincarnate(nextTaskId, basePath = "/home/parz/projects/forge") {
202
+ // Reincarnation is just hydration with fresh context
203
+ return hydrate(nextTaskId, basePath);
204
+ }
205
+ /**
206
+ * Execute the full Wipe Protocol lifecycle for a task.
207
+ *
208
+ * This is the main entry point that orchestrates all phases.
209
+ * Note that phases 2 (execute) and 4 (terminate) happen
210
+ * externally - this just sets up and tears down.
211
+ *
212
+ * @param taskId - The task ID to execute
213
+ * @param workCallback - Async function that does the actual work
214
+ * @param basePath - Root of the FORGE project
215
+ * @returns Commit hash from the completed task
216
+ */
217
+ export async function runWipeProtocol(taskId, workCallback, basePath = "/home/parz/projects/forge") {
218
+ // Phase 1: Hydrate
219
+ const context = await hydrate(taskId, basePath);
220
+ // Phase 2: Execute (setup worktree, call the worker)
221
+ const worktreePath = await execute(taskId, basePath);
222
+ try {
223
+ // Run the actual work (writes code, runs tests)
224
+ const commitMessage = await workCallback(worktreePath);
225
+ // Phase 3: Commit
226
+ const commitHash = await commitTask(taskId, commitMessage, basePath);
227
+ // Phase 4: Terminate (cleanup)
228
+ await terminate(taskId);
229
+ return commitHash;
230
+ }
231
+ catch (error) {
232
+ // On error, keep worktree for debugging
233
+ await terminate(taskId, true);
234
+ throw error;
235
+ }
236
+ }
237
+ //# sourceMappingURL=wipe-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wipe-protocol.js","sourceRoot":"","sources":["../../src/git/wipe-protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Git Worktree Management for FORGE
3
+ *
4
+ * Implements isolated worktree strategy for parallel agent execution.
5
+ * Each task gets its own worktree to prevent merge conflicts during development.
6
+ *
7
+ * Commands (from FORGE spec):
8
+ * - git worktree add .worktrees/{taskId} -b forge/{taskId}
9
+ * - git worktree remove .worktrees/{taskId}
10
+ */
11
+ export interface WorktreeOptions {
12
+ taskId: string;
13
+ branchName?: string;
14
+ baseBranch?: string;
15
+ }
16
+ export interface WorktreeInfo {
17
+ taskId: string;
18
+ branchName: string;
19
+ path: string;
20
+ commit: string;
21
+ }
22
+ export declare class WorktreeError extends Error {
23
+ readonly code?: string | undefined;
24
+ constructor(message: string, code?: string | undefined);
25
+ }
26
+ /**
27
+ * Create a new git worktree for a task.
28
+ *
29
+ * Creates a branch `forge/{taskId}` and checks it out into `.worktrees/{taskId}`.
30
+ * This gives each agent an isolated filesystem to work in.
31
+ *
32
+ * @param options - Task identification and branch configuration
33
+ * @returns Path to the new worktree
34
+ * @throws WorktreeError if worktree creation fails
35
+ */
36
+ export declare function createWorktree(options: WorktreeOptions): Promise<string>;
37
+ /**
38
+ * Get information about a worktree.
39
+ *
40
+ * @param taskId - Task ID to look up
41
+ * @returns Worktree information or null if not found
42
+ */
43
+ export declare function getWorktree(taskId: string): Promise<WorktreeInfo | null>;
44
+ /**
45
+ * Merge a worktree's branch back into the base branch.
46
+ *
47
+ * Should only be called after CI passes. The worktree is removed after merge.
48
+ *
49
+ * @param taskId - Task ID whose branch to merge
50
+ * @param targetBranch - Branch to merge into (default: main)
51
+ * @throws WorktreeError if merge fails or has conflicts
52
+ */
53
+ export declare function mergeWorktree(taskId: string, targetBranch?: string): Promise<void>;
54
+ /**
55
+ * Remove a worktree.
56
+ *
57
+ * Safely removes the worktree after cleaning up any uncommitted changes.
58
+ *
59
+ * @param taskId - Task ID whose worktree to remove
60
+ * @throws WorktreeError if removal fails
61
+ */
62
+ export declare function cleanupWorktree(taskId: string): Promise<void>;
63
+ /**
64
+ * List all FORGE worktrees.
65
+ *
66
+ * @returns Array of worktree information for all active tasks
67
+ */
68
+ export declare function listWorktrees(): Promise<WorktreeInfo[]>;
69
+ //# sourceMappingURL=worktree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/git/worktree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,aAAc,SAAQ,KAAK;aACO,IAAI,CAAC,EAAE,MAAM;gBAA9C,OAAO,EAAE,MAAM,EAAkB,IAAI,CAAC,EAAE,MAAM,YAAA;CAI3D;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAqB9E;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAyC9E;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,YAAY,GAAE,MAAe,GAC5B,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBnE;AAED;;;;GAIG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CA4C7D"}