@warpgogol/forge 2.21.0 → 2.21.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/package.json +1 -1
- package/profiles/root-agents-godot.md +4 -4
- package/src/index.ts +1 -0
- package/src/onboarding/agents-generate.ts +1 -0
- package/src/onboarding/nested-agents-templates.ts +2 -1
- package/src/onboarding/templates/root-agents-business.md +1 -1
- package/src/onboarding/templates/root-agents-creative.md +1 -1
- package/src/tests/fixtures/agents-generate-business-before.txt +3 -3
- package/src/tests/generated-marker.test.ts +14 -0
- package/src/types/werkstatt-engine-shims.d.ts +5 -0
- package/src/utils/generated-marker.ts +55 -36
- package/src/utils/index.ts +1 -0
package/package.json
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
Placeholders: projectName, projectStack, projectPm,
|
|
5
5
|
rfcsDir, adrsDir, plansDir, auditsDir, specsDir,
|
|
6
6
|
skillsDir, dynamicSections -->
|
|
7
|
+
|
|
7
8
|
# Agent Guide: {{projectName}}
|
|
8
9
|
|
|
9
|
-
> This file is generated by `forge.agents.generate` from `forge.yaml`.
|
|
10
|
-
> Do not edit by hand — edit `forge.yaml` and regenerate.
|
|
10
|
+
> This file is generated by `forge.agents.generate` from `forge.yaml`. It is a living document — edit freely to add project-specific guidance.
|
|
11
11
|
|
|
12
12
|
## Project
|
|
13
13
|
|
|
@@ -52,8 +52,7 @@ dotnet build
|
|
|
52
52
|
dotnet test
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
Run the editor or game through the installed Godot .NET binary.
|
|
56
|
-
Do not change the Godot version, .NET SDK, NuGet packages, or project settings without explicit need.
|
|
55
|
+
Run the editor or game through the installed Godot .NET binary. Do not change the Godot version, .NET SDK, NuGet packages, or project settings without explicit need.
|
|
57
56
|
|
|
58
57
|
## C# Rules
|
|
59
58
|
|
|
@@ -103,6 +102,7 @@ Before completing a task:
|
|
|
103
102
|
- When facing an unclear architectural decision, propose options and ask for direction first.
|
|
104
103
|
|
|
105
104
|
{{dynamicSections}}
|
|
105
|
+
|
|
106
106
|
## RTK — Token Optimization
|
|
107
107
|
|
|
108
108
|
Always prefix shell commands with `rtk` to minimize token consumption. RTK filters and compresses command output before it reaches the LLM context, cutting up to 90% of bash output on common operations.
|
package/src/index.ts
CHANGED
|
@@ -184,6 +184,7 @@ export function buildNestedAgentsMd(
|
|
|
184
184
|
filePath: "AGENTS.md",
|
|
185
185
|
ownerCommand: "forge.agents.generate",
|
|
186
186
|
commandPrefix: "forge",
|
|
187
|
+
editable: true,
|
|
187
188
|
});
|
|
188
189
|
|
|
189
190
|
const lines: string[] = [];
|
|
@@ -200,7 +201,7 @@ export function buildNestedAgentsMd(
|
|
|
200
201
|
}
|
|
201
202
|
|
|
202
203
|
lines.push(`> This file is generated by \`forge.agents.generate\`.`);
|
|
203
|
-
lines.push(`>
|
|
204
|
+
lines.push(`> It is a living document — edit freely to add workspace-specific guidance.`);
|
|
204
205
|
lines.push("");
|
|
205
206
|
|
|
206
207
|
lines.push(`**Workspace type:** ${TYPE_LABEL[workspace.type]}`);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# Agent Guide: {{projectName}}
|
|
8
8
|
|
|
9
9
|
> This file is generated by `forge.agents.generate` from `forge.yaml`.
|
|
10
|
-
>
|
|
10
|
+
> It is a living document — edit freely to add project-specific guidance.
|
|
11
11
|
|
|
12
12
|
## Project
|
|
13
13
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# Agent Guide: {{projectName}}
|
|
8
8
|
|
|
9
9
|
> This file is generated by `forge.agents.generate` from `forge.yaml`.
|
|
10
|
-
>
|
|
10
|
+
> It is a living document — edit freely to add project-specific guidance.
|
|
11
11
|
|
|
12
12
|
## Project
|
|
13
13
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
GENERATED.
|
|
3
|
-
|
|
2
|
+
GENERATED. Safe to edit — project-specific changes are expected and encouraged.
|
|
3
|
+
This file is generated but editable — your changes are preserved on regeneration.
|
|
4
4
|
Owner command: forge.agents.generate
|
|
5
5
|
Edit instead: the forge.agents.generate generator source (not this file).
|
|
6
6
|
Regenerate: forge forge.agents.generate
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
# Agent Guide: test-project
|
|
17
17
|
|
|
18
18
|
> This file is generated by `forge.agents.generate` from `forge.yaml`.
|
|
19
|
-
>
|
|
19
|
+
> It is a living document — edit freely to add project-specific guidance.
|
|
20
20
|
|
|
21
21
|
## Project
|
|
22
22
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { test, expect, describe } from "vitest";
|
|
2
2
|
import {
|
|
3
3
|
GENERATED_MARKER,
|
|
4
|
+
EDITABLE_GENERATED_MARKER,
|
|
4
5
|
hasGeneratedMarker,
|
|
5
6
|
stripGeneratedMarker,
|
|
6
7
|
buildGeneratedHeader,
|
|
@@ -141,6 +142,19 @@ describe("buildGeneratedHeader", () => {
|
|
|
141
142
|
});
|
|
142
143
|
expect(header).toContain("Edit instead: templates/foo.ts");
|
|
143
144
|
});
|
|
145
|
+
|
|
146
|
+
test("editable mode uses permissive marker and advisory", () => {
|
|
147
|
+
const header = buildGeneratedHeader({
|
|
148
|
+
filePath: "AGENTS.md",
|
|
149
|
+
ownerCommand: "forge.agents.generate",
|
|
150
|
+
editable: true,
|
|
151
|
+
});
|
|
152
|
+
expect(header).toContain(EDITABLE_GENERATED_MARKER);
|
|
153
|
+
expect(header).not.toContain(GENERATED_MARKER);
|
|
154
|
+
expect(header).not.toContain("DO NOT EDIT");
|
|
155
|
+
expect(header).toContain("Safe to edit");
|
|
156
|
+
expect(header).toContain("editable");
|
|
157
|
+
});
|
|
144
158
|
});
|
|
145
159
|
|
|
146
160
|
describe("isGeneratedMarkerTextCandidate", () => {
|
|
@@ -189,6 +189,7 @@ declare module "@warpgogol/werkstatt-engine/kernel" {
|
|
|
189
189
|
export const WriteFileAtomicOptions: any;
|
|
190
190
|
export const writeFileIfChanged: any;
|
|
191
191
|
export const GENERATED_MARKER: any;
|
|
192
|
+
export const EDITABLE_GENERATED_MARKER: any;
|
|
192
193
|
export const hasGeneratedMarker: any;
|
|
193
194
|
export const stripGeneratedMarker: any;
|
|
194
195
|
export const isGeneratedMarkerTextCandidate: any;
|
|
@@ -301,6 +302,7 @@ declare module "@warpgogol/werkstatt-engine/kernel/generated-marker" {
|
|
|
301
302
|
export function buildGeneratedHeader(...args: any[]): any;
|
|
302
303
|
export function isGeneratedMarkerTextCandidate(...args: any[]): any;
|
|
303
304
|
export const GENERATED_MARKER: any;
|
|
305
|
+
export const EDITABLE_GENERATED_MARKER: any;
|
|
304
306
|
export interface StripGeneratedMarkerResult {}
|
|
305
307
|
export interface GeneratedHeaderInput {}
|
|
306
308
|
}
|
|
@@ -679,6 +681,9 @@ declare module "@warpgogol/werkstatt-engine/release" {
|
|
|
679
681
|
export const BootSmokeRequestResult: any;
|
|
680
682
|
export const planBootSmokeRequests: any;
|
|
681
683
|
export const detectBootSmokeLanguages: any;
|
|
684
|
+
export const resolveWranglerConfig: any;
|
|
685
|
+
export const resolveLanguages: any;
|
|
686
|
+
export const WranglerResolution: any;
|
|
682
687
|
export const simulateBindings: any;
|
|
683
688
|
}
|
|
684
689
|
|
|
@@ -10,14 +10,22 @@ source (dependency inversion).</purpose>
|
|
|
10
10
|
<CHANGE_SUMMARY>
|
|
11
11
|
<item>Moved from @warpgogol/site-kernel/generated-marker to forge as canonical source.</item>
|
|
12
12
|
<item>Added optional commandPrefix to GeneratedHeaderInput — defaults to "forge" for autonomous mode; site-kernel passes "pnpm exec werkstatt run".</item>
|
|
13
|
+
<item>Added editable flag to GeneratedHeaderInput — when true, emits a permissive marker and advisory that encourages agents to edit the file. AGENTS.md files use editable: true; other generated files keep the restrictive marker.</item>
|
|
13
14
|
</CHANGE_SUMMARY>
|
|
14
15
|
*/
|
|
15
16
|
|
|
16
17
|
export const GENERATED_MARKER =
|
|
17
18
|
"GENERATED. Do not change this line unless the file contains project specific changes.";
|
|
18
19
|
|
|
20
|
+
export const EDITABLE_GENERATED_MARKER =
|
|
21
|
+
"GENERATED. Safe to edit — project-specific changes are expected and encouraged.";
|
|
22
|
+
|
|
23
|
+
const DO_NOT_EDIT_LINE = "DO NOT EDIT THIS FILE. Changes are overwritten on the next build.";
|
|
24
|
+
const SAFE_TO_EDIT_LINE =
|
|
25
|
+
"This file is generated but editable — your changes are preserved on regeneration.";
|
|
26
|
+
|
|
19
27
|
export function hasGeneratedMarker(content: string): boolean {
|
|
20
|
-
return content.includes(GENERATED_MARKER);
|
|
28
|
+
return content.includes(GENERATED_MARKER) || content.includes(EDITABLE_GENERATED_MARKER);
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
export interface StripGeneratedMarkerResult {
|
|
@@ -29,10 +37,7 @@ function escapeRegex(str: string): string {
|
|
|
29
37
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
30
38
|
}
|
|
31
39
|
|
|
32
|
-
const DO_NOT_EDIT_LINE = "DO NOT EDIT THIS FILE. Changes are overwritten on the next build.";
|
|
33
|
-
|
|
34
40
|
export function stripGeneratedMarker(content: string): StripGeneratedMarkerResult {
|
|
35
|
-
const raw = GENERATED_MARKER;
|
|
36
41
|
let result = content;
|
|
37
42
|
let changed = false;
|
|
38
43
|
|
|
@@ -46,38 +51,43 @@ export function stripGeneratedMarker(content: string): StripGeneratedMarkerResul
|
|
|
46
51
|
}
|
|
47
52
|
};
|
|
48
53
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
])
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
54
|
+
for (const [raw, advisory] of [
|
|
55
|
+
[GENERATED_MARKER, DO_NOT_EDIT_LINE],
|
|
56
|
+
[EDITABLE_GENERATED_MARKER, SAFE_TO_EDIT_LINE],
|
|
57
|
+
] as const) {
|
|
58
|
+
applyAll([
|
|
59
|
+
new RegExp(`<!--[ \\t]*\\n[\\s\\S]*?${escapeRegex(raw)}[\\s\\S]*?-->\\n?`, "g"),
|
|
60
|
+
new RegExp(`/\\*[ \\t]*\\n[\\s\\S]*?${escapeRegex(raw)}[\\s\\S]*?\\*/\\n?`, "g"),
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
for (const token of ["//", "#"]) {
|
|
64
|
+
const t = escapeRegex(token);
|
|
65
|
+
const advisoryLine = (suffix: string): string => `(?:[ \\t]*${t}[ \\t]*${suffix}\\n)?`;
|
|
66
|
+
const pattern = new RegExp(
|
|
67
|
+
`^[ \\t]*${t}[ \\t]*${escapeRegex(raw)}\\n` +
|
|
68
|
+
advisoryLine(escapeRegex(advisory)) +
|
|
69
|
+
advisoryLine("Owner command:.*") +
|
|
70
|
+
advisoryLine("Edit instead:.*") +
|
|
71
|
+
advisoryLine("Regenerate:.*"),
|
|
72
|
+
"gm",
|
|
73
|
+
);
|
|
74
|
+
applyAll([pattern]);
|
|
75
|
+
}
|
|
67
76
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
applyAll([
|
|
78
|
+
new RegExp(`^\\s*<!--\\s*${escapeRegex(raw)}\\s*-->\\n?`, "gm"),
|
|
79
|
+
new RegExp(`^\\s*//\\s*${escapeRegex(raw)}\\n?`, "gm"),
|
|
80
|
+
new RegExp(`^\\s*/\\*\\s*${escapeRegex(raw)}\\s*\\*/\\n?`, "gm"),
|
|
81
|
+
new RegExp(`^\\s*#\\s*${escapeRegex(raw)}\\n?`, "gm"),
|
|
82
|
+
new RegExp(`^\\s*${escapeRegex(raw)}\\n?`, "gm"),
|
|
83
|
+
]);
|
|
75
84
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
if (result.includes(raw)) {
|
|
86
|
+
const next = result.split(raw).join("");
|
|
87
|
+
if (next !== result) {
|
|
88
|
+
changed = true;
|
|
89
|
+
result = next;
|
|
90
|
+
}
|
|
81
91
|
}
|
|
82
92
|
}
|
|
83
93
|
|
|
@@ -94,6 +104,12 @@ export interface GeneratedHeaderInput {
|
|
|
94
104
|
* Site-kernel callers pass "pnpm exec werkstatt run" for Warpgogol context.
|
|
95
105
|
*/
|
|
96
106
|
commandPrefix?: string;
|
|
107
|
+
/**
|
|
108
|
+
* When true, emits a permissive marker and advisory lines that encourage agents
|
|
109
|
+
* to edit the file. Used for AGENTS.md files that are generated but should be
|
|
110
|
+
* freely editable by agents working on the project. Defaults to false.
|
|
111
|
+
*/
|
|
112
|
+
editable?: boolean;
|
|
97
113
|
}
|
|
98
114
|
|
|
99
115
|
type GeneratedHeaderCommentStyle = "line-slash" | "line-hash" | "block-html" | "block-css";
|
|
@@ -119,6 +135,9 @@ function commentStyleForPath(filePath: string): GeneratedHeaderCommentStyle {
|
|
|
119
135
|
export function buildGeneratedHeader(input: GeneratedHeaderInput): string {
|
|
120
136
|
const style = commentStyleForPath(input.filePath);
|
|
121
137
|
const prefix = input.commandPrefix ?? "forge";
|
|
138
|
+
const editable = input.editable ?? false;
|
|
139
|
+
const marker = editable ? EDITABLE_GENERATED_MARKER : GENERATED_MARKER;
|
|
140
|
+
const advisoryLine = editable ? SAFE_TO_EDIT_LINE : DO_NOT_EDIT_LINE;
|
|
122
141
|
const regenerateCommand = input.site
|
|
123
142
|
? `${prefix} ${input.ownerCommand} --site ${input.site}`
|
|
124
143
|
: `${prefix} ${input.ownerCommand}`;
|
|
@@ -127,8 +146,8 @@ export function buildGeneratedHeader(input: GeneratedHeaderInput): string {
|
|
|
127
146
|
: `Edit instead: the ${input.ownerCommand} generator source (not this file).`;
|
|
128
147
|
|
|
129
148
|
const lines = [
|
|
130
|
-
|
|
131
|
-
|
|
149
|
+
marker,
|
|
150
|
+
advisoryLine,
|
|
132
151
|
`Owner command: ${input.ownerCommand}`,
|
|
133
152
|
editInstead,
|
|
134
153
|
`Regenerate: ${regenerateCommand}`,
|
package/src/utils/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export { writeFileAtomic, type WriteFileAtomicOptions } from "./fs-atomic.ts";
|
|
|
15
15
|
export { writeFileIfChanged } from "./fs-idempotent.ts";
|
|
16
16
|
export {
|
|
17
17
|
GENERATED_MARKER,
|
|
18
|
+
EDITABLE_GENERATED_MARKER,
|
|
18
19
|
hasGeneratedMarker,
|
|
19
20
|
stripGeneratedMarker,
|
|
20
21
|
buildGeneratedHeader,
|