forge-cc 1.0.0 → 1.0.2
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/dist/cli.js +7 -1
- package/dist/cli.js.map +1 -1
- package/package.json +3 -2
- package/dist/gates/codex-gate.d.ts +0 -51
- package/dist/gates/codex-gate.js +0 -121
- package/dist/gates/codex-gate.js.map +0 -1
- package/dist/gates/prd-gate.d.ts +0 -7
- package/dist/gates/prd-gate.js +0 -193
- package/dist/gates/prd-gate.js.map +0 -1
- package/dist/gates/remediation.d.ts +0 -46
- package/dist/gates/remediation.js +0 -423
- package/dist/gates/remediation.js.map +0 -1
- package/dist/gates/review-gate.d.ts +0 -16
- package/dist/gates/review-gate.js +0 -479
- package/dist/gates/review-gate.js.map +0 -1
- package/dist/gates/runtime-gate.d.ts +0 -5
- package/dist/gates/runtime-gate.js +0 -99
- package/dist/gates/runtime-gate.js.map +0 -1
- package/dist/gates/test-analysis.d.ts +0 -21
- package/dist/gates/test-analysis.js +0 -394
- package/dist/gates/test-analysis.js.map +0 -1
- package/dist/gates/visual-capture.d.ts +0 -24
- package/dist/gates/visual-capture.js +0 -144
- package/dist/gates/visual-capture.js.map +0 -1
- package/dist/gates/visual-gate.d.ts +0 -18
- package/dist/gates/visual-gate.js +0 -234
- package/dist/gates/visual-gate.js.map +0 -1
- package/dist/gates/visual-reviewer.d.ts +0 -11
- package/dist/gates/visual-reviewer.js +0 -211
- package/dist/gates/visual-reviewer.js.map +0 -1
- package/dist/go/auto-chain.d.ts +0 -136
- package/dist/go/auto-chain.js +0 -389
- package/dist/go/auto-chain.js.map +0 -1
- package/dist/go/executor.d.ts +0 -137
- package/dist/go/executor.js +0 -447
- package/dist/go/executor.js.map +0 -1
- package/dist/go/finalize.d.ts +0 -108
- package/dist/go/finalize.js +0 -331
- package/dist/go/finalize.js.map +0 -1
- package/dist/go/linear-sync-cli.d.ts +0 -55
- package/dist/go/linear-sync-cli.js +0 -192
- package/dist/go/linear-sync-cli.js.map +0 -1
- package/dist/go/linear-sync.d.ts +0 -112
- package/dist/go/linear-sync.js +0 -375
- package/dist/go/linear-sync.js.map +0 -1
- package/dist/go/prd-queue.d.ts +0 -43
- package/dist/go/prd-queue.js +0 -67
- package/dist/go/prd-queue.js.map +0 -1
- package/dist/go/prd-selector.d.ts +0 -57
- package/dist/go/prd-selector.js +0 -101
- package/dist/go/prd-selector.js.map +0 -1
- package/dist/go/verify-loop.d.ts +0 -64
- package/dist/go/verify-loop.js +0 -327
- package/dist/go/verify-loop.js.map +0 -1
- package/dist/hooks/pre-commit.d.ts +0 -5
- package/dist/hooks/pre-commit.js +0 -75
- package/dist/hooks/pre-commit.js.map +0 -1
- package/dist/linear/issues.d.ts +0 -22
- package/dist/linear/issues.js +0 -51
- package/dist/linear/issues.js.map +0 -1
- package/dist/linear/milestones.d.ts +0 -11
- package/dist/linear/milestones.js +0 -32
- package/dist/linear/milestones.js.map +0 -1
- package/dist/linear/projects.d.ts +0 -16
- package/dist/linear/projects.js +0 -51
- package/dist/linear/projects.js.map +0 -1
- package/dist/reporter/human.d.ts +0 -7
- package/dist/reporter/human.js +0 -93
- package/dist/reporter/human.js.map +0 -1
- package/dist/reporter/json.d.ts +0 -2
- package/dist/reporter/json.js +0 -4
- package/dist/reporter/json.js.map +0 -1
- package/dist/setup/structural-templates.d.ts +0 -12
- package/dist/setup/structural-templates.js +0 -288
- package/dist/setup/structural-templates.js.map +0 -1
- package/dist/setup/templates.d.ts +0 -17
- package/dist/setup/templates.js +0 -109
- package/dist/setup/templates.js.map +0 -1
- package/dist/setup/test-planner.d.ts +0 -38
- package/dist/setup/test-planner.js +0 -91
- package/dist/setup/test-planner.js.map +0 -1
- package/dist/setup/test-scaffold.d.ts +0 -31
- package/dist/setup/test-scaffold.js +0 -209
- package/dist/setup/test-scaffold.js.map +0 -1
- package/dist/setup/test-templates.d.ts +0 -37
- package/dist/setup/test-templates.js +0 -313
- package/dist/setup/test-templates.js.map +0 -1
- package/dist/spec/generator.d.ts +0 -34
- package/dist/spec/generator.js +0 -227
- package/dist/spec/generator.js.map +0 -1
- package/dist/spec/interview.d.ts +0 -142
- package/dist/spec/interview.js +0 -287
- package/dist/spec/interview.js.map +0 -1
- package/dist/spec/linear-sync.d.ts +0 -48
- package/dist/spec/linear-sync.js +0 -125
- package/dist/spec/linear-sync.js.map +0 -1
- package/dist/spec/scanner.d.ts +0 -79
- package/dist/spec/scanner.js +0 -566
- package/dist/spec/scanner.js.map +0 -1
- package/dist/spec/templates.d.ts +0 -375
- package/dist/spec/templates.js +0 -95
- package/dist/spec/templates.js.map +0 -1
- package/dist/state/prd-status.d.ts +0 -62
- package/dist/state/prd-status.js +0 -122
- package/dist/state/prd-status.js.map +0 -1
- package/dist/state/reader.d.ts +0 -7
- package/dist/state/reader.js +0 -43
- package/dist/state/reader.js.map +0 -1
- package/dist/state/writer.d.ts +0 -21
- package/dist/state/writer.js +0 -106
- package/dist/state/writer.js.map +0 -1
- package/dist/team/consensus.d.ts +0 -28
- package/dist/team/consensus.js +0 -130
- package/dist/team/consensus.js.map +0 -1
- package/dist/team/index.d.ts +0 -4
- package/dist/team/index.js +0 -5
- package/dist/team/index.js.map +0 -1
- package/dist/team/lifecycle.d.ts +0 -37
- package/dist/team/lifecycle.js +0 -92
- package/dist/team/lifecycle.js.map +0 -1
- package/dist/team/reviewer.d.ts +0 -10
- package/dist/team/reviewer.js +0 -345
- package/dist/team/reviewer.js.map +0 -1
- package/dist/team/types.d.ts +0 -269
- package/dist/team/types.js +0 -70
- package/dist/team/types.js.map +0 -1
- package/dist/utils/browser.d.ts +0 -10
- package/dist/utils/browser.js +0 -96
- package/dist/utils/browser.js.map +0 -1
- package/dist/utils/platform.d.ts +0 -29
- package/dist/utils/platform.js +0 -90
- package/dist/utils/platform.js.map +0 -1
- package/dist/worktree/identity.d.ts +0 -9
- package/dist/worktree/identity.js +0 -32
- package/dist/worktree/identity.js.map +0 -1
- package/dist/worktree/parallel.d.ts +0 -87
- package/dist/worktree/parallel.js +0 -328
- package/dist/worktree/parallel.js.map +0 -1
- package/dist/worktree/session.d.ts +0 -67
- package/dist/worktree/session.js +0 -194
- package/dist/worktree/session.js.map +0 -1
- package/dist/worktree/state-merge.d.ts +0 -43
- package/dist/worktree/state-merge.js +0 -162
- package/dist/worktree/state-merge.js.map +0 -1
package/dist/go/prd-selector.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PRD Selector — Discovery and Presentation for PRD Picking
|
|
3
|
-
*
|
|
4
|
-
* Wraps the low-level prd-status module to provide higher-level functions
|
|
5
|
-
* for the /forge:go skill's PRD selection UI. Discovers PRDs with pending
|
|
6
|
-
* milestones, formats them for AskUserQuestion pickers, and handles
|
|
7
|
-
* single-PRD auto-selection.
|
|
8
|
-
*/
|
|
9
|
-
import { discoverPRDs } from "../state/prd-status.js";
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
// discoverPendingPRDs
|
|
12
|
-
// ---------------------------------------------------------------------------
|
|
13
|
-
/**
|
|
14
|
-
* Discover all PRDs that have at least one pending milestone.
|
|
15
|
-
*
|
|
16
|
-
* Wraps `discoverPRDs()` from prd-status, filters to those with pending
|
|
17
|
-
* milestones, and computes completion counts for each.
|
|
18
|
-
*/
|
|
19
|
-
export async function discoverPendingPRDs(projectDir) {
|
|
20
|
-
const allPRDs = await discoverPRDs(projectDir);
|
|
21
|
-
const pending = [];
|
|
22
|
-
for (const entry of allPRDs) {
|
|
23
|
-
const milestones = Object.values(entry.status.milestones);
|
|
24
|
-
const totalCount = milestones.length;
|
|
25
|
-
const pendingCount = milestones.filter((m) => m.status === "pending").length;
|
|
26
|
-
const completeCount = milestones.filter((m) => m.status === "complete").length;
|
|
27
|
-
if (pendingCount > 0) {
|
|
28
|
-
pending.push({
|
|
29
|
-
slug: entry.slug,
|
|
30
|
-
project: entry.status.project,
|
|
31
|
-
branch: entry.status.branch,
|
|
32
|
-
pendingCount,
|
|
33
|
-
completeCount,
|
|
34
|
-
totalCount,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return pending;
|
|
39
|
-
}
|
|
40
|
-
// ---------------------------------------------------------------------------
|
|
41
|
-
// presentPRDPicker
|
|
42
|
-
// ---------------------------------------------------------------------------
|
|
43
|
-
/**
|
|
44
|
-
* Format pending PRDs as label/description pairs for AskUserQuestion.
|
|
45
|
-
*
|
|
46
|
-
* Each option shows the project name, branch, and milestone progress.
|
|
47
|
-
* Example label: "forge-agent-teams (2/5 complete)"
|
|
48
|
-
* Example description: "Branch: feat/agent-teams | 3 milestones remaining"
|
|
49
|
-
*/
|
|
50
|
-
export function presentPRDPicker(prds) {
|
|
51
|
-
return prds.map((prd) => ({
|
|
52
|
-
label: `${prd.project} (${prd.completeCount}/${prd.totalCount} complete)`,
|
|
53
|
-
description: `Branch: ${prd.branch} | ${prd.pendingCount} milestone${prd.pendingCount === 1 ? "" : "s"} remaining`,
|
|
54
|
-
}));
|
|
55
|
-
}
|
|
56
|
-
// ---------------------------------------------------------------------------
|
|
57
|
-
// presentModePicker
|
|
58
|
-
// ---------------------------------------------------------------------------
|
|
59
|
-
/**
|
|
60
|
-
* Return the two execution mode options for AskUserQuestion.
|
|
61
|
-
*
|
|
62
|
-
* - "Single milestone" — execute one milestone, then stop for review
|
|
63
|
-
* - "Auto (all milestones)" — chain through all pending milestones
|
|
64
|
-
*/
|
|
65
|
-
export function presentModePicker() {
|
|
66
|
-
return [
|
|
67
|
-
{
|
|
68
|
-
label: "Single milestone",
|
|
69
|
-
description: "Execute the next pending milestone, then stop for review",
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
label: "Auto (all milestones)",
|
|
73
|
-
description: "Chain through all pending milestones with fresh context resets",
|
|
74
|
-
},
|
|
75
|
-
];
|
|
76
|
-
}
|
|
77
|
-
// ---------------------------------------------------------------------------
|
|
78
|
-
// selectPRD
|
|
79
|
-
// ---------------------------------------------------------------------------
|
|
80
|
-
/**
|
|
81
|
-
* Convenience function: discover pending PRDs and auto-select if only one.
|
|
82
|
-
*
|
|
83
|
-
* Returns the selected PRD and whether it was auto-selected (skipping the
|
|
84
|
-
* picker). Returns null if no PRDs have pending milestones.
|
|
85
|
-
*/
|
|
86
|
-
export async function selectPRD(projectDir) {
|
|
87
|
-
const pending = await discoverPendingPRDs(projectDir);
|
|
88
|
-
if (pending.length === 0) {
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
if (pending.length === 1) {
|
|
92
|
-
return { prd: pending[0], autoSelected: true };
|
|
93
|
-
}
|
|
94
|
-
// Multiple PRDs — caller must present the picker and resolve selection.
|
|
95
|
-
// Return the first one with autoSelected: false to signal that the caller
|
|
96
|
-
// should use presentPRDPicker() to let the user choose.
|
|
97
|
-
// The caller is responsible for mapping the user's selection back to the
|
|
98
|
-
// correct PendingPRD from the discoverPendingPRDs() result.
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
//# sourceMappingURL=prd-selector.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prd-selector.js","sourceRoot":"","sources":["../../src/go/prd-selector.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AA8BtD,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,UAAkB;IAElB,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,CAAC;IAE/C,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC1D,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC;QACrC,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CACpC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAC9B,CAAC,MAAM,CAAC;QACT,MAAM,aAAa,GAAG,UAAU,CAAC,MAAM,CACrC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAC/B,CAAC,MAAM,CAAC;QAET,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;gBAC7B,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;gBAC3B,YAAY;gBACZ,aAAa;gBACb,UAAU;aACX,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAkB;IACjD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACxB,KAAK,EAAE,GAAG,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,UAAU,YAAY;QACzE,WAAW,EAAE,WAAW,GAAG,CAAC,MAAM,MAAM,GAAG,CAAC,YAAY,aAAa,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,YAAY;KACnH,CAAC,CAAC,CAAC;AACN,CAAC;AAED,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO;QACL;YACE,KAAK,EAAE,kBAAkB;YACzB,WAAW,EACT,0DAA0D;SAC7D;QACD;YACE,KAAK,EAAE,uBAAuB;YAC9B,WAAW,EACT,gEAAgE;SACnE;KACF,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,UAAkB;IAElB,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAEtD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;IACjD,CAAC;IAED,wEAAwE;IACxE,0EAA0E;IAC1E,wDAAwD;IACxD,yEAAyE;IACzE,4DAA4D;IAC5D,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/go/verify-loop.d.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type { ForgeConfig, GateError, PipelineResult, Finding, TeamReviewResult } from "../types.js";
|
|
2
|
-
import type { BuilderResponse, EscalationDecision } from "../team/consensus.js";
|
|
3
|
-
/** Configuration for team-based review after mechanical gates pass */
|
|
4
|
-
export interface ReviewerConfig {
|
|
5
|
-
projectDir: string;
|
|
6
|
-
prdPath?: string;
|
|
7
|
-
baseBranch?: string;
|
|
8
|
-
/** Callback to get builder responses for findings. The skill drives this via SendMessage. */
|
|
9
|
-
onBuilderResponses?: (findings: Finding[]) => Promise<Map<string, BuilderResponse[]>>;
|
|
10
|
-
/** Callback for unresolved escalations. Executive makes the call. */
|
|
11
|
-
onEscalation?: (findings: Finding[]) => Promise<EscalationDecision[]>;
|
|
12
|
-
}
|
|
13
|
-
/** Options for the self-healing verification loop */
|
|
14
|
-
export interface VerifyLoopOptions {
|
|
15
|
-
projectDir: string;
|
|
16
|
-
config: ForgeConfig;
|
|
17
|
-
/** Override config.maxIterations */
|
|
18
|
-
maxIterations?: number;
|
|
19
|
-
/** Called after each pipeline run with the iteration number and result */
|
|
20
|
-
onIteration?: (iteration: number, result: PipelineResult) => void;
|
|
21
|
-
/**
|
|
22
|
-
* Called when verification fails, giving the caller a chance to fix errors.
|
|
23
|
-
* Returns true if a fix was attempted (loop will re-verify).
|
|
24
|
-
* Returns false or is absent to re-run verification without external fix.
|
|
25
|
-
*/
|
|
26
|
-
onFixAttempt?: (iteration: number, errors: GateError[]) => Promise<boolean>;
|
|
27
|
-
/** Configuration for team-based review after mechanical gates pass */
|
|
28
|
-
reviewerConfig?: ReviewerConfig;
|
|
29
|
-
/** Called when review findings and consensus are complete */
|
|
30
|
-
onReviewComplete?: (reviewResult: TeamReviewResult) => void;
|
|
31
|
-
}
|
|
32
|
-
/** Result from the complete verification loop */
|
|
33
|
-
export interface VerifyLoopResult {
|
|
34
|
-
passed: boolean;
|
|
35
|
-
iterations: number;
|
|
36
|
-
maxIterations: number;
|
|
37
|
-
/** All pipeline results across every iteration */
|
|
38
|
-
results: PipelineResult[];
|
|
39
|
-
/** The last pipeline result */
|
|
40
|
-
finalResult: PipelineResult;
|
|
41
|
-
/** Gate names that still fail after all iterations */
|
|
42
|
-
failedGates: string[];
|
|
43
|
-
/** Human-readable summary of remaining errors */
|
|
44
|
-
errorSummary: string;
|
|
45
|
-
/** Review findings from the team reviewer (only present when reviewerConfig is provided) */
|
|
46
|
-
reviewFindings?: TeamReviewResult;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Self-healing verification loop.
|
|
50
|
-
*
|
|
51
|
-
* Runs the forge verification pipeline, and on failure either invokes the
|
|
52
|
-
* `onFixAttempt` callback (so the caller can spawn a fix agent) or simply
|
|
53
|
-
* re-runs verification. Loops until the pipeline passes or max iterations
|
|
54
|
-
* are exhausted.
|
|
55
|
-
*/
|
|
56
|
-
export declare function runVerifyLoop(options: VerifyLoopOptions): Promise<VerifyLoopResult>;
|
|
57
|
-
/**
|
|
58
|
-
* Format gate errors into a structured prompt for a fix agent.
|
|
59
|
-
*
|
|
60
|
-
* The output is designed to be directly usable in an AI agent prompt:
|
|
61
|
-
* it includes file paths, line numbers, error messages, and remediation
|
|
62
|
-
* hints so the agent can locate and fix issues without extra searching.
|
|
63
|
-
*/
|
|
64
|
-
export declare function formatErrorsForAgent(result: PipelineResult): string;
|
package/dist/go/verify-loop.js
DELETED
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { runPipeline } from "../gates/index.js";
|
|
4
|
-
import { reviewWaveDiff } from "../team/reviewer.js";
|
|
5
|
-
import { runConsensusProtocol, escalateToExecutive, createConsensusState, recordBuilderResponse, } from "../team/consensus.js";
|
|
6
|
-
/**
|
|
7
|
-
* Self-healing verification loop.
|
|
8
|
-
*
|
|
9
|
-
* Runs the forge verification pipeline, and on failure either invokes the
|
|
10
|
-
* `onFixAttempt` callback (so the caller can spawn a fix agent) or simply
|
|
11
|
-
* re-runs verification. Loops until the pipeline passes or max iterations
|
|
12
|
-
* are exhausted.
|
|
13
|
-
*/
|
|
14
|
-
export async function runVerifyLoop(options) {
|
|
15
|
-
const { projectDir, config, onIteration, onFixAttempt, reviewerConfig, onReviewComplete, } = options;
|
|
16
|
-
const maxIterations = options.maxIterations ?? config.maxIterations;
|
|
17
|
-
const results = [];
|
|
18
|
-
// Snapshot .forge.json before the loop to detect unauthorized config mutation
|
|
19
|
-
const configPath = join(projectDir, ".forge.json");
|
|
20
|
-
let configSnapshot = null;
|
|
21
|
-
try {
|
|
22
|
-
configSnapshot = readFileSync(configPath, "utf-8");
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
// .forge.json may not exist — skip detection
|
|
26
|
-
}
|
|
27
|
-
for (let iteration = 1; iteration <= maxIterations; iteration++) {
|
|
28
|
-
const pipelineInput = {
|
|
29
|
-
projectDir,
|
|
30
|
-
gates: config.gates,
|
|
31
|
-
prdPath: config.prdPath,
|
|
32
|
-
maxIterations,
|
|
33
|
-
devServerCommand: config.devServer?.command,
|
|
34
|
-
devServerPort: config.devServer?.port,
|
|
35
|
-
};
|
|
36
|
-
const result = await runPipeline(pipelineInput);
|
|
37
|
-
// Stamp the iteration number onto the result
|
|
38
|
-
const stamped = {
|
|
39
|
-
...result,
|
|
40
|
-
iteration,
|
|
41
|
-
maxIterations,
|
|
42
|
-
};
|
|
43
|
-
results.push(stamped);
|
|
44
|
-
onIteration?.(iteration, stamped);
|
|
45
|
-
// Success — mechanical gates passed
|
|
46
|
-
if (stamped.passed) {
|
|
47
|
-
// If reviewer is configured, run team-based review before declaring success
|
|
48
|
-
if (reviewerConfig) {
|
|
49
|
-
const reviewResult = await runTeamReview(reviewerConfig, onFixAttempt, onReviewComplete, iteration);
|
|
50
|
-
// If review found accepted errors that need fixing, continue the loop
|
|
51
|
-
if (reviewResult.hasAcceptedErrors && iteration < maxIterations) {
|
|
52
|
-
// Convert accepted findings to GateErrors for the fix callback
|
|
53
|
-
const fixErrors = findingsToGateErrors(reviewResult.acceptedFindings);
|
|
54
|
-
if (onFixAttempt) {
|
|
55
|
-
await onFixAttempt(iteration, fixErrors);
|
|
56
|
-
}
|
|
57
|
-
// Continue the loop to re-verify after fixes
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
// No accepted errors or at max iterations — return with review data
|
|
61
|
-
return {
|
|
62
|
-
passed: true,
|
|
63
|
-
iterations: iteration,
|
|
64
|
-
maxIterations,
|
|
65
|
-
results,
|
|
66
|
-
finalResult: stamped,
|
|
67
|
-
failedGates: [],
|
|
68
|
-
errorSummary: "",
|
|
69
|
-
reviewFindings: reviewResult.teamReviewResult,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
// No reviewer configured — return immediately
|
|
73
|
-
return {
|
|
74
|
-
passed: true,
|
|
75
|
-
iterations: iteration,
|
|
76
|
-
maxIterations,
|
|
77
|
-
results,
|
|
78
|
-
finalResult: stamped,
|
|
79
|
-
failedGates: [],
|
|
80
|
-
errorSummary: "",
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
// Not the last iteration — attempt a fix before retrying
|
|
84
|
-
if (iteration < maxIterations) {
|
|
85
|
-
const allErrors = collectErrors(stamped);
|
|
86
|
-
if (onFixAttempt) {
|
|
87
|
-
// Give the caller a chance to fix. Even if it returns false we still
|
|
88
|
-
// loop and re-verify (the caller may have partially fixed things, or
|
|
89
|
-
// an external process may have intervened).
|
|
90
|
-
await onFixAttempt(iteration, allErrors);
|
|
91
|
-
// Guard: detect if the fix agent mutated .forge.json (gate removal, etc.)
|
|
92
|
-
if (configSnapshot !== null) {
|
|
93
|
-
try {
|
|
94
|
-
const currentConfig = readFileSync(configPath, "utf-8");
|
|
95
|
-
if (currentConfig !== configSnapshot) {
|
|
96
|
-
// Restore the original config — agents must not modify it
|
|
97
|
-
writeFileSync(configPath, configSnapshot, "utf-8");
|
|
98
|
-
// Add a warning to the last result so it surfaces in reports
|
|
99
|
-
const lastResult = results[results.length - 1];
|
|
100
|
-
if (lastResult) {
|
|
101
|
-
lastResult.gates.push({
|
|
102
|
-
gate: "config-guard",
|
|
103
|
-
passed: true,
|
|
104
|
-
errors: [],
|
|
105
|
-
warnings: [
|
|
106
|
-
".forge.json was modified by a fix agent and has been restored. Agents must not modify project configuration to pass verification.",
|
|
107
|
-
],
|
|
108
|
-
duration_ms: 0,
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
catch {
|
|
114
|
-
// Non-fatal: if we can't read the file, skip detection
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
// Exhausted all iterations without passing
|
|
121
|
-
const finalResult = results[results.length - 1];
|
|
122
|
-
const failedGates = finalResult.gates
|
|
123
|
-
.filter((g) => !g.passed)
|
|
124
|
-
.map((g) => g.gate);
|
|
125
|
-
return {
|
|
126
|
-
passed: false,
|
|
127
|
-
iterations: maxIterations,
|
|
128
|
-
maxIterations,
|
|
129
|
-
results,
|
|
130
|
-
finalResult,
|
|
131
|
-
failedGates,
|
|
132
|
-
errorSummary: buildErrorSummary(maxIterations, finalResult),
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
// ---------------------------------------------------------------------------
|
|
136
|
-
// Helpers
|
|
137
|
-
// ---------------------------------------------------------------------------
|
|
138
|
-
/** Collect all GateError items from failed gates in a pipeline result */
|
|
139
|
-
function collectErrors(result) {
|
|
140
|
-
return result.gates
|
|
141
|
-
.filter((g) => !g.passed)
|
|
142
|
-
.flatMap((g) => g.errors);
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Build a human-readable error summary for a failed verification run.
|
|
146
|
-
*
|
|
147
|
-
* Example output:
|
|
148
|
-
* ```
|
|
149
|
-
* Verification failed after 3 iterations.
|
|
150
|
-
*
|
|
151
|
-
* Failed gates:
|
|
152
|
-
* - types: 2 errors
|
|
153
|
-
* - src/foo.ts:10: Type 'string' not assignable to 'number'
|
|
154
|
-
* - src/bar.ts:5: Property 'x' does not exist on type 'Y'
|
|
155
|
-
* - lint: 1 error
|
|
156
|
-
* - src/baz.ts:20: Unexpected any type
|
|
157
|
-
* ```
|
|
158
|
-
*/
|
|
159
|
-
function buildErrorSummary(iterations, result) {
|
|
160
|
-
const lines = [];
|
|
161
|
-
lines.push(`Verification failed after ${iterations} iteration${iterations === 1 ? "" : "s"}.`);
|
|
162
|
-
lines.push("");
|
|
163
|
-
const failedGates = result.gates.filter((g) => !g.passed);
|
|
164
|
-
if (failedGates.length === 0) {
|
|
165
|
-
return lines.join("\n");
|
|
166
|
-
}
|
|
167
|
-
lines.push("Failed gates:");
|
|
168
|
-
for (const gate of failedGates) {
|
|
169
|
-
const errorCount = gate.errors.length;
|
|
170
|
-
lines.push(`- ${gate.gate}: ${errorCount} error${errorCount === 1 ? "" : "s"}`);
|
|
171
|
-
for (const err of gate.errors) {
|
|
172
|
-
const location = formatLocation(err);
|
|
173
|
-
const prefix = location ? `${location}: ` : "";
|
|
174
|
-
lines.push(` - ${prefix}${err.message}`);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
return lines.join("\n");
|
|
178
|
-
}
|
|
179
|
-
/** Format file:line location string for an error */
|
|
180
|
-
function formatLocation(err) {
|
|
181
|
-
if (!err.file)
|
|
182
|
-
return "";
|
|
183
|
-
return err.line ? `${err.file}:${err.line}` : err.file;
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Run the team-based review after mechanical gates pass.
|
|
187
|
-
*
|
|
188
|
-
* 1. Call reviewWaveDiff() to get findings from the reviewer
|
|
189
|
-
* 2. If findings exist, call onBuilderResponses() to get builder consensus
|
|
190
|
-
* 3. Run runConsensusProtocol() with the builder responses
|
|
191
|
-
* 4. If escalations are needed, call onEscalation()
|
|
192
|
-
* 5. Return the review outcome with accepted findings that need fixing
|
|
193
|
-
*/
|
|
194
|
-
async function runTeamReview(reviewerConfig, onFixAttempt, onReviewComplete, iteration) {
|
|
195
|
-
const startTime = Date.now();
|
|
196
|
-
// Step 1: Get findings from the reviewer
|
|
197
|
-
const findings = reviewWaveDiff({
|
|
198
|
-
projectDir: reviewerConfig.projectDir,
|
|
199
|
-
prdPath: reviewerConfig.prdPath,
|
|
200
|
-
baseBranch: reviewerConfig.baseBranch,
|
|
201
|
-
});
|
|
202
|
-
// No findings — review is clean
|
|
203
|
-
if (findings.length === 0) {
|
|
204
|
-
const emptyResult = {
|
|
205
|
-
findings: [],
|
|
206
|
-
consensusResults: [],
|
|
207
|
-
duration_ms: Date.now() - startTime,
|
|
208
|
-
};
|
|
209
|
-
onReviewComplete?.(emptyResult);
|
|
210
|
-
return {
|
|
211
|
-
teamReviewResult: emptyResult,
|
|
212
|
-
hasAcceptedErrors: false,
|
|
213
|
-
acceptedFindings: [],
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
// Step 2: Get builder responses via SendMessage callback
|
|
217
|
-
let responses = new Map();
|
|
218
|
-
if (reviewerConfig.onBuilderResponses) {
|
|
219
|
-
responses = await reviewerConfig.onBuilderResponses(findings);
|
|
220
|
-
}
|
|
221
|
-
// Step 3: Run consensus protocol
|
|
222
|
-
const consensusOutcome = runConsensusProtocol(findings, responses);
|
|
223
|
-
let allConsensusResults = [...consensusOutcome.results];
|
|
224
|
-
// Step 4: Handle escalations if needed
|
|
225
|
-
if (consensusOutcome.needsEscalation.length > 0 && reviewerConfig.onEscalation) {
|
|
226
|
-
const escalationDecisions = await reviewerConfig.onEscalation(consensusOutcome.needsEscalation);
|
|
227
|
-
// Apply escalation decisions to each finding that needed it
|
|
228
|
-
for (let i = 0; i < consensusOutcome.needsEscalation.length; i++) {
|
|
229
|
-
const finding = consensusOutcome.needsEscalation[i];
|
|
230
|
-
const decision = escalationDecisions[i];
|
|
231
|
-
if (finding && decision) {
|
|
232
|
-
let state = createConsensusState(finding);
|
|
233
|
-
// Replay builder responses to get to the escalation state
|
|
234
|
-
const findingResponses = responses.get(finding.id) ?? [];
|
|
235
|
-
for (const resp of findingResponses) {
|
|
236
|
-
state = recordBuilderResponse(state, resp);
|
|
237
|
-
if (state.resolved)
|
|
238
|
-
break;
|
|
239
|
-
}
|
|
240
|
-
// Apply the executive decision
|
|
241
|
-
state = escalateToExecutive(state, decision);
|
|
242
|
-
if (state.result) {
|
|
243
|
-
allConsensusResults.push(state.result);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
// Step 5: Collect accepted findings that need fixing
|
|
249
|
-
const acceptedFindingIds = new Set(allConsensusResults
|
|
250
|
-
.filter((r) => r.resolution === "accepted")
|
|
251
|
-
.map((r) => r.findingId));
|
|
252
|
-
const acceptedFindings = findings.filter((f) => acceptedFindingIds.has(f.id) && f.severity === "error");
|
|
253
|
-
const teamReviewResult = {
|
|
254
|
-
findings,
|
|
255
|
-
consensusResults: allConsensusResults,
|
|
256
|
-
duration_ms: Date.now() - startTime,
|
|
257
|
-
};
|
|
258
|
-
onReviewComplete?.(teamReviewResult);
|
|
259
|
-
return {
|
|
260
|
-
teamReviewResult,
|
|
261
|
-
hasAcceptedErrors: acceptedFindings.length > 0,
|
|
262
|
-
acceptedFindings,
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
/** Convert review Findings into GateError[] for the fix callback */
|
|
266
|
-
function findingsToGateErrors(findings) {
|
|
267
|
-
return findings.map((f) => ({
|
|
268
|
-
file: f.file,
|
|
269
|
-
line: f.line,
|
|
270
|
-
message: `[Review] ${f.message}`,
|
|
271
|
-
remediation: f.remediation,
|
|
272
|
-
}));
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Format gate errors into a structured prompt for a fix agent.
|
|
276
|
-
*
|
|
277
|
-
* The output is designed to be directly usable in an AI agent prompt:
|
|
278
|
-
* it includes file paths, line numbers, error messages, and remediation
|
|
279
|
-
* hints so the agent can locate and fix issues without extra searching.
|
|
280
|
-
*/
|
|
281
|
-
export function formatErrorsForAgent(result) {
|
|
282
|
-
const lines = [];
|
|
283
|
-
const failedGates = result.gates.filter((g) => !g.passed);
|
|
284
|
-
if (failedGates.length === 0) {
|
|
285
|
-
return "All gates passed. No errors to fix.";
|
|
286
|
-
}
|
|
287
|
-
lines.push("# Verification Errors to Fix");
|
|
288
|
-
lines.push("");
|
|
289
|
-
for (const gate of failedGates) {
|
|
290
|
-
lines.push(`## Gate: ${gate.gate} (${gate.errors.length} errors)`);
|
|
291
|
-
lines.push("");
|
|
292
|
-
if (gate.errors.length === 0) {
|
|
293
|
-
lines.push("Gate failed but reported no structured errors.");
|
|
294
|
-
lines.push("");
|
|
295
|
-
continue;
|
|
296
|
-
}
|
|
297
|
-
for (const err of gate.errors) {
|
|
298
|
-
const location = formatLocation(err);
|
|
299
|
-
if (location) {
|
|
300
|
-
lines.push(`### ${location}`);
|
|
301
|
-
}
|
|
302
|
-
else {
|
|
303
|
-
lines.push("### (no file location)");
|
|
304
|
-
}
|
|
305
|
-
lines.push(`**Error:** ${err.message}`);
|
|
306
|
-
if (err.remediation) {
|
|
307
|
-
lines.push("");
|
|
308
|
-
lines.push(`> **Remediation:** ${err.remediation}`);
|
|
309
|
-
}
|
|
310
|
-
lines.push("");
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
// Add warnings as context (non-blocking but useful for agents)
|
|
314
|
-
const gatesWithWarnings = result.gates.filter((g) => g.warnings.length > 0);
|
|
315
|
-
if (gatesWithWarnings.length > 0) {
|
|
316
|
-
lines.push("## Warnings (non-blocking)");
|
|
317
|
-
lines.push("");
|
|
318
|
-
for (const gate of gatesWithWarnings) {
|
|
319
|
-
for (const warning of gate.warnings) {
|
|
320
|
-
lines.push(`- [${gate.gate}] ${warning}`);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
lines.push("");
|
|
324
|
-
}
|
|
325
|
-
return lines.join("\n");
|
|
326
|
-
}
|
|
327
|
-
//# sourceMappingURL=verify-loop.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"verify-loop.js","sourceRoot":"","sources":["../../src/go/verify-loop.ts"],"names":[],"mappings":"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"}
|
package/dist/hooks/pre-commit.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { execSync } from "node:child_process";
|
|
4
|
-
import { loadConfig } from "../config/loader.js";
|
|
5
|
-
export function checkPreCommit(projectDir) {
|
|
6
|
-
// Wrong branch protection
|
|
7
|
-
let branch = "unknown";
|
|
8
|
-
try {
|
|
9
|
-
branch = execSync("git branch --show-current", {
|
|
10
|
-
cwd: projectDir,
|
|
11
|
-
encoding: "utf-8",
|
|
12
|
-
}).trim();
|
|
13
|
-
if (branch === "main" || branch === "master") {
|
|
14
|
-
return {
|
|
15
|
-
allowed: false,
|
|
16
|
-
reason: `Cannot commit directly to ${branch}. Create a feature branch first.`,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
// Can't determine branch — allow
|
|
22
|
-
}
|
|
23
|
-
// Check verify cache — per-branch first, fall back to legacy path
|
|
24
|
-
const slug = branch.replace(/\//g, "-").toLowerCase();
|
|
25
|
-
const perBranchCachePath = join(projectDir, ".forge", "verify-cache", `${slug}.json`);
|
|
26
|
-
const legacyCachePath = join(projectDir, ".forge", "last-verify.json");
|
|
27
|
-
const cachePath = existsSync(perBranchCachePath)
|
|
28
|
-
? perBranchCachePath
|
|
29
|
-
: legacyCachePath;
|
|
30
|
-
if (!existsSync(cachePath)) {
|
|
31
|
-
return {
|
|
32
|
-
allowed: false,
|
|
33
|
-
reason: "No verification found. Run `npx forge verify` before committing.",
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
try {
|
|
37
|
-
const cache = JSON.parse(readFileSync(cachePath, "utf-8"));
|
|
38
|
-
// Validate cache structure — treat malformed cache as invalid
|
|
39
|
-
if (typeof cache.passed !== "boolean" || typeof cache.timestamp !== "string") {
|
|
40
|
-
return {
|
|
41
|
-
allowed: false,
|
|
42
|
-
reason: "Verification cache is malformed (missing or invalid fields). Run `npx forge verify`.",
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
if (!cache.passed) {
|
|
46
|
-
return {
|
|
47
|
-
allowed: false,
|
|
48
|
-
reason: "Last verification FAILED. Fix errors and run `npx forge verify` again.",
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
const config = loadConfig(projectDir);
|
|
52
|
-
const age = Date.now() - new Date(cache.timestamp).getTime();
|
|
53
|
-
if (Number.isNaN(age) || age < 0) {
|
|
54
|
-
return {
|
|
55
|
-
allowed: false,
|
|
56
|
-
reason: "Verification cache has an invalid timestamp. Run `npx forge verify`.",
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
if (age > config.verifyFreshness) {
|
|
60
|
-
const ageMin = Math.round(age / 60_000);
|
|
61
|
-
return {
|
|
62
|
-
allowed: false,
|
|
63
|
-
reason: `Verification is stale (${ageMin}min old). Run \`npx forge verify\` again.`,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
return { allowed: true };
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
return {
|
|
70
|
-
allowed: false,
|
|
71
|
-
reason: "Could not read verification cache. Run `npx forge verify`.",
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
//# sourceMappingURL=pre-commit.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pre-commit.js","sourceRoot":"","sources":["../../src/hooks/pre-commit.ts"],"names":[],"mappings":"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"}
|
package/dist/linear/issues.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { LinearClient, type LinearIssue } from "./client.js";
|
|
2
|
-
/** Valid issue states */
|
|
3
|
-
export declare const ISSUE_STATES: readonly ["Backlog", "Todo", "In Progress", "In Review", "Done", "Canceled"];
|
|
4
|
-
export type IssueState = (typeof ISSUE_STATES)[number];
|
|
5
|
-
/** Create an issue under a project milestone */
|
|
6
|
-
export declare function createMilestoneIssue(client: LinearClient, input: {
|
|
7
|
-
title: string;
|
|
8
|
-
description?: string;
|
|
9
|
-
teamId: string;
|
|
10
|
-
projectId: string;
|
|
11
|
-
milestoneId: string;
|
|
12
|
-
priority?: number;
|
|
13
|
-
}): Promise<LinearIssue>;
|
|
14
|
-
/** Resolve a state name to its UUID for a given team */
|
|
15
|
-
export declare function resolveStateId(client: LinearClient, teamId: string, stateName: string): Promise<string>;
|
|
16
|
-
/** Transition all issues in a milestone to a target state */
|
|
17
|
-
export declare function transitionMilestoneIssues(client: LinearClient, projectId: string, milestoneId: string, targetState: string, teamId: string): Promise<{
|
|
18
|
-
updated: number;
|
|
19
|
-
issues: LinearIssue[];
|
|
20
|
-
}>;
|
|
21
|
-
/** Add a progress comment to an issue */
|
|
22
|
-
export declare function addProgressComment(client: LinearClient, issueId: string, message: string): Promise<void>;
|