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.
Files changed (3) hide show
  1. package/README.md +74 -100
  2. package/dist/index.js +490 -148
  3. 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.1.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
- async function getCurrentPaneId() {
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, 100));
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
- console.log(`Content sent to tmux pane: ${paneId}`);
160
+ logger$10.debug("Content sent to tmux pane: {paneId}", { paneId });
96
161
  }
97
162
 
98
163
  //#endregion
99
- //#region src/modules/wezterm.ts
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
- async function getCurrentPaneId$1() {
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
- console.log(error);
178
+ logger$9.debug("getCurrentPaneId failed: {error}", { error });
110
179
  return "";
111
180
  }
112
181
  }
113
- async function checkPaneExists$1(paneId) {
182
+ async function checkPaneExists(paneId) {
114
183
  try {
115
184
  const { stdout } = await execAsync("wezterm cli list --format json");
116
- console.log(stdout);
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
- console.log(error);
188
+ logger$9.debug("checkPaneExists failed: {error}", { error });
120
189
  return false;
121
190
  }
122
191
  }
123
192
  async function saveEditorPaneId(targetPaneId, editorPaneId) {
124
- console.log(`wezterm.targetPane.pane_${targetPaneId}`);
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
- console.log(error);
197
+ logger$9.debug("saveEditorPaneId failed: {error}", { error });
129
198
  }
130
199
  }
131
- async function getEditorPaneId$1(targetPaneId) {
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
- console.log(error);
206
+ logger$9.debug("getEditorPaneId failed: {error}", { error });
138
207
  return "";
139
208
  }
140
209
  }
141
- async function clearEditorPaneId$1(targetPaneId) {
210
+ async function clearEditorPaneId(targetPaneId) {
142
211
  try {
143
- const editorPaneId = await getEditorPaneId$1(targetPaneId);
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
- console.log(error);
216
+ logger$9.debug("clearEditorPaneId failed: {error}", { error });
148
217
  }
149
218
  }
150
- async function focusPane$1(paneId) {
219
+ async function focusPane(paneId) {
151
220
  await execAsync(`wezterm cli activate-pane --pane-id '${paneId}'`);
152
221
  }
153
- async function markAsEditorPane$1(editorPaneId, targetPaneIds) {
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
- console.log(error);
228
+ logger$9.debug("markAsEditorPane failed: {error}", { error });
160
229
  }
161
230
  }
162
- async function getTargetPaneIds$1(editorPaneId) {
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
- console.log(error);
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
- console.log(error);
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
- console.log(error);
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
- console.log(error);
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
- console.log(error);
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
- console.log(`Content sent to wezterm pane: ${paneId}`);
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) return rest.join(" ");
238
- return positionals[0];
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$1(firstSuccessPane);
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
- console.log("Content copied to clipboard.");
463
+ logger$8.info("Content copied to clipboard.");
389
464
  } catch (error) {
390
- console.log(`Failed to copy to clipboard: ${error instanceof Error ? error.message : "Unknown error"}`);
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
- console.log(`Failed to send to pane ${targetPane}: ${error instanceof Error ? error.message : "Unknown error"}`);
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) console.log("Content sent successfully to all panes!");
493
+ if (allSuccess) logger$8.info("Content sent successfully to all panes!");
419
494
  else if (allFailed) {
420
- console.error("Error: All target panes failed to receive content.");
421
- console.log("Falling back to clipboard...");
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
- console.log("Content copied to clipboard.");
424
- } else console.warn(`Warning: Content sent to ${successCount}/${targetPanes.length} panes. Failed panes: ${failedPanes.join(", ")}`);
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
- console.error(`Error: Invalid multiplexer type '${muxValue}'. Supported values: ${SUPPORTED_MUXES.join(", ")}`);
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
- console.error(`Error: --target-pane is required for ${commandName} command`);
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
- console.error(`Error: Invalid output(s) '${invalid.join(", ")}'. Supported values: ${SUPPORTED_OUTPUTS.join(", ")}`);
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
- console.error(`Error: ${error instanceof Error ? error.message : "Unknown error"}`);
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
- console.error("Error: Text content is required for collect mode with wezterm. Use: editprompt collect --mux wezterm --target-pane <id> -- \"<text>\"");
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: muxValue,
570
- alwaysCopy: process.env.EDITPROMPT_ALWAYS_COPY === "1"
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$1();
690
+ currentPaneId = await getCurrentPaneId();
586
691
  isEditor = isEditorPaneFromConf(currentPaneId);
587
692
  }
588
693
  if (!isEditor) {
589
- console.error("Error: Current pane is not an editor pane");
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$1(currentPaneId);
698
+ if (config.mux === "tmux") targetPanes = await getTargetPaneIds$1(currentPaneId);
699
+ else targetPanes = await getTargetPaneIds(currentPaneId);
595
700
  if (targetPanes.length === 0) {
596
- console.error("Error: No target panes registered for this editor pane");
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
- console.error(`Error: ${error instanceof Error ? error.message : "Unknown error"}`);
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
- async run() {
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
- async function runInputMode(rawContent, autoSend, sendKey) {
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
- console.log("No content to send. Exiting.");
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$1();
766
+ currentPaneId = await getCurrentPaneId();
652
767
  isEditor = isEditorPaneFromConf(currentPaneId);
653
768
  }
654
769
  if (!isEditor) {
655
- console.error("Error: Current pane is not an editor pane");
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$1(currentPaneId);
774
+ if (config.mux === "tmux") targetPanes = await getTargetPaneIds$1(currentPaneId);
775
+ else targetPanes = await getTargetPaneIds(currentPaneId);
661
776
  if (targetPanes.length === 0) {
662
- console.error("Error: No target panes registered for this editor pane");
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
- console.error(`Failed to send to pane ${targetPane}: ${error instanceof Error ? error.message : "Unknown error"}`);
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
- console.log("Also copied to clipboard.");
798
+ logger$4.info("Also copied to clipboard.");
683
799
  }
684
- if (successCount > 0) console.log("Content sent and submitted successfully!");
800
+ if (successCount > 0) logger$4.info("Content sent and submitted successfully!");
685
801
  else {
686
- console.error("Error: All target panes failed to receive content");
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
- console.log("Also copied to clipboard.");
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
- console.error(`Error: ${error instanceof Error ? error.message : "Unknown error"}`);
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
- console.error("Error: Content is required for input command");
721
- console.error("Usage: editprompt input \"your content\"");
722
- console.error(" or: editprompt input -- \"your content\"");
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
- console.error("Error: --send-key requires --auto-send to be enabled");
850
+ logger$4.error("--send-key requires --auto-send to be enabled");
727
851
  process.exit(1);
728
852
  }
729
- await runInputMode(rawContent, Boolean(ctx.values["auto-send"]), ctx.values["send-key"]);
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$1();
831
- await markAsEditorPane$1(currentPaneId, options.targetPanes);
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
- console.log("Opening editor...");
965
+ logger$3.info("Opening editor...");
839
966
  const content = await openEditorAndGetContent(options.editor, options.env, sendConfig);
840
967
  if (!content) {
841
- console.log("No content entered. Exiting.");
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
- console.log("Also copied to clipboard.");
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
- console.error(`Error: ${error instanceof Error ? error.message : "Unknown error"}`);
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$1(targetPane);
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
- console.error("Error: --target-pane is required for register command");
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
- console.error("Error: Current pane is not an editor pane. Please run this command from an editor pane or specify --editor-pane.");
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$1();
1045
+ editorPaneId = await getCurrentPaneId();
910
1046
  if (!isEditorPaneFromConf(editorPaneId)) {
911
- console.error("Error: Current pane is not an editor pane. Please run this command from an editor pane or specify --editor-pane.");
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
- console.error("Error: Unsupported multiplexer");
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$1(editorPaneId);
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$1(editorPaneId, mergedTargetPanes);
925
- console.log(`Editor pane ${editorPaneId} registered with target panes: ${mergedTargetPanes.join(", ")}`);
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
- console.error(`Error: ${error instanceof Error ? error.message : "Unknown error"}`);
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$1 = await getCurrentPaneId$1();
957
- if (isEditorPaneFromConf(currentPaneId$1)) {
958
- console.log("isEditor");
959
- const originalTargetPaneIds = await getTargetPaneIds$1(currentPaneId$1);
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
- console.log("Not found originalTargetPaneIds");
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$1(paneId)) {
966
- await focusPane$1(paneId);
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
- console.log("All target panes do not exist");
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
- console.log("not isEditor");
977
- const editorPaneId$1 = await getEditorPaneId$1(targetPane);
978
- console.log(`wezterm editorPaneId: ${editorPaneId$1}`);
979
- if (editorPaneId$1 === "") {
980
- console.log("Not found editorPaneId");
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$1(editorPaneId$1)) {
984
- console.log("Not exist editorPaneId");
985
- await clearEditorPaneId$1(targetPane);
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$1(editorPaneId$1);
1134
+ await focusPane(editorPaneId);
990
1135
  process.exit(0);
991
1136
  } catch (error) {
992
- console.log(`Can't focus editorPaneId: ${editorPaneId$1}\nerror: ${error}`);
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
- console.error("Error: Subcommand is required");
1038
- console.error("");
1039
- console.error("Migration guide from old to new syntax:");
1040
- console.error(" editprompt → editprompt open");
1041
- console.error(" editprompt --resume → editprompt resume");
1042
- console.error(" editprompt -- \"text\" → editprompt input \"text\"");
1043
- console.error(" editprompt --quote → editprompt collect");
1044
- console.error(" editprompt --capture → editprompt dump");
1045
- console.error("");
1046
- console.error("For details: https://github.com/eetann/editprompt/?tab=readme-ov-file");
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
  });