@ipul-labs/forge 1.15.0 → 1.15.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": "@ipul-labs/forge",
3
- "version": "1.15.0",
3
+ "version": "1.15.1",
4
4
  "description": "AI-powered code change & deploy control panel — connects Claude, GitLab, and Kubernetes",
5
5
  "type": "module",
6
6
  "main": "server/forge/routes.js",
@@ -438,6 +438,7 @@ export class ForgeAgent {
438
438
  title: mrTitle,
439
439
  explanation,
440
440
  changes,
441
+ removals = [],
441
442
  cost: cost2 = 0,
442
443
  inputTokens: it2 = 0,
443
444
  outputTokens: ot2 = 0,
@@ -451,6 +452,12 @@ export class ForgeAgent {
451
452
  type: "log",
452
453
  message: `Proposed ${enrichedChanges.length} change(s): ${enrichedChanges.map((c) => `${c.repo}:${c.file} (${c.action})`).join(", ")}`,
453
454
  });
455
+ if (removals.length > 0) {
456
+ emit({
457
+ type: "log",
458
+ message: `⚠ ${removals.length} removal(s) declared: ${removals.map((r) => `${r.file}: ${r.what}`).join("; ")}`,
459
+ });
460
+ }
454
461
 
455
462
  const result = {
456
463
  issue,
@@ -458,6 +465,7 @@ export class ForgeAgent {
458
465
  explanation,
459
466
  reasoning,
460
467
  changes: enrichedChanges,
468
+ removals,
461
469
  repos: this.allRepos,
462
470
  };
463
471
  emit({ type: "result", data: result });
@@ -307,22 +307,29 @@ ${ciContext.trim()}`
307
307
  ? `"feat: add browseable mixes section with platinum-gated publishing"`
308
308
  : `"fix: resolve token refresh race condition in AuthService"`;
309
309
 
310
+ const collateralGuard = `COLLATERAL DAMAGE GUARD — read BEFORE writing any "proposed" content:
311
+ Your default when modifying a file is to PRESERVE every existing line that is not directly related to the issue. Do not silently remove, reorganize, or simplify wrapper elements, imports, sibling components, or unrelated UI features (version displays, badges, icons, etc.).
312
+ If you believe existing code MUST be removed or restructured for the change to work, you MUST declare each removal in the top-level "removals" array. Each entry needs: the file path, a short description of what was removed, and why the removal is necessary. An empty "removals" array (or omitting it) means "I preserved everything unrelated."
313
+ The reviewer will see these as warnings and must acknowledge them before the change can be committed — so never silently drop existing functionality.`;
314
+
310
315
  const discipline = isFeature
311
316
  ? `Feature implementation rules (read BEFORE writing any change):
312
317
  1. Follow the issue specification precisely. If the issue says to modify a specific file, modify that file. If it says to create a new file, create it. Do NOT invent changes the issue doesn't ask for.
313
318
  2. When the issue references existing components or patterns to reuse, base your implementation on the existing patterns in the "Relevant files" section.
314
319
  3. For new files, follow the naming conventions, import style, and structure of the existing codebase.
315
320
  4. Be aware of existing routes, tabs, and UI sections that may OVERLAP with what you're implementing. If the issue creates a new "/mixes" route, check whether the codebase already has mixes-related UI elsewhere (e.g. a tab inside another page) and note any conflict in "explanation".
316
- 5. In your "explanation", state (a) which existing patterns you followed, (b) what new files you created, and (c) any conflicts or considerations the reviewer should know about.`
321
+ 5. In your "explanation", state (a) which existing patterns you followed, (b) what new files you created, and (c) any conflicts or considerations the reviewer should know about.
322
+ 6. ${collateralGuard}`
317
323
  : `Root-cause discipline (read BEFORE writing any change):
318
324
  1. Identify the ORIGIN of the bad value, not just where it's observed. If a guard, assertion, or validation is failing, trace the value one or two frames up and name the caller that produced the bad input.
319
325
  2. A fix that only makes an error message clearer (e.g. replacing \`assertIsDefined(x)\` with \`if (!x) toast.error(…)\`) is NOT a fix — it is a symptom suppressor. Reject it and propose the upstream fix instead.
320
326
  3. In your "explanation", state (a) where the bad value originates, (b) why the fix closes the reported symptom end-to-end, and (c) what would have to be true for the reported error to still appear after your change.
321
- 4. If the origin is in a file that was not selected in pass 1, your "changes" should include that file. Do not constrain yourself to only the files listed under "Relevant files" when doing so would force a symptom-level patch.`;
327
+ 4. If the origin is in a file that was not selected in pass 1, your "changes" should include that file. Do not constrain yourself to only the files listed under "Relevant files" when doing so would force a symptom-level patch.
328
+ 5. ${collateralGuard}`;
322
329
 
323
330
  return `Respond with ONLY a raw JSON object — no markdown, no prose, no code fences.
324
331
 
325
- Schema: {"title": "${titlePrefix}: concise description of the actual change (max 72 chars)", "explanation": "...", "changes": [{"repo": "<repo id>", "file": "...", "action": "modify|create|delete", "proposed": "<full file content>", "summary": "..."}]}
332
+ Schema: {"title": "${titlePrefix}: concise description of the actual change (max 72 chars)", "explanation": "...", "changes": [{"repo": "<repo id>", "file": "...", "action": "modify|create|delete", "proposed": "<full file content>", "summary": "..."}], "removals": [{"file": "...", "what": "short description of removed code", "why": "reason this removal is necessary"}]}
326
333
 
327
334
  ${isFeature ? "Implement this feature." : "Propose a targeted fix for this issue."}
328
335