lsd-pi 1.1.4 → 1.1.6
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 +2 -1
- package/dist/headless-ui.js +2 -0
- package/dist/onboarding.js +11 -8
- package/dist/resources/extensions/async-jobs/async-bash-tool.js +14 -0
- package/dist/resources/extensions/async-jobs/await-tool.js +14 -0
- package/dist/resources/extensions/async-jobs/cancel-job-tool.js +7 -0
- package/dist/resources/extensions/cache-timer/index.js +5 -0
- package/dist/resources/extensions/codex-rotate/IMPLEMENTATION.md +18 -13
- package/dist/resources/extensions/codex-rotate/README.md +9 -3
- package/dist/resources/extensions/codex-rotate/commands.js +15 -8
- package/dist/resources/extensions/codex-rotate/index.js +17 -8
- package/dist/resources/extensions/memory/auto-extract.js +196 -80
- package/dist/resources/extensions/memory/dream.js +86 -19
- package/dist/resources/extensions/shared/rtk.js +89 -87
- package/dist/resources/extensions/subagent/index.js +33 -7
- package/dist/startup-model-validation.js +12 -2
- package/dist/update-check.js +2 -2
- package/dist/update-cmd.js +3 -3
- package/dist/welcome-screen.js +43 -14
- package/package.json +3 -2
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.js +46 -0
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +43 -4
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.js +2 -0
- package/packages/pi-coding-agent/dist/core/keybindings.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/pty-executor.d.ts +48 -0
- package/packages/pi-coding-agent/dist/core/pty-executor.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/pty-executor.js +173 -0
- package/packages/pi-coding-agent/dist/core/pty-executor.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +16 -3
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +18 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tool-approval.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tool-approval.js +2 -2
- package/packages/pi-coding-agent/dist/core/tool-approval.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.js +23 -2
- package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/pty.d.ts +50 -0
- package/packages/pi-coding-agent/dist/core/tools/pty.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/pty.js +289 -0
- package/packages/pi-coding-agent/dist/core/tools/pty.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +36 -22
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +3 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +23 -62
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js +1 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js +1 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.d.ts +39 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js +182 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +36 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +2 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +106 -77
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +2 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +4 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +49 -13
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +27 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +251 -39
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/utils/terminal-screen.d.ts +10 -0
- package/packages/pi-coding-agent/dist/utils/terminal-screen.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/utils/terminal-screen.js +67 -0
- package/packages/pi-coding-agent/dist/utils/terminal-screen.js.map +1 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.d.ts +7 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.js +67 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.js.map +1 -0
- package/packages/pi-coding-agent/package.json +9 -4
- package/packages/pi-coding-agent/src/core/agent-session.clear-queue.test.ts +50 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +50 -4
- package/packages/pi-coding-agent/src/core/extensions/types.ts +1 -1
- package/packages/pi-coding-agent/src/core/keybindings.ts +4 -1
- package/packages/pi-coding-agent/src/core/pty-executor.ts +229 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +16 -3
- package/packages/pi-coding-agent/src/core/settings-manager.ts +27 -0
- package/packages/pi-coding-agent/src/core/tool-approval.ts +2 -2
- package/packages/pi-coding-agent/src/core/tools/index.ts +35 -2
- package/packages/pi-coding-agent/src/core/tools/pty.ts +354 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +37 -24
- package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +22 -70
- package/packages/pi-coding-agent/src/modes/interactive/components/branch-summary-message.ts +1 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/compaction-summary-message.ts +1 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/embedded-terminal.ts +224 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +45 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +2 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +104 -81
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +5 -19
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +55 -13
- package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +3 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +296 -48
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +2 -2
- package/packages/pi-coding-agent/src/utils/terminal-screen.ts +77 -0
- package/packages/pi-coding-agent/src/utils/terminal-serializer.ts +72 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.d.ts +2 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.js +105 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.js.map +1 -0
- package/packages/pi-tui/dist/components/editor.d.ts +4 -0
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +57 -3
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/components/loader.d.ts +26 -6
- package/packages/pi-tui/dist/components/loader.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/loader.js +178 -18
- package/packages/pi-tui/dist/components/loader.js.map +1 -1
- package/packages/pi-tui/src/components/editor.ts +65 -3
- package/packages/pi-tui/src/components/loader.ts +196 -19
- package/pkg/dist/modes/interactive/theme/themes.js +2 -2
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +13 -0
- package/src/resources/extensions/async-jobs/await-tool.ts +13 -0
- package/src/resources/extensions/async-jobs/cancel-job-tool.ts +8 -0
- package/src/resources/extensions/cache-timer/index.ts +102 -96
- package/src/resources/extensions/codex-rotate/IMPLEMENTATION.md +18 -13
- package/src/resources/extensions/codex-rotate/README.md +9 -3
- package/src/resources/extensions/codex-rotate/commands.ts +335 -329
- package/src/resources/extensions/codex-rotate/index.ts +85 -75
- package/src/resources/extensions/memory/auto-extract.ts +330 -204
- package/src/resources/extensions/memory/dream.ts +88 -21
- package/src/resources/extensions/memory/tests/auto-extract.test.ts +200 -144
- package/src/resources/extensions/shared/rtk.js +112 -0
- package/src/resources/extensions/subagent/index.ts +35 -6
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import stripAnsi from "strip-ansi";
|
|
2
|
+
|
|
3
|
+
function finalizeLine(cells: string[]): string {
|
|
4
|
+
return cells.join("").replace(/[ \t]+$/u, "");
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Convert terminal-style output into stable display lines.
|
|
9
|
+
* Handles ANSI stripping plus carriage-return overwrites and backspaces.
|
|
10
|
+
*/
|
|
11
|
+
export function renderTerminalLines(text: string): string[] {
|
|
12
|
+
const stripped = stripAnsi(text).replace(/\r\n/g, "\n");
|
|
13
|
+
const lines: string[] = [];
|
|
14
|
+
let cells: string[] = [];
|
|
15
|
+
let col = 0;
|
|
16
|
+
|
|
17
|
+
const flushLine = () => {
|
|
18
|
+
lines.push(finalizeLine(cells));
|
|
19
|
+
cells = [];
|
|
20
|
+
col = 0;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
for (let i = 0; i < stripped.length; i++) {
|
|
24
|
+
const ch = stripped[i]!;
|
|
25
|
+
|
|
26
|
+
if (ch === "\n") {
|
|
27
|
+
flushLine();
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (ch === "\r") {
|
|
32
|
+
col = 0;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (ch === "\b") {
|
|
37
|
+
col = Math.max(0, col - 1);
|
|
38
|
+
if (col < cells.length) cells[col] = " ";
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (ch < " " && ch !== "\t") {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (ch === "\t") {
|
|
47
|
+
const spaces = 4 - (col % 4 || 0);
|
|
48
|
+
for (let s = 0; s < spaces; s++) {
|
|
49
|
+
while (cells.length < col) cells.push(" ");
|
|
50
|
+
if (col < cells.length) cells[col] = " ";
|
|
51
|
+
else cells.push(" ");
|
|
52
|
+
col++;
|
|
53
|
+
}
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
while (cells.length < col) cells.push(" ");
|
|
58
|
+
if (col < cells.length) cells[col] = ch;
|
|
59
|
+
else cells.push(ch);
|
|
60
|
+
col++;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (cells.length > 0 || stripped.endsWith("\n")) {
|
|
64
|
+
lines.push(finalizeLine(cells));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return lines;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function renderTerminalText(text: string): string {
|
|
71
|
+
return renderTerminalLines(text).join("\n");
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor-dropped-image.test.d.ts","sourceRoot":"","sources":["../../../src/components/__tests__/editor-dropped-image.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Editor dropped image marker tests
|
|
2
|
+
// Tests for image path handling, spacing, and normalization
|
|
3
|
+
import { describe, it } from "node:test";
|
|
4
|
+
import assert from "node:assert/strict";
|
|
5
|
+
import { Editor } from "../editor.js";
|
|
6
|
+
// Mock TUI for testing
|
|
7
|
+
const mockTUI = {
|
|
8
|
+
requestRender() { },
|
|
9
|
+
terminal: { rows: 24, columns: 80 },
|
|
10
|
+
};
|
|
11
|
+
// Mock theme
|
|
12
|
+
const mockStyle = (s) => s;
|
|
13
|
+
const mockTheme = {
|
|
14
|
+
borderColor: mockStyle,
|
|
15
|
+
selectList: {
|
|
16
|
+
selectedPrefix: mockStyle,
|
|
17
|
+
selectedText: mockStyle,
|
|
18
|
+
description: mockStyle,
|
|
19
|
+
scrollInfo: mockStyle,
|
|
20
|
+
noMatch: mockStyle,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
describe("Editor - dropped image markers", () => {
|
|
24
|
+
describe("handlePaste with image paths", () => {
|
|
25
|
+
it("decodes file:// URIs and expands to filesystem path", () => {
|
|
26
|
+
const editor = new Editor(mockTUI, mockTheme);
|
|
27
|
+
editor.setText("foo");
|
|
28
|
+
editor.handlePaste("file:///tmp/My%20Image.png");
|
|
29
|
+
assert.equal(editor.getText(), "foo <Image1>");
|
|
30
|
+
assert.equal(editor.getExpandedText(), "foo /tmp/My Image.png");
|
|
31
|
+
});
|
|
32
|
+
it("normalizes escaped spaces in paths", () => {
|
|
33
|
+
const editor = new Editor(mockTUI, mockTheme);
|
|
34
|
+
editor.setText("bar");
|
|
35
|
+
editor.handlePaste("/tmp/My\\ Image.png");
|
|
36
|
+
assert.equal(editor.getText(), "bar <Image1>");
|
|
37
|
+
assert.equal(editor.getExpandedText(), "bar /tmp/My Image.png");
|
|
38
|
+
});
|
|
39
|
+
it("preserves leading space when pasting after word character", () => {
|
|
40
|
+
const editor = new Editor(mockTUI, mockTheme);
|
|
41
|
+
editor.setText("foo");
|
|
42
|
+
editor.handlePaste("/tmp/image.png");
|
|
43
|
+
assert.equal(editor.getText(), "foo <Image1>");
|
|
44
|
+
assert.equal(editor.getExpandedText(), "foo /tmp/image.png");
|
|
45
|
+
});
|
|
46
|
+
it("does not add leading space when cursor after space", () => {
|
|
47
|
+
const editor = new Editor(mockTUI, mockTheme);
|
|
48
|
+
editor.setText("foo ");
|
|
49
|
+
editor.handlePaste("/tmp/image.png");
|
|
50
|
+
assert.equal(editor.getText(), "foo <Image1>");
|
|
51
|
+
assert.equal(editor.getExpandedText(), "foo /tmp/image.png");
|
|
52
|
+
});
|
|
53
|
+
it("does not add leading space when cursor at line start", () => {
|
|
54
|
+
const editor = new Editor(mockTUI, mockTheme);
|
|
55
|
+
editor.setText("");
|
|
56
|
+
editor.handlePaste("/tmp/image.png");
|
|
57
|
+
assert.equal(editor.getText(), "<Image1>");
|
|
58
|
+
assert.equal(editor.getExpandedText(), "/tmp/image.png");
|
|
59
|
+
});
|
|
60
|
+
it("handles file:// URI with leading space after word", () => {
|
|
61
|
+
const editor = new Editor(mockTUI, mockTheme);
|
|
62
|
+
editor.setText("test");
|
|
63
|
+
editor.handlePaste("file:///home/user/photo.jpg");
|
|
64
|
+
assert.equal(editor.getText(), "test <Image1>");
|
|
65
|
+
assert.equal(editor.getExpandedText(), "test /home/user/photo.jpg");
|
|
66
|
+
});
|
|
67
|
+
it("handles relative paths with leading space after word", () => {
|
|
68
|
+
const editor = new Editor(mockTUI, mockTheme);
|
|
69
|
+
editor.setText("doc:");
|
|
70
|
+
editor.handlePaste("./images/screenshot.png");
|
|
71
|
+
assert.equal(editor.getText(), "doc: <Image1>");
|
|
72
|
+
assert.equal(editor.getExpandedText(), "doc: ./images/screenshot.png");
|
|
73
|
+
});
|
|
74
|
+
it("handles tilde paths with leading space after word", () => {
|
|
75
|
+
const editor = new Editor(mockTUI, mockTheme);
|
|
76
|
+
editor.setText("look at");
|
|
77
|
+
editor.handlePaste("~/Desktop/Screen%20Shot.png");
|
|
78
|
+
assert.equal(editor.getText(), "look at <Image1>");
|
|
79
|
+
assert.equal(editor.getExpandedText(), "look at ~/Desktop/Screen Shot.png");
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe("image marker expansion", () => {
|
|
83
|
+
it("expands markers with correct paths on submit", () => {
|
|
84
|
+
const editor = new Editor(mockTUI, mockTheme);
|
|
85
|
+
editor.setText("");
|
|
86
|
+
editor.handlePaste("/tmp/image1.png");
|
|
87
|
+
editor.handlePaste("/tmp/image2.png");
|
|
88
|
+
assert.equal(editor.getText(), "<Image1><Image2>");
|
|
89
|
+
assert.equal(editor.getExpandedText(), "/tmp/image1.png/tmp/image2.png");
|
|
90
|
+
});
|
|
91
|
+
it("clears dropped image state after submit", () => {
|
|
92
|
+
const editor = new Editor(mockTUI, mockTheme);
|
|
93
|
+
editor.setText("");
|
|
94
|
+
editor.handlePaste("/tmp/image.png");
|
|
95
|
+
// Simulate submit
|
|
96
|
+
const { lines, cursorLine, cursorCol } = editor.getCursor();
|
|
97
|
+
editor.submitValue();
|
|
98
|
+
editor.setText("");
|
|
99
|
+
// Paste again - should get Image1, not Image2
|
|
100
|
+
editor.handlePaste("/tmp/image2.png");
|
|
101
|
+
assert.equal(editor.getText(), "<Image1>");
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
//# sourceMappingURL=editor-dropped-image.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor-dropped-image.test.js","sourceRoot":"","sources":["../../../src/components/__tests__/editor-dropped-image.test.ts"],"names":[],"mappings":"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","sourcesContent":["// Editor dropped image marker tests\n// Tests for image path handling, spacing, and normalization\n\nimport { describe, it } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { Editor } from \"../editor.js\";\n\n// Mock TUI for testing\nconst mockTUI = {\n\trequestRender() {},\n\tterminal: { rows: 24, columns: 80 },\n};\n\n// Mock theme\nconst mockStyle = (s: string) => s;\nconst mockTheme = {\n\tborderColor: mockStyle,\n\tselectList: {\n\t\tselectedPrefix: mockStyle,\n\t\tselectedText: mockStyle,\n\t\tdescription: mockStyle,\n\t\tscrollInfo: mockStyle,\n\t\tnoMatch: mockStyle,\n\t},\n};\n\ndescribe(\"Editor - dropped image markers\", () => {\n\tdescribe(\"handlePaste with image paths\", () => {\n\t\tit(\"decodes file:// URIs and expands to filesystem path\", () => {\n\t\t\tconst editor = new Editor(mockTUI, mockTheme);\n\t\t\teditor.setText(\"foo\");\n\t\t\teditor.handlePaste(\"file:///tmp/My%20Image.png\");\n\n\t\t\tassert.equal(editor.getText(), \"foo <Image1>\");\n\t\t\tassert.equal(editor.getExpandedText(), \"foo /tmp/My Image.png\");\n\t\t});\n\n\t\tit(\"normalizes escaped spaces in paths\", () => {\n\t\t\tconst editor = new Editor(mockTUI, mockTheme);\n\t\t\teditor.setText(\"bar\");\n\t\t\teditor.handlePaste(\"/tmp/My\\\\ Image.png\");\n\n\t\t\tassert.equal(editor.getText(), \"bar <Image1>\");\n\t\t\tassert.equal(editor.getExpandedText(), \"bar /tmp/My Image.png\");\n\t\t});\n\n\t\tit(\"preserves leading space when pasting after word character\", () => {\n\t\t\tconst editor = new Editor(mockTUI, mockTheme);\n\t\t\teditor.setText(\"foo\");\n\t\t\teditor.handlePaste(\"/tmp/image.png\");\n\n\t\t\tassert.equal(editor.getText(), \"foo <Image1>\");\n\t\t\tassert.equal(editor.getExpandedText(), \"foo /tmp/image.png\");\n\t\t});\n\n\t\tit(\"does not add leading space when cursor after space\", () => {\n\t\t\tconst editor = new Editor(mockTUI, mockTheme);\n\t\t\teditor.setText(\"foo \");\n\t\t\teditor.handlePaste(\"/tmp/image.png\");\n\n\t\t\tassert.equal(editor.getText(), \"foo <Image1>\");\n\t\t\tassert.equal(editor.getExpandedText(), \"foo /tmp/image.png\");\n\t\t});\n\n\t\tit(\"does not add leading space when cursor at line start\", () => {\n\t\t\tconst editor = new Editor(mockTUI, mockTheme);\n\t\t\teditor.setText(\"\");\n\t\t\teditor.handlePaste(\"/tmp/image.png\");\n\n\t\t\tassert.equal(editor.getText(), \"<Image1>\");\n\t\t\tassert.equal(editor.getExpandedText(), \"/tmp/image.png\");\n\t\t});\n\n\t\tit(\"handles file:// URI with leading space after word\", () => {\n\t\t\tconst editor = new Editor(mockTUI, mockTheme);\n\t\t\teditor.setText(\"test\");\n\t\t\teditor.handlePaste(\"file:///home/user/photo.jpg\");\n\n\t\t\tassert.equal(editor.getText(), \"test <Image1>\");\n\t\t\tassert.equal(editor.getExpandedText(), \"test /home/user/photo.jpg\");\n\t\t});\n\n\t\tit(\"handles relative paths with leading space after word\", () => {\n\t\t\tconst editor = new Editor(mockTUI, mockTheme);\n\t\t\teditor.setText(\"doc:\");\n\t\t\teditor.handlePaste(\"./images/screenshot.png\");\n\n\t\t\tassert.equal(editor.getText(), \"doc: <Image1>\");\n\t\t\tassert.equal(editor.getExpandedText(), \"doc: ./images/screenshot.png\");\n\t\t});\n\n\t\tit(\"handles tilde paths with leading space after word\", () => {\n\t\t\tconst editor = new Editor(mockTUI, mockTheme);\n\t\t\teditor.setText(\"look at\");\n\t\t\teditor.handlePaste(\"~/Desktop/Screen%20Shot.png\");\n\n\t\t\tassert.equal(editor.getText(), \"look at <Image1>\");\n\t\t\tassert.equal(editor.getExpandedText(), \"look at ~/Desktop/Screen Shot.png\");\n\t\t});\n\t});\n\n\tdescribe(\"image marker expansion\", () => {\n\t\tit(\"expands markers with correct paths on submit\", () => {\n\t\t\tconst editor = new Editor(mockTUI, mockTheme);\n\t\t\teditor.setText(\"\");\n\t\t\teditor.handlePaste(\"/tmp/image1.png\");\n\t\t\teditor.handlePaste(\"/tmp/image2.png\");\n\n\t\t\tassert.equal(editor.getText(), \"<Image1><Image2>\");\n\t\t\tassert.equal(editor.getExpandedText(), \"/tmp/image1.png/tmp/image2.png\");\n\t\t});\n\n\t\tit(\"clears dropped image state after submit\", () => {\n\t\t\tconst editor = new Editor(mockTUI, mockTheme);\n\t\t\teditor.setText(\"\");\n\t\t\teditor.handlePaste(\"/tmp/image.png\");\n\n\t\t\t// Simulate submit\n\t\t\tconst { lines, cursorLine, cursorCol } = editor.getCursor();\n\t\t\teditor.submitValue();\n\t\t\teditor.setText(\"\");\n\n\t\t\t// Paste again - should get Image1, not Image2\n\t\t\teditor.handlePaste(\"/tmp/image2.png\");\n\t\t\tassert.equal(editor.getText(), \"<Image1>\");\n\t\t});\n\t});\n});\n"]}
|
|
@@ -39,6 +39,8 @@ export declare class Editor implements Component, Focusable {
|
|
|
39
39
|
private static readonly AUTOCOMPLETE_DEBOUNCE_MS;
|
|
40
40
|
private pastes;
|
|
41
41
|
private pasteCounter;
|
|
42
|
+
private droppedImagePaths;
|
|
43
|
+
private droppedImageCounter;
|
|
42
44
|
private pasteBuffer;
|
|
43
45
|
private isInPaste;
|
|
44
46
|
private history;
|
|
@@ -85,6 +87,8 @@ export declare class Editor implements Component, Focusable {
|
|
|
85
87
|
* Use this when you need the full content (e.g., for external editor).
|
|
86
88
|
*/
|
|
87
89
|
getExpandedText(): string;
|
|
90
|
+
private expandDroppedImageMarkers;
|
|
91
|
+
private extractDroppedImagePath;
|
|
88
92
|
getLines(): string[];
|
|
89
93
|
getCursor(): {
|
|
90
94
|
line: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/components/editor.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/components/editor.ts"],"names":[],"mappings":"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"}
|
|
@@ -95,6 +95,9 @@ export class Editor {
|
|
|
95
95
|
// Paste tracking for large pastes
|
|
96
96
|
this.pastes = new Map();
|
|
97
97
|
this.pasteCounter = 0;
|
|
98
|
+
// Drag-and-drop image path markers (visual only; expanded back on submit)
|
|
99
|
+
this.droppedImagePaths = new Map();
|
|
100
|
+
this.droppedImageCounter = 0;
|
|
98
101
|
// Bracketed paste mode buffering
|
|
99
102
|
this.pasteBuffer = "";
|
|
100
103
|
this.isInPaste = false;
|
|
@@ -723,8 +726,44 @@ export class Editor {
|
|
|
723
726
|
const markerRegex = new RegExp(`\\[paste #${pasteId}( (\\+\\d+ lines|\\d+ chars))?\\]`, "g");
|
|
724
727
|
result = result.replace(markerRegex, pasteContent);
|
|
725
728
|
}
|
|
729
|
+
return this.expandDroppedImageMarkers(result);
|
|
730
|
+
}
|
|
731
|
+
expandDroppedImageMarkers(text) {
|
|
732
|
+
let result = text;
|
|
733
|
+
for (const [imageId, imagePath] of this.droppedImagePaths) {
|
|
734
|
+
const markerRegex = new RegExp(`<Image${imageId}>`, "g");
|
|
735
|
+
result = result.replace(markerRegex, imagePath);
|
|
736
|
+
}
|
|
726
737
|
return result;
|
|
727
738
|
}
|
|
739
|
+
extractDroppedImagePath(pastedText) {
|
|
740
|
+
const trimmed = pastedText.trim();
|
|
741
|
+
if (!trimmed || /[\n\r\t]/.test(trimmed))
|
|
742
|
+
return null;
|
|
743
|
+
const unquoted = (trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
744
|
+
(trimmed.startsWith("'") && trimmed.endsWith("'"))
|
|
745
|
+
? trimmed.slice(1, -1)
|
|
746
|
+
: trimmed;
|
|
747
|
+
let maybePath = unquoted;
|
|
748
|
+
if (unquoted.startsWith("file://")) {
|
|
749
|
+
try {
|
|
750
|
+
maybePath = decodeURI(unquoted.replace(/^file:\/\//, ""));
|
|
751
|
+
}
|
|
752
|
+
catch {
|
|
753
|
+
return null;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
const normalizedPath = maybePath.replace(/\\ /g, " ");
|
|
757
|
+
if (!/\.(png|jpe?g|gif|webp|bmp|tiff?|svg|heic|heif|avif)$/i.test(normalizedPath)) {
|
|
758
|
+
return null;
|
|
759
|
+
}
|
|
760
|
+
if (!normalizedPath.startsWith("/") && !normalizedPath.startsWith("~/") && !normalizedPath.startsWith("./") && !normalizedPath.startsWith("../")) {
|
|
761
|
+
return null;
|
|
762
|
+
}
|
|
763
|
+
// Return the normalized filesystem path (not the raw trimmed input)
|
|
764
|
+
// This ensures file:// URIs are decoded and escaped spaces are normalized
|
|
765
|
+
return normalizedPath;
|
|
766
|
+
}
|
|
728
767
|
getLines() {
|
|
729
768
|
return [...this.state.lines];
|
|
730
769
|
}
|
|
@@ -880,15 +919,27 @@ export class Editor {
|
|
|
880
919
|
.split("")
|
|
881
920
|
.filter((char) => char === "\n" || char.charCodeAt(0) >= 32)
|
|
882
921
|
.join("");
|
|
883
|
-
//
|
|
884
|
-
//
|
|
885
|
-
|
|
922
|
+
// Check if we need a leading space for readability
|
|
923
|
+
// This applies to file:// URIs, absolute paths (~, /), or relative paths (., ..)
|
|
924
|
+
let needsLeadingSpace = false;
|
|
925
|
+
if (/^(file:\/\/|[/~.])/.test(filteredText)) {
|
|
886
926
|
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
887
927
|
const charBeforeCursor = this.state.cursorCol > 0 ? currentLine[this.state.cursorCol - 1] : "";
|
|
888
928
|
if (charBeforeCursor && /\w/.test(charBeforeCursor)) {
|
|
929
|
+
needsLeadingSpace = true;
|
|
889
930
|
filteredText = ` ${filteredText}`;
|
|
890
931
|
}
|
|
891
932
|
}
|
|
933
|
+
const droppedImagePath = this.extractDroppedImagePath(filteredText);
|
|
934
|
+
if (droppedImagePath) {
|
|
935
|
+
this.droppedImageCounter++;
|
|
936
|
+
const imageId = this.droppedImageCounter;
|
|
937
|
+
this.droppedImagePaths.set(imageId, droppedImagePath);
|
|
938
|
+
// Preserve leading space for readability (e.g., "foo" -> "foo <Image1>" -> "foo /tmp/image.png")
|
|
939
|
+
const toInsert = needsLeadingSpace ? ` <Image${imageId}>` : `<Image${imageId}>`;
|
|
940
|
+
this.insertTextAtCursorInternal(toInsert);
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
892
943
|
// Split into lines to check for large paste
|
|
893
944
|
const pastedLines = filteredText.split("\n");
|
|
894
945
|
// Check if this is a large paste (> 10 lines or > 1000 characters)
|
|
@@ -946,9 +997,12 @@ export class Editor {
|
|
|
946
997
|
const markerRegex = new RegExp(`\\[paste #${pasteId}( (\\+\\d+ lines|\\d+ chars))?\\]`, "g");
|
|
947
998
|
result = result.replace(markerRegex, pasteContent);
|
|
948
999
|
}
|
|
1000
|
+
result = this.expandDroppedImageMarkers(result);
|
|
949
1001
|
this.state = { lines: [""], cursorLine: 0, cursorCol: 0 };
|
|
950
1002
|
this.pastes.clear();
|
|
951
1003
|
this.pasteCounter = 0;
|
|
1004
|
+
this.droppedImagePaths.clear();
|
|
1005
|
+
this.droppedImageCounter = 0;
|
|
952
1006
|
this.historyIndex = -1;
|
|
953
1007
|
this.scrollOffset = 0;
|
|
954
1008
|
this.undoStack.clear();
|