@meistrari/tela-cli 0.7.29 → 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 +177 -16
- 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);
|
|
@@ -1906,7 +2025,7 @@ var require_claude = __commonJS({
|
|
|
1906
2025
|
}
|
|
1907
2026
|
return tools;
|
|
1908
2027
|
}
|
|
1909
|
-
async function prepareProjectScopedClaudeLaunch(repoRoot) {
|
|
2028
|
+
async function prepareProjectScopedClaudeLaunch(repoRoot, options = {}) {
|
|
1910
2029
|
const settingsPath = (0, node_path_1.join)(repoRoot, ".claude", "settings.json");
|
|
1911
2030
|
let settingsContent;
|
|
1912
2031
|
try {
|
|
@@ -1932,12 +2051,13 @@ var require_claude = __commonJS({
|
|
|
1932
2051
|
settingsPath,
|
|
1933
2052
|
allowedTools,
|
|
1934
2053
|
mcpConfig: (0, node_fs_1.existsSync)(mcpConfigPath) ? mcpConfigPath : EMPTY_MCP_CONFIG,
|
|
1935
|
-
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
|
|
1936
2056
|
};
|
|
1937
2057
|
}
|
|
1938
2058
|
function buildProjectScopedClaudeCommand(launch, options = {}) {
|
|
1939
2059
|
const command = [
|
|
1940
|
-
"claude",
|
|
2060
|
+
launch.claudeExecutablePath ?? "claude",
|
|
1941
2061
|
"--setting-sources",
|
|
1942
2062
|
"project",
|
|
1943
2063
|
"--permission-mode",
|
|
@@ -1999,9 +2119,10 @@ var require_claude = __commonJS({
|
|
|
1999
2119
|
};
|
|
2000
2120
|
}
|
|
2001
2121
|
async function inspectClaudeCli(options = {}) {
|
|
2002
|
-
const
|
|
2122
|
+
const resolveExecutableFn = options.resolveExecutableFn ?? process_1.resolveExecutable;
|
|
2003
2123
|
const runCommandFn = options.runCommandFn ?? process_1.runCommand;
|
|
2004
|
-
|
|
2124
|
+
const executablePath = options.commandExistsFn ? await options.commandExistsFn("claude") ? "claude" : null : await resolveExecutableFn("claude");
|
|
2125
|
+
if (!executablePath) {
|
|
2005
2126
|
return {
|
|
2006
2127
|
available: false,
|
|
2007
2128
|
supportsProjectScopedRun: false,
|
|
@@ -2009,13 +2130,14 @@ var require_claude = __commonJS({
|
|
|
2009
2130
|
detail: "`claude` is not available on PATH."
|
|
2010
2131
|
};
|
|
2011
2132
|
}
|
|
2012
|
-
const result = await runCommandFn([
|
|
2133
|
+
const result = await runCommandFn([executablePath, "--version"], { allowFailure: true });
|
|
2013
2134
|
const output = `${result.stdout}
|
|
2014
2135
|
${result.stderr}`.trim();
|
|
2015
2136
|
const parsedVersion = parseClaudeCliVersion(output);
|
|
2016
2137
|
if (!parsedVersion) {
|
|
2017
2138
|
return {
|
|
2018
2139
|
available: true,
|
|
2140
|
+
executablePath,
|
|
2019
2141
|
supportsProjectScopedRun: false,
|
|
2020
2142
|
problem: "unparseable",
|
|
2021
2143
|
detail: output || "Claude CLI version output was empty."
|
|
@@ -2025,6 +2147,7 @@ ${result.stderr}`.trim();
|
|
|
2025
2147
|
if (compareClaudeCliVersions(parsedVersion, exports2.MIN_CLAUDE_VERSION_FOR_PROJECT_SCOPED_RUN) < 0) {
|
|
2026
2148
|
return {
|
|
2027
2149
|
available: true,
|
|
2150
|
+
executablePath,
|
|
2028
2151
|
version,
|
|
2029
2152
|
parsedVersion,
|
|
2030
2153
|
supportsProjectScopedRun: false,
|
|
@@ -2034,6 +2157,7 @@ ${result.stderr}`.trim();
|
|
|
2034
2157
|
}
|
|
2035
2158
|
return {
|
|
2036
2159
|
available: true,
|
|
2160
|
+
executablePath,
|
|
2037
2161
|
version,
|
|
2038
2162
|
parsedVersion,
|
|
2039
2163
|
supportsProjectScopedRun: true,
|
|
@@ -2869,7 +2993,9 @@ var require_feedback = __commonJS({
|
|
|
2869
2993
|
}
|
|
2870
2994
|
async function launchFeedbackClaude(options) {
|
|
2871
2995
|
const runInteractiveCommandFn = options.runInteractiveCommand ?? process_1.runInteractiveCommand;
|
|
2872
|
-
const launch = await (0, claude_1.prepareProjectScopedClaudeLaunch)(options.repoRoot
|
|
2996
|
+
const launch = await (0, claude_1.prepareProjectScopedClaudeLaunch)(options.repoRoot, {
|
|
2997
|
+
claudeExecutablePath: options.claudeExecutablePath
|
|
2998
|
+
});
|
|
2873
2999
|
const command = (0, claude_1.buildProjectScopedClaudeCommand)(launch, {
|
|
2874
3000
|
prompt: options.prompt
|
|
2875
3001
|
});
|
|
@@ -2907,7 +3033,10 @@ var require_feedback = __commonJS({
|
|
|
2907
3033
|
const getOriginUrlFn = options.getOriginUrl ?? git_1.getOriginUrl;
|
|
2908
3034
|
const getHeadCommitHashFn = options.getHeadCommitHash ?? git_1.getHeadCommitHash;
|
|
2909
3035
|
const getDiffStatAgainstHeadFn = options.getDiffStatAgainstHead ?? git_1.getDiffStatAgainstHead;
|
|
2910
|
-
const
|
|
3036
|
+
const inspectClaudeCliFn = options.inspectClaudeCli ?? (async () => await (0, claude_1.inspectClaudeCli)({
|
|
3037
|
+
commandExistsFn: options.commandExists,
|
|
3038
|
+
runCommandFn: options.runCommand
|
|
3039
|
+
}));
|
|
2911
3040
|
const runInteractiveCommandFn = options.runInteractiveCommand ?? process_1.runInteractiveCommand;
|
|
2912
3041
|
const selectionMode = getFeedbackSelectionMode(options);
|
|
2913
3042
|
const config = await ensureConfig();
|
|
@@ -2931,13 +3060,27 @@ var require_feedback = __commonJS({
|
|
|
2931
3060
|
launchedClaude: false
|
|
2932
3061
|
});
|
|
2933
3062
|
}
|
|
2934
|
-
|
|
3063
|
+
let claudeExecutablePath;
|
|
3064
|
+
const claudeInspection = await inspectClaudeCliFn();
|
|
3065
|
+
if (!claudeInspection.available) {
|
|
2935
3066
|
throw (0, errors_1.createUserFacingError)({
|
|
2936
3067
|
code: "feedback_claude_missing",
|
|
2937
3068
|
summary: "Claude CLI is not available on PATH.",
|
|
2938
3069
|
fixes: ["Install the Claude CLI before using `tela feedback --apply ...`."]
|
|
2939
3070
|
});
|
|
2940
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;
|
|
2941
3084
|
let selectedFeedbacks = selectionMode === "select" ? [] : actionableFeedbacks;
|
|
2942
3085
|
if (selectionMode === "select" && options.feedbackIds?.length) {
|
|
2943
3086
|
selectedFeedbacks = selectFeedbackEntriesById(feedbackEntries, options.feedbackIds);
|
|
@@ -3033,6 +3176,7 @@ var require_feedback = __commonJS({
|
|
|
3033
3176
|
await launchFeedbackClaude({
|
|
3034
3177
|
repoRoot: data.repoRoot,
|
|
3035
3178
|
prompt,
|
|
3179
|
+
claudeExecutablePath,
|
|
3036
3180
|
runInteractiveCommand: runInteractiveCommandFn
|
|
3037
3181
|
});
|
|
3038
3182
|
const diffStat = await getDiffStatAgainstHeadFn(repoRoot) || "<no local diff detected>";
|
|
@@ -3067,7 +3211,8 @@ var require_commit_message = __commonJS({
|
|
|
3067
3211
|
return input.split(/\r?\n/).map((line) => line.trim()).find(Boolean) ?? "";
|
|
3068
3212
|
}
|
|
3069
3213
|
async function generateCommitMessageWithClaude(context) {
|
|
3070
|
-
|
|
3214
|
+
const claudePath = await (0, process_1.resolveExecutable)("claude");
|
|
3215
|
+
if (!claudePath) {
|
|
3071
3216
|
throw new Error("Claude CLI is not available");
|
|
3072
3217
|
}
|
|
3073
3218
|
const prompt = `You are writing a git commit message for already staged changes.
|
|
@@ -3087,7 +3232,7 @@ Write exactly one short natural-language git commit message.
|
|
|
3087
3232
|
- Keep it concise
|
|
3088
3233
|
- Return only the commit message text`;
|
|
3089
3234
|
const result = await (0, process_1.runCommand)([
|
|
3090
|
-
|
|
3235
|
+
claudePath,
|
|
3091
3236
|
"-p",
|
|
3092
3237
|
prompt,
|
|
3093
3238
|
"--output-format",
|
|
@@ -4497,7 +4642,9 @@ ${detail.errors.join("\n")}` : summary);
|
|
|
4497
4642
|
const outputFormat = parseJsonObjectFile("output-format.json", outputFormatContent, "output-format.json must be a valid JSON object.");
|
|
4498
4643
|
const config = parseAgentConfig("agent.config.json", agentConfigContent);
|
|
4499
4644
|
const resultKind = Object.keys(outputFormat).length > 0 ? "json" : "markdown";
|
|
4500
|
-
const claudeLaunch = await (0, claude_1.prepareProjectScopedClaudeLaunch)(repoRoot
|
|
4645
|
+
const claudeLaunch = await (0, claude_1.prepareProjectScopedClaudeLaunch)(repoRoot, {
|
|
4646
|
+
claudeExecutablePath: claudeInspection.executablePath
|
|
4647
|
+
});
|
|
4501
4648
|
return {
|
|
4502
4649
|
repoRoot,
|
|
4503
4650
|
config,
|
|
@@ -5902,6 +6049,7 @@ var require_cli = __commonJS({
|
|
|
5902
6049
|
var sync_1 = require_sync();
|
|
5903
6050
|
var config_1 = require_config2();
|
|
5904
6051
|
var errors_1 = require_errors();
|
|
6052
|
+
var claude_1 = require_claude();
|
|
5905
6053
|
var git_1 = require_git();
|
|
5906
6054
|
var process_1 = require_process();
|
|
5907
6055
|
var setup_1 = require_setup();
|
|
@@ -6580,15 +6728,28 @@ var require_cli = __commonJS({
|
|
|
6580
6728
|
write(io.stdout, renderFeedbackResult(result2));
|
|
6581
6729
|
return 0;
|
|
6582
6730
|
}
|
|
6583
|
-
|
|
6731
|
+
const claudeInspection = await (0, claude_1.inspectClaudeCli)();
|
|
6732
|
+
if (!claudeInspection.available) {
|
|
6584
6733
|
throw (0, errors_1.createUserFacingError)({
|
|
6585
6734
|
code: "feedback_claude_missing",
|
|
6586
6735
|
summary: "Claude CLI is not available on PATH."
|
|
6587
6736
|
});
|
|
6588
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
|
+
}
|
|
6589
6749
|
const selectedFeedbacks = data.actionableEntries;
|
|
6590
6750
|
await (0, feedback_1.launchFeedbackClaude)({
|
|
6591
6751
|
repoRoot: data.repoRoot,
|
|
6752
|
+
claudeExecutablePath: claudeInspection.executablePath,
|
|
6592
6753
|
prompt: (0, feedback_1.buildClaudeFeedbackPrompt)({
|
|
6593
6754
|
repoRoot: data.repoRoot,
|
|
6594
6755
|
organizationName: data.organizationName,
|