@linzumi/cli 0.0.87-beta → 0.0.89-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 +715 -285
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1936,6 +1936,228 @@ var init_codexRuntimeOptions = __esm({
|
|
|
1936
1936
|
}
|
|
1937
1937
|
});
|
|
1938
1938
|
|
|
1939
|
+
// src/linzumiContext.ts
|
|
1940
|
+
function parseLinzumiConversationContext(value, warn = console.warn) {
|
|
1941
|
+
if (value === void 0) {
|
|
1942
|
+
return void 0;
|
|
1943
|
+
}
|
|
1944
|
+
const context = objectValue(value);
|
|
1945
|
+
if (context === void 0) {
|
|
1946
|
+
return invalidLinzumiContext("linzumiContext must be an object", warn);
|
|
1947
|
+
}
|
|
1948
|
+
const threadId = stringValue(context.threadId);
|
|
1949
|
+
const creatorUserId = stringValue(context.creatorUserId) ?? integerValue(context.creatorUserId)?.toString();
|
|
1950
|
+
const creatorUsername = stringValue(context.creatorUsername);
|
|
1951
|
+
const conversationUrl = stringValue(context.conversationUrl);
|
|
1952
|
+
if (threadId === void 0 || creatorUserId === void 0 || creatorUsername === void 0 || conversationUrl === void 0) {
|
|
1953
|
+
return invalidLinzumiContext(
|
|
1954
|
+
"linzumiContext must include threadId, creatorUserId, creatorUsername, and conversationUrl",
|
|
1955
|
+
warn
|
|
1956
|
+
);
|
|
1957
|
+
}
|
|
1958
|
+
return { threadId, creatorUserId, creatorUsername, conversationUrl };
|
|
1959
|
+
}
|
|
1960
|
+
function formatLinzumiConversationContextForPrompt(context) {
|
|
1961
|
+
return `<linzumi_context>
|
|
1962
|
+
<linzumi_thread_id>${escapeXmlText(context.threadId)}</linzumi_thread_id>
|
|
1963
|
+
<linzumi_creator_user_id>${escapeXmlText(context.creatorUserId)}</linzumi_creator_user_id>
|
|
1964
|
+
<linzumi_creator_username>${escapeXmlText(context.creatorUsername)}</linzumi_creator_username>
|
|
1965
|
+
<linzumi_conversation_url>${escapeXmlText(context.conversationUrl)}</linzumi_conversation_url>
|
|
1966
|
+
</linzumi_context>
|
|
1967
|
+
|
|
1968
|
+
<linzumi_pr_footer_instruction>
|
|
1969
|
+
For any GitHub pull request you open from this session, include this Markdown footer link in the PR description: [Continue this on Linzumi](${context.conversationUrl})
|
|
1970
|
+
</linzumi_pr_footer_instruction>`;
|
|
1971
|
+
}
|
|
1972
|
+
function invalidLinzumiContext(reason, warn) {
|
|
1973
|
+
warn(`Ignoring invalid linzumiContext: ${reason}`);
|
|
1974
|
+
return void 0;
|
|
1975
|
+
}
|
|
1976
|
+
function escapeXmlText(value) {
|
|
1977
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
1978
|
+
}
|
|
1979
|
+
var init_linzumiContext = __esm({
|
|
1980
|
+
"src/linzumiContext.ts"() {
|
|
1981
|
+
"use strict";
|
|
1982
|
+
init_json();
|
|
1983
|
+
}
|
|
1984
|
+
});
|
|
1985
|
+
|
|
1986
|
+
// src/commanderDeveloperInstructions.ts
|
|
1987
|
+
function commanderDeveloperInstructions(args) {
|
|
1988
|
+
const agentLabel = args.agentLabel ?? "Codex";
|
|
1989
|
+
const planOpener = `Before you begin ANY work - and again whenever the job
|
|
1990
|
+
changes - call linzumi_upsert_coding_job_plan to set or refresh the current
|
|
1991
|
+
goal and the high-level plan. Always record the plan up front, before starting
|
|
1992
|
+
work, so the user can see a high-level view of what you are doing at all times
|
|
1993
|
+
and trust your work. Keep it accurate as you go: whenever you discover steps to
|
|
1994
|
+
add, steps that are no longer needed, or the nature of the job changes, update
|
|
1995
|
+
it with linzumi_upsert_coding_job_plan.`;
|
|
1996
|
+
const planStepsInstruction = args.planTool === "todo-write" ? `${planOpener}
|
|
1997
|
+
Record and maintain the plan STEPS with the TodoWrite tool. Linzumi mirrors
|
|
1998
|
+
your TodoWrite list into the coding-job plan steps automatically, one TodoWrite
|
|
1999
|
+
item per plan step.` : `${planOpener}
|
|
2000
|
+
Replace the plan STEPS with linzumi_replace_coding_job_plan_steps.`;
|
|
2001
|
+
const planUpdateInstruction = args.planTool === "todo-write" ? `As work proceeds, update each step's status with TodoWrite. Do not call
|
|
2002
|
+
linzumi_replace_coding_job_plan_steps or linzumi_update_coding_job_plan_step
|
|
2003
|
+
directly; TodoWrite is the source of truth for the plan steps.` : `As work proceeds, update each step with linzumi_update_coding_job_plan_step.`;
|
|
2004
|
+
const customPrompt = args.developerPrompt === void 0 ? "" : `
|
|
2005
|
+
<invoker_developer_prompt>
|
|
2006
|
+
${args.developerPrompt}
|
|
2007
|
+
</invoker_developer_prompt>
|
|
2008
|
+
`;
|
|
2009
|
+
const linzumiContext = args.linzumiContext === void 0 ? "" : `
|
|
2010
|
+
${formatLinzumiConversationContextForPrompt(args.linzumiContext)}
|
|
2011
|
+
`;
|
|
2012
|
+
return `<context>
|
|
2013
|
+
You are a Linzumi ${agentLabel} session launched by the Linzumi Commander.
|
|
2014
|
+
The Commander is the local bridge process that connects this computer to the
|
|
2015
|
+
user's Linzumi workspace, secure preview tunnel, browser VS Code editor, and
|
|
2016
|
+
thread transcript. Your work and progress are relayed into that Linzumi thread.
|
|
2017
|
+
</context>
|
|
2018
|
+
|
|
2019
|
+
<term_definitions>
|
|
2020
|
+
Bootstrapper ${agentLabel}: The outer setup agent that claimed/signup, generated the
|
|
2021
|
+
demo folder when applicable, and asked Linzumi to start this session. It does
|
|
2022
|
+
not own implementation work.
|
|
2023
|
+
Linzumi Commander: The local long-running process that launched this ${agentLabel}
|
|
2024
|
+
session, enforces the trusted folder, and forwards descendant preview ports to
|
|
2025
|
+
Linzumi.
|
|
2026
|
+
Linzumi ${agentLabel} session: You, the inner ${agentLabel} process that performs the actual
|
|
2027
|
+
work in the approved project folder.
|
|
2028
|
+
Approved project folder: ${args.cwd}
|
|
2029
|
+
Coding-job metadata: User-visible goal, plan steps, step statuses, completion
|
|
2030
|
+
notes, primary pull request link, and worktree state shown in Linzumi's coding
|
|
2031
|
+
job overview.
|
|
2032
|
+
Plan step: A discrete chunk of work with a short title, one-line description,
|
|
2033
|
+
status, and completion note. It should describe an actual goal, not just a
|
|
2034
|
+
process verb.
|
|
2035
|
+
Primary pull request: The GitHub PR the job is currently driving or reviewing;
|
|
2036
|
+
Linzumi uses this link to hydrate PR comments, files, commits, checks, and
|
|
2037
|
+
deployments in the metadata overview.
|
|
2038
|
+
</term_definitions>
|
|
2039
|
+
|
|
2040
|
+
<linzumi_mcp>
|
|
2041
|
+
The Codex process is preconfigured with a Linzumi MCP server named "linzumi".
|
|
2042
|
+
Use it when you need authenticated context from the current Linzumi workspace:
|
|
2043
|
+
read a message by ID/URL, read a thread by ID, read the scoped channel, or send
|
|
2044
|
+
a concise DM to the Commander owner when the task genuinely requires it.
|
|
2045
|
+
</linzumi_mcp>
|
|
2046
|
+
|
|
2047
|
+
<task_instructions>
|
|
2048
|
+
Work only in the approved project folder unless the human explicitly asks for
|
|
2049
|
+
something else in the Linzumi thread. Start, inspect, and modify the local app
|
|
2050
|
+
from that folder. Report concise progress and exact blockers in the thread.
|
|
2051
|
+
Use the Linzumi MCP server named "linzumi" when you need authenticated
|
|
2052
|
+
workspace context or coding-job metadata tools.
|
|
2053
|
+
${planStepsInstruction}
|
|
2054
|
+
When the coding-job scope changes materially, call linzumi_rename_coding_job
|
|
2055
|
+
with a concise title so the Linzumi thread title and workflow-facing title
|
|
2056
|
+
match the work.
|
|
2057
|
+
${planUpdateInstruction}
|
|
2058
|
+
When you open, discover, or choose the primary pull request, link it with
|
|
2059
|
+
linzumi_link_coding_job_pull_request.
|
|
2060
|
+
Before stopping, confirm the metadata overview tells the truth for a user who
|
|
2061
|
+
only sees that overview: completed work is completed, active work is really
|
|
2062
|
+
active, blocked work says why, and no stale in-progress step is left behind.
|
|
2063
|
+
For frontend or other user-visible changes, ask whether the user wants
|
|
2064
|
+
screenshot or screen-recording proof, ideally before/after when that helps
|
|
2065
|
+
review the change. Screen recordings should be WebM or MP4.
|
|
2066
|
+
When the user asks you to open or update a PR, attach or link feasible proof in
|
|
2067
|
+
the PR and state the exact blocker when proof is not feasible.
|
|
2068
|
+
</task_instructions>
|
|
2069
|
+
|
|
2070
|
+
<rules>
|
|
2071
|
+
You MUST treat the Linzumi thread as the source of truth for user-facing
|
|
2072
|
+
progress.
|
|
2073
|
+
For coding-job threads, you MUST keep coding-job metadata current throughout
|
|
2074
|
+
the job.
|
|
2075
|
+
Plan steps MUST be fairly granular, discrete chunks of real work that a human
|
|
2076
|
+
can track.
|
|
2077
|
+
Plan step descriptions MUST stay short, usually one line and less than one full
|
|
2078
|
+
sentence.
|
|
2079
|
+
Plan steps MUST NOT be vague process-only labels such as "sync PR",
|
|
2080
|
+
"update PR", "verify PR", or "commit and merge" when those labels hide the
|
|
2081
|
+
concrete goal.
|
|
2082
|
+
You MUST update steps in sequence as work is completed. Do not mark a later
|
|
2083
|
+
step active while earlier applicable steps are still pending.
|
|
2084
|
+
Before you stop work, you MUST reconcile the plan so the job is not left with a
|
|
2085
|
+
stale active step. You may delegate metadata upkeep to a sub-agent when useful,
|
|
2086
|
+
but the visible job state must remain truthful.
|
|
2087
|
+
If the coding-job thread title is missing, undefined, or "Untitled", you MUST
|
|
2088
|
+
choose a concise, specific title for the job.
|
|
2089
|
+
User-visible UI, status, error, and PR-review copy MUST keep it short, direct,
|
|
2090
|
+
and focused on the user's outcome unless the user explicitly asks for
|
|
2091
|
+
implementation detail.
|
|
2092
|
+
You MUST keep user-visible preview servers bound to 0.0.0.0, not 127.0.0.1 or
|
|
2093
|
+
localhost, so the Linzumi secure tunnel can reach them.
|
|
2094
|
+
You MUST keep any preview or dev server as your descendant process so the
|
|
2095
|
+
Commander can discover and forward it.
|
|
2096
|
+
You MUST NOT ask the Bootstrapper ${agentLabel} to do implementation work.
|
|
2097
|
+
You MUST NOT inspect unrelated repositories or folders.
|
|
2098
|
+
You MUST report the exact blocker if a command, preview, editor, or tunnel step
|
|
2099
|
+
fails.
|
|
2100
|
+
When several Linzumi Codex sessions work in the same repository, create or use
|
|
2101
|
+
a separate checkout or git worktree for this task before making changes, unless
|
|
2102
|
+
the human explicitly asks you to share the current checkout. Do not overwrite or
|
|
2103
|
+
revert another session's work.
|
|
2104
|
+
</rules>
|
|
2105
|
+
|
|
2106
|
+
<examples>
|
|
2107
|
+
GOOD preview command: npm run dev -- --host 0.0.0.0 --port 8787
|
|
2108
|
+
Why good: The preview is reachable through the Linzumi secure tunnel.
|
|
2109
|
+
|
|
2110
|
+
BAD preview command: npm run dev -- --host 127.0.0.1
|
|
2111
|
+
Why bad: Binding to localhost prevents the Linzumi secure tunnel from reaching
|
|
2112
|
+
the preview.
|
|
2113
|
+
|
|
2114
|
+
GOOD coding-job plan:
|
|
2115
|
+
- Inspect prompt sources: Locate the prompt builder, prompt guide, and tests.
|
|
2116
|
+
- Add metadata guidance: Patch the prompt with plan, title, and stop-state rules.
|
|
2117
|
+
- Verify compiled prompt: Run focused tests and inspect the generated text.
|
|
2118
|
+
- Push PR update: Commit owned files, push the branch, and refresh PR metadata.
|
|
2119
|
+
Why good: Each step is a concrete chunk of work, the list is short enough to
|
|
2120
|
+
scan, and the titles explain what is actually happening.
|
|
2121
|
+
|
|
2122
|
+
BAD coding-job plan:
|
|
2123
|
+
- Sync PR
|
|
2124
|
+
- Update PR
|
|
2125
|
+
- Verify PR
|
|
2126
|
+
- Commit and merge
|
|
2127
|
+
Why bad: These labels describe process mechanics, not the concrete work or
|
|
2128
|
+
product goal. A user cannot tell what the agent has learned, changed, or still
|
|
2129
|
+
needs to do.
|
|
2130
|
+
|
|
2131
|
+
BAD coding-job metadata state:
|
|
2132
|
+
- Step 1 complete, Step 2 complete, Step 3 active, Step 4 pending.
|
|
2133
|
+
- The agent has stopped working and sent its final response.
|
|
2134
|
+
Why bad: The overview still says work is active even though the agent is idle.
|
|
2135
|
+
Before stopping, the agent should mark Step 3 completed, blocked, or canceled
|
|
2136
|
+
with a truthful note.
|
|
2137
|
+
</examples>
|
|
2138
|
+
${linzumiContext}
|
|
2139
|
+
${customPrompt}
|
|
2140
|
+
<task_reminder>
|
|
2141
|
+
You are the Commander-launched Linzumi ${agentLabel} session. Do the implementation
|
|
2142
|
+
work in the approved project folder, keep preview servers reachable through the
|
|
2143
|
+
secure tunnel, and keep the Linzumi thread and coding-job metadata truthful.
|
|
2144
|
+
</task_reminder>
|
|
2145
|
+
|
|
2146
|
+
<output_format>
|
|
2147
|
+
Use normal concise Linzumi thread messages for user-facing progress and final
|
|
2148
|
+
answers. When the task requires files, code, commits, pull requests, previews,
|
|
2149
|
+
or verification output, report the concrete artifact, command, result, and any
|
|
2150
|
+
exact blocker. Do not emit machine-only JSON unless the user or tool explicitly
|
|
2151
|
+
requests it.
|
|
2152
|
+
</output_format>`;
|
|
2153
|
+
}
|
|
2154
|
+
var init_commanderDeveloperInstructions = __esm({
|
|
2155
|
+
"src/commanderDeveloperInstructions.ts"() {
|
|
2156
|
+
"use strict";
|
|
2157
|
+
init_linzumiContext();
|
|
2158
|
+
}
|
|
2159
|
+
});
|
|
2160
|
+
|
|
1939
2161
|
// src/codexOutput.ts
|
|
1940
2162
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
1941
2163
|
import { fileURLToPath } from "node:url";
|
|
@@ -6552,53 +6774,6 @@ var init_kandanQueue = __esm({
|
|
|
6552
6774
|
}
|
|
6553
6775
|
});
|
|
6554
6776
|
|
|
6555
|
-
// src/linzumiContext.ts
|
|
6556
|
-
function parseLinzumiConversationContext(value, warn = console.warn) {
|
|
6557
|
-
if (value === void 0) {
|
|
6558
|
-
return void 0;
|
|
6559
|
-
}
|
|
6560
|
-
const context = objectValue(value);
|
|
6561
|
-
if (context === void 0) {
|
|
6562
|
-
return invalidLinzumiContext("linzumiContext must be an object", warn);
|
|
6563
|
-
}
|
|
6564
|
-
const threadId = stringValue(context.threadId);
|
|
6565
|
-
const creatorUserId = stringValue(context.creatorUserId) ?? integerValue(context.creatorUserId)?.toString();
|
|
6566
|
-
const creatorUsername = stringValue(context.creatorUsername);
|
|
6567
|
-
const conversationUrl = stringValue(context.conversationUrl);
|
|
6568
|
-
if (threadId === void 0 || creatorUserId === void 0 || creatorUsername === void 0 || conversationUrl === void 0) {
|
|
6569
|
-
return invalidLinzumiContext(
|
|
6570
|
-
"linzumiContext must include threadId, creatorUserId, creatorUsername, and conversationUrl",
|
|
6571
|
-
warn
|
|
6572
|
-
);
|
|
6573
|
-
}
|
|
6574
|
-
return { threadId, creatorUserId, creatorUsername, conversationUrl };
|
|
6575
|
-
}
|
|
6576
|
-
function formatLinzumiConversationContextForPrompt(context) {
|
|
6577
|
-
return `<linzumi_context>
|
|
6578
|
-
<linzumi_thread_id>${escapeXmlText(context.threadId)}</linzumi_thread_id>
|
|
6579
|
-
<linzumi_creator_user_id>${escapeXmlText(context.creatorUserId)}</linzumi_creator_user_id>
|
|
6580
|
-
<linzumi_creator_username>${escapeXmlText(context.creatorUsername)}</linzumi_creator_username>
|
|
6581
|
-
<linzumi_conversation_url>${escapeXmlText(context.conversationUrl)}</linzumi_conversation_url>
|
|
6582
|
-
</linzumi_context>
|
|
6583
|
-
|
|
6584
|
-
<linzumi_pr_footer_instruction>
|
|
6585
|
-
For any GitHub pull request you open from this session, include this Markdown footer link in the PR description: [Continue this on Linzumi](${context.conversationUrl})
|
|
6586
|
-
</linzumi_pr_footer_instruction>`;
|
|
6587
|
-
}
|
|
6588
|
-
function invalidLinzumiContext(reason, warn) {
|
|
6589
|
-
warn(`Ignoring invalid linzumiContext: ${reason}`);
|
|
6590
|
-
return void 0;
|
|
6591
|
-
}
|
|
6592
|
-
function escapeXmlText(value) {
|
|
6593
|
-
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
6594
|
-
}
|
|
6595
|
-
var init_linzumiContext = __esm({
|
|
6596
|
-
"src/linzumiContext.ts"() {
|
|
6597
|
-
"use strict";
|
|
6598
|
-
init_json();
|
|
6599
|
-
}
|
|
6600
|
-
});
|
|
6601
|
-
|
|
6602
6777
|
// src/reconnectContext.ts
|
|
6603
6778
|
function parseReconnectContextMessages(value) {
|
|
6604
6779
|
if (!Array.isArray(value)) {
|
|
@@ -11336,10 +11511,27 @@ async function startCodexThread(codex, options) {
|
|
|
11336
11511
|
cwd: options.cwd,
|
|
11337
11512
|
serviceName: "kandan-local-runner",
|
|
11338
11513
|
personality: "pragmatic",
|
|
11514
|
+
...developerInstructionsForThreadStart(options),
|
|
11339
11515
|
...codexThreadRuntimeOverrides(options)
|
|
11340
11516
|
});
|
|
11341
11517
|
return extractThreadIdFromResponse(start);
|
|
11342
11518
|
}
|
|
11519
|
+
function developerInstructionsForThreadStart(options) {
|
|
11520
|
+
const developerPrompt = options.channelSession.developerPrompt;
|
|
11521
|
+
if (developerPrompt === void 0) {
|
|
11522
|
+
return {};
|
|
11523
|
+
}
|
|
11524
|
+
return {
|
|
11525
|
+
developerInstructions: commanderDeveloperInstructions({
|
|
11526
|
+
cwd: options.cwd,
|
|
11527
|
+
planTool: "linzumi-mcp",
|
|
11528
|
+
developerPrompt,
|
|
11529
|
+
linzumiContext: parseLinzumiConversationContext(
|
|
11530
|
+
options.channelSession.linzumiContext
|
|
11531
|
+
)
|
|
11532
|
+
})
|
|
11533
|
+
};
|
|
11534
|
+
}
|
|
11343
11535
|
async function pushOk2(kandan, topic, event, payload) {
|
|
11344
11536
|
const reply = await kandan.push(topic, event, payload);
|
|
11345
11537
|
if (isJsonObject(reply) && reply.status === "ok" && isJsonObject(reply.response)) {
|
|
@@ -11366,6 +11558,7 @@ var init_channelSession = __esm({
|
|
|
11366
11558
|
init_channelSessionSupport();
|
|
11367
11559
|
init_commanderAttachments();
|
|
11368
11560
|
init_codexRuntimeOptions();
|
|
11561
|
+
init_commanderDeveloperInstructions();
|
|
11369
11562
|
init_codexOutput();
|
|
11370
11563
|
init_codexSessionLog();
|
|
11371
11564
|
init_integration();
|
|
@@ -11541,7 +11734,7 @@ function createClaudeCodeSessionPipeline(host) {
|
|
|
11541
11734
|
const toolName2 = pending?.toolName ?? event.toolName ?? "tool";
|
|
11542
11735
|
const input = pending?.input ?? {};
|
|
11543
11736
|
const itemId = `tool:${event.itemKey}`;
|
|
11544
|
-
if (
|
|
11737
|
+
if (isFileChangeTool(toolName2)) {
|
|
11545
11738
|
const patchText = claudeFileChangePatchText(toolName2, input, {
|
|
11546
11739
|
targetExistedAtCall: pending?.targetExistedAtCall
|
|
11547
11740
|
});
|
|
@@ -11549,7 +11742,7 @@ function createClaudeCodeSessionPipeline(host) {
|
|
|
11549
11742
|
const item2 = {
|
|
11550
11743
|
type: "fileChange",
|
|
11551
11744
|
id: itemId,
|
|
11552
|
-
status: "completed",
|
|
11745
|
+
status: event.isError ? "failed" : "completed",
|
|
11553
11746
|
patchText
|
|
11554
11747
|
};
|
|
11555
11748
|
recordItem(turn, item2);
|
|
@@ -11569,12 +11762,13 @@ function createClaudeCodeSessionPipeline(host) {
|
|
|
11569
11762
|
submit("item/completed", { turnId: turn.turnId, item: item2 });
|
|
11570
11763
|
return;
|
|
11571
11764
|
}
|
|
11572
|
-
if (!event.isError && toolName2
|
|
11765
|
+
if (!event.isError && isClaudePlanTool(toolName2)) {
|
|
11573
11766
|
host.onTodoWriteCompleted?.(input);
|
|
11574
11767
|
const plan = claudePlanItem(itemId, input);
|
|
11575
11768
|
if (plan !== void 0) {
|
|
11576
|
-
|
|
11577
|
-
|
|
11769
|
+
const planRow = { ...plan, id: itemId };
|
|
11770
|
+
recordItem(turn, planRow);
|
|
11771
|
+
submit("item/completed", { turnId: turn.turnId, item: planRow });
|
|
11578
11772
|
return;
|
|
11579
11773
|
}
|
|
11580
11774
|
}
|
|
@@ -11605,7 +11799,7 @@ function createClaudeCodeSessionPipeline(host) {
|
|
|
11605
11799
|
}
|
|
11606
11800
|
case "reasoning_delta": {
|
|
11607
11801
|
const turn = ensureTurn();
|
|
11608
|
-
const itemId =
|
|
11802
|
+
const itemId = claudeReasoningPipelineItemId(event.itemKey);
|
|
11609
11803
|
appendRawText(turn, itemId, "reasoning", event.delta);
|
|
11610
11804
|
submit("item/reasoning/textDelta", {
|
|
11611
11805
|
turnId: turn.turnId,
|
|
@@ -11626,7 +11820,7 @@ function createClaudeCodeSessionPipeline(host) {
|
|
|
11626
11820
|
}
|
|
11627
11821
|
case "reasoning_message": {
|
|
11628
11822
|
const turn = ensureTurn();
|
|
11629
|
-
const itemId =
|
|
11823
|
+
const itemId = claudeReasoningPipelineItemId(event.itemKey);
|
|
11630
11824
|
setRawText(turn, itemId, "reasoning", event.content);
|
|
11631
11825
|
submit("item/completed", {
|
|
11632
11826
|
turnId: turn.turnId,
|
|
@@ -11636,14 +11830,15 @@ function createClaudeCodeSessionPipeline(host) {
|
|
|
11636
11830
|
}
|
|
11637
11831
|
case "tool_call": {
|
|
11638
11832
|
const turn = ensureTurn();
|
|
11833
|
+
const targetExistedAtCall = fileChangeTargetExists(
|
|
11834
|
+
event.toolName,
|
|
11835
|
+
event.input,
|
|
11836
|
+
host.cwd
|
|
11837
|
+
);
|
|
11639
11838
|
turn.pendingTools.set(event.itemKey, {
|
|
11640
11839
|
toolName: event.toolName,
|
|
11641
11840
|
input: event.input,
|
|
11642
|
-
targetExistedAtCall
|
|
11643
|
-
event.toolName,
|
|
11644
|
-
event.input,
|
|
11645
|
-
host.cwd
|
|
11646
|
-
)
|
|
11841
|
+
targetExistedAtCall
|
|
11647
11842
|
});
|
|
11648
11843
|
if (isWebSearchTool(event.toolName)) {
|
|
11649
11844
|
const query = stringValue(event.input.query) ?? stringValue(event.input.url) ?? event.toolName;
|
|
@@ -11655,7 +11850,34 @@ function createClaudeCodeSessionPipeline(host) {
|
|
|
11655
11850
|
query
|
|
11656
11851
|
}
|
|
11657
11852
|
});
|
|
11853
|
+
return;
|
|
11854
|
+
}
|
|
11855
|
+
if (isClaudePlanTool(event.toolName)) {
|
|
11856
|
+
return;
|
|
11658
11857
|
}
|
|
11858
|
+
const itemId = `tool:${event.itemKey}`;
|
|
11859
|
+
if (isFileChangeTool(event.toolName)) {
|
|
11860
|
+
const patchText = claudeFileChangePatchText(
|
|
11861
|
+
event.toolName,
|
|
11862
|
+
event.input,
|
|
11863
|
+
{ targetExistedAtCall }
|
|
11864
|
+
);
|
|
11865
|
+
if (patchText !== void 0 && patchText.trim() !== "") {
|
|
11866
|
+
submit("item/fileChange/outputDelta", {
|
|
11867
|
+
turnId: turn.turnId,
|
|
11868
|
+
itemId,
|
|
11869
|
+
delta: patchText
|
|
11870
|
+
});
|
|
11871
|
+
}
|
|
11872
|
+
return;
|
|
11873
|
+
}
|
|
11874
|
+
submit("item/commandExecution/outputDelta", {
|
|
11875
|
+
turnId: turn.turnId,
|
|
11876
|
+
itemId,
|
|
11877
|
+
command: claudeToolCommandLabel(event.toolName, event.input),
|
|
11878
|
+
stream: "stdout",
|
|
11879
|
+
delta: "\n"
|
|
11880
|
+
});
|
|
11659
11881
|
return;
|
|
11660
11882
|
}
|
|
11661
11883
|
case "tool_result": {
|
|
@@ -11809,6 +12031,9 @@ function claudeAssistantPipelineItemId(itemKey) {
|
|
|
11809
12031
|
const streamIndex = itemKey.match(/^assistant-stream-(\d+)$/)?.[1];
|
|
11810
12032
|
return streamIndex === void 0 ? itemKey : `content-block-${streamIndex}`;
|
|
11811
12033
|
}
|
|
12034
|
+
function claudeReasoningPipelineItemId(itemKey) {
|
|
12035
|
+
return `reasoning-${claudeAssistantPipelineItemId(itemKey)}`;
|
|
12036
|
+
}
|
|
11812
12037
|
function isFileChangeTool(toolName2) {
|
|
11813
12038
|
switch (toolName2) {
|
|
11814
12039
|
case "Edit":
|
|
@@ -11823,6 +12048,9 @@ function isFileChangeTool(toolName2) {
|
|
|
11823
12048
|
function isWebSearchTool(toolName2) {
|
|
11824
12049
|
return toolName2 === "WebSearch" || toolName2 === "WebFetch";
|
|
11825
12050
|
}
|
|
12051
|
+
function isClaudePlanTool(toolName2) {
|
|
12052
|
+
return toolName2 === "TodoWrite" || toolName2 === "TaskCreate" || toolName2 === "TaskUpdate";
|
|
12053
|
+
}
|
|
11826
12054
|
function fileChangeTargetExists(toolName2, input, sessionCwd) {
|
|
11827
12055
|
if (!isFileChangeTool(toolName2)) {
|
|
11828
12056
|
return void 0;
|
|
@@ -11895,9 +12123,18 @@ ${body}
|
|
|
11895
12123
|
*** End Patch
|
|
11896
12124
|
`;
|
|
11897
12125
|
}
|
|
12126
|
+
function claudePlanInputItems(input) {
|
|
12127
|
+
if (Array.isArray(input.todos)) {
|
|
12128
|
+
return input.todos;
|
|
12129
|
+
}
|
|
12130
|
+
if (Array.isArray(input.tasks)) {
|
|
12131
|
+
return input.tasks;
|
|
12132
|
+
}
|
|
12133
|
+
return [];
|
|
12134
|
+
}
|
|
11898
12135
|
function claudePlanItem(itemId, input) {
|
|
11899
|
-
const
|
|
11900
|
-
const lines =
|
|
12136
|
+
const items = claudePlanInputItems(input);
|
|
12137
|
+
const lines = items.flatMap((todo) => {
|
|
11901
12138
|
const value = objectValue(todo);
|
|
11902
12139
|
if (value === void 0) {
|
|
11903
12140
|
return [];
|
|
@@ -11971,7 +12208,7 @@ function objectValue2(value) {
|
|
|
11971
12208
|
return isJsonObject(value) ? value : void 0;
|
|
11972
12209
|
}
|
|
11973
12210
|
function claudeTodoWritePlanSteps(input) {
|
|
11974
|
-
const todos = Array.isArray(input.todos) ? input.todos : [];
|
|
12211
|
+
const todos = Array.isArray(input.todos) ? input.todos : Array.isArray(input.tasks) ? input.tasks : [];
|
|
11975
12212
|
const steps = todos.flatMap((todo) => {
|
|
11976
12213
|
const value = objectValue2(todo);
|
|
11977
12214
|
if (value === void 0) {
|
|
@@ -12042,6 +12279,29 @@ function createClaudeCodePlanMirror(args) {
|
|
|
12042
12279
|
settle: () => flight
|
|
12043
12280
|
};
|
|
12044
12281
|
}
|
|
12282
|
+
async function seedClaudeCodingJobGoal(args) {
|
|
12283
|
+
const goal = args.goal.trim().slice(0, 2e3);
|
|
12284
|
+
if (goal === "") {
|
|
12285
|
+
return false;
|
|
12286
|
+
}
|
|
12287
|
+
try {
|
|
12288
|
+
await args.upsertCodingJobPlan(
|
|
12289
|
+
{ thread_id: args.threadId, goal },
|
|
12290
|
+
{ signal: args.signal }
|
|
12291
|
+
);
|
|
12292
|
+
args.log("claude_code.goal_seeded", {
|
|
12293
|
+
thread_id: args.threadId,
|
|
12294
|
+
goal_length: goal.length
|
|
12295
|
+
});
|
|
12296
|
+
return true;
|
|
12297
|
+
} catch (error) {
|
|
12298
|
+
args.log("claude_code.goal_seed_failed", {
|
|
12299
|
+
thread_id: args.threadId,
|
|
12300
|
+
message: error instanceof Error ? error.message : String(error)
|
|
12301
|
+
});
|
|
12302
|
+
return false;
|
|
12303
|
+
}
|
|
12304
|
+
}
|
|
12045
12305
|
var todoStatusToPlanStepStatus, planStepTitleMaxLength, planStepDescriptionMaxLength, planStepsMaxCount;
|
|
12046
12306
|
var init_claudeCodePlanMirror = __esm({
|
|
12047
12307
|
"src/claudeCodePlanMirror.ts"() {
|
|
@@ -12597,6 +12857,87 @@ var init_claudeCodeLiveBashOutput = __esm({
|
|
|
12597
12857
|
}
|
|
12598
12858
|
});
|
|
12599
12859
|
|
|
12860
|
+
// src/claudeCodeTurnStallWatchdog.ts
|
|
12861
|
+
function createClaudeCodeTurnStallWatchdog(options) {
|
|
12862
|
+
if (!(options.thresholdMs > 0)) {
|
|
12863
|
+
throw new Error("Claude turn-stall threshold must be > 0");
|
|
12864
|
+
}
|
|
12865
|
+
const now = options.now ?? (() => Date.now());
|
|
12866
|
+
const setTimer = options.setTimer ?? ((callback, delayMs) => {
|
|
12867
|
+
const handle2 = setTimeout(callback, delayMs);
|
|
12868
|
+
handle2.unref?.();
|
|
12869
|
+
return handle2;
|
|
12870
|
+
});
|
|
12871
|
+
const clearTimer = options.clearTimer ?? ((handle2) => clearTimeout(handle2));
|
|
12872
|
+
const isTurnActive = options.isTurnActive ?? (() => true);
|
|
12873
|
+
let handle;
|
|
12874
|
+
let lastKickMs = now();
|
|
12875
|
+
let stopped = false;
|
|
12876
|
+
let fired = false;
|
|
12877
|
+
let wasActive = isTurnActive();
|
|
12878
|
+
const disarm = () => {
|
|
12879
|
+
if (handle !== void 0) {
|
|
12880
|
+
clearTimer(handle);
|
|
12881
|
+
handle = void 0;
|
|
12882
|
+
}
|
|
12883
|
+
};
|
|
12884
|
+
const onTimeout = () => {
|
|
12885
|
+
handle = void 0;
|
|
12886
|
+
if (stopped || fired) {
|
|
12887
|
+
return;
|
|
12888
|
+
}
|
|
12889
|
+
const active = isTurnActive();
|
|
12890
|
+
if (!active) {
|
|
12891
|
+
wasActive = false;
|
|
12892
|
+
arm();
|
|
12893
|
+
return;
|
|
12894
|
+
}
|
|
12895
|
+
if (!wasActive) {
|
|
12896
|
+
wasActive = true;
|
|
12897
|
+
lastKickMs = now();
|
|
12898
|
+
arm();
|
|
12899
|
+
return;
|
|
12900
|
+
}
|
|
12901
|
+
const silentMs = now() - lastKickMs;
|
|
12902
|
+
if (silentMs < options.thresholdMs) {
|
|
12903
|
+
arm();
|
|
12904
|
+
return;
|
|
12905
|
+
}
|
|
12906
|
+
fired = true;
|
|
12907
|
+
options.onStall({ silentMs });
|
|
12908
|
+
};
|
|
12909
|
+
function arm() {
|
|
12910
|
+
if (stopped || fired) {
|
|
12911
|
+
return;
|
|
12912
|
+
}
|
|
12913
|
+
disarm();
|
|
12914
|
+
const delay = isTurnActive() ? Math.max(0, options.thresholdMs - (now() - lastKickMs)) : options.thresholdMs;
|
|
12915
|
+
handle = setTimer(onTimeout, delay);
|
|
12916
|
+
}
|
|
12917
|
+
arm();
|
|
12918
|
+
return {
|
|
12919
|
+
kick: () => {
|
|
12920
|
+
if (stopped || fired) {
|
|
12921
|
+
return;
|
|
12922
|
+
}
|
|
12923
|
+
wasActive = true;
|
|
12924
|
+
lastKickMs = now();
|
|
12925
|
+
arm();
|
|
12926
|
+
},
|
|
12927
|
+
stop: () => {
|
|
12928
|
+
stopped = true;
|
|
12929
|
+
disarm();
|
|
12930
|
+
}
|
|
12931
|
+
};
|
|
12932
|
+
}
|
|
12933
|
+
var defaultClaudeCodeTurnStallThresholdMs;
|
|
12934
|
+
var init_claudeCodeTurnStallWatchdog = __esm({
|
|
12935
|
+
"src/claudeCodeTurnStallWatchdog.ts"() {
|
|
12936
|
+
"use strict";
|
|
12937
|
+
defaultClaudeCodeTurnStallThresholdMs = 10 * 6e4;
|
|
12938
|
+
}
|
|
12939
|
+
});
|
|
12940
|
+
|
|
12600
12941
|
// src/claudeCodeSession.ts
|
|
12601
12942
|
import { existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
|
|
12602
12943
|
import { homedir as homedir6 } from "node:os";
|
|
@@ -12864,8 +13205,49 @@ async function startClaudeCodeSession(options) {
|
|
|
12864
13205
|
lastCompletedTurnBody: void 0
|
|
12865
13206
|
};
|
|
12866
13207
|
const streamUsageTracker = createClaudeCodeStreamUsageTracker();
|
|
13208
|
+
let stallReason;
|
|
13209
|
+
let signalStall;
|
|
13210
|
+
const stallSignal = new Promise((resolve12) => {
|
|
13211
|
+
signalStall = resolve12;
|
|
13212
|
+
});
|
|
13213
|
+
const stallWatchdog = options.turnStallThresholdMs !== void 0 && options.turnStallThresholdMs > 0 ? createClaudeCodeTurnStallWatchdog({
|
|
13214
|
+
thresholdMs: options.turnStallThresholdMs,
|
|
13215
|
+
isTurnActive: options.turnStallIsActive,
|
|
13216
|
+
onStall: ({ silentMs }) => {
|
|
13217
|
+
stallReason = `Claude Code turn stalled: no SDK output for ${Math.round(
|
|
13218
|
+
silentMs / 1e3
|
|
13219
|
+
)}s (threshold ${Math.round(
|
|
13220
|
+
(options.turnStallThresholdMs ?? 0) / 1e3
|
|
13221
|
+
)}s)`;
|
|
13222
|
+
options.abortController?.abort();
|
|
13223
|
+
signalStall?.();
|
|
13224
|
+
}
|
|
13225
|
+
}) : void 0;
|
|
12867
13226
|
try {
|
|
12868
|
-
|
|
13227
|
+
const iterator = runner(options)[Symbol.asyncIterator]();
|
|
13228
|
+
for (; ; ) {
|
|
13229
|
+
let nextStep;
|
|
13230
|
+
if (stallWatchdog) {
|
|
13231
|
+
const nextPromise = iterator.next().then((result) => ({ kind: "next", result }));
|
|
13232
|
+
nextPromise.catch(() => void 0);
|
|
13233
|
+
const raced = await Promise.race([
|
|
13234
|
+
nextPromise,
|
|
13235
|
+
stallSignal.then(() => ({ kind: "stall" }))
|
|
13236
|
+
]);
|
|
13237
|
+
if (raced.kind === "stall") {
|
|
13238
|
+
void Promise.resolve(iterator.return?.()).catch(() => void 0);
|
|
13239
|
+
break;
|
|
13240
|
+
}
|
|
13241
|
+
nextStep = raced;
|
|
13242
|
+
} else {
|
|
13243
|
+
nextStep = { kind: "next", result: await iterator.next() };
|
|
13244
|
+
}
|
|
13245
|
+
const step = nextStep;
|
|
13246
|
+
if (step.result.done === true) {
|
|
13247
|
+
break;
|
|
13248
|
+
}
|
|
13249
|
+
const message = step.result.value;
|
|
13250
|
+
stallWatchdog?.kick();
|
|
12869
13251
|
state.sessionId = state.sessionId ?? extractClaudeSessionId(message);
|
|
12870
13252
|
const sessionId = extractClaudeSessionId(message) ?? state.sessionId;
|
|
12871
13253
|
if (sessionId !== void 0 && !state.startedSessionIds.has(sessionId)) {
|
|
@@ -12931,8 +13313,12 @@ async function startClaudeCodeSession(options) {
|
|
|
12931
13313
|
}
|
|
12932
13314
|
}
|
|
12933
13315
|
} finally {
|
|
13316
|
+
stallWatchdog?.stop();
|
|
12934
13317
|
options.streamingInput?.close();
|
|
12935
13318
|
}
|
|
13319
|
+
if (stallReason !== void 0) {
|
|
13320
|
+
return await failClaudeCodeSession(options, state.sessionId, stallReason);
|
|
13321
|
+
}
|
|
12936
13322
|
return completeClaudeCodeSession(options, state);
|
|
12937
13323
|
}
|
|
12938
13324
|
async function emitClaudeCodeTurnCompleted(options, state) {
|
|
@@ -13325,13 +13711,16 @@ function assistantTranscriptEvents(message, sessionId) {
|
|
|
13325
13711
|
contentBlockItemKey(block, index)
|
|
13326
13712
|
)
|
|
13327
13713
|
);
|
|
13328
|
-
const
|
|
13714
|
+
const hasTextContentBlock = content.some(
|
|
13715
|
+
(block) => stringValue(objectValue(block)?.type) === "text"
|
|
13716
|
+
);
|
|
13717
|
+
const directText = hasTextContentBlock ? void 0 : nonEmptyText(stringValue(message?.text));
|
|
13329
13718
|
return directText === void 0 ? contentEvents : [
|
|
13330
13719
|
...contentEvents,
|
|
13331
13720
|
{
|
|
13332
13721
|
type: "assistant_message",
|
|
13333
13722
|
sessionId,
|
|
13334
|
-
itemKey:
|
|
13723
|
+
itemKey: `content-block-${content.length}`,
|
|
13335
13724
|
content: directText,
|
|
13336
13725
|
streamState: "completed"
|
|
13337
13726
|
}
|
|
@@ -13352,7 +13741,7 @@ function userTranscriptEvents(message, sessionId) {
|
|
|
13352
13741
|
{
|
|
13353
13742
|
type: "tool_result",
|
|
13354
13743
|
sessionId,
|
|
13355
|
-
itemKey:
|
|
13744
|
+
itemKey: stringValue(value?.tool_use_id) ?? stringValue(value?.id) ?? `content-block-${index}`,
|
|
13356
13745
|
toolName: void 0,
|
|
13357
13746
|
content: visibleToolResultContent(value),
|
|
13358
13747
|
isError: value?.is_error === true
|
|
@@ -13438,12 +13827,14 @@ function unknownTranscriptEvent(message, sessionId) {
|
|
|
13438
13827
|
}
|
|
13439
13828
|
function streamItemKey(event, _message) {
|
|
13440
13829
|
const index = integerValue(event?.index);
|
|
13441
|
-
|
|
13442
|
-
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}`);
|
|
13830
|
+
return index === void 0 ? "assistant-stream" : `content-block-${index}`;
|
|
13443
13831
|
}
|
|
13444
13832
|
function contentBlockItemKey(block, index) {
|
|
13445
13833
|
const value = objectValue(block);
|
|
13446
|
-
|
|
13834
|
+
if (stringValue(value?.type) === "tool_use") {
|
|
13835
|
+
return stringValue(value?.id) ?? stringValue(value?.tool_use_id) ?? `content-block-${index}`;
|
|
13836
|
+
}
|
|
13837
|
+
return `content-block-${index}`;
|
|
13447
13838
|
}
|
|
13448
13839
|
function visibleToolResultContent(block) {
|
|
13449
13840
|
const content = block?.content;
|
|
@@ -13491,6 +13882,7 @@ var init_claudeCodeSession = __esm({
|
|
|
13491
13882
|
"use strict";
|
|
13492
13883
|
init_json();
|
|
13493
13884
|
init_claudeCodeLiveBashOutput();
|
|
13885
|
+
init_claudeCodeTurnStallWatchdog();
|
|
13494
13886
|
claudeRateLimitWindowLabels = {
|
|
13495
13887
|
five_hour: "5h window",
|
|
13496
13888
|
seven_day: "7d window",
|
|
@@ -14762,11 +15154,34 @@ var init_defaultUrls = __esm({
|
|
|
14762
15154
|
import { spawn as spawn3 } from "node:child_process";
|
|
14763
15155
|
import { randomBytes } from "node:crypto";
|
|
14764
15156
|
import { createServer as createServer2 } from "node:http";
|
|
15157
|
+
function oauthCallbackTimeoutMs(override, env = process.env) {
|
|
15158
|
+
if (typeof override === "number" && Number.isFinite(override) && override > 0) {
|
|
15159
|
+
return override;
|
|
15160
|
+
}
|
|
15161
|
+
const raw = env.LINZUMI_OAUTH_CALLBACK_TIMEOUT_MS?.trim();
|
|
15162
|
+
if (raw !== void 0 && raw !== "") {
|
|
15163
|
+
const parsed = Number.parseInt(raw, 10);
|
|
15164
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
15165
|
+
return parsed;
|
|
15166
|
+
}
|
|
15167
|
+
}
|
|
15168
|
+
return DEFAULT_OAUTH_CALLBACK_TIMEOUT_MS;
|
|
15169
|
+
}
|
|
14765
15170
|
async function acquireLocalRunnerTokenDetails(options) {
|
|
14766
15171
|
const httpBaseUrl = kandanHttpBaseUrl(options.kandanUrl);
|
|
14767
15172
|
const state = randomBytes(18).toString("base64url");
|
|
14768
15173
|
const callback = await startCallbackServer({
|
|
14769
|
-
host: oauthCallbackHost(options.kandanUrl, options.callbackHost)
|
|
15174
|
+
host: oauthCallbackHost(options.kandanUrl, options.callbackHost),
|
|
15175
|
+
exchange: async (result) => {
|
|
15176
|
+
if (result.state !== state) {
|
|
15177
|
+
throw new Error("local runner OAuth state mismatch");
|
|
15178
|
+
}
|
|
15179
|
+
return await exchangeCodeForToken({
|
|
15180
|
+
httpBaseUrl,
|
|
15181
|
+
code: result.code,
|
|
15182
|
+
redirectUri: result.redirectUri
|
|
15183
|
+
});
|
|
15184
|
+
}
|
|
14770
15185
|
});
|
|
14771
15186
|
const authorizeUrl = authorizationUrl({
|
|
14772
15187
|
httpBaseUrl,
|
|
@@ -14782,15 +15197,9 @@ ${authorizeUrl}
|
|
|
14782
15197
|
`);
|
|
14783
15198
|
try {
|
|
14784
15199
|
await (options.openAuthorizationUrl ?? openBrowser)(authorizeUrl);
|
|
14785
|
-
|
|
14786
|
-
|
|
14787
|
-
|
|
14788
|
-
}
|
|
14789
|
-
return await exchangeCodeForToken({
|
|
14790
|
-
httpBaseUrl,
|
|
14791
|
-
code: result.code,
|
|
14792
|
-
redirectUri: callback.redirectUri
|
|
14793
|
-
});
|
|
15200
|
+
return await callback.waitForToken(
|
|
15201
|
+
oauthCallbackTimeoutMs(options.waitForTokenTimeoutMs)
|
|
15202
|
+
);
|
|
14794
15203
|
} finally {
|
|
14795
15204
|
callback.close();
|
|
14796
15205
|
}
|
|
@@ -14970,49 +15379,83 @@ function stringBodyField(body, key) {
|
|
|
14970
15379
|
}
|
|
14971
15380
|
function startCallbackServer(args) {
|
|
14972
15381
|
return new Promise((resolve12, reject) => {
|
|
14973
|
-
let
|
|
14974
|
-
let
|
|
14975
|
-
|
|
14976
|
-
|
|
14977
|
-
|
|
15382
|
+
let resolveToken;
|
|
15383
|
+
let rejectToken;
|
|
15384
|
+
let settled = false;
|
|
15385
|
+
const tokenPromise = new Promise(
|
|
15386
|
+
(tokenResolve, tokenReject) => {
|
|
15387
|
+
resolveToken = tokenResolve;
|
|
15388
|
+
rejectToken = tokenReject;
|
|
15389
|
+
}
|
|
15390
|
+
);
|
|
15391
|
+
tokenPromise.catch(() => {
|
|
14978
15392
|
});
|
|
15393
|
+
const settle = (apply) => {
|
|
15394
|
+
if (settled) {
|
|
15395
|
+
return false;
|
|
15396
|
+
}
|
|
15397
|
+
settled = true;
|
|
15398
|
+
apply();
|
|
15399
|
+
return true;
|
|
15400
|
+
};
|
|
15401
|
+
let boundRedirectUri = `http://${args.host}/callback`;
|
|
14979
15402
|
const server = createServer2((request, response) => {
|
|
14980
|
-
|
|
14981
|
-
|
|
14982
|
-
|
|
14983
|
-
|
|
14984
|
-
|
|
14985
|
-
|
|
14986
|
-
|
|
15403
|
+
void (async () => {
|
|
15404
|
+
try {
|
|
15405
|
+
const url = new URL(request.url ?? "/", `http://${args.host}`);
|
|
15406
|
+
const code = url.searchParams.get("code");
|
|
15407
|
+
const state = url.searchParams.get("state");
|
|
15408
|
+
const error = url.searchParams.get("error");
|
|
15409
|
+
if (error !== null && error.trim() !== "") {
|
|
15410
|
+
settle(
|
|
15411
|
+
() => rejectToken?.(new Error(`local runner OAuth failed: ${error}`))
|
|
15412
|
+
);
|
|
15413
|
+
writeOauthResult(response, {
|
|
15414
|
+
title: "Not authorized",
|
|
15415
|
+
body: "You denied the request. Close this tab and rerun the bootstrap command when you're ready.",
|
|
15416
|
+
status: 403
|
|
15417
|
+
});
|
|
15418
|
+
return;
|
|
15419
|
+
}
|
|
15420
|
+
if (code === null || state === null || code.trim() === "" || state.trim() === "") {
|
|
15421
|
+
writeOauthResult(response, {
|
|
15422
|
+
title: "Authorization callback was incomplete",
|
|
15423
|
+
body: "We didn't receive the authorization code. Return to your terminal and try again.",
|
|
15424
|
+
status: 400
|
|
15425
|
+
});
|
|
15426
|
+
return;
|
|
15427
|
+
}
|
|
15428
|
+
let token;
|
|
15429
|
+
try {
|
|
15430
|
+
token = await args.exchange({
|
|
15431
|
+
code,
|
|
15432
|
+
state,
|
|
15433
|
+
redirectUri: boundRedirectUri
|
|
15434
|
+
});
|
|
15435
|
+
} catch (exchangeError) {
|
|
15436
|
+
settle(() => rejectToken?.(exchangeError));
|
|
15437
|
+
writeOauthResult(response, {
|
|
15438
|
+
title: "Authorization could not be completed",
|
|
15439
|
+
body: "We received the authorization but could not finish setup. Return to your terminal for details and rerun the bootstrap command.",
|
|
15440
|
+
status: 400
|
|
15441
|
+
});
|
|
15442
|
+
return;
|
|
15443
|
+
}
|
|
15444
|
+
const accepted = settle(() => resolveToken?.(token));
|
|
14987
15445
|
writeOauthResult(response, {
|
|
14988
|
-
title: "
|
|
14989
|
-
body: "
|
|
14990
|
-
status:
|
|
15446
|
+
title: accepted ? "Computer authorized" : "Already authorized",
|
|
15447
|
+
body: "This computer has been authorized for agentic use in Linzumi. Feel free to close this tab and let the terminal finish setup.",
|
|
15448
|
+
status: 200
|
|
14991
15449
|
});
|
|
14992
|
-
|
|
14993
|
-
|
|
14994
|
-
if (code === null || state === null || code.trim() === "" || state.trim() === "") {
|
|
15450
|
+
} catch (handlerError) {
|
|
15451
|
+
settle(() => rejectToken?.(handlerError));
|
|
14995
15452
|
writeOauthResult(response, {
|
|
14996
|
-
title: "Authorization callback
|
|
14997
|
-
body: "
|
|
14998
|
-
status:
|
|
15453
|
+
title: "Authorization callback failed",
|
|
15454
|
+
body: "Return to your terminal and rerun the bootstrap command.",
|
|
15455
|
+
status: 500
|
|
14999
15456
|
});
|
|
15000
|
-
return;
|
|
15001
15457
|
}
|
|
15002
|
-
|
|
15003
|
-
writeOauthResult(response, {
|
|
15004
|
-
title: "Computer authorized",
|
|
15005
|
-
body: "This computer has been authorized for agentic use in Linzumi. Feel free to close this tab and let the terminal finish setup.",
|
|
15006
|
-
status: 200
|
|
15007
|
-
});
|
|
15008
|
-
} catch (error) {
|
|
15009
|
-
rejectCallback?.(error);
|
|
15010
|
-
writeOauthResult(response, {
|
|
15011
|
-
title: "Authorization callback failed",
|
|
15012
|
-
body: "Return to your terminal and rerun the bootstrap command.",
|
|
15013
|
-
status: 500
|
|
15014
|
-
});
|
|
15015
|
-
}
|
|
15458
|
+
})();
|
|
15016
15459
|
});
|
|
15017
15460
|
server.once("error", reject);
|
|
15018
15461
|
server.listen(0, args.host, () => {
|
|
@@ -15025,9 +15468,34 @@ function startCallbackServer(args) {
|
|
|
15025
15468
|
);
|
|
15026
15469
|
return;
|
|
15027
15470
|
}
|
|
15471
|
+
boundRedirectUri = `http://${args.host}:${address.port}/callback`;
|
|
15028
15472
|
resolve12({
|
|
15029
|
-
redirectUri:
|
|
15030
|
-
|
|
15473
|
+
redirectUri: boundRedirectUri,
|
|
15474
|
+
// Bound the wait so that "only spurious/incomplete requests, no real
|
|
15475
|
+
// callback" can't hang forever. Incomplete requests deliberately never
|
|
15476
|
+
// settle the token promise (they only render the incomplete page), so
|
|
15477
|
+
// the overall timeout is what guarantees forward progress. The timer is
|
|
15478
|
+
// unref'd so it can't keep the process alive on its own, and it's
|
|
15479
|
+
// cleared once the token promise settles for any reason.
|
|
15480
|
+
waitForToken: (timeoutMs) => {
|
|
15481
|
+
const effectiveTimeoutMs = oauthCallbackTimeoutMs(timeoutMs);
|
|
15482
|
+
const timer = setTimeout(() => {
|
|
15483
|
+
settle(
|
|
15484
|
+
() => rejectToken?.(
|
|
15485
|
+
new Error(
|
|
15486
|
+
"Authorization timed out before the browser callback completed. Rerun the connect command and finish authorizing in the browser."
|
|
15487
|
+
)
|
|
15488
|
+
)
|
|
15489
|
+
);
|
|
15490
|
+
server.close();
|
|
15491
|
+
}, effectiveTimeoutMs);
|
|
15492
|
+
timer.unref?.();
|
|
15493
|
+
tokenPromise.finally(() => {
|
|
15494
|
+
clearTimeout(timer);
|
|
15495
|
+
}).catch(() => {
|
|
15496
|
+
});
|
|
15497
|
+
return tokenPromise;
|
|
15498
|
+
},
|
|
15031
15499
|
close: () => {
|
|
15032
15500
|
server.close();
|
|
15033
15501
|
}
|
|
@@ -15092,7 +15560,7 @@ function oauthResultHtml(args) {
|
|
|
15092
15560
|
place-items: center;
|
|
15093
15561
|
padding: 24px;
|
|
15094
15562
|
background:
|
|
15095
|
-
radial-gradient(1200px 600px at 50% -10%, var(--notice-soft), transparent 60%),
|
|
15563
|
+
radial-gradient(1200px 600px at 50% -10%, var(${success ? "--success-soft" : "--notice-soft"}), transparent 60%),
|
|
15096
15564
|
var(--page-bg);
|
|
15097
15565
|
color: var(--foreground);
|
|
15098
15566
|
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
@@ -15177,11 +15645,12 @@ function openBrowser(url) {
|
|
|
15177
15645
|
});
|
|
15178
15646
|
});
|
|
15179
15647
|
}
|
|
15180
|
-
var LINZUMI_LOGO_SVG;
|
|
15648
|
+
var DEFAULT_OAUTH_CALLBACK_TIMEOUT_MS, LINZUMI_LOGO_SVG;
|
|
15181
15649
|
var init_oauth = __esm({
|
|
15182
15650
|
"src/oauth.ts"() {
|
|
15183
15651
|
"use strict";
|
|
15184
15652
|
init_runnerLogger();
|
|
15653
|
+
DEFAULT_OAUTH_CALLBACK_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
15185
15654
|
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>';
|
|
15186
15655
|
}
|
|
15187
15656
|
});
|
|
@@ -18520,7 +18989,7 @@ var linzumiCliVersion, linzumiCliVersionText;
|
|
|
18520
18989
|
var init_version = __esm({
|
|
18521
18990
|
"src/version.ts"() {
|
|
18522
18991
|
"use strict";
|
|
18523
|
-
linzumiCliVersion = "0.0.
|
|
18992
|
+
linzumiCliVersion = "0.0.89-beta";
|
|
18524
18993
|
linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
|
|
18525
18994
|
}
|
|
18526
18995
|
});
|
|
@@ -20909,7 +21378,7 @@ function createLinzumiMcpApiClient(options) {
|
|
|
20909
21378
|
const baseUrl = kandanHttpBaseUrl(options.kandanUrl);
|
|
20910
21379
|
const apiPrefix = options.authMode === "personal-agent-delegation" ? "/api/v2/personal-agent-mcp" : "/api/v2/local-runner-mcp";
|
|
20911
21380
|
const operatingMode = options.operatingMode ?? "text";
|
|
20912
|
-
const request = async (method, path2, params) => {
|
|
21381
|
+
const request = async (method, path2, params, requestOptions = {}) => {
|
|
20913
21382
|
const url = new URL(path2, baseUrl);
|
|
20914
21383
|
const paramsWithMode = {
|
|
20915
21384
|
...params,
|
|
@@ -20917,7 +21386,11 @@ function createLinzumiMcpApiClient(options) {
|
|
|
20917
21386
|
};
|
|
20918
21387
|
const requestInit = {
|
|
20919
21388
|
method,
|
|
20920
|
-
headers: { authorization: `Bearer ${options.accessToken}` }
|
|
21389
|
+
headers: { authorization: `Bearer ${options.accessToken}` },
|
|
21390
|
+
// An aborted signal cancels the in-flight fetch so a caller that has
|
|
21391
|
+
// already given up (e.g. a timed-out goal seed) cannot land a LATE POST
|
|
21392
|
+
// and clobber state written after it gave up (#1864 finding 2).
|
|
21393
|
+
...requestOptions.signal === void 0 ? {} : { signal: requestOptions.signal }
|
|
20921
21394
|
};
|
|
20922
21395
|
if (method === "GET") {
|
|
20923
21396
|
for (const [key, value] of Object.entries(paramsWithMode)) {
|
|
@@ -20950,9 +21423,11 @@ function createLinzumiMcpApiClient(options) {
|
|
|
20950
21423
|
getMessage: (params) => request("GET", `${apiPrefix}/message`, params),
|
|
20951
21424
|
getThread: (params) => request("GET", `${apiPrefix}/thread`, params),
|
|
20952
21425
|
getChannel: (params) => request("GET", `${apiPrefix}/channel`, params),
|
|
21426
|
+
searchWorkspace: (params) => request("GET", `${apiPrefix}/search`, params),
|
|
21427
|
+
askWorkspace: (params) => request("POST", `${apiPrefix}/ask`, params),
|
|
20953
21428
|
getCodingJobMetadata: (params) => request("GET", `${apiPrefix}/coding-job-metadata`, params),
|
|
20954
21429
|
renameCodingJob: (params) => request("POST", `${apiPrefix}/coding-job-title`, params),
|
|
20955
|
-
upsertCodingJobPlan: (params) => request("POST", `${apiPrefix}/coding-job-plan`, params),
|
|
21430
|
+
upsertCodingJobPlan: (params, requestOptions) => request("POST", `${apiPrefix}/coding-job-plan`, params, requestOptions),
|
|
20956
21431
|
replaceCodingJobPlanSteps: (params) => request("POST", `${apiPrefix}/coding-job-plan/steps`, params),
|
|
20957
21432
|
updateCodingJobPlanStep: (params) => request("POST", `${apiPrefix}/coding-job-plan/step`, params),
|
|
20958
21433
|
linkCodingJobPullRequest: (params) => request("POST", `${apiPrefix}/coding-job-primary-pr`, params),
|
|
@@ -25877,167 +26352,6 @@ function truncateFailureDetail(message) {
|
|
|
25877
26352
|
}
|
|
25878
26353
|
return `${trimmed.slice(0, 237)}...`;
|
|
25879
26354
|
}
|
|
25880
|
-
function commanderDeveloperInstructions(args) {
|
|
25881
|
-
const agentLabel = args.agentLabel ?? "Codex";
|
|
25882
|
-
const planStepsInstruction = args.planTool === "todo-write" ? `For coding-job threads, start by setting the current goal with
|
|
25883
|
-
linzumi_upsert_coding_job_plan, then record the plan steps with the TodoWrite
|
|
25884
|
-
tool. Linzumi mirrors your TodoWrite list into the coding-job plan steps
|
|
25885
|
-
automatically, one TodoWrite item per plan step.` : `For coding-job threads, start by setting the current goal with
|
|
25886
|
-
linzumi_upsert_coding_job_plan, then replace the plan steps with
|
|
25887
|
-
linzumi_replace_coding_job_plan_steps.`;
|
|
25888
|
-
const planUpdateInstruction = args.planTool === "todo-write" ? `As work proceeds, update each step's status with TodoWrite. Do not call
|
|
25889
|
-
linzumi_replace_coding_job_plan_steps or linzumi_update_coding_job_plan_step
|
|
25890
|
-
directly; TodoWrite is the source of truth for the plan steps.` : `As work proceeds, update each step with linzumi_update_coding_job_plan_step.`;
|
|
25891
|
-
const customPrompt = args.developerPrompt === void 0 ? "" : `
|
|
25892
|
-
<invoker_developer_prompt>
|
|
25893
|
-
${args.developerPrompt}
|
|
25894
|
-
</invoker_developer_prompt>
|
|
25895
|
-
`;
|
|
25896
|
-
const linzumiContext = args.linzumiContext === void 0 ? "" : `
|
|
25897
|
-
${formatLinzumiConversationContextForPrompt(args.linzumiContext)}
|
|
25898
|
-
`;
|
|
25899
|
-
return `<context>
|
|
25900
|
-
You are a Linzumi ${agentLabel} session launched by the Linzumi Commander.
|
|
25901
|
-
The Commander is the local bridge process that connects this computer to the
|
|
25902
|
-
user's Linzumi workspace, secure preview tunnel, browser VS Code editor, and
|
|
25903
|
-
thread transcript. Your work and progress are relayed into that Linzumi thread.
|
|
25904
|
-
</context>
|
|
25905
|
-
|
|
25906
|
-
<term_definitions>
|
|
25907
|
-
Bootstrapper ${agentLabel}: The outer setup agent that claimed/signup, generated the
|
|
25908
|
-
demo folder when applicable, and asked Linzumi to start this session. It does
|
|
25909
|
-
not own implementation work.
|
|
25910
|
-
Linzumi Commander: The local long-running process that launched this ${agentLabel}
|
|
25911
|
-
session, enforces the trusted folder, and forwards descendant preview ports to
|
|
25912
|
-
Linzumi.
|
|
25913
|
-
Linzumi ${agentLabel} session: You, the inner ${agentLabel} process that performs the actual
|
|
25914
|
-
work in the approved project folder.
|
|
25915
|
-
Approved project folder: ${args.cwd}
|
|
25916
|
-
Coding-job metadata: User-visible goal, plan steps, step statuses, completion
|
|
25917
|
-
notes, primary pull request link, and worktree state shown in Linzumi's coding
|
|
25918
|
-
job overview.
|
|
25919
|
-
Plan step: A discrete chunk of work with a short title, one-line description,
|
|
25920
|
-
status, and completion note. It should describe an actual goal, not just a
|
|
25921
|
-
process verb.
|
|
25922
|
-
Primary pull request: The GitHub PR the job is currently driving or reviewing;
|
|
25923
|
-
Linzumi uses this link to hydrate PR comments, files, commits, checks, and
|
|
25924
|
-
deployments in the metadata overview.
|
|
25925
|
-
</term_definitions>
|
|
25926
|
-
|
|
25927
|
-
<linzumi_mcp>
|
|
25928
|
-
The Codex process is preconfigured with a Linzumi MCP server named "linzumi".
|
|
25929
|
-
Use it when you need authenticated context from the current Linzumi workspace:
|
|
25930
|
-
read a message by ID/URL, read a thread by ID, read the scoped channel, or send
|
|
25931
|
-
a concise DM to the Commander owner when the task genuinely requires it.
|
|
25932
|
-
</linzumi_mcp>
|
|
25933
|
-
|
|
25934
|
-
<task_instructions>
|
|
25935
|
-
Work only in the approved project folder unless the human explicitly asks for
|
|
25936
|
-
something else in the Linzumi thread. Start, inspect, and modify the local app
|
|
25937
|
-
from that folder. Report concise progress and exact blockers in the thread.
|
|
25938
|
-
Use the Linzumi MCP server named "linzumi" when you need authenticated
|
|
25939
|
-
workspace context or coding-job metadata tools.
|
|
25940
|
-
${planStepsInstruction}
|
|
25941
|
-
When the coding-job scope changes materially, call linzumi_rename_coding_job
|
|
25942
|
-
with a concise title so the Linzumi thread title and workflow-facing title
|
|
25943
|
-
match the work.
|
|
25944
|
-
${planUpdateInstruction}
|
|
25945
|
-
When you open, discover, or choose the primary pull request, link it with
|
|
25946
|
-
linzumi_link_coding_job_pull_request.
|
|
25947
|
-
Before stopping, confirm the metadata overview tells the truth for a user who
|
|
25948
|
-
only sees that overview: completed work is completed, active work is really
|
|
25949
|
-
active, blocked work says why, and no stale in-progress step is left behind.
|
|
25950
|
-
For frontend or other user-visible changes, ask whether the user wants
|
|
25951
|
-
screenshot or screen-recording proof, ideally before/after when that helps
|
|
25952
|
-
review the change. Screen recordings should be WebM or MP4.
|
|
25953
|
-
When the user asks you to open or update a PR, attach or link feasible proof in
|
|
25954
|
-
the PR and state the exact blocker when proof is not feasible.
|
|
25955
|
-
</task_instructions>
|
|
25956
|
-
|
|
25957
|
-
<rules>
|
|
25958
|
-
You MUST treat the Linzumi thread as the source of truth for user-facing
|
|
25959
|
-
progress.
|
|
25960
|
-
For coding-job threads, you MUST keep coding-job metadata current throughout
|
|
25961
|
-
the job.
|
|
25962
|
-
Plan steps MUST be fairly granular, discrete chunks of real work that a human
|
|
25963
|
-
can track.
|
|
25964
|
-
Plan step descriptions MUST stay short, usually one line and less than one full
|
|
25965
|
-
sentence.
|
|
25966
|
-
Plan steps MUST NOT be vague process-only labels such as "sync PR",
|
|
25967
|
-
"update PR", "verify PR", or "commit and merge" when those labels hide the
|
|
25968
|
-
concrete goal.
|
|
25969
|
-
You MUST update steps in sequence as work is completed. Do not mark a later
|
|
25970
|
-
step active while earlier applicable steps are still pending.
|
|
25971
|
-
Before you stop work, you MUST reconcile the plan so the job is not left with a
|
|
25972
|
-
stale active step. You may delegate metadata upkeep to a sub-agent when useful,
|
|
25973
|
-
but the visible job state must remain truthful.
|
|
25974
|
-
If the coding-job thread title is missing, undefined, or "Untitled", you MUST
|
|
25975
|
-
choose a concise, specific title for the job.
|
|
25976
|
-
User-visible UI, status, error, and PR-review copy MUST keep it short, direct,
|
|
25977
|
-
and focused on the user's outcome unless the user explicitly asks for
|
|
25978
|
-
implementation detail.
|
|
25979
|
-
You MUST keep user-visible preview servers bound to 0.0.0.0, not 127.0.0.1 or
|
|
25980
|
-
localhost, so the Linzumi secure tunnel can reach them.
|
|
25981
|
-
You MUST keep any preview or dev server as your descendant process so the
|
|
25982
|
-
Commander can discover and forward it.
|
|
25983
|
-
You MUST NOT ask the Bootstrapper ${agentLabel} to do implementation work.
|
|
25984
|
-
You MUST NOT inspect unrelated repositories or folders.
|
|
25985
|
-
You MUST report the exact blocker if a command, preview, editor, or tunnel step
|
|
25986
|
-
fails.
|
|
25987
|
-
When several Linzumi Codex sessions work in the same repository, create or use
|
|
25988
|
-
a separate checkout or git worktree for this task before making changes, unless
|
|
25989
|
-
the human explicitly asks you to share the current checkout. Do not overwrite or
|
|
25990
|
-
revert another session's work.
|
|
25991
|
-
</rules>
|
|
25992
|
-
|
|
25993
|
-
<examples>
|
|
25994
|
-
GOOD preview command: npm run dev -- --host 0.0.0.0 --port 8787
|
|
25995
|
-
Why good: The preview is reachable through the Linzumi secure tunnel.
|
|
25996
|
-
|
|
25997
|
-
BAD preview command: npm run dev -- --host 127.0.0.1
|
|
25998
|
-
Why bad: Binding to localhost prevents the Linzumi secure tunnel from reaching
|
|
25999
|
-
the preview.
|
|
26000
|
-
|
|
26001
|
-
GOOD coding-job plan:
|
|
26002
|
-
- Inspect prompt sources: Locate the prompt builder, prompt guide, and tests.
|
|
26003
|
-
- Add metadata guidance: Patch the prompt with plan, title, and stop-state rules.
|
|
26004
|
-
- Verify compiled prompt: Run focused tests and inspect the generated text.
|
|
26005
|
-
- Push PR update: Commit owned files, push the branch, and refresh PR metadata.
|
|
26006
|
-
Why good: Each step is a concrete chunk of work, the list is short enough to
|
|
26007
|
-
scan, and the titles explain what is actually happening.
|
|
26008
|
-
|
|
26009
|
-
BAD coding-job plan:
|
|
26010
|
-
- Sync PR
|
|
26011
|
-
- Update PR
|
|
26012
|
-
- Verify PR
|
|
26013
|
-
- Commit and merge
|
|
26014
|
-
Why bad: These labels describe process mechanics, not the concrete work or
|
|
26015
|
-
product goal. A user cannot tell what the agent has learned, changed, or still
|
|
26016
|
-
needs to do.
|
|
26017
|
-
|
|
26018
|
-
BAD coding-job metadata state:
|
|
26019
|
-
- Step 1 complete, Step 2 complete, Step 3 active, Step 4 pending.
|
|
26020
|
-
- The agent has stopped working and sent its final response.
|
|
26021
|
-
Why bad: The overview still says work is active even though the agent is idle.
|
|
26022
|
-
Before stopping, the agent should mark Step 3 completed, blocked, or canceled
|
|
26023
|
-
with a truthful note.
|
|
26024
|
-
</examples>
|
|
26025
|
-
${linzumiContext}
|
|
26026
|
-
${customPrompt}
|
|
26027
|
-
<task_reminder>
|
|
26028
|
-
You are the Commander-launched Linzumi ${agentLabel} session. Do the implementation
|
|
26029
|
-
work in the approved project folder, keep preview servers reachable through the
|
|
26030
|
-
secure tunnel, and keep the Linzumi thread and coding-job metadata truthful.
|
|
26031
|
-
</task_reminder>
|
|
26032
|
-
|
|
26033
|
-
<output_format>
|
|
26034
|
-
Use normal concise Linzumi thread messages for user-facing progress and final
|
|
26035
|
-
answers. When the task requires files, code, commits, pull requests, previews,
|
|
26036
|
-
or verification output, report the concrete artifact, command, result, and any
|
|
26037
|
-
exact blocker. Do not emit machine-only JSON unless the user or tool explicitly
|
|
26038
|
-
requests it.
|
|
26039
|
-
</output_format>`;
|
|
26040
|
-
}
|
|
26041
26355
|
function availableRunnerAgentProviders(options) {
|
|
26042
26356
|
switch (options.claudeCodeRunner !== void 0 || options.claudeCodeAvailable === true) {
|
|
26043
26357
|
case true:
|
|
@@ -26273,6 +26587,14 @@ async function startCodexProviderInstance(args) {
|
|
|
26273
26587
|
}
|
|
26274
26588
|
};
|
|
26275
26589
|
}
|
|
26590
|
+
function claudeCodeTurnStallThresholdMs(env) {
|
|
26591
|
+
const raw = env.LINZUMI_CLAUDE_TURN_STALL_MS?.trim();
|
|
26592
|
+
if (raw === void 0 || raw === "") {
|
|
26593
|
+
return defaultClaudeCodeTurnStallThresholdMs;
|
|
26594
|
+
}
|
|
26595
|
+
const parsed = Number.parseInt(raw, 10);
|
|
26596
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : defaultClaudeCodeTurnStallThresholdMs;
|
|
26597
|
+
}
|
|
26276
26598
|
function createClaudeCodeInputQueue(input) {
|
|
26277
26599
|
const pendingMessages = [
|
|
26278
26600
|
claudeCodeUserInputMessage(input.content)
|
|
@@ -26644,12 +26966,47 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
26644
26966
|
fetchImpl: args.options.fetch,
|
|
26645
26967
|
operatingMode: "text"
|
|
26646
26968
|
});
|
|
26969
|
+
const seededGoal = workDescription.trim().slice(0, 2e3);
|
|
26647
26970
|
const planMirror = createClaudeCodePlanMirror({
|
|
26648
26971
|
replacePlanSteps: planMirrorClient.replaceCodingJobPlanSteps,
|
|
26649
26972
|
threadId,
|
|
26650
|
-
goal:
|
|
26973
|
+
goal: seededGoal,
|
|
26651
26974
|
log: args.log
|
|
26652
26975
|
});
|
|
26976
|
+
const seedCodingJobGoalBeforeTurn = async () => {
|
|
26977
|
+
if (args.resumeSessionId !== void 0) {
|
|
26978
|
+
return;
|
|
26979
|
+
}
|
|
26980
|
+
const seedTimeoutMs = 5e3;
|
|
26981
|
+
const seedAbort = new AbortController();
|
|
26982
|
+
let timeoutHandle;
|
|
26983
|
+
const timedOut = new Promise((resolve12) => {
|
|
26984
|
+
timeoutHandle = setTimeout(() => {
|
|
26985
|
+
seedAbort.abort(new Error("claude goal seed timed out"));
|
|
26986
|
+
args.log("claude_code.goal_seed_timeout", {
|
|
26987
|
+
thread_id: threadId,
|
|
26988
|
+
timeout_ms: seedTimeoutMs
|
|
26989
|
+
});
|
|
26990
|
+
resolve12();
|
|
26991
|
+
}, seedTimeoutMs);
|
|
26992
|
+
});
|
|
26993
|
+
try {
|
|
26994
|
+
await Promise.race([
|
|
26995
|
+
seedClaudeCodingJobGoal({
|
|
26996
|
+
upsertCodingJobPlan: planMirrorClient.upsertCodingJobPlan,
|
|
26997
|
+
threadId,
|
|
26998
|
+
goal: seededGoal,
|
|
26999
|
+
log: args.log,
|
|
27000
|
+
signal: seedAbort.signal
|
|
27001
|
+
}),
|
|
27002
|
+
timedOut
|
|
27003
|
+
]);
|
|
27004
|
+
} finally {
|
|
27005
|
+
if (timeoutHandle !== void 0) {
|
|
27006
|
+
clearTimeout(timeoutHandle);
|
|
27007
|
+
}
|
|
27008
|
+
}
|
|
27009
|
+
};
|
|
26653
27010
|
const adapter = createClaudeCodeSessionPipeline({
|
|
26654
27011
|
instanceId: args.instanceId,
|
|
26655
27012
|
cwd: args.cwd,
|
|
@@ -26955,6 +27312,7 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
26955
27312
|
});
|
|
26956
27313
|
const runSession = async () => {
|
|
26957
27314
|
let result2;
|
|
27315
|
+
await seedCodingJobGoalBeforeTurn();
|
|
26958
27316
|
try {
|
|
26959
27317
|
try {
|
|
26960
27318
|
result2 = await startClaudeCodeSession({
|
|
@@ -26983,6 +27341,20 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
26983
27341
|
resumeSessionId: args.resumeSessionId,
|
|
26984
27342
|
abortController,
|
|
26985
27343
|
streamingInput: inputQueue,
|
|
27344
|
+
// PROD-RESILIENCE turn-stall watchdog (real-SDK sessions only; mock
|
|
27345
|
+
// runners drive their own timing). A turn that stays in flight with
|
|
27346
|
+
// no SDK output past the threshold is a wedged SILENT subprocess: the
|
|
27347
|
+
// watchdog aborts it and fails the turn so the thread reconnects,
|
|
27348
|
+
// instead of sitting "processing" forever (the ~28-min-hang incident).
|
|
27349
|
+
// The in-flight predicate (currentSourceSeq() is defined only while a
|
|
27350
|
+
// turn is queued/active) keeps a keep-alive session idling between
|
|
27351
|
+
// turns from being a false positive.
|
|
27352
|
+
...args.options.claudeCodeRunner === void 0 ? {
|
|
27353
|
+
turnStallThresholdMs: claudeCodeTurnStallThresholdMs(
|
|
27354
|
+
process.env
|
|
27355
|
+
),
|
|
27356
|
+
turnStallIsActive: () => inputQueue.currentSourceSeq() !== void 0
|
|
27357
|
+
} : {},
|
|
26986
27358
|
runner: args.options.claudeCodeRunner,
|
|
26987
27359
|
canUseTool,
|
|
26988
27360
|
...mcpServers === void 0 ? {} : { mcpServers },
|
|
@@ -29343,11 +29715,13 @@ var init_runner = __esm({
|
|
|
29343
29715
|
init_engineChildReaper();
|
|
29344
29716
|
init_claudeCodeLiveBashOutput();
|
|
29345
29717
|
init_claudeCodeSession();
|
|
29718
|
+
init_claudeCodeTurnStallWatchdog();
|
|
29346
29719
|
init_codexAppServer();
|
|
29347
29720
|
init_codexProjectTrust();
|
|
29348
29721
|
init_codexRuntimeOptions();
|
|
29349
29722
|
init_codexNotificationConsoleStats();
|
|
29350
29723
|
init_json();
|
|
29724
|
+
init_commanderDeveloperInstructions();
|
|
29351
29725
|
init_linzumiContext();
|
|
29352
29726
|
init_localCapabilities();
|
|
29353
29727
|
init_localConfig();
|
|
@@ -66096,6 +66470,60 @@ async function runMcpServer(args) {
|
|
|
66096
66470
|
},
|
|
66097
66471
|
async (params) => mcpJsonResult(await client.getChannel(params))
|
|
66098
66472
|
);
|
|
66473
|
+
server.tool(
|
|
66474
|
+
"linzumi_search_workspace",
|
|
66475
|
+
"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.",
|
|
66476
|
+
{
|
|
66477
|
+
workspace: external_exports2.string().optional().describe(
|
|
66478
|
+
"Workspace slug. Omit to use the authenticated token scope."
|
|
66479
|
+
),
|
|
66480
|
+
query: external_exports2.string().min(1).describe("Natural-language or keyword query to retrieve against."),
|
|
66481
|
+
limit: external_exports2.number().int().min(1).max(25).optional().describe("Maximum results to return (default 10, server-capped)."),
|
|
66482
|
+
source_types: external_exports2.array(
|
|
66483
|
+
external_exports2.enum([
|
|
66484
|
+
"message",
|
|
66485
|
+
"coding_job",
|
|
66486
|
+
"github_pr",
|
|
66487
|
+
"github_pr_review",
|
|
66488
|
+
"github_check_run",
|
|
66489
|
+
"github_workflow_run",
|
|
66490
|
+
"github_diff",
|
|
66491
|
+
"dictation",
|
|
66492
|
+
"file"
|
|
66493
|
+
])
|
|
66494
|
+
).optional().describe("Restrict results to these corpora; omit for all."),
|
|
66495
|
+
authored_after: external_exports2.string().optional().describe(
|
|
66496
|
+
"ISO8601 instant; only content authored at or after this time."
|
|
66497
|
+
),
|
|
66498
|
+
authored_before: external_exports2.string().optional().describe(
|
|
66499
|
+
"ISO8601 instant; only content authored at or before this time."
|
|
66500
|
+
),
|
|
66501
|
+
repo: external_exports2.string().optional().describe(
|
|
66502
|
+
"Restrict GitHub-sourced results to one repository by full name (owner/name)."
|
|
66503
|
+
),
|
|
66504
|
+
check_status: external_exports2.enum(["pending", "success", "failed"]).optional().describe(
|
|
66505
|
+
"Restrict check and workflow results to one conclusion bucket."
|
|
66506
|
+
)
|
|
66507
|
+
},
|
|
66508
|
+
async (params) => mcpJsonResult(await client.searchWorkspace(params))
|
|
66509
|
+
);
|
|
66510
|
+
server.tool(
|
|
66511
|
+
"linzumi_ask_workspace",
|
|
66512
|
+
'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.',
|
|
66513
|
+
{
|
|
66514
|
+
workspace: external_exports2.string().optional().describe(
|
|
66515
|
+
"Workspace slug. Omit to use the authenticated token scope."
|
|
66516
|
+
),
|
|
66517
|
+
question: external_exports2.string().min(1).max(2e3).describe("Natural-language question to answer with citations."),
|
|
66518
|
+
channel: external_exports2.string().optional().describe(
|
|
66519
|
+
"Optional channel slug providing conversational context; never widens access."
|
|
66520
|
+
),
|
|
66521
|
+
allow_cached: external_exports2.boolean().optional().describe(
|
|
66522
|
+
"Allow serving a cached synthesis when the evidence set is unchanged (default true). Set false to force fresh synthesis."
|
|
66523
|
+
)
|
|
66524
|
+
},
|
|
66525
|
+
async (params) => mcpJsonResult(await client.askWorkspace(params))
|
|
66526
|
+
);
|
|
66099
66527
|
server.tool(
|
|
66100
66528
|
"linzumi_get_coding_job_metadata",
|
|
66101
66529
|
"Read the active coding job workflow metadata for a thread, including the agent-owned goal, ordered plan steps, step lock versions, and workflow status.",
|
|
@@ -66913,6 +67341,7 @@ async function runRemoteCodexHarnessWorker(config, deps = {}) {
|
|
|
66913
67341
|
rootSeq: config.rootSeq,
|
|
66914
67342
|
startCodexThread: true,
|
|
66915
67343
|
linzumiContext: config.linzumiContext,
|
|
67344
|
+
developerPrompt: config.developerPrompt,
|
|
66916
67345
|
listenUser: config.listenUser,
|
|
66917
67346
|
model: config.model,
|
|
66918
67347
|
reasoningEffort: config.reasoningEffort,
|
|
@@ -67002,6 +67431,7 @@ function remoteCodexHarnessWorkerConfigFromJson(value) {
|
|
|
67002
67431
|
cwd: requiredString2(input, "cwd"),
|
|
67003
67432
|
workerCwd: requiredString2(input, "workerCwd"),
|
|
67004
67433
|
workDescription: requiredString2(input, "workDescription"),
|
|
67434
|
+
...optionalStringField(input, "developerPrompt"),
|
|
67005
67435
|
readyToken: requiredString2(input, "readyToken"),
|
|
67006
67436
|
codexBin: requiredString2(input, "codexBin"),
|
|
67007
67437
|
execServerUrl: requiredString2(input, "execServerUrl"),
|
package/package.json
CHANGED