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.
- package/.claude/rules/api-patterns.md +98 -0
- package/.claude/rules/security-baseline.md +204 -0
- package/.claude/rules/testing-standards.md +177 -0
- package/.claude/rules/ui-conventions.md +142 -0
- package/README.md +261 -0
- package/bin/forge.js +14 -0
- package/dist/bin/forge.js +14 -0
- package/dist/cli/index.d.ts +22 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +116 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/base.d.ts +31 -0
- package/dist/commands/base.d.ts.map +1 -0
- package/dist/commands/base.js +31 -0
- package/dist/commands/base.js.map +1 -0
- package/dist/commands/config.d.ts +14 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +175 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/generate.d.ts +17 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +159 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/help.d.ts +11 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +65 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/index.d.ts +8 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +8 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +10 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +22 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/status.d.ts +13 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +101 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stubs.d.ts +14 -0
- package/dist/commands/stubs.d.ts.map +1 -0
- package/dist/commands/stubs.js +30 -0
- package/dist/commands/stubs.js.map +1 -0
- package/dist/generators/index.d.ts +11 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +10 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/generators/required-fields.d.ts +74 -0
- package/dist/generators/required-fields.d.ts.map +1 -0
- package/dist/generators/required-fields.js +179 -0
- package/dist/generators/required-fields.js.map +1 -0
- package/dist/generators/template-engine.d.ts +65 -0
- package/dist/generators/template-engine.d.ts.map +1 -0
- package/dist/generators/template-engine.js +209 -0
- package/dist/generators/template-engine.js.map +1 -0
- package/dist/generators/token-validator.d.ts +51 -0
- package/dist/generators/token-validator.d.ts.map +1 -0
- package/dist/generators/token-validator.js +141 -0
- package/dist/generators/token-validator.js.map +1 -0
- package/dist/generators/types.d.ts +433 -0
- package/dist/generators/types.d.ts.map +1 -0
- package/dist/generators/types.js +5 -0
- package/dist/generators/types.js.map +1 -0
- package/dist/generators/xml-task-generator.d.ts +67 -0
- package/dist/generators/xml-task-generator.d.ts.map +1 -0
- package/dist/generators/xml-task-generator.js +297 -0
- package/dist/generators/xml-task-generator.js.map +1 -0
- package/dist/git/__tests__/worktree.test.d.ts +5 -0
- package/dist/git/__tests__/worktree.test.d.ts.map +1 -0
- package/dist/git/__tests__/worktree.test.js +121 -0
- package/dist/git/__tests__/worktree.test.js.map +1 -0
- package/dist/git/codeowners.d.ts +101 -0
- package/dist/git/codeowners.d.ts.map +1 -0
- package/dist/git/codeowners.js +216 -0
- package/dist/git/codeowners.js.map +1 -0
- package/dist/git/commit.d.ts +135 -0
- package/dist/git/commit.d.ts.map +1 -0
- package/dist/git/commit.js +223 -0
- package/dist/git/commit.js.map +1 -0
- package/dist/git/hooks/commit-msg.d.ts +8 -0
- package/dist/git/hooks/commit-msg.d.ts.map +1 -0
- package/dist/git/hooks/commit-msg.js +34 -0
- package/dist/git/hooks/commit-msg.js.map +1 -0
- package/dist/git/hooks/pre-commit.d.ts +8 -0
- package/dist/git/hooks/pre-commit.d.ts.map +1 -0
- package/dist/git/hooks/pre-commit.js +34 -0
- package/dist/git/hooks/pre-commit.js.map +1 -0
- package/dist/git/pre-commit-hooks.d.ts +117 -0
- package/dist/git/pre-commit-hooks.d.ts.map +1 -0
- package/dist/git/pre-commit-hooks.js +270 -0
- package/dist/git/pre-commit-hooks.js.map +1 -0
- package/dist/git/wipe-protocol.d.ts +281 -0
- package/dist/git/wipe-protocol.d.ts.map +1 -0
- package/dist/git/wipe-protocol.js +237 -0
- package/dist/git/wipe-protocol.js.map +1 -0
- package/dist/git/worktree.d.ts +69 -0
- package/dist/git/worktree.d.ts.map +1 -0
- package/dist/git/worktree.js +202 -0
- package/dist/git/worktree.js.map +1 -0
- package/dist/scripts/install.d.ts +8 -0
- package/dist/scripts/install.d.ts.map +1 -0
- package/dist/scripts/install.js +161 -0
- package/dist/scripts/install.js.map +1 -0
- package/dist/types/config.d.ts +30 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +23 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/state.d.ts +56 -0
- package/dist/types/state.d.ts.map +1 -0
- package/dist/types/state.js +6 -0
- package/dist/types/state.js.map +1 -0
- package/dist/utils/config.d.ts +15 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +80 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/errors.d.ts +25 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +48 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/index.d.ts +11 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +34 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +73 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/state-api.d.ts +128 -0
- package/dist/utils/state-api.d.ts.map +1 -0
- package/dist/utils/state-api.js +170 -0
- package/dist/utils/state-api.js.map +1 -0
- package/dist/utils/template-client.d.ts +73 -0
- package/dist/utils/template-client.d.ts.map +1 -0
- package/dist/utils/template-client.js +151 -0
- package/dist/utils/template-client.js.map +1 -0
- 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"}
|