@aiden-ade/sandbox-agent 0.1.48 → 0.1.50
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/index.cjs +1206 -642
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -4810,6 +4810,351 @@ var require_websocket_server = __commonJS({
|
|
|
4810
4810
|
}
|
|
4811
4811
|
});
|
|
4812
4812
|
|
|
4813
|
+
// src/index.ts
|
|
4814
|
+
var import_node_child_process8 = require("child_process");
|
|
4815
|
+
|
|
4816
|
+
// src/cli-executable.ts
|
|
4817
|
+
var import_node_child_process = require("child_process");
|
|
4818
|
+
var import_node_fs = require("fs");
|
|
4819
|
+
var import_node_os = require("os");
|
|
4820
|
+
var import_node_path = require("path");
|
|
4821
|
+
var PROVIDER_CLI_COMMANDS = {
|
|
4822
|
+
claude_cli: { provider: "claude_cli", command: "claude", envVars: ["ALAN_CLAUDE_PATH"] },
|
|
4823
|
+
codex_app_server: {
|
|
4824
|
+
provider: "codex_app_server",
|
|
4825
|
+
command: "codex",
|
|
4826
|
+
envVars: ["ALAN_CODEX_PATH"]
|
|
4827
|
+
},
|
|
4828
|
+
copilot_cli: { provider: "copilot_cli", command: "copilot", envVars: ["ALAN_COPILOT_PATH"] },
|
|
4829
|
+
cursor_agent_cli: {
|
|
4830
|
+
provider: "cursor_agent_cli",
|
|
4831
|
+
command: "cursor-agent",
|
|
4832
|
+
envVars: ["ALAN_CURSOR_AGENT_PATH"]
|
|
4833
|
+
},
|
|
4834
|
+
antigravity_cli: {
|
|
4835
|
+
provider: "antigravity_cli",
|
|
4836
|
+
command: "agy",
|
|
4837
|
+
envVars: ["ALAN_ANTIGRAVITY_PATH"]
|
|
4838
|
+
},
|
|
4839
|
+
kimi_cli: { provider: "kimi_cli", command: "kimi-cli", envVars: ["ALAN_KIMI_PATH"] },
|
|
4840
|
+
grok_cli: { provider: "grok_cli", command: "grok", envVars: ["ALAN_GROK_PATH"] },
|
|
4841
|
+
opencode_cli: { provider: "opencode_cli", command: "opencode", envVars: ["ALAN_OPENCODE_PATH"] },
|
|
4842
|
+
droid_cli: { provider: "droid_cli", command: "droid", envVars: ["ALAN_DROID_PATH"] },
|
|
4843
|
+
supatest_cli: { provider: "supatest_cli", command: "supatest", envVars: ["ALAN_SUPATEST_PATH"] }
|
|
4844
|
+
};
|
|
4845
|
+
var DISCOVERABLE_PROVIDER_KINDS = Object.keys(PROVIDER_CLI_COMMANDS);
|
|
4846
|
+
var PROVIDER_ALIASES = {
|
|
4847
|
+
agy: "antigravity_cli",
|
|
4848
|
+
antigravity: "antigravity_cli",
|
|
4849
|
+
antigravity_cli: "antigravity_cli",
|
|
4850
|
+
codex: "codex_app_server",
|
|
4851
|
+
gemini: "antigravity_cli",
|
|
4852
|
+
gemini_cli: "antigravity_cli"
|
|
4853
|
+
};
|
|
4854
|
+
var BACKEND_CLI_COMMANDS = {
|
|
4855
|
+
claude_cli: "claude",
|
|
4856
|
+
codex: "codex",
|
|
4857
|
+
codex_app_server: "codex",
|
|
4858
|
+
copilot_cli: "copilot",
|
|
4859
|
+
cursor_agent_cli: "cursor-agent",
|
|
4860
|
+
agy: "agy",
|
|
4861
|
+
antigravity: "agy",
|
|
4862
|
+
antigravity_cli: "agy",
|
|
4863
|
+
gemini_cli: "agy",
|
|
4864
|
+
gemini: "agy",
|
|
4865
|
+
kimi_cli: "kimi-cli",
|
|
4866
|
+
grok_cli: "grok",
|
|
4867
|
+
opencode_cli: "opencode",
|
|
4868
|
+
droid_cli: "droid",
|
|
4869
|
+
supatest_cli: "supatest"
|
|
4870
|
+
};
|
|
4871
|
+
var CLI_COMMAND_ALIASES = {
|
|
4872
|
+
"kimi-cli": ["kimi"],
|
|
4873
|
+
grok: ["grok-build"]
|
|
4874
|
+
};
|
|
4875
|
+
var resolvedCliCache = /* @__PURE__ */ new Map();
|
|
4876
|
+
var NEGATIVE_RESOLUTION_TTL_MS = 15e3;
|
|
4877
|
+
var negativeResolutionExpiry = /* @__PURE__ */ new Map();
|
|
4878
|
+
var cachedLoginShellEnv = null;
|
|
4879
|
+
function parseEnvOutput(output) {
|
|
4880
|
+
const loginEnv = {};
|
|
4881
|
+
for (const line of output.split("\n")) {
|
|
4882
|
+
if (!line.trim()) continue;
|
|
4883
|
+
const eqIdx = line.indexOf("=");
|
|
4884
|
+
if (eqIdx <= 0) continue;
|
|
4885
|
+
const key = line.slice(0, eqIdx);
|
|
4886
|
+
if (/\s/.test(key)) continue;
|
|
4887
|
+
loginEnv[key] = line.slice(eqIdx + 1);
|
|
4888
|
+
}
|
|
4889
|
+
if (!loginEnv.HOME) loginEnv.HOME = process.env.HOME ?? (0, import_node_os.homedir)();
|
|
4890
|
+
if (!loginEnv.SHELL) loginEnv.SHELL = process.env.SHELL ?? "/bin/zsh";
|
|
4891
|
+
return loginEnv;
|
|
4892
|
+
}
|
|
4893
|
+
function loadLoginShellEnvironment() {
|
|
4894
|
+
if (cachedLoginShellEnv) return cachedLoginShellEnv;
|
|
4895
|
+
if ((0, import_node_os.platform)() === "win32") {
|
|
4896
|
+
cachedLoginShellEnv = process.env;
|
|
4897
|
+
return cachedLoginShellEnv;
|
|
4898
|
+
}
|
|
4899
|
+
try {
|
|
4900
|
+
const shell = (process.env.SHELL || "/bin/bash").replace(/'/g, "'\\''");
|
|
4901
|
+
const envOutput = (0, import_node_child_process.execSync)(`'${shell}' -ilc 'env'`, {
|
|
4902
|
+
encoding: "utf8",
|
|
4903
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
4904
|
+
timeout: 5e3
|
|
4905
|
+
});
|
|
4906
|
+
cachedLoginShellEnv = parseEnvOutput(envOutput);
|
|
4907
|
+
} catch {
|
|
4908
|
+
cachedLoginShellEnv = process.env;
|
|
4909
|
+
}
|
|
4910
|
+
return cachedLoginShellEnv;
|
|
4911
|
+
}
|
|
4912
|
+
function getDaemonCliEnvironment() {
|
|
4913
|
+
const base = (0, import_node_os.platform)() === "win32" ? process.env : loadLoginShellEnvironment();
|
|
4914
|
+
return augmentCliPath(base);
|
|
4915
|
+
}
|
|
4916
|
+
function cacheResolvedCli(command, resolvedPath) {
|
|
4917
|
+
resolvedCliCache.set(command, resolvedPath);
|
|
4918
|
+
if (resolvedPath === null) {
|
|
4919
|
+
negativeResolutionExpiry.set(command, Date.now() + NEGATIVE_RESOLUTION_TTL_MS);
|
|
4920
|
+
} else {
|
|
4921
|
+
negativeResolutionExpiry.delete(command);
|
|
4922
|
+
}
|
|
4923
|
+
}
|
|
4924
|
+
function getCachedResolvedCli(command) {
|
|
4925
|
+
const cached = resolvedCliCache.get(command);
|
|
4926
|
+
if (cached === null) {
|
|
4927
|
+
const expiresAt = negativeResolutionExpiry.get(command);
|
|
4928
|
+
if (expiresAt === void 0 || Date.now() >= expiresAt) {
|
|
4929
|
+
resolvedCliCache.delete(command);
|
|
4930
|
+
negativeResolutionExpiry.delete(command);
|
|
4931
|
+
return void 0;
|
|
4932
|
+
}
|
|
4933
|
+
}
|
|
4934
|
+
return cached;
|
|
4935
|
+
}
|
|
4936
|
+
function resolveViaWhere(command, env) {
|
|
4937
|
+
if ((0, import_node_os.platform)() !== "win32") return null;
|
|
4938
|
+
const whereExe = (0, import_node_path.join)(
|
|
4939
|
+
env.SystemRoot ?? process.env.SystemRoot ?? "C:\\Windows",
|
|
4940
|
+
"System32",
|
|
4941
|
+
"where.exe"
|
|
4942
|
+
);
|
|
4943
|
+
if (!(0, import_node_fs.existsSync)(whereExe)) return null;
|
|
4944
|
+
const result = (0, import_node_child_process.spawnSync)(whereExe, [command], {
|
|
4945
|
+
encoding: "utf8",
|
|
4946
|
+
env,
|
|
4947
|
+
windowsHide: true,
|
|
4948
|
+
timeout: 3e3
|
|
4949
|
+
});
|
|
4950
|
+
if (result.error || result.status !== 0) return null;
|
|
4951
|
+
for (const line of result.stdout.split(/\r?\n/)) {
|
|
4952
|
+
const trimmed = line.trim();
|
|
4953
|
+
if (!trimmed) continue;
|
|
4954
|
+
if (isRunnableFile(trimmed)) return trimmed;
|
|
4955
|
+
}
|
|
4956
|
+
return null;
|
|
4957
|
+
}
|
|
4958
|
+
function runCliProbeAsync(executable, env, args = ["--version"], timeoutMs = 3e3, spawnOptions) {
|
|
4959
|
+
return new Promise((resolve6) => {
|
|
4960
|
+
const isWin = (0, import_node_os.platform)() === "win32";
|
|
4961
|
+
let command = executable;
|
|
4962
|
+
let commandArgs = args;
|
|
4963
|
+
if (isWin && /\.(cmd|bat)$/i.test(executable)) {
|
|
4964
|
+
command = env.ComSpec ?? process.env.ComSpec ?? "cmd.exe";
|
|
4965
|
+
commandArgs = ["/d", "/s", "/c", executable, ...args];
|
|
4966
|
+
}
|
|
4967
|
+
const useShell = isWin && command === executable && !/[\\/]/.test(executable);
|
|
4968
|
+
const closeStdin = spawnOptions?.closeStdin === true;
|
|
4969
|
+
let child;
|
|
4970
|
+
try {
|
|
4971
|
+
child = (0, import_node_child_process.spawn)(command, commandArgs, {
|
|
4972
|
+
env,
|
|
4973
|
+
shell: useShell,
|
|
4974
|
+
windowsHide: isWin ? true : void 0,
|
|
4975
|
+
timeout: timeoutMs,
|
|
4976
|
+
stdio: closeStdin ? ["pipe", "pipe", "pipe"] : void 0
|
|
4977
|
+
});
|
|
4978
|
+
} catch (error) {
|
|
4979
|
+
resolve6({ status: null, stdout: "", stderr: "", error });
|
|
4980
|
+
return;
|
|
4981
|
+
}
|
|
4982
|
+
if (closeStdin) {
|
|
4983
|
+
child.stdin?.end();
|
|
4984
|
+
}
|
|
4985
|
+
let stdout = "";
|
|
4986
|
+
let stderr = "";
|
|
4987
|
+
child.stdout?.setEncoding("utf8").on("data", (chunk) => {
|
|
4988
|
+
stdout += chunk;
|
|
4989
|
+
});
|
|
4990
|
+
child.stderr?.setEncoding("utf8").on("data", (chunk) => {
|
|
4991
|
+
stderr += chunk;
|
|
4992
|
+
});
|
|
4993
|
+
child.once("error", (error) => resolve6({ status: null, stdout, stderr, error }));
|
|
4994
|
+
child.once(
|
|
4995
|
+
"close",
|
|
4996
|
+
(status, signal) => resolve6({ status, stdout, stderr, signal: signal ?? null })
|
|
4997
|
+
);
|
|
4998
|
+
});
|
|
4999
|
+
}
|
|
5000
|
+
function runCliVersionProbeAsync(executable, env, args = ["--version"], timeoutMs = 3e3) {
|
|
5001
|
+
return runCliProbeAsync(executable, env, args, timeoutMs);
|
|
5002
|
+
}
|
|
5003
|
+
function pathSeparator() {
|
|
5004
|
+
return (0, import_node_os.platform)() === "win32" ? ";" : ":";
|
|
5005
|
+
}
|
|
5006
|
+
function splitPath(pathValue) {
|
|
5007
|
+
if (!pathValue) return [];
|
|
5008
|
+
return pathValue.split(pathSeparator()).filter(Boolean);
|
|
5009
|
+
}
|
|
5010
|
+
function isRunnableFile(path) {
|
|
5011
|
+
if (!(0, import_node_fs.existsSync)(path)) return false;
|
|
5012
|
+
if ((0, import_node_os.platform)() === "win32") return true;
|
|
5013
|
+
try {
|
|
5014
|
+
(0, import_node_fs.accessSync)(path, import_node_fs.constants.X_OK);
|
|
5015
|
+
return true;
|
|
5016
|
+
} catch {
|
|
5017
|
+
return false;
|
|
5018
|
+
}
|
|
5019
|
+
}
|
|
5020
|
+
function windowsCommandCandidates(command, pathExt) {
|
|
5021
|
+
const trimmed = command.trim();
|
|
5022
|
+
if (!trimmed) return [];
|
|
5023
|
+
const hasExtension = /\.[a-z0-9]+$/i.test(trimmed);
|
|
5024
|
+
if (hasExtension) return [trimmed];
|
|
5025
|
+
const extensions = pathExt.split(";").map((ext) => ext.trim()).filter(Boolean);
|
|
5026
|
+
return [trimmed, ...extensions.map((ext) => `${trimmed}${ext}`)];
|
|
5027
|
+
}
|
|
5028
|
+
function augmentCliPath(env) {
|
|
5029
|
+
const home = env.HOME || env.USERPROFILE || (0, import_node_os.homedir)();
|
|
5030
|
+
const isWin = (0, import_node_os.platform)() === "win32";
|
|
5031
|
+
const extraPaths = isWin ? [
|
|
5032
|
+
(0, import_node_path.join)(home, "AppData", "Roaming", "npm"),
|
|
5033
|
+
(0, import_node_path.join)(home, "AppData", "Local", "Programs", "Microsoft", "WindowsApps"),
|
|
5034
|
+
(0, import_node_path.join)(home, ".local", "bin"),
|
|
5035
|
+
"C:\\Program Files\\nodejs",
|
|
5036
|
+
"C:\\Program Files\\Git\\cmd"
|
|
5037
|
+
] : [
|
|
5038
|
+
(0, import_node_path.join)(home, ".local", "bin"),
|
|
5039
|
+
(0, import_node_path.join)(home, ".local", "node", "bin"),
|
|
5040
|
+
(0, import_node_path.join)(home, ".bun", "bin"),
|
|
5041
|
+
(0, import_node_path.join)(home, ".cargo", "bin"),
|
|
5042
|
+
"/opt/homebrew/bin",
|
|
5043
|
+
"/usr/local/bin"
|
|
5044
|
+
];
|
|
5045
|
+
const basePath = env.PATH ?? "";
|
|
5046
|
+
const existing = new Set(splitPath(basePath));
|
|
5047
|
+
const missing = extraPaths.filter((dir) => !existing.has(dir));
|
|
5048
|
+
if (missing.length === 0) return env;
|
|
5049
|
+
return {
|
|
5050
|
+
...env,
|
|
5051
|
+
PATH: missing.length > 0 ? `${missing.join(pathSeparator())}${pathSeparator()}${basePath}` : basePath
|
|
5052
|
+
};
|
|
5053
|
+
}
|
|
5054
|
+
function resolveCliExecutable(command, env = getDaemonCliEnvironment()) {
|
|
5055
|
+
const trimmed = command.trim();
|
|
5056
|
+
if (!trimmed) return null;
|
|
5057
|
+
const cached = getCachedResolvedCli(trimmed);
|
|
5058
|
+
if (cached === null) return null;
|
|
5059
|
+
if (cached && isRunnableFile(cached)) return cached;
|
|
5060
|
+
if ((trimmed.includes("/") || trimmed.includes("\\")) && isRunnableFile(trimmed)) {
|
|
5061
|
+
cacheResolvedCli(trimmed, trimmed);
|
|
5062
|
+
return trimmed;
|
|
5063
|
+
}
|
|
5064
|
+
const enriched = augmentCliPath(env);
|
|
5065
|
+
const home = enriched.HOME || enriched.USERPROFILE || (0, import_node_os.homedir)();
|
|
5066
|
+
const isWin = (0, import_node_os.platform)() === "win32";
|
|
5067
|
+
const pathExt = enriched.PATHEXT ?? (isWin ? ".EXE;.CMD;.BAT;.COM" : "");
|
|
5068
|
+
const commandNames = [trimmed, ...CLI_COMMAND_ALIASES[trimmed] ?? []];
|
|
5069
|
+
const names = commandNames.flatMap(
|
|
5070
|
+
(name) => isWin ? windowsCommandCandidates(name, pathExt) : [name]
|
|
5071
|
+
);
|
|
5072
|
+
const candidates = [];
|
|
5073
|
+
for (const name of names) {
|
|
5074
|
+
if (name.includes("/") || name.includes("\\")) {
|
|
5075
|
+
candidates.push(name);
|
|
5076
|
+
continue;
|
|
5077
|
+
}
|
|
5078
|
+
for (const dir of splitPath(enriched.PATH)) {
|
|
5079
|
+
candidates.push((0, import_node_path.join)(dir, name));
|
|
5080
|
+
}
|
|
5081
|
+
candidates.push((0, import_node_path.join)(home, ".local", "bin", name), (0, import_node_path.join)(home, ".local", "node", "bin", name));
|
|
5082
|
+
if (!isWin) {
|
|
5083
|
+
candidates.push((0, import_node_path.join)("/opt/homebrew/bin", name), (0, import_node_path.join)("/usr/local/bin", name));
|
|
5084
|
+
} else {
|
|
5085
|
+
candidates.push((0, import_node_path.join)(home, "AppData", "Roaming", "npm", name));
|
|
5086
|
+
}
|
|
5087
|
+
}
|
|
5088
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5089
|
+
for (const candidate of candidates) {
|
|
5090
|
+
if (seen.has(candidate)) continue;
|
|
5091
|
+
seen.add(candidate);
|
|
5092
|
+
if (isRunnableFile(candidate)) {
|
|
5093
|
+
cacheResolvedCli(trimmed, candidate);
|
|
5094
|
+
return candidate;
|
|
5095
|
+
}
|
|
5096
|
+
}
|
|
5097
|
+
const viaWhere = resolveViaWhere(trimmed, enriched);
|
|
5098
|
+
if (viaWhere) {
|
|
5099
|
+
cacheResolvedCli(trimmed, viaWhere);
|
|
5100
|
+
return viaWhere;
|
|
5101
|
+
}
|
|
5102
|
+
cacheResolvedCli(trimmed, null);
|
|
5103
|
+
return null;
|
|
5104
|
+
}
|
|
5105
|
+
function normalizeDiscoverableProvider(provider) {
|
|
5106
|
+
const alias = PROVIDER_ALIASES[provider];
|
|
5107
|
+
if (alias) return alias;
|
|
5108
|
+
if (provider in PROVIDER_CLI_COMMANDS) {
|
|
5109
|
+
return provider;
|
|
5110
|
+
}
|
|
5111
|
+
return null;
|
|
5112
|
+
}
|
|
5113
|
+
function resolveProviderCliCommand(provider, env = getDaemonCliEnvironment()) {
|
|
5114
|
+
const normalized = normalizeDiscoverableProvider(provider);
|
|
5115
|
+
if (!normalized) return null;
|
|
5116
|
+
const spec = PROVIDER_CLI_COMMANDS[normalized];
|
|
5117
|
+
const override = spec.envVars.map((name) => process.env[name]?.trim() || env[name]?.trim()).find(Boolean);
|
|
5118
|
+
if (override) {
|
|
5119
|
+
const resolved2 = resolveCliExecutable(override, env) ?? (isRunnableFile(override) ? override : null);
|
|
5120
|
+
if (resolved2) cacheResolvedCli(spec.command, resolved2);
|
|
5121
|
+
return resolved2;
|
|
5122
|
+
}
|
|
5123
|
+
const resolved = resolveCliExecutable(spec.command, env);
|
|
5124
|
+
if (resolved) cacheResolvedCli(spec.command, resolved);
|
|
5125
|
+
return resolved;
|
|
5126
|
+
}
|
|
5127
|
+
function resolveBackendRuntimeCommand(backendKind, env = getDaemonCliEnvironment()) {
|
|
5128
|
+
if (!backendKind) return void 0;
|
|
5129
|
+
const command = BACKEND_CLI_COMMANDS[backendKind];
|
|
5130
|
+
if (!command) return void 0;
|
|
5131
|
+
const cached = getCachedResolvedCli(command);
|
|
5132
|
+
if (cached === null) return void 0;
|
|
5133
|
+
if (cached && isRunnableFile(cached)) return cached;
|
|
5134
|
+
const spec = Object.values(PROVIDER_CLI_COMMANDS).find((entry) => entry.command === command);
|
|
5135
|
+
const envOverride = spec ? spec.envVars.map((name) => env[name]?.trim()).find(Boolean) : void 0;
|
|
5136
|
+
const resolved = resolveCliExecutable(envOverride?.trim() || command, env);
|
|
5137
|
+
cacheResolvedCli(command, resolved);
|
|
5138
|
+
return resolved ?? void 0;
|
|
5139
|
+
}
|
|
5140
|
+
function invalidateResolvedCli(command) {
|
|
5141
|
+
const trimmed = command.trim();
|
|
5142
|
+
if (trimmed) {
|
|
5143
|
+
resolvedCliCache.delete(trimmed);
|
|
5144
|
+
negativeResolutionExpiry.delete(trimmed);
|
|
5145
|
+
}
|
|
5146
|
+
}
|
|
5147
|
+
function revalidateBackendRuntimeCommand(backendKind, env = getDaemonCliEnvironment()) {
|
|
5148
|
+
if (!backendKind) return void 0;
|
|
5149
|
+
const command = BACKEND_CLI_COMMANDS[backendKind];
|
|
5150
|
+
if (!command) return void 0;
|
|
5151
|
+
invalidateResolvedCli(command);
|
|
5152
|
+
const spec = Object.values(PROVIDER_CLI_COMMANDS).find((entry) => entry.command === command);
|
|
5153
|
+
const envOverride = spec ? spec.envVars.map((name) => env[name]?.trim()).find(Boolean) : void 0;
|
|
5154
|
+
if (envOverride) invalidateResolvedCli(envOverride);
|
|
5155
|
+
return resolveBackendRuntimeCommand(backendKind, env);
|
|
5156
|
+
}
|
|
5157
|
+
|
|
4813
5158
|
// src/cli-help.ts
|
|
4814
5159
|
var HELP_TEXT = `Alan agent CLI
|
|
4815
5160
|
|
|
@@ -4859,12 +5204,12 @@ function resolveCommand(args, env) {
|
|
|
4859
5204
|
}
|
|
4860
5205
|
|
|
4861
5206
|
// src/daemon.ts
|
|
4862
|
-
var
|
|
5207
|
+
var import_node_child_process6 = require("child_process");
|
|
4863
5208
|
var import_node_crypto3 = require("crypto");
|
|
4864
|
-
var
|
|
5209
|
+
var import_node_fs13 = require("fs");
|
|
4865
5210
|
var import_node_http = __toESM(require("http"), 1);
|
|
4866
|
-
var
|
|
4867
|
-
var
|
|
5211
|
+
var import_node_os8 = require("os");
|
|
5212
|
+
var import_node_path11 = require("path");
|
|
4868
5213
|
|
|
4869
5214
|
// ../agent-core/dist/index.js
|
|
4870
5215
|
var import_fs = require("fs");
|
|
@@ -5020,69 +5365,67 @@ Every \`start_task_session\` message must include all four of these:
|
|
|
5020
5365
|
var GENERAL_PROMPT = `You are Alan, the General Agent \u2014 a flexible general-purpose agent profile. When identifying yourself, say "I'm Alan, the General Agent."`;
|
|
5021
5366
|
var SETUP_PROMPT = `## You are the Setup Agent
|
|
5022
5367
|
|
|
5023
|
-
You are the **Setup Agent** for this environment. When
|
|
5024
|
-
|
|
5025
|
-
to take
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5368
|
+
You are the **Setup Agent** for this cloud environment. When identifying yourself, say "I'm the Setup Agent (an Alan agent profile) for this environment."
|
|
5369
|
+
|
|
5370
|
+
Your job is to take the repository in this fresh cloud sandbox from an unknown state to a **running, functionally verified, reproducible environment**. You are setting up the project, not building product features. Keep working until the application actually works.
|
|
5371
|
+
|
|
5372
|
+
## Environment model
|
|
5373
|
+
|
|
5374
|
+
- You are inside an ephemeral cloud sandbox. Its filesystem can be captured as a reusable snapshot for future sessions.
|
|
5375
|
+
- Do not assume you are on the user's laptop or that tools outside this sandbox exist.
|
|
5376
|
+
- Install and build inside the workspace. Keep all setup repeatable from a fresh clone.
|
|
5377
|
+
|
|
5378
|
+
### Sandbox privileges
|
|
5029
5379
|
|
|
5030
|
-
|
|
5380
|
+
- You are the non-root user \`alan\`; \`HOME=/home/alan\`, repos in \`/home/alan/workspace\`, which you fully own. Node/pnpm/CLIs are on \`PATH\`, and \`npm install -g\` needs no sudo.
|
|
5381
|
+
- **Installing system packages is allowed**, via sudo scoped to package managers: \`sudo apt-get\`, \`sudo apt\`, \`sudo dpkg\`, \`sudo add-apt-repository\`. Other sudo (\`su\`, \`sh\`, \`systemctl\`) is refused by design.
|
|
5382
|
+
- **Always \`sudo apt-get update\` first.** Package lists ship empty, so installing without it fails with "Unable to locate package" \u2014 which reads as "permission denied" but is not:
|
|
5383
|
+
\`sudo apt-get update && sudo apt-get install -y --no-install-recommends <pkgs>\`
|
|
5384
|
+
- Never hand-compile system packages into \`$HOME\` to route around a permission you already have. Use apt; fall back to a user-local install only if the package truly is not in apt.
|
|
5385
|
+
- No Docker daemon or socket. Ports below 1024 bind fine without elevation.
|
|
5386
|
+
- Read the real error before blaming permissions: \`ELIFECYCLE\` is a generic pnpm epilogue, not a diagnosis. Find the \`ERR_\`/\`gyp ERR!\` line above it. A native build failure means a missing system package, not a missing privilege.
|
|
5387
|
+
- Persist the final ordered commands with \`set_environment_setup_commands\`. Each command is replayed in a fresh shell, so no command may depend on shell state from a previous command.
|
|
5388
|
+
- The snapshot policy is \`block_if_dirty\`: the working tree must be clean before capture.
|
|
5031
5389
|
|
|
5032
|
-
|
|
5033
|
-
a snapshot** and reused to boot future sessions instantly. This means:
|
|
5034
|
-
- Install and build into the workspace \u2014 the snapshot preserves it.
|
|
5035
|
-
- Keep tracked files clean: installs must land in git-ignored paths. Snapshot
|
|
5036
|
-
capture is blocked if the git tree is dirty.
|
|
5037
|
-
- If you must change tracked files (setup scripts, config, docs), commit them on
|
|
5038
|
-
the working branch and open a PR for those changes \u2014 do not leave the tree
|
|
5039
|
-
dirty and do not commit secrets.
|
|
5390
|
+
## Required workflow
|
|
5040
5391
|
|
|
5041
|
-
|
|
5392
|
+
1. **Explore** \u2014 read repository instructions, manifests, lockfiles, example env files, and service configuration. Detect the language, package manager, workspace layout, required services, and expected ports.
|
|
5393
|
+
2. **Set up** \u2014 install dependencies, select compatible runtimes, configure non-secret defaults, and build. Diagnose failures yourself before asking the user.
|
|
5394
|
+
3. **Run and verify** \u2014 start the real app or service. Prove it works using process stability, logs, HTTP probes, and \`agent-browser\` interaction when a UI exists. A process merely starting or dependencies merely installing is not success.
|
|
5395
|
+
4. **Persist** \u2014 call \`set_environment_setup_commands\` with only the ordered commands you actually verified from a fresh-shell model.
|
|
5396
|
+
5. **Prepare capture** \u2014 ensure every repository is clean. Verify that \`git status --porcelain --untracked-files=all\` is empty; generated untracked files count as dirty and must be removed or covered by an appropriate existing ignore rule. If setup requires tracked changes, create a focused branch, commit them, push it, and open a PR with \`github_pr_create\` explaining why the setup change is needed. When this setup session is attached to a task, link that PR with \`github_pr_link_task\`. Never commit secrets.
|
|
5397
|
+
6. **Human gate** \u2014 summarize the evidence and ask the user to approve the snapshot. The chat shows them a **Capture snapshot** button, so invite them to use it rather than dictating an exact phrase to type. Do not call \`capture_environment_snapshot\` before that approval arrives.
|
|
5398
|
+
7. **Capture and re-verify** \u2014 after approval, call \`capture_environment_snapshot\` with \`afterSnapshot: "resume"\`. Poll \`get_cloud_machine\` until the snapshot is ready, then confirm the sandbox remains usable and repeat the key runtime probe before declaring completion.
|
|
5042
5399
|
|
|
5043
|
-
|
|
5044
|
-
2. Setup commands persisted via \`set_environment_setup_commands\` so future
|
|
5045
|
-
sessions reproduce this environment.
|
|
5046
|
-
3. The app is **running** and **verified functional** \u2014 dev server up, reachable
|
|
5047
|
-
on the exposed port (curl), and rendering/working via agent-browser.
|
|
5048
|
-
4. Required environment variables are present (see below).
|
|
5049
|
-
5. After explicit human confirmation, the environment is captured via
|
|
5050
|
-
\`capture_environment_snapshot\`.
|
|
5400
|
+
## Autonomy
|
|
5051
5401
|
|
|
5052
|
-
|
|
5402
|
+
Prefer acting over asking. Read the repo, inspect logs, try the likely command, and recover from ordinary setup failures yourself. Ask only for information that cannot be derived or safely created: a required secret, paid credential, external account choice, or genuine product-intent fork. Ask one specific question at a time and continue independent work while waiting.
|
|
5053
5403
|
|
|
5054
|
-
|
|
5055
|
-
secret value into the chat. When the repo needs env vars/secrets:
|
|
5056
|
-
- Identify exactly which vars are required (from .env.example, config, or boot
|
|
5057
|
-
errors) and tell the user the names and what each is for.
|
|
5058
|
-
- Direct the user to add them in the secure env-vars UI. Adding/editing there is
|
|
5059
|
-
**live-synced into this running sandbox immediately** (no restart needed): the
|
|
5060
|
-
value is injected and the file lands at its configured destinationPath
|
|
5061
|
-
(symlinked from /run/alan/env-files/\u2026).
|
|
5062
|
-
- After the user says they've added a var, **confirm it actually arrived** by
|
|
5063
|
-
reading that destination path (never echo the secret value) and re-running the
|
|
5064
|
-
boot/verification.
|
|
5404
|
+
Do not weaken a required functional check to make it pass. If the real process cannot start, the expected port cannot bind, or a browser-required UI cannot be exercised, diagnose and fix the cause. If the restriction is truly outside the sandbox, report the precise blocker instead of declaring setup complete from a mocked handler or unit-level substitute.
|
|
5065
5405
|
|
|
5066
|
-
##
|
|
5406
|
+
## Environment variables and secrets
|
|
5067
5407
|
|
|
5068
|
-
|
|
5069
|
-
running, and verified, summarize what you did and ask the user to confirm. Only
|
|
5070
|
-
after explicit confirmation call \`capture_environment_snapshot\`. Keep the sandbox
|
|
5071
|
-
alive while you wait.
|
|
5408
|
+
Never ask the user to paste a secret into chat, and never print secret values. When a required secret is missing:
|
|
5072
5409
|
|
|
5073
|
-
|
|
5410
|
+
1. Name the exact variable and explain what it is used for.
|
|
5411
|
+
2. Direct the user to this cloud environment's Environment Variables / env-files UI.
|
|
5412
|
+
3. Explain that saved values sync into the running sandbox automatically with no restart required. Env files land at their configured \`destinationPath\` through \`/run/alan/env-files/\`.
|
|
5413
|
+
4. After the user saves it, verify only that the key arrived at the configured destination or environment\u2014never echo the value\u2014then continue.
|
|
5074
5414
|
|
|
5075
|
-
|
|
5076
|
-
verification. Ask the user only for: secret values (via the secure UI, never in
|
|
5077
|
-
chat) and final snapshot confirmation. If setup fails, prefer fixing it from live
|
|
5078
|
-
evidence (logs, boot errors, curl/agent-browser output) before asking.
|
|
5415
|
+
Derive and configure non-secret values yourself when the repository provides safe defaults.
|
|
5079
5416
|
|
|
5080
|
-
##
|
|
5417
|
+
## Evidence and completion
|
|
5081
5418
|
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5419
|
+
Do not rely on your own claim that setup worked. Before finishing, report:
|
|
5420
|
+
|
|
5421
|
+
- the install/build/run commands that succeeded;
|
|
5422
|
+
- the runtime endpoint and functional checks performed;
|
|
5423
|
+
- whether any user-provided secret was required and whether its presence was verified safely;
|
|
5424
|
+
- the persisted setup commands;
|
|
5425
|
+
- the clean-tree or PR result;
|
|
5426
|
+
- the snapshot ID/state and the post-capture verification result.
|
|
5427
|
+
|
|
5428
|
+
If any required item is missing, you are not done.`;
|
|
5086
5429
|
var REVIEW_PROMPT = `## You are the Review Agent
|
|
5087
5430
|
|
|
5088
5431
|
You are the **Review Agent** (an Alan agent profile) for pull request review sessions. When identifying yourself, say "I'm the Review Agent."
|
|
@@ -9791,8 +10134,152 @@ function createAlanProblem(input) {
|
|
|
9791
10134
|
return alanProblemV1Schema.parse({ ...input, schemaVersion: 1 });
|
|
9792
10135
|
}
|
|
9793
10136
|
|
|
9794
|
-
// ../shared/dist/agent/session-result.js
|
|
9795
|
-
var SESSION_RESUME_FAILED_MESSAGE = "Session resume failed. The previous session may have expired or is no longer available. Please start a new session.";
|
|
10137
|
+
// ../shared/dist/agent/session-result.js
|
|
10138
|
+
var SESSION_RESUME_FAILED_MESSAGE = "Session resume failed. The previous session may have expired or is no longer available. Please start a new session.";
|
|
10139
|
+
|
|
10140
|
+
// ../shared/dist/agent/skill-repo-scope.js
|
|
10141
|
+
var SKILL_ROOT_MARKER_RE = /\/\.(?:claude|agents|codex)\/(?:skills|commands)(?:\/|$)/;
|
|
10142
|
+
function normalizePath(path) {
|
|
10143
|
+
return path.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
10144
|
+
}
|
|
10145
|
+
function deriveSkillRepoRoot(sourcePath) {
|
|
10146
|
+
if (!sourcePath)
|
|
10147
|
+
return void 0;
|
|
10148
|
+
const normalized = normalizePath(sourcePath);
|
|
10149
|
+
const marker = normalized.match(SKILL_ROOT_MARKER_RE);
|
|
10150
|
+
if (!marker || marker.index === void 0)
|
|
10151
|
+
return void 0;
|
|
10152
|
+
const beforeRoot = normalized.slice(0, marker.index).replace(/\/+$/, "");
|
|
10153
|
+
return beforeRoot || void 0;
|
|
10154
|
+
}
|
|
10155
|
+
function deriveSkillRepoLabel(sourcePath) {
|
|
10156
|
+
const repoRoot = deriveSkillRepoRoot(sourcePath);
|
|
10157
|
+
if (!repoRoot)
|
|
10158
|
+
return void 0;
|
|
10159
|
+
const label = repoRoot.split("/").filter(Boolean).pop();
|
|
10160
|
+
if (!label || label === "~")
|
|
10161
|
+
return void 0;
|
|
10162
|
+
return label;
|
|
10163
|
+
}
|
|
10164
|
+
function isTeamSkillSource(source) {
|
|
10165
|
+
return source === "team" || source === "project";
|
|
10166
|
+
}
|
|
10167
|
+
function skillIdentityKey(skill) {
|
|
10168
|
+
const command = skill.command.trim();
|
|
10169
|
+
if (isTeamSkillSource(skill.source)) {
|
|
10170
|
+
const repoRoot = skill.repoRoot && normalizePath(skill.repoRoot) || deriveSkillRepoRoot(skill.sourcePath) || "unknown";
|
|
10171
|
+
return `team:${repoRoot}:${command}`;
|
|
10172
|
+
}
|
|
10173
|
+
return `global:${command}`;
|
|
10174
|
+
}
|
|
10175
|
+
|
|
10176
|
+
// ../shared/dist/agent/skill-discovery.js
|
|
10177
|
+
var SKILL_DIRECTORY_ROOTS = [".claude/skills", ".agents/skills", ".codex/skills"];
|
|
10178
|
+
var SKILL_PATH_RE = /(?:^|[/\\])\.(?:claude|agents|codex)[/\\]+skills[/\\]+([^/\\]+)[/\\]+SKILL\.md$/i;
|
|
10179
|
+
var LEGACY_COMMAND_PATH_RE = /(?:^|[/\\])\.claude[/\\]+commands[/\\]+([^/\\]+)\.md$/i;
|
|
10180
|
+
function normalizeSkillSourcePath(sourcePath) {
|
|
10181
|
+
return sourcePath.replace(/\\/g, "/").replace(/\/{2,}/g, "/");
|
|
10182
|
+
}
|
|
10183
|
+
function unquoteScalar(value2) {
|
|
10184
|
+
const trimmed = value2.trim();
|
|
10185
|
+
if (trimmed.length < 2)
|
|
10186
|
+
return trimmed;
|
|
10187
|
+
const first = trimmed[0];
|
|
10188
|
+
const last = trimmed[trimmed.length - 1];
|
|
10189
|
+
if (first === '"' && last === '"' || first === "'" && last === "'") {
|
|
10190
|
+
return trimmed.slice(1, -1).trim();
|
|
10191
|
+
}
|
|
10192
|
+
return trimmed;
|
|
10193
|
+
}
|
|
10194
|
+
function readScalarField(lines, names) {
|
|
10195
|
+
const nameSet = new Set(names);
|
|
10196
|
+
for (const line of lines) {
|
|
10197
|
+
const colonIdx = line.indexOf(":");
|
|
10198
|
+
if (colonIdx === -1)
|
|
10199
|
+
continue;
|
|
10200
|
+
const key = line.slice(0, colonIdx).trim();
|
|
10201
|
+
if (!nameSet.has(key))
|
|
10202
|
+
continue;
|
|
10203
|
+
const value2 = unquoteScalar(line.slice(colonIdx + 1));
|
|
10204
|
+
if (value2)
|
|
10205
|
+
return value2;
|
|
10206
|
+
}
|
|
10207
|
+
return "";
|
|
10208
|
+
}
|
|
10209
|
+
function parseSkillDescription(markdown) {
|
|
10210
|
+
const normalized = markdown.replace(/\r\n/g, "\n").trim();
|
|
10211
|
+
if (!normalized)
|
|
10212
|
+
return "";
|
|
10213
|
+
const frontmatterMatch = normalized.match(/^---\n([\s\S]*?)\n---(?:\n([\s\S]*))?$/);
|
|
10214
|
+
if (frontmatterMatch) {
|
|
10215
|
+
const description = readScalarField(frontmatterMatch[1].split("\n"), ["description", "desc"]);
|
|
10216
|
+
if (description)
|
|
10217
|
+
return description;
|
|
10218
|
+
const body = frontmatterMatch[2]?.trim() ?? "";
|
|
10219
|
+
const firstBodyLine = body.split("\n").find((line) => line.trim());
|
|
10220
|
+
return firstBodyLine?.trim().slice(0, 200) ?? "";
|
|
10221
|
+
}
|
|
10222
|
+
const firstLine2 = normalized.split("\n").find((line) => line.trim());
|
|
10223
|
+
if (!firstLine2)
|
|
10224
|
+
return "";
|
|
10225
|
+
const inlineDescription = readScalarField([firstLine2], ["description", "desc"]);
|
|
10226
|
+
if (inlineDescription)
|
|
10227
|
+
return inlineDescription;
|
|
10228
|
+
return firstLine2.trim().slice(0, 200);
|
|
10229
|
+
}
|
|
10230
|
+
function extractSkillCommandFromPath(sourcePath) {
|
|
10231
|
+
const normalized = normalizeSkillSourcePath(sourcePath);
|
|
10232
|
+
const skillPathMatch = normalized.match(SKILL_PATH_RE);
|
|
10233
|
+
if (skillPathMatch?.[1])
|
|
10234
|
+
return skillPathMatch[1];
|
|
10235
|
+
const legacyCommandMatch = normalized.match(LEGACY_COMMAND_PATH_RE);
|
|
10236
|
+
if (legacyCommandMatch?.[1])
|
|
10237
|
+
return legacyCommandMatch[1];
|
|
10238
|
+
return null;
|
|
10239
|
+
}
|
|
10240
|
+
function normalizeSkillEntry(entry, defaultSource = "team") {
|
|
10241
|
+
const sourcePath = normalizeSkillSourcePath(entry.sourcePath ?? entry.path ?? "");
|
|
10242
|
+
const command = entry.command ?? entry.cmd ?? extractSkillCommandFromPath(sourcePath);
|
|
10243
|
+
if (!command)
|
|
10244
|
+
return null;
|
|
10245
|
+
const description = entry.description ?? entry.desc ?? parseSkillDescription(entry.content ?? "");
|
|
10246
|
+
const source = entry.source ?? entry.src ?? defaultSource;
|
|
10247
|
+
const repoRoot = entry.repoRoot ?? (isTeamSkillSource(source) ? deriveSkillRepoRoot(sourcePath) : void 0);
|
|
10248
|
+
const repoLabel = entry.repoLabel ?? (isTeamSkillSource(source) ? deriveSkillRepoLabel(sourcePath) : void 0);
|
|
10249
|
+
return {
|
|
10250
|
+
command,
|
|
10251
|
+
description,
|
|
10252
|
+
source,
|
|
10253
|
+
sourcePath,
|
|
10254
|
+
...repoRoot ? { repoRoot } : {},
|
|
10255
|
+
...repoLabel ? { repoLabel } : {}
|
|
10256
|
+
};
|
|
10257
|
+
}
|
|
10258
|
+
function skillPriority(source) {
|
|
10259
|
+
switch (source) {
|
|
10260
|
+
case "team":
|
|
10261
|
+
case "project":
|
|
10262
|
+
return 3;
|
|
10263
|
+
case "global":
|
|
10264
|
+
return 2;
|
|
10265
|
+
case "alan":
|
|
10266
|
+
return 1;
|
|
10267
|
+
}
|
|
10268
|
+
}
|
|
10269
|
+
function dedupeSkillEntries(entries) {
|
|
10270
|
+
const deduped = /* @__PURE__ */ new Map();
|
|
10271
|
+
for (const entry of entries) {
|
|
10272
|
+
const key = skillIdentityKey(entry);
|
|
10273
|
+
const existing = deduped.get(key);
|
|
10274
|
+
if (!existing || skillPriority(entry.source) > skillPriority(existing.source)) {
|
|
10275
|
+
deduped.set(key, entry);
|
|
10276
|
+
}
|
|
10277
|
+
}
|
|
10278
|
+
return Array.from(deduped.values());
|
|
10279
|
+
}
|
|
10280
|
+
function normalizeSkillEntries(entries, defaultSource = "team") {
|
|
10281
|
+
return dedupeSkillEntries(entries.map((entry) => normalizeSkillEntry(entry, defaultSource)).filter((entry) => Boolean(entry)));
|
|
10282
|
+
}
|
|
9796
10283
|
|
|
9797
10284
|
// ../shared/dist/agent/system-prompt.js
|
|
9798
10285
|
var ALAN_IDENTITY_PROMPT = `You are Alan, the software factory agent. Alan ships software end to end \u2014 plan, write, review, test, deploy.
|
|
@@ -10155,13 +10642,78 @@ var GROK_CLI_MODELS = [
|
|
|
10155
10642
|
{ id: "grok-composer-2.5-fast", name: "Composer 2.5 Fast" }
|
|
10156
10643
|
];
|
|
10157
10644
|
var COPILOT_CLI_MODELS = [
|
|
10158
|
-
{ id: "
|
|
10645
|
+
{ id: "auto", name: "Auto" },
|
|
10646
|
+
{
|
|
10647
|
+
id: "gpt-5.6-sol",
|
|
10648
|
+
name: "GPT-5.6 Sol",
|
|
10649
|
+
capabilities: { contextWindows: [], effortLevels: GPT_5_6_ULTRA_EFFORT_LEVELS }
|
|
10650
|
+
},
|
|
10651
|
+
{
|
|
10652
|
+
id: "gpt-5.6-terra",
|
|
10653
|
+
name: "GPT-5.6 Terra",
|
|
10654
|
+
capabilities: { contextWindows: [], effortLevels: GPT_5_6_ULTRA_EFFORT_LEVELS }
|
|
10655
|
+
},
|
|
10656
|
+
{
|
|
10657
|
+
id: "gpt-5.6-luna",
|
|
10658
|
+
name: "GPT-5.6 Luna",
|
|
10659
|
+
capabilities: { contextWindows: [], effortLevels: GPT_5_6_EFFORT_LEVELS }
|
|
10660
|
+
},
|
|
10661
|
+
{
|
|
10662
|
+
id: "gpt-5.5",
|
|
10663
|
+
name: "GPT-5.5",
|
|
10664
|
+
capabilities: { contextWindows: [], effortLevels: GPT_5_5_EFFORT_LEVELS }
|
|
10665
|
+
},
|
|
10666
|
+
{
|
|
10667
|
+
id: "gpt-5.4",
|
|
10668
|
+
name: "GPT-5.4",
|
|
10669
|
+
capabilities: { contextWindows: [], effortLevels: GPT_5_4_EFFORT_LEVELS }
|
|
10670
|
+
},
|
|
10671
|
+
{
|
|
10672
|
+
id: "gpt-5.3-codex",
|
|
10673
|
+
name: "GPT-5.3 Codex",
|
|
10674
|
+
capabilities: { contextWindows: [], effortLevels: CODEX_5X_EFFORT_LEVELS }
|
|
10675
|
+
},
|
|
10676
|
+
{
|
|
10677
|
+
id: "gpt-5.4-mini",
|
|
10678
|
+
name: "GPT-5.4 Mini",
|
|
10679
|
+
capabilities: { contextWindows: [], effortLevels: GPT_5_4_EFFORT_LEVELS }
|
|
10680
|
+
},
|
|
10681
|
+
{ id: "gpt-5-mini", name: "GPT-5 Mini" },
|
|
10682
|
+
{
|
|
10683
|
+
id: "claude-sonnet-5",
|
|
10684
|
+
name: "Claude Sonnet 5",
|
|
10685
|
+
capabilities: { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_EFFORT_LEVELS }
|
|
10686
|
+
},
|
|
10159
10687
|
{ id: "claude-sonnet-4.6", name: "Claude Sonnet 4.6" },
|
|
10160
|
-
{ id: "claude-
|
|
10161
|
-
{
|
|
10162
|
-
|
|
10163
|
-
|
|
10164
|
-
|
|
10688
|
+
{ id: "claude-sonnet-4.5", name: "Claude Sonnet 4.5" },
|
|
10689
|
+
{
|
|
10690
|
+
id: "claude-haiku-4.5",
|
|
10691
|
+
name: "Claude Haiku 4.5",
|
|
10692
|
+
capabilities: { contextWindows: ["200k"], effortLevels: [] }
|
|
10693
|
+
},
|
|
10694
|
+
{
|
|
10695
|
+
id: "claude-fable-5",
|
|
10696
|
+
name: "Claude Fable 5",
|
|
10697
|
+
capabilities: { contextWindows: ["1m"], effortLevels: CLAUDE_EFFORT_LEVELS }
|
|
10698
|
+
},
|
|
10699
|
+
{
|
|
10700
|
+
id: "claude-opus-5",
|
|
10701
|
+
name: "Claude Opus 5",
|
|
10702
|
+
capabilities: { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_EFFORT_LEVELS }
|
|
10703
|
+
},
|
|
10704
|
+
{
|
|
10705
|
+
id: "claude-opus-4.8",
|
|
10706
|
+
name: "Claude Opus 4.8",
|
|
10707
|
+
capabilities: { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_EFFORT_LEVELS }
|
|
10708
|
+
},
|
|
10709
|
+
{ id: "claude-opus-4.8-fast", name: "Claude Opus 4.8 Fast" },
|
|
10710
|
+
{ id: "claude-opus-4.7", name: "Claude Opus 4.7" },
|
|
10711
|
+
{ id: "claude-opus-4.6", name: "Claude Opus 4.6" },
|
|
10712
|
+
{ id: "claude-opus-4.5", name: "Claude Opus 4.5" },
|
|
10713
|
+
{ id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro Preview" },
|
|
10714
|
+
{ id: "gemini-3.6-flash", name: "Gemini 3.6 Flash" },
|
|
10715
|
+
{ id: "gemini-3.5-flash", name: "Gemini 3.5 Flash" },
|
|
10716
|
+
{ id: "kimi-k2.7-code", name: "Kimi K2.7 Code" }
|
|
10165
10717
|
];
|
|
10166
10718
|
var OPENCODE_PAID_MODEL = {
|
|
10167
10719
|
billing: "paid",
|
|
@@ -10826,7 +11378,7 @@ var EPIC_STATUS_OPTIONS = [
|
|
|
10826
11378
|
value: "canceled",
|
|
10827
11379
|
label: "Canceled",
|
|
10828
11380
|
color: CATEGORICAL_COLORS.slateClosed,
|
|
10829
|
-
group: "
|
|
11381
|
+
group: "closed"
|
|
10830
11382
|
}
|
|
10831
11383
|
];
|
|
10832
11384
|
var DEFAULT_EPIC_STATUSES = EPIC_STATUS_OPTIONS.map((o) => ({
|
|
@@ -11580,7 +12132,12 @@ function normalizeCodexCliErrorMessage(message) {
|
|
|
11580
12132
|
if (lower.includes("reconnecting") && lower.includes("request timed out")) {
|
|
11581
12133
|
return "Codex connection to OpenAI timed out while waiting for the turn to continue. Retry the message; if it repeats, check network/API latency or reduce slow MCP/tool calls in the turn.";
|
|
11582
12134
|
}
|
|
11583
|
-
if (lower.includes("access token could not be refreshed") || lower.includes("refresh_token_invalidated") || lower.includes("refresh token has been invalidated")
|
|
12135
|
+
if (lower.includes("access token could not be refreshed") || lower.includes("refresh_token_invalidated") || lower.includes("refresh token has been invalidated") || // OpenAI's ChatGPT backend rejects a stale bearer with this pair on both the
|
|
12136
|
+
// HTTP and WSS paths, e.g. "Reconnecting... 2/5 (unexpected status 401
|
|
12137
|
+
// Unauthorized: Provided authentication token is expired. ... auth error
|
|
12138
|
+
// code: token_expired)". Left unmapped these render as a raw retry banner
|
|
12139
|
+
// with a generic "check your API key" hint and no recovery path.
|
|
12140
|
+
lower.includes("token_expired") || lower.includes("provided authentication token is expired")) {
|
|
11584
12141
|
return "Codex CLI connection expired. Re-authenticate the Codex CLI on this computer (run `codex login`) or reconnect it in Cloud settings, then retry.";
|
|
11585
12142
|
}
|
|
11586
12143
|
return message;
|
|
@@ -11817,12 +12374,29 @@ function formatCliSpawnError(command, error) {
|
|
|
11817
12374
|
`CLI command not found: ${command}. Install it or configure this provider with the full executable path.`
|
|
11818
12375
|
);
|
|
11819
12376
|
}
|
|
12377
|
+
if (error.code === "ETXTBSY") {
|
|
12378
|
+
return new Error(
|
|
12379
|
+
`CLI "${command}" is still being written by an installer (ETXTBSY) and did not become runnable in time. Retry in a moment.`
|
|
12380
|
+
);
|
|
12381
|
+
}
|
|
11820
12382
|
return error;
|
|
11821
12383
|
}
|
|
11822
|
-
|
|
12384
|
+
var SPAWN_RETRY_DELAYS_BY_CODE = {
|
|
12385
|
+
ETXTBSY: [250, 750, 1500, 3e3, 5e3],
|
|
12386
|
+
ENOENT: [250, 750]
|
|
12387
|
+
};
|
|
12388
|
+
var delay = (ms) => new Promise((resolve22) => setTimeout(resolve22, ms));
|
|
12389
|
+
var SPAWN_OUTCOME_TIMEOUT_MS = 2e3;
|
|
12390
|
+
function waitForSpawnOutcome(child, timeoutMs = SPAWN_OUTCOME_TIMEOUT_MS) {
|
|
11823
12391
|
return new Promise((resolve22) => {
|
|
11824
|
-
|
|
11825
|
-
|
|
12392
|
+
const timer = setTimeout(() => resolve22(null), timeoutMs);
|
|
12393
|
+
timer.unref?.();
|
|
12394
|
+
const settle = (value2) => {
|
|
12395
|
+
clearTimeout(timer);
|
|
12396
|
+
resolve22(value2);
|
|
12397
|
+
};
|
|
12398
|
+
child.once("spawn", () => settle(null));
|
|
12399
|
+
child.once("error", (error) => settle(error));
|
|
11826
12400
|
});
|
|
11827
12401
|
}
|
|
11828
12402
|
function createGenericCliBackend(options) {
|
|
@@ -11840,28 +12414,35 @@ function createGenericCliBackend(options) {
|
|
|
11840
12414
|
const args = options.buildArgs?.(context, prompt) ?? options.args.map((arg) => arg === "{{prompt}}" ? prompt : arg);
|
|
11841
12415
|
let command = options.command;
|
|
11842
12416
|
let child = spawnCli(command, args, context);
|
|
11843
|
-
if (context.revalidateCommand) {
|
|
11844
|
-
const spawnError = await waitForSpawnOutcome(child);
|
|
11845
|
-
if (spawnError) {
|
|
11846
|
-
const fresh = spawnError.code === "ENOENT" ? context.revalidateCommand()?.trim() || null : null;
|
|
11847
|
-
if (fresh && fresh !== command) {
|
|
11848
|
-
console.warn(
|
|
11849
|
-
`[${options.kind}] Spawn failed ENOENT for "${command}" \u2014 re-resolved to "${fresh}", retrying once`
|
|
11850
|
-
);
|
|
11851
|
-
command = fresh;
|
|
11852
|
-
child = spawnCli(command, args, context);
|
|
11853
|
-
} else {
|
|
11854
|
-
throw formatCliSpawnError(command, spawnError);
|
|
11855
|
-
}
|
|
11856
|
-
}
|
|
11857
|
-
}
|
|
11858
12417
|
state.process = child;
|
|
11859
12418
|
state.lastRawOutputAtMs = Date.now();
|
|
11860
|
-
context.onProcessSpawned?.(child);
|
|
11861
12419
|
context.registerLivenessProbe?.(() => ({
|
|
11862
12420
|
providerAlive: child.exitCode === null,
|
|
11863
12421
|
lastRawOutputAgoMs: typeof state.lastRawOutputAtMs === "number" ? Date.now() - state.lastRawOutputAtMs : null
|
|
11864
12422
|
}));
|
|
12423
|
+
for (let attempt = 0; ; attempt++) {
|
|
12424
|
+
if (child.pid !== void 0) break;
|
|
12425
|
+
const spawnError = await waitForSpawnOutcome(child);
|
|
12426
|
+
if (!spawnError) break;
|
|
12427
|
+
const delays = SPAWN_RETRY_DELAYS_BY_CODE[spawnError.code ?? ""] ?? [];
|
|
12428
|
+
if (attempt >= delays.length) {
|
|
12429
|
+
throw formatCliSpawnError(command, spawnError);
|
|
12430
|
+
}
|
|
12431
|
+
const waitMs = delays[attempt];
|
|
12432
|
+
console.warn(
|
|
12433
|
+
`[${options.kind}] Spawn of "${command}" failed ${spawnError.code} \u2014 a CLI installer is likely mid-flight; retrying in ${waitMs}ms (attempt ${attempt + 1}/${delays.length})`
|
|
12434
|
+
);
|
|
12435
|
+
await delay(waitMs);
|
|
12436
|
+
const fresh = context.revalidateCommand?.()?.trim() || null;
|
|
12437
|
+
if (fresh && fresh !== command) {
|
|
12438
|
+
console.warn(`[${options.kind}] Re-resolved "${command}" to "${fresh}"`);
|
|
12439
|
+
command = fresh;
|
|
12440
|
+
}
|
|
12441
|
+
child = spawnCli(command, args, context);
|
|
12442
|
+
}
|
|
12443
|
+
state.process = child;
|
|
12444
|
+
state.lastRawOutputAtMs = Date.now();
|
|
12445
|
+
context.onProcessSpawned?.(child);
|
|
11865
12446
|
const safeArgs = args.map(
|
|
11866
12447
|
(a, i) => i > 0 && args[i - 1] === "--system-prompt" ? `"<system-prompt ${a.length} chars>"` : a
|
|
11867
12448
|
);
|
|
@@ -12705,7 +13286,11 @@ function buildAntigravityCliArgs(context, prompt, defaultArgs = [], capabilities
|
|
|
12705
13286
|
const args = [];
|
|
12706
13287
|
const selectedModel = context.config.selectedModel?.trim();
|
|
12707
13288
|
const resumeId = context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim();
|
|
12708
|
-
if (selectedModel)
|
|
13289
|
+
if (selectedModel) {
|
|
13290
|
+
args.push("--model", selectedModel);
|
|
13291
|
+
const effort = context.config.selectedEffortLevel?.trim().toLowerCase();
|
|
13292
|
+
if (effort && isEffortLevel(effort)) args.push("--effort", effort);
|
|
13293
|
+
}
|
|
12709
13294
|
if (resumeId) args.push("--conversation", resumeId);
|
|
12710
13295
|
if (!shouldUseReadOnlyRuntimePermissions(context.config)) {
|
|
12711
13296
|
args.push("--dangerously-skip-permissions");
|
|
@@ -12716,6 +13301,14 @@ function buildAntigravityCliArgs(context, prompt, defaultArgs = [], capabilities
|
|
|
12716
13301
|
args.push("--print-timeout", "10m");
|
|
12717
13302
|
return [...args, ...defaultArgs, "-p", prompt];
|
|
12718
13303
|
}
|
|
13304
|
+
function buildAntigravityAugmentedPrompt(context, images) {
|
|
13305
|
+
const isResume = Boolean(
|
|
13306
|
+
context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim()
|
|
13307
|
+
);
|
|
13308
|
+
const base = buildResumeAwarePrompt(context.config, context.promptText, { isResume });
|
|
13309
|
+
const prompt = context.config.mode === "plan" ? buildPlanModePrefix(base) : base;
|
|
13310
|
+
return appendImagePathReferences(prompt, images);
|
|
13311
|
+
}
|
|
12719
13312
|
function createAntigravityCliBackend(command = "agy", defaultArgs = []) {
|
|
12720
13313
|
return {
|
|
12721
13314
|
kind: "antigravity_cli",
|
|
@@ -12737,7 +13330,7 @@ function createAntigravityCliBackend(command = "agy", defaultArgs = []) {
|
|
|
12737
13330
|
command,
|
|
12738
13331
|
args: [],
|
|
12739
13332
|
buildArgs: (ctx, prompt) => buildAntigravityCliArgs(ctx, prompt, defaultArgs, capabilities),
|
|
12740
|
-
augmentPrompt: (ctx) =>
|
|
13333
|
+
augmentPrompt: (ctx) => buildAntigravityAugmentedPrompt(ctx, imageFiles),
|
|
12741
13334
|
parseStructuredLine: parseAntigravityLine
|
|
12742
13335
|
}).run(context);
|
|
12743
13336
|
} finally {
|
|
@@ -14904,6 +15497,41 @@ var parseCopilotStructuredLine = createStructuredLineParser(
|
|
|
14904
15497
|
"copilot_cli",
|
|
14905
15498
|
handleCopilotStructuredEvent
|
|
14906
15499
|
);
|
|
15500
|
+
function buildCopilotCliArgs(context, prompt, defaultArgs = []) {
|
|
15501
|
+
const args = [
|
|
15502
|
+
"--autopilot",
|
|
15503
|
+
"--yolo",
|
|
15504
|
+
"--max-autopilot-continues",
|
|
15505
|
+
"20",
|
|
15506
|
+
"-s",
|
|
15507
|
+
"--stream",
|
|
15508
|
+
"on",
|
|
15509
|
+
"--output-format",
|
|
15510
|
+
"json",
|
|
15511
|
+
// Without this flag, real captured sessions on this machine show every
|
|
15512
|
+
// assistant.message carrying only an opaque, non-decodable `reasoningOpaque`
|
|
15513
|
+
// blob — never `reasoningText` — so parsers/copilot.ts's onThinking() never
|
|
15514
|
+
// fires and the thinking stream never reaches the UI. `--enable-reasoning-summaries`
|
|
15515
|
+
// is documented in `copilot --help` as exactly this: "Request reasoning
|
|
15516
|
+
// summaries for OpenAI models." Always on — it's additive (models/providers
|
|
15517
|
+
// that don't support summaries are unaffected) and this is the "start in
|
|
15518
|
+
// thinking mode by default" behavior other providers already give equivalent
|
|
15519
|
+
// visibility into.
|
|
15520
|
+
"--enable-reasoning-summaries"
|
|
15521
|
+
];
|
|
15522
|
+
if (shouldUseReadOnlyRuntimePermissions(context.config)) {
|
|
15523
|
+
args.push("--deny-tool", "write");
|
|
15524
|
+
}
|
|
15525
|
+
if (context.config.selectedModel?.trim()) {
|
|
15526
|
+
args.push("--model", context.config.selectedModel.trim());
|
|
15527
|
+
}
|
|
15528
|
+
const effort = context.config.selectedEffortLevel?.trim().toLowerCase();
|
|
15529
|
+
if (effort && isEffortLevel(effort)) {
|
|
15530
|
+
args.push("--effort", effort);
|
|
15531
|
+
}
|
|
15532
|
+
args.push("-p", prompt);
|
|
15533
|
+
return [...args, ...defaultArgs];
|
|
15534
|
+
}
|
|
14907
15535
|
function createCopilotCliBackend(command = "copilot", defaultArgs = []) {
|
|
14908
15536
|
return {
|
|
14909
15537
|
kind: "copilot_cli",
|
|
@@ -14919,25 +15547,7 @@ function createCopilotCliBackend(command = "copilot", defaultArgs = []) {
|
|
|
14919
15547
|
supportTier: "structured",
|
|
14920
15548
|
command,
|
|
14921
15549
|
args: [],
|
|
14922
|
-
buildArgs: (ctx, prompt) =>
|
|
14923
|
-
const args = [
|
|
14924
|
-
"--autopilot",
|
|
14925
|
-
"--yolo",
|
|
14926
|
-
"--max-autopilot-continues",
|
|
14927
|
-
"20",
|
|
14928
|
-
"-s",
|
|
14929
|
-
"--stream",
|
|
14930
|
-
"on",
|
|
14931
|
-
"--output-format",
|
|
14932
|
-
"json",
|
|
14933
|
-
"-p",
|
|
14934
|
-
prompt
|
|
14935
|
-
];
|
|
14936
|
-
if (ctx.config.selectedModel?.trim()) {
|
|
14937
|
-
args.push("--model", ctx.config.selectedModel.trim());
|
|
14938
|
-
}
|
|
14939
|
-
return [...args, ...defaultArgs];
|
|
14940
|
-
},
|
|
15550
|
+
buildArgs: (ctx, prompt) => buildCopilotCliArgs(ctx, prompt, defaultArgs),
|
|
14941
15551
|
augmentPrompt: (ctx) => buildPromptWithImagePathReferences(ctx, imageFiles),
|
|
14942
15552
|
parseStructuredLine: parseCopilotStructuredLine,
|
|
14943
15553
|
// Local background Agent/detached work uses the shared result gate; keep
|
|
@@ -18194,7 +18804,7 @@ function extractPathCandidates(content, options, extensionsPattern = "png|jpe?g|
|
|
|
18194
18804
|
...options.pathHints ?? []
|
|
18195
18805
|
];
|
|
18196
18806
|
}
|
|
18197
|
-
function
|
|
18807
|
+
function normalizePath2(candidate, cwd) {
|
|
18198
18808
|
let path = candidate.trim().replace(/^file:\/\//, "");
|
|
18199
18809
|
try {
|
|
18200
18810
|
path = decodeURI(path);
|
|
@@ -18217,7 +18827,7 @@ function extractBrowserMediaPathHints(content, cwd, toolName, options = {}, kind
|
|
|
18217
18827
|
return extractPathCandidatesFromValues(
|
|
18218
18828
|
collectContentStrings(content, options.toolInput),
|
|
18219
18829
|
extensionsPattern
|
|
18220
|
-
).map((candidate) =>
|
|
18830
|
+
).map((candidate) => normalizePath2(candidate, effectiveCwd)).filter((path) => Boolean(path));
|
|
18221
18831
|
}
|
|
18222
18832
|
function readImageDimensions2(buffer, mimeType) {
|
|
18223
18833
|
if (mimeType === "image/png" && buffer.length >= 24 && buffer.toString("ascii", 1, 4) === "PNG") {
|
|
@@ -18250,7 +18860,7 @@ function extractGeneratedImagesFromToolResult(toolId, content, cwd, toolName, op
|
|
|
18250
18860
|
const seen = /* @__PURE__ */ new Set();
|
|
18251
18861
|
const effectiveCwd = resolveToolCwd(cwd, options.toolInput);
|
|
18252
18862
|
for (const candidate of extractPathCandidates(content, options)) {
|
|
18253
|
-
const path =
|
|
18863
|
+
const path = normalizePath2(candidate, effectiveCwd);
|
|
18254
18864
|
if (!path || seen.has(path) || !(0, import_fs9.existsSync)(path)) continue;
|
|
18255
18865
|
seen.add(path);
|
|
18256
18866
|
const ext = (0, import_path9.extname)(path).toLowerCase();
|
|
@@ -18289,7 +18899,7 @@ function extractSessionMediaFromToolResult(toolId, content, cwd, toolName, optio
|
|
|
18289
18899
|
const maxBytes = kind === "video" ? MAX_SESSION_VIDEO_BYTES : MAX_GENERATED_IMAGE_BYTES;
|
|
18290
18900
|
const mimeByExt = kind === "video" ? VIDEO_MIME_BY_EXT : IMAGE_MIME_BY_EXT;
|
|
18291
18901
|
for (const candidate of extractPathCandidates(content, options, extensionsPattern)) {
|
|
18292
|
-
const path =
|
|
18902
|
+
const path = normalizePath2(candidate, effectiveCwd);
|
|
18293
18903
|
if (!path || seen.has(path) || !(0, import_fs9.existsSync)(path)) continue;
|
|
18294
18904
|
seen.add(path);
|
|
18295
18905
|
const ext = (0, import_path9.extname)(path).toLowerCase();
|
|
@@ -18399,18 +19009,18 @@ ${output.stderr}`;
|
|
|
18399
19009
|
}
|
|
18400
19010
|
|
|
18401
19011
|
// ../shared/dist/node/local-workspace.js
|
|
18402
|
-
var import_node_fs = require("fs");
|
|
18403
|
-
var import_node_os = require("os");
|
|
18404
|
-
var import_node_path = require("path");
|
|
18405
|
-
function resolveAlanDefaultWorkspacePath(homeDirectory = (0, import_node_os.homedir)()) {
|
|
18406
|
-
return (0, import_node_path.join)(homeDirectory, ".alan", "workspace");
|
|
18407
|
-
}
|
|
18408
|
-
|
|
18409
|
-
// ../shared/dist/node/provider-limits.js
|
|
18410
|
-
var import_node_child_process = require("child_process");
|
|
18411
19012
|
var import_node_fs2 = require("fs");
|
|
18412
19013
|
var import_node_os2 = require("os");
|
|
18413
19014
|
var import_node_path2 = require("path");
|
|
19015
|
+
function resolveAlanDefaultWorkspacePath(homeDirectory = (0, import_node_os2.homedir)()) {
|
|
19016
|
+
return (0, import_node_path2.join)(homeDirectory, ".alan", "workspace");
|
|
19017
|
+
}
|
|
19018
|
+
|
|
19019
|
+
// ../shared/dist/node/provider-limits.js
|
|
19020
|
+
var import_node_child_process2 = require("child_process");
|
|
19021
|
+
var import_node_fs3 = require("fs");
|
|
19022
|
+
var import_node_os3 = require("os");
|
|
19023
|
+
var import_node_path3 = require("path");
|
|
18414
19024
|
var CACHE_TTL_MS = 6e4;
|
|
18415
19025
|
var cachedLimits = null;
|
|
18416
19026
|
function numericValue(value2) {
|
|
@@ -18421,42 +19031,42 @@ function numericValue(value2) {
|
|
|
18421
19031
|
}
|
|
18422
19032
|
return null;
|
|
18423
19033
|
}
|
|
18424
|
-
function
|
|
18425
|
-
return (value2 ?? "").split(
|
|
19034
|
+
function splitPath2(value2) {
|
|
19035
|
+
return (value2 ?? "").split(import_node_path3.delimiter).filter(Boolean);
|
|
18426
19036
|
}
|
|
18427
19037
|
function isExecutableFile(path) {
|
|
18428
19038
|
try {
|
|
18429
|
-
(0,
|
|
19039
|
+
(0, import_node_fs3.accessSync)(path, import_node_fs3.constants.X_OK);
|
|
18430
19040
|
return true;
|
|
18431
19041
|
} catch {
|
|
18432
19042
|
return false;
|
|
18433
19043
|
}
|
|
18434
19044
|
}
|
|
18435
|
-
function
|
|
18436
|
-
const home = env.HOME || (0,
|
|
19045
|
+
function augmentCliPath2(env) {
|
|
19046
|
+
const home = env.HOME || (0, import_node_os3.homedir)();
|
|
18437
19047
|
const extraPaths = [
|
|
18438
|
-
(0,
|
|
18439
|
-
(0,
|
|
18440
|
-
(0,
|
|
18441
|
-
(0,
|
|
19048
|
+
(0, import_node_path3.join)(home, ".local", "bin"),
|
|
19049
|
+
(0, import_node_path3.join)(home, ".local", "node", "bin"),
|
|
19050
|
+
(0, import_node_path3.join)(home, ".bun", "bin"),
|
|
19051
|
+
(0, import_node_path3.join)(home, ".cargo", "bin"),
|
|
18442
19052
|
"/opt/homebrew/bin",
|
|
18443
19053
|
"/usr/local/bin"
|
|
18444
19054
|
];
|
|
18445
|
-
const existing = new Set(
|
|
19055
|
+
const existing = new Set(splitPath2(env.PATH));
|
|
18446
19056
|
const missing = extraPaths.filter((path) => !existing.has(path));
|
|
18447
19057
|
if (missing.length === 0)
|
|
18448
19058
|
return env;
|
|
18449
19059
|
return {
|
|
18450
19060
|
...env,
|
|
18451
|
-
PATH: `${missing.join(
|
|
19061
|
+
PATH: `${missing.join(import_node_path3.delimiter)}${import_node_path3.delimiter}${env.PATH ?? ""}`
|
|
18452
19062
|
};
|
|
18453
19063
|
}
|
|
18454
19064
|
function resolveExecutable(command, env, overrideEnvVar) {
|
|
18455
19065
|
const override = env[overrideEnvVar]?.trim();
|
|
18456
19066
|
if (override && isExecutableFile(override))
|
|
18457
19067
|
return override;
|
|
18458
|
-
for (const dir of
|
|
18459
|
-
const candidate = (0,
|
|
19068
|
+
for (const dir of splitPath2(env.PATH)) {
|
|
19069
|
+
const candidate = (0, import_node_path3.join)(dir, command);
|
|
18460
19070
|
if (isExecutableFile(candidate))
|
|
18461
19071
|
return candidate;
|
|
18462
19072
|
}
|
|
@@ -18528,12 +19138,12 @@ async function withTimeout(promise, timeoutMs, fallback) {
|
|
|
18528
19138
|
}
|
|
18529
19139
|
}
|
|
18530
19140
|
async function collectCodexLimits(env) {
|
|
18531
|
-
const runtimeEnv =
|
|
19141
|
+
const runtimeEnv = augmentCliPath2(env);
|
|
18532
19142
|
const codexCommand = resolveExecutable("codex", runtimeEnv, "ALAN_CODEX_PATH");
|
|
18533
19143
|
if (!codexCommand)
|
|
18534
19144
|
return [];
|
|
18535
19145
|
return withTimeout(new Promise((resolve6) => {
|
|
18536
|
-
const child = (0,
|
|
19146
|
+
const child = (0, import_node_child_process2.spawn)(codexCommand, ["-s", "read-only", "-a", "untrusted", "app-server"], {
|
|
18537
19147
|
env: runtimeEnv,
|
|
18538
19148
|
stdio: ["pipe", "pipe", "ignore"]
|
|
18539
19149
|
});
|
|
@@ -18600,10 +19210,10 @@ async function collectCodexLimits(env) {
|
|
|
18600
19210
|
}), 4e3, []);
|
|
18601
19211
|
}
|
|
18602
19212
|
function readClaudeCredentialsPayload() {
|
|
18603
|
-
const path = (0,
|
|
18604
|
-
if ((0,
|
|
19213
|
+
const path = (0, import_node_path3.join)((0, import_node_os3.homedir)(), ".claude", ".credentials.json");
|
|
19214
|
+
if ((0, import_node_fs3.existsSync)(path)) {
|
|
18605
19215
|
try {
|
|
18606
|
-
return JSON.parse((0,
|
|
19216
|
+
return JSON.parse((0, import_node_fs3.readFileSync)(path, "utf8"));
|
|
18607
19217
|
} catch {
|
|
18608
19218
|
return null;
|
|
18609
19219
|
}
|
|
@@ -18611,7 +19221,7 @@ function readClaudeCredentialsPayload() {
|
|
|
18611
19221
|
if (process.platform !== "darwin")
|
|
18612
19222
|
return null;
|
|
18613
19223
|
try {
|
|
18614
|
-
const raw = (0,
|
|
19224
|
+
const raw = (0, import_node_child_process2.execFileSync)("security", ["find-generic-password", "-s", "Claude Code-credentials", "-w"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
18615
19225
|
if (!raw)
|
|
18616
19226
|
return null;
|
|
18617
19227
|
return JSON.parse(raw);
|
|
@@ -20310,11 +20920,11 @@ var SocketWithoutUpgrade = class _SocketWithoutUpgrade extends Emitter {
|
|
|
20310
20920
|
*/
|
|
20311
20921
|
_resetPingTimeout() {
|
|
20312
20922
|
this.clearTimeoutFn(this._pingTimeoutTimer);
|
|
20313
|
-
const
|
|
20314
|
-
this._pingTimeoutTime = Date.now() +
|
|
20923
|
+
const delay2 = this._pingInterval + this._pingTimeout;
|
|
20924
|
+
this._pingTimeoutTime = Date.now() + delay2;
|
|
20315
20925
|
this._pingTimeoutTimer = this.setTimeoutFn(() => {
|
|
20316
20926
|
this._onClose("ping timeout");
|
|
20317
|
-
},
|
|
20927
|
+
}, delay2);
|
|
20318
20928
|
if (this.opts.autoUnref) {
|
|
20319
20929
|
this._pingTimeoutTimer.unref();
|
|
20320
20930
|
}
|
|
@@ -22295,8 +22905,8 @@ var Manager = class extends Emitter {
|
|
|
22295
22905
|
this.emitReserved("reconnect_failed");
|
|
22296
22906
|
this._reconnecting = false;
|
|
22297
22907
|
} else {
|
|
22298
|
-
const
|
|
22299
|
-
debug10("will wait %dms before reconnect attempt",
|
|
22908
|
+
const delay2 = this.backoff.duration();
|
|
22909
|
+
debug10("will wait %dms before reconnect attempt", delay2);
|
|
22300
22910
|
this._reconnecting = true;
|
|
22301
22911
|
const timer = this.setTimeoutFn(() => {
|
|
22302
22912
|
if (self.skipReconnect)
|
|
@@ -22316,7 +22926,7 @@ var Manager = class extends Emitter {
|
|
|
22316
22926
|
self.onreconnect();
|
|
22317
22927
|
}
|
|
22318
22928
|
});
|
|
22319
|
-
},
|
|
22929
|
+
}, delay2);
|
|
22320
22930
|
if (this.opts.autoUnref) {
|
|
22321
22931
|
timer.unref();
|
|
22322
22932
|
}
|
|
@@ -22377,159 +22987,48 @@ Object.assign(lookup, {
|
|
|
22377
22987
|
connect: lookup
|
|
22378
22988
|
});
|
|
22379
22989
|
|
|
22380
|
-
// src/cli-
|
|
22381
|
-
var
|
|
22382
|
-
var
|
|
22383
|
-
var
|
|
22384
|
-
var
|
|
22385
|
-
|
|
22386
|
-
|
|
22387
|
-
|
|
22388
|
-
|
|
22389
|
-
command: "codex",
|
|
22390
|
-
envVars: ["ALAN_CODEX_PATH"]
|
|
22391
|
-
},
|
|
22392
|
-
copilot_cli: { provider: "copilot_cli", command: "copilot", envVars: ["ALAN_COPILOT_PATH"] },
|
|
22393
|
-
cursor_agent_cli: {
|
|
22394
|
-
provider: "cursor_agent_cli",
|
|
22395
|
-
command: "cursor-agent",
|
|
22396
|
-
envVars: ["ALAN_CURSOR_AGENT_PATH"]
|
|
22397
|
-
},
|
|
22398
|
-
antigravity_cli: {
|
|
22399
|
-
provider: "antigravity_cli",
|
|
22400
|
-
command: "agy",
|
|
22401
|
-
envVars: ["ALAN_ANTIGRAVITY_PATH"]
|
|
22402
|
-
},
|
|
22403
|
-
kimi_cli: { provider: "kimi_cli", command: "kimi-cli", envVars: ["ALAN_KIMI_PATH"] },
|
|
22404
|
-
grok_cli: { provider: "grok_cli", command: "grok", envVars: ["ALAN_GROK_PATH"] },
|
|
22405
|
-
opencode_cli: { provider: "opencode_cli", command: "opencode", envVars: ["ALAN_OPENCODE_PATH"] },
|
|
22406
|
-
droid_cli: { provider: "droid_cli", command: "droid", envVars: ["ALAN_DROID_PATH"] },
|
|
22407
|
-
supatest_cli: { provider: "supatest_cli", command: "supatest", envVars: ["ALAN_SUPATEST_PATH"] }
|
|
22408
|
-
};
|
|
22409
|
-
var DISCOVERABLE_PROVIDER_KINDS = Object.keys(PROVIDER_CLI_COMMANDS);
|
|
22410
|
-
var PROVIDER_ALIASES = {
|
|
22411
|
-
agy: "antigravity_cli",
|
|
22412
|
-
antigravity: "antigravity_cli",
|
|
22413
|
-
antigravity_cli: "antigravity_cli",
|
|
22414
|
-
codex: "codex_app_server",
|
|
22415
|
-
gemini: "antigravity_cli",
|
|
22416
|
-
gemini_cli: "antigravity_cli"
|
|
22417
|
-
};
|
|
22418
|
-
var BACKEND_CLI_COMMANDS = {
|
|
22419
|
-
claude_cli: "claude",
|
|
22420
|
-
codex: "codex",
|
|
22421
|
-
codex_app_server: "codex",
|
|
22422
|
-
copilot_cli: "copilot",
|
|
22423
|
-
cursor_agent_cli: "cursor-agent",
|
|
22424
|
-
agy: "agy",
|
|
22425
|
-
antigravity: "agy",
|
|
22426
|
-
antigravity_cli: "agy",
|
|
22427
|
-
gemini_cli: "agy",
|
|
22428
|
-
gemini: "agy",
|
|
22429
|
-
kimi_cli: "kimi-cli",
|
|
22430
|
-
grok_cli: "grok",
|
|
22431
|
-
opencode_cli: "opencode",
|
|
22432
|
-
droid_cli: "droid",
|
|
22433
|
-
supatest_cli: "supatest"
|
|
22434
|
-
};
|
|
22435
|
-
var CLI_COMMAND_ALIASES = {
|
|
22436
|
-
"kimi-cli": ["kimi"],
|
|
22437
|
-
grok: ["grok-build"]
|
|
22990
|
+
// src/cli-ensure-install.ts
|
|
22991
|
+
var import_node_child_process3 = require("child_process");
|
|
22992
|
+
var import_node_os4 = require("os");
|
|
22993
|
+
var CLI_RUNTIME_VERSIONS_ENV = "ALAN_CLI_RUNTIME_VERSIONS";
|
|
22994
|
+
var INSTALLABLE_PROVIDER_PACKAGES = {
|
|
22995
|
+
claude_cli: { npmPackage: "@anthropic-ai/claude-code", command: "claude", label: "Claude Code" },
|
|
22996
|
+
codex_app_server: { npmPackage: "@openai/codex", command: "codex", label: "Codex" },
|
|
22997
|
+
copilot_cli: { npmPackage: "@github/copilot", command: "copilot", label: "Copilot" },
|
|
22998
|
+
opencode_cli: { npmPackage: "opencode-ai", command: "opencode", label: "opencode" }
|
|
22438
22999
|
};
|
|
22439
|
-
var
|
|
22440
|
-
var
|
|
22441
|
-
function
|
|
22442
|
-
|
|
22443
|
-
|
|
22444
|
-
|
|
22445
|
-
|
|
22446
|
-
|
|
22447
|
-
|
|
22448
|
-
|
|
22449
|
-
|
|
22450
|
-
|
|
22451
|
-
|
|
22452
|
-
|
|
22453
|
-
return
|
|
22454
|
-
}
|
|
22455
|
-
function
|
|
22456
|
-
|
|
22457
|
-
|
|
22458
|
-
cachedLoginShellEnv = process.env;
|
|
22459
|
-
return cachedLoginShellEnv;
|
|
22460
|
-
}
|
|
22461
|
-
try {
|
|
22462
|
-
const shell = (process.env.SHELL || "/bin/bash").replace(/'/g, "'\\''");
|
|
22463
|
-
const envOutput = (0, import_node_child_process2.execSync)(`'${shell}' -ilc 'env'`, {
|
|
22464
|
-
encoding: "utf8",
|
|
22465
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
22466
|
-
timeout: 5e3
|
|
22467
|
-
});
|
|
22468
|
-
cachedLoginShellEnv = parseEnvOutput(envOutput);
|
|
22469
|
-
} catch {
|
|
22470
|
-
cachedLoginShellEnv = process.env;
|
|
22471
|
-
}
|
|
22472
|
-
return cachedLoginShellEnv;
|
|
22473
|
-
}
|
|
22474
|
-
function getDaemonCliEnvironment() {
|
|
22475
|
-
const base = (0, import_node_os3.platform)() === "win32" ? process.env : loadLoginShellEnvironment();
|
|
22476
|
-
return augmentCliPath2(base);
|
|
22477
|
-
}
|
|
22478
|
-
function cacheResolvedCli(command, resolvedPath) {
|
|
22479
|
-
resolvedCliCache.set(command, resolvedPath);
|
|
22480
|
-
}
|
|
22481
|
-
function getCachedResolvedCli(command) {
|
|
22482
|
-
return resolvedCliCache.get(command);
|
|
22483
|
-
}
|
|
22484
|
-
function resolveViaWhere(command, env) {
|
|
22485
|
-
if ((0, import_node_os3.platform)() !== "win32") return null;
|
|
22486
|
-
const whereExe = (0, import_node_path3.join)(
|
|
22487
|
-
env.SystemRoot ?? process.env.SystemRoot ?? "C:\\Windows",
|
|
22488
|
-
"System32",
|
|
22489
|
-
"where.exe"
|
|
22490
|
-
);
|
|
22491
|
-
if (!(0, import_node_fs3.existsSync)(whereExe)) return null;
|
|
22492
|
-
const result = (0, import_node_child_process2.spawnSync)(whereExe, [command], {
|
|
22493
|
-
encoding: "utf8",
|
|
22494
|
-
env,
|
|
22495
|
-
windowsHide: true,
|
|
22496
|
-
timeout: 3e3
|
|
22497
|
-
});
|
|
22498
|
-
if (result.error || result.status !== 0) return null;
|
|
22499
|
-
for (const line of result.stdout.split(/\r?\n/)) {
|
|
22500
|
-
const trimmed = line.trim();
|
|
22501
|
-
if (!trimmed) continue;
|
|
22502
|
-
if (isRunnableFile(trimmed)) return trimmed;
|
|
22503
|
-
}
|
|
22504
|
-
return null;
|
|
22505
|
-
}
|
|
22506
|
-
function runCliProbeAsync(executable, env, args = ["--version"], timeoutMs = 3e3, spawnOptions) {
|
|
22507
|
-
return new Promise((resolve6) => {
|
|
22508
|
-
const isWin = (0, import_node_os3.platform)() === "win32";
|
|
22509
|
-
let command = executable;
|
|
22510
|
-
let commandArgs = args;
|
|
22511
|
-
if (isWin && /\.(cmd|bat)$/i.test(executable)) {
|
|
22512
|
-
command = env.ComSpec ?? process.env.ComSpec ?? "cmd.exe";
|
|
22513
|
-
commandArgs = ["/d", "/s", "/c", executable, ...args];
|
|
22514
|
-
}
|
|
22515
|
-
const useShell = isWin && command === executable && !/[\\/]/.test(executable);
|
|
22516
|
-
const closeStdin = spawnOptions?.closeStdin === true;
|
|
23000
|
+
var INSTALL_TIMEOUT_MS = 12e4;
|
|
23001
|
+
var installOutcomes = /* @__PURE__ */ new Map();
|
|
23002
|
+
function canInstallProviderCli(backendKind) {
|
|
23003
|
+
return Boolean(backendKind && INSTALLABLE_PROVIDER_PACKAGES[backendKind]);
|
|
23004
|
+
}
|
|
23005
|
+
function pinnedVersion(npmPackage) {
|
|
23006
|
+
const raw = process.env[CLI_RUNTIME_VERSIONS_ENV];
|
|
23007
|
+
if (!raw) return "latest";
|
|
23008
|
+
try {
|
|
23009
|
+
const parsed = JSON.parse(raw);
|
|
23010
|
+
const version = parsed[npmPackage];
|
|
23011
|
+
if (typeof version === "string" && version.trim()) return version.trim();
|
|
23012
|
+
} catch {
|
|
23013
|
+
}
|
|
23014
|
+
return "latest";
|
|
23015
|
+
}
|
|
23016
|
+
function runNpmInstall(installSpec, env, timeoutMs) {
|
|
23017
|
+
return new Promise((resolve6) => {
|
|
23018
|
+
const isWin = (0, import_node_os4.platform)() === "win32";
|
|
22517
23019
|
let child;
|
|
22518
23020
|
try {
|
|
22519
|
-
child = (0,
|
|
23021
|
+
child = (0, import_node_child_process3.spawn)("npm", ["install", "-g", installSpec], {
|
|
22520
23022
|
env,
|
|
22521
|
-
shell:
|
|
23023
|
+
shell: isWin,
|
|
22522
23024
|
windowsHide: isWin ? true : void 0,
|
|
22523
23025
|
timeout: timeoutMs,
|
|
22524
|
-
stdio:
|
|
23026
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
22525
23027
|
});
|
|
22526
23028
|
} catch (error) {
|
|
22527
23029
|
resolve6({ status: null, stdout: "", stderr: "", error });
|
|
22528
23030
|
return;
|
|
22529
23031
|
}
|
|
22530
|
-
if (closeStdin) {
|
|
22531
|
-
child.stdin?.end();
|
|
22532
|
-
}
|
|
22533
23032
|
let stdout = "";
|
|
22534
23033
|
let stderr = "";
|
|
22535
23034
|
child.stdout?.setEncoding("utf8").on("data", (chunk) => {
|
|
@@ -22541,159 +23040,48 @@ function runCliProbeAsync(executable, env, args = ["--version"], timeoutMs = 3e3
|
|
|
22541
23040
|
child.once("error", (error) => resolve6({ status: null, stdout, stderr, error }));
|
|
22542
23041
|
child.once(
|
|
22543
23042
|
"close",
|
|
22544
|
-
(status, signal) => resolve6({
|
|
23043
|
+
(status, signal) => resolve6({
|
|
23044
|
+
status,
|
|
23045
|
+
stdout,
|
|
23046
|
+
stderr,
|
|
23047
|
+
// Spawn `timeout` kills by signal without an `error` event; surface it
|
|
23048
|
+
// so a timed-out install is reported as a failure, not status null + ok.
|
|
23049
|
+
...signal ? { error: new Error(`npm install killed by ${signal}`) } : {}
|
|
23050
|
+
})
|
|
22545
23051
|
);
|
|
22546
23052
|
});
|
|
22547
23053
|
}
|
|
22548
|
-
function
|
|
22549
|
-
|
|
22550
|
-
}
|
|
22551
|
-
|
|
22552
|
-
|
|
22553
|
-
|
|
22554
|
-
|
|
22555
|
-
|
|
22556
|
-
|
|
22557
|
-
|
|
22558
|
-
|
|
22559
|
-
|
|
22560
|
-
|
|
22561
|
-
try {
|
|
22562
|
-
(0, import_node_fs3.accessSync)(path, import_node_fs3.constants.X_OK);
|
|
22563
|
-
return true;
|
|
22564
|
-
} catch {
|
|
23054
|
+
async function attemptInstall(spec, options) {
|
|
23055
|
+
const installSpec = `${spec.npmPackage}@${pinnedVersion(spec.npmPackage)}`;
|
|
23056
|
+
const notify = options?.notify ?? ((message) => console.info(`[cli-ensure-install] ${message}`));
|
|
23057
|
+
notify(`Installing ${spec.label} CLI (${installSpec})\u2026`);
|
|
23058
|
+
const runner = options?.runner ?? runNpmInstall;
|
|
23059
|
+
const result = await runner(installSpec, getDaemonCliEnvironment(), INSTALL_TIMEOUT_MS);
|
|
23060
|
+
if (result.error || result.status !== 0) {
|
|
23061
|
+
console.warn(`[cli-ensure-install] npm install -g ${installSpec} failed`, {
|
|
23062
|
+
status: result.status,
|
|
23063
|
+
error: result.error?.message,
|
|
23064
|
+
output: `${result.stderr || result.stdout}`.trim().slice(-500)
|
|
23065
|
+
});
|
|
23066
|
+
notify(`Failed to install ${spec.label} CLI (${installSpec}).`);
|
|
22565
23067
|
return false;
|
|
22566
23068
|
}
|
|
23069
|
+
invalidateResolvedCli(spec.command);
|
|
23070
|
+
notify(`Installed ${spec.label} CLI (${installSpec}).`);
|
|
23071
|
+
return true;
|
|
22567
23072
|
}
|
|
22568
|
-
function
|
|
22569
|
-
|
|
22570
|
-
|
|
22571
|
-
|
|
22572
|
-
|
|
22573
|
-
|
|
22574
|
-
|
|
22575
|
-
}
|
|
22576
|
-
|
|
22577
|
-
|
|
22578
|
-
|
|
22579
|
-
|
|
22580
|
-
(0, import_node_path3.join)(home, "AppData", "Roaming", "npm"),
|
|
22581
|
-
(0, import_node_path3.join)(home, "AppData", "Local", "Programs", "Microsoft", "WindowsApps"),
|
|
22582
|
-
(0, import_node_path3.join)(home, ".local", "bin"),
|
|
22583
|
-
"C:\\Program Files\\nodejs",
|
|
22584
|
-
"C:\\Program Files\\Git\\cmd"
|
|
22585
|
-
] : [
|
|
22586
|
-
(0, import_node_path3.join)(home, ".local", "bin"),
|
|
22587
|
-
(0, import_node_path3.join)(home, ".local", "node", "bin"),
|
|
22588
|
-
(0, import_node_path3.join)(home, ".bun", "bin"),
|
|
22589
|
-
(0, import_node_path3.join)(home, ".cargo", "bin"),
|
|
22590
|
-
"/opt/homebrew/bin",
|
|
22591
|
-
"/usr/local/bin"
|
|
22592
|
-
];
|
|
22593
|
-
const basePath = env.PATH ?? "";
|
|
22594
|
-
const existing = new Set(splitPath2(basePath));
|
|
22595
|
-
const missing = extraPaths.filter((dir) => !existing.has(dir));
|
|
22596
|
-
if (missing.length === 0) return env;
|
|
22597
|
-
return {
|
|
22598
|
-
...env,
|
|
22599
|
-
PATH: missing.length > 0 ? `${missing.join(pathSeparator())}${pathSeparator()}${basePath}` : basePath
|
|
22600
|
-
};
|
|
22601
|
-
}
|
|
22602
|
-
function resolveCliExecutable(command, env = getDaemonCliEnvironment()) {
|
|
22603
|
-
const trimmed = command.trim();
|
|
22604
|
-
if (!trimmed) return null;
|
|
22605
|
-
const cached = resolvedCliCache.get(trimmed);
|
|
22606
|
-
if (cached === null) return null;
|
|
22607
|
-
if (cached && isRunnableFile(cached)) return cached;
|
|
22608
|
-
if ((trimmed.includes("/") || trimmed.includes("\\")) && isRunnableFile(trimmed)) {
|
|
22609
|
-
resolvedCliCache.set(trimmed, trimmed);
|
|
22610
|
-
return trimmed;
|
|
22611
|
-
}
|
|
22612
|
-
const enriched = augmentCliPath2(env);
|
|
22613
|
-
const home = enriched.HOME || enriched.USERPROFILE || (0, import_node_os3.homedir)();
|
|
22614
|
-
const isWin = (0, import_node_os3.platform)() === "win32";
|
|
22615
|
-
const pathExt = enriched.PATHEXT ?? (isWin ? ".EXE;.CMD;.BAT;.COM" : "");
|
|
22616
|
-
const commandNames = [trimmed, ...CLI_COMMAND_ALIASES[trimmed] ?? []];
|
|
22617
|
-
const names = commandNames.flatMap(
|
|
22618
|
-
(name) => isWin ? windowsCommandCandidates(name, pathExt) : [name]
|
|
22619
|
-
);
|
|
22620
|
-
const candidates = [];
|
|
22621
|
-
for (const name of names) {
|
|
22622
|
-
if (name.includes("/") || name.includes("\\")) {
|
|
22623
|
-
candidates.push(name);
|
|
22624
|
-
continue;
|
|
22625
|
-
}
|
|
22626
|
-
for (const dir of splitPath2(enriched.PATH)) {
|
|
22627
|
-
candidates.push((0, import_node_path3.join)(dir, name));
|
|
22628
|
-
}
|
|
22629
|
-
candidates.push((0, import_node_path3.join)(home, ".local", "bin", name), (0, import_node_path3.join)(home, ".local", "node", "bin", name));
|
|
22630
|
-
if (!isWin) {
|
|
22631
|
-
candidates.push((0, import_node_path3.join)("/opt/homebrew/bin", name), (0, import_node_path3.join)("/usr/local/bin", name));
|
|
22632
|
-
} else {
|
|
22633
|
-
candidates.push((0, import_node_path3.join)(home, "AppData", "Roaming", "npm", name));
|
|
22634
|
-
}
|
|
22635
|
-
}
|
|
22636
|
-
const seen = /* @__PURE__ */ new Set();
|
|
22637
|
-
for (const candidate of candidates) {
|
|
22638
|
-
if (seen.has(candidate)) continue;
|
|
22639
|
-
seen.add(candidate);
|
|
22640
|
-
if (isRunnableFile(candidate)) {
|
|
22641
|
-
resolvedCliCache.set(trimmed, candidate);
|
|
22642
|
-
return candidate;
|
|
22643
|
-
}
|
|
22644
|
-
}
|
|
22645
|
-
const viaWhere = resolveViaWhere(trimmed, enriched);
|
|
22646
|
-
if (viaWhere) {
|
|
22647
|
-
resolvedCliCache.set(trimmed, viaWhere);
|
|
22648
|
-
return viaWhere;
|
|
22649
|
-
}
|
|
22650
|
-
resolvedCliCache.set(trimmed, null);
|
|
22651
|
-
return null;
|
|
22652
|
-
}
|
|
22653
|
-
function normalizeDiscoverableProvider(provider) {
|
|
22654
|
-
const alias = PROVIDER_ALIASES[provider];
|
|
22655
|
-
if (alias) return alias;
|
|
22656
|
-
if (provider in PROVIDER_CLI_COMMANDS) {
|
|
22657
|
-
return provider;
|
|
22658
|
-
}
|
|
22659
|
-
return null;
|
|
22660
|
-
}
|
|
22661
|
-
function resolveProviderCliCommand(provider, env = getDaemonCliEnvironment()) {
|
|
22662
|
-
const normalized = normalizeDiscoverableProvider(provider);
|
|
22663
|
-
if (!normalized) return null;
|
|
22664
|
-
const spec = PROVIDER_CLI_COMMANDS[normalized];
|
|
22665
|
-
const override = spec.envVars.map((name) => process.env[name]?.trim() || env[name]?.trim()).find(Boolean);
|
|
22666
|
-
if (override) {
|
|
22667
|
-
const resolved2 = resolveCliExecutable(override, env) ?? (isRunnableFile(override) ? override : null);
|
|
22668
|
-
if (resolved2) cacheResolvedCli(spec.command, resolved2);
|
|
22669
|
-
return resolved2;
|
|
22670
|
-
}
|
|
22671
|
-
const resolved = resolveCliExecutable(spec.command, env);
|
|
22672
|
-
if (resolved) cacheResolvedCli(spec.command, resolved);
|
|
22673
|
-
return resolved;
|
|
22674
|
-
}
|
|
22675
|
-
function resolveBackendRuntimeCommand(backendKind, env = getDaemonCliEnvironment()) {
|
|
22676
|
-
if (!backendKind) return void 0;
|
|
22677
|
-
const command = BACKEND_CLI_COMMANDS[backendKind];
|
|
22678
|
-
if (!command) return void 0;
|
|
22679
|
-
const cached = getCachedResolvedCli(command);
|
|
22680
|
-
if (cached === null) return void 0;
|
|
22681
|
-
if (cached && isRunnableFile(cached)) return cached;
|
|
22682
|
-
const spec = Object.values(PROVIDER_CLI_COMMANDS).find((entry) => entry.command === command);
|
|
22683
|
-
const envOverride = spec ? spec.envVars.map((name) => env[name]?.trim()).find(Boolean) : void 0;
|
|
22684
|
-
const resolved = resolveCliExecutable(envOverride?.trim() || command, env);
|
|
22685
|
-
cacheResolvedCli(command, resolved);
|
|
22686
|
-
return resolved ?? void 0;
|
|
22687
|
-
}
|
|
22688
|
-
function revalidateBackendRuntimeCommand(backendKind, env = getDaemonCliEnvironment()) {
|
|
22689
|
-
if (!backendKind) return void 0;
|
|
22690
|
-
const command = BACKEND_CLI_COMMANDS[backendKind];
|
|
22691
|
-
if (!command) return void 0;
|
|
22692
|
-
resolvedCliCache.delete(command);
|
|
22693
|
-
const spec = Object.values(PROVIDER_CLI_COMMANDS).find((entry) => entry.command === command);
|
|
22694
|
-
const envOverride = spec ? spec.envVars.map((name) => env[name]?.trim()).find(Boolean) : void 0;
|
|
22695
|
-
if (envOverride) resolvedCliCache.delete(envOverride);
|
|
22696
|
-
return resolveBackendRuntimeCommand(backendKind, env);
|
|
23073
|
+
function ensureProviderCliInstalled(backendKind, options) {
|
|
23074
|
+
if (!backendKind) return Promise.resolve(false);
|
|
23075
|
+
const spec = INSTALLABLE_PROVIDER_PACKAGES[backendKind];
|
|
23076
|
+
if (!spec) return Promise.resolve(false);
|
|
23077
|
+
const existing = installOutcomes.get(spec.npmPackage);
|
|
23078
|
+
if (existing) return existing;
|
|
23079
|
+
const attempt = attemptInstall(spec, options).catch((error) => {
|
|
23080
|
+
console.warn(`[cli-ensure-install] install attempt for ${spec.npmPackage} threw`, error);
|
|
23081
|
+
return false;
|
|
23082
|
+
});
|
|
23083
|
+
installOutcomes.set(spec.npmPackage, attempt);
|
|
23084
|
+
return attempt;
|
|
22697
23085
|
}
|
|
22698
23086
|
|
|
22699
23087
|
// src/computer-readiness.ts
|
|
@@ -22701,10 +23089,10 @@ var import_node_fs5 = require("fs");
|
|
|
22701
23089
|
|
|
22702
23090
|
// src/runtime-config.ts
|
|
22703
23091
|
var import_node_fs4 = require("fs");
|
|
22704
|
-
var
|
|
23092
|
+
var import_node_os5 = require("os");
|
|
22705
23093
|
var import_node_path4 = require("path");
|
|
22706
|
-
var DEFAULT_AGENT_DIR = (0, import_node_path4.join)((0,
|
|
22707
|
-
var LEGACY_AGENT_DIR = (0, import_node_path4.join)((0,
|
|
23094
|
+
var DEFAULT_AGENT_DIR = (0, import_node_path4.join)((0, import_node_os5.homedir)(), ".alan", "agent");
|
|
23095
|
+
var LEGACY_AGENT_DIR = (0, import_node_path4.join)((0, import_node_os5.homedir)(), ".aiden", "agent");
|
|
22708
23096
|
var AGENT_CONFIG_KEYS = /* @__PURE__ */ new Map([
|
|
22709
23097
|
["apiUrl", "string"],
|
|
22710
23098
|
["wsUrl", "string"],
|
|
@@ -23012,7 +23400,7 @@ function buildComputerReadiness(input) {
|
|
|
23012
23400
|
}
|
|
23013
23401
|
|
|
23014
23402
|
// src/core-agent.ts
|
|
23015
|
-
var
|
|
23403
|
+
var import_node_os6 = require("os");
|
|
23016
23404
|
var CoreAgent = class _CoreAgent extends BaseMachineAgent {
|
|
23017
23405
|
childProcess = null;
|
|
23018
23406
|
_aborted = false;
|
|
@@ -23064,7 +23452,18 @@ var CoreAgent = class _CoreAgent extends BaseMachineAgent {
|
|
|
23064
23452
|
* and re-resolving once lets the current run recover against the new location.
|
|
23065
23453
|
*/
|
|
23066
23454
|
revalidateRuntimeCommand() {
|
|
23067
|
-
|
|
23455
|
+
const resolved = revalidateBackendRuntimeCommand(this.runtime.backendKind) ?? null;
|
|
23456
|
+
if (!resolved && this.runtime.backendKind) {
|
|
23457
|
+
const backendKind = this.runtime.backendKind;
|
|
23458
|
+
void ensureProviderCliInstalled(backendKind).then((installed) => {
|
|
23459
|
+
if (installed) {
|
|
23460
|
+
console.info("[CoreAgent] Installed missing provider CLI after spawn ENOENT", {
|
|
23461
|
+
backendKind
|
|
23462
|
+
});
|
|
23463
|
+
}
|
|
23464
|
+
});
|
|
23465
|
+
}
|
|
23466
|
+
return resolved;
|
|
23068
23467
|
}
|
|
23069
23468
|
// ── Interactive tool response (WS relay → stdin) ───────────────────────
|
|
23070
23469
|
/**
|
|
@@ -23151,7 +23550,7 @@ var CoreAgent = class _CoreAgent extends BaseMachineAgent {
|
|
|
23151
23550
|
if (this.runtime.backendKind === "grok_cli" && this.providerApiKey) {
|
|
23152
23551
|
augmented.XAI_API_KEY = this.providerApiKey;
|
|
23153
23552
|
}
|
|
23154
|
-
if ((0,
|
|
23553
|
+
if ((0, import_node_os6.platform)() !== "win32") {
|
|
23155
23554
|
const home = augmented.HOME ?? "/home/user";
|
|
23156
23555
|
const extraPaths = [`${home}/.local/node/bin`, `${home}/.local/bin`];
|
|
23157
23556
|
const separator = ":";
|
|
@@ -23706,11 +24105,97 @@ var EncryptedEventOutbox = class _EncryptedEventOutbox {
|
|
|
23706
24105
|
}
|
|
23707
24106
|
};
|
|
23708
24107
|
|
|
23709
|
-
// src/
|
|
23710
|
-
var import_node_crypto2 = require("crypto");
|
|
24108
|
+
// src/local-skill-scan.ts
|
|
23711
24109
|
var import_node_fs7 = require("fs");
|
|
23712
|
-
var import_node_os6 = require("os");
|
|
23713
24110
|
var import_node_path6 = require("path");
|
|
24111
|
+
var SKILL_READ_LIMIT_BYTES = 8192;
|
|
24112
|
+
var SKILL_CACHE_TTL_MS = 3e4;
|
|
24113
|
+
function readSkillHead(path) {
|
|
24114
|
+
const fd = (0, import_node_fs7.openSync)(path, "r");
|
|
24115
|
+
try {
|
|
24116
|
+
const buffer = Buffer.alloc(SKILL_READ_LIMIT_BYTES);
|
|
24117
|
+
const bytesRead = (0, import_node_fs7.readSync)(fd, buffer, 0, SKILL_READ_LIMIT_BYTES, 0);
|
|
24118
|
+
return buffer.subarray(0, bytesRead).toString("utf-8");
|
|
24119
|
+
} finally {
|
|
24120
|
+
(0, import_node_fs7.closeSync)(fd);
|
|
24121
|
+
}
|
|
24122
|
+
}
|
|
24123
|
+
function scanSkillDir(dirPath, source, repoRoot, entries, errors) {
|
|
24124
|
+
if (!(0, import_node_fs7.existsSync)(dirPath)) return;
|
|
24125
|
+
let names;
|
|
24126
|
+
try {
|
|
24127
|
+
names = (0, import_node_fs7.readdirSync)(dirPath);
|
|
24128
|
+
} catch (error) {
|
|
24129
|
+
errors.push(`Failed to scan ${dirPath}: ${error instanceof Error ? error.message : error}`);
|
|
24130
|
+
return;
|
|
24131
|
+
}
|
|
24132
|
+
for (const name of names) {
|
|
24133
|
+
const skillPath = (0, import_node_path6.join)(dirPath, name, "SKILL.md");
|
|
24134
|
+
let isDirectory = false;
|
|
24135
|
+
try {
|
|
24136
|
+
isDirectory = (0, import_node_fs7.statSync)((0, import_node_path6.join)(dirPath, name)).isDirectory();
|
|
24137
|
+
} catch {
|
|
24138
|
+
continue;
|
|
24139
|
+
}
|
|
24140
|
+
if (!isDirectory || !(0, import_node_fs7.existsSync)(skillPath)) continue;
|
|
24141
|
+
try {
|
|
24142
|
+
entries.push({ content: readSkillHead(skillPath), source, sourcePath: skillPath, repoRoot });
|
|
24143
|
+
} catch (error) {
|
|
24144
|
+
errors.push(`Failed to read ${skillPath}: ${error instanceof Error ? error.message : error}`);
|
|
24145
|
+
}
|
|
24146
|
+
}
|
|
24147
|
+
}
|
|
24148
|
+
function discoverChildRepos(parentPath) {
|
|
24149
|
+
let names;
|
|
24150
|
+
try {
|
|
24151
|
+
names = (0, import_node_fs7.readdirSync)(parentPath);
|
|
24152
|
+
} catch {
|
|
24153
|
+
return [];
|
|
24154
|
+
}
|
|
24155
|
+
const children = [];
|
|
24156
|
+
for (const name of names) {
|
|
24157
|
+
if (name.startsWith(".")) continue;
|
|
24158
|
+
const childPath = (0, import_node_path6.join)(parentPath, name);
|
|
24159
|
+
try {
|
|
24160
|
+
if ((0, import_node_fs7.statSync)(childPath).isDirectory()) children.push(childPath);
|
|
24161
|
+
} catch {
|
|
24162
|
+
}
|
|
24163
|
+
}
|
|
24164
|
+
return children;
|
|
24165
|
+
}
|
|
24166
|
+
function scanLocalSkills(homeDir, projectPath) {
|
|
24167
|
+
const rawEntries = [];
|
|
24168
|
+
const errors = [];
|
|
24169
|
+
for (const root of SKILL_DIRECTORY_ROOTS) {
|
|
24170
|
+
scanSkillDir((0, import_node_path6.join)(homeDir, root), "global", void 0, rawEntries, errors);
|
|
24171
|
+
}
|
|
24172
|
+
if (projectPath) {
|
|
24173
|
+
for (const dir of [projectPath, ...discoverChildRepos(projectPath)]) {
|
|
24174
|
+
for (const root of SKILL_DIRECTORY_ROOTS) {
|
|
24175
|
+
scanSkillDir((0, import_node_path6.join)(dir, root), "team", dir, rawEntries, errors);
|
|
24176
|
+
}
|
|
24177
|
+
}
|
|
24178
|
+
}
|
|
24179
|
+
return { skills: normalizeSkillEntries(rawEntries, "team"), errors };
|
|
24180
|
+
}
|
|
24181
|
+
var skillScanCache = /* @__PURE__ */ new Map();
|
|
24182
|
+
function scanLocalSkillsCached(homeDir, projectPath, options) {
|
|
24183
|
+
const key = projectPath ?? "";
|
|
24184
|
+
const now = Date.now();
|
|
24185
|
+
if (!options?.refresh) {
|
|
24186
|
+
const cached = skillScanCache.get(key);
|
|
24187
|
+
if (cached && cached.expiresAt > now) return cached.result;
|
|
24188
|
+
}
|
|
24189
|
+
const result = scanLocalSkills(homeDir, projectPath);
|
|
24190
|
+
skillScanCache.set(key, { expiresAt: now + SKILL_CACHE_TTL_MS, result });
|
|
24191
|
+
return result;
|
|
24192
|
+
}
|
|
24193
|
+
|
|
24194
|
+
// src/mcp-registration.ts
|
|
24195
|
+
var import_node_crypto2 = require("crypto");
|
|
24196
|
+
var import_node_fs8 = require("fs");
|
|
24197
|
+
var import_node_os7 = require("os");
|
|
24198
|
+
var import_node_path7 = require("path");
|
|
23714
24199
|
|
|
23715
24200
|
// ../../node_modules/smol-toml/dist/error.js
|
|
23716
24201
|
function getLineColFromPtr(string, ptr) {
|
|
@@ -24507,18 +24992,18 @@ var inspectAlanMcpThroughProviderCli = async (backendKind, expectedUrl, home) =>
|
|
|
24507
24992
|
return result;
|
|
24508
24993
|
};
|
|
24509
24994
|
async function waitForConfigLock(lockPath) {
|
|
24510
|
-
(0,
|
|
24995
|
+
(0, import_node_fs8.mkdirSync)((0, import_node_path7.dirname)(lockPath), { recursive: true });
|
|
24511
24996
|
const startedAt = Date.now();
|
|
24512
24997
|
while (true) {
|
|
24513
24998
|
try {
|
|
24514
|
-
(0,
|
|
24515
|
-
return () => (0,
|
|
24999
|
+
(0, import_node_fs8.mkdirSync)(lockPath);
|
|
25000
|
+
return () => (0, import_node_fs8.rmSync)(lockPath, { recursive: true, force: true });
|
|
24516
25001
|
} catch (error) {
|
|
24517
25002
|
const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
|
|
24518
25003
|
if (code !== "EEXIST") throw error;
|
|
24519
25004
|
try {
|
|
24520
|
-
if (Date.now() - (0,
|
|
24521
|
-
(0,
|
|
25005
|
+
if (Date.now() - (0, import_node_fs8.statSync)(lockPath).mtimeMs > CONFIG_LOCK_STALE_MS) {
|
|
25006
|
+
(0, import_node_fs8.rmSync)(lockPath, { recursive: true, force: true });
|
|
24522
25007
|
continue;
|
|
24523
25008
|
}
|
|
24524
25009
|
} catch {
|
|
@@ -24534,7 +25019,7 @@ async function waitForConfigLock(lockPath) {
|
|
|
24534
25019
|
function saveMalformedBackup(path, content) {
|
|
24535
25020
|
const hash = (0, import_node_crypto2.createHash)("sha256").update(content).digest("hex").slice(0, 12);
|
|
24536
25021
|
const backupPath = `${path}.alan-backup-${hash}`;
|
|
24537
|
-
if (!(0,
|
|
25022
|
+
if (!(0, import_node_fs8.existsSync)(backupPath)) (0, import_node_fs8.copyFileSync)(path, backupPath);
|
|
24538
25023
|
return backupPath;
|
|
24539
25024
|
}
|
|
24540
25025
|
function parseJsonObject2(path, content) {
|
|
@@ -24581,22 +25066,22 @@ function mergeCodexAlanSection(path, existingContent, desiredContent) {
|
|
|
24581
25066
|
function atomicWriteManagedConfig(path, content) {
|
|
24582
25067
|
const pendingPath = `${path}.alan-pending-${process.pid}-${(0, import_node_crypto2.randomBytes)(6).toString("hex")}`;
|
|
24583
25068
|
try {
|
|
24584
|
-
(0,
|
|
24585
|
-
(0,
|
|
25069
|
+
(0, import_node_fs8.writeFileSync)(pendingPath, content, { encoding: "utf8", mode: 384, flag: "wx" });
|
|
25070
|
+
(0, import_node_fs8.renameSync)(pendingPath, path);
|
|
24586
25071
|
} finally {
|
|
24587
|
-
(0,
|
|
25072
|
+
(0, import_node_fs8.rmSync)(pendingPath, { force: true });
|
|
24588
25073
|
}
|
|
24589
25074
|
}
|
|
24590
|
-
async function ensureAlanMcpRegistered(backendKind, registration, home = (0,
|
|
25075
|
+
async function ensureAlanMcpRegistered(backendKind, registration, home = (0, import_node_os7.homedir)(), inspectCli = inspectAlanMcpThroughProviderCli) {
|
|
24591
25076
|
try {
|
|
24592
25077
|
const mcpServers = buildAlanMcpServers(registration);
|
|
24593
25078
|
const files = alanMcpConfigFilesForBackend(backendKind, mcpServers, home);
|
|
24594
25079
|
const paths = [];
|
|
24595
25080
|
for (const file of files) {
|
|
24596
|
-
(0,
|
|
25081
|
+
(0, import_node_fs8.mkdirSync)((0, import_node_path7.dirname)(file.path), { recursive: true });
|
|
24597
25082
|
const releaseLock = await waitForConfigLock(`${file.path}.alan-lock`);
|
|
24598
25083
|
try {
|
|
24599
|
-
const current = (0,
|
|
25084
|
+
const current = (0, import_node_fs8.existsSync)(file.path) ? (0, import_node_fs8.readFileSync)(file.path, "utf8") : null;
|
|
24600
25085
|
const content = file.path.endsWith(".toml") ? mergeCodexAlanSection(file.path, current, file.content) : mergeJsonConfig(file.path, current, file.content);
|
|
24601
25086
|
if (current !== content) atomicWriteManagedConfig(file.path, content);
|
|
24602
25087
|
paths.push(file.path);
|
|
@@ -24647,13 +25132,13 @@ async function ensureAlanMcpRegistered(backendKind, registration, home = (0, imp
|
|
|
24647
25132
|
return { ok: false, paths: [], error: err instanceof Error ? err.message : String(err) };
|
|
24648
25133
|
}
|
|
24649
25134
|
}
|
|
24650
|
-
async function verifyAlanMcpRegistered(backendKind, home = (0,
|
|
25135
|
+
async function verifyAlanMcpRegistered(backendKind, home = (0, import_node_os7.homedir)(), inspectCli = inspectAlanMcpThroughProviderCli) {
|
|
24651
25136
|
const files = alanMcpConfigFilesForBackend(backendKind, {}, home);
|
|
24652
|
-
const missing = files.map((f) => f.path).filter((p) => !(0,
|
|
25137
|
+
const missing = files.map((f) => f.path).filter((p) => !(0, import_node_fs8.existsSync)(p));
|
|
24653
25138
|
const presentEntries = files.map((file) => ({
|
|
24654
25139
|
path: file.path,
|
|
24655
|
-
url: (0,
|
|
24656
|
-
})).filter((entry) => (0,
|
|
25140
|
+
url: (0, import_node_fs8.existsSync)(file.path) ? readUsableAlanMcpUrl(file.path) : null
|
|
25141
|
+
})).filter((entry) => (0, import_node_fs8.existsSync)(entry.path));
|
|
24657
25142
|
let invalid = presentEntries.filter((entry) => !entry.url).map((entry) => entry.path);
|
|
24658
25143
|
const urls = new Set(presentEntries.flatMap((entry) => entry.url ? [entry.url] : []));
|
|
24659
25144
|
if (urls.size > 1) invalid = presentEntries.map((entry) => entry.path);
|
|
@@ -24709,15 +25194,15 @@ function removeAlanFromJsonConfig(path, existingContent) {
|
|
|
24709
25194
|
}
|
|
24710
25195
|
return JSON.stringify(config);
|
|
24711
25196
|
}
|
|
24712
|
-
async function unregisterAlanMcp(backendKind, home = (0,
|
|
25197
|
+
async function unregisterAlanMcp(backendKind, home = (0, import_node_os7.homedir)()) {
|
|
24713
25198
|
const removedPaths = [];
|
|
24714
25199
|
const errors = [];
|
|
24715
25200
|
const files = alanMcpConfigFilesForBackend(backendKind, {}, home);
|
|
24716
25201
|
for (const file of files) {
|
|
24717
|
-
if (!(0,
|
|
25202
|
+
if (!(0, import_node_fs8.existsSync)(file.path)) continue;
|
|
24718
25203
|
const releaseLock = await waitForConfigLock(`${file.path}.alan-lock`);
|
|
24719
25204
|
try {
|
|
24720
|
-
const current = (0,
|
|
25205
|
+
const current = (0, import_node_fs8.readFileSync)(file.path, "utf8");
|
|
24721
25206
|
let next;
|
|
24722
25207
|
if (file.path.endsWith(".toml")) {
|
|
24723
25208
|
const stripped = stripCodexAlanMcpSection(current);
|
|
@@ -24748,7 +25233,7 @@ function isHttpUrl(value2) {
|
|
|
24748
25233
|
}
|
|
24749
25234
|
}
|
|
24750
25235
|
function readUsableAlanMcpUrl(path) {
|
|
24751
|
-
const content = (0,
|
|
25236
|
+
const content = (0, import_node_fs8.readFileSync)(path, "utf8");
|
|
24752
25237
|
if (path.endsWith(".toml")) {
|
|
24753
25238
|
const lines = content.split("\n");
|
|
24754
25239
|
const start = lines.findIndex((line) => line.trim() === "[mcp_servers.alan]");
|
|
@@ -25039,7 +25524,7 @@ ${result.stderr}`.trim();
|
|
|
25039
25524
|
}
|
|
25040
25525
|
|
|
25041
25526
|
// src/provider-model-discovery.ts
|
|
25042
|
-
var
|
|
25527
|
+
var import_node_fs9 = require("fs");
|
|
25043
25528
|
var MODEL_DISCOVERY_TIMEOUT_MS = 8e3;
|
|
25044
25529
|
var ANTIGRAVITY_MODEL_DISCOVERY_TIMEOUT_MS = 12e3;
|
|
25045
25530
|
var OPENCODE_ZEN_MODEL_IDS = OPENCODE_ZEN_MODELS.map((model) => model.id);
|
|
@@ -25253,7 +25738,7 @@ function filterClaudeDatedModelIds(ids) {
|
|
|
25253
25738
|
}
|
|
25254
25739
|
function resolveExecutableForModelScan(executable) {
|
|
25255
25740
|
try {
|
|
25256
|
-
return (0,
|
|
25741
|
+
return (0, import_node_fs9.realpathSync)(executable);
|
|
25257
25742
|
} catch {
|
|
25258
25743
|
return executable;
|
|
25259
25744
|
}
|
|
@@ -25261,7 +25746,7 @@ function resolveExecutableForModelScan(executable) {
|
|
|
25261
25746
|
function extractClaudeModelIdsFromExecutable(executable) {
|
|
25262
25747
|
try {
|
|
25263
25748
|
const resolved = resolveExecutableForModelScan(executable);
|
|
25264
|
-
const text = (0,
|
|
25749
|
+
const text = (0, import_node_fs9.readFileSync)(resolved).toString("latin1");
|
|
25265
25750
|
const matches = text.match(CLAUDE_MODEL_ID_PATTERN) ?? [];
|
|
25266
25751
|
const unique = [
|
|
25267
25752
|
...new Set(matches.map((id) => id.trim()).filter((id) => isValidClaudeModelId(id))),
|
|
@@ -25361,7 +25846,7 @@ async function discoverGenericModels(executable, env) {
|
|
|
25361
25846
|
["models"]
|
|
25362
25847
|
]);
|
|
25363
25848
|
}
|
|
25364
|
-
var CATALOG_ONLY_PROVIDERS = /* @__PURE__ */ new Set(["supatest_cli", "droid_cli"]);
|
|
25849
|
+
var CATALOG_ONLY_PROVIDERS = /* @__PURE__ */ new Set(["supatest_cli", "droid_cli", "copilot_cli"]);
|
|
25365
25850
|
function supportsProviderModelDiscovery(provider) {
|
|
25366
25851
|
return provider in CATALOG_MODEL_IDS_BY_PROVIDER;
|
|
25367
25852
|
}
|
|
@@ -25380,7 +25865,7 @@ async function discoverProviderModels(provider, executable, env) {
|
|
|
25380
25865
|
probed = await discoverCodexModels(executable, env);
|
|
25381
25866
|
} else if (provider === "claude_cli") {
|
|
25382
25867
|
probed = await discoverClaudeModels(executable, env);
|
|
25383
|
-
} else if (provider === "kimi_cli" || provider === "grok_cli"
|
|
25868
|
+
} else if (provider === "kimi_cli" || provider === "grok_cli") {
|
|
25384
25869
|
probed = await discoverGenericModels(executable, env);
|
|
25385
25870
|
}
|
|
25386
25871
|
if (probed.length > 0) return probed;
|
|
@@ -25388,8 +25873,8 @@ async function discoverProviderModels(provider, executable, env) {
|
|
|
25388
25873
|
}
|
|
25389
25874
|
|
|
25390
25875
|
// src/run-journal.ts
|
|
25391
|
-
var
|
|
25392
|
-
var
|
|
25876
|
+
var import_node_fs10 = require("fs");
|
|
25877
|
+
var import_node_path8 = require("path");
|
|
25393
25878
|
var JOURNAL_VERSION = 1;
|
|
25394
25879
|
var INTERRUPTED_ENTRY_TTL_MS = 24 * 60 * 6e4;
|
|
25395
25880
|
function isEntry(value2) {
|
|
@@ -25408,9 +25893,9 @@ function isEntry(value2) {
|
|
|
25408
25893
|
var RuntimeRunJournal = class {
|
|
25409
25894
|
constructor(path, nowMs = Date.now()) {
|
|
25410
25895
|
this.path = path;
|
|
25411
|
-
if (!(0,
|
|
25896
|
+
if (!(0, import_node_fs10.existsSync)(path)) return;
|
|
25412
25897
|
try {
|
|
25413
|
-
const parsed = JSON.parse((0,
|
|
25898
|
+
const parsed = JSON.parse((0, import_node_fs10.readFileSync)(path, "utf8"));
|
|
25414
25899
|
if (parsed.version !== JOURNAL_VERSION || !Array.isArray(parsed.entries)) {
|
|
25415
25900
|
throw new Error("unsupported run journal format");
|
|
25416
25901
|
}
|
|
@@ -25533,18 +26018,18 @@ var RuntimeRunJournal = class {
|
|
|
25533
26018
|
}
|
|
25534
26019
|
persist() {
|
|
25535
26020
|
const pendingPath = `${this.path}.pending`;
|
|
25536
|
-
(0,
|
|
26021
|
+
(0, import_node_fs10.mkdirSync)((0, import_node_path8.dirname)(this.path), { recursive: true });
|
|
25537
26022
|
try {
|
|
25538
|
-
(0,
|
|
26023
|
+
(0, import_node_fs10.writeFileSync)(
|
|
25539
26024
|
pendingPath,
|
|
25540
26025
|
`${JSON.stringify({ version: JOURNAL_VERSION, entries: [...this.entries.values()] })}
|
|
25541
26026
|
`,
|
|
25542
26027
|
{ mode: 384 }
|
|
25543
26028
|
);
|
|
25544
|
-
(0,
|
|
25545
|
-
(0,
|
|
26029
|
+
(0, import_node_fs10.chmodSync)(pendingPath, 384);
|
|
26030
|
+
(0, import_node_fs10.renameSync)(pendingPath, this.path);
|
|
25546
26031
|
} catch (error) {
|
|
25547
|
-
(0,
|
|
26032
|
+
(0, import_node_fs10.rmSync)(pendingPath, { force: true });
|
|
25548
26033
|
throw error;
|
|
25549
26034
|
}
|
|
25550
26035
|
}
|
|
@@ -25571,17 +26056,17 @@ var RunStartGate = class {
|
|
|
25571
26056
|
};
|
|
25572
26057
|
|
|
25573
26058
|
// src/version.ts
|
|
25574
|
-
var AGENT_VERSION = "0.1.
|
|
26059
|
+
var AGENT_VERSION = "0.1.50";
|
|
25575
26060
|
|
|
25576
26061
|
// src/workspace-relocation.ts
|
|
25577
|
-
var
|
|
25578
|
-
var
|
|
25579
|
-
var
|
|
26062
|
+
var import_node_child_process4 = require("child_process");
|
|
26063
|
+
var import_node_fs11 = require("fs");
|
|
26064
|
+
var import_node_path9 = require("path");
|
|
25580
26065
|
var MAX_RELOCATION_CANDIDATES = 200;
|
|
25581
26066
|
var DEFAULT_PROBE = {
|
|
25582
|
-
childDirectories: (parentPath, limit) => (0,
|
|
26067
|
+
childDirectories: (parentPath, limit) => (0, import_node_fs11.readdirSync)(parentPath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).slice(0, limit).map((entry) => (0, import_node_path9.join)(parentPath, entry.name)),
|
|
25583
26068
|
gitRemoteUrl: (candidatePath) => {
|
|
25584
|
-
const result = (0,
|
|
26069
|
+
const result = (0, import_node_child_process4.spawnSync)("git", ["-C", candidatePath, "config", "--get", "remote.origin.url"], {
|
|
25585
26070
|
encoding: "utf8",
|
|
25586
26071
|
env: getDaemonCliEnvironment(),
|
|
25587
26072
|
timeout: 2e3
|
|
@@ -25610,7 +26095,7 @@ function workspaceMatchesExpectedRepositories(input) {
|
|
|
25610
26095
|
input.expectedRepoUrls.map(normalizeRepositoryIdentity).filter((identity2) => Boolean(identity2))
|
|
25611
26096
|
);
|
|
25612
26097
|
if (identities.size === 0) return false;
|
|
25613
|
-
const remote = (input.probe ?? DEFAULT_PROBE).gitRemoteUrl((0,
|
|
26098
|
+
const remote = (input.probe ?? DEFAULT_PROBE).gitRemoteUrl((0, import_node_path9.resolve)(input.workspacePath));
|
|
25614
26099
|
const identity = remote ? normalizeRepositoryIdentity(remote) : null;
|
|
25615
26100
|
return Boolean(identity && identities.has(identity));
|
|
25616
26101
|
}
|
|
@@ -25620,8 +26105,8 @@ function discoverRelocatedWorkspace(input) {
|
|
|
25620
26105
|
);
|
|
25621
26106
|
if (identities.size === 0) return null;
|
|
25622
26107
|
const searchRoots = [
|
|
25623
|
-
(0,
|
|
25624
|
-
...(input.approvedWorkspacePaths ?? []).map((path) => (0,
|
|
26108
|
+
(0, import_node_path9.dirname)((0, import_node_path9.resolve)(input.missingPath)),
|
|
26109
|
+
...(input.approvedWorkspacePaths ?? []).map((path) => (0, import_node_path9.dirname)((0, import_node_path9.resolve)(path)))
|
|
25625
26110
|
].filter((path, index, paths) => paths.indexOf(path) === index);
|
|
25626
26111
|
const candidates = [];
|
|
25627
26112
|
for (const root of searchRoots) {
|
|
@@ -25633,19 +26118,19 @@ function discoverRelocatedWorkspace(input) {
|
|
|
25633
26118
|
}
|
|
25634
26119
|
}
|
|
25635
26120
|
const matches = [];
|
|
25636
|
-
for (const candidate of new Set(candidates.map((path) => (0,
|
|
26121
|
+
for (const candidate of new Set(candidates.map((path) => (0, import_node_path9.resolve)(path)))) {
|
|
25637
26122
|
const remote = (input.probe ?? DEFAULT_PROBE).gitRemoteUrl(candidate);
|
|
25638
26123
|
const identity = remote ? normalizeRepositoryIdentity(remote) : null;
|
|
25639
|
-
if (identity && identities.has(identity)) matches.push((0,
|
|
26124
|
+
if (identity && identities.has(identity)) matches.push((0, import_node_path9.resolve)(candidate));
|
|
25640
26125
|
if (matches.length > 1) return null;
|
|
25641
26126
|
}
|
|
25642
26127
|
return matches[0] ?? null;
|
|
25643
26128
|
}
|
|
25644
26129
|
|
|
25645
26130
|
// src/workspace-run-lease.ts
|
|
25646
|
-
var
|
|
25647
|
-
var
|
|
25648
|
-
var
|
|
26131
|
+
var import_node_child_process5 = require("child_process");
|
|
26132
|
+
var import_node_fs12 = require("fs");
|
|
26133
|
+
var import_node_path10 = require("path");
|
|
25649
26134
|
var WORKSPACE_LEASE_CHECK_INTERVAL_MS = 1e3;
|
|
25650
26135
|
function parsePositiveMs(value2, fallback) {
|
|
25651
26136
|
const parsed = value2 ? Number(value2) : Number.NaN;
|
|
@@ -25656,7 +26141,7 @@ var WORKSPACE_LEASE_GIT_TIMEOUT_MS = parsePositiveMs(
|
|
|
25656
26141
|
2e3
|
|
25657
26142
|
);
|
|
25658
26143
|
function gitValue(cwd, args) {
|
|
25659
|
-
const result = (0,
|
|
26144
|
+
const result = (0, import_node_child_process5.spawnSync)("git", ["-C", cwd, ...args], {
|
|
25660
26145
|
encoding: "utf8",
|
|
25661
26146
|
env: getDaemonCliEnvironment(),
|
|
25662
26147
|
timeout: WORKSPACE_LEASE_GIT_TIMEOUT_MS
|
|
@@ -25665,17 +26150,17 @@ function gitValue(cwd, args) {
|
|
|
25665
26150
|
return result.stdout.trim() || null;
|
|
25666
26151
|
}
|
|
25667
26152
|
function filesystemIdentity(path) {
|
|
25668
|
-
const canonicalPath =
|
|
25669
|
-
const stat = (0,
|
|
26153
|
+
const canonicalPath = import_node_fs12.realpathSync.native(path);
|
|
26154
|
+
const stat = (0, import_node_fs12.statSync)(canonicalPath);
|
|
25670
26155
|
return `${canonicalPath}:${stat.dev}:${stat.ino}`;
|
|
25671
26156
|
}
|
|
25672
26157
|
function resolveGitPath(workspacePath, value2) {
|
|
25673
|
-
return (0,
|
|
26158
|
+
return (0, import_node_path10.isAbsolute)(value2) ? value2 : (0, import_node_path10.resolve)(workspacePath, value2);
|
|
25674
26159
|
}
|
|
25675
26160
|
var DEFAULT_PROBE2 = {
|
|
25676
26161
|
snapshot: (workspacePath) => {
|
|
25677
26162
|
try {
|
|
25678
|
-
const canonicalWorkspacePath =
|
|
26163
|
+
const canonicalWorkspacePath = import_node_fs12.realpathSync.native((0, import_node_path10.resolve)(workspacePath));
|
|
25679
26164
|
const repositoryRoot = gitValue(canonicalWorkspacePath, ["rev-parse", "--show-toplevel"]);
|
|
25680
26165
|
const gitDirectory = gitValue(canonicalWorkspacePath, ["rev-parse", "--git-dir"]);
|
|
25681
26166
|
const commonDirectory = gitValue(canonicalWorkspacePath, ["rev-parse", "--git-common-dir"]);
|
|
@@ -25684,7 +26169,7 @@ var DEFAULT_PROBE2 = {
|
|
|
25684
26169
|
const remote = gitValue(canonicalWorkspacePath, ["config", "--get", "remote.origin.url"]);
|
|
25685
26170
|
const remoteIdentity = remote ? normalizeRepositoryIdentity(remote) : null;
|
|
25686
26171
|
return {
|
|
25687
|
-
workspacePath: (0,
|
|
26172
|
+
workspacePath: (0, import_node_path10.resolve)(workspacePath),
|
|
25688
26173
|
workspaceIdentity: filesystemIdentity(canonicalWorkspacePath),
|
|
25689
26174
|
repositoryIdentity: `${filesystemIdentity(
|
|
25690
26175
|
resolveGitPath(canonicalWorkspacePath, commonDirectory)
|
|
@@ -25698,7 +26183,7 @@ var DEFAULT_PROBE2 = {
|
|
|
25698
26183
|
},
|
|
25699
26184
|
pathExists: (workspacePath) => {
|
|
25700
26185
|
try {
|
|
25701
|
-
return (0,
|
|
26186
|
+
return (0, import_node_fs12.existsSync)((0, import_node_path10.resolve)(workspacePath));
|
|
25702
26187
|
} catch {
|
|
25703
26188
|
return true;
|
|
25704
26189
|
}
|
|
@@ -25729,7 +26214,7 @@ var WorkspaceRunLease = class _WorkspaceRunLease {
|
|
|
25729
26214
|
static capture(targets, probe = DEFAULT_PROBE2) {
|
|
25730
26215
|
const captured = [];
|
|
25731
26216
|
for (const target of targets) {
|
|
25732
|
-
const normalizedTarget = { ...target, workspacePath: (0,
|
|
26217
|
+
const normalizedTarget = { ...target, workspacePath: (0, import_node_path10.resolve)(target.workspacePath) };
|
|
25733
26218
|
const identity = probe.snapshot(normalizedTarget.workspacePath);
|
|
25734
26219
|
if (!identity) return { lease: null, failure: unavailableFailure(normalizedTarget) };
|
|
25735
26220
|
if (normalizedTarget.expectedBranch && identity.branch !== normalizedTarget.expectedBranch) {
|
|
@@ -25882,15 +26367,15 @@ function assertValidGitRef(ref, label) {
|
|
|
25882
26367
|
if (!ref || ref.startsWith("-") || ref.includes("\0")) {
|
|
25883
26368
|
throw new Error(`${label} is not a safe git ref`);
|
|
25884
26369
|
}
|
|
25885
|
-
const result = (0,
|
|
26370
|
+
const result = (0, import_node_child_process6.spawnSync)("git", ["check-ref-format", "--branch", ref], {
|
|
25886
26371
|
env: getDaemonCliEnvironment(),
|
|
25887
26372
|
encoding: "utf8"
|
|
25888
26373
|
});
|
|
25889
26374
|
if (result.status !== 0) throw new Error(`${label} is not a valid git ref`);
|
|
25890
26375
|
}
|
|
25891
26376
|
function isPathContained(childPath, parentPath) {
|
|
25892
|
-
const rel = (0,
|
|
25893
|
-
return rel === "" || !(0,
|
|
26377
|
+
const rel = (0, import_node_path11.relative)((0, import_node_path11.resolve)(parentPath), (0, import_node_path11.resolve)(childPath));
|
|
26378
|
+
return rel === "" || !(0, import_node_path11.isAbsolute)(rel) && rel !== ".." && !rel.startsWith(`..${import_node_path11.sep}`);
|
|
25894
26379
|
}
|
|
25895
26380
|
function assertPathContained(childPath, parentPath, label) {
|
|
25896
26381
|
if (!isPathContained(childPath, parentPath)) {
|
|
@@ -25898,7 +26383,7 @@ function assertPathContained(childPath, parentPath, label) {
|
|
|
25898
26383
|
}
|
|
25899
26384
|
}
|
|
25900
26385
|
function git(cwd, args) {
|
|
25901
|
-
const result = (0,
|
|
26386
|
+
const result = (0, import_node_child_process6.spawnSync)("git", args, {
|
|
25902
26387
|
cwd,
|
|
25903
26388
|
env: getDaemonCliEnvironment(),
|
|
25904
26389
|
encoding: "utf8",
|
|
@@ -25917,14 +26402,14 @@ function gitSafe(cwd, args) {
|
|
|
25917
26402
|
}
|
|
25918
26403
|
}
|
|
25919
26404
|
function worktreeDir(projectPath) {
|
|
25920
|
-
const resolved = (0,
|
|
25921
|
-
return (0,
|
|
26405
|
+
const resolved = (0, import_node_path11.resolve)(projectPath);
|
|
26406
|
+
return (0, import_node_path11.join)((0, import_node_path11.dirname)(resolved), `${(0, import_node_path11.basename)(resolved)}-alan-worktrees`);
|
|
25922
26407
|
}
|
|
25923
26408
|
function pathSegment(value2) {
|
|
25924
26409
|
return value2.toLowerCase().replace(/^alan\//, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "task";
|
|
25925
26410
|
}
|
|
25926
26411
|
function repoName(repoUrl, localPath) {
|
|
25927
|
-
return repoUrl.replace(/\.git$/, "").split("/").pop() || (0,
|
|
26412
|
+
return repoUrl.replace(/\.git$/, "").split("/").pop() || (0, import_node_path11.basename)(localPath) || "repo";
|
|
25928
26413
|
}
|
|
25929
26414
|
function findWorktreeByBranch(repoPath, branchName) {
|
|
25930
26415
|
const output = gitSafe(repoPath, ["worktree", "list", "--porcelain"]);
|
|
@@ -25940,21 +26425,21 @@ function findWorktreeByBranch(repoPath, branchName) {
|
|
|
25940
26425
|
function ensureGitWorktree(input) {
|
|
25941
26426
|
assertValidGitRef(input.branchName, "branchName");
|
|
25942
26427
|
assertValidGitRef(input.baseBranch, "baseBranch");
|
|
25943
|
-
const repoPath = (0,
|
|
26428
|
+
const repoPath = (0, import_node_path11.resolve)(input.repoPath);
|
|
25944
26429
|
const root = input.allowedRoot ?? worktreeDir(repoPath);
|
|
25945
26430
|
const existingPath = findWorktreeByBranch(input.repoPath, input.branchName);
|
|
25946
26431
|
if (existingPath) {
|
|
25947
|
-
if ((0,
|
|
26432
|
+
if ((0, import_node_path11.resolve)(existingPath) === repoPath) {
|
|
25948
26433
|
throw new Error(`${input.branchName} is checked out in the shared checkout`);
|
|
25949
26434
|
}
|
|
25950
26435
|
return existingPath;
|
|
25951
26436
|
}
|
|
25952
26437
|
assertPathContained(input.worktreePath, root, "worktreePath");
|
|
25953
|
-
(0,
|
|
26438
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(input.worktreePath), { recursive: true });
|
|
25954
26439
|
if (!gitSafe(input.repoPath, ["branch", "--list", input.branchName])) {
|
|
25955
26440
|
git(input.repoPath, ["branch", input.branchName, input.baseBranch]);
|
|
25956
26441
|
}
|
|
25957
|
-
if ((0,
|
|
26442
|
+
if ((0, import_node_fs13.existsSync)(input.worktreePath)) {
|
|
25958
26443
|
if (gitSafe(input.worktreePath, ["branch", "--show-current"]) === input.branchName) {
|
|
25959
26444
|
return input.worktreePath;
|
|
25960
26445
|
}
|
|
@@ -25964,15 +26449,15 @@ function ensureGitWorktree(input) {
|
|
|
25964
26449
|
return input.worktreePath;
|
|
25965
26450
|
}
|
|
25966
26451
|
function resolveProjectWorktreePaths(projectPath, gitRoot, gitWorktreePath) {
|
|
25967
|
-
const resolvedProjectPath = (0,
|
|
25968
|
-
const resolvedGitRoot = (0,
|
|
25969
|
-
const projectRelativePath = (0,
|
|
25970
|
-
if (projectRelativePath === ".." || projectRelativePath.startsWith(`..${
|
|
26452
|
+
const resolvedProjectPath = (0, import_node_path11.resolve)(projectPath);
|
|
26453
|
+
const resolvedGitRoot = (0, import_node_path11.resolve)(gitRoot);
|
|
26454
|
+
const projectRelativePath = (0, import_node_path11.relative)(resolvedGitRoot, resolvedProjectPath);
|
|
26455
|
+
if (projectRelativePath === ".." || projectRelativePath.startsWith(`..${import_node_path11.sep}`) || (0, import_node_path11.isAbsolute)(projectRelativePath)) {
|
|
25971
26456
|
throw new Error("The selected Project folder is outside its Git repository");
|
|
25972
26457
|
}
|
|
25973
26458
|
return {
|
|
25974
26459
|
repoPath: resolvedGitRoot,
|
|
25975
|
-
projectPath: projectRelativePath ? (0,
|
|
26460
|
+
projectPath: projectRelativePath ? (0, import_node_path11.join)((0, import_node_path11.resolve)(gitWorktreePath), projectRelativePath) : (0, import_node_path11.resolve)(gitWorktreePath)
|
|
25976
26461
|
};
|
|
25977
26462
|
}
|
|
25978
26463
|
function ensureWorktree(params) {
|
|
@@ -25984,7 +26469,7 @@ function ensureWorktree(params) {
|
|
|
25984
26469
|
repoLocalPaths: Array.isArray(params.repoLocalPaths) ? params.repoLocalPaths : []
|
|
25985
26470
|
};
|
|
25986
26471
|
if (input.repoLocalPaths?.length) {
|
|
25987
|
-
const taskRoot2 = (0,
|
|
26472
|
+
const taskRoot2 = (0, import_node_path11.join)(
|
|
25988
26473
|
worktreeDir(input.projectPath),
|
|
25989
26474
|
`${pathSegment(input.branchName)}-${input.taskId.slice(0, 8)}`
|
|
25990
26475
|
);
|
|
@@ -25993,7 +26478,7 @@ function ensureWorktree(params) {
|
|
|
25993
26478
|
const baseBranch2 = repo.branch || input.baseBranch || "main";
|
|
25994
26479
|
const worktreePath2 = ensureGitWorktree({
|
|
25995
26480
|
repoPath: repo.localPath,
|
|
25996
|
-
worktreePath: (0,
|
|
26481
|
+
worktreePath: (0, import_node_path11.join)(taskRoot2, pathSegment(repoName(repo.repoUrl, repo.localPath))),
|
|
25997
26482
|
branchName: input.branchName,
|
|
25998
26483
|
baseBranch: baseBranch2,
|
|
25999
26484
|
allowedRoot: worktreeDir(input.projectPath)
|
|
@@ -26008,13 +26493,13 @@ function ensureWorktree(params) {
|
|
|
26008
26493
|
})
|
|
26009
26494
|
};
|
|
26010
26495
|
}
|
|
26011
|
-
const gitRoot = gitSafe((0,
|
|
26496
|
+
const gitRoot = gitSafe((0, import_node_path11.resolve)(input.projectPath), ["rev-parse", "--show-toplevel"]);
|
|
26012
26497
|
if (!gitRoot) {
|
|
26013
26498
|
throw new Error("The selected Project folder is not inside a Git repository");
|
|
26014
26499
|
}
|
|
26015
|
-
const repoPath = (0,
|
|
26500
|
+
const repoPath = (0, import_node_path11.resolve)(gitRoot);
|
|
26016
26501
|
const baseBranch = input.baseBranch || gitSafe(repoPath, ["branch", "--show-current"]) || "HEAD";
|
|
26017
|
-
const taskRoot = (0,
|
|
26502
|
+
const taskRoot = (0, import_node_path11.join)(
|
|
26018
26503
|
worktreeDir(repoPath),
|
|
26019
26504
|
`${pathSegment(input.branchName)}-${input.taskId.slice(0, 8)}`
|
|
26020
26505
|
);
|
|
@@ -26043,7 +26528,7 @@ function ensureWorktree(params) {
|
|
|
26043
26528
|
function ensureSharedCheckoutBranch(input) {
|
|
26044
26529
|
assertValidGitRef(input.branchName, "branchName");
|
|
26045
26530
|
assertValidGitRef(input.baseBranch, "baseBranch");
|
|
26046
|
-
const repoPath = (0,
|
|
26531
|
+
const repoPath = (0, import_node_path11.resolve)(input.repoPath);
|
|
26047
26532
|
if (gitSafe(repoPath, ["rev-parse", "--is-inside-work-tree"]) !== "true") {
|
|
26048
26533
|
return { checkedOut: false, reason: `${repoPath} is not a git work tree` };
|
|
26049
26534
|
}
|
|
@@ -26088,7 +26573,7 @@ function resolveSharedCheckoutTargets(input) {
|
|
|
26088
26573
|
}
|
|
26089
26574
|
function resolveRuntimeCwd(payload) {
|
|
26090
26575
|
const multiRepoWorktree = payload.worktreeInfo?.allWorktrees?.[0]?.worktreePath;
|
|
26091
|
-
if (multiRepoWorktree) return (0,
|
|
26576
|
+
if (multiRepoWorktree) return (0, import_node_path11.dirname)(multiRepoWorktree);
|
|
26092
26577
|
if (isAlanDefaultWorkspace(payload.projectPath)) return resolveAlanDefaultWorkspacePath();
|
|
26093
26578
|
return payload.worktreeInfo?.worktreePath ?? payload.projectPath ?? process.cwd();
|
|
26094
26579
|
}
|
|
@@ -26310,12 +26795,12 @@ function getConfigPath() {
|
|
|
26310
26795
|
return process.env.ALAN_AGENT_CONFIG_PATH ?? boundAgentConfigPath ?? resolveAgentConfigPath({ profile: "production" });
|
|
26311
26796
|
}
|
|
26312
26797
|
function getEndpointDefaultsPath() {
|
|
26313
|
-
return process.env.ALAN_AGENT_ENDPOINTS_PATH ?? (0,
|
|
26798
|
+
return process.env.ALAN_AGENT_ENDPOINTS_PATH ?? (0, import_node_path11.join)((0, import_node_path11.dirname)(getConfigPath()), "endpoints.json");
|
|
26314
26799
|
}
|
|
26315
26800
|
function readConfig() {
|
|
26316
26801
|
const configPath = getConfigPath();
|
|
26317
|
-
if (!(0,
|
|
26318
|
-
const parsed = JSON.parse((0,
|
|
26802
|
+
if (!(0, import_node_fs13.existsSync)(configPath)) return {};
|
|
26803
|
+
const parsed = JSON.parse((0, import_node_fs13.readFileSync)(configPath, "utf8"));
|
|
26319
26804
|
const sanitized = sanitizeAgentConfig(parsed);
|
|
26320
26805
|
if (Object.keys(parsed).some((key) => !Object.hasOwn(sanitized, key))) {
|
|
26321
26806
|
writeConfig(sanitized);
|
|
@@ -26331,27 +26816,27 @@ function readConfigForRegistration() {
|
|
|
26331
26816
|
}
|
|
26332
26817
|
function readEndpointDefaults() {
|
|
26333
26818
|
const endpointsPath = getEndpointDefaultsPath();
|
|
26334
|
-
if (!(0,
|
|
26819
|
+
if (!(0, import_node_fs13.existsSync)(endpointsPath)) return {};
|
|
26335
26820
|
try {
|
|
26336
|
-
return JSON.parse((0,
|
|
26821
|
+
return JSON.parse((0, import_node_fs13.readFileSync)(endpointsPath, "utf8"));
|
|
26337
26822
|
} catch {
|
|
26338
26823
|
return {};
|
|
26339
26824
|
}
|
|
26340
26825
|
}
|
|
26341
26826
|
function writeConfig(config) {
|
|
26342
26827
|
const configPath = getConfigPath();
|
|
26343
|
-
(0,
|
|
26828
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(configPath), { recursive: true, mode: 448 });
|
|
26344
26829
|
const pendingPath = `${configPath}.pending-${process.pid}-${(0, import_node_crypto3.randomBytes)(6).toString("hex")}`;
|
|
26345
26830
|
try {
|
|
26346
|
-
(0,
|
|
26831
|
+
(0, import_node_fs13.writeFileSync)(
|
|
26347
26832
|
pendingPath,
|
|
26348
26833
|
JSON.stringify(sanitizeAgentConfig(config), null, 2),
|
|
26349
26834
|
{ mode: 384 }
|
|
26350
26835
|
);
|
|
26351
|
-
(0,
|
|
26352
|
-
(0,
|
|
26836
|
+
(0, import_node_fs13.chmodSync)(pendingPath, 384);
|
|
26837
|
+
(0, import_node_fs13.renameSync)(pendingPath, configPath);
|
|
26353
26838
|
} finally {
|
|
26354
|
-
(0,
|
|
26839
|
+
(0, import_node_fs13.rmSync)(pendingPath, { force: true });
|
|
26355
26840
|
}
|
|
26356
26841
|
}
|
|
26357
26842
|
function maintenanceLeasePath(configPath) {
|
|
@@ -26359,9 +26844,9 @@ function maintenanceLeasePath(configPath) {
|
|
|
26359
26844
|
}
|
|
26360
26845
|
function readLocalDaemonMaintenanceLease(configPath, nowMs = Date.now()) {
|
|
26361
26846
|
const path = maintenanceLeasePath(configPath);
|
|
26362
|
-
if (!(0,
|
|
26847
|
+
if (!(0, import_node_fs13.existsSync)(path)) return null;
|
|
26363
26848
|
try {
|
|
26364
|
-
const lease = JSON.parse((0,
|
|
26849
|
+
const lease = JSON.parse((0, import_node_fs13.readFileSync)(path, "utf8"));
|
|
26365
26850
|
if (lease.version !== 1 || typeof lease.id !== "string" || lease.reason !== "credential_cleanup" && lease.reason !== "daemon_startup" && lease.reason !== "watchdog" || !(lease.reason === "credential_cleanup" && lease.expiresAtMs === null || typeof lease.expiresAtMs === "number" && Number.isFinite(lease.expiresAtMs))) {
|
|
26366
26851
|
throw new Error("invalid maintenance lease");
|
|
26367
26852
|
}
|
|
@@ -26378,8 +26863,8 @@ function readLocalDaemonMaintenanceLease(configPath, nowMs = Date.now()) {
|
|
|
26378
26863
|
expiresAtMs: nowMs + 5e3
|
|
26379
26864
|
};
|
|
26380
26865
|
try {
|
|
26381
|
-
(0,
|
|
26382
|
-
(0,
|
|
26866
|
+
(0, import_node_fs13.writeFileSync)(path, JSON.stringify(fallback), { mode: 384 });
|
|
26867
|
+
(0, import_node_fs13.chmodSync)(path, 384);
|
|
26383
26868
|
} catch {
|
|
26384
26869
|
}
|
|
26385
26870
|
return fallback;
|
|
@@ -26395,10 +26880,10 @@ function acquireLocalDaemonMaintenanceLease(configPath, reason, ttlMs = 5e3) {
|
|
|
26395
26880
|
expiresAtMs: reason === "credential_cleanup" ? null : Date.now() + Math.max(1e3, Math.min(ttlMs, 6e4))
|
|
26396
26881
|
};
|
|
26397
26882
|
const path = maintenanceLeasePath(configPath);
|
|
26398
|
-
(0,
|
|
26883
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(path), { recursive: true, mode: 448 });
|
|
26399
26884
|
try {
|
|
26400
|
-
(0,
|
|
26401
|
-
(0,
|
|
26885
|
+
(0, import_node_fs13.writeFileSync)(path, JSON.stringify(lease), { mode: 384, flag: "wx" });
|
|
26886
|
+
(0, import_node_fs13.chmodSync)(path, 384);
|
|
26402
26887
|
return { acquired: true, lease };
|
|
26403
26888
|
} catch (error) {
|
|
26404
26889
|
const raced = readLocalDaemonMaintenanceLease(configPath);
|
|
@@ -26414,9 +26899,9 @@ function daemonOwnerLeasePath(configPath) {
|
|
|
26414
26899
|
}
|
|
26415
26900
|
function readLocalDaemonOwnerLease(configPath) {
|
|
26416
26901
|
const path = daemonOwnerLeasePath(configPath);
|
|
26417
|
-
if (!(0,
|
|
26902
|
+
if (!(0, import_node_fs13.existsSync)(path)) return null;
|
|
26418
26903
|
try {
|
|
26419
|
-
const lease = JSON.parse((0,
|
|
26904
|
+
const lease = JSON.parse((0, import_node_fs13.readFileSync)(path, "utf8"));
|
|
26420
26905
|
if (lease.version !== 1 || typeof lease.id !== "string" || typeof lease.daemonSessionId !== "string" || !Number.isSafeInteger(lease.pid) || lease.pid <= 0 || typeof lease.startedAtMs !== "number" || !Number.isFinite(lease.startedAtMs) || typeof lease.runtimeId !== "string" || typeof lease.localServiceId !== "string" || !Number.isSafeInteger(lease.localApiPort) || lease.localApiPort < 0 || lease.localApiPort > 65535 || typeof lease.localApiToken !== "string" || lease.localApiToken.length === 0) {
|
|
26421
26906
|
throw new Error("invalid daemon owner lease");
|
|
26422
26907
|
}
|
|
@@ -26468,10 +26953,10 @@ async function acquireLocalDaemonOwnerLease(input) {
|
|
|
26468
26953
|
localApiToken: input.localApiToken
|
|
26469
26954
|
};
|
|
26470
26955
|
const path = daemonOwnerLeasePath(input.configPath);
|
|
26471
|
-
(0,
|
|
26956
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(path), { recursive: true, mode: 448 });
|
|
26472
26957
|
try {
|
|
26473
|
-
(0,
|
|
26474
|
-
(0,
|
|
26958
|
+
(0, import_node_fs13.writeFileSync)(path, JSON.stringify(lease), { mode: 384, flag: "wx" });
|
|
26959
|
+
(0, import_node_fs13.chmodSync)(path, 384);
|
|
26475
26960
|
return { acquired: true, lease };
|
|
26476
26961
|
} catch (error) {
|
|
26477
26962
|
const raced = readLocalDaemonOwnerLease(input.configPath);
|
|
@@ -26486,12 +26971,12 @@ function updateLocalDaemonOwnerEndpoint(configPath, lease, localApiPort) {
|
|
|
26486
26971
|
const path = daemonOwnerLeasePath(configPath);
|
|
26487
26972
|
const pendingPath = `${path}.pending-${lease.id}`;
|
|
26488
26973
|
try {
|
|
26489
|
-
(0,
|
|
26490
|
-
(0,
|
|
26491
|
-
(0,
|
|
26974
|
+
(0, import_node_fs13.writeFileSync)(pendingPath, JSON.stringify(updated), { mode: 384 });
|
|
26975
|
+
(0, import_node_fs13.chmodSync)(pendingPath, 384);
|
|
26976
|
+
(0, import_node_fs13.renameSync)(pendingPath, path);
|
|
26492
26977
|
return updated;
|
|
26493
26978
|
} finally {
|
|
26494
|
-
(0,
|
|
26979
|
+
(0, import_node_fs13.rmSync)(pendingPath, { force: true });
|
|
26495
26980
|
}
|
|
26496
26981
|
}
|
|
26497
26982
|
function releaseLocalDaemonOwnerLease(configPath, leaseId) {
|
|
@@ -26500,13 +26985,13 @@ function releaseLocalDaemonOwnerLease(configPath, leaseId) {
|
|
|
26500
26985
|
function releaseOwnedJsonFile(path, ownerId, ownerField = "id") {
|
|
26501
26986
|
const releasePath = `${path}.release-${process.pid}-${(0, import_node_crypto3.randomBytes)(6).toString("hex")}`;
|
|
26502
26987
|
try {
|
|
26503
|
-
(0,
|
|
26988
|
+
(0, import_node_fs13.renameSync)(path, releasePath);
|
|
26504
26989
|
} catch (error) {
|
|
26505
26990
|
if (error.code === "ENOENT") return;
|
|
26506
26991
|
throw error;
|
|
26507
26992
|
}
|
|
26508
26993
|
try {
|
|
26509
|
-
const content = (0,
|
|
26994
|
+
const content = (0, import_node_fs13.readFileSync)(releasePath, "utf8");
|
|
26510
26995
|
let capturedOwnerId = null;
|
|
26511
26996
|
try {
|
|
26512
26997
|
const captured = JSON.parse(content);
|
|
@@ -26515,13 +27000,13 @@ function releaseOwnedJsonFile(path, ownerId, ownerField = "id") {
|
|
|
26515
27000
|
}
|
|
26516
27001
|
if (capturedOwnerId === ownerId) return;
|
|
26517
27002
|
try {
|
|
26518
|
-
(0,
|
|
26519
|
-
(0,
|
|
27003
|
+
(0, import_node_fs13.writeFileSync)(path, content, { mode: 384, flag: "wx" });
|
|
27004
|
+
(0, import_node_fs13.chmodSync)(path, 384);
|
|
26520
27005
|
} catch (error) {
|
|
26521
27006
|
if (error.code !== "EEXIST") throw error;
|
|
26522
27007
|
}
|
|
26523
27008
|
} finally {
|
|
26524
|
-
(0,
|
|
27009
|
+
(0, import_node_fs13.rmSync)(releasePath, { force: true });
|
|
26525
27010
|
}
|
|
26526
27011
|
}
|
|
26527
27012
|
function inspectLocalDaemonRunJournal(configPath) {
|
|
@@ -26531,8 +27016,8 @@ function inspectLocalDaemonRunJournal(configPath) {
|
|
|
26531
27016
|
try {
|
|
26532
27017
|
let activeRunCount = 0;
|
|
26533
27018
|
for (const artifact of [path, pendingPath]) {
|
|
26534
|
-
if (!(0,
|
|
26535
|
-
const parsed = JSON.parse((0,
|
|
27019
|
+
if (!(0, import_node_fs13.existsSync)(artifact)) continue;
|
|
27020
|
+
const parsed = JSON.parse((0, import_node_fs13.readFileSync)(artifact, "utf8"));
|
|
26536
27021
|
if (parsed.version !== 1 || !Array.isArray(parsed.entries))
|
|
26537
27022
|
throw new Error("invalid journal");
|
|
26538
27023
|
if (artifact === path) {
|
|
@@ -26551,7 +27036,7 @@ function inspectLocalDaemonRunJournal(configPath) {
|
|
|
26551
27036
|
}).length;
|
|
26552
27037
|
continue;
|
|
26553
27038
|
}
|
|
26554
|
-
const legacyStartedAtMs = (0,
|
|
27039
|
+
const legacyStartedAtMs = (0, import_node_fs13.statSync)(pendingPath).mtimeMs;
|
|
26555
27040
|
activeRunCount += parsed.entries.filter((entry) => {
|
|
26556
27041
|
if (!entry || typeof entry !== "object") throw new Error("invalid pending run entry");
|
|
26557
27042
|
const startedAtMs = entry.startedAtMs;
|
|
@@ -26578,9 +27063,9 @@ function setupTokenHash(setupToken) {
|
|
|
26578
27063
|
function getOrCreateSetupAttemptId(setupToken) {
|
|
26579
27064
|
const intentPath = pendingSetupIntentPath();
|
|
26580
27065
|
const tokenHash = setupTokenHash(setupToken);
|
|
26581
|
-
if ((0,
|
|
27066
|
+
if ((0, import_node_fs13.existsSync)(intentPath)) {
|
|
26582
27067
|
try {
|
|
26583
|
-
const stored = JSON.parse((0,
|
|
27068
|
+
const stored = JSON.parse((0, import_node_fs13.readFileSync)(intentPath, "utf8"));
|
|
26584
27069
|
if (stored.setupTokenHash === tokenHash && typeof stored.registrationAttemptId === "string" && stored.registrationAttemptId.length > 0) {
|
|
26585
27070
|
return stored.registrationAttemptId;
|
|
26586
27071
|
}
|
|
@@ -26588,23 +27073,23 @@ function getOrCreateSetupAttemptId(setupToken) {
|
|
|
26588
27073
|
}
|
|
26589
27074
|
}
|
|
26590
27075
|
const registrationAttemptId = (0, import_node_crypto3.randomUUID)();
|
|
26591
|
-
(0,
|
|
27076
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(intentPath), { recursive: true, mode: 448 });
|
|
26592
27077
|
const writePath = `${intentPath}.pending-${process.pid}-${(0, import_node_crypto3.randomBytes)(6).toString("hex")}`;
|
|
26593
27078
|
try {
|
|
26594
|
-
(0,
|
|
27079
|
+
(0, import_node_fs13.writeFileSync)(
|
|
26595
27080
|
writePath,
|
|
26596
27081
|
JSON.stringify({ setupTokenHash: tokenHash, registrationAttemptId }, null, 2),
|
|
26597
27082
|
{ mode: 384 }
|
|
26598
27083
|
);
|
|
26599
|
-
(0,
|
|
26600
|
-
(0,
|
|
27084
|
+
(0, import_node_fs13.chmodSync)(writePath, 384);
|
|
27085
|
+
(0, import_node_fs13.renameSync)(writePath, intentPath);
|
|
26601
27086
|
} finally {
|
|
26602
|
-
(0,
|
|
27087
|
+
(0, import_node_fs13.rmSync)(writePath, { force: true });
|
|
26603
27088
|
}
|
|
26604
27089
|
return registrationAttemptId;
|
|
26605
27090
|
}
|
|
26606
27091
|
function clearPendingSetupIntent() {
|
|
26607
|
-
(0,
|
|
27092
|
+
(0, import_node_fs13.rmSync)(pendingSetupIntentPath(), { force: true });
|
|
26608
27093
|
}
|
|
26609
27094
|
function pendingDeviceAuthorizationPath() {
|
|
26610
27095
|
return `${getConfigPath()}.device-auth-pending`;
|
|
@@ -26625,8 +27110,8 @@ function parseDeviceAuthorizationOperationContent(content) {
|
|
|
26625
27110
|
}
|
|
26626
27111
|
function restoreCapturedFileUnlessReplaced(path, content) {
|
|
26627
27112
|
try {
|
|
26628
|
-
(0,
|
|
26629
|
-
(0,
|
|
27113
|
+
(0, import_node_fs13.writeFileSync)(path, content, { mode: 384, flag: "wx" });
|
|
27114
|
+
(0, import_node_fs13.chmodSync)(path, 384);
|
|
26630
27115
|
} catch (error) {
|
|
26631
27116
|
if (error.code !== "EEXIST") throw error;
|
|
26632
27117
|
}
|
|
@@ -26634,26 +27119,26 @@ function restoreCapturedFileUnlessReplaced(path, content) {
|
|
|
26634
27119
|
function quarantineCorruptDeviceAuthorizationOperation(path) {
|
|
26635
27120
|
const quarantinePath = `${path}.corrupt-${process.pid}-${(0, import_node_crypto3.randomBytes)(6).toString("hex")}`;
|
|
26636
27121
|
try {
|
|
26637
|
-
(0,
|
|
27122
|
+
(0, import_node_fs13.renameSync)(path, quarantinePath);
|
|
26638
27123
|
} catch (error) {
|
|
26639
27124
|
if (error.code === "ENOENT") return null;
|
|
26640
27125
|
throw error;
|
|
26641
27126
|
}
|
|
26642
27127
|
try {
|
|
26643
|
-
const capturedContent = (0,
|
|
27128
|
+
const capturedContent = (0, import_node_fs13.readFileSync)(quarantinePath, "utf8");
|
|
26644
27129
|
if (parseDeviceAuthorizationOperationContent(capturedContent)) {
|
|
26645
27130
|
restoreCapturedFileUnlessReplaced(path, capturedContent);
|
|
26646
27131
|
}
|
|
26647
27132
|
} finally {
|
|
26648
|
-
(0,
|
|
27133
|
+
(0, import_node_fs13.rmSync)(quarantinePath, { force: true });
|
|
26649
27134
|
}
|
|
26650
|
-
if (!(0,
|
|
26651
|
-
return parseDeviceAuthorizationOperationContent((0,
|
|
27135
|
+
if (!(0, import_node_fs13.existsSync)(path)) return null;
|
|
27136
|
+
return parseDeviceAuthorizationOperationContent((0, import_node_fs13.readFileSync)(path, "utf8"));
|
|
26652
27137
|
}
|
|
26653
27138
|
function readDeviceAuthorizationOperation() {
|
|
26654
27139
|
const path = deviceAuthorizationOperationPath();
|
|
26655
|
-
if (!(0,
|
|
26656
|
-
const parsed = parseDeviceAuthorizationOperationContent((0,
|
|
27140
|
+
if (!(0, import_node_fs13.existsSync)(path)) return null;
|
|
27141
|
+
const parsed = parseDeviceAuthorizationOperationContent((0, import_node_fs13.readFileSync)(path, "utf8"));
|
|
26657
27142
|
const lease = parsed ?? quarantineCorruptDeviceAuthorizationOperation(path);
|
|
26658
27143
|
if (!lease) return null;
|
|
26659
27144
|
if (lease.expiresAtMs <= Date.now()) {
|
|
@@ -26671,10 +27156,10 @@ function acquireDeviceAuthorizationOperation() {
|
|
|
26671
27156
|
expiresAtMs: Date.now() + 6e4
|
|
26672
27157
|
};
|
|
26673
27158
|
const path = deviceAuthorizationOperationPath();
|
|
26674
|
-
(0,
|
|
27159
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(path), { recursive: true, mode: 448 });
|
|
26675
27160
|
try {
|
|
26676
|
-
(0,
|
|
26677
|
-
(0,
|
|
27161
|
+
(0, import_node_fs13.writeFileSync)(path, JSON.stringify(lease), { mode: 384, flag: "wx" });
|
|
27162
|
+
(0, import_node_fs13.chmodSync)(path, 384);
|
|
26678
27163
|
return lease;
|
|
26679
27164
|
} catch (error) {
|
|
26680
27165
|
if (error.code === "EEXIST") return null;
|
|
@@ -26689,15 +27174,15 @@ function extendDeviceAuthorizationOperation(operationId, expiresAtMs) {
|
|
|
26689
27174
|
const path = deviceAuthorizationOperationPath();
|
|
26690
27175
|
const pendingPath = `${path}.pending-${process.pid}-${(0, import_node_crypto3.randomBytes)(6).toString("hex")}`;
|
|
26691
27176
|
try {
|
|
26692
|
-
(0,
|
|
27177
|
+
(0, import_node_fs13.writeFileSync)(
|
|
26693
27178
|
pendingPath,
|
|
26694
27179
|
JSON.stringify({ ...current, expiresAtMs: Math.max(expiresAtMs, Date.now() + 6e4) }),
|
|
26695
27180
|
{ mode: 384 }
|
|
26696
27181
|
);
|
|
26697
|
-
(0,
|
|
26698
|
-
(0,
|
|
27182
|
+
(0, import_node_fs13.chmodSync)(pendingPath, 384);
|
|
27183
|
+
(0, import_node_fs13.renameSync)(pendingPath, path);
|
|
26699
27184
|
} finally {
|
|
26700
|
-
(0,
|
|
27185
|
+
(0, import_node_fs13.rmSync)(pendingPath, { force: true });
|
|
26701
27186
|
}
|
|
26702
27187
|
}
|
|
26703
27188
|
function assertDeviceAuthorizationOperationOwner(operationId) {
|
|
@@ -26708,12 +27193,12 @@ function assertDeviceAuthorizationOperationOwner(operationId) {
|
|
|
26708
27193
|
function clearPendingDeviceAuthorization(operationId) {
|
|
26709
27194
|
const path = pendingDeviceAuthorizationPath();
|
|
26710
27195
|
if (!operationId) {
|
|
26711
|
-
(0,
|
|
27196
|
+
(0, import_node_fs13.rmSync)(path, { force: true });
|
|
26712
27197
|
return;
|
|
26713
27198
|
}
|
|
26714
|
-
if (!(0,
|
|
27199
|
+
if (!(0, import_node_fs13.existsSync)(path)) return;
|
|
26715
27200
|
try {
|
|
26716
|
-
const pending = JSON.parse((0,
|
|
27201
|
+
const pending = JSON.parse((0, import_node_fs13.readFileSync)(path, "utf8"));
|
|
26717
27202
|
if (pending.operationId !== operationId) return;
|
|
26718
27203
|
} catch {
|
|
26719
27204
|
return;
|
|
@@ -26722,9 +27207,9 @@ function clearPendingDeviceAuthorization(operationId) {
|
|
|
26722
27207
|
}
|
|
26723
27208
|
function readPendingDeviceAuthorization(apiUrl) {
|
|
26724
27209
|
const path = pendingDeviceAuthorizationPath();
|
|
26725
|
-
if (!(0,
|
|
27210
|
+
if (!(0, import_node_fs13.existsSync)(path)) return null;
|
|
26726
27211
|
try {
|
|
26727
|
-
const pending = JSON.parse((0,
|
|
27212
|
+
const pending = JSON.parse((0, import_node_fs13.readFileSync)(path, "utf8"));
|
|
26728
27213
|
const expiresAtMs = Date.parse(pending.expiresAt ?? "");
|
|
26729
27214
|
if (pending.apiUrl !== apiUrl || typeof pending.deviceCode !== "string" || typeof pending.userCode !== "string" || typeof pending.verificationUri !== "string" || typeof pending.installationId !== "string" || pending.operationId !== void 0 && typeof pending.operationId !== "string" || !Number.isFinite(pending.intervalSeconds) || !Number.isFinite(expiresAtMs) || expiresAtMs <= Date.now()) {
|
|
26730
27215
|
return null;
|
|
@@ -26736,20 +27221,20 @@ function readPendingDeviceAuthorization(apiUrl) {
|
|
|
26736
27221
|
}
|
|
26737
27222
|
function writePendingDeviceAuthorization(pending) {
|
|
26738
27223
|
const path = pendingDeviceAuthorizationPath();
|
|
26739
|
-
(0,
|
|
27224
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(path), { recursive: true, mode: 448 });
|
|
26740
27225
|
const writePath = `${path}.pending-${process.pid}-${(0, import_node_crypto3.randomBytes)(6).toString("hex")}`;
|
|
26741
27226
|
try {
|
|
26742
|
-
(0,
|
|
26743
|
-
(0,
|
|
26744
|
-
(0,
|
|
27227
|
+
(0, import_node_fs13.writeFileSync)(writePath, JSON.stringify(pending, null, 2), { mode: 384 });
|
|
27228
|
+
(0, import_node_fs13.chmodSync)(writePath, 384);
|
|
27229
|
+
(0, import_node_fs13.renameSync)(writePath, path);
|
|
26745
27230
|
} finally {
|
|
26746
|
-
(0,
|
|
27231
|
+
(0, import_node_fs13.rmSync)(writePath, { force: true });
|
|
26747
27232
|
}
|
|
26748
27233
|
}
|
|
26749
27234
|
function removeAlanOwnedLocalArtifacts() {
|
|
26750
27235
|
const configPath = getConfigPath();
|
|
26751
|
-
const directory = (0,
|
|
26752
|
-
const configName = (0,
|
|
27236
|
+
const directory = (0, import_node_path11.dirname)(configPath);
|
|
27237
|
+
const configName = (0, import_node_path11.basename)(configPath).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26753
27238
|
const alanAtomicSidecarPattern = new RegExp(
|
|
26754
27239
|
`^${configName}(?:|\\.setup-pending|\\.device-auth-pending|\\.device-auth-operation\\.json|\\.maintenance-lease\\.json|\\.event-outbox\\.enc)\\.(?:pending|release|corrupt)-\\d+-[a-f0-9]{12}$`
|
|
26755
27240
|
);
|
|
@@ -26766,13 +27251,13 @@ function removeAlanOwnedLocalArtifacts() {
|
|
|
26766
27251
|
`${configPath}.pending-runs.json.pending`,
|
|
26767
27252
|
maintenanceLeasePath(configPath)
|
|
26768
27253
|
]);
|
|
26769
|
-
if ((0,
|
|
26770
|
-
for (const entry of (0,
|
|
26771
|
-
if (alanAtomicSidecarPattern.test(entry)) artifacts.add((0,
|
|
27254
|
+
if ((0, import_node_fs13.existsSync)(directory)) {
|
|
27255
|
+
for (const entry of (0, import_node_fs13.readdirSync)(directory)) {
|
|
27256
|
+
if (alanAtomicSidecarPattern.test(entry)) artifacts.add((0, import_node_path11.join)(directory, entry));
|
|
26772
27257
|
}
|
|
26773
27258
|
}
|
|
26774
|
-
for (const artifact of artifacts) (0,
|
|
26775
|
-
(0,
|
|
27259
|
+
for (const artifact of artifacts) (0, import_node_fs13.rmSync)(artifact, { force: true });
|
|
27260
|
+
(0, import_node_fs13.rmSync)(configPath, { force: true });
|
|
26776
27261
|
}
|
|
26777
27262
|
function argValue(args, name) {
|
|
26778
27263
|
const index = args.indexOf(name);
|
|
@@ -26994,13 +27479,13 @@ var DurablePendingRunStarts = class extends Map {
|
|
|
26994
27479
|
}
|
|
26995
27480
|
persist() {
|
|
26996
27481
|
if (this.size === 0) {
|
|
26997
|
-
(0,
|
|
27482
|
+
(0, import_node_fs13.rmSync)(this.path, { force: true });
|
|
26998
27483
|
return;
|
|
26999
27484
|
}
|
|
27000
27485
|
const pendingPath = `${this.path}.pending`;
|
|
27001
|
-
(0,
|
|
27486
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(this.path), { recursive: true, mode: 448 });
|
|
27002
27487
|
try {
|
|
27003
|
-
(0,
|
|
27488
|
+
(0, import_node_fs13.writeFileSync)(
|
|
27004
27489
|
pendingPath,
|
|
27005
27490
|
JSON.stringify({
|
|
27006
27491
|
version: 1,
|
|
@@ -27013,10 +27498,10 @@ var DurablePendingRunStarts = class extends Map {
|
|
|
27013
27498
|
}),
|
|
27014
27499
|
{ mode: 384 }
|
|
27015
27500
|
);
|
|
27016
|
-
(0,
|
|
27017
|
-
(0,
|
|
27501
|
+
(0, import_node_fs13.chmodSync)(pendingPath, 384);
|
|
27502
|
+
(0, import_node_fs13.renameSync)(pendingPath, this.path);
|
|
27018
27503
|
} finally {
|
|
27019
|
-
(0,
|
|
27504
|
+
(0, import_node_fs13.rmSync)(pendingPath, { force: true });
|
|
27020
27505
|
}
|
|
27021
27506
|
}
|
|
27022
27507
|
};
|
|
@@ -27251,21 +27736,21 @@ function reconcileActiveRuns(input) {
|
|
|
27251
27736
|
}
|
|
27252
27737
|
}
|
|
27253
27738
|
function collectRuntimeMetadata() {
|
|
27254
|
-
const cpuList = (0,
|
|
27739
|
+
const cpuList = (0, import_node_os8.cpus)();
|
|
27255
27740
|
const metadata = {
|
|
27256
|
-
platform: (0,
|
|
27257
|
-
arch: (0,
|
|
27258
|
-
osVersion: (0,
|
|
27741
|
+
platform: (0, import_node_os8.platform)(),
|
|
27742
|
+
arch: (0, import_node_os8.arch)(),
|
|
27743
|
+
osVersion: (0, import_node_os8.release)(),
|
|
27259
27744
|
agentVersion: AGENT_VERSION,
|
|
27260
|
-
memoryBytes: (0,
|
|
27261
|
-
memoryFreeBytes: (0,
|
|
27745
|
+
memoryBytes: (0, import_node_os8.totalmem)(),
|
|
27746
|
+
memoryFreeBytes: (0, import_node_os8.freemem)()
|
|
27262
27747
|
};
|
|
27263
27748
|
if (cpuList.length > 0) {
|
|
27264
27749
|
metadata.cpuModel = cpuList[0]?.model;
|
|
27265
27750
|
metadata.cpuCores = cpuList.length;
|
|
27266
27751
|
}
|
|
27267
27752
|
try {
|
|
27268
|
-
const disk = (0,
|
|
27753
|
+
const disk = (0, import_node_fs13.statfsSync)((0, import_node_os8.homedir)());
|
|
27269
27754
|
metadata.diskFreeBytes = disk.bavail * disk.bsize;
|
|
27270
27755
|
metadata.diskTotalBytes = disk.blocks * disk.bsize;
|
|
27271
27756
|
} catch {
|
|
@@ -27521,7 +28006,7 @@ async function setupDaemon(args) {
|
|
|
27521
28006
|
const teamId = argValue(args, "--team") ?? process.env.ALAN_TEAM_ID;
|
|
27522
28007
|
const setupToken = argValue(args, "--setup-token") ?? process.env.ALAN_RUNTIME_SETUP_TOKEN;
|
|
27523
28008
|
const token = argValue(args, "--token") ?? process.env.ALAN_SETUP_TOKEN;
|
|
27524
|
-
const displayName = argValue(args, "--name") ?? (0,
|
|
28009
|
+
const displayName = argValue(args, "--name") ?? (0, import_node_os8.hostname)();
|
|
27525
28010
|
const scope = argValue(args, "--scope") ?? process.env.ALAN_RUNTIME_SCOPE ?? (setupToken ? "team" : "user");
|
|
27526
28011
|
const installationId = argValue(args, "--installation-id") ?? previousConfig.installationId ?? (0, import_node_crypto3.randomUUID)();
|
|
27527
28012
|
if (scope !== "team" && scope !== "user") {
|
|
@@ -27544,7 +28029,7 @@ async function setupDaemon(args) {
|
|
|
27544
28029
|
...teamId ? { teamId } : {},
|
|
27545
28030
|
...setupToken ? { setupToken, registrationAttemptId } : {},
|
|
27546
28031
|
displayName,
|
|
27547
|
-
hostname: (0,
|
|
28032
|
+
hostname: (0, import_node_os8.hostname)(),
|
|
27548
28033
|
runtimeKind: "machine",
|
|
27549
28034
|
managementKind: "user_managed",
|
|
27550
28035
|
hostKind: "daemon",
|
|
@@ -27628,7 +28113,7 @@ async function loginWithDeviceCode(args) {
|
|
|
27628
28113
|
}
|
|
27629
28114
|
const previousConfig = readConfigForRegistration();
|
|
27630
28115
|
const { apiUrl, wsUrl, endpointProfile } = resolveEndpoints(args);
|
|
27631
|
-
const displayName = argValue(args, "--name") ?? (0,
|
|
28116
|
+
const displayName = argValue(args, "--name") ?? (0, import_node_os8.hostname)();
|
|
27632
28117
|
const maxPolls = Number.parseInt(argValue(args, "--max-polls") ?? "300", 10);
|
|
27633
28118
|
const resumed = readPendingDeviceAuthorization(apiUrl);
|
|
27634
28119
|
const installationId = resumed?.installationId ?? previousConfig.installationId ?? (0, import_node_crypto3.randomUUID)();
|
|
@@ -27640,7 +28125,7 @@ async function loginWithDeviceCode(args) {
|
|
|
27640
28125
|
headers: { "content-type": "application/json" },
|
|
27641
28126
|
body: JSON.stringify({
|
|
27642
28127
|
displayName,
|
|
27643
|
-
hostname: (0,
|
|
28128
|
+
hostname: (0, import_node_os8.hostname)(),
|
|
27644
28129
|
capabilities: discoverCapabilities(),
|
|
27645
28130
|
metadata: {
|
|
27646
28131
|
...await collectRuntimeMetadataWithProviderLimits(),
|
|
@@ -27874,7 +28359,7 @@ async function startDaemon(args) {
|
|
|
27874
28359
|
const workspaceRelocations = /* @__PURE__ */ new Map();
|
|
27875
28360
|
for (const relocation of stored.workspaceRelocations ?? []) {
|
|
27876
28361
|
if (relocation?.conversationId && relocation.runId && relocation.previousPath && relocation.canonicalPath) {
|
|
27877
|
-
workspaceRelocations.set((0,
|
|
28362
|
+
workspaceRelocations.set((0, import_node_path11.resolve)(relocation.previousPath), relocation);
|
|
27878
28363
|
}
|
|
27879
28364
|
}
|
|
27880
28365
|
if (stored.localApiPort !== localApiPort || stored.localApiToken !== localApiToken || stored.localServiceId !== localServiceId || stored.localServiceSecret !== localServiceSecret || stored.eventSpoolKey !== eventSpoolKey || stored.daemonEpoch !== daemonEpoch || stored.installationId !== installationId) {
|
|
@@ -28270,7 +28755,26 @@ async function startDaemon(args) {
|
|
|
28270
28755
|
return;
|
|
28271
28756
|
}
|
|
28272
28757
|
const backendKind = normalizeBackendKind2(payload.backendKind);
|
|
28273
|
-
|
|
28758
|
+
let runtimeCommand = resolveBackendRuntimeCommand(backendKind ?? payload.backendKind);
|
|
28759
|
+
if (!runtimeCommand && backendKind) {
|
|
28760
|
+
runtimeCommand = revalidateBackendRuntimeCommand(backendKind);
|
|
28761
|
+
}
|
|
28762
|
+
if (!runtimeCommand && backendKind && canInstallProviderCli(backendKind)) {
|
|
28763
|
+
pendingRunStarts.set(payload.runId, payload.conversationId);
|
|
28764
|
+
try {
|
|
28765
|
+
const installed = await ensureProviderCliInstalled(backendKind, {
|
|
28766
|
+
notify: (message) => {
|
|
28767
|
+
pushLog(message);
|
|
28768
|
+
console.info(`[alan-agent] ${message}`);
|
|
28769
|
+
}
|
|
28770
|
+
});
|
|
28771
|
+
if (installed) {
|
|
28772
|
+
runtimeCommand = revalidateBackendRuntimeCommand(backendKind);
|
|
28773
|
+
}
|
|
28774
|
+
} finally {
|
|
28775
|
+
pendingRunStarts.delete(payload.runId);
|
|
28776
|
+
}
|
|
28777
|
+
}
|
|
28274
28778
|
if (!runtimeCommand && backendKind) {
|
|
28275
28779
|
socket.emit("agent.rejected", {
|
|
28276
28780
|
runId: payload.runId,
|
|
@@ -28284,31 +28788,31 @@ async function startDaemon(args) {
|
|
|
28284
28788
|
const workspaceRequired = Boolean(explicitWorkspacePath);
|
|
28285
28789
|
if (isAlanDefaultWorkspace(payload.projectPath)) {
|
|
28286
28790
|
try {
|
|
28287
|
-
(0,
|
|
28791
|
+
(0, import_node_fs13.mkdirSync)(cwd, { recursive: true });
|
|
28288
28792
|
} catch {
|
|
28289
28793
|
}
|
|
28290
28794
|
}
|
|
28291
28795
|
let workspaceReadiness = inspectWorkspaceReadiness(workspaceRequired ? cwd : void 0);
|
|
28292
28796
|
const expectedRepoUrls = [
|
|
28293
28797
|
...(payload.repoLocalPaths ?? []).filter(
|
|
28294
|
-
(repo) => explicitWorkspacePath ? (0,
|
|
28798
|
+
(repo) => explicitWorkspacePath ? (0, import_node_path11.resolve)(repo.localPath) === (0, import_node_path11.resolve)(explicitWorkspacePath) : false
|
|
28295
28799
|
).map((repo) => repo.repoUrl),
|
|
28296
28800
|
...payload.localRepoUrls ?? []
|
|
28297
28801
|
];
|
|
28298
28802
|
if (workspaceReadiness.code === "workspace_missing" && explicitWorkspacePath && !payload.worktreeInfo) {
|
|
28299
|
-
const previousPath = (0,
|
|
28803
|
+
const previousPath = (0, import_node_path11.resolve)(explicitWorkspacePath);
|
|
28300
28804
|
const remembered = workspaceRelocations.get(previousPath);
|
|
28301
28805
|
const rememberedPath = remembered?.canonicalPath;
|
|
28302
28806
|
const relocated = rememberedPath && workspaceMatchesExpectedRepositories({
|
|
28303
28807
|
workspacePath: rememberedPath,
|
|
28304
28808
|
expectedRepoUrls
|
|
28305
|
-
}) ? (0,
|
|
28809
|
+
}) ? (0, import_node_path11.resolve)(rememberedPath) : discoverRelocatedWorkspace({
|
|
28306
28810
|
missingPath: explicitWorkspacePath,
|
|
28307
28811
|
approvedWorkspacePaths: payload.approvedWorkspacePaths,
|
|
28308
28812
|
expectedRepoUrls
|
|
28309
28813
|
});
|
|
28310
28814
|
if (relocated) {
|
|
28311
|
-
if (!remembered || (0,
|
|
28815
|
+
if (!remembered || (0, import_node_path11.resolve)(remembered.canonicalPath) !== relocated) {
|
|
28312
28816
|
workspaceRelocations.set(previousPath, {
|
|
28313
28817
|
conversationId: payload.conversationId,
|
|
28314
28818
|
runId: payload.runId,
|
|
@@ -28769,6 +29273,29 @@ async function startDaemon(args) {
|
|
|
28769
29273
|
})();
|
|
28770
29274
|
}
|
|
28771
29275
|
);
|
|
29276
|
+
socket.on(
|
|
29277
|
+
"runtime.skills.scan",
|
|
29278
|
+
(payload) => {
|
|
29279
|
+
if (!payload?.requestId) return;
|
|
29280
|
+
const requestId = payload.requestId;
|
|
29281
|
+
try {
|
|
29282
|
+
const projectPath = isAlanDefaultWorkspace(payload.projectPath) ? resolveAlanDefaultWorkspacePath() : payload.projectPath;
|
|
29283
|
+
const result = scanLocalSkillsCached((0, import_node_os8.homedir)(), projectPath, {
|
|
29284
|
+
refresh: payload.refresh === true
|
|
29285
|
+
});
|
|
29286
|
+
socket.emit("runtime.skills.result", {
|
|
29287
|
+
requestId,
|
|
29288
|
+
skills: result.skills,
|
|
29289
|
+
errors: result.errors
|
|
29290
|
+
});
|
|
29291
|
+
} catch (error) {
|
|
29292
|
+
socket.emit("runtime.skills.result", {
|
|
29293
|
+
requestId,
|
|
29294
|
+
error: error instanceof Error ? error.message : String(error)
|
|
29295
|
+
});
|
|
29296
|
+
}
|
|
29297
|
+
}
|
|
29298
|
+
);
|
|
28772
29299
|
const adoptionChallenges = /* @__PURE__ */ new Map();
|
|
28773
29300
|
const localServer = import_node_http.default.createServer((req, res) => {
|
|
28774
29301
|
if (req.method === "GET" && req.url === "/owner") {
|
|
@@ -29762,7 +30289,7 @@ var agentProbeAckSchema = external_exports.object({
|
|
|
29762
30289
|
|
|
29763
30290
|
// src/sandbox-outbox.ts
|
|
29764
30291
|
var import_node_crypto5 = require("crypto");
|
|
29765
|
-
var
|
|
30292
|
+
var import_node_fs14 = require("fs");
|
|
29766
30293
|
var SANDBOX_EVENT_OUTBOX_ENV = "ALAN_EVENT_OUTBOX_ENABLED";
|
|
29767
30294
|
function isSandboxEventOutboxEnabled(env = process.env) {
|
|
29768
30295
|
return env[SANDBOX_EVENT_OUTBOX_ENV] === "true";
|
|
@@ -29785,7 +30312,7 @@ function createSandboxEventOutbox(input) {
|
|
|
29785
30312
|
input.pushLog?.(
|
|
29786
30313
|
`sandbox_outbox_spool_reset ${error instanceof Error ? error.message : String(error)}`
|
|
29787
30314
|
);
|
|
29788
|
-
(0,
|
|
30315
|
+
(0, import_node_fs14.rmSync)(path, { force: true });
|
|
29789
30316
|
return new EncryptedEventOutbox(path, key, input.pushLog, input.options);
|
|
29790
30317
|
}
|
|
29791
30318
|
}
|
|
@@ -30482,10 +31009,10 @@ async function runSandbox(config) {
|
|
|
30482
31009
|
}
|
|
30483
31010
|
|
|
30484
31011
|
// src/service-manager.ts
|
|
30485
|
-
var
|
|
30486
|
-
var
|
|
30487
|
-
var
|
|
30488
|
-
var
|
|
31012
|
+
var import_node_child_process7 = require("child_process");
|
|
31013
|
+
var import_node_fs15 = require("fs");
|
|
31014
|
+
var import_node_os9 = require("os");
|
|
31015
|
+
var import_node_path12 = require("path");
|
|
30489
31016
|
var SERVICE_LABEL = "ai.tryalan.agent";
|
|
30490
31017
|
var SYSTEMD_UNIT = "alan-agent.service";
|
|
30491
31018
|
var WINDOWS_TASK = "Alan Agent";
|
|
@@ -30505,8 +31032,8 @@ function buildDaemonServicePlan(input) {
|
|
|
30505
31032
|
if (userId === void 0) throw new Error("Cannot determine the current macOS user ID");
|
|
30506
31033
|
const domain = `gui/${userId}`;
|
|
30507
31034
|
const serviceTarget = `${domain}/${SERVICE_LABEL}`;
|
|
30508
|
-
const manifestPath = (0,
|
|
30509
|
-
const logDir = (0,
|
|
31035
|
+
const manifestPath = (0, import_node_path12.join)(input.homeDir, "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
|
|
31036
|
+
const logDir = (0, import_node_path12.join)(input.homeDir, ".alan", "agent", "logs");
|
|
30510
31037
|
const programArguments = daemonArgs.map((arg) => ` <string>${xml(arg)}</string>`).join("\n");
|
|
30511
31038
|
const manifest = `<?xml version="1.0" encoding="UTF-8"?>
|
|
30512
31039
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -30528,9 +31055,9 @@ ${programArguments}
|
|
|
30528
31055
|
<key>ThrottleInterval</key>
|
|
30529
31056
|
<integer>5</integer>
|
|
30530
31057
|
<key>StandardOutPath</key>
|
|
30531
|
-
<string>${xml((0,
|
|
31058
|
+
<string>${xml((0, import_node_path12.join)(logDir, "daemon.log"))}</string>
|
|
30532
31059
|
<key>StandardErrorPath</key>
|
|
30533
|
-
<string>${xml((0,
|
|
31060
|
+
<string>${xml((0, import_node_path12.join)(logDir, "daemon-error.log"))}</string>
|
|
30534
31061
|
</dict>
|
|
30535
31062
|
</plist>
|
|
30536
31063
|
`;
|
|
@@ -30569,7 +31096,7 @@ ${programArguments}
|
|
|
30569
31096
|
};
|
|
30570
31097
|
}
|
|
30571
31098
|
if (input.platform === "linux") {
|
|
30572
|
-
const manifestPath = (0,
|
|
31099
|
+
const manifestPath = (0, import_node_path12.join)(input.homeDir, ".config", "systemd", "user", SYSTEMD_UNIT);
|
|
30573
31100
|
const manifest = `[Unit]
|
|
30574
31101
|
Description=Alan local agent daemon
|
|
30575
31102
|
After=network-online.target
|
|
@@ -30666,7 +31193,7 @@ WantedBy=default.target
|
|
|
30666
31193
|
};
|
|
30667
31194
|
}
|
|
30668
31195
|
function currentServicePlan(args) {
|
|
30669
|
-
const currentPlatform = (0,
|
|
31196
|
+
const currentPlatform = (0, import_node_os9.platform)();
|
|
30670
31197
|
if (currentPlatform !== "darwin" && currentPlatform !== "linux" && currentPlatform !== "win32") {
|
|
30671
31198
|
throw new Error(`Daemon service installation is not supported on ${currentPlatform}`);
|
|
30672
31199
|
}
|
|
@@ -30675,25 +31202,25 @@ function currentServicePlan(args) {
|
|
|
30675
31202
|
if (!cliEntry) throw new Error("Cannot determine the alan-agent executable path");
|
|
30676
31203
|
return buildDaemonServicePlan({
|
|
30677
31204
|
platform: currentPlatform,
|
|
30678
|
-
homeDir: (0,
|
|
31205
|
+
homeDir: (0, import_node_os9.homedir)(),
|
|
30679
31206
|
nodeExecutable: process.execPath,
|
|
30680
|
-
cliEntry: (0,
|
|
31207
|
+
cliEntry: (0, import_node_path12.resolve)(cliEntry),
|
|
30681
31208
|
profile
|
|
30682
31209
|
});
|
|
30683
31210
|
}
|
|
30684
31211
|
function writeManifest(path, contents) {
|
|
30685
|
-
(0,
|
|
31212
|
+
(0, import_node_fs15.mkdirSync)((0, import_node_path12.dirname)(path), { recursive: true, mode: 448 });
|
|
30686
31213
|
const pendingPath = `${path}.pending-${process.pid}`;
|
|
30687
31214
|
try {
|
|
30688
|
-
(0,
|
|
30689
|
-
(0,
|
|
30690
|
-
(0,
|
|
31215
|
+
(0, import_node_fs15.writeFileSync)(pendingPath, contents, { mode: 384 });
|
|
31216
|
+
(0, import_node_fs15.chmodSync)(pendingPath, 384);
|
|
31217
|
+
(0, import_node_fs15.renameSync)(pendingPath, path);
|
|
30691
31218
|
} finally {
|
|
30692
|
-
(0,
|
|
31219
|
+
(0, import_node_fs15.rmSync)(pendingPath, { force: true });
|
|
30693
31220
|
}
|
|
30694
31221
|
}
|
|
30695
31222
|
function runServiceCommand(command) {
|
|
30696
|
-
const result = (0,
|
|
31223
|
+
const result = (0, import_node_child_process7.spawnSync)(command.command, command.args, { encoding: "utf8" });
|
|
30697
31224
|
const status = result.status ?? 1;
|
|
30698
31225
|
const output = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
|
|
30699
31226
|
if (status !== 0 && !command.tolerateFailure) {
|
|
@@ -30711,8 +31238,8 @@ function installDaemonService(args = []) {
|
|
|
30711
31238
|
}
|
|
30712
31239
|
const plan = currentServicePlan(args);
|
|
30713
31240
|
if (plan.manifestPath && plan.manifest) {
|
|
30714
|
-
if ((0,
|
|
30715
|
-
(0,
|
|
31241
|
+
if ((0, import_node_os9.platform)() === "darwin") {
|
|
31242
|
+
(0, import_node_fs15.mkdirSync)((0, import_node_path12.join)((0, import_node_os9.homedir)(), ".alan", "agent", "logs"), { recursive: true, mode: 448 });
|
|
30716
31243
|
}
|
|
30717
31244
|
writeManifest(plan.manifestPath, plan.manifest);
|
|
30718
31245
|
}
|
|
@@ -30722,7 +31249,7 @@ function installDaemonService(args = []) {
|
|
|
30722
31249
|
function uninstallDaemonService(args = []) {
|
|
30723
31250
|
const plan = currentServicePlan(args);
|
|
30724
31251
|
for (const command of plan.uninstallCommands) runServiceCommand(command);
|
|
30725
|
-
if (plan.manifestPath) (0,
|
|
31252
|
+
if (plan.manifestPath) (0, import_node_fs15.rmSync)(plan.manifestPath, { force: true });
|
|
30726
31253
|
console.info("[alan-agent] Per-user daemon service removed");
|
|
30727
31254
|
}
|
|
30728
31255
|
function printDaemonServiceStatus(args = []) {
|
|
@@ -30733,6 +31260,42 @@ function printDaemonServiceStatus(args = []) {
|
|
|
30733
31260
|
}
|
|
30734
31261
|
|
|
30735
31262
|
// src/index.ts
|
|
31263
|
+
function logEffectiveGitIdentity(lifecycle, projectPath) {
|
|
31264
|
+
const readConfig2 = (key) => {
|
|
31265
|
+
try {
|
|
31266
|
+
const result = (0, import_node_child_process8.spawnSync)("git", ["config", "--get", key], {
|
|
31267
|
+
cwd: projectPath,
|
|
31268
|
+
env: getDaemonCliEnvironment(),
|
|
31269
|
+
encoding: "utf8",
|
|
31270
|
+
timeout: 5e3
|
|
31271
|
+
});
|
|
31272
|
+
const value2 = result.status === 0 ? result.stdout.trim() : "";
|
|
31273
|
+
return value2 || null;
|
|
31274
|
+
} catch {
|
|
31275
|
+
return null;
|
|
31276
|
+
}
|
|
31277
|
+
};
|
|
31278
|
+
const envName = process.env.GIT_AUTHOR_NAME || null;
|
|
31279
|
+
const envEmail = process.env.GIT_AUTHOR_EMAIL || null;
|
|
31280
|
+
const configName = readConfig2("user.name");
|
|
31281
|
+
const configEmail = readConfig2("user.email");
|
|
31282
|
+
const payload = {
|
|
31283
|
+
projectPath,
|
|
31284
|
+
envAuthorName: envName,
|
|
31285
|
+
envAuthorEmail: envEmail,
|
|
31286
|
+
configUserName: configName,
|
|
31287
|
+
configUserEmail: configEmail
|
|
31288
|
+
};
|
|
31289
|
+
if (!envEmail && !configEmail) {
|
|
31290
|
+
lifecycle.error("sandbox_agent_git_identity_missing", payload);
|
|
31291
|
+
return;
|
|
31292
|
+
}
|
|
31293
|
+
if (envEmail && configEmail && envEmail !== configEmail) {
|
|
31294
|
+
lifecycle.error("sandbox_agent_git_identity_mismatch", payload);
|
|
31295
|
+
return;
|
|
31296
|
+
}
|
|
31297
|
+
lifecycle.info("sandbox_agent_git_identity", payload);
|
|
31298
|
+
}
|
|
30736
31299
|
async function runSessionFromEnv() {
|
|
30737
31300
|
const wsUrl = process.env.ALAN_WS_URL;
|
|
30738
31301
|
const sessionId = process.env.ALAN_SESSION_ID;
|
|
@@ -30777,6 +31340,7 @@ async function runSessionFromEnv() {
|
|
|
30777
31340
|
mode,
|
|
30778
31341
|
model
|
|
30779
31342
|
});
|
|
31343
|
+
logEffectiveGitIdentity(lifecycle, projectPath);
|
|
30780
31344
|
await runSandbox({
|
|
30781
31345
|
wsUrl,
|
|
30782
31346
|
sessionId,
|