opencode-zellij 0.0.15 → 0.0.16
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/dist/index.mjs +77 -35
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -663,6 +663,28 @@ function findTabName(value, tabId) {
|
|
|
663
663
|
if (found !== void 0) return found;
|
|
664
664
|
}
|
|
665
665
|
}
|
|
666
|
+
function activeTabNameProperty(object) {
|
|
667
|
+
if (object.active !== true || object.is_plugin === true) return void 0;
|
|
668
|
+
const name = stringProperty$2(object, ["name", "title"]);
|
|
669
|
+
return typeof name === "string" ? name : void 0;
|
|
670
|
+
}
|
|
671
|
+
function findActiveTabName(value) {
|
|
672
|
+
if (Array.isArray(value)) {
|
|
673
|
+
for (const item of value) {
|
|
674
|
+
const found = findActiveTabName(item);
|
|
675
|
+
if (found !== void 0) return found;
|
|
676
|
+
}
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
680
|
+
const object = value;
|
|
681
|
+
const name = activeTabNameProperty(object);
|
|
682
|
+
if (name !== void 0) return name;
|
|
683
|
+
for (const nested of Object.values(object)) {
|
|
684
|
+
const found = findActiveTabName(nested);
|
|
685
|
+
if (found !== void 0) return found;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
666
688
|
function parseTabName(listTabsJson, tabId) {
|
|
667
689
|
try {
|
|
668
690
|
return findTabName(JSON.parse(listTabsJson), tabId);
|
|
@@ -671,6 +693,14 @@ function parseTabName(listTabsJson, tabId) {
|
|
|
671
693
|
return;
|
|
672
694
|
}
|
|
673
695
|
}
|
|
696
|
+
function parseActiveTabName(listTabsJson) {
|
|
697
|
+
try {
|
|
698
|
+
return findActiveTabName(JSON.parse(listTabsJson));
|
|
699
|
+
} catch (error) {
|
|
700
|
+
debug("parseActiveTabName failed", errorMessage(error));
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
674
704
|
//#endregion
|
|
675
705
|
//#region src/zellij/cli.ts
|
|
676
706
|
const execFileAsync$1 = promisify(execFile);
|
|
@@ -738,25 +768,28 @@ async function runZellij(actionArgs, options = {}) {
|
|
|
738
768
|
}
|
|
739
769
|
}
|
|
740
770
|
var ZellijCli = class {
|
|
771
|
+
constructor(run = runZellij) {
|
|
772
|
+
this.run = run;
|
|
773
|
+
}
|
|
741
774
|
async newPane(options) {
|
|
742
|
-
return parsePaneId((await
|
|
775
|
+
return parsePaneId((await this.run(buildNewPaneActionArgs(options))).stdout);
|
|
743
776
|
}
|
|
744
777
|
async writeChars(paneId, data) {
|
|
745
|
-
await
|
|
778
|
+
await this.run(zellijActionArgs("write-chars", [
|
|
746
779
|
"--pane-id",
|
|
747
780
|
paneId,
|
|
748
781
|
data
|
|
749
782
|
]));
|
|
750
783
|
}
|
|
751
784
|
async sendCtrlC(paneId) {
|
|
752
|
-
await
|
|
785
|
+
await this.run(zellijActionArgs("send-keys", [
|
|
753
786
|
"--pane-id",
|
|
754
787
|
paneId,
|
|
755
788
|
"Ctrl c"
|
|
756
789
|
]));
|
|
757
790
|
}
|
|
758
791
|
async closePane(paneId) {
|
|
759
|
-
await
|
|
792
|
+
await this.run(zellijActionArgs("close-pane", ["--pane-id", paneId]));
|
|
760
793
|
}
|
|
761
794
|
closePaneSync(paneId) {
|
|
762
795
|
ensureZellijTarget();
|
|
@@ -767,10 +800,10 @@ var ZellijCli = class {
|
|
|
767
800
|
});
|
|
768
801
|
}
|
|
769
802
|
async focusPane(paneId) {
|
|
770
|
-
await
|
|
803
|
+
await this.run(zellijActionArgs("focus-pane-id", [paneId]));
|
|
771
804
|
}
|
|
772
805
|
async dumpScreen(paneId) {
|
|
773
|
-
return (await
|
|
806
|
+
return (await this.run(zellijActionArgs("dump-screen", [
|
|
774
807
|
"--pane-id",
|
|
775
808
|
paneId,
|
|
776
809
|
"--full"
|
|
@@ -779,21 +812,24 @@ var ZellijCli = class {
|
|
|
779
812
|
async currentPaneTabId() {
|
|
780
813
|
const paneId = process.env.ZELLIJ_PANE_ID;
|
|
781
814
|
if (!paneId) return void 0;
|
|
782
|
-
return parseCurrentPaneTabId((await
|
|
815
|
+
return parseCurrentPaneTabId((await this.run(zellijActionArgs("list-panes", ["--json"]), { timeoutMs: 5e3 })).stdout, paneId);
|
|
783
816
|
}
|
|
784
817
|
async paneExists(paneId) {
|
|
785
|
-
return parsePaneExists((await
|
|
818
|
+
return parsePaneExists((await this.run(zellijActionArgs("list-panes", ["--json"]), { timeoutMs: 5e3 })).stdout, paneId);
|
|
786
819
|
}
|
|
787
820
|
async renameTab(title) {
|
|
788
821
|
const tabId = await this.currentPaneTabId();
|
|
789
822
|
if (tabId === void 0 && process.env.ZELLIJ) throw new Error(`Could not resolve Zellij tab id for pane ${process.env.ZELLIJ_PANE_ID ?? "<missing>"}`);
|
|
790
|
-
await
|
|
823
|
+
await this.run(tabId === void 0 ? buildRenameTabActionArgs(title) : buildRenameTabActionArgs(title, { tabId }));
|
|
791
824
|
}
|
|
792
825
|
async currentTabTitle() {
|
|
793
|
-
if (!process.env.ZELLIJ_PANE_ID)
|
|
826
|
+
if (!process.env.ZELLIJ_PANE_ID) {
|
|
827
|
+
if (!process.env.ZELLIJ_SESSION_NAME?.trim()) return void 0;
|
|
828
|
+
return parseActiveTabName((await this.run(zellijActionArgs("list-tabs", ["--json"]), { timeoutMs: 5e3 })).stdout);
|
|
829
|
+
}
|
|
794
830
|
const tabId = await this.currentPaneTabId();
|
|
795
831
|
if (tabId === void 0) return void 0;
|
|
796
|
-
return parseTabName((await
|
|
832
|
+
return parseTabName((await this.run(zellijActionArgs("list-tabs", ["--json"]), { timeoutMs: 5e3 })).stdout, tabId);
|
|
797
833
|
}
|
|
798
834
|
};
|
|
799
835
|
const zellijCli = new ZellijCli();
|
|
@@ -1038,13 +1074,20 @@ function createExitCodeToken() {
|
|
|
1038
1074
|
return randomUUID().replaceAll("-", "");
|
|
1039
1075
|
}
|
|
1040
1076
|
function parseExitCodeMarker(line) {
|
|
1041
|
-
const match = line.replace(ansiPattern, "").trim().match(markerPattern);
|
|
1077
|
+
const match = line.replace(ansiPattern, "").replace(/\r?\n/g, "").trim().match(markerPattern);
|
|
1042
1078
|
if (!match?.[1] || !match[2]) return null;
|
|
1043
1079
|
return {
|
|
1044
1080
|
token: match[1],
|
|
1045
1081
|
exitCode: Number(match[2])
|
|
1046
1082
|
};
|
|
1047
1083
|
}
|
|
1084
|
+
function parseExitCodeMarkerLines(lines, maxWindowLines = 8) {
|
|
1085
|
+
for (let start = 0; start < lines.length; start += 1) for (let size = 1; size <= maxWindowLines && start + size <= lines.length; size += 1) {
|
|
1086
|
+
const marker = parseExitCodeMarker(lines.slice(start, start + size).join("\n"));
|
|
1087
|
+
if (marker) return marker;
|
|
1088
|
+
}
|
|
1089
|
+
return null;
|
|
1090
|
+
}
|
|
1048
1091
|
//#endregion
|
|
1049
1092
|
//#region src/zellij/subscribe.ts
|
|
1050
1093
|
const maxStderrLines = 200;
|
|
@@ -1107,9 +1150,9 @@ var SubscriberManager = class {
|
|
|
1107
1150
|
this.sessions = sessions;
|
|
1108
1151
|
this.maxBufferLines = maxBufferLines;
|
|
1109
1152
|
this.spawnProcess = dependencies.spawn ?? spawn;
|
|
1110
|
-
this.dumpScreen = dependencies.dumpScreen ?? zellijCli.dumpScreen;
|
|
1111
|
-
this.paneExists = dependencies.paneExists ?? zellijCli.paneExists;
|
|
1112
|
-
this.closePane = dependencies.closePane ?? zellijCli.closePane;
|
|
1153
|
+
this.dumpScreen = dependencies.dumpScreen ?? ((paneId) => zellijCli.dumpScreen(paneId));
|
|
1154
|
+
this.paneExists = dependencies.paneExists ?? ((paneId) => zellijCli.paneExists(paneId));
|
|
1155
|
+
this.closePane = dependencies.closePane ?? ((paneId) => zellijCli.closePane(paneId));
|
|
1113
1156
|
this.lifecycleHooks = dependencies.lifecycleHooks;
|
|
1114
1157
|
this.terminalTailLines = dependencies.terminalTailLines ?? 200;
|
|
1115
1158
|
}
|
|
@@ -1268,12 +1311,9 @@ var SubscriberManager = class {
|
|
|
1268
1311
|
captureExitCode(sessionId, lines) {
|
|
1269
1312
|
const session = this.sessions.get(sessionId);
|
|
1270
1313
|
if (!session.exitCodeToken) return;
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
this.markSessionTerminal(sessionId, "exit_marker", { exitCode: marker.exitCode });
|
|
1275
|
-
return;
|
|
1276
|
-
}
|
|
1314
|
+
const marker = parseExitCodeMarkerLines(lines);
|
|
1315
|
+
if (!marker || marker.token !== session.exitCodeToken) return;
|
|
1316
|
+
this.markSessionTerminal(sessionId, "exit_marker", { exitCode: marker.exitCode });
|
|
1277
1317
|
}
|
|
1278
1318
|
handleStderr(sessionId, child, chunk) {
|
|
1279
1319
|
const state = this.subscribers.get(sessionId);
|
|
@@ -1538,7 +1578,7 @@ async function executeZellijPtyRead(args, dependencies = {}) {
|
|
|
1538
1578
|
const nextAdviceApi = dependencies.nextAdvice ?? nextAdvice;
|
|
1539
1579
|
const readOutputSnapshotApi = dependencies.readOutputSnapshot ?? readOutputSnapshot;
|
|
1540
1580
|
const validateGrepApi = dependencies.validateGrep ?? validateGrep;
|
|
1541
|
-
const paneExistsApi = dependencies.paneExists ?? zellijCli.paneExists;
|
|
1581
|
+
const paneExistsApi = dependencies.paneExists ?? ((paneId) => zellijCli.paneExists(paneId));
|
|
1542
1582
|
const session = sessionManagerApi.get(args.id);
|
|
1543
1583
|
const grepError = validateGrepApi(args.grep);
|
|
1544
1584
|
if (grepError) return {
|
|
@@ -1714,13 +1754,6 @@ const requestSudoTool = tool({
|
|
|
1714
1754
|
floating: true,
|
|
1715
1755
|
exitCodeToken
|
|
1716
1756
|
});
|
|
1717
|
-
const warnings = [];
|
|
1718
|
-
try {
|
|
1719
|
-
await zellijCli.focusPane(paneId);
|
|
1720
|
-
} catch (error) {
|
|
1721
|
-
if (!(error instanceof Error ? error.message : String(error)).includes("already focused")) throw error;
|
|
1722
|
-
warnings.push("Pane was already focused after creation.");
|
|
1723
|
-
}
|
|
1724
1757
|
const session = sessionManager.create({
|
|
1725
1758
|
openCodeSessionId: context.sessionID,
|
|
1726
1759
|
paneId,
|
|
@@ -1738,7 +1771,7 @@ const requestSudoTool = tool({
|
|
|
1738
1771
|
session: publicSession(session),
|
|
1739
1772
|
output: readOutputSnapshot(session.id),
|
|
1740
1773
|
next: nextAdvice(false, "The user must review the summary and commands in Zellij, then type YES and any required credentials directly in the pane."),
|
|
1741
|
-
warnings
|
|
1774
|
+
warnings: []
|
|
1742
1775
|
});
|
|
1743
1776
|
}
|
|
1744
1777
|
});
|
|
@@ -1987,6 +2020,9 @@ function parseSessionStatus(value) {
|
|
|
1987
2020
|
const completionTitle = "Zellij PTY session completed";
|
|
1988
2021
|
const completionMessage = "A Zellij PTY session completed. Review the finished pane if needed.";
|
|
1989
2022
|
const queuedNoticeHeader = "[OpenCode] Zellij PTY completion notice";
|
|
2023
|
+
function supportsActivePrompt(mode) {
|
|
2024
|
+
return mode === "prompt" || mode === "queue+toast";
|
|
2025
|
+
}
|
|
1990
2026
|
function buildQueuedCompletionNotice(events) {
|
|
1991
2027
|
return [queuedNoticeHeader, ...events.map((event) => `- ${event.session.id} (${event.session.paneId}) 已完成,請使用 zellij_pty_read 讀取最終輸出並清理 pane。`)].join("\n");
|
|
1992
2028
|
}
|
|
@@ -2028,7 +2064,7 @@ function injectQueuedCompletionNotice(input, notice) {
|
|
|
2028
2064
|
};
|
|
2029
2065
|
}
|
|
2030
2066
|
function evaluateCompletionPromptDecision(input) {
|
|
2031
|
-
if (input.config.mode
|
|
2067
|
+
if (!supportsActivePrompt(input.config.mode)) return {
|
|
2032
2068
|
shouldPrompt: false,
|
|
2033
2069
|
shouldQueue: false,
|
|
2034
2070
|
reason: "prompt mode disabled"
|
|
@@ -2113,6 +2149,7 @@ var SessionCompletionNotificationQueue = class {
|
|
|
2113
2149
|
const state = {
|
|
2114
2150
|
event,
|
|
2115
2151
|
queued: false,
|
|
2152
|
+
sent: false,
|
|
2116
2153
|
toastSent: false,
|
|
2117
2154
|
promptAttempts: 0,
|
|
2118
2155
|
promptAttemptedAt: null
|
|
@@ -2127,7 +2164,7 @@ var SessionCompletionNotificationQueue = class {
|
|
|
2127
2164
|
this.finalize(state);
|
|
2128
2165
|
return;
|
|
2129
2166
|
case "queue+toast":
|
|
2130
|
-
state
|
|
2167
|
+
await this.tryPromptOrQueue(state);
|
|
2131
2168
|
await this.sendToast(state);
|
|
2132
2169
|
return;
|
|
2133
2170
|
case "prompt":
|
|
@@ -2141,7 +2178,7 @@ var SessionCompletionNotificationQueue = class {
|
|
|
2141
2178
|
if (pending.length === 0) return input;
|
|
2142
2179
|
const notice = buildQueuedCompletionNotice(pending.map((state) => state.event));
|
|
2143
2180
|
for (const state of pending) {
|
|
2144
|
-
|
|
2181
|
+
this.markStateSent(state);
|
|
2145
2182
|
this.finalize(state);
|
|
2146
2183
|
}
|
|
2147
2184
|
return injectQueuedCompletionNotice(input, notice);
|
|
@@ -2187,7 +2224,7 @@ var SessionCompletionNotificationQueue = class {
|
|
|
2187
2224
|
state.queued = true;
|
|
2188
2225
|
return;
|
|
2189
2226
|
}
|
|
2190
|
-
this.
|
|
2227
|
+
this.markStateSent(state);
|
|
2191
2228
|
this.finalize(state);
|
|
2192
2229
|
} catch (error) {
|
|
2193
2230
|
debug("completion notification prompt failed", errorMessage(error));
|
|
@@ -2208,12 +2245,17 @@ var SessionCompletionNotificationQueue = class {
|
|
|
2208
2245
|
duration: 1e4
|
|
2209
2246
|
} });
|
|
2210
2247
|
state.toastSent = true;
|
|
2211
|
-
this.
|
|
2248
|
+
this.markStateSent(state);
|
|
2212
2249
|
if (!state.queued) this.finalize(state);
|
|
2213
2250
|
} catch (error) {
|
|
2214
2251
|
debug("completion notification toast failed", errorMessage(error));
|
|
2215
2252
|
}
|
|
2216
2253
|
}
|
|
2254
|
+
markStateSent(state) {
|
|
2255
|
+
if (state.sent) return;
|
|
2256
|
+
this.context.markSent(state.event.sessionId);
|
|
2257
|
+
state.sent = true;
|
|
2258
|
+
}
|
|
2217
2259
|
finalize(state) {
|
|
2218
2260
|
this.states.delete(state.event.sessionId);
|
|
2219
2261
|
}
|