@linzumi/cli 0.0.88-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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +371 -265
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -58,7 +58,7 @@ Install the CLI or run it with `npx`:
58
58
  ```bash
59
59
  npm install -g @linzumi/cli@latest
60
60
  npx -y @linzumi/cli@latest signup
61
- npx -y @linzumi/cli@0.0.88-beta --version
61
+ npx -y @linzumi/cli@0.0.89-beta --version
62
62
  linzumi --version
63
63
  ```
64
64
 
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("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
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("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
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();
@@ -14961,11 +15154,34 @@ var init_defaultUrls = __esm({
14961
15154
  import { spawn as spawn3 } from "node:child_process";
14962
15155
  import { randomBytes } from "node:crypto";
14963
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
+ }
14964
15170
  async function acquireLocalRunnerTokenDetails(options) {
14965
15171
  const httpBaseUrl = kandanHttpBaseUrl(options.kandanUrl);
14966
15172
  const state = randomBytes(18).toString("base64url");
14967
15173
  const callback = await startCallbackServer({
14968
- 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
+ }
14969
15185
  });
14970
15186
  const authorizeUrl = authorizationUrl({
14971
15187
  httpBaseUrl,
@@ -14981,15 +15197,9 @@ ${authorizeUrl}
14981
15197
  `);
14982
15198
  try {
14983
15199
  await (options.openAuthorizationUrl ?? openBrowser)(authorizeUrl);
14984
- const result = await callback.waitForCallback();
14985
- if (result.state !== state) {
14986
- throw new Error("local runner OAuth state mismatch");
14987
- }
14988
- return await exchangeCodeForToken({
14989
- httpBaseUrl,
14990
- code: result.code,
14991
- redirectUri: callback.redirectUri
14992
- });
15200
+ return await callback.waitForToken(
15201
+ oauthCallbackTimeoutMs(options.waitForTokenTimeoutMs)
15202
+ );
14993
15203
  } finally {
14994
15204
  callback.close();
14995
15205
  }
@@ -15169,49 +15379,83 @@ function stringBodyField(body, key) {
15169
15379
  }
15170
15380
  function startCallbackServer(args) {
15171
15381
  return new Promise((resolve12, reject) => {
15172
- let resolveCallback;
15173
- let rejectCallback;
15174
- const callbackPromise = new Promise((callbackResolve, callbackReject) => {
15175
- resolveCallback = callbackResolve;
15176
- rejectCallback = callbackReject;
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(() => {
15177
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`;
15178
15402
  const server = createServer2((request, response) => {
15179
- try {
15180
- const url = new URL(request.url ?? "/", `http://${args.host}`);
15181
- const code = url.searchParams.get("code");
15182
- const state = url.searchParams.get("state");
15183
- const error = url.searchParams.get("error");
15184
- if (error !== null && error.trim() !== "") {
15185
- rejectCallback?.(new Error(`local runner OAuth failed: ${error}`));
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));
15186
15445
  writeOauthResult(response, {
15187
- title: "Not authorized",
15188
- body: "You denied the request. Close this tab and rerun the bootstrap command when you're ready.",
15189
- status: 403
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
15190
15449
  });
15191
- return;
15192
- }
15193
- if (code === null || state === null || code.trim() === "" || state.trim() === "") {
15450
+ } catch (handlerError) {
15451
+ settle(() => rejectToken?.(handlerError));
15194
15452
  writeOauthResult(response, {
15195
- title: "Authorization callback was incomplete",
15196
- body: "We didn't receive the authorization code. Return to your terminal and try again.",
15197
- status: 400
15453
+ title: "Authorization callback failed",
15454
+ body: "Return to your terminal and rerun the bootstrap command.",
15455
+ status: 500
15198
15456
  });
15199
- return;
15200
15457
  }
15201
- resolveCallback?.({ code, state });
15202
- writeOauthResult(response, {
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.",
15205
- status: 200
15206
- });
15207
- } catch (error) {
15208
- rejectCallback?.(error);
15209
- writeOauthResult(response, {
15210
- title: "Authorization callback failed",
15211
- body: "Return to your terminal and rerun the bootstrap command.",
15212
- status: 500
15213
- });
15214
- }
15458
+ })();
15215
15459
  });
15216
15460
  server.once("error", reject);
15217
15461
  server.listen(0, args.host, () => {
@@ -15224,9 +15468,34 @@ function startCallbackServer(args) {
15224
15468
  );
15225
15469
  return;
15226
15470
  }
15471
+ boundRedirectUri = `http://${args.host}:${address.port}/callback`;
15227
15472
  resolve12({
15228
- redirectUri: `http://${args.host}:${address.port}/callback`,
15229
- waitForCallback: () => callbackPromise,
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
+ },
15230
15499
  close: () => {
15231
15500
  server.close();
15232
15501
  }
@@ -15291,7 +15560,7 @@ function oauthResultHtml(args) {
15291
15560
  place-items: center;
15292
15561
  padding: 24px;
15293
15562
  background:
15294
- 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%),
15295
15564
  var(--page-bg);
15296
15565
  color: var(--foreground);
15297
15566
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
@@ -15376,11 +15645,12 @@ function openBrowser(url) {
15376
15645
  });
15377
15646
  });
15378
15647
  }
15379
- var LINZUMI_LOGO_SVG;
15648
+ var DEFAULT_OAUTH_CALLBACK_TIMEOUT_MS, LINZUMI_LOGO_SVG;
15380
15649
  var init_oauth = __esm({
15381
15650
  "src/oauth.ts"() {
15382
15651
  "use strict";
15383
15652
  init_runnerLogger();
15653
+ DEFAULT_OAUTH_CALLBACK_TIMEOUT_MS = 5 * 60 * 1e3;
15384
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>';
15385
15655
  }
15386
15656
  });
@@ -18719,7 +18989,7 @@ var linzumiCliVersion, linzumiCliVersionText;
18719
18989
  var init_version = __esm({
18720
18990
  "src/version.ts"() {
18721
18991
  "use strict";
18722
- linzumiCliVersion = "0.0.88-beta";
18992
+ linzumiCliVersion = "0.0.89-beta";
18723
18993
  linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
18724
18994
  }
18725
18995
  });
@@ -26082,173 +26352,6 @@ function truncateFailureDetail(message) {
26082
26352
  }
26083
26353
  return `${trimmed.slice(0, 237)}...`;
26084
26354
  }
26085
- function commanderDeveloperInstructions(args) {
26086
- const agentLabel = args.agentLabel ?? "Codex";
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.`;
26099
- const planUpdateInstruction = args.planTool === "todo-write" ? `As work proceeds, update each step's status with TodoWrite. Do not call
26100
- linzumi_replace_coding_job_plan_steps or linzumi_update_coding_job_plan_step
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.`;
26102
- const customPrompt = args.developerPrompt === void 0 ? "" : `
26103
- <invoker_developer_prompt>
26104
- ${args.developerPrompt}
26105
- </invoker_developer_prompt>
26106
- `;
26107
- const linzumiContext = args.linzumiContext === void 0 ? "" : `
26108
- ${formatLinzumiConversationContextForPrompt(args.linzumiContext)}
26109
- `;
26110
- return `<context>
26111
- You are a Linzumi ${agentLabel} session launched by the Linzumi Commander.
26112
- The Commander is the local bridge process that connects this computer to the
26113
- user's Linzumi workspace, secure preview tunnel, browser VS Code editor, and
26114
- thread transcript. Your work and progress are relayed into that Linzumi thread.
26115
- </context>
26116
-
26117
- <term_definitions>
26118
- Bootstrapper ${agentLabel}: The outer setup agent that claimed/signup, generated the
26119
- demo folder when applicable, and asked Linzumi to start this session. It does
26120
- not own implementation work.
26121
- Linzumi Commander: The local long-running process that launched this ${agentLabel}
26122
- session, enforces the trusted folder, and forwards descendant preview ports to
26123
- Linzumi.
26124
- Linzumi ${agentLabel} session: You, the inner ${agentLabel} process that performs the actual
26125
- work in the approved project folder.
26126
- Approved project folder: ${args.cwd}
26127
- Coding-job metadata: User-visible goal, plan steps, step statuses, completion
26128
- notes, primary pull request link, and worktree state shown in Linzumi's coding
26129
- job overview.
26130
- Plan step: A discrete chunk of work with a short title, one-line description,
26131
- status, and completion note. It should describe an actual goal, not just a
26132
- process verb.
26133
- Primary pull request: The GitHub PR the job is currently driving or reviewing;
26134
- Linzumi uses this link to hydrate PR comments, files, commits, checks, and
26135
- deployments in the metadata overview.
26136
- </term_definitions>
26137
-
26138
- <linzumi_mcp>
26139
- The Codex process is preconfigured with a Linzumi MCP server named "linzumi".
26140
- Use it when you need authenticated context from the current Linzumi workspace:
26141
- read a message by ID/URL, read a thread by ID, read the scoped channel, or send
26142
- a concise DM to the Commander owner when the task genuinely requires it.
26143
- </linzumi_mcp>
26144
-
26145
- <task_instructions>
26146
- Work only in the approved project folder unless the human explicitly asks for
26147
- something else in the Linzumi thread. Start, inspect, and modify the local app
26148
- from that folder. Report concise progress and exact blockers in the thread.
26149
- Use the Linzumi MCP server named "linzumi" when you need authenticated
26150
- workspace context or coding-job metadata tools.
26151
- ${planStepsInstruction}
26152
- When the coding-job scope changes materially, call linzumi_rename_coding_job
26153
- with a concise title so the Linzumi thread title and workflow-facing title
26154
- match the work.
26155
- ${planUpdateInstruction}
26156
- When you open, discover, or choose the primary pull request, link it with
26157
- linzumi_link_coding_job_pull_request.
26158
- Before stopping, confirm the metadata overview tells the truth for a user who
26159
- only sees that overview: completed work is completed, active work is really
26160
- active, blocked work says why, and no stale in-progress step is left behind.
26161
- For frontend or other user-visible changes, ask whether the user wants
26162
- screenshot or screen-recording proof, ideally before/after when that helps
26163
- review the change. Screen recordings should be WebM or MP4.
26164
- When the user asks you to open or update a PR, attach or link feasible proof in
26165
- the PR and state the exact blocker when proof is not feasible.
26166
- </task_instructions>
26167
-
26168
- <rules>
26169
- You MUST treat the Linzumi thread as the source of truth for user-facing
26170
- progress.
26171
- For coding-job threads, you MUST keep coding-job metadata current throughout
26172
- the job.
26173
- Plan steps MUST be fairly granular, discrete chunks of real work that a human
26174
- can track.
26175
- Plan step descriptions MUST stay short, usually one line and less than one full
26176
- sentence.
26177
- Plan steps MUST NOT be vague process-only labels such as "sync PR",
26178
- "update PR", "verify PR", or "commit and merge" when those labels hide the
26179
- concrete goal.
26180
- You MUST update steps in sequence as work is completed. Do not mark a later
26181
- step active while earlier applicable steps are still pending.
26182
- Before you stop work, you MUST reconcile the plan so the job is not left with a
26183
- stale active step. You may delegate metadata upkeep to a sub-agent when useful,
26184
- but the visible job state must remain truthful.
26185
- If the coding-job thread title is missing, undefined, or "Untitled", you MUST
26186
- choose a concise, specific title for the job.
26187
- User-visible UI, status, error, and PR-review copy MUST keep it short, direct,
26188
- and focused on the user's outcome unless the user explicitly asks for
26189
- implementation detail.
26190
- You MUST keep user-visible preview servers bound to 0.0.0.0, not 127.0.0.1 or
26191
- localhost, so the Linzumi secure tunnel can reach them.
26192
- You MUST keep any preview or dev server as your descendant process so the
26193
- Commander can discover and forward it.
26194
- You MUST NOT ask the Bootstrapper ${agentLabel} to do implementation work.
26195
- You MUST NOT inspect unrelated repositories or folders.
26196
- You MUST report the exact blocker if a command, preview, editor, or tunnel step
26197
- fails.
26198
- When several Linzumi Codex sessions work in the same repository, create or use
26199
- a separate checkout or git worktree for this task before making changes, unless
26200
- the human explicitly asks you to share the current checkout. Do not overwrite or
26201
- revert another session's work.
26202
- </rules>
26203
-
26204
- <examples>
26205
- GOOD preview command: npm run dev -- --host 0.0.0.0 --port 8787
26206
- Why good: The preview is reachable through the Linzumi secure tunnel.
26207
-
26208
- BAD preview command: npm run dev -- --host 127.0.0.1
26209
- Why bad: Binding to localhost prevents the Linzumi secure tunnel from reaching
26210
- the preview.
26211
-
26212
- GOOD coding-job plan:
26213
- - Inspect prompt sources: Locate the prompt builder, prompt guide, and tests.
26214
- - Add metadata guidance: Patch the prompt with plan, title, and stop-state rules.
26215
- - Verify compiled prompt: Run focused tests and inspect the generated text.
26216
- - Push PR update: Commit owned files, push the branch, and refresh PR metadata.
26217
- Why good: Each step is a concrete chunk of work, the list is short enough to
26218
- scan, and the titles explain what is actually happening.
26219
-
26220
- BAD coding-job plan:
26221
- - Sync PR
26222
- - Update PR
26223
- - Verify PR
26224
- - Commit and merge
26225
- Why bad: These labels describe process mechanics, not the concrete work or
26226
- product goal. A user cannot tell what the agent has learned, changed, or still
26227
- needs to do.
26228
-
26229
- BAD coding-job metadata state:
26230
- - Step 1 complete, Step 2 complete, Step 3 active, Step 4 pending.
26231
- - The agent has stopped working and sent its final response.
26232
- Why bad: The overview still says work is active even though the agent is idle.
26233
- Before stopping, the agent should mark Step 3 completed, blocked, or canceled
26234
- with a truthful note.
26235
- </examples>
26236
- ${linzumiContext}
26237
- ${customPrompt}
26238
- <task_reminder>
26239
- You are the Commander-launched Linzumi ${agentLabel} session. Do the implementation
26240
- work in the approved project folder, keep preview servers reachable through the
26241
- secure tunnel, and keep the Linzumi thread and coding-job metadata truthful.
26242
- </task_reminder>
26243
-
26244
- <output_format>
26245
- Use normal concise Linzumi thread messages for user-facing progress and final
26246
- answers. When the task requires files, code, commits, pull requests, previews,
26247
- or verification output, report the concrete artifact, command, result, and any
26248
- exact blocker. Do not emit machine-only JSON unless the user or tool explicitly
26249
- requests it.
26250
- </output_format>`;
26251
- }
26252
26355
  function availableRunnerAgentProviders(options) {
26253
26356
  switch (options.claudeCodeRunner !== void 0 || options.claudeCodeAvailable === true) {
26254
26357
  case true:
@@ -29618,6 +29721,7 @@ var init_runner = __esm({
29618
29721
  init_codexRuntimeOptions();
29619
29722
  init_codexNotificationConsoleStats();
29620
29723
  init_json();
29724
+ init_commanderDeveloperInstructions();
29621
29725
  init_linzumiContext();
29622
29726
  init_localCapabilities();
29623
29727
  init_localConfig();
@@ -67237,6 +67341,7 @@ async function runRemoteCodexHarnessWorker(config, deps = {}) {
67237
67341
  rootSeq: config.rootSeq,
67238
67342
  startCodexThread: true,
67239
67343
  linzumiContext: config.linzumiContext,
67344
+ developerPrompt: config.developerPrompt,
67240
67345
  listenUser: config.listenUser,
67241
67346
  model: config.model,
67242
67347
  reasoningEffort: config.reasoningEffort,
@@ -67326,6 +67431,7 @@ function remoteCodexHarnessWorkerConfigFromJson(value) {
67326
67431
  cwd: requiredString2(input, "cwd"),
67327
67432
  workerCwd: requiredString2(input, "workerCwd"),
67328
67433
  workDescription: requiredString2(input, "workDescription"),
67434
+ ...optionalStringField(input, "developerPrompt"),
67329
67435
  readyToken: requiredString2(input, "readyToken"),
67330
67436
  codexBin: requiredString2(input, "codexBin"),
67331
67437
  execServerUrl: requiredString2(input, "execServerUrl"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linzumi/cli",
3
- "version": "0.0.88-beta",
3
+ "version": "0.0.89-beta",
4
4
  "description": "Linzumi CLI — point a Codex agent at the real code on your laptop, with your team watching and steering from shared threads.",
5
5
  "type": "module",
6
6
  "bin": {