@linzumi/cli 0.0.45-beta → 0.0.47-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 +67 -38
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -937,6 +937,44 @@ function fuseQueuedMessages(selected) {
|
|
|
937
937
|
};
|
|
938
938
|
}
|
|
939
939
|
|
|
940
|
+
// src/linzumiContext.ts
|
|
941
|
+
function parseLinzumiConversationContext(value, warn = console.warn) {
|
|
942
|
+
if (value === undefined) {
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
const context = objectValue(value);
|
|
946
|
+
if (context === undefined) {
|
|
947
|
+
return invalidLinzumiContext("linzumiContext must be an object", warn);
|
|
948
|
+
}
|
|
949
|
+
const threadId = stringValue(context.threadId);
|
|
950
|
+
const creatorUserId = stringValue(context.creatorUserId) ?? integerValue(context.creatorUserId)?.toString();
|
|
951
|
+
const creatorUsername = stringValue(context.creatorUsername);
|
|
952
|
+
const conversationUrl = stringValue(context.conversationUrl);
|
|
953
|
+
if (threadId === undefined || creatorUserId === undefined || creatorUsername === undefined || conversationUrl === undefined) {
|
|
954
|
+
return invalidLinzumiContext("linzumiContext must include threadId, creatorUserId, creatorUsername, and conversationUrl", warn);
|
|
955
|
+
}
|
|
956
|
+
return { threadId, creatorUserId, creatorUsername, conversationUrl };
|
|
957
|
+
}
|
|
958
|
+
function formatLinzumiConversationContextForPrompt(context) {
|
|
959
|
+
return `<linzumi_context>
|
|
960
|
+
<linzumi_thread_id>${escapeXmlText(context.threadId)}</linzumi_thread_id>
|
|
961
|
+
<linzumi_creator_user_id>${escapeXmlText(context.creatorUserId)}</linzumi_creator_user_id>
|
|
962
|
+
<linzumi_creator_username>${escapeXmlText(context.creatorUsername)}</linzumi_creator_username>
|
|
963
|
+
<linzumi_conversation_url>${escapeXmlText(context.conversationUrl)}</linzumi_conversation_url>
|
|
964
|
+
</linzumi_context>
|
|
965
|
+
|
|
966
|
+
<linzumi_pr_footer_instruction>
|
|
967
|
+
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})
|
|
968
|
+
</linzumi_pr_footer_instruction>`;
|
|
969
|
+
}
|
|
970
|
+
function invalidLinzumiContext(reason, warn) {
|
|
971
|
+
warn(`Ignoring invalid linzumiContext: ${reason}`);
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
function escapeXmlText(value) {
|
|
975
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
976
|
+
}
|
|
977
|
+
|
|
940
978
|
// src/reconnectContext.ts
|
|
941
979
|
var recentVerbatimMessageCount = 5;
|
|
942
980
|
var reconnectContextModel = "openai/gpt-oss-120b";
|
|
@@ -975,7 +1013,7 @@ function filterReconnectContextMessages(messages) {
|
|
|
975
1013
|
return true;
|
|
976
1014
|
});
|
|
977
1015
|
}
|
|
978
|
-
async function buildReconnectContextInjection(messages, summarizer = createConfiguredReconnectContextSummarizer()) {
|
|
1016
|
+
async function buildReconnectContextInjection(messages, summarizer = createConfiguredReconnectContextSummarizer(), linzumiContext) {
|
|
979
1017
|
const filtered = filterReconnectContextMessages(messages);
|
|
980
1018
|
if (filtered.length === 0) {
|
|
981
1019
|
throw new Error("durable Linzumi thread history did not include user-visible context");
|
|
@@ -988,6 +1026,7 @@ async function buildReconnectContextInjection(messages, summarizer = createConfi
|
|
|
988
1026
|
"",
|
|
989
1027
|
"The local Codex app-server thread was restarted, so this durable Linzumi thread history is being injected before retrying the latest user message.",
|
|
990
1028
|
"",
|
|
1029
|
+
...linzumiContext === undefined ? [] : [formatLinzumiConversationContextForPrompt(linzumiContext), ""],
|
|
991
1030
|
...summary === undefined ? [] : ["Summary of earlier messages:", summary, ""],
|
|
992
1031
|
"Last five user-visible messages verbatim:",
|
|
993
1032
|
recent.map(formatReconnectContextMessage).join(`
|
|
@@ -1488,7 +1527,6 @@ var defaultIntervalMs = 2000;
|
|
|
1488
1527
|
var defaultDebounceMs = 750;
|
|
1489
1528
|
function startPortForwardWatcher(options) {
|
|
1490
1529
|
const rootPid = options.rootPid ?? process.pid;
|
|
1491
|
-
const rootCwd = normalizeCwd(options.rootCwd);
|
|
1492
1530
|
const intervalMs = options.intervalMs ?? defaultIntervalMs;
|
|
1493
1531
|
const debounceMs = options.debounceMs ?? defaultDebounceMs;
|
|
1494
1532
|
const lostDebounceMs = options.lostDebounceMs ?? intervalMs * 2 + debounceMs;
|
|
@@ -1508,8 +1546,8 @@ function startPortForwardWatcher(options) {
|
|
|
1508
1546
|
Promise.resolve().then(async () => {
|
|
1509
1547
|
const descendants = descendantPidSet(scanProcesses(), rootPid);
|
|
1510
1548
|
const sockets = scanListenSockets();
|
|
1511
|
-
const candidatePids =
|
|
1512
|
-
const candidates = detectedForwardCandidates(sockets, descendants, scanProcessCwds(candidatePids)
|
|
1549
|
+
const candidatePids = sockets.filter((socket) => descendants.has(socket.pid)).map((socket) => socket.pid);
|
|
1550
|
+
const candidates = detectedForwardCandidates(sockets, descendants, scanProcessCwds(candidatePids));
|
|
1513
1551
|
const scanTimeMs = nowMs();
|
|
1514
1552
|
const stable = stableForwardCandidates(candidateStabilityByPort, candidates, scanTimeMs, debounceMs);
|
|
1515
1553
|
const changes = debouncedForwardCandidateChanges(emittedByPort, missingByPort, stable.stableCandidates, scanTimeMs, lostDebounceMs);
|
|
@@ -1613,17 +1651,8 @@ function descendantPidSet(rows, rootPid) {
|
|
|
1613
1651
|
}
|
|
1614
1652
|
return descendants;
|
|
1615
1653
|
}
|
|
1616
|
-
function detectedForwardCandidates(sockets, descendantPids, processCwds = new Map
|
|
1617
|
-
|
|
1618
|
-
return sockets.filter((socket) => {
|
|
1619
|
-
if (descendantPids.has(socket.pid)) {
|
|
1620
|
-
return true;
|
|
1621
|
-
}
|
|
1622
|
-
if (rootCwd === undefined) {
|
|
1623
|
-
return false;
|
|
1624
|
-
}
|
|
1625
|
-
return cwdMatchesRoot(processCwds.get(socket.pid), rootCwd);
|
|
1626
|
-
}).filter((socket) => socket.port > 0 && socket.port < 65536).sort((left, right) => left.port - right.port).map((socket) => {
|
|
1654
|
+
function detectedForwardCandidates(sockets, descendantPids, processCwds = new Map) {
|
|
1655
|
+
return sockets.filter((socket) => descendantPids.has(socket.pid)).filter((socket) => socket.port > 0 && socket.port < 65536).sort((left, right) => left.port - right.port).map((socket) => {
|
|
1627
1656
|
const cwd = processCwds.get(socket.pid);
|
|
1628
1657
|
return {
|
|
1629
1658
|
port: socket.port,
|
|
@@ -1633,20 +1662,6 @@ function detectedForwardCandidates(sockets, descendantPids, processCwds = new Ma
|
|
|
1633
1662
|
};
|
|
1634
1663
|
});
|
|
1635
1664
|
}
|
|
1636
|
-
function normalizeCwd(cwd) {
|
|
1637
|
-
if (cwd === undefined) {
|
|
1638
|
-
return;
|
|
1639
|
-
}
|
|
1640
|
-
const normalized = cwd.trim().replace(/\/+$/, "");
|
|
1641
|
-
return normalized === "" ? undefined : normalized;
|
|
1642
|
-
}
|
|
1643
|
-
function cwdMatchesRoot(candidateCwd, rootCwd) {
|
|
1644
|
-
const normalizedCandidate = normalizeCwd(candidateCwd);
|
|
1645
|
-
if (normalizedCandidate === undefined) {
|
|
1646
|
-
return false;
|
|
1647
|
-
}
|
|
1648
|
-
return normalizedCandidate === rootCwd || normalizedCandidate.startsWith(`${rootCwd}/`);
|
|
1649
|
-
}
|
|
1650
1665
|
function parseProcessRows(output) {
|
|
1651
1666
|
return output.split(`
|
|
1652
1667
|
`).map((line) => line.trim()).filter((line) => line !== "").map((line) => {
|
|
@@ -2679,6 +2694,7 @@ function initialChannelSessionState(cursor, rootSeq, kandanThreadId, codexThread
|
|
|
2679
2694
|
portForwardWatcher: undefined,
|
|
2680
2695
|
activeProcessingState: undefined,
|
|
2681
2696
|
pendingReconnectContextInjection: undefined,
|
|
2697
|
+
linzumiContext: parseLinzumiConversationContext(options.channelSession.linzumiContext),
|
|
2682
2698
|
terminalInputForwardChain: Promise.resolve(),
|
|
2683
2699
|
webSearchProgressForwardChain: Promise.resolve(),
|
|
2684
2700
|
typingHeartbeat: undefined,
|
|
@@ -2716,7 +2732,6 @@ function startPortForwardWatchIfEnabled(args, state, payloadContext) {
|
|
|
2716
2732
|
state.approvedForwardPorts.add(port);
|
|
2717
2733
|
}
|
|
2718
2734
|
state.portForwardWatcher = start({
|
|
2719
|
-
rootCwd: watchOptions.rootCwd ?? args.options.cwd,
|
|
2720
2735
|
...watchOptions,
|
|
2721
2736
|
onCandidate: (candidate) => publishPortForwardPrompt(args, state, payloadContext, candidate),
|
|
2722
2737
|
onCandidateLost: (candidate) => handleLostPortForwardCandidate(args, state, payloadContext, candidate),
|
|
@@ -3711,7 +3726,7 @@ async function fetchReconnectContextInjection(args, state) {
|
|
|
3711
3726
|
});
|
|
3712
3727
|
const messages = parseReconnectContextMessages(reply.messages);
|
|
3713
3728
|
const summarizer = args.options.reconnectContextSummarizer ?? createConfiguredReconnectContextSummarizer();
|
|
3714
|
-
const injection = await buildReconnectContextInjection(messages, summarizer);
|
|
3729
|
+
const injection = await buildReconnectContextInjection(messages, summarizer, state.linzumiContext);
|
|
3715
3730
|
args.log("codex.thread_reconnect_context_prepared", {
|
|
3716
3731
|
codex_thread_id: state.codexThreadId ?? null,
|
|
3717
3732
|
kandan_thread_id: state.kandanThreadId,
|
|
@@ -5085,7 +5100,7 @@ async function downloadQueuedKandanAttachments(args, message) {
|
|
|
5085
5100
|
}
|
|
5086
5101
|
const fileName = safeAttachmentFileName(attachment.fileName ?? attachment.id ?? `attachment-${index + 1}`, index);
|
|
5087
5102
|
const localPath = join(directory, fileName);
|
|
5088
|
-
const response = await fetch(resolveKandanAttachmentUrl(args.options.kandanUrl, url), {
|
|
5103
|
+
const response = await (args.options.fetch ?? globalThis.fetch)(resolveKandanAttachmentUrl(args.options.kandanUrl, url), {
|
|
5089
5104
|
headers: {
|
|
5090
5105
|
authorization: `Bearer ${args.options.token}`
|
|
5091
5106
|
}
|
|
@@ -5203,7 +5218,7 @@ async function uploadedFileIdsForCodexOutput(args, body, structured) {
|
|
|
5203
5218
|
}
|
|
5204
5219
|
const bytes = await readFile(file.path);
|
|
5205
5220
|
const uploadBody = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
5206
|
-
const response = await fetch(resolveKandanAttachmentUrl(args.options.kandanUrl, uploadUrl), {
|
|
5221
|
+
const response = await (args.options.fetch ?? globalThis.fetch)(resolveKandanAttachmentUrl(args.options.kandanUrl, uploadUrl), {
|
|
5207
5222
|
method: uploadMethod,
|
|
5208
5223
|
headers: { "content-type": file.contentType },
|
|
5209
5224
|
body: uploadBody
|
|
@@ -6890,7 +6905,7 @@ function installDirectory(sourceDir, destinationDir) {
|
|
|
6890
6905
|
mkdirSync3(dirname2(destinationDir), { recursive: true });
|
|
6891
6906
|
cpSync(sourceDir, destinationDir, { recursive: true });
|
|
6892
6907
|
}
|
|
6893
|
-
function codeServerEnv(env, cwd,
|
|
6908
|
+
function codeServerEnv(env, cwd, userDataDir, collaboration) {
|
|
6894
6909
|
const { PORT: _port, ...hostEnv } = env;
|
|
6895
6910
|
const base = {
|
|
6896
6911
|
...hostEnv,
|
|
@@ -6904,7 +6919,8 @@ function codeServerEnv(env, cwd, _userDataDir, collaboration) {
|
|
|
6904
6919
|
KANDAN_EDITOR_COLLABORATION_DEPLOYMENT_SHAPE: "local_runner_sidecar",
|
|
6905
6920
|
KANDAN_EDITOR_COLLABORATION_ENTRY_MODE: "kandan_auto_host_or_join",
|
|
6906
6921
|
KANDAN_EDITOR_COLLABORATION_ROOM_ID: collaboration.roomId,
|
|
6907
|
-
KANDAN_EDITOR_COLLABORATION_SERVER_URL: collaboration.bootstrapServerUrl
|
|
6922
|
+
KANDAN_EDITOR_COLLABORATION_SERVER_URL: collaboration.bootstrapServerUrl,
|
|
6923
|
+
KANDAN_EDITOR_COLLABORATION_AUTO_HOST_CLAIM_PATH: join4(userDataDir, "kandan-oct-auto-host.lock")
|
|
6908
6924
|
};
|
|
6909
6925
|
}
|
|
6910
6926
|
function collaborationEvent(collaboration) {
|
|
@@ -8484,7 +8500,7 @@ function realpathOrResolved(pathValue) {
|
|
|
8484
8500
|
}
|
|
8485
8501
|
|
|
8486
8502
|
// src/version.ts
|
|
8487
|
-
var linzumiCliVersion = "0.0.
|
|
8503
|
+
var linzumiCliVersion = "0.0.47-beta";
|
|
8488
8504
|
var linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
|
|
8489
8505
|
|
|
8490
8506
|
// src/runnerLock.ts
|
|
@@ -8975,11 +8991,14 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
8975
8991
|
cleanup.actions.push(() => kandan.close());
|
|
8976
8992
|
const topic = `local_runner:${options.runnerId}`;
|
|
8977
8993
|
const clientId = options.machineId ?? options.runnerId;
|
|
8994
|
+
const runnerHost = hostname2();
|
|
8978
8995
|
const joinPayload = () => ({
|
|
8979
8996
|
clientName: "kandan-local-codex-runner",
|
|
8980
8997
|
clientId,
|
|
8981
8998
|
runnerPid: process.pid,
|
|
8982
8999
|
version: linzumiCliVersion,
|
|
9000
|
+
hostname: runnerHost,
|
|
9001
|
+
cwd: options.cwd,
|
|
8983
9002
|
workspace: runnerWorkspaceSlug(options) ?? null,
|
|
8984
9003
|
channel: options.channelSession?.channelSlug ?? null,
|
|
8985
9004
|
capabilities: capabilitiesPayload()
|
|
@@ -9248,7 +9267,6 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
9248
9267
|
const seq = { value: 0 };
|
|
9249
9268
|
const codexThreads = options.channelSession === undefined ? await discoverCodexThreads(codex, options.cwd) : [];
|
|
9250
9269
|
const discoveredCodexThreads = { value: codexThreads };
|
|
9251
|
-
const runnerHost = hostname2();
|
|
9252
9270
|
const runtimeDefaults = runnerRuntimeDefaults(options);
|
|
9253
9271
|
const instancePayload = {
|
|
9254
9272
|
instanceId,
|
|
@@ -9280,10 +9298,12 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
9280
9298
|
topic,
|
|
9281
9299
|
instanceId,
|
|
9282
9300
|
options: {
|
|
9301
|
+
kandanUrl: options.kandanUrl,
|
|
9283
9302
|
token: options.token,
|
|
9284
9303
|
runnerId: options.runnerId,
|
|
9285
9304
|
cwd: options.cwd,
|
|
9286
9305
|
codexBin: options.codexBin,
|
|
9306
|
+
fetch: options.fetch,
|
|
9287
9307
|
fast: options.fast,
|
|
9288
9308
|
launchTui: options.launchTui,
|
|
9289
9309
|
enablePortForwardWatch: true,
|
|
@@ -9335,10 +9355,12 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
9335
9355
|
topic,
|
|
9336
9356
|
instanceId,
|
|
9337
9357
|
options: {
|
|
9358
|
+
kandanUrl: options.kandanUrl,
|
|
9338
9359
|
token: options.token,
|
|
9339
9360
|
runnerId: options.runnerId,
|
|
9340
9361
|
cwd,
|
|
9341
9362
|
codexBin: options.codexBin,
|
|
9363
|
+
fetch: options.fetch,
|
|
9342
9364
|
fast: control.fast ?? options.fast,
|
|
9343
9365
|
launchTui: false,
|
|
9344
9366
|
enablePortForwardWatch: true,
|
|
@@ -9360,6 +9382,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
9360
9382
|
kandanThreadId,
|
|
9361
9383
|
rootSeq: integerValue(control.rootSeq),
|
|
9362
9384
|
codexThreadId,
|
|
9385
|
+
linzumiContext: control.linzumiContext,
|
|
9363
9386
|
listenUser,
|
|
9364
9387
|
model: runtimeSettings.model,
|
|
9365
9388
|
reasoningEffort: runtimeSettings.reasoningEffort,
|
|
@@ -9868,6 +9891,7 @@ async function applyControl(codex, kandan, topic, instanceId, options, allowedCw
|
|
|
9868
9891
|
}
|
|
9869
9892
|
startupStage = "starting_codex_session";
|
|
9870
9893
|
const developerPrompt = normalizedWorkDescription(control.developerPrompt);
|
|
9894
|
+
const linzumiContext = parseLinzumiConversationContext(control.linzumiContext);
|
|
9871
9895
|
const runtimeSettings = startInstanceRuntimeSettings(options, control);
|
|
9872
9896
|
const response = await codex.request("thread/start", {
|
|
9873
9897
|
cwd: cwd.cwd,
|
|
@@ -9875,7 +9899,8 @@ async function applyControl(codex, kandan, topic, instanceId, options, allowedCw
|
|
|
9875
9899
|
personality: "pragmatic",
|
|
9876
9900
|
developerInstructions: commanderDeveloperInstructions({
|
|
9877
9901
|
cwd: cwd.cwd,
|
|
9878
|
-
developerPrompt
|
|
9902
|
+
developerPrompt,
|
|
9903
|
+
linzumiContext
|
|
9879
9904
|
}),
|
|
9880
9905
|
...runtimeSettings.model === undefined ? {} : { model: runtimeSettings.model },
|
|
9881
9906
|
...runtimeSettings.reasoningEffort === undefined ? {} : { reasoningEffort: runtimeSettings.reasoningEffort },
|
|
@@ -10067,6 +10092,9 @@ function commanderDeveloperInstructions(args) {
|
|
|
10067
10092
|
<invoker_developer_prompt>
|
|
10068
10093
|
${args.developerPrompt}
|
|
10069
10094
|
</invoker_developer_prompt>
|
|
10095
|
+
`;
|
|
10096
|
+
const linzumiContext = args.linzumiContext === undefined ? "" : `
|
|
10097
|
+
${formatLinzumiConversationContextForPrompt(args.linzumiContext)}
|
|
10070
10098
|
`;
|
|
10071
10099
|
return `<context>
|
|
10072
10100
|
You are a Linzumi Codex session launched by the Linzumi Commander.
|
|
@@ -10110,6 +10138,7 @@ fails.
|
|
|
10110
10138
|
GOOD preview command: npm run dev -- --host 0.0.0.0 --port 8787
|
|
10111
10139
|
BAD preview command: npm run dev -- --host 127.0.0.1
|
|
10112
10140
|
</examples>
|
|
10141
|
+
${linzumiContext}
|
|
10113
10142
|
${customPrompt}
|
|
10114
10143
|
<task_reminder>
|
|
10115
10144
|
You are the Commander-launched Linzumi Codex session. Do the implementation
|
package/package.json
CHANGED