@higherdev/cli 0.36.0 → 0.37.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/dist/attachments.js +14 -0
- package/dist/tui/App.js +8 -2
- package/dist/tui/TextInput.js +5 -0
- package/package.json +1 -1
package/dist/attachments.js
CHANGED
|
@@ -97,6 +97,20 @@ export function parseTuiAttach(text) {
|
|
|
97
97
|
const paths = key ? words.slice(0, -1) : words;
|
|
98
98
|
return paths.length === 1 ? { path: paths[0], ...(key ? { ticketKey: key } : {}) } : null;
|
|
99
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Text that a Finder drop produces: one or more absolute paths, plain, quoted, or with
|
|
102
|
+
* escaped spaces. Terminal.app inserts a drop as typed text rather than a bracketed
|
|
103
|
+
* paste, so the input component and the Enter handler both check this before treating
|
|
104
|
+
* a line starting with "/" as a slash command.
|
|
105
|
+
*/
|
|
106
|
+
export function looksLikeDroppedPaths(text) {
|
|
107
|
+
const trimmed = text.trim();
|
|
108
|
+
if (!/^(?:\/|'\/|"\/)/.test(trimmed))
|
|
109
|
+
return false;
|
|
110
|
+
// A slash command is one word without a second "/" (e.g. /architect, /ticket HD-1).
|
|
111
|
+
const firstWord = trimmed.split(/\s+/)[0].replace(/^['"]/, "");
|
|
112
|
+
return firstWord.slice(1).includes("/") || /^['"]/.test(trimmed);
|
|
113
|
+
}
|
|
100
114
|
export async function detectDroppedPaths(pasted, isFile = async (path) => (await stat(path)).isFile()) {
|
|
101
115
|
const text = pasted.trim();
|
|
102
116
|
if (!text)
|
package/dist/tui/App.js
CHANGED
|
@@ -33,7 +33,7 @@ import { editFor, editableKeys, nextValue, seedFor, settingsRows } from "./setti
|
|
|
33
33
|
import { appendLines, runLabels, toStreamLines } from "./stream.js";
|
|
34
34
|
import { UI } from "./theme.js";
|
|
35
35
|
import { WorkspaceLoads } from "./workspace-load.js";
|
|
36
|
-
import { attachmentChip, detectDroppedPaths, uploadAttachment } from "../attachments.js";
|
|
36
|
+
import { attachmentChip, detectDroppedPaths, looksLikeDroppedPaths, uploadAttachment } from "../attachments.js";
|
|
37
37
|
let messageSeq = 0;
|
|
38
38
|
const nextId = () => `m${messageSeq++}`;
|
|
39
39
|
const tuiPrompt = (question) => promptOnStdin(question, true);
|
|
@@ -457,7 +457,7 @@ export function App({ initial, availableUpdate: initialUpdate = null, updateDeps
|
|
|
457
457
|
})();
|
|
458
458
|
}, [agentName, config, pendingAttachments, setThread, workspace.id]);
|
|
459
459
|
const receiveDrop = useCallback((pasted) => {
|
|
460
|
-
if (
|
|
460
|
+
if (!looksLikeDroppedPaths(pasted))
|
|
461
461
|
return false;
|
|
462
462
|
void (async () => {
|
|
463
463
|
const paths = await detectDroppedPaths(pasted);
|
|
@@ -520,6 +520,12 @@ export function App({ initial, availableUpdate: initialUpdate = null, updateDeps
|
|
|
520
520
|
}, [view, ticketKey, visibleStory?.latest_headline, visibleStory?.timeline, config]);
|
|
521
521
|
const run = useCallback(async (raw) => {
|
|
522
522
|
const text = raw.trim();
|
|
523
|
+
// A dropped path that reached the line as typed text is an attachment, not a command.
|
|
524
|
+
if (looksLikeDroppedPaths(text) && (await detectDroppedPaths(text)).length) {
|
|
525
|
+
setDraft("");
|
|
526
|
+
receiveDrop(text);
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
523
529
|
if (view === "settings") {
|
|
524
530
|
const open = editingRef.current;
|
|
525
531
|
if (open) {
|
package/dist/tui/TextInput.js
CHANGED
|
@@ -73,6 +73,11 @@ export default function TextInput({ value, onChange, onSubmit, onCancel, onUp, o
|
|
|
73
73
|
// most of them. Ink reports that as ordinary input with key.return
|
|
74
74
|
// false, so without this the Enter is filtered out with the other
|
|
75
75
|
// control bytes and the line just sits at the prompt unsent.
|
|
76
|
+
// A Finder drop in Terminal.app arrives as one multi-character chunk of
|
|
77
|
+
// typed text, not a bracketed paste, so it is offered to the paste
|
|
78
|
+
// handler first.
|
|
79
|
+
if (input.length > 1 && onPasteText?.(input))
|
|
80
|
+
return;
|
|
76
81
|
if (input.length > 1 && /[\r\n]/.test(input)) {
|
|
77
82
|
const parts = input.split(/\r\n|\r|\n/);
|
|
78
83
|
const submits = parts.length === 2 && parts[1] === "";
|