@meistrari/tela-cli 0.7.28 → 0.7.30
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.js +359 -36
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -910,11 +910,16 @@ var require_process = __commonJS({
|
|
|
910
910
|
exports2.runCommand = runCommand;
|
|
911
911
|
exports2.runShell = runShell;
|
|
912
912
|
exports2.commandExists = commandExists;
|
|
913
|
+
exports2.resolveExecutable = resolveExecutable;
|
|
913
914
|
exports2.runInteractiveCommand = runInteractiveCommand;
|
|
914
915
|
exports2.runStreamingCommand = runStreamingCommand;
|
|
915
916
|
exports2.spawnStreamingCommand = spawnStreamingCommand;
|
|
916
917
|
var node_child_process_1 = require("node:child_process");
|
|
917
918
|
var node_events_1 = require("node:events");
|
|
919
|
+
var node_fs_1 = require("node:fs");
|
|
920
|
+
var promises_1 = require("node:fs/promises");
|
|
921
|
+
var node_os_1 = require("node:os");
|
|
922
|
+
var node_path_1 = require("node:path");
|
|
918
923
|
var CommandError = class extends Error {
|
|
919
924
|
result;
|
|
920
925
|
constructor(message, result) {
|
|
@@ -981,8 +986,89 @@ var require_process = __commonJS({
|
|
|
981
986
|
} catch {
|
|
982
987
|
}
|
|
983
988
|
}
|
|
989
|
+
function hasPathSeparator(command) {
|
|
990
|
+
return command.includes("/") || command.includes("\\");
|
|
991
|
+
}
|
|
992
|
+
function pathDelimiterForPlatform(platform) {
|
|
993
|
+
return platform === "win32" ? ";" : ":";
|
|
994
|
+
}
|
|
995
|
+
function shellSingleQuote(value) {
|
|
996
|
+
return `'${String(value).replace(/'/g, "'\\''")}'`;
|
|
997
|
+
}
|
|
998
|
+
function isSafeExecutableName(command) {
|
|
999
|
+
return /^[A-Za-z0-9._+-]+$/.test(command);
|
|
1000
|
+
}
|
|
1001
|
+
function getWindowsExecutableSuffixes(command, env) {
|
|
1002
|
+
if (/\.[^\\/]+$/.test(command)) {
|
|
1003
|
+
return [""];
|
|
1004
|
+
}
|
|
1005
|
+
const pathExt = env.PATHEXT || ".COM;.EXE;.BAT;.CMD";
|
|
1006
|
+
return pathExt.split(";").map((item) => item.trim()).filter(Boolean);
|
|
1007
|
+
}
|
|
1008
|
+
function getPathExecutableCandidates(command, env, platform) {
|
|
1009
|
+
if (hasPathSeparator(command)) {
|
|
1010
|
+
return [command];
|
|
1011
|
+
}
|
|
1012
|
+
const suffixes = platform === "win32" ? getWindowsExecutableSuffixes(command, env) : [""];
|
|
1013
|
+
return (env.PATH || "").split(pathDelimiterForPlatform(platform)).map((item) => item.trim()).filter(Boolean).flatMap((directory) => suffixes.map((suffix) => (0, node_path_1.join)(directory, `${command}${suffix}`)));
|
|
1014
|
+
}
|
|
1015
|
+
function getKnownExecutableCandidates(command, homeDir, platform) {
|
|
1016
|
+
if (platform === "win32" || hasPathSeparator(command)) {
|
|
1017
|
+
return [];
|
|
1018
|
+
}
|
|
1019
|
+
return [
|
|
1020
|
+
"/opt/homebrew/bin",
|
|
1021
|
+
"/usr/local/bin",
|
|
1022
|
+
(0, node_path_1.join)(homeDir, ".claude", "local"),
|
|
1023
|
+
(0, node_path_1.join)(homeDir, ".claude", "local", "bin"),
|
|
1024
|
+
(0, node_path_1.join)(homeDir, ".bun", "bin"),
|
|
1025
|
+
(0, node_path_1.join)(homeDir, ".npm-global", "bin"),
|
|
1026
|
+
(0, node_path_1.join)(homeDir, ".local", "bin")
|
|
1027
|
+
].map((directory) => (0, node_path_1.join)(directory, command));
|
|
1028
|
+
}
|
|
1029
|
+
async function findFirstExecutable(candidates, accessFn) {
|
|
1030
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1031
|
+
for (const candidate of candidates) {
|
|
1032
|
+
if (!candidate || seen.has(candidate)) {
|
|
1033
|
+
continue;
|
|
1034
|
+
}
|
|
1035
|
+
seen.add(candidate);
|
|
1036
|
+
try {
|
|
1037
|
+
await accessFn(candidate, node_fs_1.constants.X_OK);
|
|
1038
|
+
return candidate;
|
|
1039
|
+
} catch {
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
return null;
|
|
1043
|
+
}
|
|
1044
|
+
async function resolveExecutableFromShell(command, options) {
|
|
1045
|
+
if (hasPathSeparator(command) || !isSafeExecutableName(command)) {
|
|
1046
|
+
return null;
|
|
1047
|
+
}
|
|
1048
|
+
const lookupCommand = options.platform === "win32" ? ["where", command] : [
|
|
1049
|
+
options.shell || (options.platform === "darwin" ? "/bin/zsh" : options.env.SHELL || process.env.SHELL || "/bin/sh"),
|
|
1050
|
+
"-lc",
|
|
1051
|
+
`command -v ${shellSingleQuote(command)}`
|
|
1052
|
+
];
|
|
1053
|
+
try {
|
|
1054
|
+
const result = await options.runCommandFn(lookupCommand, {
|
|
1055
|
+
env: options.env,
|
|
1056
|
+
allowFailure: true,
|
|
1057
|
+
timeoutMs: options.timeoutMs
|
|
1058
|
+
});
|
|
1059
|
+
if (result.exitCode !== 0) {
|
|
1060
|
+
return null;
|
|
1061
|
+
}
|
|
1062
|
+
const candidates = result.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
1063
|
+
return await findFirstExecutable(candidates, options.accessFn);
|
|
1064
|
+
} catch {
|
|
1065
|
+
return null;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
984
1068
|
async function runCommand(command, options = {}) {
|
|
985
1069
|
assertCommand(command);
|
|
1070
|
+
let timedOut = false;
|
|
1071
|
+
let timeout;
|
|
986
1072
|
const child = (0, node_child_process_1.spawn)(command[0], command.slice(1), {
|
|
987
1073
|
cwd: options.cwd,
|
|
988
1074
|
env: buildEnv(options.env),
|
|
@@ -992,6 +1078,13 @@ var require_process = __commonJS({
|
|
|
992
1078
|
"pipe"
|
|
993
1079
|
]
|
|
994
1080
|
});
|
|
1081
|
+
if (options.timeoutMs !== void 0 && options.timeoutMs > 0) {
|
|
1082
|
+
timeout = setTimeout(() => {
|
|
1083
|
+
timedOut = true;
|
|
1084
|
+
signalProcessGroup(child, "SIGTERM");
|
|
1085
|
+
}, options.timeoutMs);
|
|
1086
|
+
timeout.unref?.();
|
|
1087
|
+
}
|
|
995
1088
|
if (options.input !== void 0) {
|
|
996
1089
|
child.stdin?.end(options.input);
|
|
997
1090
|
}
|
|
@@ -1000,12 +1093,15 @@ var require_process = __commonJS({
|
|
|
1000
1093
|
readStream(child.stderr),
|
|
1001
1094
|
(0, node_events_1.once)(child, "close")
|
|
1002
1095
|
]);
|
|
1096
|
+
if (timeout) {
|
|
1097
|
+
clearTimeout(timeout);
|
|
1098
|
+
}
|
|
1003
1099
|
const [code] = closeResult;
|
|
1004
1100
|
const result = {
|
|
1005
1101
|
command,
|
|
1006
1102
|
exitCode: code ?? 1,
|
|
1007
1103
|
stdout,
|
|
1008
|
-
stderr
|
|
1104
|
+
stderr: timedOut ? `${stderr}${stderr ? "\n" : ""}Command timed out after ${options.timeoutMs}ms.` : stderr
|
|
1009
1105
|
};
|
|
1010
1106
|
if (result.exitCode !== 0 && !options.allowFailure) {
|
|
1011
1107
|
throw new CommandError(`Command failed (${result.exitCode}): ${command.join(" ")}`, result);
|
|
@@ -1016,8 +1112,31 @@ var require_process = __commonJS({
|
|
|
1016
1112
|
return await runCommand([process.env.SHELL ?? "/bin/sh", "-c", script], options);
|
|
1017
1113
|
}
|
|
1018
1114
|
async function commandExists(command) {
|
|
1019
|
-
|
|
1020
|
-
|
|
1115
|
+
return await resolveExecutable(command) !== null;
|
|
1116
|
+
}
|
|
1117
|
+
async function resolveExecutable(command, options = {}) {
|
|
1118
|
+
const platform = options.platform ?? process.platform;
|
|
1119
|
+
const env = options.env ?? process.env;
|
|
1120
|
+
const accessFn = options.accessFn ?? promises_1.access;
|
|
1121
|
+
const runCommandFn = options.runCommandFn ?? runCommand;
|
|
1122
|
+
const timeoutMs = options.timeoutMs ?? 5e3;
|
|
1123
|
+
const homeDir = options.homeDir ?? (0, node_os_1.homedir)();
|
|
1124
|
+
const pathCandidate = await findFirstExecutable(getPathExecutableCandidates(command, env, platform), accessFn);
|
|
1125
|
+
if (pathCandidate) {
|
|
1126
|
+
return pathCandidate;
|
|
1127
|
+
}
|
|
1128
|
+
const shellCandidate = await resolveExecutableFromShell(command, {
|
|
1129
|
+
env,
|
|
1130
|
+
runCommandFn,
|
|
1131
|
+
accessFn,
|
|
1132
|
+
platform,
|
|
1133
|
+
shell: options.shell,
|
|
1134
|
+
timeoutMs
|
|
1135
|
+
});
|
|
1136
|
+
if (shellCandidate) {
|
|
1137
|
+
return shellCandidate;
|
|
1138
|
+
}
|
|
1139
|
+
return await findFirstExecutable(getKnownExecutableCandidates(command, homeDir, platform), accessFn);
|
|
1021
1140
|
}
|
|
1022
1141
|
async function runInteractiveCommand(command, options = {}) {
|
|
1023
1142
|
assertCommand(command);
|
|
@@ -1415,6 +1534,7 @@ var require_auth2 = __commonJS({
|
|
|
1415
1534
|
"../../packages/agent/dist/auth.js"(exports2) {
|
|
1416
1535
|
"use strict";
|
|
1417
1536
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
1537
|
+
exports2.resolveAgentApiDataToken = resolveAgentApiDataToken;
|
|
1418
1538
|
exports2.buildAgentApiHeaders = buildAgentApiHeaders;
|
|
1419
1539
|
var tela_local_config_1 = require_dist();
|
|
1420
1540
|
var errors_1 = require_errors();
|
|
@@ -1456,18 +1576,14 @@ var require_auth2 = __commonJS({
|
|
|
1456
1576
|
}
|
|
1457
1577
|
return dataToken;
|
|
1458
1578
|
}
|
|
1459
|
-
async function
|
|
1579
|
+
async function resolveAgentApiDataToken(config, options = {}) {
|
|
1460
1580
|
const fetchFn = options.fetchFn ?? fetch;
|
|
1461
1581
|
const credentialRef = config.credentialRef;
|
|
1462
1582
|
const credentials = config.credentials;
|
|
1463
1583
|
const resolvedEnvironment = config.resolvedEnvironment;
|
|
1464
1584
|
let credential = config.credential;
|
|
1465
1585
|
if (!credential && config.auth?.session.accessToken) {
|
|
1466
|
-
|
|
1467
|
-
return {
|
|
1468
|
-
"x-data-token": dataToken2,
|
|
1469
|
-
Accept: "application/json"
|
|
1470
|
-
};
|
|
1586
|
+
return await exchangeDataToken(config, config.auth.session.accessToken, fetchFn);
|
|
1471
1587
|
}
|
|
1472
1588
|
if (!credential) {
|
|
1473
1589
|
throw (0, errors_1.createUserFacingError)({
|
|
@@ -1477,10 +1593,7 @@ var require_auth2 = __commonJS({
|
|
|
1477
1593
|
});
|
|
1478
1594
|
}
|
|
1479
1595
|
if (credential.kind === "data-token" && credential.dataToken) {
|
|
1480
|
-
return
|
|
1481
|
-
"x-data-token": credential.dataToken,
|
|
1482
|
-
Accept: "application/json"
|
|
1483
|
-
};
|
|
1596
|
+
return credential.dataToken;
|
|
1484
1597
|
}
|
|
1485
1598
|
if (credential.kind === "user-session") {
|
|
1486
1599
|
if (!credentialRef || !credentials || !resolvedEnvironment) {
|
|
@@ -1500,7 +1613,10 @@ var require_auth2 = __commonJS({
|
|
|
1500
1613
|
fixes: ["Sign in with Dock or choose a user-session context before running agent commands."]
|
|
1501
1614
|
});
|
|
1502
1615
|
}
|
|
1503
|
-
|
|
1616
|
+
return await exchangeDataToken(config, credential.accessToken, fetchFn);
|
|
1617
|
+
}
|
|
1618
|
+
async function buildAgentApiHeaders(config, options = {}) {
|
|
1619
|
+
const dataToken = await resolveAgentApiDataToken(config, options);
|
|
1504
1620
|
return {
|
|
1505
1621
|
"x-data-token": dataToken,
|
|
1506
1622
|
Accept: "application/json"
|
|
@@ -1515,6 +1631,7 @@ var require_agent_api = __commonJS({
|
|
|
1515
1631
|
"use strict";
|
|
1516
1632
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
1517
1633
|
exports2.AgentApiError = void 0;
|
|
1634
|
+
exports2.fetchOpenRouterModels = fetchOpenRouterModels;
|
|
1518
1635
|
exports2.listOrganizations = listOrganizations;
|
|
1519
1636
|
exports2.provisionForgejoUser = provisionForgejoUser;
|
|
1520
1637
|
exports2.fetchRepositoryLookup = fetchRepositoryLookup;
|
|
@@ -1593,6 +1710,37 @@ var require_agent_api = __commonJS({
|
|
|
1593
1710
|
}
|
|
1594
1711
|
};
|
|
1595
1712
|
exports2.AgentApiError = AgentApiError;
|
|
1713
|
+
function isOpenRouterModelPricingSummary(value) {
|
|
1714
|
+
if (!value || typeof value !== "object") {
|
|
1715
|
+
return false;
|
|
1716
|
+
}
|
|
1717
|
+
const candidate = value;
|
|
1718
|
+
return typeof candidate.prompt_per_million === "number" && typeof candidate.completion_per_million === "number" && (candidate.input_cache_read_per_million === void 0 || typeof candidate.input_cache_read_per_million === "number");
|
|
1719
|
+
}
|
|
1720
|
+
function isOpenRouterModelSummary(value) {
|
|
1721
|
+
if (!value || typeof value !== "object") {
|
|
1722
|
+
return false;
|
|
1723
|
+
}
|
|
1724
|
+
const candidate = value;
|
|
1725
|
+
return typeof candidate.id === "string" && typeof candidate.name === "string" && typeof candidate.context_length === "number" && (candidate.max_completion_tokens === null || typeof candidate.max_completion_tokens === "number") && isOpenRouterModelPricingSummary(candidate.pricing);
|
|
1726
|
+
}
|
|
1727
|
+
async function fetchOpenRouterModels(config, fetchFn = fetch, options = {}) {
|
|
1728
|
+
const headers = options.headers ?? await (0, auth_1.buildAgentApiHeaders)(config, { fetchFn });
|
|
1729
|
+
const response = await fetchFn(joinUrl2(config.agentApiUrl, "/v3/openrouter/models"), {
|
|
1730
|
+
method: "GET",
|
|
1731
|
+
headers,
|
|
1732
|
+
signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS)
|
|
1733
|
+
});
|
|
1734
|
+
const responseText = await response.text();
|
|
1735
|
+
const payload = parseJsonBody(responseText);
|
|
1736
|
+
if (!response.ok) {
|
|
1737
|
+
throw new AgentApiError(payload?.error ?? `Agent API OpenRouter model lookup failed with status ${response.status}`, response.status, responseText);
|
|
1738
|
+
}
|
|
1739
|
+
if (!payload || payload.object !== "list" || !Array.isArray(payload.data) || !payload.data.every(isOpenRouterModelSummary)) {
|
|
1740
|
+
throw new AgentApiError("Agent API OpenRouter model lookup returned an invalid payload", response.status, responseText);
|
|
1741
|
+
}
|
|
1742
|
+
return payload.data;
|
|
1743
|
+
}
|
|
1596
1744
|
async function listOrganizations(config, fetchFn = fetch) {
|
|
1597
1745
|
const headers = await (0, auth_1.buildAgentApiHeaders)(config, { fetchFn });
|
|
1598
1746
|
const response = await fetchFn(joinUrl2(config.agentApiUrl, "/v3/organizations"), {
|
|
@@ -1877,7 +2025,7 @@ var require_claude = __commonJS({
|
|
|
1877
2025
|
}
|
|
1878
2026
|
return tools;
|
|
1879
2027
|
}
|
|
1880
|
-
async function prepareProjectScopedClaudeLaunch(repoRoot) {
|
|
2028
|
+
async function prepareProjectScopedClaudeLaunch(repoRoot, options = {}) {
|
|
1881
2029
|
const settingsPath = (0, node_path_1.join)(repoRoot, ".claude", "settings.json");
|
|
1882
2030
|
let settingsContent;
|
|
1883
2031
|
try {
|
|
@@ -1903,12 +2051,13 @@ var require_claude = __commonJS({
|
|
|
1903
2051
|
settingsPath,
|
|
1904
2052
|
allowedTools,
|
|
1905
2053
|
mcpConfig: (0, node_fs_1.existsSync)(mcpConfigPath) ? mcpConfigPath : EMPTY_MCP_CONFIG,
|
|
1906
|
-
mcpConfigPath: (0, node_fs_1.existsSync)(mcpConfigPath) ? mcpConfigPath : void 0
|
|
2054
|
+
mcpConfigPath: (0, node_fs_1.existsSync)(mcpConfigPath) ? mcpConfigPath : void 0,
|
|
2055
|
+
claudeExecutablePath: options.claudeExecutablePath
|
|
1907
2056
|
};
|
|
1908
2057
|
}
|
|
1909
2058
|
function buildProjectScopedClaudeCommand(launch, options = {}) {
|
|
1910
2059
|
const command = [
|
|
1911
|
-
"claude",
|
|
2060
|
+
launch.claudeExecutablePath ?? "claude",
|
|
1912
2061
|
"--setting-sources",
|
|
1913
2062
|
"project",
|
|
1914
2063
|
"--permission-mode",
|
|
@@ -1970,9 +2119,10 @@ var require_claude = __commonJS({
|
|
|
1970
2119
|
};
|
|
1971
2120
|
}
|
|
1972
2121
|
async function inspectClaudeCli(options = {}) {
|
|
1973
|
-
const
|
|
2122
|
+
const resolveExecutableFn = options.resolveExecutableFn ?? process_1.resolveExecutable;
|
|
1974
2123
|
const runCommandFn = options.runCommandFn ?? process_1.runCommand;
|
|
1975
|
-
|
|
2124
|
+
const executablePath = options.commandExistsFn ? await options.commandExistsFn("claude") ? "claude" : null : await resolveExecutableFn("claude");
|
|
2125
|
+
if (!executablePath) {
|
|
1976
2126
|
return {
|
|
1977
2127
|
available: false,
|
|
1978
2128
|
supportsProjectScopedRun: false,
|
|
@@ -1980,13 +2130,14 @@ var require_claude = __commonJS({
|
|
|
1980
2130
|
detail: "`claude` is not available on PATH."
|
|
1981
2131
|
};
|
|
1982
2132
|
}
|
|
1983
|
-
const result = await runCommandFn([
|
|
2133
|
+
const result = await runCommandFn([executablePath, "--version"], { allowFailure: true });
|
|
1984
2134
|
const output = `${result.stdout}
|
|
1985
2135
|
${result.stderr}`.trim();
|
|
1986
2136
|
const parsedVersion = parseClaudeCliVersion(output);
|
|
1987
2137
|
if (!parsedVersion) {
|
|
1988
2138
|
return {
|
|
1989
2139
|
available: true,
|
|
2140
|
+
executablePath,
|
|
1990
2141
|
supportsProjectScopedRun: false,
|
|
1991
2142
|
problem: "unparseable",
|
|
1992
2143
|
detail: output || "Claude CLI version output was empty."
|
|
@@ -1996,6 +2147,7 @@ ${result.stderr}`.trim();
|
|
|
1996
2147
|
if (compareClaudeCliVersions(parsedVersion, exports2.MIN_CLAUDE_VERSION_FOR_PROJECT_SCOPED_RUN) < 0) {
|
|
1997
2148
|
return {
|
|
1998
2149
|
available: true,
|
|
2150
|
+
executablePath,
|
|
1999
2151
|
version,
|
|
2000
2152
|
parsedVersion,
|
|
2001
2153
|
supportsProjectScopedRun: false,
|
|
@@ -2005,6 +2157,7 @@ ${result.stderr}`.trim();
|
|
|
2005
2157
|
}
|
|
2006
2158
|
return {
|
|
2007
2159
|
available: true,
|
|
2160
|
+
executablePath,
|
|
2008
2161
|
version,
|
|
2009
2162
|
parsedVersion,
|
|
2010
2163
|
supportsProjectScopedRun: true,
|
|
@@ -2840,7 +2993,9 @@ var require_feedback = __commonJS({
|
|
|
2840
2993
|
}
|
|
2841
2994
|
async function launchFeedbackClaude(options) {
|
|
2842
2995
|
const runInteractiveCommandFn = options.runInteractiveCommand ?? process_1.runInteractiveCommand;
|
|
2843
|
-
const launch = await (0, claude_1.prepareProjectScopedClaudeLaunch)(options.repoRoot
|
|
2996
|
+
const launch = await (0, claude_1.prepareProjectScopedClaudeLaunch)(options.repoRoot, {
|
|
2997
|
+
claudeExecutablePath: options.claudeExecutablePath
|
|
2998
|
+
});
|
|
2844
2999
|
const command = (0, claude_1.buildProjectScopedClaudeCommand)(launch, {
|
|
2845
3000
|
prompt: options.prompt
|
|
2846
3001
|
});
|
|
@@ -2878,7 +3033,10 @@ var require_feedback = __commonJS({
|
|
|
2878
3033
|
const getOriginUrlFn = options.getOriginUrl ?? git_1.getOriginUrl;
|
|
2879
3034
|
const getHeadCommitHashFn = options.getHeadCommitHash ?? git_1.getHeadCommitHash;
|
|
2880
3035
|
const getDiffStatAgainstHeadFn = options.getDiffStatAgainstHead ?? git_1.getDiffStatAgainstHead;
|
|
2881
|
-
const
|
|
3036
|
+
const inspectClaudeCliFn = options.inspectClaudeCli ?? (async () => await (0, claude_1.inspectClaudeCli)({
|
|
3037
|
+
commandExistsFn: options.commandExists,
|
|
3038
|
+
runCommandFn: options.runCommand
|
|
3039
|
+
}));
|
|
2882
3040
|
const runInteractiveCommandFn = options.runInteractiveCommand ?? process_1.runInteractiveCommand;
|
|
2883
3041
|
const selectionMode = getFeedbackSelectionMode(options);
|
|
2884
3042
|
const config = await ensureConfig();
|
|
@@ -2902,13 +3060,27 @@ var require_feedback = __commonJS({
|
|
|
2902
3060
|
launchedClaude: false
|
|
2903
3061
|
});
|
|
2904
3062
|
}
|
|
2905
|
-
|
|
3063
|
+
let claudeExecutablePath;
|
|
3064
|
+
const claudeInspection = await inspectClaudeCliFn();
|
|
3065
|
+
if (!claudeInspection.available) {
|
|
2906
3066
|
throw (0, errors_1.createUserFacingError)({
|
|
2907
3067
|
code: "feedback_claude_missing",
|
|
2908
3068
|
summary: "Claude CLI is not available on PATH.",
|
|
2909
3069
|
fixes: ["Install the Claude CLI before using `tela feedback --apply ...`."]
|
|
2910
3070
|
});
|
|
2911
3071
|
}
|
|
3072
|
+
if (!claudeInspection.supportsProjectScopedRun) {
|
|
3073
|
+
throw (0, errors_1.createUserFacingError)({
|
|
3074
|
+
code: "feedback_claude_version_unsupported",
|
|
3075
|
+
summary: "Claude CLI version does not support project-scoped feedback runs.",
|
|
3076
|
+
details: claudeInspection.detail,
|
|
3077
|
+
fixes: [
|
|
3078
|
+
"Update Claude CLI before using `tela feedback --apply ...`.",
|
|
3079
|
+
"Run `claude --version` to confirm the installed version."
|
|
3080
|
+
]
|
|
3081
|
+
});
|
|
3082
|
+
}
|
|
3083
|
+
claudeExecutablePath = claudeInspection.executablePath;
|
|
2912
3084
|
let selectedFeedbacks = selectionMode === "select" ? [] : actionableFeedbacks;
|
|
2913
3085
|
if (selectionMode === "select" && options.feedbackIds?.length) {
|
|
2914
3086
|
selectedFeedbacks = selectFeedbackEntriesById(feedbackEntries, options.feedbackIds);
|
|
@@ -3004,6 +3176,7 @@ var require_feedback = __commonJS({
|
|
|
3004
3176
|
await launchFeedbackClaude({
|
|
3005
3177
|
repoRoot: data.repoRoot,
|
|
3006
3178
|
prompt,
|
|
3179
|
+
claudeExecutablePath,
|
|
3007
3180
|
runInteractiveCommand: runInteractiveCommandFn
|
|
3008
3181
|
});
|
|
3009
3182
|
const diffStat = await getDiffStatAgainstHeadFn(repoRoot) || "<no local diff detected>";
|
|
@@ -3038,7 +3211,8 @@ var require_commit_message = __commonJS({
|
|
|
3038
3211
|
return input.split(/\r?\n/).map((line) => line.trim()).find(Boolean) ?? "";
|
|
3039
3212
|
}
|
|
3040
3213
|
async function generateCommitMessageWithClaude(context) {
|
|
3041
|
-
|
|
3214
|
+
const claudePath = await (0, process_1.resolveExecutable)("claude");
|
|
3215
|
+
if (!claudePath) {
|
|
3042
3216
|
throw new Error("Claude CLI is not available");
|
|
3043
3217
|
}
|
|
3044
3218
|
const prompt = `You are writing a git commit message for already staged changes.
|
|
@@ -3058,7 +3232,7 @@ Write exactly one short natural-language git commit message.
|
|
|
3058
3232
|
- Keep it concise
|
|
3059
3233
|
- Return only the commit message text`;
|
|
3060
3234
|
const result = await (0, process_1.runCommand)([
|
|
3061
|
-
|
|
3235
|
+
claudePath,
|
|
3062
3236
|
"-p",
|
|
3063
3237
|
prompt,
|
|
3064
3238
|
"--output-format",
|
|
@@ -3232,6 +3406,22 @@ ${error.result.stderr}`.toLowerCase();
|
|
|
3232
3406
|
}
|
|
3233
3407
|
});
|
|
3234
3408
|
|
|
3409
|
+
// ../../packages/agent/dist/shell.js
|
|
3410
|
+
var require_shell = __commonJS({
|
|
3411
|
+
"../../packages/agent/dist/shell.js"(exports2) {
|
|
3412
|
+
"use strict";
|
|
3413
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
3414
|
+
exports2.shellSingleQuote = shellSingleQuote;
|
|
3415
|
+
exports2.shellJoinCommand = shellJoinCommand;
|
|
3416
|
+
function shellSingleQuote(value) {
|
|
3417
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
3418
|
+
}
|
|
3419
|
+
function shellJoinCommand(command) {
|
|
3420
|
+
return command.map((argument) => shellSingleQuote(argument)).join(" ");
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3423
|
+
});
|
|
3424
|
+
|
|
3235
3425
|
// ../../packages/agent/dist/commands/run.js
|
|
3236
3426
|
var require_run = __commonJS({
|
|
3237
3427
|
"../../packages/agent/dist/commands/run.js"(exports2) {
|
|
@@ -3239,7 +3429,9 @@ var require_run = __commonJS({
|
|
|
3239
3429
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
3240
3430
|
exports2.readLocalAgentRunConfig = readLocalAgentRunConfig;
|
|
3241
3431
|
exports2.updateLocalAgentRunMode = updateLocalAgentRunMode;
|
|
3432
|
+
exports2.updateLocalAgentRunModel = updateLocalAgentRunModel;
|
|
3242
3433
|
exports2.buildLocalAgentClaudeCommand = buildLocalAgentClaudeCommand;
|
|
3434
|
+
exports2.buildLocalAgentClaudeLaunchCommand = buildLocalAgentClaudeLaunchCommand;
|
|
3243
3435
|
exports2.prepareLocalAgentRun = prepareLocalAgentRun;
|
|
3244
3436
|
exports2.parseRunInputAssignment = parseRunInputAssignment;
|
|
3245
3437
|
exports2.parseRunInputAssignments = parseRunInputAssignments;
|
|
@@ -3258,10 +3450,14 @@ var require_run = __commonJS({
|
|
|
3258
3450
|
var promises_1 = require("node:fs/promises");
|
|
3259
3451
|
var node_os_1 = require("node:os");
|
|
3260
3452
|
var node_path_1 = require("node:path");
|
|
3453
|
+
var agent_api_1 = require_agent_api();
|
|
3454
|
+
var auth_1 = require_auth2();
|
|
3261
3455
|
var claude_1 = require_claude();
|
|
3262
3456
|
var git_1 = require_git();
|
|
3263
3457
|
var errors_1 = require_errors();
|
|
3264
3458
|
var process_1 = require_process();
|
|
3459
|
+
var config_1 = require_config2();
|
|
3460
|
+
var shell_1 = require_shell();
|
|
3265
3461
|
var ui_1 = require_ui();
|
|
3266
3462
|
var INITIAL_PROMPT = "Follow the instructions and return the result.";
|
|
3267
3463
|
var REQUIRED_AGENT_FILES = [
|
|
@@ -4250,6 +4446,27 @@ ${detail.errors.join("\n")}` : summary);
|
|
|
4250
4446
|
isMultiturn: options.mode === "chat"
|
|
4251
4447
|
};
|
|
4252
4448
|
await (0, promises_1.writeFile)(agentConfig.path, `${JSON.stringify(updated, null, 2)}
|
|
4449
|
+
`);
|
|
4450
|
+
return parseAgentConfig("agent.config.json", JSON.stringify(updated));
|
|
4451
|
+
}
|
|
4452
|
+
async function updateLocalAgentRunModel(options) {
|
|
4453
|
+
const repoRoot = await resolveRepositoryRoot(options.cwd ?? process.cwd());
|
|
4454
|
+
const agentConfig = await readAgentConfigFile(repoRoot);
|
|
4455
|
+
const parsed = parseJsonObjectFile("agent.config.json", agentConfig.content, "agent.config.json must be a valid JSON object.");
|
|
4456
|
+
const model = options.model.trim();
|
|
4457
|
+
parseAgentConfig("agent.config.json", agentConfig.content);
|
|
4458
|
+
if (!model || !isOpenRouterModelId(model)) {
|
|
4459
|
+
throw (0, errors_1.createUserFacingError)({
|
|
4460
|
+
code: "run_openrouter_model_invalid",
|
|
4461
|
+
summary: "Choose an OpenRouter model id.",
|
|
4462
|
+
fixes: ["Use a provider-qualified OpenRouter model id, for example `openai/gpt-5.4`."]
|
|
4463
|
+
});
|
|
4464
|
+
}
|
|
4465
|
+
const updated = {
|
|
4466
|
+
...parsed,
|
|
4467
|
+
model
|
|
4468
|
+
};
|
|
4469
|
+
await (0, promises_1.writeFile)(agentConfig.path, `${JSON.stringify(updated, null, 2)}
|
|
4253
4470
|
`);
|
|
4254
4471
|
return parseAgentConfig("agent.config.json", JSON.stringify(updated));
|
|
4255
4472
|
}
|
|
@@ -4281,6 +4498,89 @@ ${detail.errors.join("\n")}` : summary);
|
|
|
4281
4498
|
verbose: mode === "one-shot"
|
|
4282
4499
|
});
|
|
4283
4500
|
}
|
|
4501
|
+
function isOpenRouterModelId(model) {
|
|
4502
|
+
return Boolean(model && model.includes("/"));
|
|
4503
|
+
}
|
|
4504
|
+
function buildOpenRouterProxyBaseUrl(agentApiUrl) {
|
|
4505
|
+
return new URL("/v3/openrouter", agentApiUrl.endsWith("/") ? agentApiUrl : `${agentApiUrl}/`).toString().replace(/\/$/, "");
|
|
4506
|
+
}
|
|
4507
|
+
function buildOpenRouterClaudeEnvironmentOverrides(model, dataToken, agentApiUrl) {
|
|
4508
|
+
const proxyBaseUrl = buildOpenRouterProxyBaseUrl(agentApiUrl);
|
|
4509
|
+
return {
|
|
4510
|
+
ANTHROPIC_BASE_URL: proxyBaseUrl,
|
|
4511
|
+
ANTHROPIC_AUTH_TOKEN: dataToken,
|
|
4512
|
+
ANTHROPIC_API_KEY: "",
|
|
4513
|
+
ANTHROPIC_DEFAULT_OPUS_MODEL: model,
|
|
4514
|
+
ANTHROPIC_DEFAULT_SONNET_MODEL: model,
|
|
4515
|
+
ANTHROPIC_DEFAULT_HAIKU_MODEL: model,
|
|
4516
|
+
CLAUDE_CODE_SUBAGENT_MODEL: model
|
|
4517
|
+
};
|
|
4518
|
+
}
|
|
4519
|
+
function redactClaudeEnvironmentOverrides(overrides) {
|
|
4520
|
+
return {
|
|
4521
|
+
...overrides,
|
|
4522
|
+
ANTHROPIC_AUTH_TOKEN: overrides.ANTHROPIC_AUTH_TOKEN === void 0 ? void 0 : "<redacted>"
|
|
4523
|
+
};
|
|
4524
|
+
}
|
|
4525
|
+
function buildRedactedClaudeShellCommand(command, environmentOverrides) {
|
|
4526
|
+
const unsetArgs = (0, claude_1.getProjectScopedClaudeEnvDenylist)().map((key) => `-u ${key}`);
|
|
4527
|
+
const setArgs = Object.entries(environmentOverrides).filter((entry) => entry[1] !== void 0).map(([key, value]) => `${key}=${(0, shell_1.shellSingleQuote)(value)}`);
|
|
4528
|
+
return ["env", ...unsetArgs, ...setArgs, (0, shell_1.shellJoinCommand)(command)].join(" ");
|
|
4529
|
+
}
|
|
4530
|
+
async function ensureOpenRouterModelAvailable(model, models) {
|
|
4531
|
+
if (models.some((candidate) => candidate.id === model)) {
|
|
4532
|
+
return;
|
|
4533
|
+
}
|
|
4534
|
+
throw (0, errors_1.createUserFacingError)({
|
|
4535
|
+
code: "run_openrouter_model_unavailable",
|
|
4536
|
+
summary: `OpenRouter model is not available through Tela: ${model}`,
|
|
4537
|
+
fixes: [
|
|
4538
|
+
"Use a model returned by `GET /v3/openrouter/models`.",
|
|
4539
|
+
"Update `agent.config.json` to a supported OpenRouter model id, for example `openai/gpt-5.4`."
|
|
4540
|
+
]
|
|
4541
|
+
});
|
|
4542
|
+
}
|
|
4543
|
+
async function buildLocalAgentClaudeLaunchCommand(prepared, mode, options = {}) {
|
|
4544
|
+
const command = buildLocalAgentClaudeCommand(prepared, mode);
|
|
4545
|
+
const baseEnv = (0, claude_1.buildProjectScopedClaudeEnvironment)(options.baseEnv);
|
|
4546
|
+
const model = prepared.config.model;
|
|
4547
|
+
if (!isOpenRouterModelId(model)) {
|
|
4548
|
+
return {
|
|
4549
|
+
command,
|
|
4550
|
+
env: baseEnv,
|
|
4551
|
+
environmentOverrides: {},
|
|
4552
|
+
redactedEnvironmentOverrides: {},
|
|
4553
|
+
redactedCommand: buildRedactedClaudeShellCommand(command, {}),
|
|
4554
|
+
provider: "anthropic",
|
|
4555
|
+
model
|
|
4556
|
+
};
|
|
4557
|
+
}
|
|
4558
|
+
const resolveConfigFn = options.resolveAgentConfig ?? config_1.resolveAgentConfig;
|
|
4559
|
+
const resolveDataTokenFn = options.resolveAgentApiDataToken ?? auth_1.resolveAgentApiDataToken;
|
|
4560
|
+
const fetchModelsFn = options.fetchOpenRouterModels ?? agent_api_1.fetchOpenRouterModels;
|
|
4561
|
+
const config = await resolveConfigFn();
|
|
4562
|
+
const dataToken = await resolveDataTokenFn(config, { fetchFn: options.fetch });
|
|
4563
|
+
const headers = {
|
|
4564
|
+
"x-data-token": dataToken,
|
|
4565
|
+
Accept: "application/json"
|
|
4566
|
+
};
|
|
4567
|
+
const models = await fetchModelsFn(config, options.fetch, { headers });
|
|
4568
|
+
await ensureOpenRouterModelAvailable(model, models);
|
|
4569
|
+
const environmentOverrides = buildOpenRouterClaudeEnvironmentOverrides(model, dataToken, config.agentApiUrl);
|
|
4570
|
+
const redactedEnvironmentOverrides = redactClaudeEnvironmentOverrides(environmentOverrides);
|
|
4571
|
+
return {
|
|
4572
|
+
command,
|
|
4573
|
+
env: {
|
|
4574
|
+
...baseEnv,
|
|
4575
|
+
...environmentOverrides
|
|
4576
|
+
},
|
|
4577
|
+
environmentOverrides,
|
|
4578
|
+
redactedEnvironmentOverrides,
|
|
4579
|
+
redactedCommand: buildRedactedClaudeShellCommand(command, redactedEnvironmentOverrides),
|
|
4580
|
+
provider: "openrouter",
|
|
4581
|
+
model
|
|
4582
|
+
};
|
|
4583
|
+
}
|
|
4284
4584
|
async function resolveRepositoryRoot(cwd) {
|
|
4285
4585
|
try {
|
|
4286
4586
|
return await (0, git_1.getRepositoryRoot)(cwd);
|
|
@@ -4342,7 +4642,9 @@ ${detail.errors.join("\n")}` : summary);
|
|
|
4342
4642
|
const outputFormat = parseJsonObjectFile("output-format.json", outputFormatContent, "output-format.json must be a valid JSON object.");
|
|
4343
4643
|
const config = parseAgentConfig("agent.config.json", agentConfigContent);
|
|
4344
4644
|
const resultKind = Object.keys(outputFormat).length > 0 ? "json" : "markdown";
|
|
4345
|
-
const claudeLaunch = await (0, claude_1.prepareProjectScopedClaudeLaunch)(repoRoot
|
|
4645
|
+
const claudeLaunch = await (0, claude_1.prepareProjectScopedClaudeLaunch)(repoRoot, {
|
|
4646
|
+
claudeExecutablePath: claudeInspection.executablePath
|
|
4647
|
+
});
|
|
4346
4648
|
return {
|
|
4347
4649
|
repoRoot,
|
|
4348
4650
|
config,
|
|
@@ -4999,7 +5301,7 @@ Input folder: ${comparableInputRoot}`,
|
|
|
4999
5301
|
inputs
|
|
5000
5302
|
};
|
|
5001
5303
|
}
|
|
5002
|
-
async function runInteractiveAgent(prepared, runInteractiveCommandFn, options) {
|
|
5304
|
+
async function runInteractiveAgent(prepared, claudeLaunch, runInteractiveCommandFn, options) {
|
|
5003
5305
|
if (options.surface === "json") {
|
|
5004
5306
|
throw (0, errors_1.createUserFacingError)({
|
|
5005
5307
|
code: "run_multiturn_json_unsupported",
|
|
@@ -5019,12 +5321,12 @@ Input folder: ${comparableInputRoot}`,
|
|
|
5019
5321
|
if (options.surface === "plain") {
|
|
5020
5322
|
writeLine2(options.writeStdout, "Launching Claude in interactive chat mode. Tela will resume after Claude exits.");
|
|
5021
5323
|
}
|
|
5022
|
-
await runInteractiveCommandFn(
|
|
5324
|
+
await runInteractiveCommandFn(claudeLaunch.command, {
|
|
5023
5325
|
cwd: prepared.repoRoot,
|
|
5024
|
-
env:
|
|
5326
|
+
env: claudeLaunch.env
|
|
5025
5327
|
});
|
|
5026
5328
|
}
|
|
5027
|
-
async function runOneShotAgent(prepared, options, tracker) {
|
|
5329
|
+
async function runOneShotAgent(prepared, options, tracker, claudeLaunch) {
|
|
5028
5330
|
const plainRenderer = new PlainTranscriptRenderer();
|
|
5029
5331
|
const runStreamingCommandFn = options.runStreamingCommand ?? process_1.runStreamingCommand;
|
|
5030
5332
|
const spawnStreamingCommandFn = options.spawnStreamingCommand ?? ((command2, spawnOptions) => ({
|
|
@@ -5042,10 +5344,10 @@ Input folder: ${comparableInputRoot}`,
|
|
|
5042
5344
|
writeLine2(options.writeStdout, "Streaming Claude execution in one-shot mode.");
|
|
5043
5345
|
}
|
|
5044
5346
|
let cancelled = false;
|
|
5045
|
-
const command =
|
|
5347
|
+
const command = claudeLaunch.command;
|
|
5046
5348
|
const handle = spawnStreamingCommandFn(command, {
|
|
5047
5349
|
cwd: prepared.repoRoot,
|
|
5048
|
-
env:
|
|
5350
|
+
env: claudeLaunch.env,
|
|
5049
5351
|
allowFailure: true,
|
|
5050
5352
|
onStdoutLine: async (line) => {
|
|
5051
5353
|
const trimmed = line.trim();
|
|
@@ -5132,26 +5434,32 @@ Input folder: ${comparableInputRoot}`,
|
|
|
5132
5434
|
isMultiturn: options.mode === "chat"
|
|
5133
5435
|
}
|
|
5134
5436
|
} : preparedBase;
|
|
5437
|
+
const mode = prepared.config.isMultiturn ? "chat" : "one-shot";
|
|
5438
|
+
const claudeLaunch = await buildLocalAgentClaudeLaunchCommand(prepared, mode, {
|
|
5439
|
+
resolveAgentConfig: options.resolveAgentConfig,
|
|
5440
|
+
fetchOpenRouterModels: options.fetchOpenRouterModels,
|
|
5441
|
+
resolveAgentApiDataToken: options.resolveAgentApiDataToken,
|
|
5442
|
+
fetch: options.fetch
|
|
5443
|
+
});
|
|
5135
5444
|
const inputs = await prepareLocalAgentRunInputsForLaunch(prepared, {
|
|
5136
5445
|
cwd: options.cwd,
|
|
5137
5446
|
inputAssignments: options.inputAssignments,
|
|
5138
5447
|
stagedInputs: options.stagedInputs,
|
|
5139
5448
|
resolveInputConflict: options.resolveInputConflict
|
|
5140
5449
|
});
|
|
5141
|
-
const mode = prepared.config.isMultiturn ? "chat" : "one-shot";
|
|
5142
5450
|
const tracker = new RunStateTracker(prepared, mode);
|
|
5143
5451
|
const agentRunsRoot = options.agentRunsRoot ?? getDefaultAgentRunsRoot();
|
|
5144
5452
|
let snapshot = tracker.snapshot();
|
|
5145
5453
|
effectiveOptions.onSnapshot?.(snapshot);
|
|
5146
5454
|
try {
|
|
5147
5455
|
if (prepared.config.isMultiturn) {
|
|
5148
|
-
await runInteractiveAgent(prepared, options.runInteractiveCommand ?? process_1.runInteractiveCommand, effectiveOptions);
|
|
5456
|
+
await runInteractiveAgent(prepared, claudeLaunch, options.runInteractiveCommand ?? process_1.runInteractiveCommand, effectiveOptions);
|
|
5149
5457
|
snapshot = tracker.finalize("success", {
|
|
5150
5458
|
summary: "Claude chat exited. Reading result artifact\u2026"
|
|
5151
5459
|
});
|
|
5152
5460
|
effectiveOptions.onSnapshot?.(snapshot);
|
|
5153
5461
|
} else {
|
|
5154
|
-
snapshot = await runOneShotAgent(prepared, effectiveOptions, tracker);
|
|
5462
|
+
snapshot = await runOneShotAgent(prepared, effectiveOptions, tracker, claudeLaunch);
|
|
5155
5463
|
}
|
|
5156
5464
|
} catch (error) {
|
|
5157
5465
|
let terminalSnapshot = tracker.snapshot();
|
|
@@ -5741,6 +6049,7 @@ var require_cli = __commonJS({
|
|
|
5741
6049
|
var sync_1 = require_sync();
|
|
5742
6050
|
var config_1 = require_config2();
|
|
5743
6051
|
var errors_1 = require_errors();
|
|
6052
|
+
var claude_1 = require_claude();
|
|
5744
6053
|
var git_1 = require_git();
|
|
5745
6054
|
var process_1 = require_process();
|
|
5746
6055
|
var setup_1 = require_setup();
|
|
@@ -6419,15 +6728,28 @@ var require_cli = __commonJS({
|
|
|
6419
6728
|
write(io.stdout, renderFeedbackResult(result2));
|
|
6420
6729
|
return 0;
|
|
6421
6730
|
}
|
|
6422
|
-
|
|
6731
|
+
const claudeInspection = await (0, claude_1.inspectClaudeCli)();
|
|
6732
|
+
if (!claudeInspection.available) {
|
|
6423
6733
|
throw (0, errors_1.createUserFacingError)({
|
|
6424
6734
|
code: "feedback_claude_missing",
|
|
6425
6735
|
summary: "Claude CLI is not available on PATH."
|
|
6426
6736
|
});
|
|
6427
6737
|
}
|
|
6738
|
+
if (!claudeInspection.supportsProjectScopedRun) {
|
|
6739
|
+
throw (0, errors_1.createUserFacingError)({
|
|
6740
|
+
code: "feedback_claude_version_unsupported",
|
|
6741
|
+
summary: "Claude CLI version does not support project-scoped feedback runs.",
|
|
6742
|
+
details: claudeInspection.detail,
|
|
6743
|
+
fixes: [
|
|
6744
|
+
"Update Claude CLI before using `tela agent feedback`.",
|
|
6745
|
+
"Run `claude --version` to confirm the installed version."
|
|
6746
|
+
]
|
|
6747
|
+
});
|
|
6748
|
+
}
|
|
6428
6749
|
const selectedFeedbacks = data.actionableEntries;
|
|
6429
6750
|
await (0, feedback_1.launchFeedbackClaude)({
|
|
6430
6751
|
repoRoot: data.repoRoot,
|
|
6752
|
+
claudeExecutablePath: claudeInspection.executablePath,
|
|
6431
6753
|
prompt: (0, feedback_1.buildClaudeFeedbackPrompt)({
|
|
6432
6754
|
repoRoot: data.repoRoot,
|
|
6433
6755
|
organizationName: data.organizationName,
|
|
@@ -6641,6 +6963,7 @@ var require_dist2 = __commonJS({
|
|
|
6641
6963
|
__exportStar(require_git(), exports2);
|
|
6642
6964
|
__exportStar(require_process(), exports2);
|
|
6643
6965
|
__exportStar(require_setup(), exports2);
|
|
6966
|
+
__exportStar(require_shell(), exports2);
|
|
6644
6967
|
__exportStar(require_types2(), exports2);
|
|
6645
6968
|
}
|
|
6646
6969
|
});
|