@ipul-labs/forge 1.16.7 → 1.17.0
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/README.md +58 -21
- package/lib/bin/cli/analyze.d.ts +9 -0
- package/lib/bin/cli/analyze.d.ts.map +1 -0
- package/lib/bin/cli/analyze.js +491 -0
- package/lib/bin/cli/analyze.js.map +1 -0
- package/lib/bin/cli/apply.d.ts +2 -0
- package/lib/bin/cli/apply.d.ts.map +1 -0
- package/lib/bin/cli/apply.js +262 -0
- package/lib/bin/cli/apply.js.map +1 -0
- package/lib/bin/cli/cifix.d.ts +2 -0
- package/lib/bin/cli/cifix.d.ts.map +1 -0
- package/lib/bin/cli/cifix.js +310 -0
- package/lib/bin/cli/cifix.js.map +1 -0
- package/lib/bin/cli/close.d.ts +2 -0
- package/lib/bin/cli/close.d.ts.map +1 -0
- package/lib/bin/cli/close.js +113 -0
- package/lib/bin/cli/close.js.map +1 -0
- package/lib/bin/cli/createIssue.d.ts +2 -0
- package/lib/bin/cli/createIssue.d.ts.map +1 -0
- package/lib/bin/cli/createIssue.js +108 -0
- package/lib/bin/cli/createIssue.js.map +1 -0
- package/lib/bin/cli/doctor.d.ts +2 -0
- package/lib/bin/cli/doctor.d.ts.map +1 -0
- package/lib/bin/cli/doctor.js +145 -0
- package/lib/bin/cli/doctor.js.map +1 -0
- package/lib/bin/cli/init.d.ts +4 -0
- package/lib/bin/cli/init.d.ts.map +1 -0
- package/lib/bin/cli/init.js +288 -0
- package/lib/bin/cli/init.js.map +1 -0
- package/lib/bin/cli/ink.d.ts +23 -0
- package/lib/bin/cli/ink.d.ts.map +1 -0
- package/{bin → lib/bin}/cli/ink.js +18 -19
- package/lib/bin/cli/ink.js.map +1 -0
- package/lib/bin/cli/issue.d.ts +2 -0
- package/lib/bin/cli/issue.d.ts.map +1 -0
- package/lib/bin/cli/issue.js +114 -0
- package/lib/bin/cli/issue.js.map +1 -0
- package/lib/bin/cli/issues.d.ts +2 -0
- package/lib/bin/cli/issues.d.ts.map +1 -0
- package/lib/bin/cli/issues.js +149 -0
- package/lib/bin/cli/issues.js.map +1 -0
- package/lib/bin/cli/merge.d.ts +2 -0
- package/lib/bin/cli/merge.d.ts.map +1 -0
- package/lib/bin/cli/merge.js +162 -0
- package/lib/bin/cli/merge.js.map +1 -0
- package/lib/bin/cli/refine.d.ts +2 -0
- package/lib/bin/cli/refine.d.ts.map +1 -0
- package/lib/bin/cli/refine.js +249 -0
- package/lib/bin/cli/refine.js.map +1 -0
- package/lib/bin/cli/repl.d.ts +2 -0
- package/lib/bin/cli/repl.d.ts.map +1 -0
- package/lib/bin/cli/repl.js +309 -0
- package/lib/bin/cli/repl.js.map +1 -0
- package/lib/bin/cli/repos.d.ts +2 -0
- package/lib/bin/cli/repos.d.ts.map +1 -0
- package/lib/bin/cli/repos.js +86 -0
- package/lib/bin/cli/repos.js.map +1 -0
- package/lib/bin/cli/resolution.d.ts +2 -0
- package/lib/bin/cli/resolution.d.ts.map +1 -0
- package/lib/bin/cli/resolution.js +139 -0
- package/lib/bin/cli/resolution.js.map +1 -0
- package/lib/bin/cli/serverClient.d.ts +26 -0
- package/lib/bin/cli/serverClient.d.ts.map +1 -0
- package/lib/bin/cli/serverClient.js +111 -0
- package/lib/bin/cli/serverClient.js.map +1 -0
- package/lib/bin/cli/session.d.ts +8 -0
- package/lib/bin/cli/session.d.ts.map +1 -0
- package/lib/bin/cli/session.js +212 -0
- package/lib/bin/cli/session.js.map +1 -0
- package/lib/bin/cli/sessionStore.d.ts +69 -0
- package/lib/bin/cli/sessionStore.d.ts.map +1 -0
- package/lib/bin/cli/sessionStore.js +196 -0
- package/lib/bin/cli/sessionStore.js.map +1 -0
- package/lib/bin/cli/ship.d.ts +33 -0
- package/lib/bin/cli/ship.d.ts.map +1 -0
- package/lib/bin/cli/ship.js +737 -0
- package/lib/bin/cli/ship.js.map +1 -0
- package/lib/bin/cli/types.d.ts +59 -0
- package/lib/bin/cli/types.d.ts.map +1 -0
- package/lib/bin/cli/types.js +2 -0
- package/lib/bin/cli/types.js.map +1 -0
- package/lib/bin/cli/update.d.ts +2 -0
- package/lib/bin/cli/update.d.ts.map +1 -0
- package/lib/bin/cli/update.js +87 -0
- package/lib/bin/cli/update.js.map +1 -0
- package/lib/bin/cli/utils.d.ts +43 -0
- package/lib/bin/cli/utils.d.ts.map +1 -0
- package/lib/bin/cli/utils.js +171 -0
- package/lib/bin/cli/utils.js.map +1 -0
- package/lib/bin/cli/validate.d.ts +2 -0
- package/lib/bin/cli/validate.d.ts.map +1 -0
- package/lib/bin/cli/validate.js +283 -0
- package/lib/bin/cli/validate.js.map +1 -0
- package/lib/bin/cli/watch.d.ts +5 -0
- package/lib/bin/cli/watch.d.ts.map +1 -0
- package/lib/bin/cli/watch.js +263 -0
- package/lib/bin/cli/watch.js.map +1 -0
- package/lib/bin/forge-agent.d.ts +3 -0
- package/lib/bin/forge-agent.d.ts.map +1 -0
- package/{bin → lib/bin}/forge-agent.js +104 -105
- package/lib/bin/forge-agent.js.map +1 -0
- package/lib/server/forge/core/ForgeAgent.d.ts +260 -0
- package/lib/server/forge/core/ForgeAgent.d.ts.map +1 -0
- package/lib/server/forge/core/ForgeAgent.js +995 -0
- package/lib/server/forge/core/ForgeAgent.js.map +1 -0
- package/lib/server/forge/core/agentClient.d.ts +39 -0
- package/lib/server/forge/core/agentClient.d.ts.map +1 -0
- package/{server → lib/server}/forge/core/agentClient.js +7 -12
- package/lib/server/forge/core/agentClient.js.map +1 -0
- package/lib/server/forge/core/branchName.d.ts +20 -0
- package/lib/server/forge/core/branchName.d.ts.map +1 -0
- package/lib/server/forge/core/branchName.js +39 -0
- package/lib/server/forge/core/branchName.js.map +1 -0
- package/lib/server/forge/core/claudeClient.d.ts +60 -0
- package/lib/server/forge/core/claudeClient.d.ts.map +1 -0
- package/lib/server/forge/core/claudeClient.js +347 -0
- package/lib/server/forge/core/claudeClient.js.map +1 -0
- package/lib/server/forge/core/configStore.d.ts +76 -0
- package/lib/server/forge/core/configStore.d.ts.map +1 -0
- package/lib/server/forge/core/configStore.js +213 -0
- package/lib/server/forge/core/configStore.js.map +1 -0
- package/lib/server/forge/core/gitlabClient.d.ts +144 -0
- package/lib/server/forge/core/gitlabClient.d.ts.map +1 -0
- package/{server → lib/server}/forge/core/gitlabClient.js +98 -180
- package/lib/server/forge/core/gitlabClient.js.map +1 -0
- package/lib/server/forge/core/jobs.d.ts +67 -0
- package/lib/server/forge/core/jobs.d.ts.map +1 -0
- package/lib/server/forge/core/jobs.js +185 -0
- package/lib/server/forge/core/jobs.js.map +1 -0
- package/lib/server/forge/core/k8s.d.ts +18 -0
- package/lib/server/forge/core/k8s.d.ts.map +1 -0
- package/lib/server/forge/core/k8s.js +49 -0
- package/lib/server/forge/core/k8s.js.map +1 -0
- package/lib/server/forge/core/localRepo.d.ts +36 -0
- package/lib/server/forge/core/localRepo.d.ts.map +1 -0
- package/lib/server/forge/core/localRepo.js +165 -0
- package/lib/server/forge/core/localRepo.js.map +1 -0
- package/lib/server/forge/core/openclawClient.d.ts +61 -0
- package/lib/server/forge/core/openclawClient.d.ts.map +1 -0
- package/lib/server/forge/core/openclawClient.js +111 -0
- package/lib/server/forge/core/openclawClient.js.map +1 -0
- package/lib/server/forge/core/prompts.d.ts +96 -0
- package/lib/server/forge/core/prompts.d.ts.map +1 -0
- package/lib/server/forge/core/prompts.js +450 -0
- package/lib/server/forge/core/prompts.js.map +1 -0
- package/lib/server/forge/core/providers/azuredevops.d.ts +134 -0
- package/lib/server/forge/core/providers/azuredevops.d.ts.map +1 -0
- package/lib/server/forge/core/providers/azuredevops.js +360 -0
- package/lib/server/forge/core/providers/azuredevops.js.map +1 -0
- package/lib/server/forge/core/providers/base.d.ts +114 -0
- package/lib/server/forge/core/providers/base.d.ts.map +1 -0
- package/lib/server/forge/core/providers/base.js +98 -0
- package/lib/server/forge/core/providers/base.js.map +1 -0
- package/lib/server/forge/core/providers/github.d.ts +133 -0
- package/lib/server/forge/core/providers/github.d.ts.map +1 -0
- package/lib/server/forge/core/providers/github.js +307 -0
- package/lib/server/forge/core/providers/github.js.map +1 -0
- package/lib/server/forge/core/providers/gitlab.d.ts +144 -0
- package/lib/server/forge/core/providers/gitlab.d.ts.map +1 -0
- package/lib/server/forge/core/providers/gitlab.js +407 -0
- package/lib/server/forge/core/providers/gitlab.js.map +1 -0
- package/lib/server/forge/core/providers/index.d.ts +21 -0
- package/lib/server/forge/core/providers/index.d.ts.map +1 -0
- package/lib/server/forge/core/providers/index.js +43 -0
- package/lib/server/forge/core/providers/index.js.map +1 -0
- package/lib/server/forge/core/providers/types.d.ts +80 -0
- package/lib/server/forge/core/providers/types.d.ts.map +1 -0
- package/lib/server/forge/core/providers/types.js +2 -0
- package/lib/server/forge/core/providers/types.js.map +1 -0
- package/lib/server/forge/core/quotaClient.d.ts +48 -0
- package/lib/server/forge/core/quotaClient.d.ts.map +1 -0
- package/lib/server/forge/core/quotaClient.js +88 -0
- package/lib/server/forge/core/quotaClient.js.map +1 -0
- package/lib/server/forge/core/types.d.ts +160 -0
- package/lib/server/forge/core/types.d.ts.map +1 -0
- package/lib/server/forge/core/types.js +2 -0
- package/lib/server/forge/core/types.js.map +1 -0
- package/lib/server/forge/core/validator/attribute.d.ts +31 -0
- package/lib/server/forge/core/validator/attribute.d.ts.map +1 -0
- package/lib/server/forge/core/validator/attribute.js +82 -0
- package/lib/server/forge/core/validator/attribute.js.map +1 -0
- package/lib/server/forge/core/validator/clone.d.ts +14 -0
- package/lib/server/forge/core/validator/clone.d.ts.map +1 -0
- package/lib/server/forge/core/validator/clone.js +99 -0
- package/lib/server/forge/core/validator/clone.js.map +1 -0
- package/lib/server/forge/core/validator/cmd.d.ts +23 -0
- package/lib/server/forge/core/validator/cmd.d.ts.map +1 -0
- package/lib/server/forge/core/validator/cmd.js +87 -0
- package/lib/server/forge/core/validator/cmd.js.map +1 -0
- package/lib/server/forge/core/validator/fs.d.ts +5 -0
- package/lib/server/forge/core/validator/fs.d.ts.map +1 -0
- package/{server → lib/server}/forge/core/validator/fs.js +8 -3
- package/lib/server/forge/core/validator/fs.js.map +1 -0
- package/lib/server/forge/core/validator/overlay.d.ts +13 -0
- package/lib/server/forge/core/validator/overlay.d.ts.map +1 -0
- package/lib/server/forge/core/validator/overlay.js +53 -0
- package/lib/server/forge/core/validator/overlay.js.map +1 -0
- package/lib/server/forge/core/validator/projectType.d.ts +20 -0
- package/lib/server/forge/core/validator/projectType.d.ts.map +1 -0
- package/lib/server/forge/core/validator/projectType.js +94 -0
- package/lib/server/forge/core/validator/projectType.js.map +1 -0
- package/lib/server/forge/core/validator/runners/go.d.ts +21 -0
- package/lib/server/forge/core/validator/runners/go.d.ts.map +1 -0
- package/lib/server/forge/core/validator/runners/go.js +99 -0
- package/lib/server/forge/core/validator/runners/go.js.map +1 -0
- package/lib/server/forge/core/validator/runners/node.d.ts +12 -0
- package/lib/server/forge/core/validator/runners/node.d.ts.map +1 -0
- package/lib/server/forge/core/validator/runners/node.js +75 -0
- package/lib/server/forge/core/validator/runners/node.js.map +1 -0
- package/lib/server/forge/core/validator/tdd.d.ts +30 -0
- package/lib/server/forge/core/validator/tdd.d.ts.map +1 -0
- package/lib/server/forge/core/validator/tdd.js +96 -0
- package/lib/server/forge/core/validator/tdd.js.map +1 -0
- package/lib/server/forge/core/validator.d.ts +58 -0
- package/lib/server/forge/core/validator.d.ts.map +1 -0
- package/lib/server/forge/core/validator.js +150 -0
- package/lib/server/forge/core/validator.js.map +1 -0
- package/lib/server/forge/routes.d.ts +22 -0
- package/lib/server/forge/routes.d.ts.map +1 -0
- package/lib/server/forge/routes.js +984 -0
- package/lib/server/forge/routes.js.map +1 -0
- package/lib/server.d.ts +2 -0
- package/lib/server.d.ts.map +1 -0
- package/lib/server.js +52 -0
- package/lib/server.js.map +1 -0
- package/lib/shared/events.d.ts +12 -0
- package/lib/shared/events.d.ts.map +1 -0
- package/lib/shared/events.js +12 -0
- package/lib/shared/events.js.map +1 -0
- package/package.json +17 -13
- package/scripts/fix-shebang.cjs +10 -0
- package/bin/cli/analyze.js +0 -516
- package/bin/cli/apply.js +0 -264
- package/bin/cli/cifix.js +0 -300
- package/bin/cli/close.js +0 -125
- package/bin/cli/createIssue.js +0 -112
- package/bin/cli/doctor.js +0 -161
- package/bin/cli/init.js +0 -306
- package/bin/cli/issue.js +0 -116
- package/bin/cli/issues.js +0 -155
- package/bin/cli/merge.js +0 -175
- package/bin/cli/refine.js +0 -253
- package/bin/cli/repl.js +0 -301
- package/bin/cli/repos.js +0 -91
- package/bin/cli/resolution.js +0 -126
- package/bin/cli/session.js +0 -230
- package/bin/cli/sessionStore.js +0 -211
- package/bin/cli/ship.js +0 -762
- package/bin/cli/update.js +0 -95
- package/bin/cli/utils.js +0 -145
- package/bin/cli/validate.js +0 -280
- package/bin/cli/watch.js +0 -274
- package/server/forge/core/ForgeAgent.js +0 -1179
- package/server/forge/core/ForgeAgent.test.js +0 -179
- package/server/forge/core/branchName.js +0 -41
- package/server/forge/core/claudeClient.js +0 -378
- package/server/forge/core/configStore.js +0 -229
- package/server/forge/core/configStore.test.js +0 -89
- package/server/forge/core/jobs.js +0 -180
- package/server/forge/core/k8s.js +0 -54
- package/server/forge/core/localRepo.js +0 -153
- package/server/forge/core/openclawClient.js +0 -125
- package/server/forge/core/prompts.js +0 -483
- package/server/forge/core/prompts.test.js +0 -219
- package/server/forge/core/providers/azuredevops.js +0 -409
- package/server/forge/core/providers/base.js +0 -208
- package/server/forge/core/providers/github.js +0 -348
- package/server/forge/core/providers/gitlab.js +0 -529
- package/server/forge/core/providers/index.js +0 -47
- package/server/forge/core/quotaClient.js +0 -101
- package/server/forge/core/validator/attribute.js +0 -84
- package/server/forge/core/validator/clone.js +0 -105
- package/server/forge/core/validator/cmd.js +0 -98
- package/server/forge/core/validator/overlay.js +0 -52
- package/server/forge/core/validator/projectType.js +0 -87
- package/server/forge/core/validator/runners/go.js +0 -107
- package/server/forge/core/validator/runners/node.js +0 -84
- package/server/forge/core/validator/tdd.js +0 -105
- package/server/forge/core/validator.js +0 -167
- package/server/forge/routes.js +0 -1026
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* server/forge/core/quotaClient.js
|
|
3
|
+
*
|
|
4
|
+
* One-off probe of the Anthropic Messages API to read the plan-level
|
|
5
|
+
* rate-limit headers. Used by the "Refresh quota" button in the UsageWidget.
|
|
6
|
+
*
|
|
7
|
+
* The rest of Forge still runs through `claude` CLI (subscription billing);
|
|
8
|
+
* this probe is the only place that spends API credits, and only when the
|
|
9
|
+
* user explicitly asks for it. Cost is negligible — one request with
|
|
10
|
+
* `max_tokens=1` against Haiku.
|
|
11
|
+
*/
|
|
12
|
+
const PROBE_MODEL = "claude-haiku-4-5-20251001";
|
|
13
|
+
function num(v) {
|
|
14
|
+
const n = Number(v);
|
|
15
|
+
return Number.isFinite(n) ? n : null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* @param {Headers} headers
|
|
19
|
+
* @returns {null | {
|
|
20
|
+
* tokensLimit: number|null,
|
|
21
|
+
* tokensRemaining: number|null,
|
|
22
|
+
* tokensReset: string|null,
|
|
23
|
+
* requestsLimit: number|null,
|
|
24
|
+
* requestsRemaining: number|null,
|
|
25
|
+
* requestsReset: string|null,
|
|
26
|
+
* }}
|
|
27
|
+
*/
|
|
28
|
+
export function parseRateLimit(headers) {
|
|
29
|
+
const rl = {
|
|
30
|
+
tokensLimit: num(headers.get("anthropic-ratelimit-tokens-limit")),
|
|
31
|
+
tokensRemaining: num(headers.get("anthropic-ratelimit-tokens-remaining")),
|
|
32
|
+
tokensReset: headers.get("anthropic-ratelimit-tokens-reset") ?? null,
|
|
33
|
+
requestsLimit: num(headers.get("anthropic-ratelimit-requests-limit")),
|
|
34
|
+
requestsRemaining: num(headers.get("anthropic-ratelimit-requests-remaining")),
|
|
35
|
+
requestsReset: headers.get("anthropic-ratelimit-requests-reset") ?? null,
|
|
36
|
+
};
|
|
37
|
+
const any = rl.tokensLimit !== null ||
|
|
38
|
+
rl.tokensRemaining !== null ||
|
|
39
|
+
rl.tokensReset ||
|
|
40
|
+
rl.requestsLimit !== null ||
|
|
41
|
+
rl.requestsRemaining !== null ||
|
|
42
|
+
rl.requestsReset;
|
|
43
|
+
return any ? rl : null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Fires one minimal Messages API request and returns the rate-limit snapshot
|
|
47
|
+
* from the response headers.
|
|
48
|
+
*
|
|
49
|
+
* @throws if ANTHROPIC_API_KEY is not configured, or the API rejects us.
|
|
50
|
+
*/
|
|
51
|
+
export async function probeQuota() {
|
|
52
|
+
if (!process.env.ANTHROPIC_API_KEY) {
|
|
53
|
+
const err = Object.assign(new Error("Quota check requires ANTHROPIC_API_KEY to be set. Add it to your .env."), { status: 400 });
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
const controller = new AbortController();
|
|
57
|
+
const timer = setTimeout(() => controller.abort(), 10_000);
|
|
58
|
+
let res;
|
|
59
|
+
try {
|
|
60
|
+
res = await fetch("https://api.anthropic.com/v1/messages", {
|
|
61
|
+
method: "POST",
|
|
62
|
+
headers: {
|
|
63
|
+
"x-api-key": process.env.ANTHROPIC_API_KEY,
|
|
64
|
+
"anthropic-version": "2023-06-01",
|
|
65
|
+
"content-type": "application/json",
|
|
66
|
+
},
|
|
67
|
+
body: JSON.stringify({
|
|
68
|
+
model: PROBE_MODEL,
|
|
69
|
+
max_tokens: 1,
|
|
70
|
+
messages: [{ role: "user", content: "." }],
|
|
71
|
+
}),
|
|
72
|
+
signal: controller.signal,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
clearTimeout(timer);
|
|
77
|
+
}
|
|
78
|
+
// Rate-limit headers are present even on 4xx/5xx responses, so grab them
|
|
79
|
+
// before deciding whether to throw.
|
|
80
|
+
const rateLimit = parseRateLimit(res.headers);
|
|
81
|
+
if (!res.ok) {
|
|
82
|
+
const text = await res.text().catch(() => "");
|
|
83
|
+
const err = Object.assign(new Error(`Anthropic API ${res.status}: ${text.slice(0, 300)}`), { status: res.status, rateLimit });
|
|
84
|
+
throw err;
|
|
85
|
+
}
|
|
86
|
+
return { rateLimit, checkedAt: new Date().toISOString() };
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=quotaClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quotaClient.js","sourceRoot":"","sources":["../../../../server/forge/core/quotaClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
export interface ForgeChange {
|
|
2
|
+
file: string;
|
|
3
|
+
action: "create" | "modify" | "delete";
|
|
4
|
+
original?: string;
|
|
5
|
+
proposed?: string;
|
|
6
|
+
summary?: string;
|
|
7
|
+
repo?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface AnalysisResult {
|
|
10
|
+
issue: {
|
|
11
|
+
iid: number;
|
|
12
|
+
title: string;
|
|
13
|
+
description?: string | null;
|
|
14
|
+
};
|
|
15
|
+
mrTitle?: string;
|
|
16
|
+
explanation: string;
|
|
17
|
+
reasoning: string;
|
|
18
|
+
changes: ForgeChange[];
|
|
19
|
+
repos: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface ApplicationResult {
|
|
22
|
+
repo: string;
|
|
23
|
+
branchName: string;
|
|
24
|
+
mr: {
|
|
25
|
+
iid: number;
|
|
26
|
+
web_url: string;
|
|
27
|
+
title: string;
|
|
28
|
+
} | null;
|
|
29
|
+
pipelineUrl: string | null;
|
|
30
|
+
}
|
|
31
|
+
export interface ForgeEvent {
|
|
32
|
+
type: string;
|
|
33
|
+
step?: string;
|
|
34
|
+
message?: string;
|
|
35
|
+
data?: AnalysisResult | Record<string, unknown>;
|
|
36
|
+
cost?: number;
|
|
37
|
+
inputTokens?: number;
|
|
38
|
+
outputTokens?: number;
|
|
39
|
+
cacheCreationTokens?: number;
|
|
40
|
+
cacheReadTokens?: number;
|
|
41
|
+
serviceTier?: string;
|
|
42
|
+
sessionId?: string;
|
|
43
|
+
rateLimit?: unknown;
|
|
44
|
+
resumed?: boolean;
|
|
45
|
+
text?: string;
|
|
46
|
+
status?: string;
|
|
47
|
+
passed?: boolean;
|
|
48
|
+
exitCode?: number;
|
|
49
|
+
durationMs?: number;
|
|
50
|
+
tail?: string;
|
|
51
|
+
repo?: string;
|
|
52
|
+
projectType?: string;
|
|
53
|
+
stepOrder?: string[];
|
|
54
|
+
fixableSteps?: string[];
|
|
55
|
+
allPassed?: boolean;
|
|
56
|
+
checkedAt?: string;
|
|
57
|
+
files?: Array<{
|
|
58
|
+
file: string;
|
|
59
|
+
proposed: string;
|
|
60
|
+
}>;
|
|
61
|
+
}
|
|
62
|
+
export interface ClaudeResult {
|
|
63
|
+
data: Record<string, unknown>;
|
|
64
|
+
cost: number;
|
|
65
|
+
serviceTier: string;
|
|
66
|
+
inputTokens: number;
|
|
67
|
+
outputTokens: number;
|
|
68
|
+
cacheCreationTokens: number;
|
|
69
|
+
cacheReadTokens: number;
|
|
70
|
+
sessionId?: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The flattened result returned by public agent functions (checkResolution,
|
|
74
|
+
* identifyRelevantFiles, proposeFix, refineOrAsk). The parsed JSON data
|
|
75
|
+
* is spread into the top level alongside the metadata fields.
|
|
76
|
+
*/
|
|
77
|
+
export interface AgentResponse extends Record<string, unknown> {
|
|
78
|
+
cost: number;
|
|
79
|
+
serviceTier: string;
|
|
80
|
+
inputTokens: number;
|
|
81
|
+
outputTokens: number;
|
|
82
|
+
cacheCreationTokens: number;
|
|
83
|
+
cacheReadTokens: number;
|
|
84
|
+
sessionId?: string;
|
|
85
|
+
}
|
|
86
|
+
export interface RunCmdResult {
|
|
87
|
+
code: number;
|
|
88
|
+
output: string;
|
|
89
|
+
error: string | null;
|
|
90
|
+
}
|
|
91
|
+
export interface JobRecord {
|
|
92
|
+
id: string;
|
|
93
|
+
type: string;
|
|
94
|
+
status: "running" | "done" | "error" | "cancelled";
|
|
95
|
+
events: ForgeEvent[];
|
|
96
|
+
doneResult: unknown;
|
|
97
|
+
error: string | null;
|
|
98
|
+
createdAt: number;
|
|
99
|
+
finishedAt: number | null;
|
|
100
|
+
expiresAt: number | null;
|
|
101
|
+
subscribers: Set<(event: ForgeEvent) => void>;
|
|
102
|
+
controller: AbortController;
|
|
103
|
+
meta: Record<string, unknown>;
|
|
104
|
+
}
|
|
105
|
+
export interface JobSnapshot {
|
|
106
|
+
id: string;
|
|
107
|
+
type: string;
|
|
108
|
+
status: string;
|
|
109
|
+
createdAt: number;
|
|
110
|
+
finishedAt: number | null;
|
|
111
|
+
error: string | null;
|
|
112
|
+
eventCount: number;
|
|
113
|
+
meta: Record<string, unknown>;
|
|
114
|
+
}
|
|
115
|
+
export interface ForgeRepo {
|
|
116
|
+
id: string;
|
|
117
|
+
label: string;
|
|
118
|
+
}
|
|
119
|
+
export interface ForgeConfig {
|
|
120
|
+
repos: ForgeRepo[];
|
|
121
|
+
defaults: {
|
|
122
|
+
model: string | null;
|
|
123
|
+
agent: string | null;
|
|
124
|
+
autoPushOnValidatePass: boolean;
|
|
125
|
+
refineRepoAccess: boolean;
|
|
126
|
+
promptRules: string;
|
|
127
|
+
testDeployUrlTemplate?: string;
|
|
128
|
+
cliTimeout?: number;
|
|
129
|
+
};
|
|
130
|
+
connections: {
|
|
131
|
+
gitlab: {
|
|
132
|
+
token: string;
|
|
133
|
+
baseUrl: string;
|
|
134
|
+
};
|
|
135
|
+
github: {
|
|
136
|
+
token: string;
|
|
137
|
+
owner: string;
|
|
138
|
+
repo: string;
|
|
139
|
+
baseBranch: string;
|
|
140
|
+
};
|
|
141
|
+
azuredevops: {
|
|
142
|
+
token: string;
|
|
143
|
+
org: string;
|
|
144
|
+
project: string;
|
|
145
|
+
repo: string;
|
|
146
|
+
baseBranch: string;
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
export interface ValidationStepResult {
|
|
151
|
+
step: string;
|
|
152
|
+
passed: boolean;
|
|
153
|
+
output?: string;
|
|
154
|
+
}
|
|
155
|
+
export interface ValidationResult {
|
|
156
|
+
passed: boolean;
|
|
157
|
+
steps: ValidationStepResult[];
|
|
158
|
+
logs: string[];
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../server/forge/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3D,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAc,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,WAAW,CAAC;IACnD,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC,CAAC;IAC9C,UAAU,EAAE,eAAe,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,SAAS;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,QAAQ,EAAE;QACT,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,sBAAsB,EAAE,OAAO,CAAC;QAChC,gBAAgB,EAAE,OAAO,CAAC;QAC1B,WAAW,EAAE,MAAM,CAAC;QACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,WAAW,EAAE;QACZ,MAAM,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC;QAC3C,MAAM,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,CAAC;QAC3E,WAAW,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,CAAC;KAC/F,CAAC;CACF;AAED,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,oBAAoB,EAAE,CAAC;IAC9B,IAAI,EAAE,MAAM,EAAE,CAAC;CACf"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../server/forge/core/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-attribution: figure out which configured repo a proposed change
|
|
3
|
+
* actually belongs to.
|
|
4
|
+
*
|
|
5
|
+
* Uses the SCM provider's `getFileContent` as a cheap remote existence check
|
|
6
|
+
* — no clone needed. We only fall back to the model's `c.repo` for `create`
|
|
7
|
+
* actions where the file doesn't yet exist anywhere. The result: only repos
|
|
8
|
+
* that actually own at least one change end up in the validation plan, and
|
|
9
|
+
* we never clone a repo that won't be validated.
|
|
10
|
+
*/
|
|
11
|
+
import type { ForgeChange, ForgeEvent } from "../types.ts";
|
|
12
|
+
/**
|
|
13
|
+
* Convenience wrapper: returns a flat list of changes with their `repo`
|
|
14
|
+
* field rewritten to the auto-detected target. Used by callers (ForgeAgent's
|
|
15
|
+
* apply/commit/deploy paths) that want a corrected change list rather than
|
|
16
|
+
* the per-repo grouping the validator needs.
|
|
17
|
+
*
|
|
18
|
+
* @returns {Promise<{ changes: object[], unattributed: object[] }>}
|
|
19
|
+
*/
|
|
20
|
+
export declare function reattributeChanges(changes: ForgeChange[], candidates: string[]): Promise<{
|
|
21
|
+
changes: any[];
|
|
22
|
+
unattributed: ForgeChange[];
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* @returns {Promise<{ byRepo: Map<string, object[]>, unattributed: object[] }>}
|
|
26
|
+
*/
|
|
27
|
+
export declare function attributeChanges(changes: ForgeChange[], candidates: string[], emit?: (event: ForgeEvent) => void): Promise<{
|
|
28
|
+
byRepo: Map<any, any>;
|
|
29
|
+
unattributed: ForgeChange[];
|
|
30
|
+
}>;
|
|
31
|
+
//# sourceMappingURL=attribute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribute.d.ts","sourceRoot":"","sources":["../../../../../server/forge/core/validator/attribute.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAe3D;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE;;;GAOpF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAe;;;GAyChI"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-attribution: figure out which configured repo a proposed change
|
|
3
|
+
* actually belongs to.
|
|
4
|
+
*
|
|
5
|
+
* Uses the SCM provider's `getFileContent` as a cheap remote existence check
|
|
6
|
+
* — no clone needed. We only fall back to the model's `c.repo` for `create`
|
|
7
|
+
* actions where the file doesn't yet exist anywhere. The result: only repos
|
|
8
|
+
* that actually own at least one change end up in the validation plan, and
|
|
9
|
+
* we never clone a repo that won't be validated.
|
|
10
|
+
*/
|
|
11
|
+
import { createProvider } from "../providers/index.js";
|
|
12
|
+
async function existsRemote(provider, file) {
|
|
13
|
+
try {
|
|
14
|
+
await provider.getFileContent(file);
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Convenience wrapper: returns a flat list of changes with their `repo`
|
|
23
|
+
* field rewritten to the auto-detected target. Used by callers (ForgeAgent's
|
|
24
|
+
* apply/commit/deploy paths) that want a corrected change list rather than
|
|
25
|
+
* the per-repo grouping the validator needs.
|
|
26
|
+
*
|
|
27
|
+
* @returns {Promise<{ changes: object[], unattributed: object[] }>}
|
|
28
|
+
*/
|
|
29
|
+
export async function reattributeChanges(changes, candidates) {
|
|
30
|
+
const { byRepo, unattributed } = await attributeChanges(changes, candidates);
|
|
31
|
+
const out = [];
|
|
32
|
+
for (const [repo, list] of byRepo) {
|
|
33
|
+
for (const c of list)
|
|
34
|
+
out.push({ ...c, repo });
|
|
35
|
+
}
|
|
36
|
+
return { changes: out, unattributed };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* @returns {Promise<{ byRepo: Map<string, object[]>, unattributed: object[] }>}
|
|
40
|
+
*/
|
|
41
|
+
export async function attributeChanges(changes, candidates, emit = () => { }) {
|
|
42
|
+
const providers = new Map();
|
|
43
|
+
for (const repo of candidates) {
|
|
44
|
+
try {
|
|
45
|
+
providers.set(repo, createProvider(repo));
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
emit({ type: "log", message: `Couldn't build provider for ${repo}: ${err?.message ?? err}` });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const byRepo = new Map();
|
|
52
|
+
const unattributed = [];
|
|
53
|
+
for (const c of changes ?? []) {
|
|
54
|
+
let target = null;
|
|
55
|
+
if (c.action === "modify" || c.action === "delete") {
|
|
56
|
+
emit({ type: "log", message: `Locating ${c.file}…` });
|
|
57
|
+
for (const [repo, provider] of providers) {
|
|
58
|
+
if (await existsRemote(provider, c.file)) {
|
|
59
|
+
target = repo;
|
|
60
|
+
emit({ type: "log", message: ` → ${repo}` });
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else if (c.action === "create") {
|
|
66
|
+
// New file — no remote evidence to consult. Honour the model's
|
|
67
|
+
// attribution if it points to a real candidate.
|
|
68
|
+
if (c.repo && candidates.includes(c.repo))
|
|
69
|
+
target = c.repo;
|
|
70
|
+
}
|
|
71
|
+
if (target) {
|
|
72
|
+
const list = byRepo.get(target) ?? [];
|
|
73
|
+
list.push(c);
|
|
74
|
+
byRepo.set(target, list);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
unattributed.push(c);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return { byRepo, unattributed };
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=attribute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribute.js","sourceRoot":"","sources":["../../../../../server/forge/core/validator/attribute.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache + clone management for the validator's per-repo workspaces.
|
|
3
|
+
*
|
|
4
|
+
* ensureClone(repo, branchName, emit)
|
|
5
|
+
* - Lazily clones into ~/.forge/cache/<repo>/ (or FORGE_VALIDATE_CACHE).
|
|
6
|
+
* - Always fetch + reset to origin/main, then check out a stable per-issue
|
|
7
|
+
* branch so validation runs are deterministic and old overlays can't
|
|
8
|
+
* linger across runs.
|
|
9
|
+
* - GitLab-only for v1; GitHub / Azure DevOps raise a clear error.
|
|
10
|
+
* - Emits clone-step progress / log / step_result events.
|
|
11
|
+
*/
|
|
12
|
+
import type { ForgeEvent } from "../types.ts";
|
|
13
|
+
export declare function ensureClone(repo: string, branchName: string, emit: (event: ForgeEvent) => void): Promise<string>;
|
|
14
|
+
//# sourceMappingURL=clone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clone.d.ts","sourceRoot":"","sources":["../../../../../server/forge/core/validator/clone.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAkD9C,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,mBAgDpG"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache + clone management for the validator's per-repo workspaces.
|
|
3
|
+
*
|
|
4
|
+
* ensureClone(repo, branchName, emit)
|
|
5
|
+
* - Lazily clones into ~/.forge/cache/<repo>/ (or FORGE_VALIDATE_CACHE).
|
|
6
|
+
* - Always fetch + reset to origin/main, then check out a stable per-issue
|
|
7
|
+
* branch so validation runs are deterministic and old overlays can't
|
|
8
|
+
* linger across runs.
|
|
9
|
+
* - GitLab-only for v1; GitHub / Azure DevOps raise a clear error.
|
|
10
|
+
* - Emits clone-step progress / log / step_result events.
|
|
11
|
+
*/
|
|
12
|
+
import { writeFileSync, unlinkSync } from "node:fs";
|
|
13
|
+
import fs from "node:fs/promises";
|
|
14
|
+
import os from "node:os";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { getConnection } from "../configStore.js";
|
|
17
|
+
import { runCmd } from "./cmd.js";
|
|
18
|
+
import { exists } from "./fs.js";
|
|
19
|
+
const CACHE_ROOT = process.env.FORGE_VALIDATE_CACHE
|
|
20
|
+
?? path.join(os.homedir(), ".forge", "cache");
|
|
21
|
+
function sanitizeRepo(repo) {
|
|
22
|
+
return repo.replace(/[^a-zA-Z0-9_./-]/g, "_");
|
|
23
|
+
}
|
|
24
|
+
function gitlabCloneUrl(project) {
|
|
25
|
+
return `https://gitlab.com/${project}.git`;
|
|
26
|
+
}
|
|
27
|
+
function createAskpassScript(token) {
|
|
28
|
+
const script = path.join(os.tmpdir(), `.forge-askpass-${process.pid}`);
|
|
29
|
+
writeFileSync(script, `#!/bin/sh\ncase "$1" in *Username*) echo oauth2;; *) echo "${token}";; esac\n`, { mode: 0o700 });
|
|
30
|
+
return script;
|
|
31
|
+
}
|
|
32
|
+
function gitEnvWithToken() {
|
|
33
|
+
const { token } = getConnection("gitlab");
|
|
34
|
+
if (!token) {
|
|
35
|
+
throw new Error("GitLab token is required to clone the repo for validation. Set it in Settings → Connections or via GITLAB_TOKEN env var.");
|
|
36
|
+
}
|
|
37
|
+
const askpass = createAskpassScript(token);
|
|
38
|
+
return {
|
|
39
|
+
env: {
|
|
40
|
+
GIT_ASKPASS: askpass,
|
|
41
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
42
|
+
},
|
|
43
|
+
cleanup: () => { try {
|
|
44
|
+
unlinkSync(askpass);
|
|
45
|
+
}
|
|
46
|
+
catch { } },
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function resolveCloneUrl(repoInput) {
|
|
50
|
+
// Repos may arrive prefixed — "github:owner/name", "azuredevops:org/proj/repo".
|
|
51
|
+
// v1 only supports GitLab; tell the caller clearly when it's something else.
|
|
52
|
+
const colon = repoInput.indexOf(":");
|
|
53
|
+
if (colon > 0) {
|
|
54
|
+
const prefix = repoInput.slice(0, colon).toLowerCase();
|
|
55
|
+
if (prefix === "gitlab")
|
|
56
|
+
return gitlabCloneUrl(repoInput.slice(colon + 1));
|
|
57
|
+
if (prefix === "github" || prefix === "azuredevops" || prefix === "azure") {
|
|
58
|
+
throw new Error(`Validation for ${prefix} repos isn't implemented yet — GitLab only for now.`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return gitlabCloneUrl(repoInput);
|
|
62
|
+
}
|
|
63
|
+
export async function ensureClone(repo, branchName, emit) {
|
|
64
|
+
const dir = path.join(CACHE_ROOT, sanitizeRepo(repo));
|
|
65
|
+
const hasRepo = await exists(path.join(dir, ".git"));
|
|
66
|
+
emit({ type: "progress", step: "clone", status: "running" });
|
|
67
|
+
emit({ type: "log", step: "clone", message: hasRepo ? `Reusing clone at ${dir}` : `Cloning ${repo} → ${dir}` });
|
|
68
|
+
const { env: gitEnv, cleanup } = gitEnvWithToken();
|
|
69
|
+
const envOpts = { env: { ...process.env, ...gitEnv } };
|
|
70
|
+
try {
|
|
71
|
+
if (!hasRepo) {
|
|
72
|
+
await fs.mkdir(dir, { recursive: true });
|
|
73
|
+
const clone = await runCmd("git", ["clone", "--depth=1", resolveCloneUrl(repo), dir], envOpts, (l) => emit({ type: "log", step: "clone", message: l }));
|
|
74
|
+
if (clone.code !== 0)
|
|
75
|
+
throw new Error(`git clone failed (code ${clone.code})`);
|
|
76
|
+
}
|
|
77
|
+
const fetch = await runCmd("git", ["fetch", "--depth=1", "origin", "main"], { cwd: dir, ...envOpts }, (l) => emit({ type: "log", step: "clone", message: l }));
|
|
78
|
+
if (fetch.code !== 0)
|
|
79
|
+
throw new Error(`git fetch failed (code ${fetch.code})`);
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
cleanup();
|
|
83
|
+
}
|
|
84
|
+
// Two-step reset+clean before the branch switch so any lingering overlay
|
|
85
|
+
// from a prior run is wiped — `git checkout -B` alone refuses if dirty.
|
|
86
|
+
// `clean -fd` preserves node_modules because it's .gitignored.
|
|
87
|
+
emit({ type: "log", step: "clone", message: `Resetting workspace to origin/main` });
|
|
88
|
+
const reset = await runCmd("git", ["reset", "--hard", "origin/main"], { cwd: dir });
|
|
89
|
+
if (reset.code !== 0)
|
|
90
|
+
throw new Error(`git reset failed (code ${reset.code})`);
|
|
91
|
+
await runCmd("git", ["clean", "-fd"], { cwd: dir });
|
|
92
|
+
emit({ type: "log", step: "clone", message: `Checking out workspace branch ${branchName}` });
|
|
93
|
+
const checkout = await runCmd("git", ["checkout", "-B", branchName], { cwd: dir }, (l) => emit({ type: "log", step: "clone", message: l }));
|
|
94
|
+
if (checkout.code !== 0)
|
|
95
|
+
throw new Error(`git checkout ${branchName} failed (code ${checkout.code})`);
|
|
96
|
+
emit({ type: "step_result", step: "clone", passed: true });
|
|
97
|
+
return dir;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=clone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clone.js","sourceRoot":"","sources":["../../../../../server/forge/core/validator/clone.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level child-process helpers shared by every runner.
|
|
3
|
+
*
|
|
4
|
+
* runCmd — spawn → resolve with { code, output, error }; line-buffers
|
|
5
|
+
* stdout+stderr through `onLine` for live streaming.
|
|
6
|
+
* runStep — runCmd + emits the standard progress / step_result events
|
|
7
|
+
* the SSE consumer expects, returning a `{ passed, ... }` row.
|
|
8
|
+
*
|
|
9
|
+
* Children inherit a forced no-colour CI environment so eslint/tsc/jest/vitest
|
|
10
|
+
* don't spam ANSI into the SSE stream.
|
|
11
|
+
*/
|
|
12
|
+
import type { RunCmdResult, ForgeEvent } from "../types.ts";
|
|
13
|
+
export declare const MAX_TAIL_LINES = 60;
|
|
14
|
+
export declare function stripAnsi(s: string): string;
|
|
15
|
+
export interface StepResult {
|
|
16
|
+
passed: boolean;
|
|
17
|
+
exitCode: number;
|
|
18
|
+
durationMs: number;
|
|
19
|
+
tail: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function runCmd(cmd: string, args: string[], opts?: Record<string, unknown>, onLine?: (line: string) => void): Promise<RunCmdResult>;
|
|
22
|
+
export declare function runStep(dir: string, stepName: string, cmd: string, args: string[], emit: (event: ForgeEvent) => void): Promise<StepResult>;
|
|
23
|
+
//# sourceMappingURL=cmd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cmd.d.ts","sourceRoot":"","sources":["../../../../../server/forge/core/validator/cmd.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE5D,eAAO,MAAM,cAAc,KAAK,CAAC;AAMjC,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,UAElC;AAED,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAmD9I;AAED,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,CAoBhJ"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level child-process helpers shared by every runner.
|
|
3
|
+
*
|
|
4
|
+
* runCmd — spawn → resolve with { code, output, error }; line-buffers
|
|
5
|
+
* stdout+stderr through `onLine` for live streaming.
|
|
6
|
+
* runStep — runCmd + emits the standard progress / step_result events
|
|
7
|
+
* the SSE consumer expects, returning a `{ passed, ... }` row.
|
|
8
|
+
*
|
|
9
|
+
* Children inherit a forced no-colour CI environment so eslint/tsc/jest/vitest
|
|
10
|
+
* don't spam ANSI into the SSE stream.
|
|
11
|
+
*/
|
|
12
|
+
import { spawn } from "node:child_process";
|
|
13
|
+
export const MAX_TAIL_LINES = 60;
|
|
14
|
+
// CSI (colour, cursor moves), OSC (titles), and simple ESC[ sequences.
|
|
15
|
+
// eslint-disable-next-line no-control-regex
|
|
16
|
+
const ANSI_RX = /\x1b\[[0-9;?]*[a-zA-Z]|\x1b\][^\x07]*\x07|\x1b[@-Z\\-_]/g;
|
|
17
|
+
export function stripAnsi(s) {
|
|
18
|
+
return s.replace(ANSI_RX, "");
|
|
19
|
+
}
|
|
20
|
+
export function runCmd(cmd, args, opts = {}, onLine) {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
const env = {
|
|
23
|
+
...process.env,
|
|
24
|
+
...(opts.env ?? {}),
|
|
25
|
+
FORCE_COLOR: "0",
|
|
26
|
+
NO_COLOR: "1",
|
|
27
|
+
CI: "1",
|
|
28
|
+
TERM: "dumb",
|
|
29
|
+
};
|
|
30
|
+
const proc = spawn(cmd, args, { ...opts, env, stdio: ["ignore", "pipe", "pipe"] });
|
|
31
|
+
const lines = [];
|
|
32
|
+
let outBuf = "";
|
|
33
|
+
let errBuf = "";
|
|
34
|
+
const flush = (buf, sink) => {
|
|
35
|
+
let i;
|
|
36
|
+
while ((i = buf.indexOf("\n")) !== -1) {
|
|
37
|
+
const line = stripAnsi(buf.slice(0, i)).replace(/\r$/, "");
|
|
38
|
+
lines.push(line);
|
|
39
|
+
sink(line);
|
|
40
|
+
buf = buf.slice(i + 1);
|
|
41
|
+
}
|
|
42
|
+
return buf;
|
|
43
|
+
};
|
|
44
|
+
proc.stdout.on("data", (d) => {
|
|
45
|
+
outBuf += d.toString();
|
|
46
|
+
outBuf = flush(outBuf, (l) => onLine?.(l));
|
|
47
|
+
});
|
|
48
|
+
proc.stderr.on("data", (d) => {
|
|
49
|
+
errBuf += d.toString();
|
|
50
|
+
errBuf = flush(errBuf, (l) => onLine?.(l));
|
|
51
|
+
});
|
|
52
|
+
proc.on("error", (err) => {
|
|
53
|
+
resolve({ code: -1, output: lines.join("\n"), error: err.message });
|
|
54
|
+
});
|
|
55
|
+
proc.on("close", (code) => {
|
|
56
|
+
if (outBuf) {
|
|
57
|
+
const line = stripAnsi(outBuf).replace(/\r$/, "");
|
|
58
|
+
lines.push(line);
|
|
59
|
+
onLine?.(line);
|
|
60
|
+
}
|
|
61
|
+
if (errBuf) {
|
|
62
|
+
const line = stripAnsi(errBuf).replace(/\r$/, "");
|
|
63
|
+
lines.push(line);
|
|
64
|
+
onLine?.(line);
|
|
65
|
+
}
|
|
66
|
+
resolve({ code: code ?? -1, output: lines.join("\n"), error: null });
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
export async function runStep(dir, stepName, cmd, args, emit) {
|
|
71
|
+
emit({ type: "progress", step: stepName, status: "running" });
|
|
72
|
+
const start = Date.now();
|
|
73
|
+
const result = await runCmd(cmd, args, { cwd: dir }, (l) => emit({ type: "log", step: stepName, message: l }));
|
|
74
|
+
const durationMs = Date.now() - start;
|
|
75
|
+
const tail = result.output.split("\n").slice(-MAX_TAIL_LINES).join("\n");
|
|
76
|
+
const passed = result.code === 0;
|
|
77
|
+
emit({
|
|
78
|
+
type: "step_result",
|
|
79
|
+
step: stepName,
|
|
80
|
+
passed,
|
|
81
|
+
exitCode: result.code,
|
|
82
|
+
durationMs,
|
|
83
|
+
tail,
|
|
84
|
+
});
|
|
85
|
+
return { passed, exitCode: result.code, durationMs, tail };
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=cmd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cmd.js","sourceRoot":"","sources":["../../../../../server/forge/core/validator/cmd.ts"],"names":[],"mappings":"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"}
|