@maria_rcks/t1code 0.0.9 → 0.0.10

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 (2) hide show
  1. package/dist/index.mjs +140 -59
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -87436,7 +87436,7 @@ var import_react13 = __toESM(require_react(), 1);
87436
87436
  // package.json
87437
87437
  var package_default2 = {
87438
87438
  name: "@maria_rcks/t1code",
87439
- version: "0.0.9",
87439
+ version: "0.0.10",
87440
87440
  description: "Terminal-first T3 Code fork with an OpenTUI client",
87441
87441
  homepage: "https://github.com/maria-rcks/t1code#readme",
87442
87442
  bugs: {
@@ -87808,12 +87808,16 @@ var KEYBINDING_GUIDE_SECTIONS = [
87808
87808
  {
87809
87809
  title: "Global",
87810
87810
  items: [
87811
+ {
87812
+ shortcut: "Ctrl+C",
87813
+ action: "Open the quit prompt; press Ctrl+C again to confirm exit"
87814
+ },
87811
87815
  {
87812
87816
  shortcut: "Esc",
87813
- action: "Close the active dialog, overlay, or image preview; otherwise open the quit prompt"
87817
+ action: "Close the active dialog, overlay, or image preview"
87814
87818
  },
87815
87819
  {
87816
- shortcut: "Esc / Enter",
87820
+ shortcut: "Ctrl+C / Enter",
87817
87821
  action: "Confirm quit from the exit prompt"
87818
87822
  }
87819
87823
  ]
@@ -87909,11 +87913,11 @@ var KEYBINDING_GUIDE_SECTIONS = [
87909
87913
  ]
87910
87914
  }
87911
87915
  ];
87912
- function shouldOpenQuitPromptOnEscape(input) {
87913
- return input.keyName === "escape" && !input.hasDismissibleLayer;
87916
+ function isCtrlC(input) {
87917
+ return input.ctrl === true && input.keyName === "c";
87914
87918
  }
87915
87919
  function shouldClearComposerOnCtrlC(input) {
87916
- return input.ctrl === true && input.keyName === "c";
87920
+ return isCtrlC(input);
87917
87921
  }
87918
87922
 
87919
87923
  // src/log.ts
@@ -90242,6 +90246,7 @@ function ComposerSendButton(props) {
90242
90246
  }
90243
90247
  function App({
90244
90248
  renderer: _renderer,
90249
+ interruptRequestToken = 0,
90245
90250
  onRequestExit
90246
90251
  }) {
90247
90252
  const terminalRenderer = _renderer;
@@ -90257,6 +90262,7 @@ function App({
90257
90262
  const [composerAttachmentDeleteArmed, setComposerAttachmentDeleteArmed] = import_react13.useState(false);
90258
90263
  const [composerResetKey, setComposerResetKey] = import_react13.useState(0);
90259
90264
  const composerRef = import_react13.useRef(null);
90265
+ const composerValueRef = import_react13.useRef("");
90260
90266
  const deferredComposerSyncRef = import_react13.useRef(createDeferredComposerSyncState());
90261
90267
  const timelineScrollRef = import_react13.useRef(null);
90262
90268
  const [imagePasteInFlight, setImagePasteInFlight] = import_react13.useState(false);
@@ -91141,6 +91147,7 @@ function App({
91141
91147
  state: deferredComposerSyncRef.current,
91142
91148
  onSync: () => {
91143
91149
  const nextValue = composerRef.current?.plainText ?? "";
91150
+ composerValueRef.current = nextValue;
91144
91151
  setComposer(nextValue);
91145
91152
  if (activePendingProgress?.activeQuestion) {
91146
91153
  const questionId = activePendingProgress.activeQuestion.id;
@@ -91161,15 +91168,33 @@ function App({
91161
91168
  }
91162
91169
  });
91163
91170
  }
91171
+ function syncComposerValueRefSoon() {
91172
+ queueMicrotask(() => {
91173
+ composerValueRef.current = composerRef.current?.plainText ?? composerValueRef.current;
91174
+ });
91175
+ }
91164
91176
  function readComposerValue() {
91165
- return composerRef.current?.plainText ?? composer;
91177
+ return composerRef.current?.plainText ?? composerValueRef.current ?? composer;
91166
91178
  }
91167
91179
  function resetComposerTextarea(nextValue) {
91168
91180
  invalidateDeferredComposerSync(deferredComposerSyncRef.current);
91181
+ composerValueRef.current = nextValue;
91169
91182
  setComposer(nextValue);
91170
91183
  setComposerResetKey((current) => current + 1);
91171
91184
  }
91172
- function clearComposerDraft() {
91185
+ const requestAppExit = import_react13.useCallback(() => {
91186
+ setConfirmDialog({
91187
+ title: "Quit T1 Code?",
91188
+ body: "Press Ctrl-C again or Enter to quit. Press Escape to stay in the session.",
91189
+ confirmLabel: "Quit",
91190
+ escapeBehavior: "cancel",
91191
+ ctrlCBehavior: "confirm",
91192
+ onConfirm: async () => {
91193
+ onRequestExit?.();
91194
+ }
91195
+ });
91196
+ }, [onRequestExit]);
91197
+ const clearComposerDraft = import_react13.useCallback(() => {
91173
91198
  resetComposerTextarea("");
91174
91199
  setComposerAttachmentDeleteArmed(false);
91175
91200
  setPathSuggestionEntries([]);
@@ -91189,18 +91214,34 @@ function App({
91189
91214
  }));
91190
91215
  }
91191
91216
  setStatus("Composer cleared");
91192
- }
91193
- function requestAppExit() {
91194
- setConfirmDialog({
91195
- title: "Quit T1 Code?",
91196
- body: "Press Enter or Escape again to quit. Use Cancel to stay in the session.",
91197
- confirmLabel: "Quit",
91198
- escapeBehavior: "confirm",
91199
- onConfirm: async () => {
91200
- onRequestExit?.();
91201
- }
91202
- });
91203
- }
91217
+ }, [activePendingProgress, activePendingUserInput]);
91218
+ const handleInterruptRequest = import_react13.useCallback(() => {
91219
+ if (confirmDialog?.confirmLabel === "Quit") {
91220
+ const action = confirmDialog.onConfirm;
91221
+ setConfirmDialog(null);
91222
+ action();
91223
+ return;
91224
+ }
91225
+ const composerFocused = focusArea === "composer" && !imagePasteInFlight && !activePendingApproval;
91226
+ const composerValue = composerRef.current?.plainText ?? composerValueRef.current;
91227
+ if (composerFocused && composerValue.length > 0) {
91228
+ clearComposerDraft();
91229
+ return;
91230
+ }
91231
+ requestAppExit();
91232
+ }, [
91233
+ activePendingApproval,
91234
+ clearComposerDraft,
91235
+ confirmDialog,
91236
+ focusArea,
91237
+ imagePasteInFlight,
91238
+ requestAppExit
91239
+ ]);
91240
+ import_react13.useEffect(() => {
91241
+ if (interruptRequestToken > 0) {
91242
+ handleInterruptRequest();
91243
+ }
91244
+ }, [handleInterruptRequest, interruptRequestToken]);
91204
91245
  function applyComposerPathMention(entry) {
91205
91246
  const trigger = detectTrailingComposerPathTrigger(readComposerValue());
91206
91247
  if (!trigger) {
@@ -91473,35 +91514,7 @@ function App({
91473
91514
  clearInterval(interval);
91474
91515
  };
91475
91516
  }, [syncTimelineScrollState]);
91476
- async function handleComposerPaste(event) {
91477
- logger.log("composer.paste");
91478
- if (activePendingApproval) {
91479
- event.preventDefault();
91480
- setStatus("Resolve approval first");
91481
- return;
91482
- }
91483
- syncComposerFromTextarea();
91484
- const fallbackText = stripAnsiSequences(decodePasteBytes(event.bytes));
91485
- if (fallbackText.length > 0) {
91486
- event.preventDefault();
91487
- const resolvedSubmission = await resolveComposerSubmission({
91488
- text: fallbackText,
91489
- homeDir: paths.homeDir
91490
- });
91491
- if (resolvedSubmission.attachments.length > 0) {
91492
- addComposerAttachments(resolvedSubmission.attachments);
91493
- if (resolvedSubmission.promptText.length > 0) {
91494
- composerRef.current?.insertText(resolvedSubmission.promptText);
91495
- setComposer(composerRef.current?.plainText ?? `${readComposerValue()}${resolvedSubmission.promptText}`);
91496
- }
91497
- setStatus(resolvedSubmission.attachments.length === 1 ? "Image attached" : `${resolvedSubmission.attachments.length} images attached`);
91498
- return;
91499
- }
91500
- composerRef.current?.insertText(fallbackText);
91501
- setComposer(composerRef.current?.plainText ?? `${readComposerValue()}${fallbackText}`);
91502
- return;
91503
- }
91504
- event.preventDefault();
91517
+ async function attachClipboardImage() {
91505
91518
  if (activePendingUserInput) {
91506
91519
  setStatus("Image attachments are disabled while questions are pending");
91507
91520
  return;
@@ -91514,6 +91527,7 @@ function App({
91514
91527
  try {
91515
91528
  const filePath = await saveClipboardImageToFile(paths.imagesDir);
91516
91529
  if (!filePath) {
91530
+ setStatus(process.platform === "darwin" ? "No image found on clipboard" : "Clipboard images are not supported on this platform");
91517
91531
  return;
91518
91532
  }
91519
91533
  const attachment = await resolveImageAttachmentFromPath({
@@ -91539,6 +91553,37 @@ function App({
91539
91553
  setImagePasteInFlight(false);
91540
91554
  }
91541
91555
  }
91556
+ async function handleComposerPaste(event) {
91557
+ logger.log("composer.paste");
91558
+ if (activePendingApproval) {
91559
+ event.preventDefault();
91560
+ setStatus("Resolve approval first");
91561
+ return;
91562
+ }
91563
+ syncComposerFromTextarea();
91564
+ const fallbackText = stripAnsiSequences(decodePasteBytes(event.bytes));
91565
+ if (fallbackText.length > 0) {
91566
+ event.preventDefault();
91567
+ const resolvedSubmission = await resolveComposerSubmission({
91568
+ text: fallbackText,
91569
+ homeDir: paths.homeDir
91570
+ });
91571
+ if (resolvedSubmission.attachments.length > 0) {
91572
+ addComposerAttachments(resolvedSubmission.attachments);
91573
+ if (resolvedSubmission.promptText.length > 0) {
91574
+ composerRef.current?.insertText(resolvedSubmission.promptText);
91575
+ setComposer(composerRef.current?.plainText ?? `${readComposerValue()}${resolvedSubmission.promptText}`);
91576
+ }
91577
+ setStatus(resolvedSubmission.attachments.length === 1 ? "Image attached" : `${resolvedSubmission.attachments.length} images attached`);
91578
+ return;
91579
+ }
91580
+ composerRef.current?.insertText(fallbackText);
91581
+ setComposer(composerRef.current?.plainText ?? `${readComposerValue()}${fallbackText}`);
91582
+ return;
91583
+ }
91584
+ event.preventDefault();
91585
+ await attachClipboardImage();
91586
+ }
91542
91587
  function syncProjectPathFromTextarea() {
91543
91588
  setTimeout(() => {
91544
91589
  const nextValue = projectPathRef.current?.plainText ?? "";
@@ -91888,6 +91933,10 @@ function App({
91888
91933
  setFocusArea("threads");
91889
91934
  }
91890
91935
  useKeyboard((key) => {
91936
+ const ctrlCPressed = isCtrlC({
91937
+ keyName: key.name,
91938
+ ctrl: key.ctrl
91939
+ });
91891
91940
  const isNavUp = key.name === "up" || key.ctrl && key.name === "k";
91892
91941
  const isNavDown = key.name === "down" || key.ctrl && key.name === "j";
91893
91942
  const hasDismissibleLayer = Boolean(confirmDialog || renameThreadDialog || imagePreview || showSidebarOverlay || projectPathPromptOpen || overlayMenu || sidebarContextMenu);
@@ -91901,6 +91950,7 @@ function App({
91901
91950
  sequence: key.sequence
91902
91951
  });
91903
91952
  if (confirmDialog && key.name === "escape") {
91953
+ key.preventDefault();
91904
91954
  if (confirmDialog.escapeBehavior === "confirm") {
91905
91955
  const action = confirmDialog.onConfirm;
91906
91956
  setConfirmDialog(null);
@@ -91910,6 +91960,17 @@ function App({
91910
91960
  setConfirmDialog(null);
91911
91961
  return;
91912
91962
  }
91963
+ if (confirmDialog && ctrlCPressed) {
91964
+ key.preventDefault();
91965
+ if (confirmDialog.ctrlCBehavior === "confirm") {
91966
+ const action = confirmDialog.onConfirm;
91967
+ setConfirmDialog(null);
91968
+ action();
91969
+ return;
91970
+ }
91971
+ setConfirmDialog(null);
91972
+ return;
91973
+ }
91913
91974
  if (confirmDialog && (key.name === "return" || key.name === "enter" || key.name === "kpenter" || key.name === "linefeed")) {
91914
91975
  key.preventDefault();
91915
91976
  const action = confirmDialog.onConfirm;
@@ -91965,10 +92026,8 @@ function App({
91965
92026
  closeSidebarContextMenu();
91966
92027
  return;
91967
92028
  }
91968
- if (shouldOpenQuitPromptOnEscape({
91969
- keyName: key.name,
91970
- hasDismissibleLayer
91971
- })) {
92029
+ if (ctrlCPressed && !hasDismissibleLayer) {
92030
+ key.preventDefault();
91972
92031
  requestAppExit();
91973
92032
  return;
91974
92033
  }
@@ -95183,12 +95242,17 @@ ${rawComposerValue}` : `${serializedMentionText} ` : rawComposerValue;
95183
95242
  key.preventDefault();
95184
95243
  return;
95185
95244
  }
95245
+ syncComposerValueRefSoon();
95186
95246
  if (shouldClearComposerOnCtrlC({
95187
95247
  keyName: key.name,
95188
95248
  ctrl: key.ctrl
95189
95249
  })) {
95190
95250
  key.preventDefault();
95191
- clearComposerDraft();
95251
+ if (readComposerValue().length > 0) {
95252
+ clearComposerDraft();
95253
+ } else {
95254
+ requestAppExit();
95255
+ }
95192
95256
  return;
95193
95257
  }
95194
95258
  if (!activePendingUserInput && (composerAttachments.length > 0 || composerMentions.length > 0) && (key.name === "backspace" || key.name === "delete") && readComposerValue().length === 0) {
@@ -95216,6 +95280,11 @@ ${rawComposerValue}` : `${serializedMentionText} ` : rawComposerValue;
95216
95280
  source: key.source,
95217
95281
  sequence: key.sequence
95218
95282
  });
95283
+ if (!activePendingUserInput && key.ctrl && !key.meta && !key.shift && key.name === "y") {
95284
+ key.preventDefault();
95285
+ attachClipboardImage();
95286
+ return;
95287
+ }
95219
95288
  if (showPathSuggestions && pathSuggestionEntries.length > 0) {
95220
95289
  if (key.name === "up" || key.ctrl && key.name === "k") {
95221
95290
  key.preventDefault();
@@ -95252,6 +95321,7 @@ ${rawComposerValue}` : `${serializedMentionText} ` : rawComposerValue;
95252
95321
  syncComposerFromTextarea();
95253
95322
  },
95254
95323
  onPaste: (event) => {
95324
+ syncComposerValueRefSoon();
95255
95325
  handleComposerPaste(event);
95256
95326
  },
95257
95327
  onSubmit: () => {
@@ -96101,6 +96171,7 @@ if (process.env.T3CODE_HEADLESS === "1") {
96101
96171
  }, timeoutMs);
96102
96172
  } else {
96103
96173
  let shuttingDown = false;
96174
+ let interruptRequestToken = 0;
96104
96175
  const paths = resolveTuiPaths();
96105
96176
  const prefs = await readPrefs(paths);
96106
96177
  const rendererBackgroundColor = prefs.appSettings?.theme === "light" ? "#f5f5f5" : "#171717";
@@ -96113,6 +96184,13 @@ if (process.env.T3CODE_HEADLESS === "1") {
96113
96184
  backgroundColor: rendererBackgroundColor
96114
96185
  });
96115
96186
  const root = createRoot(renderer);
96187
+ const renderApp = () => {
96188
+ root.render(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(App, {
96189
+ renderer,
96190
+ interruptRequestToken,
96191
+ onRequestExit: () => shutdown(0)
96192
+ }, undefined, false, undefined, this));
96193
+ };
96116
96194
  const shutdown = (code = 0, error) => {
96117
96195
  if (shuttingDown)
96118
96196
  return;
@@ -96135,7 +96213,13 @@ if (process.env.T3CODE_HEADLESS === "1") {
96135
96213
  }, 50).unref();
96136
96214
  };
96137
96215
  const signalHandlers = [
96138
- ["SIGINT", () => shutdown(0)],
96216
+ [
96217
+ "SIGINT",
96218
+ () => {
96219
+ interruptRequestToken += 1;
96220
+ renderApp();
96221
+ }
96222
+ ],
96139
96223
  ["SIGTERM", () => shutdown(0)],
96140
96224
  ["SIGHUP", () => shutdown(0)],
96141
96225
  ["uncaughtException", (error) => shutdown(1, error)],
@@ -96149,8 +96233,5 @@ if (process.env.T3CODE_HEADLESS === "1") {
96149
96233
  process.off(event, handler);
96150
96234
  }
96151
96235
  });
96152
- root.render(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(App, {
96153
- renderer,
96154
- onRequestExit: () => shutdown(0)
96155
- }, undefined, false, undefined, this));
96236
+ renderApp();
96156
96237
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maria_rcks/t1code",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "description": "Terminal-first T3 Code fork with an OpenTUI client",
5
5
  "homepage": "https://github.com/maria-rcks/t1code#readme",
6
6
  "bugs": {