@almyty/chat 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +163 -24
- package/dist/app.d.ts +3 -1
- package/dist/app.js +283 -177
- package/dist/args.d.ts +64 -0
- package/dist/args.js +207 -0
- package/dist/commands.d.ts +21 -1
- package/dist/commands.js +50 -4
- package/dist/components.d.ts +7 -1
- package/dist/components.js +18 -26
- package/dist/errors.d.ts +49 -0
- package/dist/errors.js +144 -0
- package/dist/exit-codes.d.ts +32 -0
- package/dist/exit-codes.js +65 -0
- package/dist/headless.d.ts +44 -0
- package/dist/headless.js +106 -0
- package/dist/history.d.ts +51 -0
- package/dist/history.js +146 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +112 -40
- package/dist/stream.d.ts +95 -0
- package/dist/stream.js +276 -0
- package/dist/turn.d.ts +53 -0
- package/dist/turn.js +147 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +27 -0
- package/dist/viewport.d.ts +61 -0
- package/dist/viewport.js +118 -0
- package/package.json +9 -5
package/dist/viewport.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How much of the transcript fits on screen.
|
|
3
|
+
*
|
|
4
|
+
* ink redraws its whole tree, so a transcript taller than the terminal
|
|
5
|
+
* garbles the frame instead of scrolling it. The fix is to draw only
|
|
6
|
+
* what fits and say how much is above. Pure arithmetic, kept out of the
|
|
7
|
+
* components so it can be tested at any terminal size — including the
|
|
8
|
+
* 40-column window nobody remembers to try.
|
|
9
|
+
*/
|
|
10
|
+
/** Narrowest width worth laying out for. */
|
|
11
|
+
export const MIN_COLUMNS = 40;
|
|
12
|
+
/** Fewest transcript rows to draw, even on a very short terminal. */
|
|
13
|
+
export const MIN_ROWS = 5;
|
|
14
|
+
export function columns(stdoutColumns) {
|
|
15
|
+
return Math.max(stdoutColumns && stdoutColumns > 0 ? stdoutColumns : 80, MIN_COLUMNS);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Rows left for the transcript once the header, prompt and status bar
|
|
19
|
+
* have taken theirs.
|
|
20
|
+
*/
|
|
21
|
+
export function usableRows(stdoutRows, chromeRows) {
|
|
22
|
+
const total = stdoutRows && stdoutRows > 0 ? stdoutRows : 24;
|
|
23
|
+
return Math.max(total - chromeRows, MIN_ROWS);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Code points that take two terminal columns: the East Asian Wide and
|
|
27
|
+
* Fullwidth ranges, plus the emoji blocks terminals render double-width.
|
|
28
|
+
*/
|
|
29
|
+
function isWide(cp) {
|
|
30
|
+
return ((cp >= 0x1100 && cp <= 0x115f) || // Hangul Jamo
|
|
31
|
+
(cp >= 0x2e80 && cp <= 0x303e) || // CJK radicals, Kangxi, CJK symbols
|
|
32
|
+
(cp >= 0x3041 && cp <= 0x33ff) || // Hiragana, Katakana, Hangul, CJK compatibility
|
|
33
|
+
(cp >= 0x3400 && cp <= 0x4dbf) || // CJK extension A
|
|
34
|
+
(cp >= 0x4e00 && cp <= 0x9fff) || // CJK unified ideographs
|
|
35
|
+
(cp >= 0xa000 && cp <= 0xa4cf) || // Yi
|
|
36
|
+
(cp >= 0xac00 && cp <= 0xd7a3) || // Hangul syllables
|
|
37
|
+
(cp >= 0xf900 && cp <= 0xfaff) || // CJK compatibility ideographs
|
|
38
|
+
(cp >= 0xfe30 && cp <= 0xfe6f) || // CJK compatibility forms
|
|
39
|
+
(cp >= 0xff00 && cp <= 0xff60) || // Fullwidth forms
|
|
40
|
+
(cp >= 0xffe0 && cp <= 0xffe6) ||
|
|
41
|
+
(cp >= 0x1f300 && cp <= 0x1f64f) || // emoji, pictographs
|
|
42
|
+
(cp >= 0x1f680 && cp <= 0x1f6ff) ||
|
|
43
|
+
(cp >= 0x1f900 && cp <= 0x1f9ff) ||
|
|
44
|
+
(cp >= 0x20000 && cp <= 0x3fffd) // CJK extension B and later
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* How many terminal columns a string occupies.
|
|
49
|
+
*
|
|
50
|
+
* `String.length` counts UTF-16 units, which is not width. A CJK
|
|
51
|
+
* character is one unit and two columns; an emoji is two units and two
|
|
52
|
+
* columns; a combining mark or a zero-width joiner is a unit and no
|
|
53
|
+
* columns. Measuring by length made a Japanese or Chinese transcript
|
|
54
|
+
* estimate half its real height, so the window packed twice what fits
|
|
55
|
+
* and ink drew a frame taller than the terminal — the garbling the rest
|
|
56
|
+
* of this module exists to prevent.
|
|
57
|
+
*/
|
|
58
|
+
export function displayWidth(text) {
|
|
59
|
+
let width = 0;
|
|
60
|
+
for (const ch of text) {
|
|
61
|
+
const cp = ch.codePointAt(0);
|
|
62
|
+
// Zero-width: combining marks, joiners, variation selectors.
|
|
63
|
+
if (cp === 0x200b || cp === 0x200d || cp === 0xfeff ||
|
|
64
|
+
(cp >= 0x0300 && cp <= 0x036f) ||
|
|
65
|
+
(cp >= 0x1ab0 && cp <= 0x1aff) ||
|
|
66
|
+
(cp >= 0x20d0 && cp <= 0x20f0) ||
|
|
67
|
+
(cp >= 0xfe00 && cp <= 0xfe0f)) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
width += isWide(cp) ? 2 : 1;
|
|
71
|
+
}
|
|
72
|
+
return width;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Rows one message will occupy at this width.
|
|
76
|
+
*
|
|
77
|
+
* Counts the wrap, not the characters: a 300-character paragraph is
|
|
78
|
+
* four rows at 80 columns and eight at 40.
|
|
79
|
+
*/
|
|
80
|
+
export function estimateLines(text, cols) {
|
|
81
|
+
const textWidth = Math.max(cols - 10, 20);
|
|
82
|
+
const lines = text.split('\n');
|
|
83
|
+
let total = 1; // the margin every message carries
|
|
84
|
+
for (const line of lines) {
|
|
85
|
+
total += Math.max(1, Math.ceil(Math.max(displayWidth(line), 1) / textWidth));
|
|
86
|
+
}
|
|
87
|
+
return total;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The slice of messages to draw.
|
|
91
|
+
*
|
|
92
|
+
* Walks backwards from the end so the newest message is always visible:
|
|
93
|
+
* a transcript that scrolls away from the answer you just asked for is
|
|
94
|
+
* worse than one that hides the beginning. The newest message is kept
|
|
95
|
+
* even when it alone is taller than the window, because dropping it
|
|
96
|
+
* would leave an empty screen.
|
|
97
|
+
*/
|
|
98
|
+
export function selectWindow(messages, options) {
|
|
99
|
+
const scrollOffset = Math.max(0, Math.min(options.scrollOffset ?? 0, messages.length));
|
|
100
|
+
const available = Math.max(options.rows - (options.reservedRows ?? 0), MIN_ROWS);
|
|
101
|
+
const endIdx = Math.max(0, messages.length - scrollOffset);
|
|
102
|
+
let used = 0;
|
|
103
|
+
let startIdx = endIdx;
|
|
104
|
+
for (let i = endIdx - 1; i >= 0; i--) {
|
|
105
|
+
const cost = estimateLines(messages[i].text, options.cols);
|
|
106
|
+
// The last message always goes in; anything earlier has to fit.
|
|
107
|
+
if (used + cost > available && i < endIdx - 1)
|
|
108
|
+
break;
|
|
109
|
+
used += cost;
|
|
110
|
+
startIdx = i;
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
startIdx,
|
|
114
|
+
endIdx,
|
|
115
|
+
hiddenBefore: startIdx,
|
|
116
|
+
hiddenAfter: messages.length - endIdx,
|
|
117
|
+
};
|
|
118
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@almyty/chat",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"description": "Chat with your almyty agents in an interactive terminal REPL
|
|
7
|
+
"description": "Chat with your almyty agents in an interactive terminal REPL — multi-turn and streaming, with tool calls and autonomous runs.",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "dist/index.js",
|
|
10
10
|
"bin": {
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
],
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "tsc && chmod +x dist/index.js",
|
|
18
|
-
"dev": "tsx src/index.
|
|
18
|
+
"dev": "tsx src/index.tsx",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
19
20
|
"test": "vitest run",
|
|
20
21
|
"test:watch": "vitest",
|
|
21
22
|
"prepublishOnly": "npm run build"
|
|
@@ -31,15 +32,15 @@
|
|
|
31
32
|
"license": "Apache-2.0",
|
|
32
33
|
"dependencies": {
|
|
33
34
|
"@almyty/client": "^1.2.0",
|
|
34
|
-
"@types/react": "^19.2.14",
|
|
35
35
|
"ink": "^7.0.1",
|
|
36
36
|
"ink-spinner": "^5.0.0",
|
|
37
|
-
"ink-testing-library": "^4.0.0",
|
|
38
37
|
"ink-text-input": "^6.0.0",
|
|
39
38
|
"react": "^19.2.5"
|
|
40
39
|
},
|
|
41
40
|
"devDependencies": {
|
|
42
41
|
"@types/node": "^25.4.0",
|
|
42
|
+
"@types/react": "^19.2.14",
|
|
43
|
+
"ink-testing-library": "^4.0.0",
|
|
43
44
|
"tsx": "^4.7.0",
|
|
44
45
|
"typescript": "^5.3.0",
|
|
45
46
|
"vitest": "^4.1.0"
|
|
@@ -52,5 +53,8 @@
|
|
|
52
53
|
},
|
|
53
54
|
"bugs": {
|
|
54
55
|
"url": "https://github.com/almyty-inc/almyty/issues"
|
|
56
|
+
},
|
|
57
|
+
"overrides": {
|
|
58
|
+
"postcss": "^8.5.23"
|
|
55
59
|
}
|
|
56
60
|
}
|