@linzumi/cli 0.0.109-beta → 0.0.111-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 +404 -46
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -5863,6 +5863,9 @@ function handleEvent(state, event, deps, effects) {
|
|
|
5863
5863
|
}
|
|
5864
5864
|
handleCodexNotification(state, event, deps, effects);
|
|
5865
5865
|
}
|
|
5866
|
+
function modelInteractionMethod(method) {
|
|
5867
|
+
return modelInteractionMethods.has(method);
|
|
5868
|
+
}
|
|
5866
5869
|
function handleCodexNotification(state, event, deps, effects) {
|
|
5867
5870
|
const method = event.notification.method;
|
|
5868
5871
|
const params = event.notification.params ?? {};
|
|
@@ -5879,9 +5882,7 @@ function handleCodexNotification(state, event, deps, effects) {
|
|
|
5879
5882
|
const explicitTurnId = notificationTurnId(params);
|
|
5880
5883
|
const turnId = explicitTurnId ?? singleActiveTurnId(state);
|
|
5881
5884
|
if (turnId === void 0) {
|
|
5882
|
-
effects.push(
|
|
5883
|
-
log("pipeline.loop.notification_without_turn", { method })
|
|
5884
|
-
);
|
|
5885
|
+
effects.push(log("pipeline.loop.notification_without_turn", { method }));
|
|
5885
5886
|
return;
|
|
5886
5887
|
}
|
|
5887
5888
|
if (state.terminalTurnIds.has(turnId)) {
|
|
@@ -5902,6 +5903,10 @@ function handleCodexNotification(state, event, deps, effects) {
|
|
|
5902
5903
|
}
|
|
5903
5904
|
turn = createTurn(state, turnId, sourceSeq);
|
|
5904
5905
|
}
|
|
5906
|
+
turn.notificationCount += 1;
|
|
5907
|
+
if (modelInteractionMethod(method)) {
|
|
5908
|
+
turn.modelInteractionSeen = true;
|
|
5909
|
+
}
|
|
5905
5910
|
if (method === "turn/started") {
|
|
5906
5911
|
return;
|
|
5907
5912
|
}
|
|
@@ -5915,6 +5920,7 @@ function handleCodexNotification(state, event, deps, effects) {
|
|
|
5915
5920
|
return;
|
|
5916
5921
|
}
|
|
5917
5922
|
if (method === "error") {
|
|
5923
|
+
turn.errorNotificationCount += 1;
|
|
5918
5924
|
const upstreamReason = upstreamErrorReason(params);
|
|
5919
5925
|
if (upstreamReason !== void 0) {
|
|
5920
5926
|
turn.lastUpstreamErrorReason = upstreamReason;
|
|
@@ -5924,6 +5930,17 @@ function handleCodexNotification(state, event, deps, effects) {
|
|
|
5924
5930
|
reason: upstreamReason
|
|
5925
5931
|
})
|
|
5926
5932
|
);
|
|
5933
|
+
} else {
|
|
5934
|
+
const diagnosticText = errorDiagnosticText(params);
|
|
5935
|
+
if (diagnosticText !== void 0) {
|
|
5936
|
+
turn.lastErrorDiagnosticText = diagnosticText;
|
|
5937
|
+
effects.push(
|
|
5938
|
+
log("codex.error_without_http_status_captured", {
|
|
5939
|
+
turn_id: turn.turnId,
|
|
5940
|
+
diagnostic_text: diagnosticText
|
|
5941
|
+
})
|
|
5942
|
+
);
|
|
5943
|
+
}
|
|
5927
5944
|
}
|
|
5928
5945
|
return;
|
|
5929
5946
|
}
|
|
@@ -5978,6 +5995,10 @@ function createTurn(state, turnId, sourceSeq) {
|
|
|
5978
5995
|
phase: "active",
|
|
5979
5996
|
protocolFailureReason: void 0,
|
|
5980
5997
|
lastUpstreamErrorReason: void 0,
|
|
5998
|
+
lastErrorDiagnosticText: void 0,
|
|
5999
|
+
errorNotificationCount: 0,
|
|
6000
|
+
notificationCount: 0,
|
|
6001
|
+
modelInteractionSeen: false,
|
|
5981
6002
|
items: []
|
|
5982
6003
|
};
|
|
5983
6004
|
state.turns.set(turnId, turn);
|
|
@@ -6144,7 +6165,11 @@ function handleItemCompleted(turn, params, deps, effects) {
|
|
|
6144
6165
|
);
|
|
6145
6166
|
}
|
|
6146
6167
|
function emitRowUpdate(turn, item, deltaIndex, streamState, deps, effects) {
|
|
6147
|
-
const rendered = renderPipelineItem(
|
|
6168
|
+
const rendered = renderPipelineItem(
|
|
6169
|
+
item.wireItemKey,
|
|
6170
|
+
item.content,
|
|
6171
|
+
streamState
|
|
6172
|
+
);
|
|
6148
6173
|
if (!item.posted) {
|
|
6149
6174
|
if (rendered.body.trim() === "") {
|
|
6150
6175
|
return;
|
|
@@ -6238,9 +6263,7 @@ function createItem(turn, streamKind, itemId, deps) {
|
|
|
6238
6263
|
}
|
|
6239
6264
|
function handleSnapshot(state, turnId, snapshot, deps, effects) {
|
|
6240
6265
|
if (state.terminalTurnIds.has(turnId)) {
|
|
6241
|
-
effects.push(
|
|
6242
|
-
log("pipeline.loop.duplicate_snapshot", { turn_id: turnId })
|
|
6243
|
-
);
|
|
6266
|
+
effects.push(log("pipeline.loop.duplicate_snapshot", { turn_id: turnId }));
|
|
6244
6267
|
return;
|
|
6245
6268
|
}
|
|
6246
6269
|
const turn = state.turns.get(turnId);
|
|
@@ -6363,7 +6386,9 @@ function handleSnapshot(state, turnId, snapshot, deps, effects) {
|
|
|
6363
6386
|
const assistantResponseSeen = turn.items.some(
|
|
6364
6387
|
(item) => item.identity.streamKind === "assistant" && item.posted
|
|
6365
6388
|
) || projected.some((proj) => proj.streamKind === "assistant");
|
|
6366
|
-
const
|
|
6389
|
+
const emptyTurnDiagnostic = !assistantResponseSeen && turn.protocolFailureReason === void 0 && turn.lastUpstreamErrorReason === void 0 ? classifyEmptyTurn(turn, projected.length) : void 0;
|
|
6390
|
+
const baseNoOutputReason = turn.lastUpstreamErrorReason ?? (emptyTurnDiagnostic === void 0 ? completedWithoutAssistantOutputReason : `${completedWithoutAssistantOutputReason} [${emptyTurnDiagnostic.cause}]`);
|
|
6391
|
+
const terminalFailureReason = turn.protocolFailureReason ?? (assistantResponseSeen ? void 0 : baseNoOutputReason);
|
|
6367
6392
|
if (turn.protocolFailureReason !== void 0) {
|
|
6368
6393
|
effects.push(
|
|
6369
6394
|
log("codex.turn_completed_with_protocol_failure", {
|
|
@@ -6381,7 +6406,19 @@ function handleSnapshot(state, turnId, snapshot, deps, effects) {
|
|
|
6381
6406
|
turn_id: turn.turnId,
|
|
6382
6407
|
source_seq: turn.sourceSeq,
|
|
6383
6408
|
streamed_item_count: turn.items.length,
|
|
6384
|
-
snapshot_item_count: projected.length
|
|
6409
|
+
snapshot_item_count: projected.length,
|
|
6410
|
+
// LAUNCH-LIVE self-diagnosing fields: tell apart "codex never called the
|
|
6411
|
+
// model" from "model returned empty" from "error without HTTP status".
|
|
6412
|
+
notification_count: turn.notificationCount,
|
|
6413
|
+
error_notification_count: turn.errorNotificationCount,
|
|
6414
|
+
model_interaction_seen: turn.modelInteractionSeen,
|
|
6415
|
+
last_error_diagnostic_text: turn.lastErrorDiagnosticText ?? null,
|
|
6416
|
+
last_upstream_error_reason: turn.lastUpstreamErrorReason ?? null,
|
|
6417
|
+
empty_turn_cause: emptyTurnDiagnostic?.cause ?? null,
|
|
6418
|
+
// True iff the surfaced failure is the safe, retryable empty/no-response
|
|
6419
|
+
// terminal (no output produced, no real upstream error) - the signal
|
|
6420
|
+
// the client uses to offer a one-click retry (PART B, loud affordance).
|
|
6421
|
+
retryable_empty_turn: emptyTurnDiagnostic !== void 0
|
|
6385
6422
|
})
|
|
6386
6423
|
);
|
|
6387
6424
|
}
|
|
@@ -6394,7 +6431,13 @@ function handleSnapshot(state, turnId, snapshot, deps, effects) {
|
|
|
6394
6431
|
seq: turn.sourceSeq,
|
|
6395
6432
|
...terminalFailureReason === void 0 ? { status: "processed" } : {
|
|
6396
6433
|
status: "failed",
|
|
6397
|
-
reason: terminalFailureReason
|
|
6434
|
+
reason: terminalFailureReason,
|
|
6435
|
+
// PART B (loud retry affordance): mark the safe empty/no-response
|
|
6436
|
+
// terminal as retryable so the client can offer a one-click retry.
|
|
6437
|
+
// Additive optional field; older servers ignore it. Only the empty
|
|
6438
|
+
// terminal is retryable - real upstream errors (402/429/gateway,
|
|
6439
|
+
// protocol failures) carry their own handling and are NOT flagged.
|
|
6440
|
+
...emptyTurnDiagnostic !== void 0 ? { retryable: true } : {}
|
|
6398
6441
|
}
|
|
6399
6442
|
},
|
|
6400
6443
|
resolution: "must_ack"
|
|
@@ -6483,7 +6526,9 @@ function failureReason(params) {
|
|
|
6483
6526
|
return stringValue(params.reason) ?? stringValue(params.message) ?? stringValue(objectValue(params.error)?.message) ?? stringValue(params.error) ?? "codex_turn_aborted";
|
|
6484
6527
|
}
|
|
6485
6528
|
function upstreamErrorReason(params) {
|
|
6486
|
-
const summaryRaw = stringValue(params.diagnostic_summary) ?? stringValue(
|
|
6529
|
+
const summaryRaw = stringValue(params.diagnostic_summary) ?? stringValue(
|
|
6530
|
+
objectValue(objectValue(params.diagnostic_payload)?.error)?.message
|
|
6531
|
+
);
|
|
6487
6532
|
if (summaryRaw === void 0) {
|
|
6488
6533
|
return void 0;
|
|
6489
6534
|
}
|
|
@@ -6501,10 +6546,33 @@ function upstreamErrorHttpStatus(params) {
|
|
|
6501
6546
|
const code = disconnected?.httpStatusCode;
|
|
6502
6547
|
return typeof code === "number" ? code : void 0;
|
|
6503
6548
|
}
|
|
6549
|
+
function errorDiagnosticText(params) {
|
|
6550
|
+
const raw = stringValue(params.message) ?? stringValue(params.reason) ?? stringValue(objectValue(params.error)?.message) ?? stringValue(params.error) ?? stringValue(params.diagnostic);
|
|
6551
|
+
if (raw === void 0) {
|
|
6552
|
+
return void 0;
|
|
6553
|
+
}
|
|
6554
|
+
const cleaned = raw.replace(/<[^>]*>/g, " ").replace(/data:[^"' )]+/g, "").replace(/\s+/g, " ").trim().slice(0, 180);
|
|
6555
|
+
return cleaned.length === 0 ? void 0 : cleaned;
|
|
6556
|
+
}
|
|
6557
|
+
function classifyEmptyTurn(turn, snapshotItemCount) {
|
|
6558
|
+
if (turn.lastErrorDiagnosticText !== void 0) {
|
|
6559
|
+
return {
|
|
6560
|
+
cause: `codex error without HTTP status: ${turn.lastErrorDiagnosticText}`
|
|
6561
|
+
};
|
|
6562
|
+
}
|
|
6563
|
+
if (!turn.modelInteractionSeen) {
|
|
6564
|
+
return {
|
|
6565
|
+
cause: `codex never called the model: 0 model interactions, ${turn.notificationCount} notifications, ${turn.errorNotificationCount} errors`
|
|
6566
|
+
};
|
|
6567
|
+
}
|
|
6568
|
+
return {
|
|
6569
|
+
cause: `model returned no assistant output: ${turn.items.length} streamed items, ${snapshotItemCount} snapshot items`
|
|
6570
|
+
};
|
|
6571
|
+
}
|
|
6504
6572
|
function log(event, fields) {
|
|
6505
6573
|
return { type: "log", event, fields };
|
|
6506
6574
|
}
|
|
6507
|
-
var terminalRowStreamStates, turnMappingReadyMethod, turnMappingFailedMethod, maxTerminalTurnIds, completedWithoutAssistantOutputReason, unsupportedCodexToolCallReasonPrefix, turnTerminalFailureMethods, handledNotificationMethods;
|
|
6575
|
+
var terminalRowStreamStates, turnMappingReadyMethod, turnMappingFailedMethod, maxTerminalTurnIds, completedWithoutAssistantOutputReason, unsupportedCodexToolCallReasonPrefix, turnTerminalFailureMethods, handledNotificationMethods, modelInteractionMethods;
|
|
6508
6576
|
var init_transition = __esm({
|
|
6509
6577
|
"src/pipeline/transition.ts"() {
|
|
6510
6578
|
"use strict";
|
|
@@ -6545,6 +6613,17 @@ var init_transition = __esm({
|
|
|
6545
6613
|
"item/completed",
|
|
6546
6614
|
"response_item"
|
|
6547
6615
|
]);
|
|
6616
|
+
modelInteractionMethods = /* @__PURE__ */ new Set([
|
|
6617
|
+
"item/agentMessage/delta",
|
|
6618
|
+
"item/reasoning/textDelta",
|
|
6619
|
+
"item/commandExecution/outputDelta",
|
|
6620
|
+
"command/exec/outputDelta",
|
|
6621
|
+
"item/fileChange/outputDelta",
|
|
6622
|
+
"item/commandExecution/terminalInteraction",
|
|
6623
|
+
"item/started",
|
|
6624
|
+
"item/completed",
|
|
6625
|
+
"response_item"
|
|
6626
|
+
]);
|
|
6548
6627
|
}
|
|
6549
6628
|
});
|
|
6550
6629
|
|
|
@@ -20078,7 +20157,7 @@ var linzumiCliVersion, linzumiCliVersionText;
|
|
|
20078
20157
|
var init_version = __esm({
|
|
20079
20158
|
"src/version.ts"() {
|
|
20080
20159
|
"use strict";
|
|
20081
|
-
linzumiCliVersion = "0.0.
|
|
20160
|
+
linzumiCliVersion = "0.0.111-beta";
|
|
20082
20161
|
linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
|
|
20083
20162
|
}
|
|
20084
20163
|
});
|
|
@@ -23176,30 +23255,225 @@ var init_threadCodexWorkerIpc = __esm({
|
|
|
23176
23255
|
}
|
|
23177
23256
|
});
|
|
23178
23257
|
|
|
23258
|
+
// src/signupTaskSuggestionsProgress.ts
|
|
23259
|
+
function basenameOf(rawPath) {
|
|
23260
|
+
const trimmed = rawPath.trim();
|
|
23261
|
+
if (trimmed === "") {
|
|
23262
|
+
return void 0;
|
|
23263
|
+
}
|
|
23264
|
+
const withoutTrailing = trimmed.replace(/[/\\]+$/, "");
|
|
23265
|
+
const segments = withoutTrailing.split(/[/\\]+/);
|
|
23266
|
+
const last = segments[segments.length - 1];
|
|
23267
|
+
if (last === void 0 || last === "" || last === "." || last === "..") {
|
|
23268
|
+
return void 0;
|
|
23269
|
+
}
|
|
23270
|
+
if (last.length > MAX_BASENAME_LENGTH) {
|
|
23271
|
+
return `${last.slice(0, MAX_BASENAME_LENGTH - 1)}\u2026`;
|
|
23272
|
+
}
|
|
23273
|
+
return last;
|
|
23274
|
+
}
|
|
23275
|
+
function lookingAtFileLabel(rawPath) {
|
|
23276
|
+
if (typeof rawPath !== "string") {
|
|
23277
|
+
return void 0;
|
|
23278
|
+
}
|
|
23279
|
+
const basename10 = basenameOf(rawPath);
|
|
23280
|
+
return basename10 === void 0 ? void 0 : `Looking at ${basename10}...`;
|
|
23281
|
+
}
|
|
23282
|
+
function commandLabel2(command) {
|
|
23283
|
+
let head;
|
|
23284
|
+
let target;
|
|
23285
|
+
if (Array.isArray(command)) {
|
|
23286
|
+
const parts = command.filter((part) => typeof part === "string");
|
|
23287
|
+
const meaningful = parts.filter(
|
|
23288
|
+
(part) => part !== "bash" && part !== "sh" && part !== "-lc" && part !== "-c"
|
|
23289
|
+
);
|
|
23290
|
+
head = meaningful[0];
|
|
23291
|
+
target = meaningful.slice(1).find((part) => !part.startsWith("-"));
|
|
23292
|
+
} else if (typeof command === "string") {
|
|
23293
|
+
const tokens = command.trim().split(/\s+/);
|
|
23294
|
+
head = tokens[0];
|
|
23295
|
+
target = tokens.slice(1).find((part) => !part.startsWith("-"));
|
|
23296
|
+
} else {
|
|
23297
|
+
return void 0;
|
|
23298
|
+
}
|
|
23299
|
+
if (head === void 0) {
|
|
23300
|
+
return void 0;
|
|
23301
|
+
}
|
|
23302
|
+
const baseCommand = basenameOf(head) ?? head;
|
|
23303
|
+
if (!READ_COMMAND_PREFIXES.includes(baseCommand)) {
|
|
23304
|
+
return READING_REPO;
|
|
23305
|
+
}
|
|
23306
|
+
const fileLabel = target === void 0 ? void 0 : lookingAtFileLabel(target);
|
|
23307
|
+
return fileLabel ?? READING_REPO;
|
|
23308
|
+
}
|
|
23309
|
+
function progressLabelForCodexEvent(event) {
|
|
23310
|
+
if (typeof event !== "object" || event === null || Array.isArray(event)) {
|
|
23311
|
+
return void 0;
|
|
23312
|
+
}
|
|
23313
|
+
const record = event;
|
|
23314
|
+
const item = record["item"];
|
|
23315
|
+
if (typeof item === "object" && item !== null && !Array.isArray(item)) {
|
|
23316
|
+
const itemRecord = item;
|
|
23317
|
+
const itemType = itemRecord["item_type"] ?? itemRecord["type"];
|
|
23318
|
+
switch (itemType) {
|
|
23319
|
+
case "reasoning":
|
|
23320
|
+
return READING_REPO;
|
|
23321
|
+
case "command_execution":
|
|
23322
|
+
case "local_shell_call":
|
|
23323
|
+
return commandLabel2(itemRecord["command"] ?? itemRecord["argv"]) ?? READING_REPO;
|
|
23324
|
+
case "file_change":
|
|
23325
|
+
case "file_read":
|
|
23326
|
+
return lookingAtFileLabel(itemRecord["path"]) ?? READING_REPO;
|
|
23327
|
+
case "agent_message":
|
|
23328
|
+
case "assistant_message":
|
|
23329
|
+
return DRAFTING_TASKS;
|
|
23330
|
+
default:
|
|
23331
|
+
return void 0;
|
|
23332
|
+
}
|
|
23333
|
+
}
|
|
23334
|
+
const msg = record["msg"];
|
|
23335
|
+
const msgRecord = typeof msg === "object" && msg !== null && !Array.isArray(msg) ? msg : record;
|
|
23336
|
+
const msgType = msgRecord["type"] ?? record["type"];
|
|
23337
|
+
switch (msgType) {
|
|
23338
|
+
case "task_started":
|
|
23339
|
+
case "agent_reasoning":
|
|
23340
|
+
case "agent_reasoning_delta":
|
|
23341
|
+
case "agent_reasoning_section_break":
|
|
23342
|
+
return READING_REPO;
|
|
23343
|
+
case "exec_command_begin":
|
|
23344
|
+
case "exec_command_end":
|
|
23345
|
+
return commandLabel2(msgRecord["command"]) ?? READING_REPO;
|
|
23346
|
+
case "agent_message":
|
|
23347
|
+
case "agent_message_delta":
|
|
23348
|
+
return DRAFTING_TASKS;
|
|
23349
|
+
default:
|
|
23350
|
+
return void 0;
|
|
23351
|
+
}
|
|
23352
|
+
}
|
|
23353
|
+
function createTaskSuggestionProgressParser(onLabel) {
|
|
23354
|
+
let buffer = "";
|
|
23355
|
+
let lastLabel;
|
|
23356
|
+
const emit = (label) => {
|
|
23357
|
+
if (label === void 0 || label === lastLabel) {
|
|
23358
|
+
return;
|
|
23359
|
+
}
|
|
23360
|
+
lastLabel = label;
|
|
23361
|
+
try {
|
|
23362
|
+
onLabel(label);
|
|
23363
|
+
} catch {
|
|
23364
|
+
}
|
|
23365
|
+
};
|
|
23366
|
+
const consumeLine = (line) => {
|
|
23367
|
+
const trimmed = line.trim();
|
|
23368
|
+
if (trimmed === "" || trimmed[0] !== "{") {
|
|
23369
|
+
return;
|
|
23370
|
+
}
|
|
23371
|
+
let parsed;
|
|
23372
|
+
try {
|
|
23373
|
+
parsed = JSON.parse(trimmed);
|
|
23374
|
+
} catch {
|
|
23375
|
+
return;
|
|
23376
|
+
}
|
|
23377
|
+
emit(progressLabelForCodexEvent(parsed));
|
|
23378
|
+
};
|
|
23379
|
+
return {
|
|
23380
|
+
push: (chunk) => {
|
|
23381
|
+
buffer += chunk;
|
|
23382
|
+
let newlineIndex = buffer.indexOf("\n");
|
|
23383
|
+
while (newlineIndex !== -1) {
|
|
23384
|
+
const line = buffer.slice(0, newlineIndex);
|
|
23385
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
23386
|
+
consumeLine(line);
|
|
23387
|
+
newlineIndex = buffer.indexOf("\n");
|
|
23388
|
+
}
|
|
23389
|
+
},
|
|
23390
|
+
flush: () => {
|
|
23391
|
+
if (buffer.trim() !== "") {
|
|
23392
|
+
consumeLine(buffer);
|
|
23393
|
+
buffer = "";
|
|
23394
|
+
}
|
|
23395
|
+
}
|
|
23396
|
+
};
|
|
23397
|
+
}
|
|
23398
|
+
var READING_REPO, DRAFTING_TASKS, MAX_BASENAME_LENGTH, READ_COMMAND_PREFIXES;
|
|
23399
|
+
var init_signupTaskSuggestionsProgress = __esm({
|
|
23400
|
+
"src/signupTaskSuggestionsProgress.ts"() {
|
|
23401
|
+
"use strict";
|
|
23402
|
+
READING_REPO = "Reading your repository...";
|
|
23403
|
+
DRAFTING_TASKS = "Drafting tasks...";
|
|
23404
|
+
MAX_BASENAME_LENGTH = 60;
|
|
23405
|
+
READ_COMMAND_PREFIXES = [
|
|
23406
|
+
"ls",
|
|
23407
|
+
"cat",
|
|
23408
|
+
"head",
|
|
23409
|
+
"tail",
|
|
23410
|
+
"find",
|
|
23411
|
+
"rg",
|
|
23412
|
+
"grep",
|
|
23413
|
+
"tree",
|
|
23414
|
+
"wc",
|
|
23415
|
+
"sed",
|
|
23416
|
+
"awk",
|
|
23417
|
+
"pwd",
|
|
23418
|
+
"stat",
|
|
23419
|
+
"file"
|
|
23420
|
+
];
|
|
23421
|
+
}
|
|
23422
|
+
});
|
|
23423
|
+
|
|
23179
23424
|
// src/signupTaskSuggestions.ts
|
|
23180
23425
|
import { spawn as spawn7 } from "node:child_process";
|
|
23181
23426
|
import { mkdtempSync as mkdtempSync3, readFileSync as readFileSync16, rmSync as rmSync4, writeFileSync as writeFileSync11 } from "node:fs";
|
|
23182
23427
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
23183
23428
|
import { join as join20 } from "node:path";
|
|
23184
23429
|
async function suggestSignupTasksWithCodex(args) {
|
|
23185
|
-
const
|
|
23430
|
+
const model = resolveTaskSuggestionModel(args.model, args.modelProvider);
|
|
23431
|
+
const startedAt = Date.now();
|
|
23186
23432
|
let previousResponse;
|
|
23187
|
-
|
|
23188
|
-
|
|
23189
|
-
|
|
23190
|
-
|
|
23191
|
-
|
|
23192
|
-
|
|
23193
|
-
}
|
|
23433
|
+
let lastFailure;
|
|
23434
|
+
for (let attempt = 0; attempt <= MAX_SCHEMA_REPAIR_ATTEMPTS; attempt += 1) {
|
|
23435
|
+
const elapsed = Date.now() - startedAt;
|
|
23436
|
+
const remaining = SUGGESTION_TIMEOUT_MS - elapsed;
|
|
23437
|
+
if (remaining <= 0) {
|
|
23438
|
+
break;
|
|
23439
|
+
}
|
|
23440
|
+
let response;
|
|
23441
|
+
try {
|
|
23442
|
+
response = await runCodexTaskSuggestion({
|
|
23443
|
+
projectPath: args.projectPath,
|
|
23444
|
+
codexBin: args.codexBin,
|
|
23445
|
+
model,
|
|
23446
|
+
modelProvider: args.modelProvider,
|
|
23447
|
+
previousResponse,
|
|
23448
|
+
timeoutMs: remaining,
|
|
23449
|
+
onProgress: args.onProgress
|
|
23450
|
+
});
|
|
23451
|
+
} catch (error) {
|
|
23452
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
23453
|
+
}
|
|
23194
23454
|
const tasks = parseTaskSuggestionResponse(response);
|
|
23195
23455
|
if (tasks !== void 0) {
|
|
23196
23456
|
return tasks;
|
|
23197
23457
|
}
|
|
23198
23458
|
previousResponse = response;
|
|
23459
|
+
lastFailure = new Error(
|
|
23460
|
+
"Codex returned a response that did not match the task suggestion schema"
|
|
23461
|
+
);
|
|
23199
23462
|
}
|
|
23200
|
-
throw new Error(
|
|
23201
|
-
|
|
23202
|
-
|
|
23463
|
+
throw lastFailure ?? new Error("Codex did not return valid task suggestions in the time budget");
|
|
23464
|
+
}
|
|
23465
|
+
function resolveTaskSuggestionModel(explicitModel, modelProvider) {
|
|
23466
|
+
const envModel = process.env.LINZUMI_SIGNUP_TASK_MODEL;
|
|
23467
|
+
if (explicitModel !== void 0 && explicitModel !== "") {
|
|
23468
|
+
return explicitModel;
|
|
23469
|
+
}
|
|
23470
|
+
if (envModel !== void 0 && envModel !== "") {
|
|
23471
|
+
return envModel;
|
|
23472
|
+
}
|
|
23473
|
+
if (modelProvider !== void 0) {
|
|
23474
|
+
return DEFAULT_WAFER_SUGGESTION_MODEL;
|
|
23475
|
+
}
|
|
23476
|
+
return DEFAULT_CODEX_AUTH_SUGGESTION_MODEL;
|
|
23203
23477
|
}
|
|
23204
23478
|
async function runCodexTaskSuggestion(args) {
|
|
23205
23479
|
const tempRoot = mkdtempSync3(join20(tmpdir2(), "linzumi-signup-codex-tasks-"));
|
|
@@ -23217,11 +23491,14 @@ async function runCodexTaskSuggestion(args) {
|
|
|
23217
23491
|
codexTaskSuggestionProcess({
|
|
23218
23492
|
command: args.codexBin,
|
|
23219
23493
|
model: args.model,
|
|
23494
|
+
modelProvider: args.modelProvider,
|
|
23220
23495
|
projectPath: args.projectPath,
|
|
23221
23496
|
schemaPath,
|
|
23222
23497
|
outputPath,
|
|
23223
|
-
prompt
|
|
23224
|
-
|
|
23498
|
+
prompt,
|
|
23499
|
+
timeoutMs: args.timeoutMs
|
|
23500
|
+
}),
|
|
23501
|
+
args.onProgress
|
|
23225
23502
|
);
|
|
23226
23503
|
return readFileSync16(outputPath, "utf8");
|
|
23227
23504
|
} finally {
|
|
@@ -23236,9 +23513,19 @@ function codexTaskSuggestionProcess(args) {
|
|
|
23236
23513
|
"--model",
|
|
23237
23514
|
args.model,
|
|
23238
23515
|
"-c",
|
|
23239
|
-
|
|
23516
|
+
// RELIABILITY: minimal reasoning effort keeps the agentic turn fast and
|
|
23517
|
+
// far less flaky while still producing repo-specific tasks (it still
|
|
23518
|
+
// inspects the real repo below). The latency/flake budget was the main
|
|
23519
|
+
// driver of runner_task_suggestion_failed.
|
|
23520
|
+
'model_reasoning_effort="minimal"',
|
|
23240
23521
|
"-c",
|
|
23241
23522
|
'approval_policy="never"',
|
|
23523
|
+
// Wafer routing: render the `-c model_providers.linzumi.*` config args
|
|
23524
|
+
// plus `-c model_provider=linzumi`, identical to the main per-thread codex
|
|
23525
|
+
// app-server start (codexModelProviderConfigArgs). Secrets stay in env via
|
|
23526
|
+
// env_key/env_http_headers, never argv. Omitted for native-codex-auth
|
|
23527
|
+
// users, who keep their own provider.
|
|
23528
|
+
...args.modelProvider === void 0 ? [] : codexModelProviderConfigArgs(args.modelProvider.config),
|
|
23242
23529
|
"--sandbox",
|
|
23243
23530
|
"read-only",
|
|
23244
23531
|
"--skip-git-repo-check",
|
|
@@ -23248,13 +23535,22 @@ function codexTaskSuggestionProcess(args) {
|
|
|
23248
23535
|
args.schemaPath,
|
|
23249
23536
|
"--output-last-message",
|
|
23250
23537
|
args.outputPath,
|
|
23538
|
+
// LIVE PROGRESS: stream the agentic turn as JSONL events on stdout so we
|
|
23539
|
+
// can parse privacy-safe step labels ("Reading your repository...",
|
|
23540
|
+
// "Looking at <file>...", "Drafting tasks...") and relay them to the
|
|
23541
|
+
// onboarding wizard while the (up to ~150s) turn runs. The final task
|
|
23542
|
+
// JSON still comes from --output-last-message, so this is purely additive
|
|
23543
|
+
// - if a codex build ignores or changes --json, we simply get no progress
|
|
23544
|
+
// and the suggestion result is unaffected.
|
|
23545
|
+
"--json",
|
|
23251
23546
|
"--color",
|
|
23252
23547
|
"never",
|
|
23253
23548
|
"-"
|
|
23254
23549
|
],
|
|
23255
23550
|
cwd: args.projectPath,
|
|
23256
23551
|
stdin: args.prompt,
|
|
23257
|
-
|
|
23552
|
+
...args.modelProvider === void 0 ? {} : { env: args.modelProvider.env },
|
|
23553
|
+
timeoutMs: args.timeoutMs ?? SUGGESTION_TIMEOUT_MS
|
|
23258
23554
|
};
|
|
23259
23555
|
}
|
|
23260
23556
|
function taskSuggestionPrompt(previousResponse) {
|
|
@@ -23272,16 +23568,13 @@ function taskSuggestionPrompt(previousResponse) {
|
|
|
23272
23568
|
"Task:",
|
|
23273
23569
|
"Inspect this repository read-only and suggest exactly 5 useful quick starter tasks for Codex agents.",
|
|
23274
23570
|
"",
|
|
23275
|
-
"
|
|
23276
|
-
"-
|
|
23277
|
-
"-
|
|
23278
|
-
"-
|
|
23279
|
-
"- Be mindful of GitHub rate limits, CPU usage, and network usage; prefer one or two small calls and do not paginate or crawl exhaustively.",
|
|
23280
|
-
"- If a GitHub call returns unauthorized, forbidden, or not found for this repository, stop GitHub lookups for this repository.",
|
|
23281
|
-
"- Use pull request and issue titles, states, labels, and recent activity to infer what the repo is about, what the user has been working on, and likely next tasks.",
|
|
23571
|
+
"How to inspect (be fast - aim to answer within a single short pass):",
|
|
23572
|
+
"- Read the repo locally: top-level files, README, package manifests, and a shallow look at the main source directories are enough to infer what the project is.",
|
|
23573
|
+
"- Base the suggestions on the ACTUAL repository contents you observe, not on generic templates.",
|
|
23574
|
+
"- Do NOT crawl GitHub. Skip `gh` entirely; local files are sufficient and far faster.",
|
|
23282
23575
|
"",
|
|
23283
23576
|
"Constraints:",
|
|
23284
|
-
"- Prefer tasks that are small, concrete, and
|
|
23577
|
+
"- Prefer tasks that are small, concrete, and specific to THIS repository (reference real files, modules, or features you saw).",
|
|
23285
23578
|
"- Do not modify files.",
|
|
23286
23579
|
"- Do not include markdown fences or prose outside the JSON response.",
|
|
23287
23580
|
"- Keep each task title under 120 characters.",
|
|
@@ -23343,12 +23636,28 @@ function parseTaskSuggestionResponse(response) {
|
|
|
23343
23636
|
return void 0;
|
|
23344
23637
|
}
|
|
23345
23638
|
}
|
|
23346
|
-
function runProcess2(args) {
|
|
23639
|
+
function runProcess2(args, onProgress) {
|
|
23347
23640
|
return new Promise((resolveProcess, rejectProcess) => {
|
|
23348
23641
|
const child = spawn7(args.command, [...args.args], {
|
|
23349
23642
|
cwd: args.cwd,
|
|
23350
|
-
|
|
23643
|
+
// Inherit the runner env (codex auth, PATH, etc.) and layer the wafer
|
|
23644
|
+
// proxy credential (LINZUMI_LLM_PROXY_TOKEN) on top when wafer-routed.
|
|
23645
|
+
...args.env === void 0 ? {} : { env: { ...process.env, ...args.env } },
|
|
23646
|
+
// LIVE PROGRESS: capture stdout (the `--json` JSONL event stream) only
|
|
23647
|
+
// when a progress callback is supplied; otherwise discard it as before.
|
|
23648
|
+
// We never depend on stdout for the result (that's --output-last-message),
|
|
23649
|
+
// so stdout parsing is purely a best-effort enhancement.
|
|
23650
|
+
stdio: ["pipe", onProgress === void 0 ? "ignore" : "pipe", "pipe"]
|
|
23351
23651
|
});
|
|
23652
|
+
const progress = onProgress === void 0 ? void 0 : createTaskSuggestionProgressParser(onProgress);
|
|
23653
|
+
if (progress !== void 0) {
|
|
23654
|
+
child.stdout?.on("data", (chunk) => {
|
|
23655
|
+
try {
|
|
23656
|
+
progress.push(String(chunk));
|
|
23657
|
+
} catch {
|
|
23658
|
+
}
|
|
23659
|
+
});
|
|
23660
|
+
}
|
|
23352
23661
|
let stderr = "";
|
|
23353
23662
|
let settled = false;
|
|
23354
23663
|
const timeout = setTimeout(() => {
|
|
@@ -23361,6 +23670,10 @@ function runProcess2(args) {
|
|
|
23361
23670
|
}
|
|
23362
23671
|
settled = true;
|
|
23363
23672
|
clearTimeout(timeout);
|
|
23673
|
+
try {
|
|
23674
|
+
progress?.flush();
|
|
23675
|
+
} catch {
|
|
23676
|
+
}
|
|
23364
23677
|
if (error === void 0) {
|
|
23365
23678
|
resolveProcess();
|
|
23366
23679
|
return;
|
|
@@ -23387,9 +23700,16 @@ function runProcess2(args) {
|
|
|
23387
23700
|
child.stdin?.end(args.stdin);
|
|
23388
23701
|
});
|
|
23389
23702
|
}
|
|
23703
|
+
var DEFAULT_CODEX_AUTH_SUGGESTION_MODEL, DEFAULT_WAFER_SUGGESTION_MODEL, SUGGESTION_TIMEOUT_MS, MAX_SCHEMA_REPAIR_ATTEMPTS;
|
|
23390
23704
|
var init_signupTaskSuggestions = __esm({
|
|
23391
23705
|
"src/signupTaskSuggestions.ts"() {
|
|
23392
23706
|
"use strict";
|
|
23707
|
+
init_codexAppServer();
|
|
23708
|
+
init_signupTaskSuggestionsProgress();
|
|
23709
|
+
DEFAULT_CODEX_AUTH_SUGGESTION_MODEL = "gpt-5.4-mini";
|
|
23710
|
+
DEFAULT_WAFER_SUGGESTION_MODEL = "GLM-5.2";
|
|
23711
|
+
SUGGESTION_TIMEOUT_MS = 15e4;
|
|
23712
|
+
MAX_SCHEMA_REPAIR_ATTEMPTS = 1;
|
|
23393
23713
|
}
|
|
23394
23714
|
});
|
|
23395
23715
|
|
|
@@ -27033,7 +27353,10 @@ async function openLocalCodexRunner(options, log2, cleanup, close, runnerDrainHo
|
|
|
27033
27353
|
const entries = parseResumeReconcileEntries(reconcileValue);
|
|
27034
27354
|
for (const entry of entries) {
|
|
27035
27355
|
if (entry.leaseEpoch !== void 0) {
|
|
27036
|
-
const adopted = leaseEpochRegistry.adopt(
|
|
27356
|
+
const adopted = leaseEpochRegistry.adopt(
|
|
27357
|
+
entry.threadId,
|
|
27358
|
+
entry.leaseEpoch
|
|
27359
|
+
);
|
|
27037
27360
|
if (adopted) {
|
|
27038
27361
|
log2("runner.resume_reconcile_lease_adopted", {
|
|
27039
27362
|
kandanThreadId: entry.threadId,
|
|
@@ -27896,10 +28219,7 @@ function appliedSourceSeqStorePath(runnerId) {
|
|
|
27896
28219
|
const sanitized = runnerId.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[-.]+|[-.]+$/g, "").slice(0, 80);
|
|
27897
28220
|
const digest = createHash7("sha256").update(runnerId).digest("hex").slice(0, 8);
|
|
27898
28221
|
const stem = sanitized === "" ? "runner" : sanitized;
|
|
27899
|
-
return join22(
|
|
27900
|
-
controlCursorsDir(),
|
|
27901
|
-
`${stem}.${digest}.source-seq.json`
|
|
27902
|
-
);
|
|
28222
|
+
return join22(controlCursorsDir(), `${stem}.${digest}.source-seq.json`);
|
|
27903
28223
|
}
|
|
27904
28224
|
function startTurnWatermarkKey(topic, threadId) {
|
|
27905
28225
|
return `${topic} ${threadId}`;
|
|
@@ -29549,7 +29869,10 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
|
|
|
29549
29869
|
return createRunnerProject(control, options, allowedCwds);
|
|
29550
29870
|
}
|
|
29551
29871
|
case "suggest_tasks": {
|
|
29552
|
-
return suggestRunnerTasks(control, options, allowedCwds.value
|
|
29872
|
+
return suggestRunnerTasks(control, options, allowedCwds.value, {
|
|
29873
|
+
kandan,
|
|
29874
|
+
topic
|
|
29875
|
+
});
|
|
29553
29876
|
}
|
|
29554
29877
|
case "remote_codex_exec": {
|
|
29555
29878
|
return await applyRemoteCodexExecControl(
|
|
@@ -33486,7 +33809,27 @@ function projectPathExists(projectPath) {
|
|
|
33486
33809
|
throw error;
|
|
33487
33810
|
}
|
|
33488
33811
|
}
|
|
33489
|
-
|
|
33812
|
+
function resolveSuggestTasksModelProvider(control) {
|
|
33813
|
+
if (stringValue(control.modelProvider)?.trim() !== "wafer") {
|
|
33814
|
+
return void 0;
|
|
33815
|
+
}
|
|
33816
|
+
const llmProxy = objectValue(control.llmProxy);
|
|
33817
|
+
const baseUrl = stringValue(llmProxy?.baseUrl)?.trim();
|
|
33818
|
+
const token = stringValue(llmProxy?.token)?.trim();
|
|
33819
|
+
if (baseUrl === void 0 || baseUrl === "" || token === void 0 || token === "") {
|
|
33820
|
+
return void 0;
|
|
33821
|
+
}
|
|
33822
|
+
const runtime = {
|
|
33823
|
+
provider: "wafer",
|
|
33824
|
+
llmProxyBaseUrl: baseUrl,
|
|
33825
|
+
llmProxyToken: token
|
|
33826
|
+
};
|
|
33827
|
+
return {
|
|
33828
|
+
config: linzumiCodexModelProviderConfig(runtime),
|
|
33829
|
+
env: codexModelProviderAppServerEnv(runtime)
|
|
33830
|
+
};
|
|
33831
|
+
}
|
|
33832
|
+
async function suggestRunnerTasks(control, options, allowedCwds, progressSink) {
|
|
33490
33833
|
const requestId = stringValue(control.requestId) ?? null;
|
|
33491
33834
|
const cwd = resolveAllowedCwd(control.cwd, allowedCwds);
|
|
33492
33835
|
if (!cwd.ok) {
|
|
@@ -33498,10 +33841,25 @@ async function suggestRunnerTasks(control, options, allowedCwds) {
|
|
|
33498
33841
|
error: cwd.reason
|
|
33499
33842
|
};
|
|
33500
33843
|
}
|
|
33844
|
+
const modelProvider = resolveSuggestTasksModelProvider(control);
|
|
33845
|
+
const model = stringValue(control.model)?.trim();
|
|
33846
|
+
const workspaceSlug = stringValue(control.workspace)?.trim();
|
|
33847
|
+
const onProgress = progressSink === void 0 || requestId === null ? void 0 : (label) => {
|
|
33848
|
+
void progressSink.kandan.pushIfConnected(progressSink.topic, "suggest_tasks_progress", {
|
|
33849
|
+
instanceId: options.runnerId,
|
|
33850
|
+
controlType: control.type,
|
|
33851
|
+
requestId,
|
|
33852
|
+
...workspaceSlug === void 0 || workspaceSlug === "" ? {} : { workspace: workspaceSlug },
|
|
33853
|
+
label
|
|
33854
|
+
}).catch(() => void 0);
|
|
33855
|
+
};
|
|
33501
33856
|
try {
|
|
33502
33857
|
const tasks = await suggestSignupTasksWithCodex({
|
|
33503
33858
|
projectPath: cwd.cwd,
|
|
33504
|
-
codexBin: options.codexBin
|
|
33859
|
+
codexBin: options.codexBin,
|
|
33860
|
+
...model === void 0 || model === "" ? {} : { model },
|
|
33861
|
+
...modelProvider === void 0 ? {} : { modelProvider },
|
|
33862
|
+
...onProgress === void 0 ? {} : { onProgress }
|
|
33505
33863
|
});
|
|
33506
33864
|
return {
|
|
33507
33865
|
instanceId: options.runnerId,
|
package/package.json
CHANGED