@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warpgogol/forge",
3
- "version": "2.21.0",
3
+ "version": "2.21.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -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
@@ -43,6 +43,7 @@ export {
43
43
  writeFileAtomic,
44
44
  type WriteFileAtomicOptions,
45
45
  GENERATED_MARKER,
46
+ EDITABLE_GENERATED_MARKER,
46
47
  hasGeneratedMarker,
47
48
  stripGeneratedMarker,
48
49
  buildGeneratedHeader,
@@ -266,6 +266,7 @@ export async function runAgentsGenerate(
266
266
  filePath: "AGENTS.md",
267
267
  ownerCommand: "forge.agents.generate",
268
268
  commandPrefix: "forge",
269
+ editable: true,
269
270
  });
270
271
 
271
272
  // RFC-0643: determine register from PREFERENCES.md or profile
@@ -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(`> Do not edit by handre-run \`forge agents generate\` to regenerate.`);
204
+ lines.push(`> It is a living documentedit 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
- > Do not edit by hand — edit `forge.yaml` and regenerate.
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
- > Do not edit by hand — edit `forge.yaml` and regenerate.
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. Do not change this line unless the file contains project specific changes.
3
- DO NOT EDIT THIS FILE. Changes are overwritten on the next build.
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
- > Do not edit by hand — edit `forge.yaml` and regenerate.
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
- applyAll([
50
- new RegExp(`<!--[ \\t]*\\n[\\s\\S]*?${escapeRegex(raw)}[\\s\\S]*?-->\\n?`, "g"),
51
- new RegExp(`/\\*[ \\t]*\\n[\\s\\S]*?${escapeRegex(raw)}[\\s\\S]*?\\*/\\n?`, "g"),
52
- ]);
53
-
54
- for (const token of ["//", "#"]) {
55
- const t = escapeRegex(token);
56
- const advisoryLine = (suffix: string): string => `(?:[ \\t]*${t}[ \\t]*${suffix}\\n)?`;
57
- const pattern = new RegExp(
58
- `^[ \\t]*${t}[ \\t]*${escapeRegex(raw)}\\n` +
59
- advisoryLine(escapeRegex(DO_NOT_EDIT_LINE)) +
60
- advisoryLine("Owner command:.*") +
61
- advisoryLine("Edit instead:.*") +
62
- advisoryLine("Regenerate:.*"),
63
- "gm",
64
- );
65
- applyAll([pattern]);
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
- applyAll([
69
- new RegExp(`^\\s*<!--\\s*${escapeRegex(raw)}\\s*-->\\n?`, "gm"),
70
- new RegExp(`^\\s*//\\s*${escapeRegex(raw)}\\n?`, "gm"),
71
- new RegExp(`^\\s*/\\*\\s*${escapeRegex(raw)}\\s*\\*/\\n?`, "gm"),
72
- new RegExp(`^\\s*#\\s*${escapeRegex(raw)}\\n?`, "gm"),
73
- new RegExp(`^\\s*${escapeRegex(raw)}\\n?`, "gm"),
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
- if (result.includes(raw)) {
77
- const next = result.split(raw).join("");
78
- if (next !== result) {
79
- changed = true;
80
- result = next;
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
- GENERATED_MARKER,
131
- DO_NOT_EDIT_LINE,
149
+ marker,
150
+ advisoryLine,
132
151
  `Owner command: ${input.ownerCommand}`,
133
152
  editInstead,
134
153
  `Regenerate: ${regenerateCommand}`,
@@ -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,