editprompt 1.4.1 → 1.6.0
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 +45 -10
- package/dist/index.js +688 -201
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,15 +2,33 @@
|
|
|
2
2
|
import { configureSync, getAnsiColorFormatter, getLogger, getTextFormatter, parseLogLevel, withFilter } from "@logtape/logtape";
|
|
3
3
|
import { cli, define } from "gunshi";
|
|
4
4
|
import { appendFileSync } from "node:fs";
|
|
5
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
6
|
+
import { createConnection } from "node:net";
|
|
7
|
+
import Conf from "conf";
|
|
5
8
|
import { exec, spawn } from "node:child_process";
|
|
6
9
|
import { promisify } from "node:util";
|
|
7
|
-
import Conf from "conf";
|
|
8
10
|
import clipboardy from "clipboardy";
|
|
9
11
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
10
|
-
import { randomBytes } from "node:crypto";
|
|
11
12
|
import { tmpdir } from "node:os";
|
|
12
13
|
import { join } from "node:path";
|
|
13
14
|
|
|
15
|
+
//#region \0rolldown/runtime.js
|
|
16
|
+
var __defProp = Object.defineProperty;
|
|
17
|
+
var __exportAll = (all, no_symbols) => {
|
|
18
|
+
let target = {};
|
|
19
|
+
for (var name in all) {
|
|
20
|
+
__defProp(target, name, {
|
|
21
|
+
get: all[name],
|
|
22
|
+
enumerable: true
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if (!no_symbols) {
|
|
26
|
+
__defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
27
|
+
}
|
|
28
|
+
return target;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
14
32
|
//#region src/modules/logger.ts
|
|
15
33
|
function resolveLogFilePath(options) {
|
|
16
34
|
if (options.logFile) return options.logFile;
|
|
@@ -72,12 +90,323 @@ function setupLogger(options = {}) {
|
|
|
72
90
|
|
|
73
91
|
//#endregion
|
|
74
92
|
//#region package.json
|
|
75
|
-
var version = "1.
|
|
93
|
+
var version = "1.6.0";
|
|
94
|
+
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region src/config/constants.ts
|
|
97
|
+
const TEMP_FILE_PREFIX = ".editprompt-";
|
|
98
|
+
const TEMP_FILE_EXTENSION = ".md";
|
|
99
|
+
const DEFAULT_EDITOR = "vim";
|
|
100
|
+
const TMUX_IMSG_LIMIT_BYTES = 16 * 1024;
|
|
101
|
+
const TMUX_SEND_CHUNK_BYTES = TMUX_IMSG_LIMIT_BYTES / 2;
|
|
102
|
+
const WEZTERM_SEND_CHUNK_BYTES = TMUX_SEND_CHUNK_BYTES;
|
|
103
|
+
const HERDR_REQUEST_LIMIT_BYTES = 1024 * 1024;
|
|
104
|
+
const HERDR_SEND_CHUNK_BYTES = HERDR_REQUEST_LIMIT_BYTES / 8;
|
|
105
|
+
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/utils/contentChunker.ts
|
|
108
|
+
/**
|
|
109
|
+
* Split content into chunks not exceeding maxBytes (UTF-8 byte count),
|
|
110
|
+
* never breaking a Unicode code point across chunks.
|
|
111
|
+
*
|
|
112
|
+
* Content shorter than maxBytes is returned as a single chunk, so short
|
|
113
|
+
* input keeps the previous behavior of being sent in one shot.
|
|
114
|
+
*/
|
|
115
|
+
function splitByByteSize(content, maxBytes) {
|
|
116
|
+
if (content === "") return [];
|
|
117
|
+
const chunks = [];
|
|
118
|
+
let current = "";
|
|
119
|
+
let currentBytes = 0;
|
|
120
|
+
for (const char of content) {
|
|
121
|
+
const charBytes = Buffer.byteLength(char, "utf8");
|
|
122
|
+
if (current !== "" && currentBytes + charBytes > maxBytes) {
|
|
123
|
+
chunks.push(current);
|
|
124
|
+
current = "";
|
|
125
|
+
currentBytes = 0;
|
|
126
|
+
}
|
|
127
|
+
current += char;
|
|
128
|
+
currentBytes += charBytes;
|
|
129
|
+
}
|
|
130
|
+
if (current !== "") chunks.push(current);
|
|
131
|
+
return chunks;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/modules/conf.ts
|
|
136
|
+
const projectName = process.env.NODE_ENV === "test" ? "editprompt-test" : "editprompt";
|
|
137
|
+
const conf = new Conf({ projectName });
|
|
138
|
+
|
|
139
|
+
//#endregion
|
|
140
|
+
//#region src/modules/herdr.ts
|
|
141
|
+
var herdr_exports = /* @__PURE__ */ __exportAll({
|
|
142
|
+
appendToQuoteText: () => appendToQuoteText$1,
|
|
143
|
+
calculateEditorSplitRatio: () => calculateEditorSplitRatio,
|
|
144
|
+
checkPaneExists: () => checkPaneExists$2,
|
|
145
|
+
clearEditorPaneId: () => clearEditorPaneId$2,
|
|
146
|
+
clearQuoteText: () => clearQuoteText$1,
|
|
147
|
+
closePane: () => closePane,
|
|
148
|
+
focusPane: () => focusPane$2,
|
|
149
|
+
getCurrentPaneId: () => getCurrentPaneId$2,
|
|
150
|
+
getEditorPaneId: () => getEditorPaneId$2,
|
|
151
|
+
getQuoteText: () => getQuoteText$1,
|
|
152
|
+
getStorageNamespace: () => getStorageNamespace,
|
|
153
|
+
getTargetPaneIds: () => getTargetPaneIds$2,
|
|
154
|
+
inputToHerdrPane: () => inputToHerdrPane,
|
|
155
|
+
isEditorPaneFromConf: () => isEditorPaneFromConf$1,
|
|
156
|
+
markAsEditorPane: () => markAsEditorPane$2,
|
|
157
|
+
resumeEditorPane: () => resumeEditorPane,
|
|
158
|
+
runCommandInPane: () => runCommandInPane,
|
|
159
|
+
saveEditorPaneId: () => saveEditorPaneId$2,
|
|
160
|
+
sendKeyToHerdrPane: () => sendKeyToHerdrPane,
|
|
161
|
+
splitEditorPane: () => splitEditorPane
|
|
162
|
+
});
|
|
163
|
+
const logger$13 = getLogger(["editprompt", "herdr"]);
|
|
164
|
+
const HERDR_REQUEST_TIMEOUT_MS = 6e3;
|
|
165
|
+
let requestSequence = 0;
|
|
166
|
+
function getSocketPath() {
|
|
167
|
+
const socketPath = process.env.HERDR_SOCKET_PATH?.trim();
|
|
168
|
+
if (!socketPath) throw new Error("HERDR_SOCKET_PATH is not set");
|
|
169
|
+
return socketPath;
|
|
170
|
+
}
|
|
171
|
+
async function sendRequest(method, params) {
|
|
172
|
+
const id = `editprompt_${process.pid}_${++requestSequence}`;
|
|
173
|
+
const request = `${JSON.stringify({
|
|
174
|
+
id,
|
|
175
|
+
method,
|
|
176
|
+
params
|
|
177
|
+
})}\n`;
|
|
178
|
+
return new Promise((resolve, reject) => {
|
|
179
|
+
const socket = createConnection(getSocketPath());
|
|
180
|
+
let buffer = "";
|
|
181
|
+
let settled = false;
|
|
182
|
+
const finish = (callback) => {
|
|
183
|
+
if (settled) return;
|
|
184
|
+
settled = true;
|
|
185
|
+
socket.end();
|
|
186
|
+
callback();
|
|
187
|
+
};
|
|
188
|
+
socket.setEncoding("utf8");
|
|
189
|
+
socket.setTimeout(HERDR_REQUEST_TIMEOUT_MS);
|
|
190
|
+
socket.on("connect", () => {
|
|
191
|
+
socket.write(request);
|
|
192
|
+
});
|
|
193
|
+
socket.on("data", (chunk) => {
|
|
194
|
+
buffer += chunk;
|
|
195
|
+
const newlineIndex = buffer.indexOf("\n");
|
|
196
|
+
if (newlineIndex === -1) return;
|
|
197
|
+
const line = buffer.slice(0, newlineIndex);
|
|
198
|
+
let response;
|
|
199
|
+
try {
|
|
200
|
+
response = JSON.parse(line);
|
|
201
|
+
} catch (error) {
|
|
202
|
+
finish(() => {
|
|
203
|
+
reject(/* @__PURE__ */ new Error(`Invalid response from Herdr: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
204
|
+
});
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (response.id !== id) {
|
|
208
|
+
finish(() => {
|
|
209
|
+
reject(/* @__PURE__ */ new Error(`Unexpected response ID from Herdr: ${response.id}`));
|
|
210
|
+
});
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (response.error) {
|
|
214
|
+
finish(() => {
|
|
215
|
+
reject(/* @__PURE__ */ new Error(`Herdr ${response.error?.code}: ${response.error?.message}`));
|
|
216
|
+
});
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
finish(() => {
|
|
220
|
+
resolve(response.result);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
socket.on("error", (error) => {
|
|
224
|
+
finish(() => {
|
|
225
|
+
reject(/* @__PURE__ */ new Error(`Failed to communicate with Herdr: ${error.message}`));
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
socket.on("timeout", () => {
|
|
229
|
+
if (settled) return;
|
|
230
|
+
settled = true;
|
|
231
|
+
socket.destroy();
|
|
232
|
+
reject(/* @__PURE__ */ new Error(`Timed out waiting for Herdr response after ${HERDR_REQUEST_TIMEOUT_MS}ms`));
|
|
233
|
+
});
|
|
234
|
+
socket.on("end", () => {
|
|
235
|
+
if (!settled) finish(() => {
|
|
236
|
+
reject(/* @__PURE__ */ new Error("Herdr closed the socket before sending a response"));
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
function getStorageNamespace() {
|
|
242
|
+
return `herdr.session_${createHash("sha256").update(getSocketPath()).digest("hex").slice(0, 16)}`;
|
|
243
|
+
}
|
|
244
|
+
function targetPaneKey(paneId) {
|
|
245
|
+
return `${getStorageNamespace()}.targetPane.pane_${paneId}`;
|
|
246
|
+
}
|
|
247
|
+
function editorPaneKey(paneId) {
|
|
248
|
+
return `${getStorageNamespace()}.editorPane.pane_${paneId}`;
|
|
249
|
+
}
|
|
250
|
+
async function getCurrentPaneId$2() {
|
|
251
|
+
const paneId = process.env.HERDR_PANE_ID?.trim() || process.env.HERDR_ACTIVE_PANE_ID?.trim();
|
|
252
|
+
if (!paneId) throw new Error("HERDR_PANE_ID or HERDR_ACTIVE_PANE_ID is not set");
|
|
253
|
+
return paneId;
|
|
254
|
+
}
|
|
255
|
+
async function checkPaneExists$2(paneId) {
|
|
256
|
+
try {
|
|
257
|
+
await sendRequest("pane.get", { pane_id: paneId });
|
|
258
|
+
return true;
|
|
259
|
+
} catch (error) {
|
|
260
|
+
logger$13.debug("checkPaneExists failed: {error}", { error });
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
async function focusPane$2(paneId) {
|
|
265
|
+
await sendRequest("pane.focus", { pane_id: paneId });
|
|
266
|
+
}
|
|
267
|
+
function calculateEditorSplitRatio(paneHeight, editorPaneRows) {
|
|
268
|
+
if (!Number.isInteger(paneHeight) || paneHeight <= 1) throw new Error(`Invalid Herdr pane height: ${paneHeight}`);
|
|
269
|
+
if (!Number.isInteger(editorPaneRows) || editorPaneRows <= 0) throw new Error(`Invalid Herdr editor pane rows: ${editorPaneRows}`);
|
|
270
|
+
return Math.min(.9, Math.max(.1, 1 - editorPaneRows / paneHeight));
|
|
271
|
+
}
|
|
272
|
+
async function splitEditorPane(targetPaneId, editorPaneRows, cwd, env = {}) {
|
|
273
|
+
const paneHeight = ((await sendRequest("pane.layout", { pane_id: targetPaneId })).layout?.panes?.find((pane) => pane.pane_id === targetPaneId))?.rect?.height;
|
|
274
|
+
if (typeof paneHeight !== "number") throw new Error(`Herdr pane.layout did not return a height for pane ${targetPaneId}`);
|
|
275
|
+
const params = {
|
|
276
|
+
target_pane_id: targetPaneId,
|
|
277
|
+
direction: "down",
|
|
278
|
+
ratio: calculateEditorSplitRatio(paneHeight, editorPaneRows),
|
|
279
|
+
focus: true,
|
|
280
|
+
env
|
|
281
|
+
};
|
|
282
|
+
if (cwd?.trim()) params.cwd = cwd;
|
|
283
|
+
const editorPaneId = (await sendRequest("pane.split", params)).pane?.pane_id;
|
|
284
|
+
if (typeof editorPaneId !== "string" || editorPaneId === "") throw new Error("Herdr pane.split did not return the new pane ID");
|
|
285
|
+
return editorPaneId;
|
|
286
|
+
}
|
|
287
|
+
function quoteShellWord(value) {
|
|
288
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
289
|
+
}
|
|
290
|
+
async function runCommandInPane(paneId, argv) {
|
|
291
|
+
if (argv.length === 0) throw new Error("Cannot run an empty command in a Herdr pane");
|
|
292
|
+
await sendRequest("pane.send_input", {
|
|
293
|
+
pane_id: paneId,
|
|
294
|
+
text: `exec ${argv.map(quoteShellWord).join(" ")}`,
|
|
295
|
+
keys: ["Enter"]
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
async function closePane(paneId) {
|
|
299
|
+
await sendRequest("pane.close", { pane_id: paneId });
|
|
300
|
+
}
|
|
301
|
+
async function inputToHerdrPane(paneId, content) {
|
|
302
|
+
const chunks = splitByByteSize(content, HERDR_SEND_CHUNK_BYTES);
|
|
303
|
+
for (const chunk of chunks) await sendRequest("pane.send_text", {
|
|
304
|
+
pane_id: paneId,
|
|
305
|
+
text: chunk
|
|
306
|
+
});
|
|
307
|
+
logger$13.debug("Content sent to Herdr pane: {paneId} ({chunkCount} chunks)", {
|
|
308
|
+
paneId,
|
|
309
|
+
chunkCount: chunks.length
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
async function sendKeyToHerdrPane(paneId, key, delay = 1e3) {
|
|
313
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
314
|
+
await sendRequest("pane.send_keys", {
|
|
315
|
+
pane_id: paneId,
|
|
316
|
+
keys: [key]
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
async function saveEditorPaneId$2(targetPaneId, editorPaneId) {
|
|
320
|
+
const data = conf.get(targetPaneKey(targetPaneId));
|
|
321
|
+
const existing = typeof data === "object" && data !== null ? data : {};
|
|
322
|
+
conf.set(targetPaneKey(targetPaneId), {
|
|
323
|
+
...existing,
|
|
324
|
+
editorPaneId
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
async function getEditorPaneId$2(targetPaneId) {
|
|
328
|
+
const data = conf.get(targetPaneKey(targetPaneId));
|
|
329
|
+
if (typeof data === "object" && data !== null && "editorPaneId" in data) return String(data.editorPaneId);
|
|
330
|
+
return "";
|
|
331
|
+
}
|
|
332
|
+
async function clearEditorPaneId$2(targetPaneId, expectedEditorPaneId) {
|
|
333
|
+
const editorPaneId = await getEditorPaneId$2(targetPaneId);
|
|
334
|
+
if (expectedEditorPaneId && editorPaneId !== expectedEditorPaneId) {
|
|
335
|
+
conf.delete(editorPaneKey(expectedEditorPaneId));
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const data = conf.get(targetPaneKey(targetPaneId));
|
|
339
|
+
if (typeof data === "object" && data !== null && "editorPaneId" in data) {
|
|
340
|
+
const { editorPaneId: _, ...remaining } = data;
|
|
341
|
+
if (Object.keys(remaining).length === 0) conf.delete(targetPaneKey(targetPaneId));
|
|
342
|
+
else conf.set(targetPaneKey(targetPaneId), remaining);
|
|
343
|
+
}
|
|
344
|
+
if (editorPaneId) conf.delete(editorPaneKey(editorPaneId));
|
|
345
|
+
}
|
|
346
|
+
async function markAsEditorPane$2(editorPaneId, targetPaneIds) {
|
|
347
|
+
const uniqueTargetPaneIds = [...new Set(targetPaneIds)];
|
|
348
|
+
conf.set(editorPaneKey(editorPaneId), { targetPaneIds: uniqueTargetPaneIds });
|
|
349
|
+
for (const targetPaneId of uniqueTargetPaneIds) await saveEditorPaneId$2(targetPaneId, editorPaneId);
|
|
350
|
+
}
|
|
351
|
+
async function getTargetPaneIds$2(editorPaneId) {
|
|
352
|
+
const data = conf.get(editorPaneKey(editorPaneId));
|
|
353
|
+
if (typeof data === "object" && data !== null && "targetPaneIds" in data) {
|
|
354
|
+
const targetPaneIds = data.targetPaneIds;
|
|
355
|
+
if (Array.isArray(targetPaneIds)) return targetPaneIds.map((id) => String(id));
|
|
356
|
+
}
|
|
357
|
+
return [];
|
|
358
|
+
}
|
|
359
|
+
function isEditorPaneFromConf$1(paneId) {
|
|
360
|
+
return conf.has(editorPaneKey(paneId));
|
|
361
|
+
}
|
|
362
|
+
async function resumeEditorPane(targetPaneId) {
|
|
363
|
+
const currentPaneId = await getCurrentPaneId$2();
|
|
364
|
+
const editorPaneId = isEditorPaneFromConf$1(currentPaneId) ? currentPaneId : isEditorPaneFromConf$1(targetPaneId) ? targetPaneId : "";
|
|
365
|
+
if (editorPaneId) {
|
|
366
|
+
const targetPaneIds = await getTargetPaneIds$2(editorPaneId);
|
|
367
|
+
for (const paneId of targetPaneIds) if (await checkPaneExists$2(paneId)) {
|
|
368
|
+
await focusPane$2(paneId);
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
const registeredEditorPaneId = await getEditorPaneId$2(targetPaneId);
|
|
374
|
+
if (registeredEditorPaneId === "") return false;
|
|
375
|
+
if (!await checkPaneExists$2(registeredEditorPaneId)) {
|
|
376
|
+
await clearEditorPaneId$2(targetPaneId);
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
await focusPane$2(registeredEditorPaneId);
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
async function appendToQuoteText$1(paneId, content) {
|
|
383
|
+
const data = conf.get(targetPaneKey(paneId));
|
|
384
|
+
const existing = typeof data === "object" && data !== null ? data : {};
|
|
385
|
+
const existingQuoteText = "quote_text" in existing ? String(existing.quote_text) : "";
|
|
386
|
+
const quoteText = existingQuoteText.trim() !== "" ? `${existingQuoteText}\n\n${content}` : content;
|
|
387
|
+
conf.set(targetPaneKey(paneId), {
|
|
388
|
+
...existing,
|
|
389
|
+
quote_text: quoteText
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
async function getQuoteText$1(paneId) {
|
|
393
|
+
const data = conf.get(targetPaneKey(paneId));
|
|
394
|
+
if (typeof data === "object" && data !== null && "quote_text" in data) return String(data.quote_text);
|
|
395
|
+
return "";
|
|
396
|
+
}
|
|
397
|
+
async function clearQuoteText$1(paneId) {
|
|
398
|
+
const data = conf.get(targetPaneKey(paneId));
|
|
399
|
+
if (typeof data === "object" && data !== null && "quote_text" in data) {
|
|
400
|
+
const { quote_text: _, ...remaining } = data;
|
|
401
|
+
if (Object.keys(remaining).length === 0) conf.delete(targetPaneKey(paneId));
|
|
402
|
+
else conf.set(targetPaneKey(paneId), remaining);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
76
405
|
|
|
77
406
|
//#endregion
|
|
78
407
|
//#region src/modules/tmux.ts
|
|
79
408
|
const execAsync$1 = promisify(exec);
|
|
80
|
-
const logger$
|
|
409
|
+
const logger$12 = getLogger(["editprompt", "tmux"]);
|
|
81
410
|
async function getCurrentPaneId$1() {
|
|
82
411
|
const envPaneId = process.env.TMUX_PANE?.trim();
|
|
83
412
|
if (envPaneId) return envPaneId;
|
|
@@ -157,18 +486,17 @@ async function sendKeyToTmuxPane(paneId, key, delay = 1e3) {
|
|
|
157
486
|
}
|
|
158
487
|
async function inputToTmuxPane(paneId, content) {
|
|
159
488
|
await execAsync$1(`tmux if-shell -t '${paneId}' '[ "#{pane_in_mode}" = "1" ]' "copy-mode -q -t '${paneId}'"`);
|
|
160
|
-
|
|
161
|
-
|
|
489
|
+
const chunks = splitByByteSize(content, TMUX_SEND_CHUNK_BYTES);
|
|
490
|
+
for (const chunk of chunks) await execAsync$1(`tmux send-keys -t '${paneId}' -- '${chunk.replace(/'/g, "'\\''")}'`);
|
|
491
|
+
logger$12.debug("Content sent to tmux pane: {paneId} ({chunks} chunk(s))", {
|
|
492
|
+
paneId,
|
|
493
|
+
chunks: chunks.length
|
|
494
|
+
});
|
|
162
495
|
}
|
|
163
496
|
|
|
164
|
-
//#endregion
|
|
165
|
-
//#region src/modules/conf.ts
|
|
166
|
-
const projectName = process.env.NODE_ENV === "test" ? "editprompt-test" : "editprompt";
|
|
167
|
-
const conf = new Conf({ projectName });
|
|
168
|
-
|
|
169
497
|
//#endregion
|
|
170
498
|
//#region src/modules/wezterm.ts
|
|
171
|
-
const logger$
|
|
499
|
+
const logger$11 = getLogger(["editprompt", "wezterm"]);
|
|
172
500
|
const execAsync = promisify(exec);
|
|
173
501
|
async function getCurrentPaneId() {
|
|
174
502
|
try {
|
|
@@ -176,26 +504,26 @@ async function getCurrentPaneId() {
|
|
|
176
504
|
const activePane = JSON.parse(stdout).find((pane) => pane.is_active === true);
|
|
177
505
|
return String(activePane?.pane_id);
|
|
178
506
|
} catch (error) {
|
|
179
|
-
logger$
|
|
507
|
+
logger$11.debug("getCurrentPaneId failed: {error}", { error });
|
|
180
508
|
return "";
|
|
181
509
|
}
|
|
182
510
|
}
|
|
183
511
|
async function checkPaneExists(paneId) {
|
|
184
512
|
try {
|
|
185
513
|
const { stdout } = await execAsync("wezterm cli list --format json");
|
|
186
|
-
logger$
|
|
514
|
+
logger$11.debug("wezterm cli list output: {stdout}", { stdout });
|
|
187
515
|
return JSON.parse(stdout).some((pane) => String(pane.pane_id) === paneId);
|
|
188
516
|
} catch (error) {
|
|
189
|
-
logger$
|
|
517
|
+
logger$11.debug("checkPaneExists failed: {error}", { error });
|
|
190
518
|
return false;
|
|
191
519
|
}
|
|
192
520
|
}
|
|
193
521
|
async function saveEditorPaneId(targetPaneId, editorPaneId) {
|
|
194
|
-
logger$
|
|
522
|
+
logger$11.debug("Saving editor pane ID to conf key: wezterm.targetPane.pane_{targetPaneId}", { targetPaneId });
|
|
195
523
|
try {
|
|
196
524
|
conf.set(`wezterm.targetPane.pane_${targetPaneId}`, { editorPaneId });
|
|
197
525
|
} catch (error) {
|
|
198
|
-
logger$
|
|
526
|
+
logger$11.debug("saveEditorPaneId failed: {error}", { error });
|
|
199
527
|
}
|
|
200
528
|
}
|
|
201
529
|
async function getEditorPaneId(targetPaneId) {
|
|
@@ -204,7 +532,7 @@ async function getEditorPaneId(targetPaneId) {
|
|
|
204
532
|
if (typeof data === "object" && data !== null && "editorPaneId" in data) return String(data.editorPaneId);
|
|
205
533
|
return "";
|
|
206
534
|
} catch (error) {
|
|
207
|
-
logger$
|
|
535
|
+
logger$11.debug("getEditorPaneId failed: {error}", { error });
|
|
208
536
|
return "";
|
|
209
537
|
}
|
|
210
538
|
}
|
|
@@ -214,7 +542,7 @@ async function clearEditorPaneId(targetPaneId) {
|
|
|
214
542
|
conf.delete(`wezterm.targetPane.pane_${targetPaneId}`);
|
|
215
543
|
if (editorPaneId) conf.delete(`wezterm.editorPane.pane_${editorPaneId}`);
|
|
216
544
|
} catch (error) {
|
|
217
|
-
logger$
|
|
545
|
+
logger$11.debug("clearEditorPaneId failed: {error}", { error });
|
|
218
546
|
}
|
|
219
547
|
}
|
|
220
548
|
async function focusPane(paneId) {
|
|
@@ -226,7 +554,7 @@ async function markAsEditorPane(editorPaneId, targetPaneIds) {
|
|
|
226
554
|
conf.set(`wezterm.editorPane.pane_${editorPaneId}`, { targetPaneIds: uniqueTargetPaneIds });
|
|
227
555
|
for (const targetPaneId of uniqueTargetPaneIds) await saveEditorPaneId(targetPaneId, editorPaneId);
|
|
228
556
|
} catch (error) {
|
|
229
|
-
logger$
|
|
557
|
+
logger$11.debug("markAsEditorPane failed: {error}", { error });
|
|
230
558
|
}
|
|
231
559
|
}
|
|
232
560
|
async function getTargetPaneIds(editorPaneId) {
|
|
@@ -238,7 +566,7 @@ async function getTargetPaneIds(editorPaneId) {
|
|
|
238
566
|
}
|
|
239
567
|
return [];
|
|
240
568
|
} catch (error) {
|
|
241
|
-
logger$
|
|
569
|
+
logger$11.debug("getTargetPaneIds failed: {error}", { error });
|
|
242
570
|
return [];
|
|
243
571
|
}
|
|
244
572
|
}
|
|
@@ -246,7 +574,7 @@ function isEditorPaneFromConf(paneId) {
|
|
|
246
574
|
try {
|
|
247
575
|
return conf.has(`wezterm.editorPane.pane_${paneId}`);
|
|
248
576
|
} catch (error) {
|
|
249
|
-
logger$
|
|
577
|
+
logger$11.debug("isEditorPaneFromConf failed: {error}", { error });
|
|
250
578
|
return false;
|
|
251
579
|
}
|
|
252
580
|
}
|
|
@@ -264,7 +592,7 @@ async function appendToQuoteText(paneId, content) {
|
|
|
264
592
|
} else newData = { quote_text: content };
|
|
265
593
|
conf.set(`wezterm.targetPane.pane_${paneId}`, newData);
|
|
266
594
|
} catch (error) {
|
|
267
|
-
logger$
|
|
595
|
+
logger$11.debug("appendToQuoteText failed: {error}", { error });
|
|
268
596
|
}
|
|
269
597
|
}
|
|
270
598
|
async function getQuoteText(paneId) {
|
|
@@ -273,7 +601,7 @@ async function getQuoteText(paneId) {
|
|
|
273
601
|
if (typeof data === "object" && data !== null && "quote_text" in data) return String(data.quote_text);
|
|
274
602
|
return "";
|
|
275
603
|
} catch (error) {
|
|
276
|
-
logger$
|
|
604
|
+
logger$11.debug("getQuoteText failed: {error}", { error });
|
|
277
605
|
return "";
|
|
278
606
|
}
|
|
279
607
|
}
|
|
@@ -282,7 +610,7 @@ async function clearQuoteText(paneId) {
|
|
|
282
610
|
const key = `wezterm.targetPane.pane_${paneId}.quote_text`;
|
|
283
611
|
if (conf.has(key)) conf.delete(key);
|
|
284
612
|
} catch (error) {
|
|
285
|
-
logger$
|
|
613
|
+
logger$11.debug("clearQuoteText failed: {error}", { error });
|
|
286
614
|
}
|
|
287
615
|
}
|
|
288
616
|
async function sendKeyToWeztermPane(paneId, key, delay = 1e3) {
|
|
@@ -290,8 +618,12 @@ async function sendKeyToWeztermPane(paneId, key, delay = 1e3) {
|
|
|
290
618
|
await execAsync(`wezterm cli send-text --no-paste --pane-id '${paneId}' $'${key}'`);
|
|
291
619
|
}
|
|
292
620
|
async function inputToWeztermPane(paneId, content) {
|
|
293
|
-
|
|
294
|
-
|
|
621
|
+
const chunks = splitByByteSize(content, WEZTERM_SEND_CHUNK_BYTES);
|
|
622
|
+
for (const chunk of chunks) await execAsync(`wezterm cli send-text --no-paste --pane-id '${paneId}' -- '${chunk.replace(/'/g, "'\\''")}'`);
|
|
623
|
+
logger$11.debug("Content sent to wezterm pane: {paneId} ({chunks} chunk(s))", {
|
|
624
|
+
paneId,
|
|
625
|
+
chunks: chunks.length
|
|
626
|
+
});
|
|
295
627
|
}
|
|
296
628
|
|
|
297
629
|
//#endregion
|
|
@@ -432,87 +764,36 @@ function processQuoteText(text, options) {
|
|
|
432
764
|
}
|
|
433
765
|
|
|
434
766
|
//#endregion
|
|
435
|
-
//#region src/
|
|
436
|
-
const
|
|
767
|
+
//#region src/utils/mux.ts
|
|
768
|
+
const SUPPORTED_MUXES = [
|
|
769
|
+
"tmux",
|
|
770
|
+
"wezterm",
|
|
771
|
+
"herdr"
|
|
772
|
+
];
|
|
437
773
|
function isMuxType(value) {
|
|
438
|
-
return value === "tmux" || value === "wezterm";
|
|
774
|
+
return value === "tmux" || value === "wezterm" || value === "herdr";
|
|
439
775
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
await clipboardy.write(content);
|
|
776
|
+
function hasValue(value) {
|
|
777
|
+
return typeof value === "string" && value.trim() !== "";
|
|
443
778
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
else await inputToTmuxPane(targetPaneId, content);
|
|
447
|
-
}
|
|
448
|
-
async function focusFirstSuccessPane(mux, targetPanes, failedPanes) {
|
|
449
|
-
const firstSuccessPane = targetPanes.find((p) => !failedPanes.includes(p));
|
|
450
|
-
if (firstSuccessPane) if (mux === "tmux") await focusPane$1(firstSuccessPane);
|
|
451
|
-
else await focusPane(firstSuccessPane);
|
|
779
|
+
function isHerdrEnvironment(env = process.env) {
|
|
780
|
+
return hasValue(env.HERDR_SOCKET_PATH) && (hasValue(env.HERDR_PANE_ID) || hasValue(env.HERDR_ACTIVE_PANE_ID));
|
|
452
781
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
allFailed: false,
|
|
459
|
-
failedPanes: []
|
|
460
|
-
};
|
|
461
|
-
if (targetPanes.length === 0) {
|
|
462
|
-
try {
|
|
463
|
-
await copyToClipboard(content);
|
|
464
|
-
logger$9.info("Content copied to clipboard.");
|
|
465
|
-
} catch (error) {
|
|
466
|
-
logger$9.warn(`Failed to copy to clipboard: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
467
|
-
}
|
|
468
|
-
return {
|
|
469
|
-
successCount: 0,
|
|
470
|
-
totalCount: 0,
|
|
471
|
-
allSuccess: true,
|
|
472
|
-
allFailed: false,
|
|
473
|
-
failedPanes: []
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
const results = [];
|
|
477
|
-
for (const targetPane of targetPanes) try {
|
|
478
|
-
await inputContentToPane(content, mux, targetPane);
|
|
479
|
-
results.push({
|
|
480
|
-
pane: targetPane,
|
|
481
|
-
success: true
|
|
482
|
-
});
|
|
483
|
-
} catch (error) {
|
|
484
|
-
logger$9.warn(`Failed to send to pane ${targetPane}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
485
|
-
results.push({
|
|
486
|
-
pane: targetPane,
|
|
487
|
-
success: false
|
|
488
|
-
});
|
|
782
|
+
function resolveMux(explicitMux, env = process.env) {
|
|
783
|
+
const muxValue = explicitMux || env.EDITPROMPT_MUX || (isHerdrEnvironment(env) ? "herdr" : "tmux");
|
|
784
|
+
if (!isMuxType(muxValue)) {
|
|
785
|
+
const displayValue = typeof muxValue === "string" ? muxValue : `<${typeof muxValue}>`;
|
|
786
|
+
throw new Error(`Invalid multiplexer type '${displayValue}'. Supported values: ${SUPPORTED_MUXES.join(", ")}`);
|
|
489
787
|
}
|
|
490
|
-
|
|
491
|
-
const failedPanes = results.filter((r) => !r.success).map((r) => r.pane);
|
|
492
|
-
const allSuccess = successCount === targetPanes.length;
|
|
493
|
-
const allFailed = successCount === 0;
|
|
494
|
-
if (allSuccess) logger$9.info("Content sent successfully to all panes!");
|
|
495
|
-
else if (allFailed) {
|
|
496
|
-
logger$9.error("All target panes failed to receive content.");
|
|
497
|
-
logger$9.info("Falling back to clipboard...");
|
|
498
|
-
await copyToClipboard(content);
|
|
499
|
-
logger$9.info("Content copied to clipboard.");
|
|
500
|
-
} else logger$9.warn(`Content sent to ${successCount}/${targetPanes.length} panes. Failed panes: ${failedPanes.join(", ")}`);
|
|
501
|
-
return {
|
|
502
|
-
successCount,
|
|
503
|
-
totalCount: targetPanes.length,
|
|
504
|
-
allSuccess,
|
|
505
|
-
allFailed,
|
|
506
|
-
failedPanes
|
|
507
|
-
};
|
|
788
|
+
return muxValue;
|
|
508
789
|
}
|
|
509
790
|
|
|
510
791
|
//#endregion
|
|
511
792
|
//#region src/modes/args.ts
|
|
512
|
-
const logger$
|
|
793
|
+
const logger$10 = getLogger(["editprompt"]);
|
|
513
794
|
const ARG_MUX = {
|
|
514
795
|
short: "m",
|
|
515
|
-
description: "Multiplexer type (tmux or
|
|
796
|
+
description: "Multiplexer type (tmux, wezterm, or herdr; auto-detects Herdr, otherwise tmux)",
|
|
516
797
|
type: "string"
|
|
517
798
|
};
|
|
518
799
|
const ARG_TARGET_PANE_SINGLE = {
|
|
@@ -558,17 +839,23 @@ const ARG_VERBOSE = {
|
|
|
558
839
|
description: "Enable debug-level log output",
|
|
559
840
|
type: "boolean"
|
|
560
841
|
};
|
|
842
|
+
const ARG_ENV = {
|
|
843
|
+
short: "E",
|
|
844
|
+
description: "Environment variables to set (e.g., KEY=VALUE)",
|
|
845
|
+
type: "string",
|
|
846
|
+
multiple: true
|
|
847
|
+
};
|
|
561
848
|
function validateMux(value) {
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
849
|
+
try {
|
|
850
|
+
return resolveMux(value);
|
|
851
|
+
} catch (error) {
|
|
852
|
+
logger$10.error(error instanceof Error ? error.message : String(error));
|
|
565
853
|
process.exit(1);
|
|
566
854
|
}
|
|
567
|
-
return muxValue;
|
|
568
855
|
}
|
|
569
856
|
function validateTargetPane(value, commandName) {
|
|
570
857
|
if (!value || typeof value !== "string") {
|
|
571
|
-
logger$
|
|
858
|
+
logger$10.error(`--target-pane is required for ${commandName} command`);
|
|
572
859
|
process.exit(1);
|
|
573
860
|
}
|
|
574
861
|
return value;
|
|
@@ -581,7 +868,7 @@ function normalizeTargetPanes(value) {
|
|
|
581
868
|
|
|
582
869
|
//#endregion
|
|
583
870
|
//#region src/modes/collect.ts
|
|
584
|
-
const logger$
|
|
871
|
+
const logger$9 = getLogger(["editprompt", "collect"]);
|
|
585
872
|
const SUPPORTED_OUTPUTS = ["buffer", "stdout"];
|
|
586
873
|
async function readStdin() {
|
|
587
874
|
return new Promise((resolve, reject) => {
|
|
@@ -605,7 +892,7 @@ function normalizeCollectOutputs(value) {
|
|
|
605
892
|
const uniqueOutputs = [...new Set(outputs)];
|
|
606
893
|
const invalid = uniqueOutputs.filter((v) => !SUPPORTED_OUTPUTS.includes(v));
|
|
607
894
|
if (invalid.length > 0) {
|
|
608
|
-
logger$
|
|
895
|
+
logger$9.error(`Invalid output(s) '${invalid.join(", ")}'. Supported values: ${SUPPORTED_OUTPUTS.join(", ")}`);
|
|
609
896
|
process.exit(1);
|
|
610
897
|
}
|
|
611
898
|
return uniqueOutputs;
|
|
@@ -616,12 +903,12 @@ async function runCollectMode(mux, targetPaneId, rawContent, outputs = ["buffer"
|
|
|
616
903
|
if (rawContent !== void 0) selection = rawContent;
|
|
617
904
|
else selection = await readStdin();
|
|
618
905
|
const processedText = processQuoteText(selection, { withQuote });
|
|
619
|
-
for (const output of outputs) if (output === "buffer")
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
906
|
+
for (const output of outputs) if (output === "buffer") if (mux === "tmux") await appendToQuoteVariable(targetPaneId, processedText);
|
|
907
|
+
else if (mux === "wezterm") await appendToQuoteText(targetPaneId, processedText);
|
|
908
|
+
else await appendToQuoteText$1(targetPaneId, processedText);
|
|
909
|
+
else if (output === "stdout") process.stdout.write(processedText);
|
|
623
910
|
} catch (error) {
|
|
624
|
-
logger$
|
|
911
|
+
logger$9.error(`${error instanceof Error ? error.message : "Unknown error"}`);
|
|
625
912
|
process.exit(1);
|
|
626
913
|
}
|
|
627
914
|
}
|
|
@@ -648,10 +935,10 @@ const collectCommand = define({
|
|
|
648
935
|
const outputs = normalizeCollectOutputs(ctx.values.output);
|
|
649
936
|
const withQuote = !ctx.values["no-quote"];
|
|
650
937
|
let rawContent;
|
|
651
|
-
if (mux === "wezterm") {
|
|
938
|
+
if (mux === "wezterm" || mux === "herdr") {
|
|
652
939
|
rawContent = extractRawContent(ctx.rest, ctx.positionals);
|
|
653
940
|
if (rawContent === void 0) {
|
|
654
|
-
logger$
|
|
941
|
+
logger$9.error(`Text content is required for collect mode with ${mux}. Use: editprompt collect --mux ${mux} --target-pane <id> -- "<text>"`);
|
|
655
942
|
process.exit(1);
|
|
656
943
|
}
|
|
657
944
|
}
|
|
@@ -661,11 +948,8 @@ const collectCommand = define({
|
|
|
661
948
|
|
|
662
949
|
//#endregion
|
|
663
950
|
//#region src/utils/sendConfig.ts
|
|
664
|
-
const VALID_MUX_TYPES = ["tmux", "wezterm"];
|
|
665
951
|
function readSendConfig() {
|
|
666
|
-
const
|
|
667
|
-
if (!VALID_MUX_TYPES.includes(muxValue)) throw new Error(`Invalid EDITPROMPT_MUX value: ${muxValue}. Must be one of: ${VALID_MUX_TYPES.join(", ")}`);
|
|
668
|
-
const mux = muxValue;
|
|
952
|
+
const mux = resolveMux();
|
|
669
953
|
const alwaysCopy = process.env.EDITPROMPT_ALWAYS_COPY === "1";
|
|
670
954
|
const delayValue = process.env.EDITPROMPT_SEND_KEY_DELAY;
|
|
671
955
|
const parsedDelay = delayValue ? Number.parseInt(delayValue, 10) : NaN;
|
|
@@ -678,7 +962,7 @@ function readSendConfig() {
|
|
|
678
962
|
|
|
679
963
|
//#endregion
|
|
680
964
|
//#region src/modes/dump.ts
|
|
681
|
-
const logger$
|
|
965
|
+
const logger$8 = getLogger(["editprompt", "dump"]);
|
|
682
966
|
async function runDumpMode() {
|
|
683
967
|
try {
|
|
684
968
|
const config = readSendConfig();
|
|
@@ -687,19 +971,23 @@ async function runDumpMode() {
|
|
|
687
971
|
if (config.mux === "tmux") {
|
|
688
972
|
currentPaneId = await getCurrentPaneId$1();
|
|
689
973
|
isEditor = await isEditorPane(currentPaneId);
|
|
690
|
-
} else {
|
|
974
|
+
} else if (config.mux === "wezterm") {
|
|
691
975
|
currentPaneId = await getCurrentPaneId();
|
|
692
976
|
isEditor = isEditorPaneFromConf(currentPaneId);
|
|
977
|
+
} else {
|
|
978
|
+
currentPaneId = await getCurrentPaneId$2();
|
|
979
|
+
isEditor = isEditorPaneFromConf$1(currentPaneId);
|
|
693
980
|
}
|
|
694
981
|
if (!isEditor) {
|
|
695
|
-
logger$
|
|
982
|
+
logger$8.error("Current pane is not an editor pane");
|
|
696
983
|
process.exit(1);
|
|
697
984
|
}
|
|
698
985
|
let targetPanes;
|
|
699
986
|
if (config.mux === "tmux") targetPanes = await getTargetPaneIds$1(currentPaneId);
|
|
700
|
-
else targetPanes = await getTargetPaneIds(currentPaneId);
|
|
987
|
+
else if (config.mux === "wezterm") targetPanes = await getTargetPaneIds(currentPaneId);
|
|
988
|
+
else targetPanes = await getTargetPaneIds$2(currentPaneId);
|
|
701
989
|
if (targetPanes.length === 0) {
|
|
702
|
-
logger$
|
|
990
|
+
logger$8.error("No target panes registered for this editor pane");
|
|
703
991
|
process.exit(1);
|
|
704
992
|
}
|
|
705
993
|
const quoteContents = [];
|
|
@@ -708,9 +996,12 @@ async function runDumpMode() {
|
|
|
708
996
|
if (config.mux === "tmux") {
|
|
709
997
|
content = await getQuoteVariableContent(targetPane);
|
|
710
998
|
await clearQuoteVariable(targetPane);
|
|
711
|
-
} else {
|
|
999
|
+
} else if (config.mux === "wezterm") {
|
|
712
1000
|
content = await getQuoteText(targetPane);
|
|
713
1001
|
await clearQuoteText(targetPane);
|
|
1002
|
+
} else {
|
|
1003
|
+
content = await getQuoteText$1(targetPane);
|
|
1004
|
+
await clearQuoteText$1(targetPane);
|
|
714
1005
|
}
|
|
715
1006
|
if (content.trim() !== "") quoteContents.push(content);
|
|
716
1007
|
}
|
|
@@ -718,7 +1009,7 @@ async function runDumpMode() {
|
|
|
718
1009
|
process.stdout.write(combinedContent.replace(/\n{3,}$/, "\n\n"));
|
|
719
1010
|
process.exit(0);
|
|
720
1011
|
} catch (error) {
|
|
721
|
-
logger$
|
|
1012
|
+
logger$8.error(`${error instanceof Error ? error.message : "Unknown error"}`);
|
|
722
1013
|
process.exit(1);
|
|
723
1014
|
}
|
|
724
1015
|
}
|
|
@@ -748,13 +1039,87 @@ function processContent(content) {
|
|
|
748
1039
|
return processed;
|
|
749
1040
|
}
|
|
750
1041
|
|
|
1042
|
+
//#endregion
|
|
1043
|
+
//#region src/modes/common.ts
|
|
1044
|
+
const logger$7 = getLogger(["editprompt", "delivery"]);
|
|
1045
|
+
async function copyToClipboard(content) {
|
|
1046
|
+
await clipboardy.write(content);
|
|
1047
|
+
}
|
|
1048
|
+
async function inputContentToPane(content, mux, targetPaneId) {
|
|
1049
|
+
if (mux === "wezterm") await inputToWeztermPane(targetPaneId, content);
|
|
1050
|
+
else if (mux === "herdr") await inputToHerdrPane(targetPaneId, content);
|
|
1051
|
+
else await inputToTmuxPane(targetPaneId, content);
|
|
1052
|
+
}
|
|
1053
|
+
async function focusFirstSuccessPane(mux, targetPanes, failedPanes) {
|
|
1054
|
+
const firstSuccessPane = targetPanes.find((p) => !failedPanes.includes(p));
|
|
1055
|
+
if (firstSuccessPane) if (mux === "tmux") await focusPane$1(firstSuccessPane);
|
|
1056
|
+
else if (mux === "wezterm") await focusPane(firstSuccessPane);
|
|
1057
|
+
else await focusPane$2(firstSuccessPane);
|
|
1058
|
+
}
|
|
1059
|
+
async function handleContentDelivery(content, mux, targetPanes) {
|
|
1060
|
+
if (!content) return {
|
|
1061
|
+
successCount: 0,
|
|
1062
|
+
totalCount: 0,
|
|
1063
|
+
allSuccess: true,
|
|
1064
|
+
allFailed: false,
|
|
1065
|
+
failedPanes: []
|
|
1066
|
+
};
|
|
1067
|
+
if (targetPanes.length === 0) {
|
|
1068
|
+
try {
|
|
1069
|
+
await copyToClipboard(content);
|
|
1070
|
+
logger$7.info("Content copied to clipboard.");
|
|
1071
|
+
} catch (error) {
|
|
1072
|
+
logger$7.warn(`Failed to copy to clipboard: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1073
|
+
}
|
|
1074
|
+
return {
|
|
1075
|
+
successCount: 0,
|
|
1076
|
+
totalCount: 0,
|
|
1077
|
+
allSuccess: true,
|
|
1078
|
+
allFailed: false,
|
|
1079
|
+
failedPanes: []
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
const results = [];
|
|
1083
|
+
for (const targetPane of targetPanes) try {
|
|
1084
|
+
await inputContentToPane(content, mux, targetPane);
|
|
1085
|
+
results.push({
|
|
1086
|
+
pane: targetPane,
|
|
1087
|
+
success: true
|
|
1088
|
+
});
|
|
1089
|
+
} catch (error) {
|
|
1090
|
+
logger$7.warn(`Failed to send to pane ${targetPane}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1091
|
+
results.push({
|
|
1092
|
+
pane: targetPane,
|
|
1093
|
+
success: false
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
const successCount = results.filter((r) => r.success).length;
|
|
1097
|
+
const failedPanes = results.filter((r) => !r.success).map((r) => r.pane);
|
|
1098
|
+
const allSuccess = successCount === targetPanes.length;
|
|
1099
|
+
const allFailed = successCount === 0;
|
|
1100
|
+
if (allSuccess) logger$7.info("Content sent successfully to all panes!");
|
|
1101
|
+
else if (allFailed) {
|
|
1102
|
+
logger$7.error("All target panes failed to receive content.");
|
|
1103
|
+
logger$7.info("Falling back to clipboard...");
|
|
1104
|
+
await copyToClipboard(content);
|
|
1105
|
+
logger$7.info("Content copied to clipboard.");
|
|
1106
|
+
} else logger$7.warn(`Content sent to ${successCount}/${targetPanes.length} panes. Failed panes: ${failedPanes.join(", ")}`);
|
|
1107
|
+
return {
|
|
1108
|
+
successCount,
|
|
1109
|
+
totalCount: targetPanes.length,
|
|
1110
|
+
allSuccess,
|
|
1111
|
+
allFailed,
|
|
1112
|
+
failedPanes
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
|
|
751
1116
|
//#endregion
|
|
752
1117
|
//#region src/modes/input.ts
|
|
753
|
-
const logger$
|
|
1118
|
+
const logger$6 = getLogger(["editprompt", "input"]);
|
|
754
1119
|
async function runInputMode(rawContent, autoSend, sendKey, sendKeyDelay) {
|
|
755
1120
|
const content = processContent(rawContent);
|
|
756
1121
|
if (!content) {
|
|
757
|
-
logger$
|
|
1122
|
+
logger$6.info("No content to send. Exiting.");
|
|
758
1123
|
return;
|
|
759
1124
|
}
|
|
760
1125
|
const config = readSendConfig();
|
|
@@ -763,44 +1128,51 @@ async function runInputMode(rawContent, autoSend, sendKey, sendKeyDelay) {
|
|
|
763
1128
|
if (config.mux === "tmux") {
|
|
764
1129
|
currentPaneId = await getCurrentPaneId$1();
|
|
765
1130
|
isEditor = await isEditorPane(currentPaneId);
|
|
766
|
-
} else {
|
|
1131
|
+
} else if (config.mux === "wezterm") {
|
|
767
1132
|
currentPaneId = await getCurrentPaneId();
|
|
768
1133
|
isEditor = isEditorPaneFromConf(currentPaneId);
|
|
1134
|
+
} else {
|
|
1135
|
+
currentPaneId = await getCurrentPaneId$2();
|
|
1136
|
+
isEditor = isEditorPaneFromConf$1(currentPaneId);
|
|
769
1137
|
}
|
|
770
1138
|
if (!isEditor) {
|
|
771
|
-
logger$
|
|
1139
|
+
logger$6.error("Current pane is not an editor pane");
|
|
772
1140
|
process.exit(1);
|
|
773
1141
|
}
|
|
774
1142
|
let targetPanes;
|
|
775
1143
|
if (config.mux === "tmux") targetPanes = await getTargetPaneIds$1(currentPaneId);
|
|
776
|
-
else targetPanes = await getTargetPaneIds(currentPaneId);
|
|
1144
|
+
else if (config.mux === "wezterm") targetPanes = await getTargetPaneIds(currentPaneId);
|
|
1145
|
+
else targetPanes = await getTargetPaneIds$2(currentPaneId);
|
|
777
1146
|
if (targetPanes.length === 0) {
|
|
778
|
-
logger$
|
|
1147
|
+
logger$6.error("No target panes registered for this editor pane");
|
|
779
1148
|
process.exit(1);
|
|
780
1149
|
}
|
|
781
1150
|
if (autoSend) {
|
|
782
|
-
const key = sendKey || (config.mux === "wezterm" ? "\\r" : "C-m");
|
|
1151
|
+
const key = sendKey || (config.mux === "wezterm" ? "\\r" : config.mux === "herdr" ? "enter" : "C-m");
|
|
783
1152
|
const delay = /\.(png|webp|avif|jpe?g|gif)\b/i.test(content) ? sendKeyDelay ?? 1e3 : 200;
|
|
784
1153
|
let successCount = 0;
|
|
785
1154
|
for (const targetPane of targetPanes) try {
|
|
786
1155
|
if (config.mux === "wezterm") {
|
|
787
1156
|
await inputToWeztermPane(targetPane, content);
|
|
788
1157
|
await sendKeyToWeztermPane(targetPane, key, delay);
|
|
1158
|
+
} else if (config.mux === "herdr") {
|
|
1159
|
+
await inputToHerdrPane(targetPane, content);
|
|
1160
|
+
await sendKeyToHerdrPane(targetPane, key, delay);
|
|
789
1161
|
} else {
|
|
790
1162
|
await inputToTmuxPane(targetPane, content);
|
|
791
1163
|
await sendKeyToTmuxPane(targetPane, key, delay);
|
|
792
1164
|
}
|
|
793
1165
|
successCount++;
|
|
794
1166
|
} catch (error) {
|
|
795
|
-
logger$
|
|
1167
|
+
logger$6.error(`Failed to send to pane ${targetPane}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
796
1168
|
}
|
|
797
1169
|
if (config.alwaysCopy) {
|
|
798
1170
|
await copyToClipboard(content);
|
|
799
|
-
logger$
|
|
1171
|
+
logger$6.info("Also copied to clipboard.");
|
|
800
1172
|
}
|
|
801
|
-
if (successCount > 0) logger$
|
|
1173
|
+
if (successCount > 0) logger$6.info("Content sent and submitted successfully!");
|
|
802
1174
|
else {
|
|
803
|
-
logger$
|
|
1175
|
+
logger$6.error("All target panes failed to receive content");
|
|
804
1176
|
process.exit(1);
|
|
805
1177
|
}
|
|
806
1178
|
return;
|
|
@@ -809,12 +1181,12 @@ async function runInputMode(rawContent, autoSend, sendKey, sendKeyDelay) {
|
|
|
809
1181
|
const result = await handleContentDelivery(content, config.mux, targetPanes);
|
|
810
1182
|
if (config.alwaysCopy && !result.allFailed) {
|
|
811
1183
|
await copyToClipboard(content);
|
|
812
|
-
logger$
|
|
1184
|
+
logger$6.info("Also copied to clipboard.");
|
|
813
1185
|
}
|
|
814
1186
|
if (result.successCount > 0) await focusFirstSuccessPane(config.mux, targetPanes, result.failedPanes);
|
|
815
1187
|
if (result.allFailed) process.exit(1);
|
|
816
1188
|
} catch (error) {
|
|
817
|
-
logger$
|
|
1189
|
+
logger$6.error(`${error instanceof Error ? error.message : "Unknown error"}`);
|
|
818
1190
|
process.exit(1);
|
|
819
1191
|
}
|
|
820
1192
|
}
|
|
@@ -842,13 +1214,13 @@ const inputCommand = define({
|
|
|
842
1214
|
});
|
|
843
1215
|
const rawContent = extractRawContent(ctx.rest, ctx.positionals);
|
|
844
1216
|
if (rawContent === void 0) {
|
|
845
|
-
logger$
|
|
846
|
-
logger$
|
|
847
|
-
logger$
|
|
1217
|
+
logger$6.error("Content is required for input command");
|
|
1218
|
+
logger$6.error("Usage: editprompt input \"your content\"");
|
|
1219
|
+
logger$6.error(" or: editprompt input -- \"your content\"");
|
|
848
1220
|
process.exit(1);
|
|
849
1221
|
}
|
|
850
1222
|
if (ctx.values["send-key"] && !ctx.values["auto-send"]) {
|
|
851
|
-
logger$
|
|
1223
|
+
logger$6.error("--send-key requires --auto-send to be enabled");
|
|
852
1224
|
process.exit(1);
|
|
853
1225
|
}
|
|
854
1226
|
const config = readSendConfig();
|
|
@@ -856,12 +1228,6 @@ const inputCommand = define({
|
|
|
856
1228
|
}
|
|
857
1229
|
});
|
|
858
1230
|
|
|
859
|
-
//#endregion
|
|
860
|
-
//#region src/config/constants.ts
|
|
861
|
-
const TEMP_FILE_PREFIX = ".editprompt-";
|
|
862
|
-
const TEMP_FILE_EXTENSION = ".md";
|
|
863
|
-
const DEFAULT_EDITOR = "vim";
|
|
864
|
-
|
|
865
1231
|
//#endregion
|
|
866
1232
|
//#region src/utils/envParser.ts
|
|
867
1233
|
/**
|
|
@@ -948,8 +1314,9 @@ async function openEditorAndGetContent(editorOption, envVars, sendConfig) {
|
|
|
948
1314
|
|
|
949
1315
|
//#endregion
|
|
950
1316
|
//#region src/modes/openEditor.ts
|
|
951
|
-
const logger$
|
|
1317
|
+
const logger$5 = getLogger(["editprompt", "open"]);
|
|
952
1318
|
async function runOpenEditorMode(options) {
|
|
1319
|
+
let herdrEditorPaneId;
|
|
953
1320
|
if (options.targetPanes.length > 0 && options.mux === "tmux") try {
|
|
954
1321
|
await markAsEditorPane$1(await getCurrentPaneId$1(), options.targetPanes);
|
|
955
1322
|
} catch {}
|
|
@@ -957,16 +1324,21 @@ async function runOpenEditorMode(options) {
|
|
|
957
1324
|
const currentPaneId = await getCurrentPaneId();
|
|
958
1325
|
await markAsEditorPane(currentPaneId, options.targetPanes);
|
|
959
1326
|
} catch {}
|
|
1327
|
+
else if (options.targetPanes.length > 0 && options.mux === "herdr") try {
|
|
1328
|
+
const currentPaneId = await getCurrentPaneId$2();
|
|
1329
|
+
herdrEditorPaneId = currentPaneId;
|
|
1330
|
+
await markAsEditorPane$2(currentPaneId, options.targetPanes);
|
|
1331
|
+
} catch {}
|
|
960
1332
|
try {
|
|
961
1333
|
const sendConfig = {
|
|
962
1334
|
mux: options.mux,
|
|
963
1335
|
alwaysCopy: options.alwaysCopy,
|
|
964
1336
|
sendKeyDelay: Number.parseInt(process.env.EDITPROMPT_SEND_KEY_DELAY || "", 10) || 1e3
|
|
965
1337
|
};
|
|
966
|
-
logger$
|
|
1338
|
+
logger$5.info("Opening editor...");
|
|
967
1339
|
const content = await openEditorAndGetContent(options.editor, options.env, sendConfig);
|
|
968
1340
|
if (!content) {
|
|
969
|
-
logger$
|
|
1341
|
+
logger$5.info("No content entered. Exiting.");
|
|
970
1342
|
return;
|
|
971
1343
|
}
|
|
972
1344
|
try {
|
|
@@ -975,12 +1347,12 @@ async function runOpenEditorMode(options) {
|
|
|
975
1347
|
console.log(content);
|
|
976
1348
|
if (options.alwaysCopy && !result.allFailed) {
|
|
977
1349
|
await copyToClipboard(content);
|
|
978
|
-
logger$
|
|
1350
|
+
logger$5.info("Also copied to clipboard.");
|
|
979
1351
|
}
|
|
980
1352
|
if (options.targetPanes.length > 0 && result.successCount > 0) await focusFirstSuccessPane(options.mux, options.targetPanes, result.failedPanes);
|
|
981
1353
|
if (!result.allSuccess) process.exit(1);
|
|
982
1354
|
} catch (error) {
|
|
983
|
-
logger$
|
|
1355
|
+
logger$5.error(`${error instanceof Error ? error.message : "Unknown error"}`);
|
|
984
1356
|
process.exit(1);
|
|
985
1357
|
}
|
|
986
1358
|
} finally {
|
|
@@ -990,6 +1362,9 @@ async function runOpenEditorMode(options) {
|
|
|
990
1362
|
else if (options.targetPanes.length > 0 && options.mux === "wezterm") try {
|
|
991
1363
|
for (const targetPane of options.targetPanes) await clearEditorPaneId(targetPane);
|
|
992
1364
|
} catch {}
|
|
1365
|
+
else if (options.targetPanes.length > 0 && options.mux === "herdr") try {
|
|
1366
|
+
for (const targetPane of options.targetPanes) await clearEditorPaneId$2(targetPane, herdrEditorPaneId);
|
|
1367
|
+
} catch {}
|
|
993
1368
|
}
|
|
994
1369
|
}
|
|
995
1370
|
const openCommand = define({
|
|
@@ -1003,12 +1378,7 @@ const openCommand = define({
|
|
|
1003
1378
|
"log-file": ARG_LOG_FILE,
|
|
1004
1379
|
quiet: ARG_QUIET,
|
|
1005
1380
|
verbose: ARG_VERBOSE,
|
|
1006
|
-
env:
|
|
1007
|
-
short: "E",
|
|
1008
|
-
description: "Environment variables to set (e.g., KEY=VALUE)",
|
|
1009
|
-
type: "string",
|
|
1010
|
-
multiple: true
|
|
1011
|
-
}
|
|
1381
|
+
env: ARG_ENV
|
|
1012
1382
|
},
|
|
1013
1383
|
async run(ctx) {
|
|
1014
1384
|
setupLogger({
|
|
@@ -1028,10 +1398,10 @@ const openCommand = define({
|
|
|
1028
1398
|
|
|
1029
1399
|
//#endregion
|
|
1030
1400
|
//#region src/modes/register.ts
|
|
1031
|
-
const logger$
|
|
1401
|
+
const logger$4 = getLogger(["editprompt", "register"]);
|
|
1032
1402
|
async function runRegisterMode(options) {
|
|
1033
1403
|
if (options.targetPanes.length === 0) {
|
|
1034
|
-
logger$
|
|
1404
|
+
logger$4.error("--target-pane is required for register command");
|
|
1035
1405
|
process.exit(1);
|
|
1036
1406
|
}
|
|
1037
1407
|
let editorPaneId;
|
|
@@ -1039,29 +1409,37 @@ async function runRegisterMode(options) {
|
|
|
1039
1409
|
else if (options.mux === "tmux") {
|
|
1040
1410
|
editorPaneId = await getCurrentPaneId$1();
|
|
1041
1411
|
if (!await isEditorPane(editorPaneId)) {
|
|
1042
|
-
logger$
|
|
1412
|
+
logger$4.error("Current pane is not an editor pane. Please run this command from an editor pane or specify --editor-pane.");
|
|
1043
1413
|
process.exit(1);
|
|
1044
1414
|
}
|
|
1045
1415
|
} else if (options.mux === "wezterm") {
|
|
1046
1416
|
editorPaneId = await getCurrentPaneId();
|
|
1047
1417
|
if (!isEditorPaneFromConf(editorPaneId)) {
|
|
1048
|
-
logger$
|
|
1418
|
+
logger$4.error("Current pane is not an editor pane. Please run this command from an editor pane or specify --editor-pane.");
|
|
1419
|
+
process.exit(1);
|
|
1420
|
+
}
|
|
1421
|
+
} else if (options.mux === "herdr") {
|
|
1422
|
+
editorPaneId = await getCurrentPaneId$2();
|
|
1423
|
+
if (!isEditorPaneFromConf$1(editorPaneId)) {
|
|
1424
|
+
logger$4.error("Current pane is not an editor pane. Please run this command from an editor pane or specify --editor-pane.");
|
|
1049
1425
|
process.exit(1);
|
|
1050
1426
|
}
|
|
1051
1427
|
} else {
|
|
1052
|
-
logger$
|
|
1428
|
+
logger$4.error("Unsupported multiplexer");
|
|
1053
1429
|
process.exit(1);
|
|
1054
1430
|
}
|
|
1055
1431
|
try {
|
|
1056
1432
|
let existingPanes = [];
|
|
1057
1433
|
if (options.mux === "tmux") existingPanes = await getTargetPaneIds$1(editorPaneId);
|
|
1058
1434
|
else if (options.mux === "wezterm") existingPanes = await getTargetPaneIds(editorPaneId);
|
|
1435
|
+
else if (options.mux === "herdr") existingPanes = await getTargetPaneIds$2(editorPaneId);
|
|
1059
1436
|
const mergedTargetPanes = [...new Set([...existingPanes, ...options.targetPanes])];
|
|
1060
1437
|
if (options.mux === "tmux") await markAsEditorPane$1(editorPaneId, mergedTargetPanes);
|
|
1061
1438
|
else if (options.mux === "wezterm") await markAsEditorPane(editorPaneId, mergedTargetPanes);
|
|
1062
|
-
|
|
1439
|
+
else if (options.mux === "herdr") await markAsEditorPane$2(editorPaneId, mergedTargetPanes);
|
|
1440
|
+
logger$4.info(`Editor pane ${editorPaneId} registered with target panes: ${mergedTargetPanes.join(", ")}`);
|
|
1063
1441
|
} catch (error) {
|
|
1064
|
-
logger$
|
|
1442
|
+
logger$4.error(`${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1065
1443
|
process.exit(1);
|
|
1066
1444
|
}
|
|
1067
1445
|
}
|
|
@@ -1096,15 +1474,21 @@ const registerCommand = define({
|
|
|
1096
1474
|
|
|
1097
1475
|
//#endregion
|
|
1098
1476
|
//#region src/modes/resume.ts
|
|
1099
|
-
const logger$
|
|
1477
|
+
const logger$3 = getLogger(["editprompt", "resume"]);
|
|
1100
1478
|
async function runResumeMode(targetPane, mux) {
|
|
1479
|
+
if (mux === "herdr") try {
|
|
1480
|
+
process.exit(await resumeEditorPane(targetPane) ? 0 : 1);
|
|
1481
|
+
} catch (error) {
|
|
1482
|
+
logger$3.debug("Herdr resume failed: {error}", { error });
|
|
1483
|
+
process.exit(1);
|
|
1484
|
+
}
|
|
1101
1485
|
if (mux === "wezterm") {
|
|
1102
1486
|
const currentPaneId = await getCurrentPaneId();
|
|
1103
1487
|
if (isEditorPaneFromConf(currentPaneId)) {
|
|
1104
|
-
logger$
|
|
1488
|
+
logger$3.debug("Current pane is an editor pane");
|
|
1105
1489
|
const originalTargetPaneIds = await getTargetPaneIds(currentPaneId);
|
|
1106
1490
|
if (originalTargetPaneIds.length === 0) {
|
|
1107
|
-
logger$
|
|
1491
|
+
logger$3.debug("No target pane IDs found for editor pane");
|
|
1108
1492
|
process.exit(1);
|
|
1109
1493
|
}
|
|
1110
1494
|
let focused = false;
|
|
@@ -1114,20 +1498,20 @@ async function runResumeMode(targetPane, mux) {
|
|
|
1114
1498
|
break;
|
|
1115
1499
|
}
|
|
1116
1500
|
if (!focused) {
|
|
1117
|
-
logger$
|
|
1501
|
+
logger$3.debug("All target panes do not exist");
|
|
1118
1502
|
process.exit(1);
|
|
1119
1503
|
}
|
|
1120
1504
|
process.exit(0);
|
|
1121
1505
|
}
|
|
1122
|
-
logger$
|
|
1506
|
+
logger$3.debug("Current pane is not an editor pane");
|
|
1123
1507
|
const editorPaneId = await getEditorPaneId(targetPane);
|
|
1124
|
-
logger$
|
|
1508
|
+
logger$3.debug("wezterm editorPaneId: {editorPaneId}", { editorPaneId });
|
|
1125
1509
|
if (editorPaneId === "") {
|
|
1126
|
-
logger$
|
|
1510
|
+
logger$3.debug("Editor pane ID not found");
|
|
1127
1511
|
process.exit(1);
|
|
1128
1512
|
}
|
|
1129
1513
|
if (!await checkPaneExists(editorPaneId)) {
|
|
1130
|
-
logger$
|
|
1514
|
+
logger$3.debug("Editor pane does not exist");
|
|
1131
1515
|
await clearEditorPaneId(targetPane);
|
|
1132
1516
|
process.exit(1);
|
|
1133
1517
|
}
|
|
@@ -1135,7 +1519,7 @@ async function runResumeMode(targetPane, mux) {
|
|
|
1135
1519
|
await focusPane(editorPaneId);
|
|
1136
1520
|
process.exit(0);
|
|
1137
1521
|
} catch (error) {
|
|
1138
|
-
logger$
|
|
1522
|
+
logger$3.debug("Can't focus editorPaneId: {editorPaneId}, error: {error}", {
|
|
1139
1523
|
editorPaneId,
|
|
1140
1524
|
error
|
|
1141
1525
|
});
|
|
@@ -1186,10 +1570,10 @@ const resumeCommand = define({
|
|
|
1186
1570
|
|
|
1187
1571
|
//#endregion
|
|
1188
1572
|
//#region src/modes/press.ts
|
|
1189
|
-
const logger$
|
|
1573
|
+
const logger$2 = getLogger(["editprompt", "press"]);
|
|
1190
1574
|
async function runPressMode(key, delay = 0) {
|
|
1191
1575
|
if (!key) {
|
|
1192
|
-
logger$
|
|
1576
|
+
logger$2.error("Key is required");
|
|
1193
1577
|
process.exit(1);
|
|
1194
1578
|
}
|
|
1195
1579
|
const config = readSendConfig();
|
|
@@ -1198,32 +1582,37 @@ async function runPressMode(key, delay = 0) {
|
|
|
1198
1582
|
if (config.mux === "tmux") {
|
|
1199
1583
|
currentPaneId = await getCurrentPaneId$1();
|
|
1200
1584
|
isEditor = await isEditorPane(currentPaneId);
|
|
1201
|
-
} else {
|
|
1585
|
+
} else if (config.mux === "wezterm") {
|
|
1202
1586
|
currentPaneId = await getCurrentPaneId();
|
|
1203
1587
|
isEditor = isEditorPaneFromConf(currentPaneId);
|
|
1588
|
+
} else {
|
|
1589
|
+
currentPaneId = await getCurrentPaneId$2();
|
|
1590
|
+
isEditor = isEditorPaneFromConf$1(currentPaneId);
|
|
1204
1591
|
}
|
|
1205
1592
|
if (!isEditor) {
|
|
1206
|
-
logger$
|
|
1593
|
+
logger$2.error("Current pane is not an editor pane");
|
|
1207
1594
|
process.exit(1);
|
|
1208
1595
|
}
|
|
1209
1596
|
let targetPanes;
|
|
1210
1597
|
if (config.mux === "tmux") targetPanes = await getTargetPaneIds$1(currentPaneId);
|
|
1211
|
-
else targetPanes = await getTargetPaneIds(currentPaneId);
|
|
1598
|
+
else if (config.mux === "wezterm") targetPanes = await getTargetPaneIds(currentPaneId);
|
|
1599
|
+
else targetPanes = await getTargetPaneIds$2(currentPaneId);
|
|
1212
1600
|
if (targetPanes.length === 0) {
|
|
1213
|
-
logger$
|
|
1601
|
+
logger$2.error("No target panes registered for this editor pane");
|
|
1214
1602
|
process.exit(1);
|
|
1215
1603
|
}
|
|
1216
1604
|
let successCount = 0;
|
|
1217
1605
|
for (const targetPane of targetPanes) try {
|
|
1218
1606
|
if (config.mux === "wezterm") await sendKeyToWeztermPane(targetPane, key, delay);
|
|
1607
|
+
else if (config.mux === "herdr") await sendKeyToHerdrPane(targetPane, key, delay);
|
|
1219
1608
|
else await sendKeyToTmuxPane(targetPane, key, delay);
|
|
1220
1609
|
successCount++;
|
|
1221
1610
|
} catch (error) {
|
|
1222
|
-
logger$
|
|
1611
|
+
logger$2.warn(`Failed to send key to pane ${targetPane}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1223
1612
|
}
|
|
1224
|
-
if (successCount > 0) logger$
|
|
1613
|
+
if (successCount > 0) logger$2.info("Key sent successfully!");
|
|
1225
1614
|
else {
|
|
1226
|
-
logger$
|
|
1615
|
+
logger$2.error("All target panes failed to receive key");
|
|
1227
1616
|
process.exit(1);
|
|
1228
1617
|
}
|
|
1229
1618
|
}
|
|
@@ -1247,8 +1636,8 @@ const pressCommand = define({
|
|
|
1247
1636
|
});
|
|
1248
1637
|
const key = extractRawContent(ctx.rest, ctx.positionals);
|
|
1249
1638
|
if (key === void 0 || key === "") {
|
|
1250
|
-
logger$
|
|
1251
|
-
logger$
|
|
1639
|
+
logger$2.error("Key is required for press command");
|
|
1640
|
+
logger$2.error("Usage: editprompt press -- \"Tab\"");
|
|
1252
1641
|
process.exit(1);
|
|
1253
1642
|
}
|
|
1254
1643
|
await runPressMode(key, ctx.values.delay ? Number(ctx.values.delay) : 0);
|
|
@@ -1257,9 +1646,9 @@ const pressCommand = define({
|
|
|
1257
1646
|
|
|
1258
1647
|
//#endregion
|
|
1259
1648
|
//#region src/modes/stash.ts
|
|
1260
|
-
const logger = getLogger(["editprompt", "stash"]);
|
|
1649
|
+
const logger$1 = getLogger(["editprompt", "stash"]);
|
|
1261
1650
|
function getStashKey(mux, targetPaneId) {
|
|
1262
|
-
return `${mux}.targetPane.pane_${targetPaneId}.stash`;
|
|
1651
|
+
return `${mux === "herdr" ? getStorageNamespace() : mux}.targetPane.pane_${targetPaneId}.stash`;
|
|
1263
1652
|
}
|
|
1264
1653
|
async function pushStash(mux, targetPaneId, content) {
|
|
1265
1654
|
const key = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1306,19 +1695,23 @@ async function getTargetPaneForStash() {
|
|
|
1306
1695
|
if (config.mux === "tmux") {
|
|
1307
1696
|
currentPaneId = await getCurrentPaneId$1();
|
|
1308
1697
|
isEditor = await isEditorPane(currentPaneId);
|
|
1309
|
-
} else {
|
|
1698
|
+
} else if (config.mux === "wezterm") {
|
|
1310
1699
|
currentPaneId = await getCurrentPaneId();
|
|
1311
1700
|
isEditor = isEditorPaneFromConf(currentPaneId);
|
|
1701
|
+
} else {
|
|
1702
|
+
currentPaneId = await getCurrentPaneId$2();
|
|
1703
|
+
isEditor = isEditorPaneFromConf$1(currentPaneId);
|
|
1312
1704
|
}
|
|
1313
1705
|
if (!isEditor) {
|
|
1314
|
-
logger.error("Current pane is not an editor pane");
|
|
1706
|
+
logger$1.error("Current pane is not an editor pane");
|
|
1315
1707
|
process.exit(1);
|
|
1316
1708
|
}
|
|
1317
1709
|
let targetPanes;
|
|
1318
1710
|
if (config.mux === "tmux") targetPanes = await getTargetPaneIds$1(currentPaneId);
|
|
1319
|
-
else targetPanes = await getTargetPaneIds(currentPaneId);
|
|
1711
|
+
else if (config.mux === "wezterm") targetPanes = await getTargetPaneIds(currentPaneId);
|
|
1712
|
+
else targetPanes = await getTargetPaneIds$2(currentPaneId);
|
|
1320
1713
|
if (targetPanes.length === 0) {
|
|
1321
|
-
logger.error("No target panes registered for this editor pane");
|
|
1714
|
+
logger$1.error("No target panes registered for this editor pane");
|
|
1322
1715
|
process.exit(1);
|
|
1323
1716
|
}
|
|
1324
1717
|
return {
|
|
@@ -1329,13 +1722,13 @@ async function getTargetPaneForStash() {
|
|
|
1329
1722
|
async function runPush(rest, positionals) {
|
|
1330
1723
|
const rawContent = extractRawContent(rest, positionals);
|
|
1331
1724
|
if (rawContent === void 0 || rawContent.trim() === "") {
|
|
1332
|
-
logger.error("Content is required for stash push");
|
|
1333
|
-
logger.error("Usage: editprompt stash push -- \"your content\"");
|
|
1725
|
+
logger$1.error("Content is required for stash push");
|
|
1726
|
+
logger$1.error("Usage: editprompt stash push -- \"your content\"");
|
|
1334
1727
|
process.exit(1);
|
|
1335
1728
|
}
|
|
1336
1729
|
const { mux, targetPaneId } = await getTargetPaneForStash();
|
|
1337
1730
|
const key = await pushStash(mux, targetPaneId, rawContent);
|
|
1338
|
-
logger.info("Stashed with key: {key}", { key });
|
|
1731
|
+
logger$1.info("Stashed with key: {key}", { key });
|
|
1339
1732
|
}
|
|
1340
1733
|
async function runList() {
|
|
1341
1734
|
const { mux, targetPaneId } = await getTargetPaneForStash();
|
|
@@ -1346,8 +1739,8 @@ async function runApply(key) {
|
|
|
1346
1739
|
const { mux, targetPaneId } = await getTargetPaneForStash();
|
|
1347
1740
|
const content = getStashContent(mux, targetPaneId, key);
|
|
1348
1741
|
if (content === "") {
|
|
1349
|
-
if (key) logger.error("No stash entry found with key: {key}", { key });
|
|
1350
|
-
else logger.error("No stash entries found");
|
|
1742
|
+
if (key) logger$1.error("No stash entry found with key: {key}", { key });
|
|
1743
|
+
else logger$1.error("No stash entries found");
|
|
1351
1744
|
process.exit(1);
|
|
1352
1745
|
}
|
|
1353
1746
|
process.stdout.write(content);
|
|
@@ -1355,18 +1748,18 @@ async function runApply(key) {
|
|
|
1355
1748
|
async function runDrop(key) {
|
|
1356
1749
|
const { mux, targetPaneId } = await getTargetPaneForStash();
|
|
1357
1750
|
if (!dropStash(mux, targetPaneId, key)) {
|
|
1358
|
-
if (key) logger.error("No stash entry found with key: {key}", { key });
|
|
1359
|
-
else logger.error("No stash entries found");
|
|
1751
|
+
if (key) logger$1.error("No stash entry found with key: {key}", { key });
|
|
1752
|
+
else logger$1.error("No stash entries found");
|
|
1360
1753
|
process.exit(1);
|
|
1361
1754
|
}
|
|
1362
|
-
logger.info("Stash entry dropped");
|
|
1755
|
+
logger$1.info("Stash entry dropped");
|
|
1363
1756
|
}
|
|
1364
1757
|
async function runPop(key) {
|
|
1365
1758
|
const { mux, targetPaneId } = await getTargetPaneForStash();
|
|
1366
1759
|
const content = getStashContent(mux, targetPaneId, key);
|
|
1367
1760
|
if (content === "") {
|
|
1368
|
-
if (key) logger.error("No stash entry found with key: {key}", { key });
|
|
1369
|
-
else logger.error("No stash entries found");
|
|
1761
|
+
if (key) logger$1.error("No stash entry found with key: {key}", { key });
|
|
1762
|
+
else logger$1.error("No stash entries found");
|
|
1370
1763
|
process.exit(1);
|
|
1371
1764
|
}
|
|
1372
1765
|
process.stdout.write(content);
|
|
@@ -1430,14 +1823,107 @@ const stashCommand = define({
|
|
|
1430
1823
|
await runPop(parseKeyOption(subArgs));
|
|
1431
1824
|
break;
|
|
1432
1825
|
default:
|
|
1433
|
-
logger.error("Unknown subcommand '{subcommand}'", { subcommand });
|
|
1434
|
-
logger.error("");
|
|
1826
|
+
logger$1.error("Unknown subcommand '{subcommand}'", { subcommand });
|
|
1827
|
+
logger$1.error("");
|
|
1435
1828
|
showHelp();
|
|
1436
1829
|
process.exit(1);
|
|
1437
1830
|
}
|
|
1438
1831
|
}
|
|
1439
1832
|
});
|
|
1440
1833
|
|
|
1834
|
+
//#endregion
|
|
1835
|
+
//#region src/modes/toggle.ts
|
|
1836
|
+
const logger = getLogger(["editprompt", "toggle"]);
|
|
1837
|
+
const DEFAULT_EDITOR_PANE_ROWS = 12;
|
|
1838
|
+
function buildOpenEditorArgv(options) {
|
|
1839
|
+
const invocation = options.invocation ?? {
|
|
1840
|
+
execPath: process.execPath,
|
|
1841
|
+
scriptPath: process.argv[1]
|
|
1842
|
+
};
|
|
1843
|
+
if (!invocation.scriptPath) throw new Error("Cannot determine the editprompt entrypoint");
|
|
1844
|
+
const argv = [
|
|
1845
|
+
invocation.execPath,
|
|
1846
|
+
invocation.scriptPath,
|
|
1847
|
+
"open",
|
|
1848
|
+
"--mux",
|
|
1849
|
+
options.mux,
|
|
1850
|
+
"--target-pane",
|
|
1851
|
+
options.targetPane
|
|
1852
|
+
];
|
|
1853
|
+
if (options.editor) argv.push("--editor", options.editor);
|
|
1854
|
+
if (options.alwaysCopy) argv.push("--always-copy");
|
|
1855
|
+
for (const env of options.env ?? []) argv.push("--env", env);
|
|
1856
|
+
if (options.logFile) argv.push("--log-file", options.logFile);
|
|
1857
|
+
if (options.quiet) argv.push("--quiet");
|
|
1858
|
+
if (options.verbose) argv.push("--verbose");
|
|
1859
|
+
return argv;
|
|
1860
|
+
}
|
|
1861
|
+
async function runToggleMode(options, herdrApi = herdr_exports) {
|
|
1862
|
+
if (options.mux !== "herdr") throw new Error("toggle currently supports only the Herdr multiplexer");
|
|
1863
|
+
if (!Number.isInteger(options.paneRows) || options.paneRows <= 0) throw new Error("--pane-rows must be a positive integer");
|
|
1864
|
+
if (await herdrApi.resumeEditorPane(options.targetPane)) return;
|
|
1865
|
+
const launchEnv = {};
|
|
1866
|
+
if (process.env.NODE_NO_WARNINGS !== void 0) launchEnv.NODE_NO_WARNINGS = process.env.NODE_NO_WARNINGS;
|
|
1867
|
+
const editorPaneId = await herdrApi.splitEditorPane(options.targetPane, options.paneRows, process.env.HERDR_ACTIVE_PANE_CWD, launchEnv);
|
|
1868
|
+
try {
|
|
1869
|
+
await herdrApi.runCommandInPane(editorPaneId, buildOpenEditorArgv(options));
|
|
1870
|
+
} catch (error) {
|
|
1871
|
+
try {
|
|
1872
|
+
await herdrApi.closePane(editorPaneId);
|
|
1873
|
+
} catch (closeError) {
|
|
1874
|
+
logger.warn("Failed to close editor pane after launch failure: {error}", { error: closeError });
|
|
1875
|
+
}
|
|
1876
|
+
throw error;
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
const toggleCommand = define({
|
|
1880
|
+
name: "toggle",
|
|
1881
|
+
description: "Open or focus an editor pane",
|
|
1882
|
+
args: {
|
|
1883
|
+
mux: ARG_MUX,
|
|
1884
|
+
"target-pane": ARG_TARGET_PANE_SINGLE,
|
|
1885
|
+
"pane-rows": {
|
|
1886
|
+
description: "Desired rows for the Herdr editor pane",
|
|
1887
|
+
type: "number",
|
|
1888
|
+
default: DEFAULT_EDITOR_PANE_ROWS
|
|
1889
|
+
},
|
|
1890
|
+
editor: ARG_EDITOR,
|
|
1891
|
+
"always-copy": ARG_ALWAYS_COPY,
|
|
1892
|
+
env: ARG_ENV,
|
|
1893
|
+
"log-file": ARG_LOG_FILE,
|
|
1894
|
+
quiet: ARG_QUIET,
|
|
1895
|
+
verbose: ARG_VERBOSE
|
|
1896
|
+
},
|
|
1897
|
+
async run(ctx) {
|
|
1898
|
+
const logFile = ctx.values["log-file"];
|
|
1899
|
+
const quiet = Boolean(ctx.values.quiet);
|
|
1900
|
+
const verbose = Boolean(ctx.values.verbose);
|
|
1901
|
+
setupLogger({
|
|
1902
|
+
quiet,
|
|
1903
|
+
verbose,
|
|
1904
|
+
logFile
|
|
1905
|
+
});
|
|
1906
|
+
const targetPane = validateTargetPane(ctx.values["target-pane"], "toggle");
|
|
1907
|
+
const mux = validateMux(ctx.values.mux);
|
|
1908
|
+
try {
|
|
1909
|
+
await runToggleMode({
|
|
1910
|
+
mux,
|
|
1911
|
+
targetPane,
|
|
1912
|
+
paneRows: Number(ctx.values["pane-rows"]),
|
|
1913
|
+
alwaysCopy: Boolean(ctx.values["always-copy"]),
|
|
1914
|
+
editor: ctx.values.editor,
|
|
1915
|
+
env: ctx.values.env,
|
|
1916
|
+
logFile,
|
|
1917
|
+
quiet,
|
|
1918
|
+
verbose
|
|
1919
|
+
});
|
|
1920
|
+
} catch (error) {
|
|
1921
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
1922
|
+
process.exit(1);
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
});
|
|
1926
|
+
|
|
1441
1927
|
//#endregion
|
|
1442
1928
|
//#region src/index.ts
|
|
1443
1929
|
await cli(process.argv.slice(2), {
|
|
@@ -1466,6 +1952,7 @@ await cli(process.argv.slice(2), {
|
|
|
1466
1952
|
open: openCommand,
|
|
1467
1953
|
register: registerCommand,
|
|
1468
1954
|
resume: resumeCommand,
|
|
1955
|
+
toggle: toggleCommand,
|
|
1469
1956
|
input: inputCommand,
|
|
1470
1957
|
press: pressCommand,
|
|
1471
1958
|
collect: collectCommand,
|