@linzumi/cli 0.0.93-beta → 0.0.95-beta
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/README.md +1 -1
- package/dist/index.js +326 -36
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -112,6 +112,14 @@ import { spawnSync } from "node:child_process";
|
|
|
112
112
|
import { homedir } from "node:os";
|
|
113
113
|
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
114
114
|
import { basename, dirname, join } from "node:path";
|
|
115
|
+
function projectScanBudgetMs() {
|
|
116
|
+
const raw = process.env.LINZUMI_ONBOARDING_PROJECT_SCAN_BUDGET_MS?.trim();
|
|
117
|
+
if (raw === void 0 || raw === "") {
|
|
118
|
+
return defaultProjectScanBudgetMs;
|
|
119
|
+
}
|
|
120
|
+
const parsed = Number.parseInt(raw, 10);
|
|
121
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : defaultProjectScanBudgetMs;
|
|
122
|
+
}
|
|
115
123
|
function discoverCurrentGitProject(args) {
|
|
116
124
|
const startedAtMs = args.nowMs ?? Date.now();
|
|
117
125
|
const responsiveness = args.placeResponsiveness;
|
|
@@ -136,7 +144,19 @@ function discoverCurrentGitProject(args) {
|
|
|
136
144
|
});
|
|
137
145
|
const sourceRoots = args.sourceRoots ?? defaultLocalProjectSourceRoots(args.cwd);
|
|
138
146
|
let placesSearched = 1;
|
|
147
|
+
const scanBudgetMs = projectScanBudgetMs();
|
|
139
148
|
for (const sourceRoot of sourceRoots) {
|
|
149
|
+
if (Date.now() - startedAtMs >= scanBudgetMs) {
|
|
150
|
+
searchStats.push({
|
|
151
|
+
place: sourceRoot,
|
|
152
|
+
source: "git",
|
|
153
|
+
duration_ms: 0,
|
|
154
|
+
result_count: 0,
|
|
155
|
+
skipped_scan_budget_exceeded: true
|
|
156
|
+
});
|
|
157
|
+
placesSearched += 1;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
140
160
|
const sourceRootStartedAtMs = Date.now();
|
|
141
161
|
const rootResponsive = isPlaceResponsive(sourceRoot, responsiveness);
|
|
142
162
|
if (!rootResponsive) {
|
|
@@ -296,6 +316,9 @@ function isGitWorktreeRoot(path2) {
|
|
|
296
316
|
return existsSync(join(path2, ".git"));
|
|
297
317
|
}
|
|
298
318
|
function defaultLocalProjectSourceRoots(cwd) {
|
|
319
|
+
if (cwd === dirname(cwd)) {
|
|
320
|
+
return [];
|
|
321
|
+
}
|
|
299
322
|
return uniqueStrings([
|
|
300
323
|
...ancestorSourceRoots(cwd),
|
|
301
324
|
...homeSourceRoots(),
|
|
@@ -409,13 +432,14 @@ function compactJsonObject(value) {
|
|
|
409
432
|
})
|
|
410
433
|
);
|
|
411
434
|
}
|
|
412
|
-
var worktreePathSampleLimit, gitSpawnTimeoutMs;
|
|
435
|
+
var worktreePathSampleLimit, gitSpawnTimeoutMs, defaultProjectScanBudgetMs;
|
|
413
436
|
var init_onboardingProjectDiscovery = __esm({
|
|
414
437
|
"src/onboardingProjectDiscovery.ts"() {
|
|
415
438
|
"use strict";
|
|
416
439
|
init_onboardingPlaceResponsiveness();
|
|
417
440
|
worktreePathSampleLimit = 25;
|
|
418
441
|
gitSpawnTimeoutMs = 4e3;
|
|
442
|
+
defaultProjectScanBudgetMs = 2e4;
|
|
419
443
|
}
|
|
420
444
|
});
|
|
421
445
|
|
|
@@ -8437,6 +8461,38 @@ var init_userFacingErrors = __esm({
|
|
|
8437
8461
|
|
|
8438
8462
|
// src/channelSession.ts
|
|
8439
8463
|
import { createHash as createHash3, randomUUID } from "node:crypto";
|
|
8464
|
+
function codexStartRequestTimeoutMs() {
|
|
8465
|
+
const raw = process.env.LINZUMI_CODEX_START_REQUEST_TIMEOUT_MS?.trim();
|
|
8466
|
+
if (raw === void 0 || raw === "") {
|
|
8467
|
+
return CODEX_START_REQUEST_TIMEOUT_MS;
|
|
8468
|
+
}
|
|
8469
|
+
const parsed = Number.parseInt(raw, 10);
|
|
8470
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : CODEX_START_REQUEST_TIMEOUT_MS;
|
|
8471
|
+
}
|
|
8472
|
+
function isCodexStartRequestTimeoutError(error) {
|
|
8473
|
+
return error instanceof CodexStartRequestTimeoutError;
|
|
8474
|
+
}
|
|
8475
|
+
function withCodexStartRequestTimeout(method, request, timeoutMs = codexStartRequestTimeoutMs()) {
|
|
8476
|
+
if (!(timeoutMs > 0)) {
|
|
8477
|
+
return request;
|
|
8478
|
+
}
|
|
8479
|
+
return new Promise((resolve12, reject) => {
|
|
8480
|
+
const timer = setTimeout(() => {
|
|
8481
|
+
reject(new CodexStartRequestTimeoutError(method, timeoutMs));
|
|
8482
|
+
}, timeoutMs);
|
|
8483
|
+
timer.unref?.();
|
|
8484
|
+
request.then(
|
|
8485
|
+
(value) => {
|
|
8486
|
+
clearTimeout(timer);
|
|
8487
|
+
resolve12(value);
|
|
8488
|
+
},
|
|
8489
|
+
(error) => {
|
|
8490
|
+
clearTimeout(timer);
|
|
8491
|
+
reject(error);
|
|
8492
|
+
}
|
|
8493
|
+
);
|
|
8494
|
+
});
|
|
8495
|
+
}
|
|
8440
8496
|
async function attachChannelSession(args) {
|
|
8441
8497
|
const session = args.options.channelSession;
|
|
8442
8498
|
const chatTopic = `chat:${session.workspaceSlug}:${session.channelSlug}`;
|
|
@@ -8941,6 +8997,7 @@ function initialChannelSessionState(cursor, rootSeq, kandanThreadId, codexThread
|
|
|
8941
8997
|
failedSeqs: /* @__PURE__ */ new Map(),
|
|
8942
8998
|
drainInFlight: false,
|
|
8943
8999
|
drainRequested: false,
|
|
9000
|
+
boundStartTimeout: false,
|
|
8944
9001
|
fusedQueuedSeqs: /* @__PURE__ */ new Map(),
|
|
8945
9002
|
reconnectRetryTimer: void 0,
|
|
8946
9003
|
reconnectRetryAttempts: 0,
|
|
@@ -10295,6 +10352,9 @@ async function startThreadMessageTurn(args, state, payloadContext, message) {
|
|
|
10295
10352
|
if (state.kandanThreadId === void 0 || state.codexThreadId === void 0) {
|
|
10296
10353
|
throw new Error("cannot start a local Codex turn before thread binding");
|
|
10297
10354
|
}
|
|
10355
|
+
if (message.boundStartTimeout === true) {
|
|
10356
|
+
state.boundStartTimeout = true;
|
|
10357
|
+
}
|
|
10298
10358
|
const queued = {
|
|
10299
10359
|
seq: message.seq,
|
|
10300
10360
|
actorSlug: message.actorSlug,
|
|
@@ -10558,7 +10618,9 @@ async function drainKandanMessageQueueOnce(args, state, payloadContext) {
|
|
|
10558
10618
|
if (state.kandanThreadId !== void 0) {
|
|
10559
10619
|
startCodexTypingHeartbeat(args, state, state.kandanThreadId);
|
|
10560
10620
|
}
|
|
10561
|
-
const
|
|
10621
|
+
const boundStartTimeout = state.boundStartTimeout;
|
|
10622
|
+
state.boundStartTimeout = false;
|
|
10623
|
+
const turnStartRequest = args.codex.request("turn/start", {
|
|
10562
10624
|
threadId: codexThreadId,
|
|
10563
10625
|
input: await codexInputItemsForQueuedKandanMessage(
|
|
10564
10626
|
args,
|
|
@@ -10569,6 +10631,7 @@ async function drainKandanMessageQueueOnce(args, state, payloadContext) {
|
|
|
10569
10631
|
runtimeOptionsForSettings(args.options, state.runtimeSettings)
|
|
10570
10632
|
)
|
|
10571
10633
|
});
|
|
10634
|
+
const started = boundStartTimeout ? await withCodexStartRequestTimeout("turn/start", turnStartRequest) : await turnStartRequest;
|
|
10572
10635
|
const turnId = extractTurnIdFromResponse(started);
|
|
10573
10636
|
state.pendingReconnectContextInjection = void 0;
|
|
10574
10637
|
const interruptAfterStart = state.turn.status === "starting" && state.turn.interruptAfterStart;
|
|
@@ -10641,6 +10704,9 @@ async function drainKandanMessageQueueOnce(args, state, payloadContext) {
|
|
|
10641
10704
|
queued_seq: next.seq,
|
|
10642
10705
|
message: error instanceof Error ? error.message : String(error)
|
|
10643
10706
|
});
|
|
10707
|
+
if (isCodexStartRequestTimeoutError(error)) {
|
|
10708
|
+
throw error;
|
|
10709
|
+
}
|
|
10644
10710
|
}
|
|
10645
10711
|
}
|
|
10646
10712
|
function drainKandanMessageQueueBlocked(args, state) {
|
|
@@ -11654,7 +11720,7 @@ async function pushOptional(kandan, topic, event, payload, log2) {
|
|
|
11654
11720
|
});
|
|
11655
11721
|
}
|
|
11656
11722
|
}
|
|
11657
|
-
var codexTypingHeartbeatMs, maxTrackedFailedChatEventSeqs, maxChatEventFailureAttempts, maxForwardedTurnIds, maxClaimedKandanMessageKeys, claimedKandanMessageKeys, nextChatJoinRegistrationSerial, defaultReconnectHandlingRetryDelaysMs, defaultTuiInputMirrorRetryDelaysMs, pipelineCloseTimeoutMs;
|
|
11723
|
+
var codexTypingHeartbeatMs, CODEX_START_REQUEST_TIMEOUT_MS, CodexStartRequestTimeoutError, maxTrackedFailedChatEventSeqs, maxChatEventFailureAttempts, maxForwardedTurnIds, maxClaimedKandanMessageKeys, claimedKandanMessageKeys, nextChatJoinRegistrationSerial, defaultReconnectHandlingRetryDelaysMs, defaultTuiInputMirrorRetryDelaysMs, pipelineCloseTimeoutMs;
|
|
11658
11724
|
var init_channelSession = __esm({
|
|
11659
11725
|
"src/channelSession.ts"() {
|
|
11660
11726
|
"use strict";
|
|
@@ -11679,6 +11745,15 @@ var init_channelSession = __esm({
|
|
|
11679
11745
|
init_processNameCatalog();
|
|
11680
11746
|
init_userFacingErrors();
|
|
11681
11747
|
codexTypingHeartbeatMs = 5e3;
|
|
11748
|
+
CODEX_START_REQUEST_TIMEOUT_MS = 12e4;
|
|
11749
|
+
CodexStartRequestTimeoutError = class extends Error {
|
|
11750
|
+
constructor(method, timeoutMs) {
|
|
11751
|
+
super(
|
|
11752
|
+
`Codex ${method} did not reply within ${timeoutMs}ms (start request timed out)`
|
|
11753
|
+
);
|
|
11754
|
+
this.name = "CodexStartRequestTimeoutError";
|
|
11755
|
+
}
|
|
11756
|
+
};
|
|
11682
11757
|
maxTrackedFailedChatEventSeqs = 256;
|
|
11683
11758
|
maxChatEventFailureAttempts = 5;
|
|
11684
11759
|
maxForwardedTurnIds = 64;
|
|
@@ -19376,7 +19451,7 @@ var linzumiCliVersion, linzumiCliVersionText;
|
|
|
19376
19451
|
var init_version = __esm({
|
|
19377
19452
|
"src/version.ts"() {
|
|
19378
19453
|
"use strict";
|
|
19379
|
-
linzumiCliVersion = "0.0.
|
|
19454
|
+
linzumiCliVersion = "0.0.95-beta";
|
|
19380
19455
|
linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
|
|
19381
19456
|
}
|
|
19382
19457
|
});
|
|
@@ -19487,6 +19562,82 @@ function assessRunnerLockHolder(record, isPidAlive, now) {
|
|
|
19487
19562
|
}
|
|
19488
19563
|
return { state: "live" };
|
|
19489
19564
|
}
|
|
19565
|
+
function shouldAutoTakeOverForUpdate(existing, myVersion, myLaunchSource, holderState) {
|
|
19566
|
+
if (myLaunchSource !== electronAutoConnectLaunchSource) {
|
|
19567
|
+
return false;
|
|
19568
|
+
}
|
|
19569
|
+
if (existing.launchSource !== electronAutoConnectLaunchSource) {
|
|
19570
|
+
return false;
|
|
19571
|
+
}
|
|
19572
|
+
if (holderState.state !== "live") {
|
|
19573
|
+
return true;
|
|
19574
|
+
}
|
|
19575
|
+
return compareCliVersions(myVersion, existing.cliVersion) > 0;
|
|
19576
|
+
}
|
|
19577
|
+
function compareCliVersions(a, b) {
|
|
19578
|
+
const pa = parseCliVersion(a);
|
|
19579
|
+
const pb = parseCliVersion(b);
|
|
19580
|
+
for (let i = 0; i < 3; i++) {
|
|
19581
|
+
if (pa.core[i] !== pb.core[i]) {
|
|
19582
|
+
return pa.core[i] > pb.core[i] ? 1 : -1;
|
|
19583
|
+
}
|
|
19584
|
+
}
|
|
19585
|
+
if (pa.prerelease.length === 0 && pb.prerelease.length === 0) {
|
|
19586
|
+
return 0;
|
|
19587
|
+
}
|
|
19588
|
+
if (pa.prerelease.length === 0) {
|
|
19589
|
+
return 1;
|
|
19590
|
+
}
|
|
19591
|
+
if (pb.prerelease.length === 0) {
|
|
19592
|
+
return -1;
|
|
19593
|
+
}
|
|
19594
|
+
return comparePrerelease(pa.prerelease, pb.prerelease);
|
|
19595
|
+
}
|
|
19596
|
+
function parseCliVersion(value) {
|
|
19597
|
+
const trimmed = value.trim().replace(/^v/i, "").split("+", 1)[0] ?? "";
|
|
19598
|
+
const hyphen = trimmed.indexOf("-");
|
|
19599
|
+
const coreText = hyphen === -1 ? trimmed : trimmed.slice(0, hyphen);
|
|
19600
|
+
const prereleaseText = hyphen === -1 ? "" : trimmed.slice(hyphen + 1);
|
|
19601
|
+
const parts = coreText.split(".");
|
|
19602
|
+
const core = [
|
|
19603
|
+
parseCoreNumber(parts[0]),
|
|
19604
|
+
parseCoreNumber(parts[1]),
|
|
19605
|
+
parseCoreNumber(parts[2])
|
|
19606
|
+
];
|
|
19607
|
+
const prerelease = prereleaseText === "" ? [] : prereleaseText.split(".").filter((id) => id !== "");
|
|
19608
|
+
return { core, prerelease };
|
|
19609
|
+
}
|
|
19610
|
+
function parseCoreNumber(value) {
|
|
19611
|
+
const parsed = Number.parseInt(value ?? "", 10);
|
|
19612
|
+
return Number.isInteger(parsed) && parsed >= 0 ? parsed : 0;
|
|
19613
|
+
}
|
|
19614
|
+
function comparePrerelease(a, b) {
|
|
19615
|
+
const length = Math.max(a.length, b.length);
|
|
19616
|
+
for (let i = 0; i < length; i++) {
|
|
19617
|
+
if (i >= a.length) {
|
|
19618
|
+
return -1;
|
|
19619
|
+
}
|
|
19620
|
+
if (i >= b.length) {
|
|
19621
|
+
return 1;
|
|
19622
|
+
}
|
|
19623
|
+
const idA = a[i];
|
|
19624
|
+
const idB = b[i];
|
|
19625
|
+
const numA = Number.parseInt(idA, 10);
|
|
19626
|
+
const numB = Number.parseInt(idB, 10);
|
|
19627
|
+
const aIsNum = numA.toString() === idA;
|
|
19628
|
+
const bIsNum = numB.toString() === idB;
|
|
19629
|
+
if (aIsNum && bIsNum) {
|
|
19630
|
+
if (numA !== numB) {
|
|
19631
|
+
return numA > numB ? 1 : -1;
|
|
19632
|
+
}
|
|
19633
|
+
} else if (aIsNum !== bIsNum) {
|
|
19634
|
+
return aIsNum ? -1 : 1;
|
|
19635
|
+
} else if (idA !== idB) {
|
|
19636
|
+
return idA > idB ? 1 : -1;
|
|
19637
|
+
}
|
|
19638
|
+
}
|
|
19639
|
+
return 0;
|
|
19640
|
+
}
|
|
19490
19641
|
function takeOverWedgedHolder(lockPath, holder, reason, killPid, onTakeover) {
|
|
19491
19642
|
try {
|
|
19492
19643
|
killPid(holder.pid);
|
|
@@ -19754,7 +19905,7 @@ function displayLinzumiUrl(linzumiUrl) {
|
|
|
19754
19905
|
function isNodeErrorCode2(error, code) {
|
|
19755
19906
|
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
19756
19907
|
}
|
|
19757
|
-
var runnerLockHeartbeatIntervalMs, runnerLockTakeoverAfterMs, runnerLockHeldErrorName, RunnerLockHeldError;
|
|
19908
|
+
var runnerLockHeartbeatIntervalMs, runnerLockTakeoverAfterMs, runnerLockHeldErrorName, RunnerLockHeldError, electronAutoConnectLaunchSource;
|
|
19758
19909
|
var init_runnerLock = __esm({
|
|
19759
19910
|
"src/runnerLock.ts"() {
|
|
19760
19911
|
"use strict";
|
|
@@ -19775,6 +19926,7 @@ var init_runnerLock = __esm({
|
|
|
19775
19926
|
this.heldBy = heldBy;
|
|
19776
19927
|
}
|
|
19777
19928
|
};
|
|
19929
|
+
electronAutoConnectLaunchSource = "electron_auto_connect";
|
|
19778
19930
|
}
|
|
19779
19931
|
});
|
|
19780
19932
|
|
|
@@ -22958,6 +23110,34 @@ async function runThreadCodexWorker(options) {
|
|
|
22958
23110
|
async function openLocalCodexRunner(options, log2, cleanup, close) {
|
|
22959
23111
|
const agentProviders = availableRunnerAgentProviders(options);
|
|
22960
23112
|
const localCodexAppServerAvailable = hasLocalCodexAppServerCapability(options);
|
|
23113
|
+
const dependencyStatusRef = {
|
|
23114
|
+
value: options.dependencyStatus
|
|
23115
|
+
};
|
|
23116
|
+
const refreshDependencyStatus = async () => {
|
|
23117
|
+
if (dependencyStatusRef.value === void 0) {
|
|
23118
|
+
return;
|
|
23119
|
+
}
|
|
23120
|
+
try {
|
|
23121
|
+
const refreshed = await buildRunnerDependencyStatus({
|
|
23122
|
+
cwd: options.cwd,
|
|
23123
|
+
codexBin: options.codexBin,
|
|
23124
|
+
codeServerBin: options.codeServerBin,
|
|
23125
|
+
editorRuntime: dependencyStatusRef.value?.editorRuntime
|
|
23126
|
+
});
|
|
23127
|
+
const previousCodexAvailable = dependencyStatusRef.value?.codex.available;
|
|
23128
|
+
dependencyStatusRef.value = refreshed;
|
|
23129
|
+
log2("runner.dependency_status_reprobed", {
|
|
23130
|
+
runnerId: options.runnerId,
|
|
23131
|
+
codex_available: refreshed.codex.available,
|
|
23132
|
+
codex_available_changed: previousCodexAvailable !== refreshed.codex.available
|
|
23133
|
+
});
|
|
23134
|
+
} catch (error) {
|
|
23135
|
+
log2("runner.dependency_status_reprobe_failed", {
|
|
23136
|
+
runnerId: options.runnerId,
|
|
23137
|
+
message: error instanceof Error ? error.message : String(error)
|
|
23138
|
+
});
|
|
23139
|
+
}
|
|
23140
|
+
};
|
|
22961
23141
|
const allowedForwardPorts = options.allowedForwardPorts ?? [];
|
|
22962
23142
|
const liveForwardPorts = new Set(allowedForwardPorts);
|
|
22963
23143
|
const managedForwardPorts = /* @__PURE__ */ new Set();
|
|
@@ -23130,8 +23310,8 @@ async function openLocalCodexRunner(options, log2, cleanup, close) {
|
|
|
23130
23310
|
),
|
|
23131
23311
|
forwardedPortAttributions: buildForwardPortAttributionPayload(),
|
|
23132
23312
|
pendingEditorForwardPortRequests: pendingEditorForwardPortRequests(),
|
|
23133
|
-
toolStatus:
|
|
23134
|
-
editorRuntime:
|
|
23313
|
+
toolStatus: dependencyStatusRef.value === void 0 ? null : dependencyStatusPayload(dependencyStatusRef.value),
|
|
23314
|
+
editorRuntime: dependencyStatusRef.value?.editorRuntime === void 0 ? null : dependencyStatusPayload(dependencyStatusRef.value).editorRuntime,
|
|
23135
23315
|
...localEditorCapabilities(
|
|
23136
23316
|
options.editorRuntime,
|
|
23137
23317
|
allowedCwds.value,
|
|
@@ -24994,14 +25174,15 @@ async function openLocalCodexRunner(options, log2, cleanup, close) {
|
|
|
24994
25174
|
log2,
|
|
24995
25175
|
pendingControls,
|
|
24996
25176
|
controlDispatcher,
|
|
24997
|
-
dispatchControl
|
|
25177
|
+
dispatchControl,
|
|
25178
|
+
refreshDependencyStatus
|
|
24998
25179
|
);
|
|
24999
25180
|
return { instanceId, codexUrl, close };
|
|
25000
25181
|
}
|
|
25001
|
-
function finishRunnerStartup(options, log2, pendingControls, controlDispatcher, dispatchControl) {
|
|
25182
|
+
function finishRunnerStartup(options, log2, pendingControls, controlDispatcher, dispatchControl, onOnboardingDiscoveryComplete) {
|
|
25002
25183
|
controlDispatcher.value = dispatchControl;
|
|
25003
25184
|
pendingControls.splice(0).forEach(({ control, ack }) => dispatchControl(control, ack));
|
|
25004
|
-
startOnboardingDiscoveryAgents(options, log2);
|
|
25185
|
+
startOnboardingDiscoveryAgents(options, log2, onOnboardingDiscoveryComplete);
|
|
25005
25186
|
}
|
|
25006
25187
|
function commanderOutboxPersistDir() {
|
|
25007
25188
|
const override = process.env.LINZUMI_COMMANDER_OUTBOX_DIR?.trim();
|
|
@@ -25632,6 +25813,43 @@ async function acquireRunnerLockWithConflictResolution(acquire, options, log2) {
|
|
|
25632
25813
|
lockPath: error.lockPath
|
|
25633
25814
|
});
|
|
25634
25815
|
const lockTakeover = options.lockTakeover;
|
|
25816
|
+
const autoTakeoverDeps = resolveRunnerLockTakeoverDeps(
|
|
25817
|
+
error.lockPath,
|
|
25818
|
+
lockTakeover?.takeover,
|
|
25819
|
+
log2
|
|
25820
|
+
);
|
|
25821
|
+
const holderState = assessRunnerLockHolder(
|
|
25822
|
+
error.heldBy,
|
|
25823
|
+
autoTakeoverDeps.isPidAlive,
|
|
25824
|
+
() => new Date(autoTakeoverDeps.now())
|
|
25825
|
+
);
|
|
25826
|
+
if (shouldAutoTakeOverForUpdate(
|
|
25827
|
+
error.heldBy,
|
|
25828
|
+
linzumiCliVersion,
|
|
25829
|
+
options.launchSource,
|
|
25830
|
+
holderState
|
|
25831
|
+
)) {
|
|
25832
|
+
log2("runner.lock_auto_takeover_for_update", {
|
|
25833
|
+
runnerId: options.runnerId,
|
|
25834
|
+
heldByRunnerId: error.heldBy.runnerId,
|
|
25835
|
+
heldByPid: error.heldBy.pid,
|
|
25836
|
+
lockPath: error.lockPath,
|
|
25837
|
+
fromVersion: error.heldBy.cliVersion,
|
|
25838
|
+
toVersion: linzumiCliVersion,
|
|
25839
|
+
launchSource: electronAutoConnectLaunchSource,
|
|
25840
|
+
holderState: holderState.state
|
|
25841
|
+
});
|
|
25842
|
+
const autoPromptDeps = lockTakeover?.prompt ?? defaultRunnerLockTakeoverPromptDeps(lockTakeover);
|
|
25843
|
+
await resolveRunnerLockConflict({
|
|
25844
|
+
holder: error.heldBy,
|
|
25845
|
+
lockPath: error.lockPath,
|
|
25846
|
+
baseMessage: error.message,
|
|
25847
|
+
takeOverWithoutPrompt: true,
|
|
25848
|
+
prompt: autoPromptDeps,
|
|
25849
|
+
takeover: autoTakeoverDeps
|
|
25850
|
+
});
|
|
25851
|
+
return acquire();
|
|
25852
|
+
}
|
|
25635
25853
|
if (!shouldResolveRunnerLockConflict(lockTakeover)) {
|
|
25636
25854
|
throw error;
|
|
25637
25855
|
}
|
|
@@ -25848,6 +26066,32 @@ async function resumeCodexThreadForReconnect(codex, codexThreadId, resumeOverrid
|
|
|
25848
26066
|
);
|
|
25849
26067
|
}
|
|
25850
26068
|
}
|
|
26069
|
+
async function applyCodexUnavailableControl(kandan, topic, instanceId, control, log2) {
|
|
26070
|
+
const error = "agent_provider_unavailable:codex";
|
|
26071
|
+
log2("kandan.start_instance_codex_app_server_unavailable", {
|
|
26072
|
+
controlType: control.type,
|
|
26073
|
+
thread_id: controlThreadId(control) ?? null,
|
|
26074
|
+
instanceId
|
|
26075
|
+
});
|
|
26076
|
+
if (control.type === "start_instance" || control.type === "reconnect_thread") {
|
|
26077
|
+
try {
|
|
26078
|
+
await publishStartInstanceMessageState(
|
|
26079
|
+
kandan,
|
|
26080
|
+
topic,
|
|
26081
|
+
control,
|
|
26082
|
+
"failed",
|
|
26083
|
+
error,
|
|
26084
|
+
{ instanceId }
|
|
26085
|
+
);
|
|
26086
|
+
} catch (publishError) {
|
|
26087
|
+
log2("kandan.start_instance_unavailable_state_push_failed", {
|
|
26088
|
+
agent_provider: "codex",
|
|
26089
|
+
message: publishError instanceof Error ? publishError.message : String(publishError)
|
|
26090
|
+
});
|
|
26091
|
+
}
|
|
26092
|
+
}
|
|
26093
|
+
throw new Error(error);
|
|
26094
|
+
}
|
|
25851
26095
|
async function applyControl(codex, kandan, topic, instanceId, options, agentProviders, allowedCwds, remoteCodexSandboxRunner, activeRemoteCodexExecRequests, activeClaudeCodeSessions, pendingClaudeCodeApprovals, ensureClaudeCodeForwardPortSession, disposeClaudeCodeForwardPortSession, control, log2, onStartedThread, onThreadProcessStart) {
|
|
25852
26096
|
if (codex === void 0) {
|
|
25853
26097
|
switch (control.type) {
|
|
@@ -25861,6 +26105,43 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
|
|
|
25861
26105
|
activeRemoteCodexExecRequests,
|
|
25862
26106
|
log2
|
|
25863
26107
|
);
|
|
26108
|
+
// PROD WEDGE (coding jobs down on the shipped CLI beta): a runner whose
|
|
26109
|
+
// cached dependencyStatus.codex.available was `false` at connect (the
|
|
26110
|
+
// `codex --version` probe timed out during the blocking onboarding scan
|
|
26111
|
+
// and was never re-probed) never started its SHARED codex app-server, so
|
|
26112
|
+
// this `codex` is undefined. But a start_instance / reconnect_thread runs
|
|
26113
|
+
// in its OWN thread worker that spawns its OWN codex app-server - it does
|
|
26114
|
+
// NOT need the shared client. The old `default` arm returned
|
|
26115
|
+
// `agent_provider_unavailable:codex` HERE, before delegating, and only as
|
|
26116
|
+
// a bare codex_response: no thread-worker spawn, no
|
|
26117
|
+
// `runner.thread_process_starting` log, no message_state - a SILENT no-op
|
|
26118
|
+
// that left the user's job stuck in `coding` (prod thread 99d5808e,
|
|
26119
|
+
// control_seq 13). When a thread worker IS available (onThreadProcessStart
|
|
26120
|
+
// wired), fall through to the normal switch so the control delegates to
|
|
26121
|
+
// the worker; the worker's own start surfaces any genuine engine failure.
|
|
26122
|
+
// When NO thread worker exists, codex genuinely cannot run the job, so
|
|
26123
|
+
// fail LOUD (log + failed message_state + throw -> codex_error) instead of
|
|
26124
|
+
// leaving it silently stuck. This loud path is SCOPED to start_instance /
|
|
26125
|
+
// reconnect_thread only.
|
|
26126
|
+
case "start_instance":
|
|
26127
|
+
case "reconnect_thread":
|
|
26128
|
+
if (onThreadProcessStart !== void 0) {
|
|
26129
|
+
break;
|
|
26130
|
+
}
|
|
26131
|
+
return await applyCodexUnavailableControl(
|
|
26132
|
+
kandan,
|
|
26133
|
+
topic,
|
|
26134
|
+
instanceId,
|
|
26135
|
+
control,
|
|
26136
|
+
log2
|
|
26137
|
+
);
|
|
26138
|
+
// Every OTHER control type that reaches here is a request/response control
|
|
26139
|
+
// that does NOT need the shared codex app-server to fail gracefully
|
|
26140
|
+
// (browse_directory, create_project, suggest_tasks,
|
|
26141
|
+
// list_claude_code_sessions, interrupt, cancel_turn, ...). Preserve the
|
|
26142
|
+
// original behavior: return a bare `agent_provider_unavailable:codex`
|
|
26143
|
+
// codex_response - NO throw, NO failed message_state, NO start_instance
|
|
26144
|
+
// log - so onboarding/UI features keep working while codex is unavailable.
|
|
25864
26145
|
default:
|
|
25865
26146
|
return {
|
|
25866
26147
|
instanceId,
|
|
@@ -26998,22 +27279,25 @@ async function startCodexProviderInstance(args) {
|
|
|
26998
27279
|
args.options,
|
|
26999
27280
|
args.control
|
|
27000
27281
|
);
|
|
27001
|
-
const response = await
|
|
27002
|
-
|
|
27003
|
-
|
|
27004
|
-
personality: "pragmatic",
|
|
27005
|
-
developerInstructions: commanderDeveloperInstructions({
|
|
27282
|
+
const response = await withCodexStartRequestTimeout(
|
|
27283
|
+
"thread/start",
|
|
27284
|
+
args.codex.request("thread/start", {
|
|
27006
27285
|
cwd: args.cwd,
|
|
27007
|
-
|
|
27008
|
-
|
|
27009
|
-
|
|
27010
|
-
|
|
27011
|
-
|
|
27012
|
-
|
|
27013
|
-
|
|
27014
|
-
|
|
27015
|
-
|
|
27016
|
-
|
|
27286
|
+
serviceName: "kandan-local-runner",
|
|
27287
|
+
personality: "pragmatic",
|
|
27288
|
+
developerInstructions: commanderDeveloperInstructions({
|
|
27289
|
+
cwd: args.cwd,
|
|
27290
|
+
planTool: "linzumi-mcp",
|
|
27291
|
+
developerPrompt,
|
|
27292
|
+
linzumiContext
|
|
27293
|
+
}),
|
|
27294
|
+
...runtimeSettings.model === void 0 ? {} : { model: runtimeSettings.model },
|
|
27295
|
+
...runtimeSettings.reasoningEffort === void 0 ? {} : { reasoningEffort: runtimeSettings.reasoningEffort },
|
|
27296
|
+
...runtimeSettings.approvalPolicy === void 0 ? {} : { approvalPolicy: runtimeSettings.approvalPolicy },
|
|
27297
|
+
...runtimeSettings.sandbox === void 0 ? {} : { sandbox: runtimeSettings.sandbox },
|
|
27298
|
+
...runtimeSettings.fast === true ? { serviceTier: "fast" } : {}
|
|
27299
|
+
})
|
|
27300
|
+
);
|
|
27017
27301
|
const codexThreadId = extractStartedThreadId(response);
|
|
27018
27302
|
args.setStartedCodexThreadId(codexThreadId);
|
|
27019
27303
|
const workDescription = normalizedWorkDescription(
|
|
@@ -27047,13 +27331,17 @@ async function startCodexProviderInstance(args) {
|
|
|
27047
27331
|
seq: sourceSeq,
|
|
27048
27332
|
body: workDescription,
|
|
27049
27333
|
actorSlug: identity.actorUsername,
|
|
27050
|
-
actorUserId: identity.actorUserId
|
|
27334
|
+
actorUserId: identity.actorUserId,
|
|
27335
|
+
boundStartTimeout: true
|
|
27051
27336
|
});
|
|
27052
27337
|
} else {
|
|
27053
|
-
await
|
|
27054
|
-
|
|
27055
|
-
|
|
27056
|
-
|
|
27338
|
+
await withCodexStartRequestTimeout(
|
|
27339
|
+
"turn/start",
|
|
27340
|
+
args.codex.request("turn/start", {
|
|
27341
|
+
threadId: codexThreadId,
|
|
27342
|
+
input: [{ type: "text", text: workDescription }]
|
|
27343
|
+
})
|
|
27344
|
+
);
|
|
27057
27345
|
}
|
|
27058
27346
|
}
|
|
27059
27347
|
return {
|
|
@@ -28953,9 +29241,10 @@ function redactedThreadRunnerCliArgs(args) {
|
|
|
28953
29241
|
function optionalCliValue(flag, value) {
|
|
28954
29242
|
return value === void 0 || value === "" ? [] : [flag, value];
|
|
28955
29243
|
}
|
|
28956
|
-
function startOnboardingDiscoveryAgents(options, log2) {
|
|
29244
|
+
function startOnboardingDiscoveryAgents(options, log2, onOnboardingDiscoveryComplete) {
|
|
28957
29245
|
const workspaceSlug = runnerWorkspaceSlug(options);
|
|
28958
29246
|
if (!shouldStartOnboardingDiscoveryAgents(options, workspaceSlug)) {
|
|
29247
|
+
void onOnboardingDiscoveryComplete?.();
|
|
28959
29248
|
return;
|
|
28960
29249
|
}
|
|
28961
29250
|
const startKey = onboardingDiscoveryAgentStartKey(options, workspaceSlug);
|
|
@@ -29013,6 +29302,7 @@ function startOnboardingDiscoveryAgents(options, log2) {
|
|
|
29013
29302
|
workers_completed: 2,
|
|
29014
29303
|
successful_write_count: successfulWriteCount
|
|
29015
29304
|
});
|
|
29305
|
+
await onOnboardingDiscoveryComplete?.();
|
|
29016
29306
|
});
|
|
29017
29307
|
}
|
|
29018
29308
|
function withSuccessfulWriteCount(report, successfulPostStartWriteCount) {
|
|
@@ -68863,7 +69153,7 @@ async function parseStartRunnerArgs(args, deps = {
|
|
|
68863
69153
|
cwd,
|
|
68864
69154
|
codexBin,
|
|
68865
69155
|
codexUrl: stringValue8(values, "codex-url"),
|
|
68866
|
-
launchSource:
|
|
69156
|
+
launchSource: electronAutoConnectLaunchSource2(),
|
|
68867
69157
|
launchTui: values.get("launch-tui") === true,
|
|
68868
69158
|
fast: values.get("fast") === true,
|
|
68869
69159
|
logFile: stringValue8(values, "log-file"),
|
|
@@ -68968,7 +69258,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
68968
69258
|
cwd,
|
|
68969
69259
|
codexBin,
|
|
68970
69260
|
codexUrl: stringValue8(values, "codex-url"),
|
|
68971
|
-
launchSource:
|
|
69261
|
+
launchSource: electronAutoConnectLaunchSource2(),
|
|
68972
69262
|
launchTui: values.get("launch-tui") === true,
|
|
68973
69263
|
fast: values.get("fast") === true,
|
|
68974
69264
|
logFile: stringValue8(values, "log-file"),
|
|
@@ -69143,7 +69433,7 @@ async function parseRunnerArgs(args, deps = {
|
|
|
69143
69433
|
cwd,
|
|
69144
69434
|
codexBin,
|
|
69145
69435
|
codexUrl: stringValue8(values, "codex-url"),
|
|
69146
|
-
launchSource:
|
|
69436
|
+
launchSource: electronAutoConnectLaunchSource2(),
|
|
69147
69437
|
launchTui: values.get("launch-tui") === true,
|
|
69148
69438
|
fast: values.get("fast") === true,
|
|
69149
69439
|
logFile: stringValue8(values, "log-file"),
|
|
@@ -69178,11 +69468,11 @@ function runnerRuntimeDefaultsFromValues(values) {
|
|
|
69178
69468
|
allowPortForwardingByDefault: true
|
|
69179
69469
|
};
|
|
69180
69470
|
}
|
|
69181
|
-
function
|
|
69471
|
+
function electronAutoConnectLaunchSource2() {
|
|
69182
69472
|
return process.env.LINZUMI_ELECTRON_AUTO_CONNECT_RUNNER === "1" ? "electron_auto_connect" : void 0;
|
|
69183
69473
|
}
|
|
69184
69474
|
function connectLaunchSourceTelemetryValue() {
|
|
69185
|
-
return
|
|
69475
|
+
return electronAutoConnectLaunchSource2() ?? "cli";
|
|
69186
69476
|
}
|
|
69187
69477
|
function workspaceTelemetryAttribute(workspace) {
|
|
69188
69478
|
return workspace === void 0 ? {} : { workspace };
|
package/package.json
CHANGED