@meistrari/tela-cli 0.7.44 → 0.7.46
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 +333 -63
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1642,6 +1642,9 @@ var require_agent_api = __commonJS({
|
|
|
1642
1642
|
exports2.fetchRepositoryLookup = fetchRepositoryLookup;
|
|
1643
1643
|
exports2.fetchCommitFeedback = fetchCommitFeedback;
|
|
1644
1644
|
exports2.listTelaAgents = listTelaAgents;
|
|
1645
|
+
exports2.listAgentRunHistory = listAgentRunHistory;
|
|
1646
|
+
exports2.fetchAgentRunDetail = fetchAgentRunDetail;
|
|
1647
|
+
exports2.searchAgentRuns = searchAgentRuns;
|
|
1645
1648
|
exports2.listAvailableRepositories = listAvailableRepositories;
|
|
1646
1649
|
var tela_local_config_1 = require_dist();
|
|
1647
1650
|
var auth_1 = require_auth2();
|
|
@@ -1853,6 +1856,82 @@ var require_agent_api = __commonJS({
|
|
|
1853
1856
|
}
|
|
1854
1857
|
return payload.data;
|
|
1855
1858
|
}
|
|
1859
|
+
function isAgentRunHistoryItem(value) {
|
|
1860
|
+
if (!value || typeof value !== "object") {
|
|
1861
|
+
return false;
|
|
1862
|
+
}
|
|
1863
|
+
const candidate = value;
|
|
1864
|
+
return typeof candidate.id === "string" && typeof candidate.sessionId === "string" && typeof candidate.status === "string" && typeof candidate.provider === "string" && (typeof candidate.calculatedCostUsd === "number" || candidate.calculatedCostUsd === null) && typeof candidate.executionSurface === "string" && typeof candidate.createdAt === "string";
|
|
1865
|
+
}
|
|
1866
|
+
async function listAgentRunHistory(config, options, fetchFn = fetch) {
|
|
1867
|
+
const headers = await (0, auth_1.buildAgentApiHeaders)(config, { fetchFn });
|
|
1868
|
+
const url = new URL(joinUrl2(config.agentApiUrl, "/v3/runs"));
|
|
1869
|
+
if (options?.agentRepoId) {
|
|
1870
|
+
url.searchParams.set("agentRepoId", options.agentRepoId);
|
|
1871
|
+
}
|
|
1872
|
+
if (options?.status) {
|
|
1873
|
+
url.searchParams.set("status", options.status);
|
|
1874
|
+
}
|
|
1875
|
+
if (options?.cursor) {
|
|
1876
|
+
url.searchParams.set("cursor", options.cursor);
|
|
1877
|
+
}
|
|
1878
|
+
if (options?.limit != null) {
|
|
1879
|
+
url.searchParams.set("limit", String(options.limit));
|
|
1880
|
+
}
|
|
1881
|
+
const response = await fetchFn(url.toString(), {
|
|
1882
|
+
method: "GET",
|
|
1883
|
+
headers,
|
|
1884
|
+
signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS)
|
|
1885
|
+
});
|
|
1886
|
+
const responseText = await response.text();
|
|
1887
|
+
const payload = parseJsonBody(responseText);
|
|
1888
|
+
if (!response.ok) {
|
|
1889
|
+
throw new AgentApiError(payload?.error ?? `Agent API run history listing failed with status ${response.status}`, response.status, responseText);
|
|
1890
|
+
}
|
|
1891
|
+
if (!payload || !Array.isArray(payload.runs) || !payload.runs.every(isAgentRunHistoryItem)) {
|
|
1892
|
+
throw new AgentApiError("Agent API run history listing returned an invalid payload", response.status, responseText);
|
|
1893
|
+
}
|
|
1894
|
+
return {
|
|
1895
|
+
runs: payload.runs,
|
|
1896
|
+
nextCursor: payload.nextCursor ?? null
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
async function fetchAgentRunDetail(runId, config, fetchFn = fetch) {
|
|
1900
|
+
const headers = await (0, auth_1.buildAgentApiHeaders)(config, { fetchFn });
|
|
1901
|
+
const response = await fetchFn(joinUrl2(config.agentApiUrl, `/v3/runs/${encodeURIComponent(runId)}`), {
|
|
1902
|
+
method: "GET",
|
|
1903
|
+
headers,
|
|
1904
|
+
signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS)
|
|
1905
|
+
});
|
|
1906
|
+
const responseText = await response.text();
|
|
1907
|
+
const payload = parseJsonBody(responseText);
|
|
1908
|
+
if (!response.ok) {
|
|
1909
|
+
throw new AgentApiError(payload?.error ?? `Agent API run detail failed with status ${response.status}`, response.status, responseText);
|
|
1910
|
+
}
|
|
1911
|
+
if (!payload || !isAgentRunHistoryItem(payload)) {
|
|
1912
|
+
throw new AgentApiError("Agent API run detail returned an invalid payload", response.status, responseText);
|
|
1913
|
+
}
|
|
1914
|
+
return payload;
|
|
1915
|
+
}
|
|
1916
|
+
async function searchAgentRuns(query, config, options, fetchFn = fetch) {
|
|
1917
|
+
const headers = await (0, auth_1.buildAgentApiHeaders)(config, { fetchFn });
|
|
1918
|
+
const url = new URL(joinUrl2(config.agentApiUrl, "/v3/runs/search"));
|
|
1919
|
+
url.searchParams.set("q", query);
|
|
1920
|
+
if (options?.limit != null) {
|
|
1921
|
+
url.searchParams.set("limit", String(options.limit));
|
|
1922
|
+
}
|
|
1923
|
+
const response = await fetchFn(url.toString(), {
|
|
1924
|
+
method: "GET",
|
|
1925
|
+
headers,
|
|
1926
|
+
signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS)
|
|
1927
|
+
});
|
|
1928
|
+
const responseText = await response.text();
|
|
1929
|
+
const payload = parseJsonBody(responseText);
|
|
1930
|
+
if (!response.ok) {
|
|
1931
|
+
throw new AgentApiError(payload?.error ?? `Agent API run search failed with status ${response.status}`, response.status, responseText);
|
|
1932
|
+
}
|
|
1933
|
+
return payload ?? { results: [] };
|
|
1934
|
+
}
|
|
1856
1935
|
async function listAvailableRepositories(config, fetchFn = fetch) {
|
|
1857
1936
|
const headers = await (0, auth_1.buildAgentApiHeaders)(config, { fetchFn });
|
|
1858
1937
|
const response = await fetchFn(joinUrl2(config.agentApiUrl, "/v3/agents/repositories"), {
|
|
@@ -2267,12 +2346,14 @@ var require_git = __commonJS({
|
|
|
2267
2346
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
2268
2347
|
exports2.buildGitSshCommand = buildGitSshCommand;
|
|
2269
2348
|
exports2.isSshRemoteUrl = isSshRemoteUrl;
|
|
2349
|
+
exports2.getRemoteUrl = getRemoteUrl;
|
|
2270
2350
|
exports2.findRepositoryRoot = findRepositoryRoot;
|
|
2271
2351
|
exports2.getRepositoryRoot = getRepositoryRoot;
|
|
2272
2352
|
exports2.assertGitRepository = assertGitRepository;
|
|
2273
2353
|
exports2.cloneRepository = cloneRepository;
|
|
2274
2354
|
exports2.getOriginUrl = getOriginUrl;
|
|
2275
2355
|
exports2.fetchOrigin = fetchOrigin;
|
|
2356
|
+
exports2.fetchRemote = fetchRemote;
|
|
2276
2357
|
exports2.fetchAllRemotes = fetchAllRemotes;
|
|
2277
2358
|
exports2.getWorktreeStatus = getWorktreeStatus;
|
|
2278
2359
|
exports2.isWorktreeDirty = isWorktreeDirty;
|
|
@@ -2281,6 +2362,10 @@ var require_git = __commonJS({
|
|
|
2281
2362
|
exports2.unstageMatching = unstageMatching;
|
|
2282
2363
|
exports2.getCurrentBranch = getCurrentBranch;
|
|
2283
2364
|
exports2.getUpstreamBranch = getUpstreamBranch;
|
|
2365
|
+
exports2.getPushBranch = getPushBranch;
|
|
2366
|
+
exports2.refExists = refExists;
|
|
2367
|
+
exports2.getAheadBehind = getAheadBehind;
|
|
2368
|
+
exports2.getCommitCount = getCommitCount;
|
|
2284
2369
|
exports2.pullCurrentBranch = pullCurrentBranch;
|
|
2285
2370
|
exports2.pullDefaultBranch = pullDefaultBranch;
|
|
2286
2371
|
exports2.getShortStatus = getShortStatus;
|
|
@@ -2348,6 +2433,9 @@ var require_git = __commonJS({
|
|
|
2348
2433
|
}
|
|
2349
2434
|
return result.stdout.trim() || null;
|
|
2350
2435
|
}
|
|
2436
|
+
async function getRemoteUrl(cwd, remote) {
|
|
2437
|
+
return await getRemoteUrlInternal(cwd, remote);
|
|
2438
|
+
}
|
|
2351
2439
|
async function remoteRequiresConfiguredSsh(cwd, remote) {
|
|
2352
2440
|
const remoteUrl = await getRemoteUrlInternal(cwd, remote);
|
|
2353
2441
|
return Boolean(remoteUrl && isSshRemoteUrl(remoteUrl));
|
|
@@ -2420,6 +2508,14 @@ var require_git = __commonJS({
|
|
|
2420
2508
|
sshHostKeyPolicy: "accept-new"
|
|
2421
2509
|
});
|
|
2422
2510
|
}
|
|
2511
|
+
async function fetchRemote(cwd, remote, sshPrivateKeyPath) {
|
|
2512
|
+
await runGitCommand(["fetch", remote, "--prune"], {
|
|
2513
|
+
cwd,
|
|
2514
|
+
requireConfiguredSsh: await remoteRequiresConfiguredSsh(cwd, remote),
|
|
2515
|
+
sshPrivateKeyPath,
|
|
2516
|
+
sshHostKeyPolicy: "accept-new"
|
|
2517
|
+
});
|
|
2518
|
+
}
|
|
2423
2519
|
async function fetchAllRemotes(cwd, sshPrivateKeyPath) {
|
|
2424
2520
|
await runGitCommand(["fetch", "--all", "--prune"], {
|
|
2425
2521
|
cwd,
|
|
@@ -2465,6 +2561,38 @@ var require_git = __commonJS({
|
|
|
2465
2561
|
}
|
|
2466
2562
|
return result.stdout.trim() || null;
|
|
2467
2563
|
}
|
|
2564
|
+
async function getPushBranch(cwd) {
|
|
2565
|
+
const result = await runGitCommand(["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{push}"], { cwd, allowFailure: true });
|
|
2566
|
+
if (result.exitCode !== 0) {
|
|
2567
|
+
return null;
|
|
2568
|
+
}
|
|
2569
|
+
return result.stdout.trim() || null;
|
|
2570
|
+
}
|
|
2571
|
+
async function refExists(cwd, ref) {
|
|
2572
|
+
const result = await runGitCommand(["rev-parse", "--verify", "--quiet", ref], {
|
|
2573
|
+
cwd,
|
|
2574
|
+
allowFailure: true
|
|
2575
|
+
});
|
|
2576
|
+
return result.exitCode === 0;
|
|
2577
|
+
}
|
|
2578
|
+
async function getAheadBehind(cwd, ref) {
|
|
2579
|
+
if (!await refExists(cwd, ref)) {
|
|
2580
|
+
return { aheadCount: 0, behindCount: 0 };
|
|
2581
|
+
}
|
|
2582
|
+
const result = await runGitCommand(["rev-list", "--left-right", "--count", `HEAD...${ref}`], { cwd });
|
|
2583
|
+
const [aheadRaw, behindRaw] = result.stdout.trim().split(/\s+/);
|
|
2584
|
+
return {
|
|
2585
|
+
aheadCount: Number.parseInt(aheadRaw ?? "0", 10) || 0,
|
|
2586
|
+
behindCount: Number.parseInt(behindRaw ?? "0", 10) || 0
|
|
2587
|
+
};
|
|
2588
|
+
}
|
|
2589
|
+
async function getCommitCount(cwd, ref = "HEAD") {
|
|
2590
|
+
const result = await runGitCommand(["rev-list", "--count", ref], { cwd, allowFailure: true });
|
|
2591
|
+
if (result.exitCode !== 0) {
|
|
2592
|
+
return 0;
|
|
2593
|
+
}
|
|
2594
|
+
return Number.parseInt(result.stdout.trim(), 10) || 0;
|
|
2595
|
+
}
|
|
2468
2596
|
async function pullCurrentBranch(cwd, sshPrivateKeyPath) {
|
|
2469
2597
|
await runGitCommand(["pull", "--ff-only"], {
|
|
2470
2598
|
cwd,
|
|
@@ -2555,26 +2683,27 @@ var require_git = __commonJS({
|
|
|
2555
2683
|
}
|
|
2556
2684
|
function buildFallbackCommitMessage(files) {
|
|
2557
2685
|
if (files.length === 0) {
|
|
2558
|
-
return "
|
|
2686
|
+
return "chore: update repository files";
|
|
2559
2687
|
}
|
|
2560
2688
|
if (files.length === 1) {
|
|
2561
|
-
return `
|
|
2689
|
+
return `chore: update ${(0, node_path_1.basename)(files[0]) || files[0]}`;
|
|
2562
2690
|
}
|
|
2563
|
-
return `
|
|
2691
|
+
return `chore: update ${(0, node_path_1.basename)(files[0]) || files[0]} and ${files.length - 1} other files`;
|
|
2564
2692
|
}
|
|
2565
2693
|
async function commitWithMessage(cwd, message) {
|
|
2566
|
-
await runGitCommand(["commit", "-F", "-"], {
|
|
2694
|
+
await runGitCommand(["commit", "--no-verify", "-F", "-"], {
|
|
2567
2695
|
cwd,
|
|
2568
2696
|
input: message
|
|
2569
2697
|
});
|
|
2570
2698
|
}
|
|
2571
|
-
async function pushBranch(cwd, branch, setUpstream, sshPrivateKeyPath) {
|
|
2572
|
-
const args = setUpstream ? ["push", "--set-upstream",
|
|
2573
|
-
const requireConfiguredSsh = setUpstream ? await remoteRequiresConfiguredSsh(cwd,
|
|
2699
|
+
async function pushBranch(cwd, branch, setUpstream, sshPrivateKeyPath, remote = "origin") {
|
|
2700
|
+
const args = setUpstream ? ["push", "--set-upstream", remote, branch] : ["push"];
|
|
2701
|
+
const requireConfiguredSsh = sshPrivateKeyPath ? await anyRemoteRequiresConfiguredSsh(cwd) : setUpstream ? await remoteRequiresConfiguredSsh(cwd, remote) : await upstreamRequiresConfiguredSsh(cwd);
|
|
2574
2702
|
await runGitCommand(args, {
|
|
2575
2703
|
cwd,
|
|
2576
2704
|
requireConfiguredSsh,
|
|
2577
|
-
sshPrivateKeyPath
|
|
2705
|
+
sshPrivateKeyPath,
|
|
2706
|
+
sshHostKeyPolicy: "accept-new"
|
|
2578
2707
|
});
|
|
2579
2708
|
}
|
|
2580
2709
|
async function getHeadShortSha(cwd) {
|
|
@@ -3208,33 +3337,73 @@ var require_commit_message = __commonJS({
|
|
|
3208
3337
|
"../../packages/agent/dist/commit-message.js"(exports2) {
|
|
3209
3338
|
"use strict";
|
|
3210
3339
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
3340
|
+
exports2.isConventionalCommitMessage = isConventionalCommitMessage;
|
|
3341
|
+
exports2.normalizeConventionalCommitMessage = normalizeConventionalCommitMessage;
|
|
3211
3342
|
exports2.generateCommitMessageWithClaude = generateCommitMessageWithClaude;
|
|
3212
3343
|
exports2.fallbackCommitMessageFromFiles = fallbackCommitMessageFromFiles;
|
|
3213
3344
|
var node_path_1 = require("node:path");
|
|
3214
3345
|
var process_1 = require_process();
|
|
3346
|
+
var conventionalCommitPattern = /^(?:build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(?:\([^)]+\))?!?:\s+\S/;
|
|
3215
3347
|
function firstNonEmptyLine(input) {
|
|
3216
3348
|
return input.split(/\r?\n/).map((line) => line.trim()).find(Boolean) ?? "";
|
|
3217
3349
|
}
|
|
3350
|
+
function splitCommitMessage(message) {
|
|
3351
|
+
const lines = message.trim().split(/\r?\n/);
|
|
3352
|
+
const subjectIndex = lines.findIndex((line) => Boolean(line.trim()));
|
|
3353
|
+
if (subjectIndex === -1) {
|
|
3354
|
+
return { subject: "", body: "" };
|
|
3355
|
+
}
|
|
3356
|
+
return {
|
|
3357
|
+
subject: lines[subjectIndex].trim(),
|
|
3358
|
+
body: lines.slice(subjectIndex + 1).join("\n").trim()
|
|
3359
|
+
};
|
|
3360
|
+
}
|
|
3361
|
+
function cleanCommitSubject(message) {
|
|
3362
|
+
const rawSubject = splitCommitMessage(message).subject;
|
|
3363
|
+
const subject = rawSubject.replace(/^["'`]+|["'`]+$/g, "").replace(/^commit message:\s*/i, "").replace(/^[-*]\s+/, "").replace(/\s+/g, " ").replace(/[.!?]$/, "").trim();
|
|
3364
|
+
if (!subject) {
|
|
3365
|
+
return "update repository files";
|
|
3366
|
+
}
|
|
3367
|
+
return `${subject.charAt(0).toLowerCase()}${subject.slice(1)}`;
|
|
3368
|
+
}
|
|
3369
|
+
function isConventionalCommitMessage(message) {
|
|
3370
|
+
return conventionalCommitPattern.test(firstNonEmptyLine(message));
|
|
3371
|
+
}
|
|
3372
|
+
function normalizeConventionalCommitMessage(message) {
|
|
3373
|
+
const trimmed = message.trim();
|
|
3374
|
+
if (!trimmed) {
|
|
3375
|
+
return "chore: update repository files";
|
|
3376
|
+
}
|
|
3377
|
+
if (isConventionalCommitMessage(trimmed)) {
|
|
3378
|
+
return trimmed;
|
|
3379
|
+
}
|
|
3380
|
+
const { body } = splitCommitMessage(trimmed);
|
|
3381
|
+
const subject = `chore: ${cleanCommitSubject(trimmed)}`;
|
|
3382
|
+
return body ? `${subject}
|
|
3383
|
+
|
|
3384
|
+
${body}` : subject;
|
|
3385
|
+
}
|
|
3218
3386
|
async function generateCommitMessageWithClaude(context) {
|
|
3219
3387
|
const claudePath = await (0, process_1.resolveExecutable)("claude");
|
|
3220
3388
|
if (!claudePath) {
|
|
3221
3389
|
throw new Error("Claude CLI is not available");
|
|
3222
3390
|
}
|
|
3223
|
-
const prompt = `You are writing a git commit message for
|
|
3391
|
+
const prompt = `You are writing a git commit message for pushable changes.
|
|
3224
3392
|
|
|
3225
3393
|
Recent git status:
|
|
3226
3394
|
${context.status || "<empty>"}
|
|
3227
3395
|
|
|
3228
|
-
Recent git diff
|
|
3396
|
+
Recent git diff:
|
|
3229
3397
|
${context.diff || "<empty>"}
|
|
3230
3398
|
|
|
3231
3399
|
Recent git log:
|
|
3232
3400
|
${context.log || "<empty>"}
|
|
3233
3401
|
|
|
3234
|
-
Write exactly one short
|
|
3235
|
-
-
|
|
3402
|
+
Write exactly one short Conventional Commit message.
|
|
3403
|
+
- Format the first line as <type>: <subject>
|
|
3404
|
+
- Use a lowercase type such as feat, fix, docs, refactor, test, chore, or perf
|
|
3236
3405
|
- Focus on the purpose of the change
|
|
3237
|
-
- Keep
|
|
3406
|
+
- Keep the first line under 72 characters when possible
|
|
3238
3407
|
- Return only the commit message text`;
|
|
3239
3408
|
const result = await (0, process_1.runCommand)([
|
|
3240
3409
|
claudePath,
|
|
@@ -3249,16 +3418,16 @@ Write exactly one short natural-language git commit message.
|
|
|
3249
3418
|
if (!message) {
|
|
3250
3419
|
throw new Error("Claude returned an empty commit message");
|
|
3251
3420
|
}
|
|
3252
|
-
return message;
|
|
3421
|
+
return normalizeConventionalCommitMessage(message);
|
|
3253
3422
|
}
|
|
3254
3423
|
function fallbackCommitMessageFromFiles(files) {
|
|
3255
3424
|
if (files.length === 0) {
|
|
3256
|
-
return "
|
|
3425
|
+
return "chore: update repository files";
|
|
3257
3426
|
}
|
|
3258
3427
|
if (files.length === 1) {
|
|
3259
|
-
return `
|
|
3428
|
+
return `chore: update ${(0, node_path_1.basename)(files[0]) || files[0]}`;
|
|
3260
3429
|
}
|
|
3261
|
-
return `
|
|
3430
|
+
return `chore: update ${(0, node_path_1.basename)(files[0]) || files[0]} and ${files.length - 1} other files`;
|
|
3262
3431
|
}
|
|
3263
3432
|
}
|
|
3264
3433
|
});
|
|
@@ -3269,10 +3438,11 @@ var require_push = __commonJS({
|
|
|
3269
3438
|
"use strict";
|
|
3270
3439
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
3271
3440
|
exports2.previewPush = previewPush;
|
|
3441
|
+
exports2.preparePushPreview = preparePushPreview;
|
|
3272
3442
|
exports2.pushRepository = pushRepository;
|
|
3273
3443
|
var commit_message_1 = require_commit_message();
|
|
3274
3444
|
var git_1 = require_git();
|
|
3275
|
-
var
|
|
3445
|
+
var errors_1 = require_errors();
|
|
3276
3446
|
var PUSH_ARTIFACT_ROOTS = ["input", "output"];
|
|
3277
3447
|
var PUSH_INCLUDED_PATHSPECS = [
|
|
3278
3448
|
".",
|
|
@@ -3281,14 +3451,6 @@ var require_push = __commonJS({
|
|
|
3281
3451
|
":(exclude)output",
|
|
3282
3452
|
":(exclude)output/**"
|
|
3283
3453
|
];
|
|
3284
|
-
function shouldRetryCommit(error) {
|
|
3285
|
-
if (!(error instanceof process_1.CommandError)) {
|
|
3286
|
-
return false;
|
|
3287
|
-
}
|
|
3288
|
-
const details = `${error.result.stdout}
|
|
3289
|
-
${error.result.stderr}`.toLowerCase();
|
|
3290
|
-
return details.includes("hook") || details.includes("pre-commit") || details.includes("modified") || details.includes("stashed changes conflicted");
|
|
3291
|
-
}
|
|
3292
3454
|
async function resolveCommitMessage(repoRoot, options, mode = "staged") {
|
|
3293
3455
|
if (options.mode === "manual" && options.manualMessage?.trim()) {
|
|
3294
3456
|
return {
|
|
@@ -3307,7 +3469,7 @@ ${error.result.stderr}`.toLowerCase();
|
|
|
3307
3469
|
const generatedMessage = await generateCommitMessage({ status, diff, log });
|
|
3308
3470
|
if (generatedMessage.trim()) {
|
|
3309
3471
|
return {
|
|
3310
|
-
message:
|
|
3472
|
+
message: (0, commit_message_1.normalizeConventionalCommitMessage)(generatedMessage),
|
|
3311
3473
|
source: "claude"
|
|
3312
3474
|
};
|
|
3313
3475
|
}
|
|
@@ -3332,8 +3494,72 @@ ${error.result.stderr}`.toLowerCase();
|
|
|
3332
3494
|
await (0, git_1.stageAllMatching)(repoRoot, PUSH_INCLUDED_PATHSPECS);
|
|
3333
3495
|
await (0, git_1.unstageMatching)(repoRoot, PUSH_ARTIFACT_ROOTS);
|
|
3334
3496
|
}
|
|
3335
|
-
|
|
3336
|
-
|
|
3497
|
+
function getUpstreamRemoteName(upstream) {
|
|
3498
|
+
if (!upstream) {
|
|
3499
|
+
return null;
|
|
3500
|
+
}
|
|
3501
|
+
const separator = upstream.indexOf("/");
|
|
3502
|
+
return separator > 0 ? upstream.slice(0, separator) : null;
|
|
3503
|
+
}
|
|
3504
|
+
async function inspectPushRemoteState(repoRoot, branch, upstream, sshPrivateKeyPath) {
|
|
3505
|
+
const pushRef = await (0, git_1.getPushBranch)(repoRoot);
|
|
3506
|
+
const compareRef = pushRef ?? upstream ?? `origin/${branch}`;
|
|
3507
|
+
const remoteName = getUpstreamRemoteName(compareRef) ?? "origin";
|
|
3508
|
+
const setUpstream = !upstream;
|
|
3509
|
+
const remoteUrl = await (0, git_1.getRemoteUrl)(repoRoot, remoteName);
|
|
3510
|
+
if (!remoteUrl) {
|
|
3511
|
+
return {
|
|
3512
|
+
branch,
|
|
3513
|
+
upstream,
|
|
3514
|
+
remoteName,
|
|
3515
|
+
compareRef,
|
|
3516
|
+
setUpstream,
|
|
3517
|
+
aheadCount: 0,
|
|
3518
|
+
behindCount: 0
|
|
3519
|
+
};
|
|
3520
|
+
}
|
|
3521
|
+
await (0, git_1.fetchRemote)(repoRoot, remoteName, sshPrivateKeyPath);
|
|
3522
|
+
if (!await (0, git_1.refExists)(repoRoot, compareRef)) {
|
|
3523
|
+
return {
|
|
3524
|
+
branch,
|
|
3525
|
+
upstream,
|
|
3526
|
+
remoteName,
|
|
3527
|
+
compareRef,
|
|
3528
|
+
setUpstream,
|
|
3529
|
+
aheadCount: await (0, git_1.getCommitCount)(repoRoot),
|
|
3530
|
+
behindCount: 0
|
|
3531
|
+
};
|
|
3532
|
+
}
|
|
3533
|
+
const counts = await (0, git_1.getAheadBehind)(repoRoot, compareRef);
|
|
3534
|
+
return {
|
|
3535
|
+
branch,
|
|
3536
|
+
upstream,
|
|
3537
|
+
remoteName,
|
|
3538
|
+
compareRef,
|
|
3539
|
+
setUpstream,
|
|
3540
|
+
...counts
|
|
3541
|
+
};
|
|
3542
|
+
}
|
|
3543
|
+
function assertPushRemoteCurrent(state) {
|
|
3544
|
+
if (state.behindCount === 0) {
|
|
3545
|
+
return;
|
|
3546
|
+
}
|
|
3547
|
+
throw (0, errors_1.createUserFacingError)({
|
|
3548
|
+
code: "push_remote_ahead",
|
|
3549
|
+
summary: state.aheadCount > 0 ? "Remote branch has diverged." : "Remote branch has new commits.",
|
|
3550
|
+
details: `${state.compareRef ?? "The push target"} is ${state.behindCount} commit${state.behindCount === 1 ? "" : "s"} ahead of the local branch.`,
|
|
3551
|
+
fixes: [
|
|
3552
|
+
"Run `git pull --rebase --autostash`, resolve conflicts if needed, then retry Push."
|
|
3553
|
+
]
|
|
3554
|
+
});
|
|
3555
|
+
}
|
|
3556
|
+
function getReusableRemoteState(state, branch, upstream) {
|
|
3557
|
+
if (!state || state.branch !== branch || state.upstream !== upstream) {
|
|
3558
|
+
return null;
|
|
3559
|
+
}
|
|
3560
|
+
return state;
|
|
3561
|
+
}
|
|
3562
|
+
async function buildPushPreview(repoRoot, options, mode) {
|
|
3337
3563
|
const [worktreeStatus, statusCounts] = await Promise.all([
|
|
3338
3564
|
(0, git_1.getShortStatus)(repoRoot, PUSH_INCLUDED_PATHSPECS),
|
|
3339
3565
|
(0, git_1.getStatusCounts)(repoRoot, PUSH_INCLUDED_PATHSPECS)
|
|
@@ -3349,15 +3575,24 @@ ${error.result.stderr}`.toLowerCase();
|
|
|
3349
3575
|
detached = true;
|
|
3350
3576
|
}
|
|
3351
3577
|
const upstream = detached ? null : await (0, git_1.getUpstreamBranch)(repoRoot);
|
|
3352
|
-
const
|
|
3578
|
+
const remoteState = branch && !detached ? await inspectPushRemoteState(repoRoot, branch, upstream, options.sshPrivateKeyPath) : null;
|
|
3579
|
+
if (remoteState) {
|
|
3580
|
+
assertPushRemoteCurrent(remoteState);
|
|
3581
|
+
}
|
|
3582
|
+
const hasChanges = mode === "staged" ? await (0, git_1.hasStagedChanges)(repoRoot, PUSH_INCLUDED_PATHSPECS) : Boolean(worktreeStatus.trim());
|
|
3583
|
+
const willCommit = hasChanges;
|
|
3584
|
+
const willPushExistingCommits = !willCommit && Boolean(remoteState && remoteState.aheadCount > 0);
|
|
3353
3585
|
let suggestedMessage;
|
|
3354
3586
|
let messageSource;
|
|
3355
3587
|
let fallbackReason;
|
|
3356
3588
|
if (hasChanges) {
|
|
3357
|
-
const resolved = await resolveCommitMessage(repoRoot, options,
|
|
3589
|
+
const resolved = await resolveCommitMessage(repoRoot, options, mode);
|
|
3358
3590
|
suggestedMessage = resolved.message;
|
|
3359
3591
|
messageSource = resolved.source;
|
|
3360
3592
|
fallbackReason = resolved.fallbackReason;
|
|
3593
|
+
} else if (willPushExistingCommits) {
|
|
3594
|
+
suggestedMessage = await (0, git_1.getHeadCommitMessage)(repoRoot);
|
|
3595
|
+
messageSource = "manual";
|
|
3361
3596
|
}
|
|
3362
3597
|
return {
|
|
3363
3598
|
repoRoot,
|
|
@@ -3369,39 +3604,56 @@ ${error.result.stderr}`.toLowerCase();
|
|
|
3369
3604
|
statusCounts,
|
|
3370
3605
|
suggestedMessage,
|
|
3371
3606
|
messageSource,
|
|
3372
|
-
fallbackReason
|
|
3607
|
+
fallbackReason,
|
|
3608
|
+
aheadCount: remoteState?.aheadCount ?? 0,
|
|
3609
|
+
behindCount: remoteState?.behindCount ?? 0,
|
|
3610
|
+
willCommit,
|
|
3611
|
+
willPushExistingCommits,
|
|
3612
|
+
remoteState: remoteState ?? void 0
|
|
3373
3613
|
};
|
|
3374
3614
|
}
|
|
3615
|
+
async function previewPush(options) {
|
|
3616
|
+
const repoRoot = await (0, git_1.getRepositoryRoot)(options.cwd ?? process.cwd());
|
|
3617
|
+
return await buildPushPreview(repoRoot, options, "worktree");
|
|
3618
|
+
}
|
|
3619
|
+
async function preparePushPreview(options) {
|
|
3620
|
+
const repoRoot = await (0, git_1.getRepositoryRoot)(options.cwd ?? process.cwd());
|
|
3621
|
+
await stagePushableChanges(repoRoot);
|
|
3622
|
+
return await buildPushPreview(repoRoot, options, "staged");
|
|
3623
|
+
}
|
|
3375
3624
|
async function pushRepository(options) {
|
|
3376
3625
|
const repoRoot = await (0, git_1.getRepositoryRoot)(options.cwd ?? process.cwd());
|
|
3626
|
+
const branch = await (0, git_1.getCurrentBranch)(repoRoot);
|
|
3627
|
+
const upstream = await (0, git_1.getUpstreamBranch)(repoRoot);
|
|
3628
|
+
const remoteState = getReusableRemoteState(options.remoteState, branch, upstream) ?? await inspectPushRemoteState(repoRoot, branch, upstream, options.sshPrivateKeyPath);
|
|
3629
|
+
assertPushRemoteCurrent(remoteState);
|
|
3377
3630
|
await stagePushableChanges(repoRoot);
|
|
3378
3631
|
if (!await (0, git_1.hasStagedChanges)(repoRoot, PUSH_INCLUDED_PATHSPECS)) {
|
|
3632
|
+
if (remoteState.aheadCount > 0) {
|
|
3633
|
+
const message2 = options.resolvedMessage?.message ?? options.manualMessage?.trim() ?? await (0, git_1.getHeadCommitMessage)(repoRoot);
|
|
3634
|
+
await (0, git_1.pushBranch)(repoRoot, branch, remoteState.setUpstream, options.sshPrivateKeyPath, remoteState.remoteName ?? "origin");
|
|
3635
|
+
return {
|
|
3636
|
+
repoRoot,
|
|
3637
|
+
branch,
|
|
3638
|
+
message: message2,
|
|
3639
|
+
retriedCommit: false,
|
|
3640
|
+
commitSha: await (0, git_1.getHeadShortSha)(repoRoot),
|
|
3641
|
+
upstream: await (0, git_1.getUpstreamBranch)(repoRoot),
|
|
3642
|
+
messageSource: options.resolvedMessage?.source ?? "manual",
|
|
3643
|
+
fallbackReason: options.resolvedMessage?.fallbackReason
|
|
3644
|
+
};
|
|
3645
|
+
}
|
|
3379
3646
|
throw new Error("No changes to push.");
|
|
3380
3647
|
}
|
|
3381
3648
|
const resolvedMessage = options.resolvedMessage ?? await resolveCommitMessage(repoRoot, options);
|
|
3382
3649
|
const message = resolvedMessage.message;
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
await (0, git_1.commitWithMessage)(repoRoot, message);
|
|
3386
|
-
} catch (error) {
|
|
3387
|
-
if (!shouldRetryCommit(error)) {
|
|
3388
|
-
throw error;
|
|
3389
|
-
}
|
|
3390
|
-
retriedCommit = true;
|
|
3391
|
-
await stagePushableChanges(repoRoot);
|
|
3392
|
-
if (!await (0, git_1.hasStagedChanges)(repoRoot, PUSH_INCLUDED_PATHSPECS)) {
|
|
3393
|
-
throw new Error("No changes to push.");
|
|
3394
|
-
}
|
|
3395
|
-
await (0, git_1.commitWithMessage)(repoRoot, message);
|
|
3396
|
-
}
|
|
3397
|
-
const branch = await (0, git_1.getCurrentBranch)(repoRoot);
|
|
3398
|
-
const upstream = await (0, git_1.getUpstreamBranch)(repoRoot);
|
|
3399
|
-
await (0, git_1.pushBranch)(repoRoot, branch, !upstream, options.sshPrivateKeyPath);
|
|
3650
|
+
await (0, git_1.commitWithMessage)(repoRoot, message);
|
|
3651
|
+
await (0, git_1.pushBranch)(repoRoot, branch, remoteState.setUpstream, options.sshPrivateKeyPath, remoteState.remoteName ?? "origin");
|
|
3400
3652
|
return {
|
|
3401
3653
|
repoRoot,
|
|
3402
3654
|
branch,
|
|
3403
3655
|
message,
|
|
3404
|
-
retriedCommit,
|
|
3656
|
+
retriedCommit: false,
|
|
3405
3657
|
commitSha: await (0, git_1.getHeadShortSha)(repoRoot),
|
|
3406
3658
|
upstream: await (0, git_1.getUpstreamBranch)(repoRoot),
|
|
3407
3659
|
messageSource: resolvedMessage.source,
|
|
@@ -4747,10 +4999,10 @@ ${detail.errors.join("\n")}` : summary);
|
|
|
4747
4999
|
function buildOpenRouterProxyBaseUrl(agentApiUrl) {
|
|
4748
5000
|
return new URL("/v3/openrouter", agentApiUrl.endsWith("/") ? agentApiUrl : `${agentApiUrl}/`).toString().replace(/\/$/, "");
|
|
4749
5001
|
}
|
|
4750
|
-
function buildOpenRouterClaudeEnvironmentOverrides(model, dataToken, agentApiUrl) {
|
|
4751
|
-
const proxyBaseUrl = buildOpenRouterProxyBaseUrl(agentApiUrl);
|
|
5002
|
+
function buildOpenRouterClaudeEnvironmentOverrides(model, dataToken, agentApiUrl, sessionId) {
|
|
4752
5003
|
return {
|
|
4753
|
-
ANTHROPIC_BASE_URL:
|
|
5004
|
+
ANTHROPIC_BASE_URL: buildOpenRouterProxyBaseUrl(agentApiUrl),
|
|
5005
|
+
...sessionId ? { ANTHROPIC_CUSTOM_HEADERS: `x-agent-session-id: ${sessionId}` } : {},
|
|
4754
5006
|
ANTHROPIC_AUTH_TOKEN: dataToken,
|
|
4755
5007
|
ANTHROPIC_API_KEY: "",
|
|
4756
5008
|
ANTHROPIC_DEFAULT_OPUS_MODEL: model,
|
|
@@ -4809,7 +5061,8 @@ ${detail.errors.join("\n")}` : summary);
|
|
|
4809
5061
|
};
|
|
4810
5062
|
const models = await fetchModelsFn(config, options.fetch, { headers });
|
|
4811
5063
|
await ensureOpenRouterModelAvailable(model, models);
|
|
4812
|
-
const
|
|
5064
|
+
const agentSessionId = `local-${(0, node_crypto_1.randomUUID)()}`;
|
|
5065
|
+
const environmentOverrides = buildOpenRouterClaudeEnvironmentOverrides(model, dataToken, config.agentApiUrl, agentSessionId);
|
|
4813
5066
|
const redactedEnvironmentOverrides = redactClaudeEnvironmentOverrides(environmentOverrides);
|
|
4814
5067
|
return {
|
|
4815
5068
|
command,
|
|
@@ -6726,23 +6979,25 @@ var require_cli = __commonJS({
|
|
|
6726
6979
|
});
|
|
6727
6980
|
}
|
|
6728
6981
|
const mode = resolvePushMode(options);
|
|
6982
|
+
const config = await (0, config_1.resolveAgentConfig)();
|
|
6729
6983
|
const preview = await (0, push_1.previewPush)({
|
|
6730
6984
|
cwd: repoRoot,
|
|
6731
6985
|
mode,
|
|
6732
|
-
manualMessage: options.message?.trim() || void 0
|
|
6986
|
+
manualMessage: options.message?.trim() || void 0,
|
|
6987
|
+
sshPrivateKeyPath: config.gitSshKey?.privateKeyPath
|
|
6733
6988
|
});
|
|
6734
|
-
if (!preview.hasChanges) {
|
|
6735
|
-
throw (0, errors_1.createUserFacingError)({
|
|
6736
|
-
code: "push_no_changes",
|
|
6737
|
-
summary: "No changes to push."
|
|
6738
|
-
});
|
|
6739
|
-
}
|
|
6740
6989
|
if (preview.detached) {
|
|
6741
6990
|
throw (0, errors_1.createUserFacingError)({
|
|
6742
6991
|
code: "push_detached_head",
|
|
6743
6992
|
summary: "Detached HEAD; check out a branch before pushing."
|
|
6744
6993
|
});
|
|
6745
6994
|
}
|
|
6995
|
+
if (!preview.hasChanges && !preview.willPushExistingCommits) {
|
|
6996
|
+
throw (0, errors_1.createUserFacingError)({
|
|
6997
|
+
code: "push_no_changes",
|
|
6998
|
+
summary: "No changes to push."
|
|
6999
|
+
});
|
|
7000
|
+
}
|
|
6746
7001
|
if (!options.json) {
|
|
6747
7002
|
write(io.stdout, renderPushPreview(preview));
|
|
6748
7003
|
}
|
|
@@ -6756,15 +7011,24 @@ var require_cli = __commonJS({
|
|
|
6756
7011
|
if (options.dryRun) {
|
|
6757
7012
|
const result2 = {
|
|
6758
7013
|
ok: true,
|
|
7014
|
+
repoRoot: preview.repoRoot,
|
|
6759
7015
|
branch: preview.branch,
|
|
7016
|
+
upstream: preview.upstream,
|
|
7017
|
+
statusCounts: preview.statusCounts,
|
|
7018
|
+
worktreeStatus: preview.worktreeStatus,
|
|
6760
7019
|
commitMessage: resolvedMessage,
|
|
7020
|
+
messageSource: preview.messageSource,
|
|
7021
|
+
fallbackReason: preview.fallbackReason,
|
|
7022
|
+
aheadCount: preview.aheadCount,
|
|
7023
|
+
behindCount: preview.behindCount,
|
|
7024
|
+
willCommit: preview.willCommit,
|
|
7025
|
+
willPushExistingCommits: preview.willPushExistingCommits,
|
|
6761
7026
|
nextActions: ["Run `tela agent push` without `--dry-run` when the plan looks correct."]
|
|
6762
7027
|
};
|
|
6763
7028
|
if (options.json)
|
|
6764
7029
|
emitJson(io, result2);
|
|
6765
7030
|
return 0;
|
|
6766
7031
|
}
|
|
6767
|
-
const config = await (0, config_1.resolveAgentConfig)();
|
|
6768
7032
|
const push = await (0, push_1.pushRepository)({
|
|
6769
7033
|
cwd: repoRoot,
|
|
6770
7034
|
mode: "manual",
|
|
@@ -6774,12 +7038,17 @@ var require_cli = __commonJS({
|
|
|
6774
7038
|
source: preview.messageSource ?? (options.message ? "manual" : "fallback"),
|
|
6775
7039
|
fallbackReason: preview.fallbackReason
|
|
6776
7040
|
},
|
|
6777
|
-
sshPrivateKeyPath: config.gitSshKey?.privateKeyPath
|
|
7041
|
+
sshPrivateKeyPath: config.gitSshKey?.privateKeyPath,
|
|
7042
|
+
remoteState: preview.remoteState
|
|
6778
7043
|
});
|
|
6779
7044
|
const result = {
|
|
6780
7045
|
ok: true,
|
|
7046
|
+
repoRoot: push.repoRoot,
|
|
6781
7047
|
branch: push.branch,
|
|
7048
|
+
upstream: push.upstream,
|
|
6782
7049
|
commitMessage: push.message,
|
|
7050
|
+
messageSource: push.messageSource,
|
|
7051
|
+
fallbackReason: push.fallbackReason,
|
|
6783
7052
|
commitSha: push.commitSha,
|
|
6784
7053
|
retriedCommit: push.retriedCommit,
|
|
6785
7054
|
nextActions: ["Run `tela agent feedback --list` to inspect feedback for the pushed commit."]
|
|
@@ -7229,6 +7498,7 @@ var require_dist2 = __commonJS({
|
|
|
7229
7498
|
__exportStar(require_push(), exports2);
|
|
7230
7499
|
__exportStar(require_run(), exports2);
|
|
7231
7500
|
__exportStar(require_sync(), exports2);
|
|
7501
|
+
__exportStar(require_commit_message(), exports2);
|
|
7232
7502
|
var config_1 = require_config2();
|
|
7233
7503
|
Object.defineProperty(exports2, "getDefaultAgentCloneRoot", { enumerable: true, get: function() {
|
|
7234
7504
|
return config_1.getDefaultAgentCloneRoot;
|