@linzumi/cli 0.0.86-beta → 0.0.88-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 +534 -69
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -11541,7 +11541,7 @@ function createClaudeCodeSessionPipeline(host) {
|
|
|
11541
11541
|
const toolName2 = pending?.toolName ?? event.toolName ?? "tool";
|
|
11542
11542
|
const input = pending?.input ?? {};
|
|
11543
11543
|
const itemId = `tool:${event.itemKey}`;
|
|
11544
|
-
if (
|
|
11544
|
+
if (isFileChangeTool(toolName2)) {
|
|
11545
11545
|
const patchText = claudeFileChangePatchText(toolName2, input, {
|
|
11546
11546
|
targetExistedAtCall: pending?.targetExistedAtCall
|
|
11547
11547
|
});
|
|
@@ -11549,7 +11549,7 @@ function createClaudeCodeSessionPipeline(host) {
|
|
|
11549
11549
|
const item2 = {
|
|
11550
11550
|
type: "fileChange",
|
|
11551
11551
|
id: itemId,
|
|
11552
|
-
status: "completed",
|
|
11552
|
+
status: event.isError ? "failed" : "completed",
|
|
11553
11553
|
patchText
|
|
11554
11554
|
};
|
|
11555
11555
|
recordItem(turn, item2);
|
|
@@ -11569,12 +11569,13 @@ function createClaudeCodeSessionPipeline(host) {
|
|
|
11569
11569
|
submit("item/completed", { turnId: turn.turnId, item: item2 });
|
|
11570
11570
|
return;
|
|
11571
11571
|
}
|
|
11572
|
-
if (!event.isError && toolName2
|
|
11572
|
+
if (!event.isError && isClaudePlanTool(toolName2)) {
|
|
11573
11573
|
host.onTodoWriteCompleted?.(input);
|
|
11574
11574
|
const plan = claudePlanItem(itemId, input);
|
|
11575
11575
|
if (plan !== void 0) {
|
|
11576
|
-
|
|
11577
|
-
|
|
11576
|
+
const planRow = { ...plan, id: itemId };
|
|
11577
|
+
recordItem(turn, planRow);
|
|
11578
|
+
submit("item/completed", { turnId: turn.turnId, item: planRow });
|
|
11578
11579
|
return;
|
|
11579
11580
|
}
|
|
11580
11581
|
}
|
|
@@ -11605,7 +11606,7 @@ function createClaudeCodeSessionPipeline(host) {
|
|
|
11605
11606
|
}
|
|
11606
11607
|
case "reasoning_delta": {
|
|
11607
11608
|
const turn = ensureTurn();
|
|
11608
|
-
const itemId =
|
|
11609
|
+
const itemId = claudeReasoningPipelineItemId(event.itemKey);
|
|
11609
11610
|
appendRawText(turn, itemId, "reasoning", event.delta);
|
|
11610
11611
|
submit("item/reasoning/textDelta", {
|
|
11611
11612
|
turnId: turn.turnId,
|
|
@@ -11626,7 +11627,7 @@ function createClaudeCodeSessionPipeline(host) {
|
|
|
11626
11627
|
}
|
|
11627
11628
|
case "reasoning_message": {
|
|
11628
11629
|
const turn = ensureTurn();
|
|
11629
|
-
const itemId =
|
|
11630
|
+
const itemId = claudeReasoningPipelineItemId(event.itemKey);
|
|
11630
11631
|
setRawText(turn, itemId, "reasoning", event.content);
|
|
11631
11632
|
submit("item/completed", {
|
|
11632
11633
|
turnId: turn.turnId,
|
|
@@ -11636,14 +11637,15 @@ function createClaudeCodeSessionPipeline(host) {
|
|
|
11636
11637
|
}
|
|
11637
11638
|
case "tool_call": {
|
|
11638
11639
|
const turn = ensureTurn();
|
|
11640
|
+
const targetExistedAtCall = fileChangeTargetExists(
|
|
11641
|
+
event.toolName,
|
|
11642
|
+
event.input,
|
|
11643
|
+
host.cwd
|
|
11644
|
+
);
|
|
11639
11645
|
turn.pendingTools.set(event.itemKey, {
|
|
11640
11646
|
toolName: event.toolName,
|
|
11641
11647
|
input: event.input,
|
|
11642
|
-
targetExistedAtCall
|
|
11643
|
-
event.toolName,
|
|
11644
|
-
event.input,
|
|
11645
|
-
host.cwd
|
|
11646
|
-
)
|
|
11648
|
+
targetExistedAtCall
|
|
11647
11649
|
});
|
|
11648
11650
|
if (isWebSearchTool(event.toolName)) {
|
|
11649
11651
|
const query = stringValue(event.input.query) ?? stringValue(event.input.url) ?? event.toolName;
|
|
@@ -11655,7 +11657,34 @@ function createClaudeCodeSessionPipeline(host) {
|
|
|
11655
11657
|
query
|
|
11656
11658
|
}
|
|
11657
11659
|
});
|
|
11660
|
+
return;
|
|
11658
11661
|
}
|
|
11662
|
+
if (isClaudePlanTool(event.toolName)) {
|
|
11663
|
+
return;
|
|
11664
|
+
}
|
|
11665
|
+
const itemId = `tool:${event.itemKey}`;
|
|
11666
|
+
if (isFileChangeTool(event.toolName)) {
|
|
11667
|
+
const patchText = claudeFileChangePatchText(
|
|
11668
|
+
event.toolName,
|
|
11669
|
+
event.input,
|
|
11670
|
+
{ targetExistedAtCall }
|
|
11671
|
+
);
|
|
11672
|
+
if (patchText !== void 0 && patchText.trim() !== "") {
|
|
11673
|
+
submit("item/fileChange/outputDelta", {
|
|
11674
|
+
turnId: turn.turnId,
|
|
11675
|
+
itemId,
|
|
11676
|
+
delta: patchText
|
|
11677
|
+
});
|
|
11678
|
+
}
|
|
11679
|
+
return;
|
|
11680
|
+
}
|
|
11681
|
+
submit("item/commandExecution/outputDelta", {
|
|
11682
|
+
turnId: turn.turnId,
|
|
11683
|
+
itemId,
|
|
11684
|
+
command: claudeToolCommandLabel(event.toolName, event.input),
|
|
11685
|
+
stream: "stdout",
|
|
11686
|
+
delta: "\n"
|
|
11687
|
+
});
|
|
11659
11688
|
return;
|
|
11660
11689
|
}
|
|
11661
11690
|
case "tool_result": {
|
|
@@ -11809,6 +11838,9 @@ function claudeAssistantPipelineItemId(itemKey) {
|
|
|
11809
11838
|
const streamIndex = itemKey.match(/^assistant-stream-(\d+)$/)?.[1];
|
|
11810
11839
|
return streamIndex === void 0 ? itemKey : `content-block-${streamIndex}`;
|
|
11811
11840
|
}
|
|
11841
|
+
function claudeReasoningPipelineItemId(itemKey) {
|
|
11842
|
+
return `reasoning-${claudeAssistantPipelineItemId(itemKey)}`;
|
|
11843
|
+
}
|
|
11812
11844
|
function isFileChangeTool(toolName2) {
|
|
11813
11845
|
switch (toolName2) {
|
|
11814
11846
|
case "Edit":
|
|
@@ -11823,6 +11855,9 @@ function isFileChangeTool(toolName2) {
|
|
|
11823
11855
|
function isWebSearchTool(toolName2) {
|
|
11824
11856
|
return toolName2 === "WebSearch" || toolName2 === "WebFetch";
|
|
11825
11857
|
}
|
|
11858
|
+
function isClaudePlanTool(toolName2) {
|
|
11859
|
+
return toolName2 === "TodoWrite" || toolName2 === "TaskCreate" || toolName2 === "TaskUpdate";
|
|
11860
|
+
}
|
|
11826
11861
|
function fileChangeTargetExists(toolName2, input, sessionCwd) {
|
|
11827
11862
|
if (!isFileChangeTool(toolName2)) {
|
|
11828
11863
|
return void 0;
|
|
@@ -11895,9 +11930,18 @@ ${body}
|
|
|
11895
11930
|
*** End Patch
|
|
11896
11931
|
`;
|
|
11897
11932
|
}
|
|
11933
|
+
function claudePlanInputItems(input) {
|
|
11934
|
+
if (Array.isArray(input.todos)) {
|
|
11935
|
+
return input.todos;
|
|
11936
|
+
}
|
|
11937
|
+
if (Array.isArray(input.tasks)) {
|
|
11938
|
+
return input.tasks;
|
|
11939
|
+
}
|
|
11940
|
+
return [];
|
|
11941
|
+
}
|
|
11898
11942
|
function claudePlanItem(itemId, input) {
|
|
11899
|
-
const
|
|
11900
|
-
const lines =
|
|
11943
|
+
const items = claudePlanInputItems(input);
|
|
11944
|
+
const lines = items.flatMap((todo) => {
|
|
11901
11945
|
const value = objectValue(todo);
|
|
11902
11946
|
if (value === void 0) {
|
|
11903
11947
|
return [];
|
|
@@ -11971,7 +12015,7 @@ function objectValue2(value) {
|
|
|
11971
12015
|
return isJsonObject(value) ? value : void 0;
|
|
11972
12016
|
}
|
|
11973
12017
|
function claudeTodoWritePlanSteps(input) {
|
|
11974
|
-
const todos = Array.isArray(input.todos) ? input.todos : [];
|
|
12018
|
+
const todos = Array.isArray(input.todos) ? input.todos : Array.isArray(input.tasks) ? input.tasks : [];
|
|
11975
12019
|
const steps = todos.flatMap((todo) => {
|
|
11976
12020
|
const value = objectValue2(todo);
|
|
11977
12021
|
if (value === void 0) {
|
|
@@ -12042,6 +12086,29 @@ function createClaudeCodePlanMirror(args) {
|
|
|
12042
12086
|
settle: () => flight
|
|
12043
12087
|
};
|
|
12044
12088
|
}
|
|
12089
|
+
async function seedClaudeCodingJobGoal(args) {
|
|
12090
|
+
const goal = args.goal.trim().slice(0, 2e3);
|
|
12091
|
+
if (goal === "") {
|
|
12092
|
+
return false;
|
|
12093
|
+
}
|
|
12094
|
+
try {
|
|
12095
|
+
await args.upsertCodingJobPlan(
|
|
12096
|
+
{ thread_id: args.threadId, goal },
|
|
12097
|
+
{ signal: args.signal }
|
|
12098
|
+
);
|
|
12099
|
+
args.log("claude_code.goal_seeded", {
|
|
12100
|
+
thread_id: args.threadId,
|
|
12101
|
+
goal_length: goal.length
|
|
12102
|
+
});
|
|
12103
|
+
return true;
|
|
12104
|
+
} catch (error) {
|
|
12105
|
+
args.log("claude_code.goal_seed_failed", {
|
|
12106
|
+
thread_id: args.threadId,
|
|
12107
|
+
message: error instanceof Error ? error.message : String(error)
|
|
12108
|
+
});
|
|
12109
|
+
return false;
|
|
12110
|
+
}
|
|
12111
|
+
}
|
|
12045
12112
|
var todoStatusToPlanStepStatus, planStepTitleMaxLength, planStepDescriptionMaxLength, planStepsMaxCount;
|
|
12046
12113
|
var init_claudeCodePlanMirror = __esm({
|
|
12047
12114
|
"src/claudeCodePlanMirror.ts"() {
|
|
@@ -12597,6 +12664,87 @@ var init_claudeCodeLiveBashOutput = __esm({
|
|
|
12597
12664
|
}
|
|
12598
12665
|
});
|
|
12599
12666
|
|
|
12667
|
+
// src/claudeCodeTurnStallWatchdog.ts
|
|
12668
|
+
function createClaudeCodeTurnStallWatchdog(options) {
|
|
12669
|
+
if (!(options.thresholdMs > 0)) {
|
|
12670
|
+
throw new Error("Claude turn-stall threshold must be > 0");
|
|
12671
|
+
}
|
|
12672
|
+
const now = options.now ?? (() => Date.now());
|
|
12673
|
+
const setTimer = options.setTimer ?? ((callback, delayMs) => {
|
|
12674
|
+
const handle2 = setTimeout(callback, delayMs);
|
|
12675
|
+
handle2.unref?.();
|
|
12676
|
+
return handle2;
|
|
12677
|
+
});
|
|
12678
|
+
const clearTimer = options.clearTimer ?? ((handle2) => clearTimeout(handle2));
|
|
12679
|
+
const isTurnActive = options.isTurnActive ?? (() => true);
|
|
12680
|
+
let handle;
|
|
12681
|
+
let lastKickMs = now();
|
|
12682
|
+
let stopped = false;
|
|
12683
|
+
let fired = false;
|
|
12684
|
+
let wasActive = isTurnActive();
|
|
12685
|
+
const disarm = () => {
|
|
12686
|
+
if (handle !== void 0) {
|
|
12687
|
+
clearTimer(handle);
|
|
12688
|
+
handle = void 0;
|
|
12689
|
+
}
|
|
12690
|
+
};
|
|
12691
|
+
const onTimeout = () => {
|
|
12692
|
+
handle = void 0;
|
|
12693
|
+
if (stopped || fired) {
|
|
12694
|
+
return;
|
|
12695
|
+
}
|
|
12696
|
+
const active = isTurnActive();
|
|
12697
|
+
if (!active) {
|
|
12698
|
+
wasActive = false;
|
|
12699
|
+
arm();
|
|
12700
|
+
return;
|
|
12701
|
+
}
|
|
12702
|
+
if (!wasActive) {
|
|
12703
|
+
wasActive = true;
|
|
12704
|
+
lastKickMs = now();
|
|
12705
|
+
arm();
|
|
12706
|
+
return;
|
|
12707
|
+
}
|
|
12708
|
+
const silentMs = now() - lastKickMs;
|
|
12709
|
+
if (silentMs < options.thresholdMs) {
|
|
12710
|
+
arm();
|
|
12711
|
+
return;
|
|
12712
|
+
}
|
|
12713
|
+
fired = true;
|
|
12714
|
+
options.onStall({ silentMs });
|
|
12715
|
+
};
|
|
12716
|
+
function arm() {
|
|
12717
|
+
if (stopped || fired) {
|
|
12718
|
+
return;
|
|
12719
|
+
}
|
|
12720
|
+
disarm();
|
|
12721
|
+
const delay = isTurnActive() ? Math.max(0, options.thresholdMs - (now() - lastKickMs)) : options.thresholdMs;
|
|
12722
|
+
handle = setTimer(onTimeout, delay);
|
|
12723
|
+
}
|
|
12724
|
+
arm();
|
|
12725
|
+
return {
|
|
12726
|
+
kick: () => {
|
|
12727
|
+
if (stopped || fired) {
|
|
12728
|
+
return;
|
|
12729
|
+
}
|
|
12730
|
+
wasActive = true;
|
|
12731
|
+
lastKickMs = now();
|
|
12732
|
+
arm();
|
|
12733
|
+
},
|
|
12734
|
+
stop: () => {
|
|
12735
|
+
stopped = true;
|
|
12736
|
+
disarm();
|
|
12737
|
+
}
|
|
12738
|
+
};
|
|
12739
|
+
}
|
|
12740
|
+
var defaultClaudeCodeTurnStallThresholdMs;
|
|
12741
|
+
var init_claudeCodeTurnStallWatchdog = __esm({
|
|
12742
|
+
"src/claudeCodeTurnStallWatchdog.ts"() {
|
|
12743
|
+
"use strict";
|
|
12744
|
+
defaultClaudeCodeTurnStallThresholdMs = 10 * 6e4;
|
|
12745
|
+
}
|
|
12746
|
+
});
|
|
12747
|
+
|
|
12600
12748
|
// src/claudeCodeSession.ts
|
|
12601
12749
|
import { existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
|
|
12602
12750
|
import { homedir as homedir6 } from "node:os";
|
|
@@ -12864,8 +13012,49 @@ async function startClaudeCodeSession(options) {
|
|
|
12864
13012
|
lastCompletedTurnBody: void 0
|
|
12865
13013
|
};
|
|
12866
13014
|
const streamUsageTracker = createClaudeCodeStreamUsageTracker();
|
|
13015
|
+
let stallReason;
|
|
13016
|
+
let signalStall;
|
|
13017
|
+
const stallSignal = new Promise((resolve12) => {
|
|
13018
|
+
signalStall = resolve12;
|
|
13019
|
+
});
|
|
13020
|
+
const stallWatchdog = options.turnStallThresholdMs !== void 0 && options.turnStallThresholdMs > 0 ? createClaudeCodeTurnStallWatchdog({
|
|
13021
|
+
thresholdMs: options.turnStallThresholdMs,
|
|
13022
|
+
isTurnActive: options.turnStallIsActive,
|
|
13023
|
+
onStall: ({ silentMs }) => {
|
|
13024
|
+
stallReason = `Claude Code turn stalled: no SDK output for ${Math.round(
|
|
13025
|
+
silentMs / 1e3
|
|
13026
|
+
)}s (threshold ${Math.round(
|
|
13027
|
+
(options.turnStallThresholdMs ?? 0) / 1e3
|
|
13028
|
+
)}s)`;
|
|
13029
|
+
options.abortController?.abort();
|
|
13030
|
+
signalStall?.();
|
|
13031
|
+
}
|
|
13032
|
+
}) : void 0;
|
|
12867
13033
|
try {
|
|
12868
|
-
|
|
13034
|
+
const iterator = runner(options)[Symbol.asyncIterator]();
|
|
13035
|
+
for (; ; ) {
|
|
13036
|
+
let nextStep;
|
|
13037
|
+
if (stallWatchdog) {
|
|
13038
|
+
const nextPromise = iterator.next().then((result) => ({ kind: "next", result }));
|
|
13039
|
+
nextPromise.catch(() => void 0);
|
|
13040
|
+
const raced = await Promise.race([
|
|
13041
|
+
nextPromise,
|
|
13042
|
+
stallSignal.then(() => ({ kind: "stall" }))
|
|
13043
|
+
]);
|
|
13044
|
+
if (raced.kind === "stall") {
|
|
13045
|
+
void Promise.resolve(iterator.return?.()).catch(() => void 0);
|
|
13046
|
+
break;
|
|
13047
|
+
}
|
|
13048
|
+
nextStep = raced;
|
|
13049
|
+
} else {
|
|
13050
|
+
nextStep = { kind: "next", result: await iterator.next() };
|
|
13051
|
+
}
|
|
13052
|
+
const step = nextStep;
|
|
13053
|
+
if (step.result.done === true) {
|
|
13054
|
+
break;
|
|
13055
|
+
}
|
|
13056
|
+
const message = step.result.value;
|
|
13057
|
+
stallWatchdog?.kick();
|
|
12869
13058
|
state.sessionId = state.sessionId ?? extractClaudeSessionId(message);
|
|
12870
13059
|
const sessionId = extractClaudeSessionId(message) ?? state.sessionId;
|
|
12871
13060
|
if (sessionId !== void 0 && !state.startedSessionIds.has(sessionId)) {
|
|
@@ -12931,8 +13120,12 @@ async function startClaudeCodeSession(options) {
|
|
|
12931
13120
|
}
|
|
12932
13121
|
}
|
|
12933
13122
|
} finally {
|
|
13123
|
+
stallWatchdog?.stop();
|
|
12934
13124
|
options.streamingInput?.close();
|
|
12935
13125
|
}
|
|
13126
|
+
if (stallReason !== void 0) {
|
|
13127
|
+
return await failClaudeCodeSession(options, state.sessionId, stallReason);
|
|
13128
|
+
}
|
|
12936
13129
|
return completeClaudeCodeSession(options, state);
|
|
12937
13130
|
}
|
|
12938
13131
|
async function emitClaudeCodeTurnCompleted(options, state) {
|
|
@@ -13073,7 +13266,16 @@ async function* defaultClaudeCodeRunner(options) {
|
|
|
13073
13266
|
options.wrapApprovedToolInput
|
|
13074
13267
|
)
|
|
13075
13268
|
},
|
|
13076
|
-
...options.model === void 0 ? {} : { model: options.model }
|
|
13269
|
+
...options.model === void 0 ? {} : { model: options.model },
|
|
13270
|
+
...options.permissionMode === void 0 ? {} : {
|
|
13271
|
+
permissionMode: options.permissionMode,
|
|
13272
|
+
// The SDK requires this safety acknowledgement when a session is
|
|
13273
|
+
// constructed in 'bypassPermissions' (sdk.d.ts Options:
|
|
13274
|
+
// "Must be set to true when using permissionMode:
|
|
13275
|
+
// 'bypassPermissions'"). It is the intentional-bypass flag, only
|
|
13276
|
+
// meaningful for that mode; harmless for the others.
|
|
13277
|
+
...options.permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}
|
|
13278
|
+
}
|
|
13077
13279
|
// exactOptionalPropertyTypes: the conditional spreads build a union the
|
|
13078
13280
|
// SDK's Options cannot absorb verbatim; the shape is correct field-wise.
|
|
13079
13281
|
}
|
|
@@ -13316,13 +13518,16 @@ function assistantTranscriptEvents(message, sessionId) {
|
|
|
13316
13518
|
contentBlockItemKey(block, index)
|
|
13317
13519
|
)
|
|
13318
13520
|
);
|
|
13319
|
-
const
|
|
13521
|
+
const hasTextContentBlock = content.some(
|
|
13522
|
+
(block) => stringValue(objectValue(block)?.type) === "text"
|
|
13523
|
+
);
|
|
13524
|
+
const directText = hasTextContentBlock ? void 0 : nonEmptyText(stringValue(message?.text));
|
|
13320
13525
|
return directText === void 0 ? contentEvents : [
|
|
13321
13526
|
...contentEvents,
|
|
13322
13527
|
{
|
|
13323
13528
|
type: "assistant_message",
|
|
13324
13529
|
sessionId,
|
|
13325
|
-
itemKey:
|
|
13530
|
+
itemKey: `content-block-${content.length}`,
|
|
13326
13531
|
content: directText,
|
|
13327
13532
|
streamState: "completed"
|
|
13328
13533
|
}
|
|
@@ -13343,7 +13548,7 @@ function userTranscriptEvents(message, sessionId) {
|
|
|
13343
13548
|
{
|
|
13344
13549
|
type: "tool_result",
|
|
13345
13550
|
sessionId,
|
|
13346
|
-
itemKey:
|
|
13551
|
+
itemKey: stringValue(value?.tool_use_id) ?? stringValue(value?.id) ?? `content-block-${index}`,
|
|
13347
13552
|
toolName: void 0,
|
|
13348
13553
|
content: visibleToolResultContent(value),
|
|
13349
13554
|
isError: value?.is_error === true
|
|
@@ -13429,12 +13634,14 @@ function unknownTranscriptEvent(message, sessionId) {
|
|
|
13429
13634
|
}
|
|
13430
13635
|
function streamItemKey(event, _message) {
|
|
13431
13636
|
const index = integerValue(event?.index);
|
|
13432
|
-
|
|
13433
|
-
return stringValue(event?.content_block_id) ?? stringValue(contentBlock?.id) ?? stringValue(contentBlock?.tool_use_id) ?? stringValue(contentBlock?.uuid) ?? (index === void 0 ? "assistant-stream" : `assistant-stream-${index}`);
|
|
13637
|
+
return index === void 0 ? "assistant-stream" : `content-block-${index}`;
|
|
13434
13638
|
}
|
|
13435
13639
|
function contentBlockItemKey(block, index) {
|
|
13436
13640
|
const value = objectValue(block);
|
|
13437
|
-
|
|
13641
|
+
if (stringValue(value?.type) === "tool_use") {
|
|
13642
|
+
return stringValue(value?.id) ?? stringValue(value?.tool_use_id) ?? `content-block-${index}`;
|
|
13643
|
+
}
|
|
13644
|
+
return `content-block-${index}`;
|
|
13438
13645
|
}
|
|
13439
13646
|
function visibleToolResultContent(block) {
|
|
13440
13647
|
const content = block?.content;
|
|
@@ -13482,6 +13689,7 @@ var init_claudeCodeSession = __esm({
|
|
|
13482
13689
|
"use strict";
|
|
13483
13690
|
init_json();
|
|
13484
13691
|
init_claudeCodeLiveBashOutput();
|
|
13692
|
+
init_claudeCodeTurnStallWatchdog();
|
|
13485
13693
|
claudeRateLimitWindowLabels = {
|
|
13486
13694
|
five_hour: "5h window",
|
|
13487
13695
|
seven_day: "7d window",
|
|
@@ -14992,8 +15200,8 @@ function startCallbackServer(args) {
|
|
|
14992
15200
|
}
|
|
14993
15201
|
resolveCallback?.({ code, state });
|
|
14994
15202
|
writeOauthResult(response, {
|
|
14995
|
-
title: "
|
|
14996
|
-
body: "
|
|
15203
|
+
title: "Computer authorized",
|
|
15204
|
+
body: "This computer has been authorized for agentic use in Linzumi. Feel free to close this tab and let the terminal finish setup.",
|
|
14997
15205
|
status: 200
|
|
14998
15206
|
});
|
|
14999
15207
|
} catch (error) {
|
|
@@ -15036,29 +15244,108 @@ function writeOauthResult(response, args) {
|
|
|
15036
15244
|
response.end(oauthResultHtml(args));
|
|
15037
15245
|
}
|
|
15038
15246
|
function oauthResultHtml(args) {
|
|
15247
|
+
const success = args.status >= 200 && args.status < 300;
|
|
15248
|
+
const badgeClass = success ? "badge badge--success" : "badge badge--notice";
|
|
15249
|
+
const badgeMark = success ? '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" class="mark"><path fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" d="M5 12.5l4.2 4.2L19 7"/></svg>' : '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" class="mark"><path fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" d="M12 7v6M12 17h.01"/></svg>';
|
|
15039
15250
|
return `<!doctype html>
|
|
15040
|
-
<html>
|
|
15251
|
+
<html lang="en">
|
|
15041
15252
|
<head>
|
|
15042
15253
|
<meta charset="utf-8" />
|
|
15043
15254
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
15044
15255
|
<title>${escapeHtml(args.title)}</title>
|
|
15045
15256
|
<style>
|
|
15046
|
-
:root {
|
|
15047
|
-
|
|
15048
|
-
|
|
15049
|
-
|
|
15050
|
-
|
|
15257
|
+
:root {
|
|
15258
|
+
color-scheme: light dark;
|
|
15259
|
+
/* Linzumi brand tokens (light) \u2014 kandan/server_v2/web/src/ui/theme/tokens.css */
|
|
15260
|
+
--page-bg: #f5f2ee;
|
|
15261
|
+
--surface: #fcfaf7;
|
|
15262
|
+
--foreground: #1e1b18;
|
|
15263
|
+
--muted: #5c5550;
|
|
15264
|
+
--divider: rgba(138, 148, 144, 0.16);
|
|
15265
|
+
--accent: #c4897a;
|
|
15266
|
+
--success: #5a9a6a;
|
|
15267
|
+
--success-soft: rgba(90, 154, 106, 0.1);
|
|
15268
|
+
--notice-soft: rgba(196, 137, 122, 0.1);
|
|
15269
|
+
--shadow: 0 12px 40px rgba(106, 138, 122, 0.12), 0 4px 12px rgba(106, 138, 122, 0.06);
|
|
15270
|
+
}
|
|
15051
15271
|
@media (prefers-color-scheme: dark) {
|
|
15052
|
-
|
|
15053
|
-
|
|
15054
|
-
|
|
15272
|
+
:root {
|
|
15273
|
+
/* Linzumi brand tokens (dark) */
|
|
15274
|
+
--page-bg: #171b19;
|
|
15275
|
+
--surface: #202522;
|
|
15276
|
+
--foreground: rgba(245, 241, 232, 0.95);
|
|
15277
|
+
--muted: rgba(245, 241, 232, 0.68);
|
|
15278
|
+
--divider: rgba(245, 241, 232, 0.1);
|
|
15279
|
+
--accent: #c8a0b0;
|
|
15280
|
+
--success: #72c488;
|
|
15281
|
+
--success-soft: rgba(114, 196, 136, 0.14);
|
|
15282
|
+
--notice-soft: rgba(200, 160, 176, 0.14);
|
|
15283
|
+
--shadow: 0 18px 50px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.35);
|
|
15284
|
+
}
|
|
15285
|
+
}
|
|
15286
|
+
* { box-sizing: border-box; }
|
|
15287
|
+
body {
|
|
15288
|
+
margin: 0;
|
|
15289
|
+
min-height: 100vh;
|
|
15290
|
+
display: grid;
|
|
15291
|
+
place-items: center;
|
|
15292
|
+
padding: 24px;
|
|
15293
|
+
background:
|
|
15294
|
+
radial-gradient(1200px 600px at 50% -10%, var(--notice-soft), transparent 60%),
|
|
15295
|
+
var(--page-bg);
|
|
15296
|
+
color: var(--foreground);
|
|
15297
|
+
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
15298
|
+
-webkit-font-smoothing: antialiased;
|
|
15299
|
+
}
|
|
15300
|
+
main {
|
|
15301
|
+
width: min(520px, 100%);
|
|
15302
|
+
border: 1px solid var(--divider);
|
|
15303
|
+
border-radius: 16px;
|
|
15304
|
+
background: var(--surface);
|
|
15305
|
+
padding: 40px 36px;
|
|
15306
|
+
box-shadow: var(--shadow);
|
|
15307
|
+
text-align: center;
|
|
15308
|
+
}
|
|
15309
|
+
.logo {
|
|
15310
|
+
width: 44px;
|
|
15311
|
+
height: 44px;
|
|
15312
|
+
margin: 28px auto 0;
|
|
15313
|
+
color: var(--accent);
|
|
15314
|
+
}
|
|
15315
|
+
.logo svg { display: block; width: 100%; height: 100%; }
|
|
15316
|
+
.badge {
|
|
15317
|
+
width: 64px;
|
|
15318
|
+
height: 64px;
|
|
15319
|
+
margin: 0 auto 22px;
|
|
15320
|
+
display: grid;
|
|
15321
|
+
place-items: center;
|
|
15322
|
+
border-radius: 999px;
|
|
15323
|
+
}
|
|
15324
|
+
.badge--success { background: var(--success-soft); color: var(--success); }
|
|
15325
|
+
.badge--notice { background: var(--notice-soft); color: var(--accent); }
|
|
15326
|
+
.mark { width: 32px; height: 32px; }
|
|
15327
|
+
h1 {
|
|
15328
|
+
margin: 0 0 12px;
|
|
15329
|
+
font-size: 23px;
|
|
15330
|
+
font-weight: 600;
|
|
15331
|
+
line-height: 1.3;
|
|
15332
|
+
letter-spacing: -0.01em;
|
|
15333
|
+
color: var(--foreground);
|
|
15334
|
+
}
|
|
15335
|
+
p {
|
|
15336
|
+
margin: 0;
|
|
15337
|
+
color: var(--muted);
|
|
15338
|
+
font-size: 15px;
|
|
15339
|
+
line-height: 1.6;
|
|
15055
15340
|
}
|
|
15056
15341
|
</style>
|
|
15057
15342
|
</head>
|
|
15058
15343
|
<body>
|
|
15059
15344
|
<main>
|
|
15345
|
+
<div class="${badgeClass}">${badgeMark}</div>
|
|
15060
15346
|
<h1>${escapeHtml(args.title)}</h1>
|
|
15061
15347
|
<p>${escapeHtml(args.body)}</p>
|
|
15348
|
+
<div class="logo">${LINZUMI_LOGO_SVG}</div>
|
|
15062
15349
|
</main>
|
|
15063
15350
|
</body>
|
|
15064
15351
|
</html>`;
|
|
@@ -15089,10 +15376,12 @@ function openBrowser(url) {
|
|
|
15089
15376
|
});
|
|
15090
15377
|
});
|
|
15091
15378
|
}
|
|
15379
|
+
var LINZUMI_LOGO_SVG;
|
|
15092
15380
|
var init_oauth = __esm({
|
|
15093
15381
|
"src/oauth.ts"() {
|
|
15094
15382
|
"use strict";
|
|
15095
15383
|
init_runnerLogger();
|
|
15384
|
+
LINZUMI_LOGO_SVG = '<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path fill="currentColor" d="M206.7,82.37l2.55-6.45,2.01-3.63c.67-1.21,1.07-1.88,2.55-3.63,1.34-1.61,3.36-4.43,5.64-6.58,2.42-2.24,5.06-4.3,7.93-6.18,3.92-2.53,8.17-4.52,12.63-5.91,1.79-.63,4.03-1.16,6.72-1.61,6.1-.88,12.29-.92,18.4-.13,2.69.45,5.06,1.03,7.12,1.75,2.15.67,3.49,1.07,5.64,2.15,4.55,2.16,8.87,4.77,12.9,7.79,1.61,1.34,2.42,2.15,4.16,4.16l5.91,7.66c1.34,2.01,1.34,2.28,2.15,4.03l2.55,6.58c.67,1.34-.13,1.34,1.07.94,1.21-.27,4.3-2.01,6.45-2.82,4.7-1.83,9.62-3,14.64-3.49,2.42-.27,3.76-.54,7.12-.27s9.27,1.21,12.76,2.15c3.63.94,6.58,2.55,8.73,3.49,2.15,1.07,2.55,1.48,4.16,2.55,3.49,2.51,6.77,5.29,9.81,8.33,1.52,1.7,3.04,3.58,4.57,5.64,2.74,4.49,4.86,9.32,6.31,14.37.67,2.28,1.07,3.49,1.34,6.72.27,3.22,0,10.48.4,12.76.27,2.28.27.67,1.61.94,1.48.27,4.3,0,6.72.4,2.42.27,4.97.85,7.66,1.75,6.76,2.32,13.01,5.92,18.4,10.61,2.28,1.75,2.96,2.69,4.3,4.3,3.51,3.93,6.32,8.43,8.33,13.3,1.07,2.15,1.21,2.28,1.88,5.1.54,2.96,1.61,8.19,1.61,12.36s-.81,9.67-1.34,12.76c-.67,3.22-1.07,4.03-2.15,6.18-2.16,4.54-4.81,8.82-7.93,12.76-1.25,1.61-2.6,3-4.03,4.16-1.48,1.34-2.69,2.42-4.7,3.76-3.79,2.34-7.74,4.4-11.82,6.18l-6.58,2.15c-2.06.45-4.12.72-6.18.81l-7.25.13c-2.28,0-2.82.27-6.58-.4-3.76-.81-11.69-2.82-15.99-4.3-4.16-1.34-6.31-2.69-9.67-4.43-3.49-1.75-10.48-6.18-12.9-7.39-8.26-4.54-16.78-8.58-25.52-12.09-4.3-1.75-9.27-3.22-11.82-4.03-2.55-.81-5.24-1.61-7.66-2.15-8.39-2.25-16.99-3.6-25.66-4.03-3.9-.27-4.84-.27-8.19-.13-3.67-.09-7.79.04-12.36.4-7.9.79-15.75,2.04-23.51,3.76-8.37,2.26-16.62,4.95-24.72,8.06-3.22,1.34-2.82.81-9.13,4.16-6.31,3.36-22.03,12.22-28.75,15.58-6.72,3.36-8.73,3.49-11.82,4.43-3.09,1.07-4.3,1.21-6.58,1.61-7.3,1.09-14.71,1.18-22.03.27-2.55-.54-5.78-1.61-7.79-2.28-2.01-.54-2.15-.67-4.03-1.75-2.02-1.07-5.64-3.22-7.79-4.7-3.24-2.15-6.14-4.77-8.6-7.79-1.34-1.52-2.69-3.36-4.03-5.51-1.52-2.51-2.96-5.24-4.3-8.19-2.03-5.46-3.03-11.24-2.96-17.06,0-2.96.13-6.72.67-9.67.54-2.87,1.34-5.6,2.42-8.19,4.24-10.52,12.04-19.22,22.03-24.58,5.19-2.98,10.88-4.98,16.79-5.91,2.55-.4,5.37-.13,6.72-.4,1.34-.27,1.34,1.34,1.61-.94.4-2.28,0-9.4.4-12.76.27-3.36.81-4.97,1.48-7.25,1.87-6.19,4.88-11.97,8.87-17.06,3.47-3.98,7.39-7.54,11.69-10.61,4.43-2.61,9.11-4.77,13.97-6.45,2.55-.67,6.99-1.34,9.13-1.75,2.15-.27,1.88-.13,3.63-.13,1.79-.09,4.03,0,6.72.27,2.69.18,5.73.72,9.13,1.61,3.49,1.07,9.27,4.03,11.28,4.7s.4.27,1.07-.94ZM512.27,255.7c0,141.39-114.62,256-256,256S.27,397.09.27,255.7,114.89-.3,256.27-.3s256,114.62,256,256ZM449.33,352.66c14.67-29.16,22.94-62.09,22.94-96.95,0-119.29-96.71-216-216-216S40.27,136.41,40.27,255.7c0,41.89,11.94,80.98,32.57,114.09,1.7,1.79,2.94.65,3.05-.57.27-1.61,2.75-20.85,4.43-27.27,1.87-7.6,4.52-14.98,7.93-22.03,1.75-3.49,3.76-7.93,6.18-11.82,8.77-13.95,19.75-26.38,32.51-36.81,7.24-5.32,14.87-10.08,22.84-14.24,9.74-4.78,20.09-8.22,30.76-10.21,4.03-.99,7.61-1.66,10.75-2.02,3.36-.54,5.78-.54,9.27-.94,3.49-.54,9.32-1.16,11.82-2.01,6.65-2.27,5.64-6.72,3.09-7.52-2.55-.81-9.67-1.88-13.84-2.96-4.16-1.21-8.73-2.82-11.28-3.76-2.55-.94-2.28-.94-3.9-2.02l-5.91-4.03c-.94-.94-1.34-.94.54-2.02l10.21-5.51c2.01-1.07,1.75-.67,3.09-.13,1.34.67,4.3,2.42,6.72,3.36,7.2,2.69,14.96,3.52,22.57,2.42,1.34-.27,1.34-.54,1.61-1.21.27-.67.81-.94-.13-2.69-.94-1.88-4.43-6.58-5.64-8.46l-1.21-2.28c-.27-.45-1.07-1.07,1.21-1.75,2.42-.54,10.48-2.58,12.9-2.82.86-.09.67,0,1.75,1.07,1.07,1.07,3.09,3.63,4.84,5.24,1.88,1.61,4.43,3.22,6.18,4.3,2.8,1.71,5.99,2.68,9.27,2.82,1.88,0,4.97-.13,7.12-.67,2.15-.4,3.63-.94,5.64-2.02,2.01-1.07,4.7-2.69,6.72-4.43,2.01-1.75,3.49-5.1,5.64-6.04,2.15-.81,4.97.54,7.12.94,2.28.4,4.97,1.21,6.18,1.61,1.21.4,2.01.4.67,2.28l-8.06,10.34c-1.34,1.88.13,5.51,1.21,5.64l5.64.27c2.28-.13,4.43.13,7.66-.67,3.36-.81,9.27-2.96,11.82-3.9,2.69-.94,3.22-1.34,4.16-2.01.81-.54,1.39-1.03,1.75-1.48.45-.27.67-1.07,2.82,0s9.4,4.97,11.28,6.18c2.01,1.21,1.07.94,0,1.75l-5.51,3.9c-1.48.94-1.07.94-3.22,1.88-2.15,1.07-6.58,2.96-9.67,4.03s-4.03,1.75-8.73,2.69c-4.7.81-14.51,1.75-19.48,2.55-4.97.81-7.93,1.34-10.34,2.01-2.28.67-2.15.94-3.49,1.88-1.48,1.07-2.69,1.61-4.97,3.9-2.28,2.28-5.91,6.85-8.73,9.81-2.82,2.96-6.45,6.04-8.33,7.79-2.02,1.61-1.61,1.34-3.36,2.42l-6.99,4.03-4.03,2.02-6.72,2.15c-2.42.67-3.9,1.21-7.66,2.01l-14.91,2.82c-3.63.81-4.3,1.07-7.12,2.01-2.96,1.07-6.22,2.46-9.81,4.16-3.22,1.43-6.81,3.45-10.75,6.04-13.6,9.14-24.61,21.63-31.97,36.27-2.01,3.76-2.96,6.58-3.9,9.27-1.07,2.69-1.61,4.03-2.28,6.58-.67,2.69-1.48,5.24-2.15,9.27-.54,4.16-1.48,11.15-1.75,15.45-.27,4.16-.27,6.04,0,10.21l1.88,14.91c.67,3.76,1.48,5.91,2.15,8.19l1.88,5.64c.99,2.6,2.42,5.78,4.3,9.54,2.15,3.76,5.37,9.13,8.06,13.03,10.08,14.51,23.81,26.36,40.17,33.05,22.55,9.22,43.32,10.46,61.89,10.46,3.25,0,6.49-.09,9.71-.23,3.07-.42,2.74-6.09,10.48-9.42,5.26-2.26,13.7-2.42,14.91-2.55,1.07-.13-5.24-4.57-7.79-6.45-2.55-1.88-4.97-4.3-6.72-5.91-1.75-1.75-2.42-2.28-3.9-4.16-1.61-1.88-3.9-5.51-5.24-7.12-1.34-1.61-1.48-2.28-2.55-2.55-.98-.27-2.37-.09-4.16.54-1.88.4-5.37,1.21-7.12,1.88-1.75.67-2.02.81-3.09,2.01-1.07,1.07-2.69,3.76-3.63,4.7-.81.94-.67.67-1.48.94-.81.27-2.42.67-3.63.54-1.34-.18-2.55-.58-3.63-1.21-.81-.81-1.48-2.42-1.88-3.22-.4-.94-.54-1.21-.54-2.15l.4-3.49c.18-1.52.72-3.27,1.61-5.24.94-1.75,1.88-3.49,4.16-5.64,2.15-2.02,7.52-5.51,9.13-6.85,1.61-1.34,1.21-2.15.54-3.63-2.69-5.16-6.33-9.77-10.75-13.57-2.42-1.88-5.51-3.22-7.79-4.3-2.15-1.21-2.01-1.21-5.78-2.42-3.76-1.07-13.16-3.63-16.79-4.84-3.63-1.07-2.82-.94-5.1-2.01l-8.19-4.3c-1.75-.94-1.34-.54-2.69-1.61l-5.51-4.57c-2.18-1.93-3.77-4.45-4.57-7.25-.45-1.52-.45-2.87,0-4.03.4-1.34,0-1.21,2.01-3.63,2.15-2.42,7.25-7.93,10.21-10.75,3.09-2.82,4.97-4.03,7.79-6.04,5.43-3.82,11.09-7.32,16.93-10.48,2.42-1.21,5.37-2.02,7.12-2.69,1.61-.81,2.64-1.43,3.09-1.88.54-.4.67.54.4-.94-.4-1.48-1.88-4.97-2.28-7.66-.4-2.82-.4-6.18,0-8.73.36-2.42,1.03-4.66,2.01-6.72,1.16-2.24,2.46-4.3,3.9-6.18,1.34-1.7,2.91-3.04,4.7-4.03,1.75-1.07,4.3-2.01,6.18-2.42,1.61-.45,3.13-.58,4.57-.4l4.57.27c1.34.18,2.55.49,3.63.94,1.07.54,2.55,1.48,3.09,2.01.4.67.67.13-.27,1.61-1.07,1.48-4.16,4.57-5.78,7.12-1.61,2.69-2.96,5.6-4.03,8.73-.94,3.22-1.88,8.73-2.01,10.75-.27,2.15,4.7,1.75,5.1.54.54-1.07.27-2.55,1.07-5.1.81-2.42,2.42-7.25,3.9-9.81,1.34-2.55,2.82-3.76,4.57-5.51,1.79-1.88,3.67-3.45,5.64-4.7,1.88-1.21,3.22-1.75,5.64-2.28,2.42-.4,6.18-.67,8.73-.67,2.42,0,3.9.13,6.18.94,2.15.81,5.24,2.69,7.12,4.03,1.79,1.52,3.22,3.09,4.3,4.7,1.21,1.61,1.88,2.96,2.55,5.1.67,2.15,1.34,5.1,1.34,7.66,0,2.69-.54,6.04-1.21,8.19-.63,2.24-1.43,4.03-2.42,5.37-.67,1.34-.94,1.61-2.15,2.82-1.21,1.34-3.22,3.22-4.97,4.57-1.75,1.21-4.43,2.28-5.51,3.22-.94.81-.4,2.51.4,2.42.94.13,1.75.4,4.57-.13,2.82-.4,8.33-2.15,12.22-2.82,11.99-2.63,24.41-2.63,36.4,0,3.22.54,4.16,1.07,6.31,1.75l6.04,2.28c2.42,1.07,5.51,2.42,8.19,4.16,8.15,5.36,15.14,12.3,20.55,20.42,1.61,2.42,2.87,4.66,3.76,6.72,1.85,4.51,3.42,9.13,4.7,13.84.67,2.82,1.21,4.43,1.61,8.19.4,3.76.4,11.82.54,14.37.27,2.55-.13,2.28,1.75,1.34,1.75-.94,20.09-7.74,30.63-31.57,9.16-20.71,1.9-47.26-2.28-55.34-1.75-3.22-4.16-6.99-6.31-9.81-4.44-5.14-9.6-9.62-15.31-13.3-2.96-1.7-5.55-3.09-7.79-4.16-4.33-1.6-8.77-2.86-13.3-3.76l-6.18-.4h-14.37c-2.69-.27-3.1-3.18-.54-4.3,3.64-1.58,9.88-2.63,18.54-2.42,8.78.21,14.91,1.88,17.33,2.55,13.98,3.94,30.19,16.65,38.55,30.76,6.61,11.16,9.81,29.96,9.81,29.96.37,1.75,2.18,1.66,3.08.35ZM232.78,345.3c-3.91,0-7.08,3.17-7.08,7.08s3.17,7.08,7.08,7.08,7.08-3.17,7.08-7.08-3.17-7.08-7.08-7.08Z"/></svg>';
|
|
15096
15385
|
}
|
|
15097
15386
|
});
|
|
15098
15387
|
|
|
@@ -15805,7 +16094,7 @@ var init_remoteCodexExecutionContext = __esm({
|
|
|
15805
16094
|
"SHELL",
|
|
15806
16095
|
"TMPDIR"
|
|
15807
16096
|
]);
|
|
15808
|
-
ignoredEnvOverrideKeys = /* @__PURE__ */ new Set(["PATH"]);
|
|
16097
|
+
ignoredEnvOverrideKeys = /* @__PURE__ */ new Set(["PATH", "GIT_PAGER"]);
|
|
15809
16098
|
deniedEnvKeys = /* @__PURE__ */ new Set([
|
|
15810
16099
|
"BASH_ENV",
|
|
15811
16100
|
"ENV",
|
|
@@ -18430,7 +18719,7 @@ var linzumiCliVersion, linzumiCliVersionText;
|
|
|
18430
18719
|
var init_version = __esm({
|
|
18431
18720
|
"src/version.ts"() {
|
|
18432
18721
|
"use strict";
|
|
18433
|
-
linzumiCliVersion = "0.0.
|
|
18722
|
+
linzumiCliVersion = "0.0.88-beta";
|
|
18434
18723
|
linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
|
|
18435
18724
|
}
|
|
18436
18725
|
});
|
|
@@ -20819,7 +21108,7 @@ function createLinzumiMcpApiClient(options) {
|
|
|
20819
21108
|
const baseUrl = kandanHttpBaseUrl(options.kandanUrl);
|
|
20820
21109
|
const apiPrefix = options.authMode === "personal-agent-delegation" ? "/api/v2/personal-agent-mcp" : "/api/v2/local-runner-mcp";
|
|
20821
21110
|
const operatingMode = options.operatingMode ?? "text";
|
|
20822
|
-
const request = async (method, path2, params) => {
|
|
21111
|
+
const request = async (method, path2, params, requestOptions = {}) => {
|
|
20823
21112
|
const url = new URL(path2, baseUrl);
|
|
20824
21113
|
const paramsWithMode = {
|
|
20825
21114
|
...params,
|
|
@@ -20827,7 +21116,11 @@ function createLinzumiMcpApiClient(options) {
|
|
|
20827
21116
|
};
|
|
20828
21117
|
const requestInit = {
|
|
20829
21118
|
method,
|
|
20830
|
-
headers: { authorization: `Bearer ${options.accessToken}` }
|
|
21119
|
+
headers: { authorization: `Bearer ${options.accessToken}` },
|
|
21120
|
+
// An aborted signal cancels the in-flight fetch so a caller that has
|
|
21121
|
+
// already given up (e.g. a timed-out goal seed) cannot land a LATE POST
|
|
21122
|
+
// and clobber state written after it gave up (#1864 finding 2).
|
|
21123
|
+
...requestOptions.signal === void 0 ? {} : { signal: requestOptions.signal }
|
|
20831
21124
|
};
|
|
20832
21125
|
if (method === "GET") {
|
|
20833
21126
|
for (const [key, value] of Object.entries(paramsWithMode)) {
|
|
@@ -20860,9 +21153,11 @@ function createLinzumiMcpApiClient(options) {
|
|
|
20860
21153
|
getMessage: (params) => request("GET", `${apiPrefix}/message`, params),
|
|
20861
21154
|
getThread: (params) => request("GET", `${apiPrefix}/thread`, params),
|
|
20862
21155
|
getChannel: (params) => request("GET", `${apiPrefix}/channel`, params),
|
|
21156
|
+
searchWorkspace: (params) => request("GET", `${apiPrefix}/search`, params),
|
|
21157
|
+
askWorkspace: (params) => request("POST", `${apiPrefix}/ask`, params),
|
|
20863
21158
|
getCodingJobMetadata: (params) => request("GET", `${apiPrefix}/coding-job-metadata`, params),
|
|
20864
21159
|
renameCodingJob: (params) => request("POST", `${apiPrefix}/coding-job-title`, params),
|
|
20865
|
-
upsertCodingJobPlan: (params) => request("POST", `${apiPrefix}/coding-job-plan`, params),
|
|
21160
|
+
upsertCodingJobPlan: (params, requestOptions) => request("POST", `${apiPrefix}/coding-job-plan`, params, requestOptions),
|
|
20866
21161
|
replaceCodingJobPlanSteps: (params) => request("POST", `${apiPrefix}/coding-job-plan/steps`, params),
|
|
20867
21162
|
updateCodingJobPlanStep: (params) => request("POST", `${apiPrefix}/coding-job-plan/step`, params),
|
|
20868
21163
|
linkCodingJobPullRequest: (params) => request("POST", `${apiPrefix}/coding-job-primary-pr`, params),
|
|
@@ -25649,29 +25944,18 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
|
|
|
25649
25944
|
approvalPolicy: stringValue(control.approvalPolicy) ?? void 0
|
|
25650
25945
|
});
|
|
25651
25946
|
if (applied.approval_policy === "never") {
|
|
25652
|
-
|
|
25653
|
-
|
|
25654
|
-
|
|
25655
|
-
|
|
25656
|
-
|
|
25657
|
-
|
|
25658
|
-
|
|
25659
|
-
|
|
25660
|
-
|
|
25661
|
-
|
|
25662
|
-
|
|
25663
|
-
|
|
25664
|
-
status: "processing",
|
|
25665
|
-
reason: "Claude Code tool approved",
|
|
25666
|
-
sessionId: pending.sessionId ?? control.threadId
|
|
25667
|
-
});
|
|
25668
|
-
log2("claude_code.approval_request_auto_approved", {
|
|
25669
|
-
request_id: requestId,
|
|
25670
|
-
source_seq: pending.sourceSeq,
|
|
25671
|
-
session_id: pending.sessionId ?? control.threadId,
|
|
25672
|
-
reason: "full_access_enabled"
|
|
25673
|
-
});
|
|
25674
|
-
}
|
|
25947
|
+
await settleClaudeCodeApprovalsForSession({
|
|
25948
|
+
kandan,
|
|
25949
|
+
topic,
|
|
25950
|
+
pendingClaudeCodeApprovals,
|
|
25951
|
+
// activeClaudeCodeSessions is keyed by the SDK session id, so
|
|
25952
|
+
// control.threadId here is the SDK session id, NOT the linzumi thread
|
|
25953
|
+
// id. The drain matches pending approvals by their linzumi threadId,
|
|
25954
|
+
// so pass the session's stored linzumi threadId (Codex PR #1846 P1).
|
|
25955
|
+
sessionThreadId: claudeSession.threadId,
|
|
25956
|
+
log: log2,
|
|
25957
|
+
reason: "full_access_enabled"
|
|
25958
|
+
});
|
|
25675
25959
|
}
|
|
25676
25960
|
return {
|
|
25677
25961
|
instanceId,
|
|
@@ -25800,12 +26084,18 @@ function truncateFailureDetail(message) {
|
|
|
25800
26084
|
}
|
|
25801
26085
|
function commanderDeveloperInstructions(args) {
|
|
25802
26086
|
const agentLabel = args.agentLabel ?? "Codex";
|
|
25803
|
-
const
|
|
25804
|
-
|
|
25805
|
-
|
|
25806
|
-
|
|
25807
|
-
|
|
25808
|
-
|
|
26087
|
+
const planOpener = `Before you begin ANY work - and again whenever the job
|
|
26088
|
+
changes - call linzumi_upsert_coding_job_plan to set or refresh the current
|
|
26089
|
+
goal and the high-level plan. Always record the plan up front, before starting
|
|
26090
|
+
work, so the user can see a high-level view of what you are doing at all times
|
|
26091
|
+
and trust your work. Keep it accurate as you go: whenever you discover steps to
|
|
26092
|
+
add, steps that are no longer needed, or the nature of the job changes, update
|
|
26093
|
+
it with linzumi_upsert_coding_job_plan.`;
|
|
26094
|
+
const planStepsInstruction = args.planTool === "todo-write" ? `${planOpener}
|
|
26095
|
+
Record and maintain the plan STEPS with the TodoWrite tool. Linzumi mirrors
|
|
26096
|
+
your TodoWrite list into the coding-job plan steps automatically, one TodoWrite
|
|
26097
|
+
item per plan step.` : `${planOpener}
|
|
26098
|
+
Replace the plan STEPS with linzumi_replace_coding_job_plan_steps.`;
|
|
25809
26099
|
const planUpdateInstruction = args.planTool === "todo-write" ? `As work proceeds, update each step's status with TodoWrite. Do not call
|
|
25810
26100
|
linzumi_replace_coding_job_plan_steps or linzumi_update_coding_job_plan_step
|
|
25811
26101
|
directly; TodoWrite is the source of truth for the plan steps.` : `As work proceeds, update each step with linzumi_update_coding_job_plan_step.`;
|
|
@@ -26194,6 +26484,14 @@ async function startCodexProviderInstance(args) {
|
|
|
26194
26484
|
}
|
|
26195
26485
|
};
|
|
26196
26486
|
}
|
|
26487
|
+
function claudeCodeTurnStallThresholdMs(env) {
|
|
26488
|
+
const raw = env.LINZUMI_CLAUDE_TURN_STALL_MS?.trim();
|
|
26489
|
+
if (raw === void 0 || raw === "") {
|
|
26490
|
+
return defaultClaudeCodeTurnStallThresholdMs;
|
|
26491
|
+
}
|
|
26492
|
+
const parsed = Number.parseInt(raw, 10);
|
|
26493
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : defaultClaudeCodeTurnStallThresholdMs;
|
|
26494
|
+
}
|
|
26197
26495
|
function createClaudeCodeInputQueue(input) {
|
|
26198
26496
|
const pendingMessages = [
|
|
26199
26497
|
claudeCodeUserInputMessage(input.content)
|
|
@@ -26521,6 +26819,7 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
26521
26819
|
args.options,
|
|
26522
26820
|
args.control
|
|
26523
26821
|
);
|
|
26822
|
+
const initialPermissionMode = runtimeSettings.approvalPolicy === void 0 ? void 0 : claudePermissionModeForApprovalPolicy(runtimeSettings.approvalPolicy);
|
|
26524
26823
|
if (args.resumeSessionId !== void 0) {
|
|
26525
26824
|
try {
|
|
26526
26825
|
await validateClaudeCodeResumeSession({
|
|
@@ -26557,18 +26856,54 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
26557
26856
|
let startControlResponded = false;
|
|
26558
26857
|
let activeSessionId;
|
|
26559
26858
|
let sessionControls;
|
|
26859
|
+
let startupApprovalDrain;
|
|
26560
26860
|
const planMirrorClient = createLinzumiMcpApiClient({
|
|
26561
26861
|
kandanUrl: args.options.kandanUrl,
|
|
26562
26862
|
accessToken: args.options.token,
|
|
26563
26863
|
fetchImpl: args.options.fetch,
|
|
26564
26864
|
operatingMode: "text"
|
|
26565
26865
|
});
|
|
26866
|
+
const seededGoal = workDescription.trim().slice(0, 2e3);
|
|
26566
26867
|
const planMirror = createClaudeCodePlanMirror({
|
|
26567
26868
|
replacePlanSteps: planMirrorClient.replaceCodingJobPlanSteps,
|
|
26568
26869
|
threadId,
|
|
26569
|
-
goal:
|
|
26870
|
+
goal: seededGoal,
|
|
26570
26871
|
log: args.log
|
|
26571
26872
|
});
|
|
26873
|
+
const seedCodingJobGoalBeforeTurn = async () => {
|
|
26874
|
+
if (args.resumeSessionId !== void 0) {
|
|
26875
|
+
return;
|
|
26876
|
+
}
|
|
26877
|
+
const seedTimeoutMs = 5e3;
|
|
26878
|
+
const seedAbort = new AbortController();
|
|
26879
|
+
let timeoutHandle;
|
|
26880
|
+
const timedOut = new Promise((resolve12) => {
|
|
26881
|
+
timeoutHandle = setTimeout(() => {
|
|
26882
|
+
seedAbort.abort(new Error("claude goal seed timed out"));
|
|
26883
|
+
args.log("claude_code.goal_seed_timeout", {
|
|
26884
|
+
thread_id: threadId,
|
|
26885
|
+
timeout_ms: seedTimeoutMs
|
|
26886
|
+
});
|
|
26887
|
+
resolve12();
|
|
26888
|
+
}, seedTimeoutMs);
|
|
26889
|
+
});
|
|
26890
|
+
try {
|
|
26891
|
+
await Promise.race([
|
|
26892
|
+
seedClaudeCodingJobGoal({
|
|
26893
|
+
upsertCodingJobPlan: planMirrorClient.upsertCodingJobPlan,
|
|
26894
|
+
threadId,
|
|
26895
|
+
goal: seededGoal,
|
|
26896
|
+
log: args.log,
|
|
26897
|
+
signal: seedAbort.signal
|
|
26898
|
+
}),
|
|
26899
|
+
timedOut
|
|
26900
|
+
]);
|
|
26901
|
+
} finally {
|
|
26902
|
+
if (timeoutHandle !== void 0) {
|
|
26903
|
+
clearTimeout(timeoutHandle);
|
|
26904
|
+
}
|
|
26905
|
+
}
|
|
26906
|
+
};
|
|
26572
26907
|
const adapter = createClaudeCodeSessionPipeline({
|
|
26573
26908
|
instanceId: args.instanceId,
|
|
26574
26909
|
cwd: args.cwd,
|
|
@@ -26874,6 +27209,7 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
26874
27209
|
});
|
|
26875
27210
|
const runSession = async () => {
|
|
26876
27211
|
let result2;
|
|
27212
|
+
await seedCodingJobGoalBeforeTurn();
|
|
26877
27213
|
try {
|
|
26878
27214
|
try {
|
|
26879
27215
|
result2 = await startClaudeCodeSession({
|
|
@@ -26887,9 +27223,35 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
26887
27223
|
linzumiContext
|
|
26888
27224
|
}),
|
|
26889
27225
|
model: claudeCodeModelForRuntimeModel(runtimeSettings.model),
|
|
27226
|
+
// Apply the user's initial access level at session START, mirroring
|
|
27227
|
+
// codex (which seeds approvalPolicy / sandbox via
|
|
27228
|
+
// codexThreadRuntimeOverrides at start). Without this every Claude
|
|
27229
|
+
// Code session started in the SDK's 'default' mode and the no-prompt
|
|
27230
|
+
// ("never" -> bypassPermissions) level only took effect once an
|
|
27231
|
+
// update_session_settings control arrived post-start - so WebFetch
|
|
27232
|
+
// (no built-in allowlist) still raised an approval card on turn 1.
|
|
27233
|
+
// The mode is derived from runtimeSettings.approvalPolicy, which the
|
|
27234
|
+
// server already gates so only "never" (paired with a full-access
|
|
27235
|
+
// sandbox) survives to map to bypassPermissions; lesser levels keep
|
|
27236
|
+
// their 'default' / 'acceptEdits' modes.
|
|
27237
|
+
...initialPermissionMode === void 0 ? {} : { permissionMode: initialPermissionMode },
|
|
26890
27238
|
resumeSessionId: args.resumeSessionId,
|
|
26891
27239
|
abortController,
|
|
26892
27240
|
streamingInput: inputQueue,
|
|
27241
|
+
// PROD-RESILIENCE turn-stall watchdog (real-SDK sessions only; mock
|
|
27242
|
+
// runners drive their own timing). A turn that stays in flight with
|
|
27243
|
+
// no SDK output past the threshold is a wedged SILENT subprocess: the
|
|
27244
|
+
// watchdog aborts it and fails the turn so the thread reconnects,
|
|
27245
|
+
// instead of sitting "processing" forever (the ~28-min-hang incident).
|
|
27246
|
+
// The in-flight predicate (currentSourceSeq() is defined only while a
|
|
27247
|
+
// turn is queued/active) keeps a keep-alive session idling between
|
|
27248
|
+
// turns from being a false positive.
|
|
27249
|
+
...args.options.claudeCodeRunner === void 0 ? {
|
|
27250
|
+
turnStallThresholdMs: claudeCodeTurnStallThresholdMs(
|
|
27251
|
+
process.env
|
|
27252
|
+
),
|
|
27253
|
+
turnStallIsActive: () => inputQueue.currentSourceSeq() !== void 0
|
|
27254
|
+
} : {},
|
|
26893
27255
|
runner: args.options.claudeCodeRunner,
|
|
26894
27256
|
canUseTool,
|
|
26895
27257
|
...mcpServers === void 0 ? {} : { mcpServers },
|
|
@@ -26904,6 +27266,22 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
26904
27266
|
allowedTools: ["mcp__linzumi__*"],
|
|
26905
27267
|
onSessionControls: (controls) => {
|
|
26906
27268
|
sessionControls = controls;
|
|
27269
|
+
if (initialPermissionMode === "bypassPermissions") {
|
|
27270
|
+
startupApprovalDrain = settleClaudeCodeApprovalsForSession({
|
|
27271
|
+
kandan: args.kandan,
|
|
27272
|
+
topic: args.topic,
|
|
27273
|
+
pendingClaudeCodeApprovals: args.pendingClaudeCodeApprovals,
|
|
27274
|
+
sessionThreadId: threadId,
|
|
27275
|
+
log: args.log,
|
|
27276
|
+
reason: "full_access_started"
|
|
27277
|
+
}).catch((error) => {
|
|
27278
|
+
args.log("claude_code.startup_approval_drain_failed", {
|
|
27279
|
+
linzumi_thread_id: threadId,
|
|
27280
|
+
claude_session_id: activeSessionId ?? null,
|
|
27281
|
+
message: error instanceof Error ? error.message : String(error)
|
|
27282
|
+
});
|
|
27283
|
+
});
|
|
27284
|
+
}
|
|
26907
27285
|
},
|
|
26908
27286
|
onTurnCompleted: () => {
|
|
26909
27287
|
inputQueue.completeTurn();
|
|
@@ -26996,6 +27374,9 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
26996
27374
|
message: error instanceof Error ? error.message : String(error)
|
|
26997
27375
|
});
|
|
26998
27376
|
}
|
|
27377
|
+
if (startupApprovalDrain !== void 0) {
|
|
27378
|
+
await startupApprovalDrain;
|
|
27379
|
+
}
|
|
26999
27380
|
void sessionWork.then(
|
|
27000
27381
|
() => {
|
|
27001
27382
|
args.log("claude_code.session_loop_ended", {
|
|
@@ -27031,6 +27412,35 @@ function claudePermissionModeForApprovalPolicy(approvalPolicy) {
|
|
|
27031
27412
|
return void 0;
|
|
27032
27413
|
}
|
|
27033
27414
|
}
|
|
27415
|
+
function claudeCodeApprovalsForSessionThread(pendingClaudeCodeApprovals, sessionThreadId) {
|
|
27416
|
+
return [...pendingClaudeCodeApprovals.entries()].filter(
|
|
27417
|
+
([, pending]) => pending.threadId === sessionThreadId
|
|
27418
|
+
);
|
|
27419
|
+
}
|
|
27420
|
+
async function settleClaudeCodeApprovalsForSession(args) {
|
|
27421
|
+
const pendingForSession = claudeCodeApprovalsForSessionThread(
|
|
27422
|
+
args.pendingClaudeCodeApprovals,
|
|
27423
|
+
args.sessionThreadId
|
|
27424
|
+
);
|
|
27425
|
+
for (const [requestId, pending] of pendingForSession) {
|
|
27426
|
+
pending.resolve({ type: "allow" });
|
|
27427
|
+
await publishClaudeCodeMessageState(args.kandan, args.topic, {
|
|
27428
|
+
workspace: pending.workspace,
|
|
27429
|
+
channel: pending.channel,
|
|
27430
|
+
threadId: pending.threadId,
|
|
27431
|
+
sourceSeq: pending.sourceSeq,
|
|
27432
|
+
status: "processing",
|
|
27433
|
+
reason: "Claude Code tool approved",
|
|
27434
|
+
sessionId: pending.sessionId ?? args.sessionThreadId
|
|
27435
|
+
});
|
|
27436
|
+
args.log("claude_code.approval_request_auto_approved", {
|
|
27437
|
+
request_id: requestId,
|
|
27438
|
+
source_seq: pending.sourceSeq,
|
|
27439
|
+
session_id: pending.sessionId ?? args.sessionThreadId,
|
|
27440
|
+
reason: args.reason
|
|
27441
|
+
});
|
|
27442
|
+
}
|
|
27443
|
+
}
|
|
27034
27444
|
function claudeSteerInputText(input) {
|
|
27035
27445
|
const items = arrayValue(input) ?? [];
|
|
27036
27446
|
const text2 = items.flatMap((item) => {
|
|
@@ -29202,6 +29612,7 @@ var init_runner = __esm({
|
|
|
29202
29612
|
init_engineChildReaper();
|
|
29203
29613
|
init_claudeCodeLiveBashOutput();
|
|
29204
29614
|
init_claudeCodeSession();
|
|
29615
|
+
init_claudeCodeTurnStallWatchdog();
|
|
29205
29616
|
init_codexAppServer();
|
|
29206
29617
|
init_codexProjectTrust();
|
|
29207
29618
|
init_codexRuntimeOptions();
|
|
@@ -65955,6 +66366,60 @@ async function runMcpServer(args) {
|
|
|
65955
66366
|
},
|
|
65956
66367
|
async (params) => mcpJsonResult(await client.getChannel(params))
|
|
65957
66368
|
);
|
|
66369
|
+
server.tool(
|
|
66370
|
+
"linzumi_search_workspace",
|
|
66371
|
+
"Search the Linzumi workspace with hybrid lexical+semantic retrieval, scoped to what the authorizing user can access. Returns scored content chunks with provenance (channel, thread, authored time) and a permalink to cite.",
|
|
66372
|
+
{
|
|
66373
|
+
workspace: external_exports2.string().optional().describe(
|
|
66374
|
+
"Workspace slug. Omit to use the authenticated token scope."
|
|
66375
|
+
),
|
|
66376
|
+
query: external_exports2.string().min(1).describe("Natural-language or keyword query to retrieve against."),
|
|
66377
|
+
limit: external_exports2.number().int().min(1).max(25).optional().describe("Maximum results to return (default 10, server-capped)."),
|
|
66378
|
+
source_types: external_exports2.array(
|
|
66379
|
+
external_exports2.enum([
|
|
66380
|
+
"message",
|
|
66381
|
+
"coding_job",
|
|
66382
|
+
"github_pr",
|
|
66383
|
+
"github_pr_review",
|
|
66384
|
+
"github_check_run",
|
|
66385
|
+
"github_workflow_run",
|
|
66386
|
+
"github_diff",
|
|
66387
|
+
"dictation",
|
|
66388
|
+
"file"
|
|
66389
|
+
])
|
|
66390
|
+
).optional().describe("Restrict results to these corpora; omit for all."),
|
|
66391
|
+
authored_after: external_exports2.string().optional().describe(
|
|
66392
|
+
"ISO8601 instant; only content authored at or after this time."
|
|
66393
|
+
),
|
|
66394
|
+
authored_before: external_exports2.string().optional().describe(
|
|
66395
|
+
"ISO8601 instant; only content authored at or before this time."
|
|
66396
|
+
),
|
|
66397
|
+
repo: external_exports2.string().optional().describe(
|
|
66398
|
+
"Restrict GitHub-sourced results to one repository by full name (owner/name)."
|
|
66399
|
+
),
|
|
66400
|
+
check_status: external_exports2.enum(["pending", "success", "failed"]).optional().describe(
|
|
66401
|
+
"Restrict check and workflow results to one conclusion bucket."
|
|
66402
|
+
)
|
|
66403
|
+
},
|
|
66404
|
+
async (params) => mcpJsonResult(await client.searchWorkspace(params))
|
|
66405
|
+
);
|
|
66406
|
+
server.tool(
|
|
66407
|
+
"linzumi_ask_workspace",
|
|
66408
|
+
'Ask the Linzumi workspace a natural-language question and get a synthesized, citation-backed answer over what the authorizing user can access. Costs an LLM call on cache misses, so prefer linzumi_search_workspace for simple lookups. A "refused" status means there was not enough accessible evidence - treat it as "the workspace does not know", never retry verbatim.',
|
|
66409
|
+
{
|
|
66410
|
+
workspace: external_exports2.string().optional().describe(
|
|
66411
|
+
"Workspace slug. Omit to use the authenticated token scope."
|
|
66412
|
+
),
|
|
66413
|
+
question: external_exports2.string().min(1).max(2e3).describe("Natural-language question to answer with citations."),
|
|
66414
|
+
channel: external_exports2.string().optional().describe(
|
|
66415
|
+
"Optional channel slug providing conversational context; never widens access."
|
|
66416
|
+
),
|
|
66417
|
+
allow_cached: external_exports2.boolean().optional().describe(
|
|
66418
|
+
"Allow serving a cached synthesis when the evidence set is unchanged (default true). Set false to force fresh synthesis."
|
|
66419
|
+
)
|
|
66420
|
+
},
|
|
66421
|
+
async (params) => mcpJsonResult(await client.askWorkspace(params))
|
|
66422
|
+
);
|
|
65958
66423
|
server.tool(
|
|
65959
66424
|
"linzumi_get_coding_job_metadata",
|
|
65960
66425
|
"Read the active coding job workflow metadata for a thread, including the agent-owned goal, ordered plan steps, step lock versions, and workflow status.",
|
package/package.json
CHANGED