editprompt 1.1.1 → 1.3.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 +74 -100
- package/dist/index.js +490 -148
- package/package.json +34 -28
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { configureSync, getAnsiColorFormatter, getLogger, getTextFormatter, parseLogLevel, withFilter } from "@logtape/logtape";
|
|
2
3
|
import { cli, define } from "gunshi";
|
|
4
|
+
import { appendFileSync } from "node:fs";
|
|
3
5
|
import { exec, spawn } from "node:child_process";
|
|
4
6
|
import { promisify } from "node:util";
|
|
5
7
|
import Conf from "conf";
|
|
@@ -8,23 +10,86 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
|
8
10
|
import { tmpdir } from "node:os";
|
|
9
11
|
import { join } from "node:path";
|
|
10
12
|
|
|
13
|
+
//#region src/modules/logger.ts
|
|
14
|
+
function resolveLogFilePath(options) {
|
|
15
|
+
if (options.logFile) return options.logFile;
|
|
16
|
+
const envPath = process.env.EDITPROMPT_LOG_FILE;
|
|
17
|
+
if (envPath) return envPath;
|
|
18
|
+
}
|
|
19
|
+
function resolveFileLogLevel(options) {
|
|
20
|
+
if (options.verbose) return "debug";
|
|
21
|
+
const envLevel = process.env.EDITPROMPT_LOG_LEVEL;
|
|
22
|
+
if (envLevel) return parseLogLevel(envLevel);
|
|
23
|
+
return "info";
|
|
24
|
+
}
|
|
25
|
+
function resolveLogLevel(options) {
|
|
26
|
+
if (options.quiet) return null;
|
|
27
|
+
if (options.verbose) return "debug";
|
|
28
|
+
const envLevel = process.env.EDITPROMPT_LOG_LEVEL;
|
|
29
|
+
if (envLevel) return parseLogLevel(envLevel);
|
|
30
|
+
return "info";
|
|
31
|
+
}
|
|
32
|
+
function setupLogger(options = {}) {
|
|
33
|
+
const stderrLevel = resolveLogLevel(options);
|
|
34
|
+
const stderrFormatter = getAnsiColorFormatter({
|
|
35
|
+
timestamp: "time-timezone",
|
|
36
|
+
level: "ABBR"
|
|
37
|
+
});
|
|
38
|
+
const rawStderrSink = (record) => {
|
|
39
|
+
process.stderr.write(stderrFormatter(record));
|
|
40
|
+
};
|
|
41
|
+
const sinks = { stderr: stderrLevel === null ? () => {} : withFilter(rawStderrSink, stderrLevel) };
|
|
42
|
+
const loggerSinks = ["stderr"];
|
|
43
|
+
const logFilePath = resolveLogFilePath(options);
|
|
44
|
+
const fileLogLevel = resolveFileLogLevel(options);
|
|
45
|
+
if (logFilePath) try {
|
|
46
|
+
appendFileSync(logFilePath, "");
|
|
47
|
+
const fileFormatter = getTextFormatter({
|
|
48
|
+
timestamp: "date-time-timezone",
|
|
49
|
+
level: "ABBR"
|
|
50
|
+
});
|
|
51
|
+
const rawFileSink = (record) => {
|
|
52
|
+
appendFileSync(logFilePath, fileFormatter(record));
|
|
53
|
+
};
|
|
54
|
+
sinks.file = withFilter(rawFileSink, fileLogLevel);
|
|
55
|
+
loggerSinks.push("file");
|
|
56
|
+
} catch {
|
|
57
|
+
process.stderr.write(`Warning: Cannot write to log file '${logFilePath}', continuing without file logging.\n`);
|
|
58
|
+
}
|
|
59
|
+
configureSync({
|
|
60
|
+
sinks,
|
|
61
|
+
loggers: [{
|
|
62
|
+
category: ["editprompt"],
|
|
63
|
+
sinks: loggerSinks,
|
|
64
|
+
lowestLevel: "trace"
|
|
65
|
+
}, {
|
|
66
|
+
category: ["logtape", "meta"],
|
|
67
|
+
lowestLevel: null
|
|
68
|
+
}]
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
//#endregion
|
|
11
73
|
//#region package.json
|
|
12
|
-
var version = "1.
|
|
74
|
+
var version = "1.3.0";
|
|
13
75
|
|
|
14
76
|
//#endregion
|
|
15
77
|
//#region src/modules/tmux.ts
|
|
16
78
|
const execAsync$1 = promisify(exec);
|
|
17
|
-
|
|
79
|
+
const logger$10 = getLogger(["editprompt", "tmux"]);
|
|
80
|
+
async function getCurrentPaneId$1() {
|
|
81
|
+
const envPaneId = process.env.TMUX_PANE?.trim();
|
|
82
|
+
if (envPaneId) return envPaneId;
|
|
18
83
|
const { stdout } = await execAsync$1("tmux display-message -p \"#{pane_id}\"");
|
|
19
84
|
return stdout.trim();
|
|
20
85
|
}
|
|
21
86
|
async function saveEditorPaneId$1(targetPaneId, editorPaneId) {
|
|
22
87
|
await execAsync$1(`tmux set-option -pt '${targetPaneId}' @editprompt_editor_pane '${editorPaneId}'`);
|
|
23
88
|
}
|
|
24
|
-
async function clearEditorPaneId(targetPaneId) {
|
|
89
|
+
async function clearEditorPaneId$1(targetPaneId) {
|
|
25
90
|
await execAsync$1(`tmux set-option -pt '${targetPaneId}' @editprompt_editor_pane ""`);
|
|
26
91
|
}
|
|
27
|
-
async function getEditorPaneId(targetPaneId) {
|
|
92
|
+
async function getEditorPaneId$1(targetPaneId) {
|
|
28
93
|
try {
|
|
29
94
|
const { stdout } = await execAsync$1(`tmux show -pt '${targetPaneId}' -v @editprompt_editor_pane`);
|
|
30
95
|
return stdout.trim();
|
|
@@ -32,7 +97,7 @@ async function getEditorPaneId(targetPaneId) {
|
|
|
32
97
|
return "";
|
|
33
98
|
}
|
|
34
99
|
}
|
|
35
|
-
async function checkPaneExists(paneId) {
|
|
100
|
+
async function checkPaneExists$1(paneId) {
|
|
36
101
|
try {
|
|
37
102
|
const { stdout } = await execAsync$1("tmux list-panes -a -F \"#{pane_id}\"");
|
|
38
103
|
return stdout.split("\n").map((id) => id.trim()).includes(paneId);
|
|
@@ -40,16 +105,16 @@ async function checkPaneExists(paneId) {
|
|
|
40
105
|
return false;
|
|
41
106
|
}
|
|
42
107
|
}
|
|
43
|
-
async function focusPane(paneId) {
|
|
108
|
+
async function focusPane$1(paneId) {
|
|
44
109
|
await execAsync$1(`tmux select-pane -t '${paneId}'`);
|
|
45
110
|
}
|
|
46
|
-
async function markAsEditorPane(editorPaneId, targetPaneIds) {
|
|
111
|
+
async function markAsEditorPane$1(editorPaneId, targetPaneIds) {
|
|
47
112
|
await execAsync$1(`tmux set-option -pt '${editorPaneId}' @editprompt_is_editor 1`);
|
|
48
113
|
const uniqueTargetPaneIds = [...new Set(targetPaneIds)];
|
|
49
114
|
await execAsync$1(`tmux set-option -pt '${editorPaneId}' @editprompt_target_panes '${uniqueTargetPaneIds.join(",")}'`);
|
|
50
115
|
for (const targetPaneId of uniqueTargetPaneIds) await saveEditorPaneId$1(targetPaneId, editorPaneId);
|
|
51
116
|
}
|
|
52
|
-
async function getTargetPaneIds(editorPaneId) {
|
|
117
|
+
async function getTargetPaneIds$1(editorPaneId) {
|
|
53
118
|
try {
|
|
54
119
|
const { stdout } = await execAsync$1(`tmux show -pt '${editorPaneId}' -v @editprompt_target_panes`);
|
|
55
120
|
const value = stdout.trim();
|
|
@@ -85,81 +150,85 @@ async function appendToQuoteVariable(paneId, content) {
|
|
|
85
150
|
async function clearQuoteVariable(targetPaneId) {
|
|
86
151
|
await execAsync$1(`tmux set-option -pt '${targetPaneId}' @editprompt_quote ""`);
|
|
87
152
|
}
|
|
88
|
-
async function sendKeyToTmuxPane(paneId, key) {
|
|
89
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
153
|
+
async function sendKeyToTmuxPane(paneId, key, delay = 1e3) {
|
|
154
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
90
155
|
await execAsync$1(`tmux send-keys -t '${paneId}' '${key}'`);
|
|
91
156
|
}
|
|
92
157
|
async function inputToTmuxPane(paneId, content) {
|
|
93
158
|
await execAsync$1(`tmux if-shell -t '${paneId}' '[ "#{pane_in_mode}" = "1" ]' "copy-mode -q -t '${paneId}'"`);
|
|
94
159
|
await execAsync$1(`tmux send-keys -t '${paneId}' -- '${content.replace(/'/g, "'\\''")}'`);
|
|
95
|
-
|
|
160
|
+
logger$10.debug("Content sent to tmux pane: {paneId}", { paneId });
|
|
96
161
|
}
|
|
97
162
|
|
|
98
163
|
//#endregion
|
|
99
|
-
//#region src/modules/
|
|
100
|
-
const execAsync = promisify(exec);
|
|
164
|
+
//#region src/modules/conf.ts
|
|
101
165
|
const projectName = process.env.NODE_ENV === "test" ? "editprompt-test" : "editprompt";
|
|
102
166
|
const conf = new Conf({ projectName });
|
|
103
|
-
|
|
167
|
+
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region src/modules/wezterm.ts
|
|
170
|
+
const logger$9 = getLogger(["editprompt", "wezterm"]);
|
|
171
|
+
const execAsync = promisify(exec);
|
|
172
|
+
async function getCurrentPaneId() {
|
|
104
173
|
try {
|
|
105
174
|
const { stdout } = await execAsync("wezterm cli list --format json");
|
|
106
175
|
const activePane = JSON.parse(stdout).find((pane) => pane.is_active === true);
|
|
107
176
|
return String(activePane?.pane_id);
|
|
108
177
|
} catch (error) {
|
|
109
|
-
|
|
178
|
+
logger$9.debug("getCurrentPaneId failed: {error}", { error });
|
|
110
179
|
return "";
|
|
111
180
|
}
|
|
112
181
|
}
|
|
113
|
-
async function checkPaneExists
|
|
182
|
+
async function checkPaneExists(paneId) {
|
|
114
183
|
try {
|
|
115
184
|
const { stdout } = await execAsync("wezterm cli list --format json");
|
|
116
|
-
|
|
185
|
+
logger$9.debug("wezterm cli list output: {stdout}", { stdout });
|
|
117
186
|
return JSON.parse(stdout).some((pane) => String(pane.pane_id) === paneId);
|
|
118
187
|
} catch (error) {
|
|
119
|
-
|
|
188
|
+
logger$9.debug("checkPaneExists failed: {error}", { error });
|
|
120
189
|
return false;
|
|
121
190
|
}
|
|
122
191
|
}
|
|
123
192
|
async function saveEditorPaneId(targetPaneId, editorPaneId) {
|
|
124
|
-
|
|
193
|
+
logger$9.debug("Saving editor pane ID to conf key: wezterm.targetPane.pane_{targetPaneId}", { targetPaneId });
|
|
125
194
|
try {
|
|
126
195
|
conf.set(`wezterm.targetPane.pane_${targetPaneId}`, { editorPaneId });
|
|
127
196
|
} catch (error) {
|
|
128
|
-
|
|
197
|
+
logger$9.debug("saveEditorPaneId failed: {error}", { error });
|
|
129
198
|
}
|
|
130
199
|
}
|
|
131
|
-
async function getEditorPaneId
|
|
200
|
+
async function getEditorPaneId(targetPaneId) {
|
|
132
201
|
try {
|
|
133
202
|
const data = conf.get(`wezterm.targetPane.pane_${targetPaneId}`);
|
|
134
203
|
if (typeof data === "object" && data !== null && "editorPaneId" in data) return String(data.editorPaneId);
|
|
135
204
|
return "";
|
|
136
205
|
} catch (error) {
|
|
137
|
-
|
|
206
|
+
logger$9.debug("getEditorPaneId failed: {error}", { error });
|
|
138
207
|
return "";
|
|
139
208
|
}
|
|
140
209
|
}
|
|
141
|
-
async function clearEditorPaneId
|
|
210
|
+
async function clearEditorPaneId(targetPaneId) {
|
|
142
211
|
try {
|
|
143
|
-
const editorPaneId = await getEditorPaneId
|
|
212
|
+
const editorPaneId = await getEditorPaneId(targetPaneId);
|
|
144
213
|
conf.delete(`wezterm.targetPane.pane_${targetPaneId}`);
|
|
145
214
|
if (editorPaneId) conf.delete(`wezterm.editorPane.pane_${editorPaneId}`);
|
|
146
215
|
} catch (error) {
|
|
147
|
-
|
|
216
|
+
logger$9.debug("clearEditorPaneId failed: {error}", { error });
|
|
148
217
|
}
|
|
149
218
|
}
|
|
150
|
-
async function focusPane
|
|
219
|
+
async function focusPane(paneId) {
|
|
151
220
|
await execAsync(`wezterm cli activate-pane --pane-id '${paneId}'`);
|
|
152
221
|
}
|
|
153
|
-
async function markAsEditorPane
|
|
222
|
+
async function markAsEditorPane(editorPaneId, targetPaneIds) {
|
|
154
223
|
try {
|
|
155
224
|
const uniqueTargetPaneIds = [...new Set(targetPaneIds)];
|
|
156
225
|
conf.set(`wezterm.editorPane.pane_${editorPaneId}`, { targetPaneIds: uniqueTargetPaneIds });
|
|
157
226
|
for (const targetPaneId of uniqueTargetPaneIds) await saveEditorPaneId(targetPaneId, editorPaneId);
|
|
158
227
|
} catch (error) {
|
|
159
|
-
|
|
228
|
+
logger$9.debug("markAsEditorPane failed: {error}", { error });
|
|
160
229
|
}
|
|
161
230
|
}
|
|
162
|
-
async function getTargetPaneIds
|
|
231
|
+
async function getTargetPaneIds(editorPaneId) {
|
|
163
232
|
try {
|
|
164
233
|
const data = conf.get(`wezterm.editorPane.pane_${editorPaneId}`);
|
|
165
234
|
if (typeof data === "object" && data !== null && "targetPaneIds" in data) {
|
|
@@ -168,7 +237,7 @@ async function getTargetPaneIds$1(editorPaneId) {
|
|
|
168
237
|
}
|
|
169
238
|
return [];
|
|
170
239
|
} catch (error) {
|
|
171
|
-
|
|
240
|
+
logger$9.debug("getTargetPaneIds failed: {error}", { error });
|
|
172
241
|
return [];
|
|
173
242
|
}
|
|
174
243
|
}
|
|
@@ -176,7 +245,7 @@ function isEditorPaneFromConf(paneId) {
|
|
|
176
245
|
try {
|
|
177
246
|
return conf.has(`wezterm.editorPane.pane_${paneId}`);
|
|
178
247
|
} catch (error) {
|
|
179
|
-
|
|
248
|
+
logger$9.debug("isEditorPaneFromConf failed: {error}", { error });
|
|
180
249
|
return false;
|
|
181
250
|
}
|
|
182
251
|
}
|
|
@@ -194,7 +263,7 @@ async function appendToQuoteText(paneId, content) {
|
|
|
194
263
|
} else newData = { quote_text: content };
|
|
195
264
|
conf.set(`wezterm.targetPane.pane_${paneId}`, newData);
|
|
196
265
|
} catch (error) {
|
|
197
|
-
|
|
266
|
+
logger$9.debug("appendToQuoteText failed: {error}", { error });
|
|
198
267
|
}
|
|
199
268
|
}
|
|
200
269
|
async function getQuoteText(paneId) {
|
|
@@ -203,7 +272,7 @@ async function getQuoteText(paneId) {
|
|
|
203
272
|
if (typeof data === "object" && data !== null && "quote_text" in data) return String(data.quote_text);
|
|
204
273
|
return "";
|
|
205
274
|
} catch (error) {
|
|
206
|
-
|
|
275
|
+
logger$9.debug("getQuoteText failed: {error}", { error });
|
|
207
276
|
return "";
|
|
208
277
|
}
|
|
209
278
|
}
|
|
@@ -212,15 +281,16 @@ async function clearQuoteText(paneId) {
|
|
|
212
281
|
const key = `wezterm.targetPane.pane_${paneId}.quote_text`;
|
|
213
282
|
if (conf.has(key)) conf.delete(key);
|
|
214
283
|
} catch (error) {
|
|
215
|
-
|
|
284
|
+
logger$9.debug("clearQuoteText failed: {error}", { error });
|
|
216
285
|
}
|
|
217
286
|
}
|
|
218
|
-
async function sendKeyToWeztermPane(paneId, key) {
|
|
287
|
+
async function sendKeyToWeztermPane(paneId, key, delay = 1e3) {
|
|
288
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
219
289
|
await execAsync(`wezterm cli send-text --no-paste --pane-id '${paneId}' $'${key}'`);
|
|
220
290
|
}
|
|
221
291
|
async function inputToWeztermPane(paneId, content) {
|
|
222
292
|
await execAsync(`wezterm cli send-text --no-paste --pane-id '${paneId}' -- '${content.replace(/'/g, "'\\''")}'`);
|
|
223
|
-
|
|
293
|
+
logger$9.debug("Content sent to wezterm pane: {paneId}", { paneId });
|
|
224
294
|
}
|
|
225
295
|
|
|
226
296
|
//#endregion
|
|
@@ -234,8 +304,12 @@ async function inputToWeztermPane(paneId, content) {
|
|
|
234
304
|
* @returns Raw content string or undefined if no content provided
|
|
235
305
|
*/
|
|
236
306
|
function extractRawContent(rest, positionals) {
|
|
237
|
-
if (rest.length > 0)
|
|
238
|
-
|
|
307
|
+
if (rest.length > 0) {
|
|
308
|
+
const joined = rest.join(" ");
|
|
309
|
+
if (joined.trim() !== "") return joined;
|
|
310
|
+
}
|
|
311
|
+
const first = positionals[0];
|
|
312
|
+
if (first !== void 0 && first.trim() !== "") return first;
|
|
239
313
|
}
|
|
240
314
|
|
|
241
315
|
//#endregion
|
|
@@ -358,6 +432,7 @@ function processQuoteText(text, options) {
|
|
|
358
432
|
|
|
359
433
|
//#endregion
|
|
360
434
|
//#region src/modes/common.ts
|
|
435
|
+
const logger$8 = getLogger(["editprompt", "delivery"]);
|
|
361
436
|
function isMuxType(value) {
|
|
362
437
|
return value === "tmux" || value === "wezterm";
|
|
363
438
|
}
|
|
@@ -371,8 +446,8 @@ async function inputContentToPane(content, mux, targetPaneId) {
|
|
|
371
446
|
}
|
|
372
447
|
async function focusFirstSuccessPane(mux, targetPanes, failedPanes) {
|
|
373
448
|
const firstSuccessPane = targetPanes.find((p) => !failedPanes.includes(p));
|
|
374
|
-
if (firstSuccessPane) if (mux === "tmux") await focusPane(firstSuccessPane);
|
|
375
|
-
else await focusPane
|
|
449
|
+
if (firstSuccessPane) if (mux === "tmux") await focusPane$1(firstSuccessPane);
|
|
450
|
+
else await focusPane(firstSuccessPane);
|
|
376
451
|
}
|
|
377
452
|
async function handleContentDelivery(content, mux, targetPanes) {
|
|
378
453
|
if (!content) return {
|
|
@@ -385,9 +460,9 @@ async function handleContentDelivery(content, mux, targetPanes) {
|
|
|
385
460
|
if (targetPanes.length === 0) {
|
|
386
461
|
try {
|
|
387
462
|
await copyToClipboard(content);
|
|
388
|
-
|
|
463
|
+
logger$8.info("Content copied to clipboard.");
|
|
389
464
|
} catch (error) {
|
|
390
|
-
|
|
465
|
+
logger$8.warn(`Failed to copy to clipboard: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
391
466
|
}
|
|
392
467
|
return {
|
|
393
468
|
successCount: 0,
|
|
@@ -405,7 +480,7 @@ async function handleContentDelivery(content, mux, targetPanes) {
|
|
|
405
480
|
success: true
|
|
406
481
|
});
|
|
407
482
|
} catch (error) {
|
|
408
|
-
|
|
483
|
+
logger$8.warn(`Failed to send to pane ${targetPane}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
409
484
|
results.push({
|
|
410
485
|
pane: targetPane,
|
|
411
486
|
success: false
|
|
@@ -415,13 +490,13 @@ async function handleContentDelivery(content, mux, targetPanes) {
|
|
|
415
490
|
const failedPanes = results.filter((r) => !r.success).map((r) => r.pane);
|
|
416
491
|
const allSuccess = successCount === targetPanes.length;
|
|
417
492
|
const allFailed = successCount === 0;
|
|
418
|
-
if (allSuccess)
|
|
493
|
+
if (allSuccess) logger$8.info("Content sent successfully to all panes!");
|
|
419
494
|
else if (allFailed) {
|
|
420
|
-
|
|
421
|
-
|
|
495
|
+
logger$8.error("All target panes failed to receive content.");
|
|
496
|
+
logger$8.info("Falling back to clipboard...");
|
|
422
497
|
await copyToClipboard(content);
|
|
423
|
-
|
|
424
|
-
} else
|
|
498
|
+
logger$8.info("Content copied to clipboard.");
|
|
499
|
+
} else logger$8.warn(`Content sent to ${successCount}/${targetPanes.length} panes. Failed panes: ${failedPanes.join(", ")}`);
|
|
425
500
|
return {
|
|
426
501
|
successCount,
|
|
427
502
|
totalCount: targetPanes.length,
|
|
@@ -433,6 +508,7 @@ async function handleContentDelivery(content, mux, targetPanes) {
|
|
|
433
508
|
|
|
434
509
|
//#endregion
|
|
435
510
|
//#region src/modes/args.ts
|
|
511
|
+
const logger$7 = getLogger(["editprompt"]);
|
|
436
512
|
const ARG_MUX = {
|
|
437
513
|
short: "m",
|
|
438
514
|
description: "Multiplexer type (tmux or wezterm, default: tmux)",
|
|
@@ -467,17 +543,31 @@ const ARG_OUTPUT = {
|
|
|
467
543
|
type: "string",
|
|
468
544
|
multiple: true
|
|
469
545
|
};
|
|
546
|
+
const ARG_LOG_FILE = {
|
|
547
|
+
description: "Write logs to the specified file (appends)",
|
|
548
|
+
type: "string"
|
|
549
|
+
};
|
|
550
|
+
const ARG_QUIET = {
|
|
551
|
+
short: "q",
|
|
552
|
+
description: "Suppress all log output",
|
|
553
|
+
type: "boolean"
|
|
554
|
+
};
|
|
555
|
+
const ARG_VERBOSE = {
|
|
556
|
+
short: "v",
|
|
557
|
+
description: "Enable debug-level log output",
|
|
558
|
+
type: "boolean"
|
|
559
|
+
};
|
|
470
560
|
function validateMux(value) {
|
|
471
561
|
const muxValue = value || "tmux";
|
|
472
562
|
if (!isMuxType(muxValue)) {
|
|
473
|
-
|
|
563
|
+
logger$7.error(`Invalid multiplexer type '${muxValue}'. Supported values: ${SUPPORTED_MUXES.join(", ")}`);
|
|
474
564
|
process.exit(1);
|
|
475
565
|
}
|
|
476
566
|
return muxValue;
|
|
477
567
|
}
|
|
478
568
|
function validateTargetPane(value, commandName) {
|
|
479
569
|
if (!value || typeof value !== "string") {
|
|
480
|
-
|
|
570
|
+
logger$7.error(`--target-pane is required for ${commandName} command`);
|
|
481
571
|
process.exit(1);
|
|
482
572
|
}
|
|
483
573
|
return value;
|
|
@@ -490,6 +580,7 @@ function normalizeTargetPanes(value) {
|
|
|
490
580
|
|
|
491
581
|
//#endregion
|
|
492
582
|
//#region src/modes/collect.ts
|
|
583
|
+
const logger$6 = getLogger(["editprompt", "collect"]);
|
|
493
584
|
const SUPPORTED_OUTPUTS = ["buffer", "stdout"];
|
|
494
585
|
async function readStdin() {
|
|
495
586
|
return new Promise((resolve, reject) => {
|
|
@@ -513,7 +604,7 @@ function normalizeCollectOutputs(value) {
|
|
|
513
604
|
const uniqueOutputs = [...new Set(outputs)];
|
|
514
605
|
const invalid = uniqueOutputs.filter((v) => !SUPPORTED_OUTPUTS.includes(v));
|
|
515
606
|
if (invalid.length > 0) {
|
|
516
|
-
|
|
607
|
+
logger$6.error(`Invalid output(s) '${invalid.join(", ")}'. Supported values: ${SUPPORTED_OUTPUTS.join(", ")}`);
|
|
517
608
|
process.exit(1);
|
|
518
609
|
}
|
|
519
610
|
return uniqueOutputs;
|
|
@@ -529,7 +620,7 @@ async function runCollectMode(mux, targetPaneId, rawContent, outputs = ["buffer"
|
|
|
529
620
|
else if (mux === "wezterm") await appendToQuoteText(targetPaneId, processedText);
|
|
530
621
|
} else if (output === "stdout") process.stdout.write(processedText);
|
|
531
622
|
} catch (error) {
|
|
532
|
-
|
|
623
|
+
logger$6.error(`${error instanceof Error ? error.message : "Unknown error"}`);
|
|
533
624
|
process.exit(1);
|
|
534
625
|
}
|
|
535
626
|
}
|
|
@@ -540,9 +631,17 @@ const collectCommand = define({
|
|
|
540
631
|
mux: ARG_MUX,
|
|
541
632
|
"target-pane": ARG_TARGET_PANE_SINGLE,
|
|
542
633
|
output: ARG_OUTPUT,
|
|
543
|
-
"no-quote": ARG_NO_QUOTE
|
|
634
|
+
"no-quote": ARG_NO_QUOTE,
|
|
635
|
+
"log-file": ARG_LOG_FILE,
|
|
636
|
+
quiet: ARG_QUIET,
|
|
637
|
+
verbose: ARG_VERBOSE
|
|
544
638
|
},
|
|
545
639
|
async run(ctx) {
|
|
640
|
+
setupLogger({
|
|
641
|
+
quiet: Boolean(ctx.values.quiet),
|
|
642
|
+
verbose: Boolean(ctx.values.verbose),
|
|
643
|
+
logFile: ctx.values["log-file"]
|
|
644
|
+
});
|
|
546
645
|
const targetPane = validateTargetPane(ctx.values["target-pane"], "collect");
|
|
547
646
|
const mux = validateMux(ctx.values.mux);
|
|
548
647
|
const outputs = normalizeCollectOutputs(ctx.values.output);
|
|
@@ -551,7 +650,7 @@ const collectCommand = define({
|
|
|
551
650
|
if (mux === "wezterm") {
|
|
552
651
|
rawContent = extractRawContent(ctx.rest, ctx.positionals);
|
|
553
652
|
if (rawContent === void 0) {
|
|
554
|
-
|
|
653
|
+
logger$6.error("Text content is required for collect mode with wezterm. Use: editprompt collect --mux wezterm --target-pane <id> -- \"<text>\"");
|
|
555
654
|
process.exit(1);
|
|
556
655
|
}
|
|
557
656
|
}
|
|
@@ -565,35 +664,41 @@ const VALID_MUX_TYPES = ["tmux", "wezterm"];
|
|
|
565
664
|
function readSendConfig() {
|
|
566
665
|
const muxValue = process.env.EDITPROMPT_MUX || "tmux";
|
|
567
666
|
if (!VALID_MUX_TYPES.includes(muxValue)) throw new Error(`Invalid EDITPROMPT_MUX value: ${muxValue}. Must be one of: ${VALID_MUX_TYPES.join(", ")}`);
|
|
667
|
+
const mux = muxValue;
|
|
668
|
+
const alwaysCopy = process.env.EDITPROMPT_ALWAYS_COPY === "1";
|
|
669
|
+
const delayValue = process.env.EDITPROMPT_SEND_KEY_DELAY;
|
|
670
|
+
const parsedDelay = delayValue ? Number.parseInt(delayValue, 10) : NaN;
|
|
568
671
|
return {
|
|
569
|
-
mux
|
|
570
|
-
alwaysCopy
|
|
672
|
+
mux,
|
|
673
|
+
alwaysCopy,
|
|
674
|
+
sendKeyDelay: Number.isNaN(parsedDelay) ? 1e3 : parsedDelay
|
|
571
675
|
};
|
|
572
676
|
}
|
|
573
677
|
|
|
574
678
|
//#endregion
|
|
575
679
|
//#region src/modes/dump.ts
|
|
680
|
+
const logger$5 = getLogger(["editprompt", "dump"]);
|
|
576
681
|
async function runDumpMode() {
|
|
577
682
|
try {
|
|
578
683
|
const config = readSendConfig();
|
|
579
684
|
let currentPaneId;
|
|
580
685
|
let isEditor;
|
|
581
686
|
if (config.mux === "tmux") {
|
|
582
|
-
currentPaneId = await getCurrentPaneId();
|
|
687
|
+
currentPaneId = await getCurrentPaneId$1();
|
|
583
688
|
isEditor = await isEditorPane(currentPaneId);
|
|
584
689
|
} else {
|
|
585
|
-
currentPaneId = await getCurrentPaneId
|
|
690
|
+
currentPaneId = await getCurrentPaneId();
|
|
586
691
|
isEditor = isEditorPaneFromConf(currentPaneId);
|
|
587
692
|
}
|
|
588
693
|
if (!isEditor) {
|
|
589
|
-
|
|
694
|
+
logger$5.error("Current pane is not an editor pane");
|
|
590
695
|
process.exit(1);
|
|
591
696
|
}
|
|
592
697
|
let targetPanes;
|
|
593
|
-
if (config.mux === "tmux") targetPanes = await getTargetPaneIds(currentPaneId);
|
|
594
|
-
else targetPanes = await getTargetPaneIds
|
|
698
|
+
if (config.mux === "tmux") targetPanes = await getTargetPaneIds$1(currentPaneId);
|
|
699
|
+
else targetPanes = await getTargetPaneIds(currentPaneId);
|
|
595
700
|
if (targetPanes.length === 0) {
|
|
596
|
-
|
|
701
|
+
logger$5.error("No target panes registered for this editor pane");
|
|
597
702
|
process.exit(1);
|
|
598
703
|
}
|
|
599
704
|
const quoteContents = [];
|
|
@@ -612,15 +717,24 @@ async function runDumpMode() {
|
|
|
612
717
|
process.stdout.write(combinedContent.replace(/\n{3,}$/, "\n\n"));
|
|
613
718
|
process.exit(0);
|
|
614
719
|
} catch (error) {
|
|
615
|
-
|
|
720
|
+
logger$5.error(`${error instanceof Error ? error.message : "Unknown error"}`);
|
|
616
721
|
process.exit(1);
|
|
617
722
|
}
|
|
618
723
|
}
|
|
619
724
|
const dumpCommand = define({
|
|
620
725
|
name: "dump",
|
|
621
726
|
description: "Output and clear collected quoted text from environment variables",
|
|
622
|
-
args: {
|
|
623
|
-
|
|
727
|
+
args: {
|
|
728
|
+
"log-file": ARG_LOG_FILE,
|
|
729
|
+
quiet: ARG_QUIET,
|
|
730
|
+
verbose: ARG_VERBOSE
|
|
731
|
+
},
|
|
732
|
+
async run(ctx) {
|
|
733
|
+
setupLogger({
|
|
734
|
+
quiet: Boolean(ctx.values.quiet),
|
|
735
|
+
verbose: Boolean(ctx.values.verbose),
|
|
736
|
+
logFile: ctx.values["log-file"]
|
|
737
|
+
});
|
|
624
738
|
await runDumpMode();
|
|
625
739
|
}
|
|
626
740
|
});
|
|
@@ -635,55 +749,57 @@ function processContent(content) {
|
|
|
635
749
|
|
|
636
750
|
//#endregion
|
|
637
751
|
//#region src/modes/input.ts
|
|
638
|
-
|
|
752
|
+
const logger$4 = getLogger(["editprompt", "input"]);
|
|
753
|
+
async function runInputMode(rawContent, autoSend, sendKey, sendKeyDelay) {
|
|
639
754
|
const content = processContent(rawContent);
|
|
640
755
|
if (!content) {
|
|
641
|
-
|
|
756
|
+
logger$4.info("No content to send. Exiting.");
|
|
642
757
|
return;
|
|
643
758
|
}
|
|
644
759
|
const config = readSendConfig();
|
|
645
760
|
let currentPaneId;
|
|
646
761
|
let isEditor;
|
|
647
762
|
if (config.mux === "tmux") {
|
|
648
|
-
currentPaneId = await getCurrentPaneId();
|
|
763
|
+
currentPaneId = await getCurrentPaneId$1();
|
|
649
764
|
isEditor = await isEditorPane(currentPaneId);
|
|
650
765
|
} else {
|
|
651
|
-
currentPaneId = await getCurrentPaneId
|
|
766
|
+
currentPaneId = await getCurrentPaneId();
|
|
652
767
|
isEditor = isEditorPaneFromConf(currentPaneId);
|
|
653
768
|
}
|
|
654
769
|
if (!isEditor) {
|
|
655
|
-
|
|
770
|
+
logger$4.error("Current pane is not an editor pane");
|
|
656
771
|
process.exit(1);
|
|
657
772
|
}
|
|
658
773
|
let targetPanes;
|
|
659
|
-
if (config.mux === "tmux") targetPanes = await getTargetPaneIds(currentPaneId);
|
|
660
|
-
else targetPanes = await getTargetPaneIds
|
|
774
|
+
if (config.mux === "tmux") targetPanes = await getTargetPaneIds$1(currentPaneId);
|
|
775
|
+
else targetPanes = await getTargetPaneIds(currentPaneId);
|
|
661
776
|
if (targetPanes.length === 0) {
|
|
662
|
-
|
|
777
|
+
logger$4.error("No target panes registered for this editor pane");
|
|
663
778
|
process.exit(1);
|
|
664
779
|
}
|
|
665
780
|
if (autoSend) {
|
|
666
781
|
const key = sendKey || (config.mux === "wezterm" ? "\\r" : "C-m");
|
|
782
|
+
const delay = /\.(png|webp|avif|jpe?g|gif)\b/i.test(content) ? sendKeyDelay ?? 1e3 : 200;
|
|
667
783
|
let successCount = 0;
|
|
668
784
|
for (const targetPane of targetPanes) try {
|
|
669
785
|
if (config.mux === "wezterm") {
|
|
670
786
|
await inputToWeztermPane(targetPane, content);
|
|
671
|
-
await sendKeyToWeztermPane(targetPane, key);
|
|
787
|
+
await sendKeyToWeztermPane(targetPane, key, delay);
|
|
672
788
|
} else {
|
|
673
789
|
await inputToTmuxPane(targetPane, content);
|
|
674
|
-
await sendKeyToTmuxPane(targetPane, key);
|
|
790
|
+
await sendKeyToTmuxPane(targetPane, key, delay);
|
|
675
791
|
}
|
|
676
792
|
successCount++;
|
|
677
793
|
} catch (error) {
|
|
678
|
-
|
|
794
|
+
logger$4.error(`Failed to send to pane ${targetPane}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
679
795
|
}
|
|
680
796
|
if (config.alwaysCopy) {
|
|
681
797
|
await copyToClipboard(content);
|
|
682
|
-
|
|
798
|
+
logger$4.info("Also copied to clipboard.");
|
|
683
799
|
}
|
|
684
|
-
if (successCount > 0)
|
|
800
|
+
if (successCount > 0) logger$4.info("Content sent and submitted successfully!");
|
|
685
801
|
else {
|
|
686
|
-
|
|
802
|
+
logger$4.error("All target panes failed to receive content");
|
|
687
803
|
process.exit(1);
|
|
688
804
|
}
|
|
689
805
|
return;
|
|
@@ -692,12 +808,12 @@ async function runInputMode(rawContent, autoSend, sendKey) {
|
|
|
692
808
|
const result = await handleContentDelivery(content, config.mux, targetPanes);
|
|
693
809
|
if (config.alwaysCopy && !result.allFailed) {
|
|
694
810
|
await copyToClipboard(content);
|
|
695
|
-
|
|
811
|
+
logger$4.info("Also copied to clipboard.");
|
|
696
812
|
}
|
|
697
813
|
if (result.successCount > 0) await focusFirstSuccessPane(config.mux, targetPanes, result.failedPanes);
|
|
698
814
|
if (result.allFailed) process.exit(1);
|
|
699
815
|
} catch (error) {
|
|
700
|
-
|
|
816
|
+
logger$4.error(`${error instanceof Error ? error.message : "Unknown error"}`);
|
|
701
817
|
process.exit(1);
|
|
702
818
|
}
|
|
703
819
|
}
|
|
@@ -712,21 +828,30 @@ const inputCommand = define({
|
|
|
712
828
|
"send-key": {
|
|
713
829
|
description: "Key to send after content (requires --auto-send)",
|
|
714
830
|
type: "string"
|
|
715
|
-
}
|
|
831
|
+
},
|
|
832
|
+
"log-file": ARG_LOG_FILE,
|
|
833
|
+
quiet: ARG_QUIET,
|
|
834
|
+
verbose: ARG_VERBOSE
|
|
716
835
|
},
|
|
717
836
|
async run(ctx) {
|
|
837
|
+
setupLogger({
|
|
838
|
+
quiet: Boolean(ctx.values.quiet),
|
|
839
|
+
verbose: Boolean(ctx.values.verbose),
|
|
840
|
+
logFile: ctx.values["log-file"]
|
|
841
|
+
});
|
|
718
842
|
const rawContent = extractRawContent(ctx.rest, ctx.positionals);
|
|
719
843
|
if (rawContent === void 0) {
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
844
|
+
logger$4.error("Content is required for input command");
|
|
845
|
+
logger$4.error("Usage: editprompt input \"your content\"");
|
|
846
|
+
logger$4.error(" or: editprompt input -- \"your content\"");
|
|
723
847
|
process.exit(1);
|
|
724
848
|
}
|
|
725
849
|
if (ctx.values["send-key"] && !ctx.values["auto-send"]) {
|
|
726
|
-
|
|
850
|
+
logger$4.error("--send-key requires --auto-send to be enabled");
|
|
727
851
|
process.exit(1);
|
|
728
852
|
}
|
|
729
|
-
|
|
853
|
+
const config = readSendConfig();
|
|
854
|
+
await runInputMode(rawContent, Boolean(ctx.values["auto-send"]), ctx.values["send-key"], config.sendKeyDelay);
|
|
730
855
|
}
|
|
731
856
|
});
|
|
732
857
|
|
|
@@ -822,23 +947,25 @@ async function openEditorAndGetContent(editorOption, envVars, sendConfig) {
|
|
|
822
947
|
|
|
823
948
|
//#endregion
|
|
824
949
|
//#region src/modes/openEditor.ts
|
|
950
|
+
const logger$3 = getLogger(["editprompt", "open"]);
|
|
825
951
|
async function runOpenEditorMode(options) {
|
|
826
952
|
if (options.targetPanes.length > 0 && options.mux === "tmux") try {
|
|
827
|
-
await markAsEditorPane(await getCurrentPaneId(), options.targetPanes);
|
|
953
|
+
await markAsEditorPane$1(await getCurrentPaneId$1(), options.targetPanes);
|
|
828
954
|
} catch {}
|
|
829
955
|
else if (options.targetPanes.length > 0 && options.mux === "wezterm") try {
|
|
830
|
-
const currentPaneId = await getCurrentPaneId
|
|
831
|
-
await markAsEditorPane
|
|
956
|
+
const currentPaneId = await getCurrentPaneId();
|
|
957
|
+
await markAsEditorPane(currentPaneId, options.targetPanes);
|
|
832
958
|
} catch {}
|
|
833
959
|
try {
|
|
834
960
|
const sendConfig = {
|
|
835
961
|
mux: options.mux,
|
|
836
|
-
alwaysCopy: options.alwaysCopy
|
|
962
|
+
alwaysCopy: options.alwaysCopy,
|
|
963
|
+
sendKeyDelay: Number.parseInt(process.env.EDITPROMPT_SEND_KEY_DELAY || "", 10) || 1e3
|
|
837
964
|
};
|
|
838
|
-
|
|
965
|
+
logger$3.info("Opening editor...");
|
|
839
966
|
const content = await openEditorAndGetContent(options.editor, options.env, sendConfig);
|
|
840
967
|
if (!content) {
|
|
841
|
-
|
|
968
|
+
logger$3.info("No content entered. Exiting.");
|
|
842
969
|
return;
|
|
843
970
|
}
|
|
844
971
|
try {
|
|
@@ -847,20 +974,20 @@ async function runOpenEditorMode(options) {
|
|
|
847
974
|
console.log(content);
|
|
848
975
|
if (options.alwaysCopy && !result.allFailed) {
|
|
849
976
|
await copyToClipboard(content);
|
|
850
|
-
|
|
977
|
+
logger$3.info("Also copied to clipboard.");
|
|
851
978
|
}
|
|
852
979
|
if (options.targetPanes.length > 0 && result.successCount > 0) await focusFirstSuccessPane(options.mux, options.targetPanes, result.failedPanes);
|
|
853
980
|
if (!result.allSuccess) process.exit(1);
|
|
854
981
|
} catch (error) {
|
|
855
|
-
|
|
982
|
+
logger$3.error(`${error instanceof Error ? error.message : "Unknown error"}`);
|
|
856
983
|
process.exit(1);
|
|
857
984
|
}
|
|
858
985
|
} finally {
|
|
859
986
|
if (options.targetPanes.length > 0 && options.mux === "tmux") try {
|
|
860
|
-
for (const targetPane of options.targetPanes) await clearEditorPaneId(targetPane);
|
|
987
|
+
for (const targetPane of options.targetPanes) await clearEditorPaneId$1(targetPane);
|
|
861
988
|
} catch {}
|
|
862
989
|
else if (options.targetPanes.length > 0 && options.mux === "wezterm") try {
|
|
863
|
-
for (const targetPane of options.targetPanes) await clearEditorPaneId
|
|
990
|
+
for (const targetPane of options.targetPanes) await clearEditorPaneId(targetPane);
|
|
864
991
|
} catch {}
|
|
865
992
|
}
|
|
866
993
|
}
|
|
@@ -872,6 +999,9 @@ const openCommand = define({
|
|
|
872
999
|
"target-pane": ARG_TARGET_PANE_MULTI,
|
|
873
1000
|
editor: ARG_EDITOR,
|
|
874
1001
|
"always-copy": ARG_ALWAYS_COPY,
|
|
1002
|
+
"log-file": ARG_LOG_FILE,
|
|
1003
|
+
quiet: ARG_QUIET,
|
|
1004
|
+
verbose: ARG_VERBOSE,
|
|
875
1005
|
env: {
|
|
876
1006
|
short: "E",
|
|
877
1007
|
description: "Environment variables to set (e.g., KEY=VALUE)",
|
|
@@ -880,6 +1010,11 @@ const openCommand = define({
|
|
|
880
1010
|
}
|
|
881
1011
|
},
|
|
882
1012
|
async run(ctx) {
|
|
1013
|
+
setupLogger({
|
|
1014
|
+
quiet: Boolean(ctx.values.quiet),
|
|
1015
|
+
verbose: Boolean(ctx.values.verbose),
|
|
1016
|
+
logFile: ctx.values["log-file"]
|
|
1017
|
+
});
|
|
883
1018
|
await runOpenEditorMode({
|
|
884
1019
|
mux: validateMux(ctx.values.mux),
|
|
885
1020
|
targetPanes: normalizeTargetPanes(ctx.values["target-pane"]),
|
|
@@ -892,39 +1027,40 @@ const openCommand = define({
|
|
|
892
1027
|
|
|
893
1028
|
//#endregion
|
|
894
1029
|
//#region src/modes/register.ts
|
|
1030
|
+
const logger$2 = getLogger(["editprompt", "register"]);
|
|
895
1031
|
async function runRegisterMode(options) {
|
|
896
1032
|
if (options.targetPanes.length === 0) {
|
|
897
|
-
|
|
1033
|
+
logger$2.error("--target-pane is required for register command");
|
|
898
1034
|
process.exit(1);
|
|
899
1035
|
}
|
|
900
1036
|
let editorPaneId;
|
|
901
1037
|
if (options.editorPane) editorPaneId = options.editorPane;
|
|
902
1038
|
else if (options.mux === "tmux") {
|
|
903
|
-
editorPaneId = await getCurrentPaneId();
|
|
1039
|
+
editorPaneId = await getCurrentPaneId$1();
|
|
904
1040
|
if (!await isEditorPane(editorPaneId)) {
|
|
905
|
-
|
|
1041
|
+
logger$2.error("Current pane is not an editor pane. Please run this command from an editor pane or specify --editor-pane.");
|
|
906
1042
|
process.exit(1);
|
|
907
1043
|
}
|
|
908
1044
|
} else if (options.mux === "wezterm") {
|
|
909
|
-
editorPaneId = await getCurrentPaneId
|
|
1045
|
+
editorPaneId = await getCurrentPaneId();
|
|
910
1046
|
if (!isEditorPaneFromConf(editorPaneId)) {
|
|
911
|
-
|
|
1047
|
+
logger$2.error("Current pane is not an editor pane. Please run this command from an editor pane or specify --editor-pane.");
|
|
912
1048
|
process.exit(1);
|
|
913
1049
|
}
|
|
914
1050
|
} else {
|
|
915
|
-
|
|
1051
|
+
logger$2.error("Unsupported multiplexer");
|
|
916
1052
|
process.exit(1);
|
|
917
1053
|
}
|
|
918
1054
|
try {
|
|
919
1055
|
let existingPanes = [];
|
|
920
|
-
if (options.mux === "tmux") existingPanes = await getTargetPaneIds(editorPaneId);
|
|
921
|
-
else if (options.mux === "wezterm") existingPanes = await getTargetPaneIds
|
|
1056
|
+
if (options.mux === "tmux") existingPanes = await getTargetPaneIds$1(editorPaneId);
|
|
1057
|
+
else if (options.mux === "wezterm") existingPanes = await getTargetPaneIds(editorPaneId);
|
|
922
1058
|
const mergedTargetPanes = [...new Set([...existingPanes, ...options.targetPanes])];
|
|
923
|
-
if (options.mux === "tmux") await markAsEditorPane(editorPaneId, mergedTargetPanes);
|
|
924
|
-
else if (options.mux === "wezterm") await markAsEditorPane
|
|
925
|
-
|
|
1059
|
+
if (options.mux === "tmux") await markAsEditorPane$1(editorPaneId, mergedTargetPanes);
|
|
1060
|
+
else if (options.mux === "wezterm") await markAsEditorPane(editorPaneId, mergedTargetPanes);
|
|
1061
|
+
logger$2.info(`Editor pane ${editorPaneId} registered with target panes: ${mergedTargetPanes.join(", ")}`);
|
|
926
1062
|
} catch (error) {
|
|
927
|
-
|
|
1063
|
+
logger$2.error(`${error instanceof Error ? error.message : "Unknown error"}`);
|
|
928
1064
|
process.exit(1);
|
|
929
1065
|
}
|
|
930
1066
|
}
|
|
@@ -938,9 +1074,17 @@ const registerCommand = define({
|
|
|
938
1074
|
short: "e",
|
|
939
1075
|
description: "Editor pane ID (defaults to current pane)",
|
|
940
1076
|
type: "string"
|
|
941
|
-
}
|
|
1077
|
+
},
|
|
1078
|
+
"log-file": ARG_LOG_FILE,
|
|
1079
|
+
quiet: ARG_QUIET,
|
|
1080
|
+
verbose: ARG_VERBOSE
|
|
942
1081
|
},
|
|
943
1082
|
async run(ctx) {
|
|
1083
|
+
setupLogger({
|
|
1084
|
+
quiet: Boolean(ctx.values.quiet),
|
|
1085
|
+
verbose: Boolean(ctx.values.verbose),
|
|
1086
|
+
logFile: ctx.values["log-file"]
|
|
1087
|
+
});
|
|
944
1088
|
await runRegisterMode({
|
|
945
1089
|
mux: validateMux(ctx.values.mux),
|
|
946
1090
|
targetPanes: normalizeTargetPanes(ctx.values["target-pane"]),
|
|
@@ -951,68 +1095,72 @@ const registerCommand = define({
|
|
|
951
1095
|
|
|
952
1096
|
//#endregion
|
|
953
1097
|
//#region src/modes/resume.ts
|
|
1098
|
+
const logger$1 = getLogger(["editprompt", "resume"]);
|
|
954
1099
|
async function runResumeMode(targetPane, mux) {
|
|
955
1100
|
if (mux === "wezterm") {
|
|
956
|
-
const currentPaneId
|
|
957
|
-
if (isEditorPaneFromConf(currentPaneId
|
|
958
|
-
|
|
959
|
-
const originalTargetPaneIds = await getTargetPaneIds
|
|
1101
|
+
const currentPaneId = await getCurrentPaneId();
|
|
1102
|
+
if (isEditorPaneFromConf(currentPaneId)) {
|
|
1103
|
+
logger$1.debug("Current pane is an editor pane");
|
|
1104
|
+
const originalTargetPaneIds = await getTargetPaneIds(currentPaneId);
|
|
960
1105
|
if (originalTargetPaneIds.length === 0) {
|
|
961
|
-
|
|
1106
|
+
logger$1.debug("No target pane IDs found for editor pane");
|
|
962
1107
|
process.exit(1);
|
|
963
1108
|
}
|
|
964
1109
|
let focused = false;
|
|
965
|
-
for (const paneId of originalTargetPaneIds) if (await checkPaneExists
|
|
966
|
-
await focusPane
|
|
1110
|
+
for (const paneId of originalTargetPaneIds) if (await checkPaneExists(paneId)) {
|
|
1111
|
+
await focusPane(paneId);
|
|
967
1112
|
focused = true;
|
|
968
1113
|
break;
|
|
969
1114
|
}
|
|
970
1115
|
if (!focused) {
|
|
971
|
-
|
|
1116
|
+
logger$1.debug("All target panes do not exist");
|
|
972
1117
|
process.exit(1);
|
|
973
1118
|
}
|
|
974
1119
|
process.exit(0);
|
|
975
1120
|
}
|
|
976
|
-
|
|
977
|
-
const editorPaneId
|
|
978
|
-
|
|
979
|
-
if (editorPaneId
|
|
980
|
-
|
|
1121
|
+
logger$1.debug("Current pane is not an editor pane");
|
|
1122
|
+
const editorPaneId = await getEditorPaneId(targetPane);
|
|
1123
|
+
logger$1.debug("wezterm editorPaneId: {editorPaneId}", { editorPaneId });
|
|
1124
|
+
if (editorPaneId === "") {
|
|
1125
|
+
logger$1.debug("Editor pane ID not found");
|
|
981
1126
|
process.exit(1);
|
|
982
1127
|
}
|
|
983
|
-
if (!await checkPaneExists
|
|
984
|
-
|
|
985
|
-
await clearEditorPaneId
|
|
1128
|
+
if (!await checkPaneExists(editorPaneId)) {
|
|
1129
|
+
logger$1.debug("Editor pane does not exist");
|
|
1130
|
+
await clearEditorPaneId(targetPane);
|
|
986
1131
|
process.exit(1);
|
|
987
1132
|
}
|
|
988
1133
|
try {
|
|
989
|
-
await focusPane
|
|
1134
|
+
await focusPane(editorPaneId);
|
|
990
1135
|
process.exit(0);
|
|
991
1136
|
} catch (error) {
|
|
992
|
-
|
|
1137
|
+
logger$1.debug("Can't focus editorPaneId: {editorPaneId}, error: {error}", {
|
|
1138
|
+
editorPaneId,
|
|
1139
|
+
error
|
|
1140
|
+
});
|
|
993
1141
|
process.exit(1);
|
|
994
1142
|
}
|
|
995
1143
|
}
|
|
996
|
-
const currentPaneId = await getCurrentPaneId();
|
|
1144
|
+
const currentPaneId = await getCurrentPaneId$1();
|
|
997
1145
|
if (await isEditorPane(currentPaneId)) {
|
|
998
|
-
const originalTargetPaneIds = await getTargetPaneIds(currentPaneId);
|
|
1146
|
+
const originalTargetPaneIds = await getTargetPaneIds$1(currentPaneId);
|
|
999
1147
|
if (originalTargetPaneIds.length === 0) process.exit(1);
|
|
1000
1148
|
let focused = false;
|
|
1001
|
-
for (const paneId of originalTargetPaneIds) if (await checkPaneExists(paneId)) {
|
|
1002
|
-
await focusPane(paneId);
|
|
1149
|
+
for (const paneId of originalTargetPaneIds) if (await checkPaneExists$1(paneId)) {
|
|
1150
|
+
await focusPane$1(paneId);
|
|
1003
1151
|
focused = true;
|
|
1004
1152
|
break;
|
|
1005
1153
|
}
|
|
1006
1154
|
if (!focused) process.exit(1);
|
|
1007
1155
|
process.exit(0);
|
|
1008
1156
|
}
|
|
1009
|
-
const editorPaneId = await getEditorPaneId(targetPane);
|
|
1157
|
+
const editorPaneId = await getEditorPaneId$1(targetPane);
|
|
1010
1158
|
if (editorPaneId === "") process.exit(1);
|
|
1011
|
-
if (!await checkPaneExists(editorPaneId)) {
|
|
1012
|
-
await clearEditorPaneId(targetPane);
|
|
1159
|
+
if (!await checkPaneExists$1(editorPaneId)) {
|
|
1160
|
+
await clearEditorPaneId$1(targetPane);
|
|
1013
1161
|
process.exit(1);
|
|
1014
1162
|
}
|
|
1015
|
-
await focusPane(editorPaneId);
|
|
1163
|
+
await focusPane$1(editorPaneId);
|
|
1016
1164
|
process.exit(0);
|
|
1017
1165
|
}
|
|
1018
1166
|
const resumeCommand = define({
|
|
@@ -1020,13 +1168,204 @@ const resumeCommand = define({
|
|
|
1020
1168
|
description: "Resume existing editor pane or focus back to target pane",
|
|
1021
1169
|
args: {
|
|
1022
1170
|
mux: ARG_MUX,
|
|
1023
|
-
"target-pane": ARG_TARGET_PANE_SINGLE
|
|
1171
|
+
"target-pane": ARG_TARGET_PANE_SINGLE,
|
|
1172
|
+
"log-file": ARG_LOG_FILE,
|
|
1173
|
+
quiet: ARG_QUIET,
|
|
1174
|
+
verbose: ARG_VERBOSE
|
|
1024
1175
|
},
|
|
1025
1176
|
async run(ctx) {
|
|
1177
|
+
setupLogger({
|
|
1178
|
+
quiet: Boolean(ctx.values.quiet),
|
|
1179
|
+
verbose: Boolean(ctx.values.verbose),
|
|
1180
|
+
logFile: ctx.values["log-file"]
|
|
1181
|
+
});
|
|
1026
1182
|
await runResumeMode(validateTargetPane(ctx.values["target-pane"], "resume"), validateMux(ctx.values.mux));
|
|
1027
1183
|
}
|
|
1028
1184
|
});
|
|
1029
1185
|
|
|
1186
|
+
//#endregion
|
|
1187
|
+
//#region src/modes/stash.ts
|
|
1188
|
+
const logger = getLogger(["editprompt", "stash"]);
|
|
1189
|
+
function getStashKey(mux, targetPaneId) {
|
|
1190
|
+
return `${mux}.targetPane.pane_${targetPaneId}.stash`;
|
|
1191
|
+
}
|
|
1192
|
+
async function pushStash(mux, targetPaneId, content) {
|
|
1193
|
+
const key = (/* @__PURE__ */ new Date()).toISOString();
|
|
1194
|
+
const stashKey = getStashKey(mux, targetPaneId);
|
|
1195
|
+
const existing = conf.get(stashKey) || {};
|
|
1196
|
+
existing[key] = content;
|
|
1197
|
+
conf.set(stashKey, existing);
|
|
1198
|
+
return key;
|
|
1199
|
+
}
|
|
1200
|
+
function getStashList(mux, targetPaneId) {
|
|
1201
|
+
const stashKey = getStashKey(mux, targetPaneId);
|
|
1202
|
+
const data = conf.get(stashKey) || {};
|
|
1203
|
+
return Object.entries(data).map(([key, content]) => ({
|
|
1204
|
+
key,
|
|
1205
|
+
content
|
|
1206
|
+
})).sort((a, b) => b.key.localeCompare(a.key));
|
|
1207
|
+
}
|
|
1208
|
+
function getStashContent(mux, targetPaneId, key) {
|
|
1209
|
+
const stashKey = getStashKey(mux, targetPaneId);
|
|
1210
|
+
const data = conf.get(stashKey) || {};
|
|
1211
|
+
if (key) return data[key] ?? "";
|
|
1212
|
+
const keys = Object.keys(data);
|
|
1213
|
+
if (keys.length === 0) return "";
|
|
1214
|
+
return data[keys.sort().pop()];
|
|
1215
|
+
}
|
|
1216
|
+
function dropStash(mux, targetPaneId, key) {
|
|
1217
|
+
const stashKey = getStashKey(mux, targetPaneId);
|
|
1218
|
+
const data = conf.get(stashKey) || {};
|
|
1219
|
+
let targetKey = key;
|
|
1220
|
+
if (!targetKey) {
|
|
1221
|
+
const keys = Object.keys(data);
|
|
1222
|
+
if (keys.length === 0) return false;
|
|
1223
|
+
targetKey = keys.sort().pop();
|
|
1224
|
+
}
|
|
1225
|
+
if (!(targetKey in data)) return false;
|
|
1226
|
+
delete data[targetKey];
|
|
1227
|
+
conf.set(stashKey, data);
|
|
1228
|
+
return true;
|
|
1229
|
+
}
|
|
1230
|
+
async function getTargetPaneForStash() {
|
|
1231
|
+
const config = readSendConfig();
|
|
1232
|
+
let currentPaneId;
|
|
1233
|
+
let isEditor;
|
|
1234
|
+
if (config.mux === "tmux") {
|
|
1235
|
+
currentPaneId = await getCurrentPaneId$1();
|
|
1236
|
+
isEditor = await isEditorPane(currentPaneId);
|
|
1237
|
+
} else {
|
|
1238
|
+
currentPaneId = await getCurrentPaneId();
|
|
1239
|
+
isEditor = isEditorPaneFromConf(currentPaneId);
|
|
1240
|
+
}
|
|
1241
|
+
if (!isEditor) {
|
|
1242
|
+
logger.error("Current pane is not an editor pane");
|
|
1243
|
+
process.exit(1);
|
|
1244
|
+
}
|
|
1245
|
+
let targetPanes;
|
|
1246
|
+
if (config.mux === "tmux") targetPanes = await getTargetPaneIds$1(currentPaneId);
|
|
1247
|
+
else targetPanes = await getTargetPaneIds(currentPaneId);
|
|
1248
|
+
if (targetPanes.length === 0) {
|
|
1249
|
+
logger.error("No target panes registered for this editor pane");
|
|
1250
|
+
process.exit(1);
|
|
1251
|
+
}
|
|
1252
|
+
return {
|
|
1253
|
+
mux: config.mux,
|
|
1254
|
+
targetPaneId: targetPanes[0]
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
async function runPush(rest, positionals) {
|
|
1258
|
+
const rawContent = extractRawContent(rest, positionals);
|
|
1259
|
+
if (rawContent === void 0 || rawContent.trim() === "") {
|
|
1260
|
+
logger.error("Content is required for stash push");
|
|
1261
|
+
logger.error("Usage: editprompt stash push -- \"your content\"");
|
|
1262
|
+
process.exit(1);
|
|
1263
|
+
}
|
|
1264
|
+
const { mux, targetPaneId } = await getTargetPaneForStash();
|
|
1265
|
+
const key = await pushStash(mux, targetPaneId, rawContent);
|
|
1266
|
+
logger.info("Stashed with key: {key}", { key });
|
|
1267
|
+
}
|
|
1268
|
+
async function runList() {
|
|
1269
|
+
const { mux, targetPaneId } = await getTargetPaneForStash();
|
|
1270
|
+
const entries = getStashList(mux, targetPaneId);
|
|
1271
|
+
console.log(JSON.stringify(entries, null, 2));
|
|
1272
|
+
}
|
|
1273
|
+
async function runApply(key) {
|
|
1274
|
+
const { mux, targetPaneId } = await getTargetPaneForStash();
|
|
1275
|
+
const content = getStashContent(mux, targetPaneId, key);
|
|
1276
|
+
if (content === "") {
|
|
1277
|
+
if (key) logger.error("No stash entry found with key: {key}", { key });
|
|
1278
|
+
else logger.error("No stash entries found");
|
|
1279
|
+
process.exit(1);
|
|
1280
|
+
}
|
|
1281
|
+
process.stdout.write(content);
|
|
1282
|
+
}
|
|
1283
|
+
async function runDrop(key) {
|
|
1284
|
+
const { mux, targetPaneId } = await getTargetPaneForStash();
|
|
1285
|
+
if (!dropStash(mux, targetPaneId, key)) {
|
|
1286
|
+
if (key) logger.error("No stash entry found with key: {key}", { key });
|
|
1287
|
+
else logger.error("No stash entries found");
|
|
1288
|
+
process.exit(1);
|
|
1289
|
+
}
|
|
1290
|
+
logger.info("Stash entry dropped");
|
|
1291
|
+
}
|
|
1292
|
+
async function runPop(key) {
|
|
1293
|
+
const { mux, targetPaneId } = await getTargetPaneForStash();
|
|
1294
|
+
const content = getStashContent(mux, targetPaneId, key);
|
|
1295
|
+
if (content === "") {
|
|
1296
|
+
if (key) logger.error("No stash entry found with key: {key}", { key });
|
|
1297
|
+
else logger.error("No stash entries found");
|
|
1298
|
+
process.exit(1);
|
|
1299
|
+
}
|
|
1300
|
+
process.stdout.write(content);
|
|
1301
|
+
dropStash(mux, targetPaneId, key);
|
|
1302
|
+
}
|
|
1303
|
+
function showHelp() {
|
|
1304
|
+
console.log("Usage: editprompt stash <subcommand> [options]");
|
|
1305
|
+
console.log("");
|
|
1306
|
+
console.log("Stash prompts for later use");
|
|
1307
|
+
console.log("");
|
|
1308
|
+
console.log("Subcommands:");
|
|
1309
|
+
console.log(" push -- \"<content>\" Push content to stash");
|
|
1310
|
+
console.log(" list List stashed entries (JSON)");
|
|
1311
|
+
console.log(" apply [--key <key>] Apply (output) stashed content");
|
|
1312
|
+
console.log(" drop [--key <key>] Drop stashed entry");
|
|
1313
|
+
console.log(" pop [--key <key>] Apply and drop stashed entry");
|
|
1314
|
+
console.log("");
|
|
1315
|
+
console.log("Options:");
|
|
1316
|
+
console.log(" -k, --key <key> Stash key (ISO datetime). Default: latest");
|
|
1317
|
+
console.log(" -h, --help Show this help message");
|
|
1318
|
+
}
|
|
1319
|
+
function parseKeyOption(args) {
|
|
1320
|
+
const keyIndex = args.findIndex((arg) => arg === "-k" || arg === "--key");
|
|
1321
|
+
if (keyIndex !== -1 && args[keyIndex + 1]) return args[keyIndex + 1];
|
|
1322
|
+
}
|
|
1323
|
+
const stashCommand = define({
|
|
1324
|
+
name: "stash",
|
|
1325
|
+
description: "Stash prompts for later use",
|
|
1326
|
+
args: {
|
|
1327
|
+
"log-file": ARG_LOG_FILE,
|
|
1328
|
+
quiet: ARG_QUIET,
|
|
1329
|
+
verbose: ARG_VERBOSE
|
|
1330
|
+
},
|
|
1331
|
+
async run(ctx) {
|
|
1332
|
+
setupLogger({
|
|
1333
|
+
quiet: Boolean(ctx.values.quiet),
|
|
1334
|
+
verbose: Boolean(ctx.values.verbose),
|
|
1335
|
+
logFile: ctx.values["log-file"]
|
|
1336
|
+
});
|
|
1337
|
+
const args = ctx.positionals.slice(1);
|
|
1338
|
+
if (args.length === 0 || args[0] === "-h" || args[0] === "--help") {
|
|
1339
|
+
showHelp();
|
|
1340
|
+
process.exit(args.length === 0 ? 1 : 0);
|
|
1341
|
+
}
|
|
1342
|
+
const subcommand = args[0];
|
|
1343
|
+
const subArgs = args.slice(1);
|
|
1344
|
+
switch (subcommand) {
|
|
1345
|
+
case "push":
|
|
1346
|
+
await runPush(ctx.rest, subArgs);
|
|
1347
|
+
break;
|
|
1348
|
+
case "list":
|
|
1349
|
+
await runList();
|
|
1350
|
+
break;
|
|
1351
|
+
case "apply":
|
|
1352
|
+
await runApply(parseKeyOption(subArgs));
|
|
1353
|
+
break;
|
|
1354
|
+
case "drop":
|
|
1355
|
+
await runDrop(parseKeyOption(subArgs));
|
|
1356
|
+
break;
|
|
1357
|
+
case "pop":
|
|
1358
|
+
await runPop(parseKeyOption(subArgs));
|
|
1359
|
+
break;
|
|
1360
|
+
default:
|
|
1361
|
+
logger.error("Unknown subcommand '{subcommand}'", { subcommand });
|
|
1362
|
+
logger.error("");
|
|
1363
|
+
showHelp();
|
|
1364
|
+
process.exit(1);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
});
|
|
1368
|
+
|
|
1030
1369
|
//#endregion
|
|
1031
1370
|
//#region src/index.ts
|
|
1032
1371
|
await cli(process.argv.slice(2), {
|
|
@@ -1034,16 +1373,18 @@ await cli(process.argv.slice(2), {
|
|
|
1034
1373
|
description: "A CLI tool that lets you write prompts for CLI tools using your favorite text editor",
|
|
1035
1374
|
args: {},
|
|
1036
1375
|
async run() {
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1376
|
+
setupLogger();
|
|
1377
|
+
const logger = getLogger(["editprompt"]);
|
|
1378
|
+
logger.error("Subcommand is required");
|
|
1379
|
+
logger.error("");
|
|
1380
|
+
logger.error("Migration guide from old to new syntax:");
|
|
1381
|
+
logger.error(" editprompt → editprompt open");
|
|
1382
|
+
logger.error(" editprompt --resume → editprompt resume");
|
|
1383
|
+
logger.error(" editprompt -- \"text\" → editprompt input \"text\"");
|
|
1384
|
+
logger.error(" editprompt --quote → editprompt collect");
|
|
1385
|
+
logger.error(" editprompt --capture → editprompt dump");
|
|
1386
|
+
logger.error("");
|
|
1387
|
+
logger.error("For details: https://github.com/eetann/editprompt/?tab=readme-ov-file");
|
|
1047
1388
|
process.exit(1);
|
|
1048
1389
|
}
|
|
1049
1390
|
}, {
|
|
@@ -1055,7 +1396,8 @@ await cli(process.argv.slice(2), {
|
|
|
1055
1396
|
resume: resumeCommand,
|
|
1056
1397
|
input: inputCommand,
|
|
1057
1398
|
collect: collectCommand,
|
|
1058
|
-
dump: dumpCommand
|
|
1399
|
+
dump: dumpCommand,
|
|
1400
|
+
stash: stashCommand
|
|
1059
1401
|
},
|
|
1060
1402
|
renderHeader: null
|
|
1061
1403
|
});
|