@adhdev/daemon-core 0.7.43 → 0.7.45
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/commands/upgrade-helper.d.ts +10 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +441 -252
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +429 -241
- package/dist/index.mjs.map +1 -1
- package/node_modules/@adhdev/session-host-core/dist/index.js +2 -2
- package/node_modules/@adhdev/session-host-core/dist/index.js.map +1 -1
- package/node_modules/@adhdev/session-host-core/dist/index.mjs +2 -2
- package/node_modules/@adhdev/session-host-core/dist/index.mjs.map +1 -1
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +4 -4
- package/src/commands/router.ts +29 -23
- package/src/commands/upgrade-helper.ts +214 -0
- package/src/index.ts +1 -0
package/dist/index.mjs
CHANGED
|
@@ -686,7 +686,7 @@ var init_terminal_screen = __esm({
|
|
|
686
686
|
});
|
|
687
687
|
|
|
688
688
|
// src/cli-adapters/pty-transport.ts
|
|
689
|
-
import * as
|
|
689
|
+
import * as os12 from "os";
|
|
690
690
|
var pty, NodePtyRuntimeTransport, NodePtyTransportFactory;
|
|
691
691
|
var init_pty_transport = __esm({
|
|
692
692
|
"src/cli-adapters/pty-transport.ts"() {
|
|
@@ -728,7 +728,7 @@ var init_pty_transport = __esm({
|
|
|
728
728
|
spawn(command, args, options) {
|
|
729
729
|
if (!pty) throw new Error("node-pty is not installed");
|
|
730
730
|
const handle = pty.spawn(command, args, {
|
|
731
|
-
name:
|
|
731
|
+
name: os12.platform() === "win32" ? "xterm-color" : "xterm-256color",
|
|
732
732
|
cols: options.cols,
|
|
733
733
|
rows: options.rows,
|
|
734
734
|
cwd: options.cwd,
|
|
@@ -746,8 +746,8 @@ __export(provider_cli_adapter_exports, {
|
|
|
746
746
|
ProviderCliAdapter: () => ProviderCliAdapter,
|
|
747
747
|
normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
|
|
748
748
|
});
|
|
749
|
-
import * as
|
|
750
|
-
import * as
|
|
749
|
+
import * as os13 from "os";
|
|
750
|
+
import * as path10 from "path";
|
|
751
751
|
import { execSync as execSync4 } from "child_process";
|
|
752
752
|
function stripAnsi(str) {
|
|
753
753
|
return str.replace(/\x1B\[\d*[A-HJKSTfG]/g, " ").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][^\x1B]*\x1B\\/g, "").replace(/ +/g, " ");
|
|
@@ -785,7 +785,7 @@ function computeTerminalQueryTail(buffer) {
|
|
|
785
785
|
return "";
|
|
786
786
|
}
|
|
787
787
|
function findBinary(name) {
|
|
788
|
-
const isWin =
|
|
788
|
+
const isWin = os13.platform() === "win32";
|
|
789
789
|
try {
|
|
790
790
|
const cmd = isWin ? `where ${name}` : `which ${name}`;
|
|
791
791
|
return execSync4(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n")[0].trim();
|
|
@@ -794,14 +794,14 @@ function findBinary(name) {
|
|
|
794
794
|
}
|
|
795
795
|
}
|
|
796
796
|
function isScriptBinary(binaryPath) {
|
|
797
|
-
if (!
|
|
797
|
+
if (!path10.isAbsolute(binaryPath)) return false;
|
|
798
798
|
try {
|
|
799
|
-
const
|
|
800
|
-
const resolved =
|
|
799
|
+
const fs13 = __require("fs");
|
|
800
|
+
const resolved = fs13.realpathSync(binaryPath);
|
|
801
801
|
const head = Buffer.alloc(8);
|
|
802
|
-
const fd =
|
|
803
|
-
|
|
804
|
-
|
|
802
|
+
const fd = fs13.openSync(resolved, "r");
|
|
803
|
+
fs13.readSync(fd, head, 0, 8, 0);
|
|
804
|
+
fs13.closeSync(fd);
|
|
805
805
|
let i = 0;
|
|
806
806
|
if (head[0] === 239 && head[1] === 187 && head[2] === 191) i = 3;
|
|
807
807
|
return head[i] === 35 && head[i + 1] === 33;
|
|
@@ -810,14 +810,14 @@ function isScriptBinary(binaryPath) {
|
|
|
810
810
|
}
|
|
811
811
|
}
|
|
812
812
|
function looksLikeMachOOrElf(filePath) {
|
|
813
|
-
if (!
|
|
813
|
+
if (!path10.isAbsolute(filePath)) return false;
|
|
814
814
|
try {
|
|
815
|
-
const
|
|
816
|
-
const resolved =
|
|
815
|
+
const fs13 = __require("fs");
|
|
816
|
+
const resolved = fs13.realpathSync(filePath);
|
|
817
817
|
const buf = Buffer.alloc(8);
|
|
818
|
-
const fd =
|
|
819
|
-
|
|
820
|
-
|
|
818
|
+
const fd = fs13.openSync(resolved, "r");
|
|
819
|
+
fs13.readSync(fd, buf, 0, 8, 0);
|
|
820
|
+
fs13.closeSync(fd);
|
|
821
821
|
let i = 0;
|
|
822
822
|
if (buf[0] === 239 && buf[1] === 187 && buf[2] === 191) i = 3;
|
|
823
823
|
const b = buf.subarray(i);
|
|
@@ -833,12 +833,12 @@ function looksLikeMachOOrElf(filePath) {
|
|
|
833
833
|
}
|
|
834
834
|
function shSingleQuote(arg) {
|
|
835
835
|
if (/^[a-zA-Z0-9@%_+=:,./-]+$/.test(arg)) return arg;
|
|
836
|
-
if (
|
|
836
|
+
if (os13.platform() === "win32") {
|
|
837
837
|
return `"${arg.replace(/"/g, '""')}"`;
|
|
838
838
|
}
|
|
839
839
|
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
840
840
|
}
|
|
841
|
-
function estimatePromptDisplayLines(text, cols =
|
|
841
|
+
function estimatePromptDisplayLines(text, cols = 80) {
|
|
842
842
|
const normalized = String(text || "").replace(/\r/g, "");
|
|
843
843
|
if (!normalized) return 1;
|
|
844
844
|
return normalized.split("\n").reduce((sum, line) => sum + Math.max(1, Math.ceil(Math.max(1, line.length) / cols)), 0);
|
|
@@ -903,16 +903,16 @@ var init_provider_cli_adapter = __esm({
|
|
|
903
903
|
init_pty_transport();
|
|
904
904
|
try {
|
|
905
905
|
pty2 = __require("node-pty");
|
|
906
|
-
if (
|
|
906
|
+
if (os13.platform() !== "win32") {
|
|
907
907
|
try {
|
|
908
|
-
const
|
|
909
|
-
const ptyDir =
|
|
910
|
-
const platformArch = `${
|
|
911
|
-
const helper =
|
|
912
|
-
if (
|
|
913
|
-
const stat =
|
|
908
|
+
const fs13 = __require("fs");
|
|
909
|
+
const ptyDir = path10.resolve(path10.dirname(__require.resolve("node-pty")), "..");
|
|
910
|
+
const platformArch = `${os13.platform()}-${os13.arch()}`;
|
|
911
|
+
const helper = path10.join(ptyDir, "prebuilds", platformArch, "spawn-helper");
|
|
912
|
+
if (fs13.existsSync(helper)) {
|
|
913
|
+
const stat = fs13.statSync(helper);
|
|
914
914
|
if (!(stat.mode & 73)) {
|
|
915
|
-
|
|
915
|
+
fs13.chmodSync(helper, stat.mode | 493);
|
|
916
916
|
LOG.info("CLI", "[node-pty] Fixed spawn-helper permissions");
|
|
917
917
|
}
|
|
918
918
|
}
|
|
@@ -929,7 +929,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
929
929
|
this.transportFactory = transportFactory;
|
|
930
930
|
this.cliType = provider.type;
|
|
931
931
|
this.cliName = provider.name;
|
|
932
|
-
this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/,
|
|
932
|
+
this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os13.homedir()) : workingDir;
|
|
933
933
|
const t = provider.timeouts || {};
|
|
934
934
|
this.timeouts = {
|
|
935
935
|
ptyFlush: t.ptyFlush ?? 50,
|
|
@@ -1096,12 +1096,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
1096
1096
|
if (this.ptyProcess) return;
|
|
1097
1097
|
const { spawn: spawnConfig } = this.provider;
|
|
1098
1098
|
const binaryPath = findBinary(spawnConfig.command);
|
|
1099
|
-
const isWin =
|
|
1099
|
+
const isWin = os13.platform() === "win32";
|
|
1100
1100
|
const allArgs = [...spawnConfig.args, ...this.extraArgs];
|
|
1101
1101
|
LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
|
|
1102
1102
|
let shellCmd;
|
|
1103
1103
|
let shellArgs;
|
|
1104
|
-
const useShellUnix = !isWin && (!!spawnConfig.shell || !
|
|
1104
|
+
const useShellUnix = !isWin && (!!spawnConfig.shell || !path10.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
|
|
1105
1105
|
const useShell = isWin ? !!spawnConfig.shell : useShellUnix;
|
|
1106
1106
|
if (useShell) {
|
|
1107
1107
|
if (!spawnConfig.shell && !isWin) {
|
|
@@ -1119,8 +1119,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
1119
1119
|
shellArgs = allArgs;
|
|
1120
1120
|
}
|
|
1121
1121
|
const ptyOpts = {
|
|
1122
|
-
cols:
|
|
1123
|
-
rows:
|
|
1122
|
+
cols: 80,
|
|
1123
|
+
rows: 24,
|
|
1124
1124
|
cwd: this.workingDir,
|
|
1125
1125
|
env: buildCliSpawnEnv(process.env, spawnConfig.env)
|
|
1126
1126
|
};
|
|
@@ -1176,7 +1176,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
1176
1176
|
this.spawnAt = Date.now();
|
|
1177
1177
|
this.startupParseGate = true;
|
|
1178
1178
|
this.startupBuffer = "";
|
|
1179
|
-
this.terminalScreen.reset(
|
|
1179
|
+
this.terminalScreen.reset(24, 80);
|
|
1180
1180
|
this.pendingTerminalQueryTail = "";
|
|
1181
1181
|
this.currentTurnScope = null;
|
|
1182
1182
|
this.ready = false;
|
|
@@ -2204,18 +2204,18 @@ function checkPathExists(paths) {
|
|
|
2204
2204
|
return null;
|
|
2205
2205
|
}
|
|
2206
2206
|
async function detectIDEs() {
|
|
2207
|
-
const
|
|
2207
|
+
const os17 = platform();
|
|
2208
2208
|
const results = [];
|
|
2209
2209
|
for (const def of getMergedDefinitions()) {
|
|
2210
2210
|
const cliPath = findCliCommand(def.cli);
|
|
2211
|
-
const appPath = checkPathExists(def.paths[
|
|
2211
|
+
const appPath = checkPathExists(def.paths[os17] || []);
|
|
2212
2212
|
const installed = !!(cliPath || appPath);
|
|
2213
2213
|
let resolvedCli = cliPath;
|
|
2214
|
-
if (!resolvedCli && appPath &&
|
|
2214
|
+
if (!resolvedCli && appPath && os17 === "darwin") {
|
|
2215
2215
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
2216
2216
|
if (existsSync3(bundledCli)) resolvedCli = bundledCli;
|
|
2217
2217
|
}
|
|
2218
|
-
if (!resolvedCli && appPath &&
|
|
2218
|
+
if (!resolvedCli && appPath && os17 === "win32") {
|
|
2219
2219
|
const { dirname: dirname7 } = await import("path");
|
|
2220
2220
|
const appDir = dirname7(appPath);
|
|
2221
2221
|
const candidates = [
|
|
@@ -8234,7 +8234,7 @@ function detectCurrentWorkspace(ideId) {
|
|
|
8234
8234
|
}
|
|
8235
8235
|
} else if (plat === "win32") {
|
|
8236
8236
|
try {
|
|
8237
|
-
const
|
|
8237
|
+
const fs13 = __require("fs");
|
|
8238
8238
|
const appNameMap = getMacAppIdentifiers();
|
|
8239
8239
|
const appName = appNameMap[ideId];
|
|
8240
8240
|
if (appName) {
|
|
@@ -8243,8 +8243,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
8243
8243
|
appName,
|
|
8244
8244
|
"storage.json"
|
|
8245
8245
|
);
|
|
8246
|
-
if (
|
|
8247
|
-
const data = JSON.parse(
|
|
8246
|
+
if (fs13.existsSync(storagePath)) {
|
|
8247
|
+
const data = JSON.parse(fs13.readFileSync(storagePath, "utf-8"));
|
|
8248
8248
|
const workspaces = data?.openedPathsList?.workspaces3 || data?.openedPathsList?.entries || [];
|
|
8249
8249
|
if (workspaces.length > 0) {
|
|
8250
8250
|
const recent = workspaces[0];
|
|
@@ -8689,8 +8689,191 @@ function buildStatusSnapshot(options) {
|
|
|
8689
8689
|
};
|
|
8690
8690
|
}
|
|
8691
8691
|
|
|
8692
|
-
// src/commands/
|
|
8692
|
+
// src/commands/upgrade-helper.ts
|
|
8693
|
+
import { execFileSync } from "child_process";
|
|
8694
|
+
import { spawn as spawn2 } from "child_process";
|
|
8693
8695
|
import * as fs7 from "fs";
|
|
8696
|
+
import * as os11 from "os";
|
|
8697
|
+
import * as path9 from "path";
|
|
8698
|
+
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
8699
|
+
function getUpgradeLogPath() {
|
|
8700
|
+
const home = os11.homedir();
|
|
8701
|
+
const dir = path9.join(home, ".adhdev");
|
|
8702
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
8703
|
+
return path9.join(dir, "daemon-upgrade.log");
|
|
8704
|
+
}
|
|
8705
|
+
function appendUpgradeLog(message) {
|
|
8706
|
+
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
8707
|
+
`;
|
|
8708
|
+
try {
|
|
8709
|
+
fs7.appendFileSync(getUpgradeLogPath(), line, "utf8");
|
|
8710
|
+
} catch {
|
|
8711
|
+
}
|
|
8712
|
+
}
|
|
8713
|
+
function getNpmExecutable() {
|
|
8714
|
+
return process.platform === "win32" ? "npm.cmd" : "npm";
|
|
8715
|
+
}
|
|
8716
|
+
function killPid(pid) {
|
|
8717
|
+
try {
|
|
8718
|
+
if (process.platform === "win32") {
|
|
8719
|
+
execFileSync("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
|
|
8720
|
+
} else {
|
|
8721
|
+
process.kill(pid, "SIGTERM");
|
|
8722
|
+
}
|
|
8723
|
+
return true;
|
|
8724
|
+
} catch {
|
|
8725
|
+
return false;
|
|
8726
|
+
}
|
|
8727
|
+
}
|
|
8728
|
+
async function waitForPidExit(pid, timeoutMs) {
|
|
8729
|
+
const start = Date.now();
|
|
8730
|
+
while (Date.now() - start < timeoutMs) {
|
|
8731
|
+
try {
|
|
8732
|
+
process.kill(pid, 0);
|
|
8733
|
+
await new Promise((resolve9) => setTimeout(resolve9, 250));
|
|
8734
|
+
} catch {
|
|
8735
|
+
return;
|
|
8736
|
+
}
|
|
8737
|
+
}
|
|
8738
|
+
}
|
|
8739
|
+
function stopSessionHostProcesses(appName) {
|
|
8740
|
+
const pidFile = path9.join(os11.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
8741
|
+
try {
|
|
8742
|
+
if (fs7.existsSync(pidFile)) {
|
|
8743
|
+
const pid = Number.parseInt(fs7.readFileSync(pidFile, "utf8").trim(), 10);
|
|
8744
|
+
if (Number.isFinite(pid)) {
|
|
8745
|
+
killPid(pid);
|
|
8746
|
+
}
|
|
8747
|
+
}
|
|
8748
|
+
} catch {
|
|
8749
|
+
} finally {
|
|
8750
|
+
try {
|
|
8751
|
+
fs7.unlinkSync(pidFile);
|
|
8752
|
+
} catch {
|
|
8753
|
+
}
|
|
8754
|
+
}
|
|
8755
|
+
if (process.platform !== "win32") {
|
|
8756
|
+
try {
|
|
8757
|
+
const raw = execFileSync("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
|
|
8758
|
+
for (const line of raw.split("\n")) {
|
|
8759
|
+
const pid = Number.parseInt(line.trim(), 10);
|
|
8760
|
+
if (Number.isFinite(pid)) {
|
|
8761
|
+
killPid(pid);
|
|
8762
|
+
}
|
|
8763
|
+
}
|
|
8764
|
+
} catch {
|
|
8765
|
+
}
|
|
8766
|
+
}
|
|
8767
|
+
}
|
|
8768
|
+
function removeDaemonPidFile() {
|
|
8769
|
+
const pidFile = path9.join(os11.homedir(), ".adhdev", "daemon.pid");
|
|
8770
|
+
try {
|
|
8771
|
+
fs7.unlinkSync(pidFile);
|
|
8772
|
+
} catch {
|
|
8773
|
+
}
|
|
8774
|
+
}
|
|
8775
|
+
function cleanupStaleGlobalInstallDirs(pkgName) {
|
|
8776
|
+
const npmRoot = execFileSync(getNpmExecutable(), ["root", "-g"], { encoding: "utf8" }).trim();
|
|
8777
|
+
if (!npmRoot) return;
|
|
8778
|
+
const npmPrefix = execFileSync(getNpmExecutable(), ["prefix", "-g"], { encoding: "utf8" }).trim();
|
|
8779
|
+
const binDir = process.platform === "win32" ? npmPrefix : path9.join(npmPrefix, "bin");
|
|
8780
|
+
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
8781
|
+
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
8782
|
+
if (pkgName === "@adhdev/daemon-standalone") {
|
|
8783
|
+
binNames.add("adhdev-standalone");
|
|
8784
|
+
}
|
|
8785
|
+
if (pkgName.startsWith("@")) {
|
|
8786
|
+
const [scope, name] = pkgName.split("/");
|
|
8787
|
+
const scopeDir = path9.join(npmRoot, scope);
|
|
8788
|
+
if (!fs7.existsSync(scopeDir)) return;
|
|
8789
|
+
for (const entry of fs7.readdirSync(scopeDir)) {
|
|
8790
|
+
if (!entry.startsWith(`.${name}-`)) continue;
|
|
8791
|
+
fs7.rmSync(path9.join(scopeDir, entry), { recursive: true, force: true });
|
|
8792
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path9.join(scopeDir, entry)}`);
|
|
8793
|
+
}
|
|
8794
|
+
} else {
|
|
8795
|
+
for (const entry of fs7.readdirSync(npmRoot)) {
|
|
8796
|
+
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
8797
|
+
fs7.rmSync(path9.join(npmRoot, entry), { recursive: true, force: true });
|
|
8798
|
+
appendUpgradeLog(`Removed stale staging dir: ${path9.join(npmRoot, entry)}`);
|
|
8799
|
+
}
|
|
8800
|
+
}
|
|
8801
|
+
if (fs7.existsSync(binDir)) {
|
|
8802
|
+
for (const entry of fs7.readdirSync(binDir)) {
|
|
8803
|
+
if (![...binNames].some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
8804
|
+
fs7.rmSync(path9.join(binDir, entry), { recursive: true, force: true });
|
|
8805
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path9.join(binDir, entry)}`);
|
|
8806
|
+
}
|
|
8807
|
+
}
|
|
8808
|
+
}
|
|
8809
|
+
function spawnDetachedDaemonUpgradeHelper(payload) {
|
|
8810
|
+
const env = { ...process.env, [UPGRADE_HELPER_ENV]: JSON.stringify(payload) };
|
|
8811
|
+
const child = spawn2(process.execPath, process.argv.slice(1), {
|
|
8812
|
+
detached: true,
|
|
8813
|
+
stdio: "ignore",
|
|
8814
|
+
windowsHide: true,
|
|
8815
|
+
cwd: payload.cwd || process.cwd(),
|
|
8816
|
+
env
|
|
8817
|
+
});
|
|
8818
|
+
child.unref();
|
|
8819
|
+
}
|
|
8820
|
+
async function runDaemonUpgradeHelper(payload) {
|
|
8821
|
+
const restartArgv = Array.isArray(payload.restartArgv) ? payload.restartArgv : [];
|
|
8822
|
+
const sessionHostAppName = payload.sessionHostAppName || process.env.ADHDEV_SESSION_HOST_NAME || "adhdev";
|
|
8823
|
+
appendUpgradeLog(`Upgrade helper started for ${payload.packageName}@${payload.targetVersion}`);
|
|
8824
|
+
if (Number.isFinite(payload.parentPid) && payload.parentPid > 0) {
|
|
8825
|
+
appendUpgradeLog(`Waiting for parent pid ${payload.parentPid} to exit`);
|
|
8826
|
+
await waitForPidExit(payload.parentPid, 15e3);
|
|
8827
|
+
}
|
|
8828
|
+
stopSessionHostProcesses(sessionHostAppName);
|
|
8829
|
+
removeDaemonPidFile();
|
|
8830
|
+
cleanupStaleGlobalInstallDirs(payload.packageName);
|
|
8831
|
+
const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
|
|
8832
|
+
appendUpgradeLog(`Installing ${spec}`);
|
|
8833
|
+
const installOutput = execFileSync(
|
|
8834
|
+
getNpmExecutable(),
|
|
8835
|
+
["install", "-g", spec, "--force"],
|
|
8836
|
+
{
|
|
8837
|
+
encoding: "utf8",
|
|
8838
|
+
stdio: "pipe",
|
|
8839
|
+
maxBuffer: 20 * 1024 * 1024
|
|
8840
|
+
}
|
|
8841
|
+
);
|
|
8842
|
+
if (installOutput.trim()) {
|
|
8843
|
+
appendUpgradeLog(installOutput.trim());
|
|
8844
|
+
}
|
|
8845
|
+
if (restartArgv.length > 0) {
|
|
8846
|
+
const env = { ...process.env };
|
|
8847
|
+
delete env[UPGRADE_HELPER_ENV];
|
|
8848
|
+
appendUpgradeLog(`Restarting daemon with args: ${restartArgv.join(" ")}`);
|
|
8849
|
+
const child = spawn2(process.execPath, restartArgv, {
|
|
8850
|
+
detached: true,
|
|
8851
|
+
stdio: "ignore",
|
|
8852
|
+
windowsHide: true,
|
|
8853
|
+
cwd: payload.cwd || process.cwd(),
|
|
8854
|
+
env
|
|
8855
|
+
});
|
|
8856
|
+
child.unref();
|
|
8857
|
+
} else {
|
|
8858
|
+
appendUpgradeLog("No restart argv provided; upgrade completed without restart");
|
|
8859
|
+
}
|
|
8860
|
+
}
|
|
8861
|
+
async function maybeRunDaemonUpgradeHelperFromEnv() {
|
|
8862
|
+
const raw = process.env[UPGRADE_HELPER_ENV];
|
|
8863
|
+
if (!raw) return false;
|
|
8864
|
+
delete process.env[UPGRADE_HELPER_ENV];
|
|
8865
|
+
try {
|
|
8866
|
+
const payload = JSON.parse(raw);
|
|
8867
|
+
await runDaemonUpgradeHelper(payload);
|
|
8868
|
+
process.exit(0);
|
|
8869
|
+
} catch (error) {
|
|
8870
|
+
appendUpgradeLog(`Upgrade helper failed: ${error?.stack || error?.message || String(error)}`);
|
|
8871
|
+
process.exit(1);
|
|
8872
|
+
}
|
|
8873
|
+
}
|
|
8874
|
+
|
|
8875
|
+
// src/commands/router.ts
|
|
8876
|
+
import * as fs8 from "fs";
|
|
8694
8877
|
var CHAT_COMMANDS = [
|
|
8695
8878
|
"send_chat",
|
|
8696
8879
|
"new_chat",
|
|
@@ -8761,8 +8944,8 @@ var DaemonCommandRouter = class {
|
|
|
8761
8944
|
if (logs.length > 0) {
|
|
8762
8945
|
return { success: true, logs, totalBuffered: logs.length };
|
|
8763
8946
|
}
|
|
8764
|
-
if (
|
|
8765
|
-
const content =
|
|
8947
|
+
if (fs8.existsSync(LOG_PATH)) {
|
|
8948
|
+
const content = fs8.readFileSync(LOG_PATH, "utf-8");
|
|
8766
8949
|
const allLines = content.split("\n");
|
|
8767
8950
|
const recent = allLines.slice(-count).join("\n");
|
|
8768
8951
|
return { success: true, logs: recent, totalLines: allLines.length };
|
|
@@ -8910,31 +9093,35 @@ var DaemonCommandRouter = class {
|
|
|
8910
9093
|
const pkgName = isStandalone ? "@adhdev/daemon-standalone" : "adhdev";
|
|
8911
9094
|
const latest = execSync7(`npm view ${pkgName} version`, { encoding: "utf-8", timeout: 1e4 }).trim();
|
|
8912
9095
|
LOG.info("Upgrade", `Latest ${pkgName}: v${latest}`);
|
|
8913
|
-
|
|
8914
|
-
|
|
8915
|
-
|
|
8916
|
-
|
|
9096
|
+
let currentInstalled = null;
|
|
9097
|
+
try {
|
|
9098
|
+
const currentJson = execSync7(`npm ls -g ${pkgName} --depth=0 --json`, {
|
|
9099
|
+
encoding: "utf-8",
|
|
9100
|
+
timeout: 1e4,
|
|
9101
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
9102
|
+
}).trim();
|
|
9103
|
+
const parsed = JSON.parse(currentJson);
|
|
9104
|
+
currentInstalled = parsed?.dependencies?.[pkgName]?.version || null;
|
|
9105
|
+
} catch {
|
|
9106
|
+
}
|
|
9107
|
+
if (currentInstalled === latest) {
|
|
9108
|
+
LOG.info("Upgrade", `Already on latest version v${latest}; skipping install`);
|
|
9109
|
+
return { success: true, upgraded: false, alreadyLatest: true, version: latest };
|
|
9110
|
+
}
|
|
9111
|
+
spawnDetachedDaemonUpgradeHelper({
|
|
9112
|
+
packageName: pkgName,
|
|
9113
|
+
targetVersion: latest,
|
|
9114
|
+
parentPid: process.pid,
|
|
9115
|
+
restartArgv: process.argv.slice(1),
|
|
9116
|
+
cwd: process.cwd(),
|
|
9117
|
+
sessionHostAppName: process.env.ADHDEV_SESSION_HOST_NAME || "adhdev"
|
|
8917
9118
|
});
|
|
8918
|
-
LOG.info("Upgrade",
|
|
9119
|
+
LOG.info("Upgrade", `Scheduled detached upgrade to v${latest}`);
|
|
8919
9120
|
setTimeout(() => {
|
|
8920
|
-
LOG.info("Upgrade", "
|
|
8921
|
-
try {
|
|
8922
|
-
const path15 = __require("path");
|
|
8923
|
-
const fs12 = __require("fs");
|
|
8924
|
-
const pidFile = path15.join(process.env.HOME || process.env.USERPROFILE || "", ".adhdev", "daemon.pid");
|
|
8925
|
-
if (fs12.existsSync(pidFile)) fs12.unlinkSync(pidFile);
|
|
8926
|
-
} catch {
|
|
8927
|
-
}
|
|
8928
|
-
const { spawn: spawn3 } = __require("child_process");
|
|
8929
|
-
const child = spawn3(process.execPath, process.argv.slice(1), {
|
|
8930
|
-
detached: true,
|
|
8931
|
-
stdio: "ignore",
|
|
8932
|
-
env: { ...process.env }
|
|
8933
|
-
});
|
|
8934
|
-
child.unref();
|
|
9121
|
+
LOG.info("Upgrade", "Exiting daemon so detached upgrader can continue...");
|
|
8935
9122
|
process.exit(0);
|
|
8936
9123
|
}, 3e3);
|
|
8937
|
-
return { success: true, upgraded: true, version: latest };
|
|
9124
|
+
return { success: true, upgraded: true, version: latest, restarting: true };
|
|
8938
9125
|
} catch (e) {
|
|
8939
9126
|
LOG.error("Upgrade", `Failed: ${e.message}`);
|
|
8940
9127
|
return { success: false, error: e.message };
|
|
@@ -9231,8 +9418,8 @@ init_logger();
|
|
|
9231
9418
|
|
|
9232
9419
|
// src/commands/cli-manager.ts
|
|
9233
9420
|
init_provider_cli_adapter();
|
|
9234
|
-
import * as
|
|
9235
|
-
import * as
|
|
9421
|
+
import * as os14 from "os";
|
|
9422
|
+
import * as path11 from "path";
|
|
9236
9423
|
import * as crypto4 from "crypto";
|
|
9237
9424
|
import chalk from "chalk";
|
|
9238
9425
|
init_config();
|
|
@@ -9478,7 +9665,7 @@ var CliProviderInstance = class {
|
|
|
9478
9665
|
|
|
9479
9666
|
// src/providers/acp-provider-instance.ts
|
|
9480
9667
|
import { Readable, Writable } from "stream";
|
|
9481
|
-
import { spawn as
|
|
9668
|
+
import { spawn as spawn3 } from "child_process";
|
|
9482
9669
|
import {
|
|
9483
9670
|
ClientSideConnection,
|
|
9484
9671
|
ndJsonStream,
|
|
@@ -9813,7 +10000,7 @@ var AcpProviderInstance = class {
|
|
|
9813
10000
|
this.errorMessage = null;
|
|
9814
10001
|
this.errorReason = null;
|
|
9815
10002
|
this.stderrBuffer = [];
|
|
9816
|
-
this.process =
|
|
10003
|
+
this.process = spawn3(command, args, {
|
|
9817
10004
|
cwd: this.workingDir,
|
|
9818
10005
|
env,
|
|
9819
10006
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -10496,7 +10683,7 @@ var DaemonCliManager = class {
|
|
|
10496
10683
|
async startSession(cliType, workingDir, cliArgs, initialModel) {
|
|
10497
10684
|
const trimmed = (workingDir || "").trim();
|
|
10498
10685
|
if (!trimmed) throw new Error("working directory required");
|
|
10499
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/,
|
|
10686
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os14.homedir()) : path11.resolve(trimmed);
|
|
10500
10687
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
10501
10688
|
const provider = this.providerLoader.getByAlias(cliType);
|
|
10502
10689
|
const key = crypto4.randomUUID();
|
|
@@ -11693,12 +11880,12 @@ var ProviderInstanceManager = class {
|
|
|
11693
11880
|
};
|
|
11694
11881
|
|
|
11695
11882
|
// src/providers/version-archive.ts
|
|
11696
|
-
import * as
|
|
11697
|
-
import * as
|
|
11698
|
-
import * as
|
|
11883
|
+
import * as fs9 from "fs";
|
|
11884
|
+
import * as path12 from "path";
|
|
11885
|
+
import * as os15 from "os";
|
|
11699
11886
|
import { execSync as execSync5 } from "child_process";
|
|
11700
11887
|
import { platform as platform8 } from "os";
|
|
11701
|
-
var ARCHIVE_PATH =
|
|
11888
|
+
var ARCHIVE_PATH = path12.join(os15.homedir(), ".adhdev", "version-history.json");
|
|
11702
11889
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
11703
11890
|
var VersionArchive = class {
|
|
11704
11891
|
history = {};
|
|
@@ -11707,8 +11894,8 @@ var VersionArchive = class {
|
|
|
11707
11894
|
}
|
|
11708
11895
|
load() {
|
|
11709
11896
|
try {
|
|
11710
|
-
if (
|
|
11711
|
-
this.history = JSON.parse(
|
|
11897
|
+
if (fs9.existsSync(ARCHIVE_PATH)) {
|
|
11898
|
+
this.history = JSON.parse(fs9.readFileSync(ARCHIVE_PATH, "utf-8"));
|
|
11712
11899
|
}
|
|
11713
11900
|
} catch {
|
|
11714
11901
|
this.history = {};
|
|
@@ -11745,8 +11932,8 @@ var VersionArchive = class {
|
|
|
11745
11932
|
}
|
|
11746
11933
|
save() {
|
|
11747
11934
|
try {
|
|
11748
|
-
|
|
11749
|
-
|
|
11935
|
+
fs9.mkdirSync(path12.dirname(ARCHIVE_PATH), { recursive: true });
|
|
11936
|
+
fs9.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
11750
11937
|
} catch {
|
|
11751
11938
|
}
|
|
11752
11939
|
}
|
|
@@ -11785,19 +11972,19 @@ function getVersion(binary, versionCommand) {
|
|
|
11785
11972
|
function checkPathExists2(paths) {
|
|
11786
11973
|
for (const p of paths) {
|
|
11787
11974
|
if (p.includes("*")) {
|
|
11788
|
-
const home =
|
|
11789
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
11790
|
-
if (
|
|
11975
|
+
const home = os15.homedir();
|
|
11976
|
+
const resolved = p.replace(/\*/g, home.split(path12.sep).pop() || "");
|
|
11977
|
+
if (fs9.existsSync(resolved)) return resolved;
|
|
11791
11978
|
} else {
|
|
11792
|
-
if (
|
|
11979
|
+
if (fs9.existsSync(p)) return p;
|
|
11793
11980
|
}
|
|
11794
11981
|
}
|
|
11795
11982
|
return null;
|
|
11796
11983
|
}
|
|
11797
11984
|
function getMacAppVersion(appPath) {
|
|
11798
11985
|
if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
11799
|
-
const plistPath =
|
|
11800
|
-
if (!
|
|
11986
|
+
const plistPath = path12.join(appPath, "Contents", "Info.plist");
|
|
11987
|
+
if (!fs9.existsSync(plistPath)) return null;
|
|
11801
11988
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
11802
11989
|
return raw || null;
|
|
11803
11990
|
}
|
|
@@ -11823,8 +12010,8 @@ async function detectAllVersions(loader, archive) {
|
|
|
11823
12010
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
11824
12011
|
let resolvedBin = cliBin;
|
|
11825
12012
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
11826
|
-
const bundled =
|
|
11827
|
-
if (provider.cli &&
|
|
12013
|
+
const bundled = path12.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
12014
|
+
if (provider.cli && fs9.existsSync(bundled)) resolvedBin = bundled;
|
|
11828
12015
|
}
|
|
11829
12016
|
info.installed = !!(appPath || resolvedBin);
|
|
11830
12017
|
info.path = appPath || null;
|
|
@@ -11863,8 +12050,8 @@ async function detectAllVersions(loader, archive) {
|
|
|
11863
12050
|
|
|
11864
12051
|
// src/daemon/dev-server.ts
|
|
11865
12052
|
import * as http2 from "http";
|
|
11866
|
-
import * as
|
|
11867
|
-
import * as
|
|
12053
|
+
import * as fs12 from "fs";
|
|
12054
|
+
import * as path15 from "path";
|
|
11868
12055
|
|
|
11869
12056
|
// src/daemon/scaffold-template.ts
|
|
11870
12057
|
function generateFiles(type, name, category, opts = {}) {
|
|
@@ -12200,8 +12387,8 @@ init_logger();
|
|
|
12200
12387
|
|
|
12201
12388
|
// src/daemon/dev-cdp-handlers.ts
|
|
12202
12389
|
init_logger();
|
|
12203
|
-
import * as
|
|
12204
|
-
import * as
|
|
12390
|
+
import * as fs10 from "fs";
|
|
12391
|
+
import * as path13 from "path";
|
|
12205
12392
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
12206
12393
|
const body = await ctx.readBody(req);
|
|
12207
12394
|
const { expression, timeout, ideType } = body;
|
|
@@ -12379,18 +12566,18 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
12379
12566
|
return;
|
|
12380
12567
|
}
|
|
12381
12568
|
let scriptsPath = "";
|
|
12382
|
-
const directScripts =
|
|
12383
|
-
if (
|
|
12569
|
+
const directScripts = path13.join(dir, "scripts.js");
|
|
12570
|
+
if (fs10.existsSync(directScripts)) {
|
|
12384
12571
|
scriptsPath = directScripts;
|
|
12385
12572
|
} else {
|
|
12386
|
-
const scriptsDir =
|
|
12387
|
-
if (
|
|
12388
|
-
const versions =
|
|
12389
|
-
return
|
|
12573
|
+
const scriptsDir = path13.join(dir, "scripts");
|
|
12574
|
+
if (fs10.existsSync(scriptsDir)) {
|
|
12575
|
+
const versions = fs10.readdirSync(scriptsDir).filter((d) => {
|
|
12576
|
+
return fs10.statSync(path13.join(scriptsDir, d)).isDirectory();
|
|
12390
12577
|
}).sort().reverse();
|
|
12391
12578
|
for (const ver of versions) {
|
|
12392
|
-
const p =
|
|
12393
|
-
if (
|
|
12579
|
+
const p = path13.join(scriptsDir, ver, "scripts.js");
|
|
12580
|
+
if (fs10.existsSync(p)) {
|
|
12394
12581
|
scriptsPath = p;
|
|
12395
12582
|
break;
|
|
12396
12583
|
}
|
|
@@ -12402,7 +12589,7 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
12402
12589
|
return;
|
|
12403
12590
|
}
|
|
12404
12591
|
try {
|
|
12405
|
-
const source =
|
|
12592
|
+
const source = fs10.readFileSync(scriptsPath, "utf-8");
|
|
12406
12593
|
const hints = {};
|
|
12407
12594
|
const funcRegex = /module\.exports\.(\w+)\s*=\s*function\s+\w+\s*\(params\)/g;
|
|
12408
12595
|
let match;
|
|
@@ -13443,9 +13630,9 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
13443
13630
|
}
|
|
13444
13631
|
|
|
13445
13632
|
// src/daemon/dev-auto-implement.ts
|
|
13446
|
-
import * as
|
|
13447
|
-
import * as
|
|
13448
|
-
import * as
|
|
13633
|
+
import * as fs11 from "fs";
|
|
13634
|
+
import * as path14 from "path";
|
|
13635
|
+
import * as os16 from "os";
|
|
13449
13636
|
function getDefaultAutoImplReference(ctx, category, type) {
|
|
13450
13637
|
if (category === "cli") {
|
|
13451
13638
|
return type === "codex-cli" ? "claude-cli" : "codex-cli";
|
|
@@ -13461,45 +13648,45 @@ function resolveAutoImplReference(ctx, category, requestedReference, targetType)
|
|
|
13461
13648
|
return fallback?.type || null;
|
|
13462
13649
|
}
|
|
13463
13650
|
function getLatestScriptVersionDir(scriptsDir) {
|
|
13464
|
-
if (!
|
|
13465
|
-
const versions =
|
|
13651
|
+
if (!fs11.existsSync(scriptsDir)) return null;
|
|
13652
|
+
const versions = fs11.readdirSync(scriptsDir).filter((d) => {
|
|
13466
13653
|
try {
|
|
13467
|
-
return
|
|
13654
|
+
return fs11.statSync(path14.join(scriptsDir, d)).isDirectory();
|
|
13468
13655
|
} catch {
|
|
13469
13656
|
return false;
|
|
13470
13657
|
}
|
|
13471
13658
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
13472
13659
|
if (versions.length === 0) return null;
|
|
13473
|
-
return
|
|
13660
|
+
return path14.join(scriptsDir, versions[0]);
|
|
13474
13661
|
}
|
|
13475
13662
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
13476
|
-
const canonicalUserDir =
|
|
13477
|
-
const desiredDir = requestedDir ?
|
|
13478
|
-
const upstreamRoot =
|
|
13479
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
13663
|
+
const canonicalUserDir = path14.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
13664
|
+
const desiredDir = requestedDir ? path14.resolve(requestedDir) : canonicalUserDir;
|
|
13665
|
+
const upstreamRoot = path14.resolve(ctx.providerLoader.getUpstreamDir());
|
|
13666
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path14.sep}`)) {
|
|
13480
13667
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
13481
13668
|
}
|
|
13482
|
-
if (
|
|
13669
|
+
if (path14.basename(desiredDir) !== type) {
|
|
13483
13670
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
13484
13671
|
}
|
|
13485
13672
|
const sourceDir = ctx.findProviderDir(type);
|
|
13486
13673
|
if (!sourceDir) {
|
|
13487
13674
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
13488
13675
|
}
|
|
13489
|
-
if (!
|
|
13490
|
-
|
|
13491
|
-
|
|
13676
|
+
if (!fs11.existsSync(desiredDir)) {
|
|
13677
|
+
fs11.mkdirSync(path14.dirname(desiredDir), { recursive: true });
|
|
13678
|
+
fs11.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
13492
13679
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
13493
13680
|
}
|
|
13494
|
-
const providerJson =
|
|
13495
|
-
if (!
|
|
13681
|
+
const providerJson = path14.join(desiredDir, "provider.json");
|
|
13682
|
+
if (!fs11.existsSync(providerJson)) {
|
|
13496
13683
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
13497
13684
|
}
|
|
13498
13685
|
try {
|
|
13499
|
-
const providerData = JSON.parse(
|
|
13686
|
+
const providerData = JSON.parse(fs11.readFileSync(providerJson, "utf-8"));
|
|
13500
13687
|
if (providerData.disableUpstream !== true) {
|
|
13501
13688
|
providerData.disableUpstream = true;
|
|
13502
|
-
|
|
13689
|
+
fs11.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
|
|
13503
13690
|
}
|
|
13504
13691
|
} catch (error) {
|
|
13505
13692
|
return {
|
|
@@ -13512,15 +13699,15 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
13512
13699
|
function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
13513
13700
|
if (!referenceType) return {};
|
|
13514
13701
|
const refDir = ctx.findProviderDir(referenceType);
|
|
13515
|
-
if (!refDir || !
|
|
13702
|
+
if (!refDir || !fs11.existsSync(refDir)) return {};
|
|
13516
13703
|
const referenceScripts = {};
|
|
13517
|
-
const scriptsDir =
|
|
13704
|
+
const scriptsDir = path14.join(refDir, "scripts");
|
|
13518
13705
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
13519
13706
|
if (!latestDir) return referenceScripts;
|
|
13520
|
-
for (const file of
|
|
13707
|
+
for (const file of fs11.readdirSync(latestDir)) {
|
|
13521
13708
|
if (!file.endsWith(".js")) continue;
|
|
13522
13709
|
try {
|
|
13523
|
-
referenceScripts[file] =
|
|
13710
|
+
referenceScripts[file] = fs11.readFileSync(path14.join(latestDir, file), "utf-8");
|
|
13524
13711
|
} catch {
|
|
13525
13712
|
}
|
|
13526
13713
|
}
|
|
@@ -13571,16 +13758,16 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
13571
13758
|
});
|
|
13572
13759
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
13573
13760
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference);
|
|
13574
|
-
const tmpDir =
|
|
13575
|
-
if (!
|
|
13576
|
-
const promptFile =
|
|
13577
|
-
|
|
13761
|
+
const tmpDir = path14.join(os16.tmpdir(), "adhdev-autoimpl");
|
|
13762
|
+
if (!fs11.existsSync(tmpDir)) fs11.mkdirSync(tmpDir, { recursive: true });
|
|
13763
|
+
const promptFile = path14.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
13764
|
+
fs11.writeFileSync(promptFile, prompt, "utf-8");
|
|
13578
13765
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
13579
13766
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
13580
|
-
const
|
|
13581
|
-
if (!
|
|
13767
|
+
const spawn4 = agentProvider?.spawn;
|
|
13768
|
+
if (!spawn4?.command) {
|
|
13582
13769
|
try {
|
|
13583
|
-
|
|
13770
|
+
fs11.unlinkSync(promptFile);
|
|
13584
13771
|
} catch {
|
|
13585
13772
|
}
|
|
13586
13773
|
ctx.json(res, 400, { error: `Agent '${agent}' has no spawn config. Select a CLI provider with a spawn configuration.` });
|
|
@@ -13588,21 +13775,21 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
13588
13775
|
}
|
|
13589
13776
|
const agentCategory = agentProvider?.category;
|
|
13590
13777
|
if (agentCategory === "acp") {
|
|
13591
|
-
sendAutoImplSSE(ctx, { event: "progress", data: { function: "_init", status: "spawning", message: `Spawning ACP agent: ${
|
|
13778
|
+
sendAutoImplSSE(ctx, { event: "progress", data: { function: "_init", status: "spawning", message: `Spawning ACP agent: ${spawn4.command} ${(spawn4.args || []).join(" ")}` } });
|
|
13592
13779
|
ctx.autoImplStatus = { running: true, type, progress: [] };
|
|
13593
13780
|
const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await import("@agentclientprotocol/sdk");
|
|
13594
13781
|
const { Readable: Readable2, Writable: Writable2 } = await import("stream");
|
|
13595
13782
|
const { spawn: spawnFn2 } = await import("child_process");
|
|
13596
|
-
const acpArgs = [...
|
|
13783
|
+
const acpArgs = [...spawn4.args || []];
|
|
13597
13784
|
if (model) {
|
|
13598
13785
|
acpArgs.push("--model", model);
|
|
13599
13786
|
ctx.log(`Auto-implement ACP using model: ${model}`);
|
|
13600
13787
|
}
|
|
13601
|
-
const child2 = spawnFn2(
|
|
13788
|
+
const child2 = spawnFn2(spawn4.command, acpArgs, {
|
|
13602
13789
|
cwd: providerDir,
|
|
13603
13790
|
stdio: ["pipe", "pipe", "pipe"],
|
|
13604
|
-
shell:
|
|
13605
|
-
env: { ...process.env, ...
|
|
13791
|
+
shell: spawn4.shell ?? false,
|
|
13792
|
+
env: { ...process.env, ...spawn4.env || {} }
|
|
13606
13793
|
});
|
|
13607
13794
|
ctx.autoImplProcess = child2;
|
|
13608
13795
|
child2.stderr?.on("data", (d) => {
|
|
@@ -13681,7 +13868,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
13681
13868
|
} catch {
|
|
13682
13869
|
}
|
|
13683
13870
|
try {
|
|
13684
|
-
|
|
13871
|
+
fs11.unlinkSync(promptFile);
|
|
13685
13872
|
} catch {
|
|
13686
13873
|
}
|
|
13687
13874
|
ctx.log(`Auto-implement (ACP) ${success ? "completed" : "failed"}: ${type} (exit: ${code})`);
|
|
@@ -13712,7 +13899,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
13712
13899
|
ctx.json(res, 202, {
|
|
13713
13900
|
started: true,
|
|
13714
13901
|
type,
|
|
13715
|
-
agent:
|
|
13902
|
+
agent: spawn4.command,
|
|
13716
13903
|
functions,
|
|
13717
13904
|
providerDir,
|
|
13718
13905
|
message: "ACP Auto-implement started. Connect to SSE for progress.",
|
|
@@ -13720,11 +13907,11 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
13720
13907
|
});
|
|
13721
13908
|
return;
|
|
13722
13909
|
}
|
|
13723
|
-
const command =
|
|
13910
|
+
const command = spawn4.command;
|
|
13724
13911
|
const interactiveFlags = ["--yolo", "--interactive", "-i"];
|
|
13725
|
-
const baseArgs = [...
|
|
13912
|
+
const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
|
|
13726
13913
|
let shellCmd;
|
|
13727
|
-
const isWin =
|
|
13914
|
+
const isWin = os16.platform() === "win32";
|
|
13728
13915
|
const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
|
|
13729
13916
|
if (command === "claude") {
|
|
13730
13917
|
const args = [...baseArgs, "--dangerously-skip-permissions"];
|
|
@@ -13767,13 +13954,13 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
13767
13954
|
try {
|
|
13768
13955
|
const pty3 = __require("node-pty");
|
|
13769
13956
|
ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
|
|
13770
|
-
const isWin2 =
|
|
13957
|
+
const isWin2 = os16.platform() === "win32";
|
|
13771
13958
|
child = pty3.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
|
|
13772
13959
|
name: "xterm-256color",
|
|
13773
13960
|
cols: 120,
|
|
13774
13961
|
rows: 40,
|
|
13775
13962
|
cwd: providerDir,
|
|
13776
|
-
env: { ...process.env, ...
|
|
13963
|
+
env: { ...process.env, ...spawn4.env || {} }
|
|
13777
13964
|
});
|
|
13778
13965
|
isPty = true;
|
|
13779
13966
|
} catch (err) {
|
|
@@ -13785,7 +13972,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
13785
13972
|
stdio: ["pipe", "pipe", "pipe"],
|
|
13786
13973
|
env: {
|
|
13787
13974
|
...process.env,
|
|
13788
|
-
...
|
|
13975
|
+
...spawn4.env || {},
|
|
13789
13976
|
...command === "gemini" ? { SANDBOX: "1", GEMINI_CLI_NO_RELAUNCH: "1" } : {}
|
|
13790
13977
|
}
|
|
13791
13978
|
});
|
|
@@ -13861,7 +14048,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
13861
14048
|
} catch {
|
|
13862
14049
|
}
|
|
13863
14050
|
try {
|
|
13864
|
-
|
|
14051
|
+
fs11.unlinkSync(promptFile);
|
|
13865
14052
|
} catch {
|
|
13866
14053
|
}
|
|
13867
14054
|
});
|
|
@@ -13897,7 +14084,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
13897
14084
|
} catch {
|
|
13898
14085
|
}
|
|
13899
14086
|
try {
|
|
13900
|
-
|
|
14087
|
+
fs11.unlinkSync(promptFile);
|
|
13901
14088
|
} catch {
|
|
13902
14089
|
}
|
|
13903
14090
|
ctx.log(`Auto-implement ${success ? "completed" : "failed"}: ${type} (exit: ${code})`);
|
|
@@ -13944,7 +14131,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
13944
14131
|
setMode: "set_mode.js"
|
|
13945
14132
|
};
|
|
13946
14133
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
13947
|
-
const scriptsDir =
|
|
14134
|
+
const scriptsDir = path14.join(providerDir, "scripts");
|
|
13948
14135
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
13949
14136
|
if (latestScriptsDir) {
|
|
13950
14137
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -13952,10 +14139,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
13952
14139
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
13953
14140
|
lines.push("These are the ONLY files you are allowed to modify. Replace the TODO stubs with working implementations.");
|
|
13954
14141
|
lines.push("");
|
|
13955
|
-
for (const file of
|
|
14142
|
+
for (const file of fs11.readdirSync(latestScriptsDir)) {
|
|
13956
14143
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
13957
14144
|
try {
|
|
13958
|
-
const content =
|
|
14145
|
+
const content = fs11.readFileSync(path14.join(latestScriptsDir, file), "utf-8");
|
|
13959
14146
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
13960
14147
|
lines.push("```javascript");
|
|
13961
14148
|
lines.push(content);
|
|
@@ -13965,14 +14152,14 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
13965
14152
|
}
|
|
13966
14153
|
}
|
|
13967
14154
|
}
|
|
13968
|
-
const refFiles =
|
|
14155
|
+
const refFiles = fs11.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
13969
14156
|
if (refFiles.length > 0) {
|
|
13970
14157
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
13971
14158
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
13972
14159
|
lines.push("");
|
|
13973
14160
|
for (const file of refFiles) {
|
|
13974
14161
|
try {
|
|
13975
|
-
const content =
|
|
14162
|
+
const content = fs11.readFileSync(path14.join(latestScriptsDir, file), "utf-8");
|
|
13976
14163
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
13977
14164
|
lines.push("```javascript");
|
|
13978
14165
|
lines.push(content);
|
|
@@ -14013,11 +14200,11 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
14013
14200
|
lines.push("");
|
|
14014
14201
|
}
|
|
14015
14202
|
}
|
|
14016
|
-
const docsDir =
|
|
14203
|
+
const docsDir = path14.join(providerDir, "../../docs");
|
|
14017
14204
|
const loadGuide = (name) => {
|
|
14018
14205
|
try {
|
|
14019
|
-
const p =
|
|
14020
|
-
if (
|
|
14206
|
+
const p = path14.join(docsDir, name);
|
|
14207
|
+
if (fs11.existsSync(p)) return fs11.readFileSync(p, "utf-8");
|
|
14021
14208
|
} catch {
|
|
14022
14209
|
}
|
|
14023
14210
|
return null;
|
|
@@ -14190,7 +14377,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
14190
14377
|
parseApproval: "parse_approval.js"
|
|
14191
14378
|
};
|
|
14192
14379
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
14193
|
-
const scriptsDir =
|
|
14380
|
+
const scriptsDir = path14.join(providerDir, "scripts");
|
|
14194
14381
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
14195
14382
|
if (latestScriptsDir) {
|
|
14196
14383
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -14198,11 +14385,11 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
14198
14385
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
14199
14386
|
lines.push("These are the ONLY files you are allowed to modify. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
|
|
14200
14387
|
lines.push("");
|
|
14201
|
-
for (const file of
|
|
14388
|
+
for (const file of fs11.readdirSync(latestScriptsDir)) {
|
|
14202
14389
|
if (!file.endsWith(".js")) continue;
|
|
14203
14390
|
if (!targetFileNames.has(file)) continue;
|
|
14204
14391
|
try {
|
|
14205
|
-
const content =
|
|
14392
|
+
const content = fs11.readFileSync(path14.join(latestScriptsDir, file), "utf-8");
|
|
14206
14393
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
14207
14394
|
lines.push("```javascript");
|
|
14208
14395
|
lines.push(content);
|
|
@@ -14211,14 +14398,14 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
14211
14398
|
} catch {
|
|
14212
14399
|
}
|
|
14213
14400
|
}
|
|
14214
|
-
const refFiles =
|
|
14401
|
+
const refFiles = fs11.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
14215
14402
|
if (refFiles.length > 0) {
|
|
14216
14403
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
14217
14404
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
14218
14405
|
lines.push("");
|
|
14219
14406
|
for (const file of refFiles) {
|
|
14220
14407
|
try {
|
|
14221
|
-
const content =
|
|
14408
|
+
const content = fs11.readFileSync(path14.join(latestScriptsDir, file), "utf-8");
|
|
14222
14409
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
14223
14410
|
lines.push("```javascript");
|
|
14224
14411
|
lines.push(content);
|
|
@@ -14251,11 +14438,11 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
14251
14438
|
lines.push("");
|
|
14252
14439
|
}
|
|
14253
14440
|
}
|
|
14254
|
-
const docsDir =
|
|
14441
|
+
const docsDir = path14.join(providerDir, "../../docs");
|
|
14255
14442
|
const loadGuide = (name) => {
|
|
14256
14443
|
try {
|
|
14257
|
-
const p =
|
|
14258
|
-
if (
|
|
14444
|
+
const p = path14.join(docsDir, name);
|
|
14445
|
+
if (fs11.existsSync(p)) return fs11.readFileSync(p, "utf-8");
|
|
14259
14446
|
} catch {
|
|
14260
14447
|
}
|
|
14261
14448
|
return null;
|
|
@@ -14512,8 +14699,8 @@ var DevServer = class _DevServer {
|
|
|
14512
14699
|
}
|
|
14513
14700
|
getEndpointList() {
|
|
14514
14701
|
return this.routes.map((r) => {
|
|
14515
|
-
const
|
|
14516
|
-
return `${r.method.padEnd(5)} ${
|
|
14702
|
+
const path16 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
14703
|
+
return `${r.method.padEnd(5)} ${path16}`;
|
|
14517
14704
|
});
|
|
14518
14705
|
}
|
|
14519
14706
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -14614,16 +14801,16 @@ var DevServer = class _DevServer {
|
|
|
14614
14801
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
14615
14802
|
return;
|
|
14616
14803
|
}
|
|
14617
|
-
const
|
|
14618
|
-
if (!
|
|
14804
|
+
const spawn4 = provider.spawn;
|
|
14805
|
+
if (!spawn4) {
|
|
14619
14806
|
this.json(res, 400, { error: `Provider ${type} has no spawn config` });
|
|
14620
14807
|
return;
|
|
14621
14808
|
}
|
|
14622
14809
|
const { spawn: spawnFn } = await import("child_process");
|
|
14623
14810
|
const start = Date.now();
|
|
14624
14811
|
try {
|
|
14625
|
-
const child = spawnFn(
|
|
14626
|
-
shell:
|
|
14812
|
+
const child = spawnFn(spawn4.command, [...spawn4.args || []], {
|
|
14813
|
+
shell: spawn4.shell ?? false,
|
|
14627
14814
|
timeout: 5e3,
|
|
14628
14815
|
stdio: ["pipe", "pipe", "pipe"]
|
|
14629
14816
|
});
|
|
@@ -14655,7 +14842,7 @@ var DevServer = class _DevServer {
|
|
|
14655
14842
|
const elapsed = Date.now() - start;
|
|
14656
14843
|
this.json(res, 200, {
|
|
14657
14844
|
success: true,
|
|
14658
|
-
command: `${
|
|
14845
|
+
command: `${spawn4.command} ${(spawn4.args || []).join(" ")}`,
|
|
14659
14846
|
elapsed,
|
|
14660
14847
|
stdout: stdout.trim(),
|
|
14661
14848
|
stderr: stderr.trim(),
|
|
@@ -14665,7 +14852,7 @@ var DevServer = class _DevServer {
|
|
|
14665
14852
|
const elapsed = Date.now() - start;
|
|
14666
14853
|
this.json(res, 200, {
|
|
14667
14854
|
success: false,
|
|
14668
|
-
command: `${
|
|
14855
|
+
command: `${spawn4.command} ${(spawn4.args || []).join(" ")}`,
|
|
14669
14856
|
elapsed,
|
|
14670
14857
|
error: e.message
|
|
14671
14858
|
});
|
|
@@ -14795,12 +14982,12 @@ var DevServer = class _DevServer {
|
|
|
14795
14982
|
// ─── DevConsole SPA ───
|
|
14796
14983
|
getConsoleDistDir() {
|
|
14797
14984
|
const candidates = [
|
|
14798
|
-
|
|
14799
|
-
|
|
14800
|
-
|
|
14985
|
+
path15.resolve(__dirname, "../../web-devconsole/dist"),
|
|
14986
|
+
path15.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
14987
|
+
path15.join(process.cwd(), "packages/web-devconsole/dist")
|
|
14801
14988
|
];
|
|
14802
14989
|
for (const dir of candidates) {
|
|
14803
|
-
if (
|
|
14990
|
+
if (fs12.existsSync(path15.join(dir, "index.html"))) return dir;
|
|
14804
14991
|
}
|
|
14805
14992
|
return null;
|
|
14806
14993
|
}
|
|
@@ -14810,9 +14997,9 @@ var DevServer = class _DevServer {
|
|
|
14810
14997
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
14811
14998
|
return;
|
|
14812
14999
|
}
|
|
14813
|
-
const htmlPath =
|
|
15000
|
+
const htmlPath = path15.join(distDir, "index.html");
|
|
14814
15001
|
try {
|
|
14815
|
-
const html =
|
|
15002
|
+
const html = fs12.readFileSync(htmlPath, "utf-8");
|
|
14816
15003
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
14817
15004
|
res.end(html);
|
|
14818
15005
|
} catch (e) {
|
|
@@ -14835,15 +15022,15 @@ var DevServer = class _DevServer {
|
|
|
14835
15022
|
this.json(res, 404, { error: "Not found" });
|
|
14836
15023
|
return;
|
|
14837
15024
|
}
|
|
14838
|
-
const safePath =
|
|
14839
|
-
const filePath =
|
|
15025
|
+
const safePath = path15.normalize(pathname).replace(/^\.\.\//, "");
|
|
15026
|
+
const filePath = path15.join(distDir, safePath);
|
|
14840
15027
|
if (!filePath.startsWith(distDir)) {
|
|
14841
15028
|
this.json(res, 403, { error: "Forbidden" });
|
|
14842
15029
|
return;
|
|
14843
15030
|
}
|
|
14844
15031
|
try {
|
|
14845
|
-
const content =
|
|
14846
|
-
const ext =
|
|
15032
|
+
const content = fs12.readFileSync(filePath);
|
|
15033
|
+
const ext = path15.extname(filePath);
|
|
14847
15034
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
14848
15035
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
14849
15036
|
res.end(content);
|
|
@@ -14951,14 +15138,14 @@ var DevServer = class _DevServer {
|
|
|
14951
15138
|
const files = [];
|
|
14952
15139
|
const scan = (d, prefix) => {
|
|
14953
15140
|
try {
|
|
14954
|
-
for (const entry of
|
|
15141
|
+
for (const entry of fs12.readdirSync(d, { withFileTypes: true })) {
|
|
14955
15142
|
if (entry.name.startsWith(".") || entry.name.endsWith(".bak")) continue;
|
|
14956
15143
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
14957
15144
|
if (entry.isDirectory()) {
|
|
14958
15145
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
14959
|
-
scan(
|
|
15146
|
+
scan(path15.join(d, entry.name), rel);
|
|
14960
15147
|
} else {
|
|
14961
|
-
const stat =
|
|
15148
|
+
const stat = fs12.statSync(path15.join(d, entry.name));
|
|
14962
15149
|
files.push({ path: rel, size: stat.size, type: "file" });
|
|
14963
15150
|
}
|
|
14964
15151
|
}
|
|
@@ -14981,16 +15168,16 @@ var DevServer = class _DevServer {
|
|
|
14981
15168
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
14982
15169
|
return;
|
|
14983
15170
|
}
|
|
14984
|
-
const fullPath =
|
|
15171
|
+
const fullPath = path15.resolve(dir, path15.normalize(filePath));
|
|
14985
15172
|
if (!fullPath.startsWith(dir)) {
|
|
14986
15173
|
this.json(res, 403, { error: "Forbidden" });
|
|
14987
15174
|
return;
|
|
14988
15175
|
}
|
|
14989
|
-
if (!
|
|
15176
|
+
if (!fs12.existsSync(fullPath) || fs12.statSync(fullPath).isDirectory()) {
|
|
14990
15177
|
this.json(res, 404, { error: `File not found: ${filePath}` });
|
|
14991
15178
|
return;
|
|
14992
15179
|
}
|
|
14993
|
-
const content =
|
|
15180
|
+
const content = fs12.readFileSync(fullPath, "utf-8");
|
|
14994
15181
|
this.json(res, 200, { type, path: filePath, content, lines: content.split("\n").length });
|
|
14995
15182
|
}
|
|
14996
15183
|
/** POST /api/providers/:type/file — write a file { path, content } */
|
|
@@ -15006,15 +15193,15 @@ var DevServer = class _DevServer {
|
|
|
15006
15193
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
15007
15194
|
return;
|
|
15008
15195
|
}
|
|
15009
|
-
const fullPath =
|
|
15196
|
+
const fullPath = path15.resolve(dir, path15.normalize(filePath));
|
|
15010
15197
|
if (!fullPath.startsWith(dir)) {
|
|
15011
15198
|
this.json(res, 403, { error: "Forbidden" });
|
|
15012
15199
|
return;
|
|
15013
15200
|
}
|
|
15014
15201
|
try {
|
|
15015
|
-
if (
|
|
15016
|
-
|
|
15017
|
-
|
|
15202
|
+
if (fs12.existsSync(fullPath)) fs12.copyFileSync(fullPath, fullPath + ".bak");
|
|
15203
|
+
fs12.mkdirSync(path15.dirname(fullPath), { recursive: true });
|
|
15204
|
+
fs12.writeFileSync(fullPath, content, "utf-8");
|
|
15018
15205
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
15019
15206
|
this.providerLoader.reload();
|
|
15020
15207
|
this.json(res, 200, { saved: true, path: filePath, chars: content.length });
|
|
@@ -15030,9 +15217,9 @@ var DevServer = class _DevServer {
|
|
|
15030
15217
|
return;
|
|
15031
15218
|
}
|
|
15032
15219
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
15033
|
-
const p =
|
|
15034
|
-
if (
|
|
15035
|
-
const source =
|
|
15220
|
+
const p = path15.join(dir, name);
|
|
15221
|
+
if (fs12.existsSync(p)) {
|
|
15222
|
+
const source = fs12.readFileSync(p, "utf-8");
|
|
15036
15223
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
15037
15224
|
return;
|
|
15038
15225
|
}
|
|
@@ -15051,11 +15238,11 @@ var DevServer = class _DevServer {
|
|
|
15051
15238
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
15052
15239
|
return;
|
|
15053
15240
|
}
|
|
15054
|
-
const target =
|
|
15055
|
-
const targetPath =
|
|
15241
|
+
const target = fs12.existsSync(path15.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
15242
|
+
const targetPath = path15.join(dir, target);
|
|
15056
15243
|
try {
|
|
15057
|
-
if (
|
|
15058
|
-
|
|
15244
|
+
if (fs12.existsSync(targetPath)) fs12.copyFileSync(targetPath, targetPath + ".bak");
|
|
15245
|
+
fs12.writeFileSync(targetPath, source, "utf-8");
|
|
15059
15246
|
this.log(`Saved provider: ${targetPath} (${source.length} chars)`);
|
|
15060
15247
|
this.providerLoader.reload();
|
|
15061
15248
|
this.json(res, 200, { saved: true, path: targetPath, chars: source.length });
|
|
@@ -15134,20 +15321,20 @@ var DevServer = class _DevServer {
|
|
|
15134
15321
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
15135
15322
|
return;
|
|
15136
15323
|
}
|
|
15137
|
-
const
|
|
15138
|
-
if (!
|
|
15324
|
+
const spawn4 = provider.spawn;
|
|
15325
|
+
if (!spawn4) {
|
|
15139
15326
|
this.json(res, 400, { error: `Provider ${type} has no spawn config` });
|
|
15140
15327
|
return;
|
|
15141
15328
|
}
|
|
15142
15329
|
const { spawn: spawnFn } = await import("child_process");
|
|
15143
15330
|
const start = Date.now();
|
|
15144
15331
|
try {
|
|
15145
|
-
const args = [...
|
|
15146
|
-
const child = spawnFn(
|
|
15147
|
-
shell:
|
|
15332
|
+
const args = [...spawn4.args || [], message];
|
|
15333
|
+
const child = spawnFn(spawn4.command, args, {
|
|
15334
|
+
shell: spawn4.shell ?? false,
|
|
15148
15335
|
timeout,
|
|
15149
15336
|
stdio: ["pipe", "pipe", "pipe"],
|
|
15150
|
-
env: { ...process.env, ...
|
|
15337
|
+
env: { ...process.env, ...spawn4.env || {} }
|
|
15151
15338
|
});
|
|
15152
15339
|
let stdout = "";
|
|
15153
15340
|
let stderr = "";
|
|
@@ -15212,21 +15399,21 @@ var DevServer = class _DevServer {
|
|
|
15212
15399
|
}
|
|
15213
15400
|
let targetDir;
|
|
15214
15401
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
15215
|
-
const jsonPath =
|
|
15216
|
-
if (
|
|
15402
|
+
const jsonPath = path15.join(targetDir, "provider.json");
|
|
15403
|
+
if (fs12.existsSync(jsonPath)) {
|
|
15217
15404
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
15218
15405
|
return;
|
|
15219
15406
|
}
|
|
15220
15407
|
try {
|
|
15221
15408
|
const result = generateFiles(type, name, category, { cdpPorts, cli, processName, installPath, binary, extensionId, version, osPaths, processNames });
|
|
15222
|
-
|
|
15223
|
-
|
|
15409
|
+
fs12.mkdirSync(targetDir, { recursive: true });
|
|
15410
|
+
fs12.writeFileSync(jsonPath, result["provider.json"], "utf-8");
|
|
15224
15411
|
const createdFiles = ["provider.json"];
|
|
15225
15412
|
if (result.files) {
|
|
15226
15413
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
15227
|
-
const fullPath =
|
|
15228
|
-
|
|
15229
|
-
|
|
15414
|
+
const fullPath = path15.join(targetDir, relPath);
|
|
15415
|
+
fs12.mkdirSync(path15.dirname(fullPath), { recursive: true });
|
|
15416
|
+
fs12.writeFileSync(fullPath, content, "utf-8");
|
|
15230
15417
|
createdFiles.push(relPath);
|
|
15231
15418
|
}
|
|
15232
15419
|
}
|
|
@@ -15275,45 +15462,45 @@ var DevServer = class _DevServer {
|
|
|
15275
15462
|
}
|
|
15276
15463
|
// ─── Phase 2: Auto-Implement Backend ───
|
|
15277
15464
|
getLatestScriptVersionDir(scriptsDir) {
|
|
15278
|
-
if (!
|
|
15279
|
-
const versions =
|
|
15465
|
+
if (!fs12.existsSync(scriptsDir)) return null;
|
|
15466
|
+
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
15280
15467
|
try {
|
|
15281
|
-
return
|
|
15468
|
+
return fs12.statSync(path15.join(scriptsDir, d)).isDirectory();
|
|
15282
15469
|
} catch {
|
|
15283
15470
|
return false;
|
|
15284
15471
|
}
|
|
15285
15472
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
15286
15473
|
if (versions.length === 0) return null;
|
|
15287
|
-
return
|
|
15474
|
+
return path15.join(scriptsDir, versions[0]);
|
|
15288
15475
|
}
|
|
15289
15476
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
15290
|
-
const canonicalUserDir =
|
|
15291
|
-
const desiredDir = requestedDir ?
|
|
15292
|
-
const upstreamRoot =
|
|
15293
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
15477
|
+
const canonicalUserDir = path15.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
15478
|
+
const desiredDir = requestedDir ? path15.resolve(requestedDir) : canonicalUserDir;
|
|
15479
|
+
const upstreamRoot = path15.resolve(this.providerLoader.getUpstreamDir());
|
|
15480
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path15.sep}`)) {
|
|
15294
15481
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
15295
15482
|
}
|
|
15296
|
-
if (
|
|
15483
|
+
if (path15.basename(desiredDir) !== type) {
|
|
15297
15484
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
15298
15485
|
}
|
|
15299
15486
|
const sourceDir = this.findProviderDir(type);
|
|
15300
15487
|
if (!sourceDir) {
|
|
15301
15488
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
15302
15489
|
}
|
|
15303
|
-
if (!
|
|
15304
|
-
|
|
15305
|
-
|
|
15490
|
+
if (!fs12.existsSync(desiredDir)) {
|
|
15491
|
+
fs12.mkdirSync(path15.dirname(desiredDir), { recursive: true });
|
|
15492
|
+
fs12.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
15306
15493
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
15307
15494
|
}
|
|
15308
|
-
const providerJson =
|
|
15309
|
-
if (!
|
|
15495
|
+
const providerJson = path15.join(desiredDir, "provider.json");
|
|
15496
|
+
if (!fs12.existsSync(providerJson)) {
|
|
15310
15497
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
15311
15498
|
}
|
|
15312
15499
|
try {
|
|
15313
|
-
const providerData = JSON.parse(
|
|
15500
|
+
const providerData = JSON.parse(fs12.readFileSync(providerJson, "utf-8"));
|
|
15314
15501
|
if (providerData.disableUpstream !== true) {
|
|
15315
15502
|
providerData.disableUpstream = true;
|
|
15316
|
-
|
|
15503
|
+
fs12.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
|
|
15317
15504
|
}
|
|
15318
15505
|
} catch (error) {
|
|
15319
15506
|
return {
|
|
@@ -15353,7 +15540,7 @@ var DevServer = class _DevServer {
|
|
|
15353
15540
|
setMode: "set_mode.js"
|
|
15354
15541
|
};
|
|
15355
15542
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
15356
|
-
const scriptsDir =
|
|
15543
|
+
const scriptsDir = path15.join(providerDir, "scripts");
|
|
15357
15544
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
15358
15545
|
if (latestScriptsDir) {
|
|
15359
15546
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -15361,10 +15548,10 @@ var DevServer = class _DevServer {
|
|
|
15361
15548
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
15362
15549
|
lines.push("These are the ONLY files you are allowed to modify. Replace the TODO stubs with working implementations.");
|
|
15363
15550
|
lines.push("");
|
|
15364
|
-
for (const file of
|
|
15551
|
+
for (const file of fs12.readdirSync(latestScriptsDir)) {
|
|
15365
15552
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
15366
15553
|
try {
|
|
15367
|
-
const content =
|
|
15554
|
+
const content = fs12.readFileSync(path15.join(latestScriptsDir, file), "utf-8");
|
|
15368
15555
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
15369
15556
|
lines.push("```javascript");
|
|
15370
15557
|
lines.push(content);
|
|
@@ -15374,14 +15561,14 @@ var DevServer = class _DevServer {
|
|
|
15374
15561
|
}
|
|
15375
15562
|
}
|
|
15376
15563
|
}
|
|
15377
|
-
const refFiles =
|
|
15564
|
+
const refFiles = fs12.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
15378
15565
|
if (refFiles.length > 0) {
|
|
15379
15566
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
15380
15567
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
15381
15568
|
lines.push("");
|
|
15382
15569
|
for (const file of refFiles) {
|
|
15383
15570
|
try {
|
|
15384
|
-
const content =
|
|
15571
|
+
const content = fs12.readFileSync(path15.join(latestScriptsDir, file), "utf-8");
|
|
15385
15572
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
15386
15573
|
lines.push("```javascript");
|
|
15387
15574
|
lines.push(content);
|
|
@@ -15422,11 +15609,11 @@ var DevServer = class _DevServer {
|
|
|
15422
15609
|
lines.push("");
|
|
15423
15610
|
}
|
|
15424
15611
|
}
|
|
15425
|
-
const docsDir =
|
|
15612
|
+
const docsDir = path15.join(providerDir, "../../docs");
|
|
15426
15613
|
const loadGuide = (name) => {
|
|
15427
15614
|
try {
|
|
15428
|
-
const p =
|
|
15429
|
-
if (
|
|
15615
|
+
const p = path15.join(docsDir, name);
|
|
15616
|
+
if (fs12.existsSync(p)) return fs12.readFileSync(p, "utf-8");
|
|
15430
15617
|
} catch {
|
|
15431
15618
|
}
|
|
15432
15619
|
return null;
|
|
@@ -15599,7 +15786,7 @@ var DevServer = class _DevServer {
|
|
|
15599
15786
|
parseApproval: "parse_approval.js"
|
|
15600
15787
|
};
|
|
15601
15788
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
15602
|
-
const scriptsDir =
|
|
15789
|
+
const scriptsDir = path15.join(providerDir, "scripts");
|
|
15603
15790
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
15604
15791
|
if (latestScriptsDir) {
|
|
15605
15792
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -15607,11 +15794,11 @@ var DevServer = class _DevServer {
|
|
|
15607
15794
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
15608
15795
|
lines.push("These are the ONLY files you are allowed to modify. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
|
|
15609
15796
|
lines.push("");
|
|
15610
|
-
for (const file of
|
|
15797
|
+
for (const file of fs12.readdirSync(latestScriptsDir)) {
|
|
15611
15798
|
if (!file.endsWith(".js")) continue;
|
|
15612
15799
|
if (!targetFileNames.has(file)) continue;
|
|
15613
15800
|
try {
|
|
15614
|
-
const content =
|
|
15801
|
+
const content = fs12.readFileSync(path15.join(latestScriptsDir, file), "utf-8");
|
|
15615
15802
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
15616
15803
|
lines.push("```javascript");
|
|
15617
15804
|
lines.push(content);
|
|
@@ -15620,14 +15807,14 @@ var DevServer = class _DevServer {
|
|
|
15620
15807
|
} catch {
|
|
15621
15808
|
}
|
|
15622
15809
|
}
|
|
15623
|
-
const refFiles =
|
|
15810
|
+
const refFiles = fs12.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
15624
15811
|
if (refFiles.length > 0) {
|
|
15625
15812
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
15626
15813
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
15627
15814
|
lines.push("");
|
|
15628
15815
|
for (const file of refFiles) {
|
|
15629
15816
|
try {
|
|
15630
|
-
const content =
|
|
15817
|
+
const content = fs12.readFileSync(path15.join(latestScriptsDir, file), "utf-8");
|
|
15631
15818
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
15632
15819
|
lines.push("```javascript");
|
|
15633
15820
|
lines.push(content);
|
|
@@ -15660,11 +15847,11 @@ var DevServer = class _DevServer {
|
|
|
15660
15847
|
lines.push("");
|
|
15661
15848
|
}
|
|
15662
15849
|
}
|
|
15663
|
-
const docsDir =
|
|
15850
|
+
const docsDir = path15.join(providerDir, "../../docs");
|
|
15664
15851
|
const loadGuide = (name) => {
|
|
15665
15852
|
try {
|
|
15666
|
-
const p =
|
|
15667
|
-
if (
|
|
15853
|
+
const p = path15.join(docsDir, name);
|
|
15854
|
+
if (fs12.existsSync(p)) return fs12.readFileSync(p, "utf-8");
|
|
15668
15855
|
} catch {
|
|
15669
15856
|
}
|
|
15670
15857
|
return null;
|
|
@@ -16403,8 +16590,8 @@ async function installExtension(ide, extension) {
|
|
|
16403
16590
|
const res = await fetch(extension.vsixUrl);
|
|
16404
16591
|
if (res.ok) {
|
|
16405
16592
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
16406
|
-
const
|
|
16407
|
-
|
|
16593
|
+
const fs13 = await import("fs");
|
|
16594
|
+
fs13.writeFileSync(vsixPath, buffer);
|
|
16408
16595
|
return new Promise((resolve9) => {
|
|
16409
16596
|
const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
|
|
16410
16597
|
exec2(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
|
|
@@ -16771,6 +16958,7 @@ export {
|
|
|
16771
16958
|
loadConfig,
|
|
16772
16959
|
logCommand,
|
|
16773
16960
|
markSetupComplete,
|
|
16961
|
+
maybeRunDaemonUpgradeHelperFromEnv,
|
|
16774
16962
|
normalizeActiveChatData,
|
|
16775
16963
|
normalizeManagedStatus,
|
|
16776
16964
|
probeCdpPort,
|