@ipul-labs/forge 1.16.8 → 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 +39 -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 +15 -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 -163
- 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 -116
- 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 -1027
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* server/forge/core/localRepo.js
|
|
3
|
-
*
|
|
4
|
-
* Shared helpers for maintaining a shallow working clone of a repo under
|
|
5
|
-
* ~/.forge/cache/<repo>/ and overlaying proposed file changes onto it.
|
|
6
|
-
*
|
|
7
|
-
* Used by:
|
|
8
|
-
* - validator.js → run lint/typecheck/test against the overlaid tree
|
|
9
|
-
* - ForgeAgent.refineIssue → give the refine model real Read/Glob/Grep access
|
|
10
|
-
* against the current state of the working tree (FORGE_REFINE_REPO_ACCESS)
|
|
11
|
-
*
|
|
12
|
-
* Scope matches validator v1: GitLab HTTPS clones only. GitHub / Azure DevOps
|
|
13
|
-
* raise a clear "not supported yet" error so the caller can fall back cleanly.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { spawn } from "child_process";
|
|
17
|
-
import { writeFileSync, unlinkSync } from "fs";
|
|
18
|
-
import fs from "fs/promises";
|
|
19
|
-
import os from "os";
|
|
20
|
-
import path from "path";
|
|
21
|
-
|
|
22
|
-
import { getConnection } from "./configStore.js";
|
|
23
|
-
|
|
24
|
-
const CACHE_ROOT = process.env.FORGE_VALIDATE_CACHE
|
|
25
|
-
?? path.join(os.homedir(), ".forge", "cache");
|
|
26
|
-
|
|
27
|
-
function runGit(args, opts = {}, onLog) {
|
|
28
|
-
return new Promise((resolve) => {
|
|
29
|
-
const proc = spawn("git", args, {
|
|
30
|
-
...opts,
|
|
31
|
-
env: { ...process.env, ...(opts.env ?? {}), FORCE_COLOR: "0", NO_COLOR: "1", TERM: "dumb" },
|
|
32
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
33
|
-
});
|
|
34
|
-
const lines = [];
|
|
35
|
-
const collect = (buf) => {
|
|
36
|
-
for (const raw of buf.toString().split("\n")) {
|
|
37
|
-
const line = raw.replace(/\r$/, "");
|
|
38
|
-
if (!line) continue;
|
|
39
|
-
lines.push(line);
|
|
40
|
-
onLog?.(line);
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
proc.stdout.on("data", collect);
|
|
44
|
-
proc.stderr.on("data", collect);
|
|
45
|
-
proc.on("error", (err) => resolve({ code: -1, output: lines.join("\n"), error: err.message }));
|
|
46
|
-
proc.on("close", (code) => resolve({ code: code ?? -1, output: lines.join("\n"), error: null }));
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async function exists(p) {
|
|
51
|
-
try { await fs.access(p); return true; } catch { return false; }
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function sanitizeRepo(repo) {
|
|
55
|
-
return repo.replace(/[^a-zA-Z0-9_./-]/g, "_");
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function gitlabCloneUrl(project) {
|
|
59
|
-
return `https://gitlab.com/${project}.git`;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function createAskpassScript(token) {
|
|
63
|
-
const script = path.join(os.tmpdir(), `.forge-askpass-${process.pid}-${Date.now()}`);
|
|
64
|
-
writeFileSync(script, `#!/bin/sh\ncase "$1" in *Username*) echo oauth2;; *) echo "${token}";; esac\n`, { mode: 0o700 });
|
|
65
|
-
return script;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function gitEnvWithToken() {
|
|
69
|
-
const { token } = getConnection("gitlab");
|
|
70
|
-
if (!token) throw new Error("GitLab token is required to clone the repo locally. Set it in Settings → Connections or via GITLAB_TOKEN env var.");
|
|
71
|
-
const askpass = createAskpassScript(token);
|
|
72
|
-
return {
|
|
73
|
-
env: {
|
|
74
|
-
GIT_ASKPASS: askpass,
|
|
75
|
-
GIT_TERMINAL_PROMPT: "0",
|
|
76
|
-
},
|
|
77
|
-
cleanup: () => { try { unlinkSync(askpass); } catch {} },
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function resolveCloneUrl(repoInput) {
|
|
82
|
-
const colon = repoInput.indexOf(":");
|
|
83
|
-
if (colon > 0) {
|
|
84
|
-
const prefix = repoInput.slice(0, colon).toLowerCase();
|
|
85
|
-
if (prefix === "gitlab") return gitlabCloneUrl(repoInput.slice(colon + 1));
|
|
86
|
-
if (prefix === "github" || prefix === "azuredevops" || prefix === "azure") {
|
|
87
|
-
throw new Error(`Local clone for ${prefix} repos isn't supported yet — GitLab only.`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return gitlabCloneUrl(repoInput);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function cachePathFor(repo) {
|
|
94
|
-
return path.join(CACHE_ROOT, sanitizeRepo(repo));
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Ensures the repo is cloned and reset to a clean branch at origin/main.
|
|
99
|
-
* Reuses any existing clone under ~/.forge/cache/<repo>/.
|
|
100
|
-
*
|
|
101
|
-
* @param {string} repo Repo id (may carry a "gitlab:" prefix)
|
|
102
|
-
* @param {string} branchName Workspace branch to check out
|
|
103
|
-
* @param {(msg: string) => void} [onLog]
|
|
104
|
-
* @returns {Promise<string>} Absolute path to the working tree
|
|
105
|
-
*/
|
|
106
|
-
export async function ensureWorkingTree(repo, branchName, onLog) {
|
|
107
|
-
const dir = cachePathFor(repo);
|
|
108
|
-
const hasRepo = await exists(path.join(dir, ".git"));
|
|
109
|
-
const log = (m) => onLog?.(m);
|
|
110
|
-
|
|
111
|
-
const { env: gitEnv, cleanup } = gitEnvWithToken();
|
|
112
|
-
const envOpts = { env: { ...process.env, ...gitEnv } };
|
|
113
|
-
try {
|
|
114
|
-
if (!hasRepo) {
|
|
115
|
-
log(`Cloning ${repo} → ${dir}`);
|
|
116
|
-
await fs.mkdir(dir, { recursive: true });
|
|
117
|
-
const clone = await runGit(["clone", "--depth=1", resolveCloneUrl(repo), dir], envOpts, onLog);
|
|
118
|
-
if (clone.code !== 0) throw new Error(`git clone failed (code ${clone.code})`);
|
|
119
|
-
} else {
|
|
120
|
-
log(`Reusing clone at ${dir}`);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const fetch = await runGit(["fetch", "--depth=1", "origin", "main"], { cwd: dir, ...envOpts }, onLog);
|
|
124
|
-
if (fetch.code !== 0) throw new Error(`git fetch failed (code ${fetch.code})`);
|
|
125
|
-
|
|
126
|
-
const reset = await runGit(["reset", "--hard", "origin/main"], { cwd: dir }, onLog);
|
|
127
|
-
if (reset.code !== 0) throw new Error(`git reset failed (code ${reset.code})`);
|
|
128
|
-
await runGit(["clean", "-fd"], { cwd: dir }, onLog);
|
|
129
|
-
|
|
130
|
-
const checkout = await runGit(["checkout", "-B", branchName], { cwd: dir }, onLog);
|
|
131
|
-
if (checkout.code !== 0) throw new Error(`git checkout ${branchName} failed (code ${checkout.code})`);
|
|
132
|
-
|
|
133
|
-
return dir;
|
|
134
|
-
} finally {
|
|
135
|
-
cleanup();
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Writes proposed file contents into the working tree (or deletes files for
|
|
141
|
-
* action="delete"). Refuses paths that escape the clone directory.
|
|
142
|
-
*
|
|
143
|
-
* @param {string} dir
|
|
144
|
-
* @param {Array<{file: string, action: 'create'|'modify'|'delete', proposed?: string}>} changes
|
|
145
|
-
* @param {(msg: string) => void} [onLog]
|
|
146
|
-
*/
|
|
147
|
-
export async function overlayChanges(dir, changes, onLog) {
|
|
148
|
-
const realBase = await fs.realpath(dir);
|
|
149
|
-
for (const c of changes) {
|
|
150
|
-
const full = path.resolve(dir, c.file);
|
|
151
|
-
if (!full.startsWith(realBase + path.sep) && full !== realBase) {
|
|
152
|
-
throw new Error(`Refusing to write outside clone dir: ${c.file}`);
|
|
153
|
-
}
|
|
154
|
-
if (c.action === "delete") {
|
|
155
|
-
await fs.rm(full, { force: true });
|
|
156
|
-
onLog?.(`- ${c.file}`);
|
|
157
|
-
} else {
|
|
158
|
-
await fs.mkdir(path.dirname(full), { recursive: true });
|
|
159
|
-
await fs.writeFile(full, c.proposed ?? "");
|
|
160
|
-
onLog?.(`+ ${c.file} (${c.action})`);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* server/forge/core/openclawClient.js
|
|
3
|
-
*
|
|
4
|
-
* Communicates with a locally-running OpenClaw Gateway over HTTP.
|
|
5
|
-
* Configure with:
|
|
6
|
-
* OPENCLAW_GATEWAY_URL — e.g. http://192.168.x.x:18789 (Tailscale) or SSH tunnel
|
|
7
|
-
* OPENCLAW_TOKEN — Bearer token if your Gateway requires auth
|
|
8
|
-
*
|
|
9
|
-
* The Gateway runs on 127.0.0.1:18789 by default. Expose it remotely via:
|
|
10
|
-
* Tailscale: bind to tailnet interface
|
|
11
|
-
* SSH tunnel: ssh -N -L 18789:127.0.0.1:18789 user@host
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
buildIdentifyFilesPrompt,
|
|
16
|
-
buildProposeFixPrompt,
|
|
17
|
-
buildRefineOrAskPrompt,
|
|
18
|
-
buildCheckResolutionPrompt,
|
|
19
|
-
} from "./prompts.js";
|
|
20
|
-
|
|
21
|
-
const GATEWAY_URL = process.env.OPENCLAW_GATEWAY_URL?.replace(/\/$/, "");
|
|
22
|
-
const GATEWAY_TOKEN = process.env.OPENCLAW_TOKEN;
|
|
23
|
-
const TIMEOUT_MS = 120_000;
|
|
24
|
-
|
|
25
|
-
// ─── JSON output helpers ──────────────────────────────────────────────────────
|
|
26
|
-
|
|
27
|
-
function extractJSON(text) {
|
|
28
|
-
const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
29
|
-
if (fenced) return JSON.parse(fenced[1].trim());
|
|
30
|
-
const start = text.indexOf("{");
|
|
31
|
-
const end = text.lastIndexOf("}");
|
|
32
|
-
if (start !== -1 && end !== -1) return JSON.parse(text.slice(start, end + 1));
|
|
33
|
-
throw new Error("No JSON found in OpenClaw response");
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ─── Gateway transport ────────────────────────────────────────────────────────
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Send a prompt to the OpenClaw Gateway and return the text response.
|
|
40
|
-
*
|
|
41
|
-
* @param {string} prompt
|
|
42
|
-
* @param {string} [model]
|
|
43
|
-
* @param {{ signal?: AbortSignal }} [opts]
|
|
44
|
-
* @returns {Promise<string>}
|
|
45
|
-
*/
|
|
46
|
-
async function callGateway(prompt, model, opts = {}) {
|
|
47
|
-
if (!GATEWAY_URL) {
|
|
48
|
-
throw new Error(
|
|
49
|
-
"OPENCLAW_GATEWAY_URL is not set. Add it to your .env and point it at your OpenClaw Gateway.",
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const controller = new AbortController();
|
|
54
|
-
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
55
|
-
// Chain the external cancel signal so a job cancel aborts the fetch in
|
|
56
|
-
// addition to the timeout.
|
|
57
|
-
const external = opts.signal;
|
|
58
|
-
const onExternalAbort = () => controller.abort();
|
|
59
|
-
if (external) {
|
|
60
|
-
if (external.aborted) controller.abort();
|
|
61
|
-
else external.addEventListener("abort", onExternalAbort, { once: true });
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
try {
|
|
65
|
-
const body = { message: prompt };
|
|
66
|
-
if (model) body.model = model;
|
|
67
|
-
|
|
68
|
-
const res = await fetch(`${GATEWAY_URL}/api/v1/agent`, {
|
|
69
|
-
method: "POST",
|
|
70
|
-
headers: {
|
|
71
|
-
"Content-Type": "application/json",
|
|
72
|
-
...(GATEWAY_TOKEN ? { Authorization: `Bearer ${GATEWAY_TOKEN}` } : {}),
|
|
73
|
-
},
|
|
74
|
-
body: JSON.stringify(body),
|
|
75
|
-
signal: controller.signal,
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
if (!res.ok) {
|
|
79
|
-
const text = await res.text().catch(() => "");
|
|
80
|
-
throw new Error(`OpenClaw gateway ${res.status}: ${text.slice(0, 300)}`);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const data = await res.json();
|
|
84
|
-
return data.result ?? data.message ?? data.content ?? data.text ?? JSON.stringify(data);
|
|
85
|
-
} catch (err) {
|
|
86
|
-
if (err.name === "AbortError") {
|
|
87
|
-
// External cancellation wins over "timeout" framing so the terminal
|
|
88
|
-
// event the job emits reflects the user action, not a stale timer.
|
|
89
|
-
if (external?.aborted) throw err;
|
|
90
|
-
throw new Error("OpenClaw gateway timed out after 2 minutes");
|
|
91
|
-
}
|
|
92
|
-
throw err;
|
|
93
|
-
} finally {
|
|
94
|
-
clearTimeout(timer);
|
|
95
|
-
external?.removeEventListener("abort", onExternalAbort);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// ─── Public API (mirrors claudeClient.js) ────────────────────────────────────
|
|
100
|
-
|
|
101
|
-
export async function checkResolution(issue, diffs, model, opts = {}) {
|
|
102
|
-
const text = await callGateway(buildCheckResolutionPrompt(issue, diffs), model, opts);
|
|
103
|
-
const data = extractJSON(text);
|
|
104
|
-
return { ...data, cost: 0, serviceTier: "openclaw", inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 };
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export async function identifyRelevantFiles(issue, fileTree, model, opts = {}) {
|
|
108
|
-
const text = await callGateway(buildIdentifyFilesPrompt(issue, fileTree), model, opts);
|
|
109
|
-
const data = extractJSON(text);
|
|
110
|
-
return { ...data, cost: 0, serviceTier: "openclaw", inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 };
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export async function proposeFix(issue, fileContents, options = {}, model, opts = {}) {
|
|
114
|
-
const text = await callGateway(buildProposeFixPrompt(issue, fileContents, options), model, opts);
|
|
115
|
-
const data = extractJSON(text);
|
|
116
|
-
return { ...data, cost: 0, serviceTier: "openclaw", inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 };
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export async function refineOrAsk(issue, fileContents, options = {}, model, _onEvent, opts = {}) {
|
|
120
|
-
// OpenClaw is a single HTTP round-trip — no streaming surface. The onEvent
|
|
121
|
-
// callback is accepted for signature parity with claudeClient and ignored.
|
|
122
|
-
const text = await callGateway(buildRefineOrAskPrompt(issue, fileContents, options), model, opts);
|
|
123
|
-
const data = extractJSON(text);
|
|
124
|
-
return { ...data, cost: 0, serviceTier: "openclaw", inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 };
|
|
125
|
-
}
|