oharness 0.1.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 (76) hide show
  1. package/dist/bin/sync.d.ts +3 -0
  2. package/dist/bin/sync.js +4 -0
  3. package/dist/bin/sync.js.map +1 -0
  4. package/dist/bin/web.d.ts +10 -0
  5. package/dist/bin/web.js +11 -0
  6. package/dist/bin/web.js.map +1 -0
  7. package/dist/headless/main.d.ts +2 -0
  8. package/dist/headless/main.js +133 -0
  9. package/dist/headless/main.js.map +1 -0
  10. package/dist/index.d.ts +8 -0
  11. package/dist/index.js +9 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/providers.d.ts +2 -0
  14. package/dist/providers.js +3 -0
  15. package/dist/providers.js.map +1 -0
  16. package/dist/tools.d.ts +2 -0
  17. package/dist/tools.js +3 -0
  18. package/dist/tools.js.map +1 -0
  19. package/dist/ui/artifact.d.ts +32 -0
  20. package/dist/ui/artifact.js +49 -0
  21. package/dist/ui/artifact.js.map +1 -0
  22. package/dist/ui/auth.d.ts +14 -0
  23. package/dist/ui/auth.js +177 -0
  24. package/dist/ui/auth.js.map +1 -0
  25. package/dist/ui/colors.d.ts +21 -0
  26. package/dist/ui/colors.js +28 -0
  27. package/dist/ui/colors.js.map +1 -0
  28. package/dist/ui/ink/app.d.ts +13 -0
  29. package/dist/ui/ink/app.js +418 -0
  30. package/dist/ui/ink/app.js.map +1 -0
  31. package/dist/ui/ink/logo.d.ts +6 -0
  32. package/dist/ui/ink/logo.js +20 -0
  33. package/dist/ui/ink/logo.js.map +1 -0
  34. package/dist/ui/ink/main.d.ts +2 -0
  35. package/dist/ui/ink/main.js +55 -0
  36. package/dist/ui/ink/main.js.map +1 -0
  37. package/dist/ui/ink/screen.d.ts +15 -0
  38. package/dist/ui/ink/screen.js +76 -0
  39. package/dist/ui/ink/screen.js.map +1 -0
  40. package/dist/ui/ink/select.d.ts +24 -0
  41. package/dist/ui/ink/select.js +74 -0
  42. package/dist/ui/ink/select.js.map +1 -0
  43. package/dist/ui/main.d.ts +2 -0
  44. package/dist/ui/main.js +1062 -0
  45. package/dist/ui/main.js.map +1 -0
  46. package/dist/ui/render.d.ts +15 -0
  47. package/dist/ui/render.js +130 -0
  48. package/dist/ui/render.js.map +1 -0
  49. package/dist/ui/select.d.ts +26 -0
  50. package/dist/ui/select.js +107 -0
  51. package/dist/ui/select.js.map +1 -0
  52. package/dist/ui/tui/app.d.ts +96 -0
  53. package/dist/ui/tui/app.js +476 -0
  54. package/dist/ui/tui/app.js.map +1 -0
  55. package/dist/ui/tui/editor.d.ts +40 -0
  56. package/dist/ui/tui/editor.js +124 -0
  57. package/dist/ui/tui/editor.js.map +1 -0
  58. package/dist/ui/tui/keys.d.ts +25 -0
  59. package/dist/ui/tui/keys.js +133 -0
  60. package/dist/ui/tui/keys.js.map +1 -0
  61. package/dist/ui/tui/layout.d.ts +63 -0
  62. package/dist/ui/tui/layout.js +202 -0
  63. package/dist/ui/tui/layout.js.map +1 -0
  64. package/dist/ui/tui/logo.d.ts +18 -0
  65. package/dist/ui/tui/logo.js +33 -0
  66. package/dist/ui/tui/logo.js.map +1 -0
  67. package/dist/ui/tui/screen.d.ts +48 -0
  68. package/dist/ui/tui/screen.js +150 -0
  69. package/dist/ui/tui/screen.js.map +1 -0
  70. package/dist/ui/tui/width.d.ts +30 -0
  71. package/dist/ui/tui/width.js +197 -0
  72. package/dist/ui/tui/width.js.map +1 -0
  73. package/dist/ui/wordmark.d.ts +30 -0
  74. package/dist/ui/wordmark.js +63 -0
  75. package/dist/ui/wordmark.js.map +1 -0
  76. package/package.json +49 -0
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Terminal ownership: the alternate buffer, raw mode, and getting out again.
3
+ *
4
+ * The failure that matters here is not a misdrawn frame. It is exiting without
5
+ * restoring: the user is left in raw mode with no echo and no cursor, facing a
6
+ * terminal that appears frozen, and their only recovery is to type `reset`
7
+ * blind. So restoration is wired to every exit path there is — normal return,
8
+ * thrown exception, unhandled rejection, and the signals a terminal or a
9
+ * supervisor can deliver — and it is idempotent, because several of those can
10
+ * fire together.
11
+ */
12
+ const ESC = "\u001b";
13
+ const ALT_SCREEN_ON = `${ESC}[?1049h`;
14
+ const ALT_SCREEN_OFF = `${ESC}[?1049l`;
15
+ const CURSOR_HIDE = `${ESC}[?25l`;
16
+ const CURSOR_SHOW = `${ESC}[?25h`;
17
+ const CURSOR_HOME = `${ESC}[H`;
18
+ const CLEAR_BELOW = `${ESC}[J`;
19
+ const CLEAR_LINE_END = `${ESC}[K`;
20
+ /**
21
+ * Synchronized output: the terminal buffers everything between these and
22
+ * presents it at once. Terminals that do not support it ignore the sequence,
23
+ * so it costs nothing and removes tearing on the ones that do.
24
+ */
25
+ const SYNC_BEGIN = `${ESC}[?2026h`;
26
+ const SYNC_END = `${ESC}[?2026l`;
27
+ /**
28
+ * How long a signal waits for `beforeExit`.
29
+ *
30
+ * A tool that ignores its abort signal must not keep the process alive, and a
31
+ * supervisor that sent SIGTERM will follow with SIGKILL soon enough anyway.
32
+ */
33
+ const EXIT_GRACE_MS = 5_000;
34
+ /**
35
+ * Streams are injectable so the restore path can be tested.
36
+ *
37
+ * Not a general-purpose seam: it exists because "does this leave the terminal
38
+ * usable" is the one behaviour here worth proving, and proving it against the
39
+ * real process streams would wreck the terminal running the tests.
40
+ */
41
+ export function openScreen(streams, opts) {
42
+ const out = (streams?.out ?? process.stdout);
43
+ const input = (streams?.input ?? process.stdin);
44
+ const wasRaw = input.isRaw ?? false;
45
+ let closed = false;
46
+ let keyHandler;
47
+ let resizeHandler;
48
+ const restore = () => {
49
+ if (closed)
50
+ return;
51
+ closed = true;
52
+ // Order matters: leave raw mode before the alt buffer, so a terminal that
53
+ // redraws on buffer switch does it with echo already back on.
54
+ try {
55
+ if (input.isTTY)
56
+ input.setRawMode(wasRaw);
57
+ }
58
+ catch {
59
+ // A stdin that has already been torn down cannot be restored, and
60
+ // throwing here would mask whatever error is actually ending the process.
61
+ }
62
+ input.pause();
63
+ out.write(`${CURSOR_SHOW}${ALT_SCREEN_OFF}`);
64
+ process.off("exit", restore);
65
+ process.off("SIGINT", onSignal);
66
+ process.off("SIGTERM", onSignal);
67
+ process.off("SIGHUP", onSignal);
68
+ out.off("resize", onResize);
69
+ input.off("data", onData);
70
+ };
71
+ const onSignal = () => {
72
+ // Restore before waiting, not after: the terminal has to come back even if
73
+ // the flush below hangs, and `render` is a no-op once closed, so nothing
74
+ // can draw over the restored screen in the meantime. `restore` also
75
+ // unregisters these handlers, so a second signal takes the default action
76
+ // and kills us immediately — which is what an impatient user wants.
77
+ restore();
78
+ const pending = opts?.beforeExit?.();
79
+ // Exit code 130 by convention, so a supervisor reading the status can see
80
+ // that a signal ended this rather than a clean return.
81
+ if (!pending)
82
+ process.exit(130);
83
+ void Promise.race([
84
+ pending.catch(() => { }),
85
+ new Promise((resolve) => setTimeout(resolve, EXIT_GRACE_MS)),
86
+ ]).then(() => process.exit(130));
87
+ };
88
+ const onData = (data) => keyHandler?.(data.toString());
89
+ const onResize = () => resizeHandler?.();
90
+ if (input.isTTY)
91
+ input.setRawMode(true);
92
+ input.resume();
93
+ out.write(`${ALT_SCREEN_ON}${CURSOR_HIDE}${CURSOR_HOME}${CLEAR_BELOW}`);
94
+ // `exit` covers a normal return and an explicit process.exit; the two
95
+ // handlers below cover the errors that would otherwise bypass it.
96
+ process.on("exit", restore);
97
+ process.on("SIGINT", onSignal);
98
+ process.on("SIGTERM", onSignal);
99
+ process.on("SIGHUP", onSignal);
100
+ process.on("uncaughtException", (err) => {
101
+ restore();
102
+ console.error(err);
103
+ process.exit(1);
104
+ });
105
+ process.on("unhandledRejection", (err) => {
106
+ restore();
107
+ console.error(err);
108
+ process.exit(1);
109
+ });
110
+ out.on("resize", onResize);
111
+ input.on("data", onData);
112
+ return {
113
+ get rows() {
114
+ // A terminal that reports nothing still has to be given a size, or every
115
+ // layout calculation divides into an undefined viewport.
116
+ return out.rows || 24;
117
+ },
118
+ get columns() {
119
+ return out.columns || 80;
120
+ },
121
+ render(lines, cursor) {
122
+ if (closed)
123
+ return;
124
+ const height = out.rows || 24;
125
+ const frame = lines.slice(0, height);
126
+ let buffer = `${SYNC_BEGIN}${CURSOR_HIDE}${CURSOR_HOME}`;
127
+ for (let i = 0; i < frame.length; i++) {
128
+ // Erase to end of line per row instead of clearing the screen first:
129
+ // a full clear makes every frame flash on terminals without
130
+ // synchronized output.
131
+ buffer += `${frame[i]}${CLEAR_LINE_END}`;
132
+ if (i < frame.length - 1)
133
+ buffer += "\r\n";
134
+ }
135
+ buffer += CLEAR_BELOW;
136
+ if (cursor)
137
+ buffer += `${ESC}[${cursor.row};${cursor.column}H${CURSOR_SHOW}`;
138
+ buffer += SYNC_END;
139
+ out.write(buffer);
140
+ },
141
+ onKey(handler) {
142
+ keyHandler = handler;
143
+ },
144
+ onResize(handler) {
145
+ resizeHandler = handler;
146
+ },
147
+ close: restore,
148
+ };
149
+ }
150
+ //# sourceMappingURL=screen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen.js","sourceRoot":"","sources":["../../../src/ui/tui/screen.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * How wide a string is on a terminal, and how to break it into rows.
3
+ *
4
+ * Every row count in the layout comes from here, so the two ways a naive
5
+ * `string.length` lies both have to be handled:
6
+ *
7
+ * - ANSI colour codes are in the string but occupy no columns.
8
+ * - East Asian characters occupy two columns each. Getting this wrong makes
9
+ * Chinese text wrap short, and every row below it lands in the wrong place.
10
+ */
11
+ export declare function stripAnsi(text: string): string;
12
+ export declare function charWidth(codePoint: number): number;
13
+ /** Columns the string occupies once colour codes are discounted. */
14
+ export declare function visibleWidth(text: string): number;
15
+ /**
16
+ * Cut a string to at most `columns`, appending an ellipsis when it did not fit.
17
+ *
18
+ * Cuts on character boundaries, never inside a surrogate pair, and never
19
+ * halfway through a wide character — a half-drawn CJK glyph corrupts every
20
+ * column after it on that row.
21
+ */
22
+ export declare function truncate(text: string, columns: number): string;
23
+ /**
24
+ * Break text into rows no wider than `columns`.
25
+ *
26
+ * Wraps at word boundaries when it can and mid-word when a single word is
27
+ * longer than the line, which is common for paths and stack traces. Explicit
28
+ * newlines always start a new row.
29
+ */
30
+ export declare function wrap(text: string, columns: number): string[];
@@ -0,0 +1,197 @@
1
+ /**
2
+ * How wide a string is on a terminal, and how to break it into rows.
3
+ *
4
+ * Every row count in the layout comes from here, so the two ways a naive
5
+ * `string.length` lies both have to be handled:
6
+ *
7
+ * - ANSI colour codes are in the string but occupy no columns.
8
+ * - East Asian characters occupy two columns each. Getting this wrong makes
9
+ * Chinese text wrap short, and every row below it lands in the wrong place.
10
+ */
11
+ // eslint-disable-next-line no-control-regex
12
+ const ANSI = /\u001b\[[0-9;?]*[a-zA-Z]/g;
13
+ export function stripAnsi(text) {
14
+ return text.replace(ANSI, "");
15
+ }
16
+ /**
17
+ * Columns occupied by one code point.
18
+ *
19
+ * Ranges follow Unicode's East Asian Width property (W and F). This is the
20
+ * same table every terminal uses; an approximation here would show up as text
21
+ * drifting one column further right with each CJK character on the line.
22
+ */
23
+ /**
24
+ * Code point ranges that occupy two columns, sorted and non-overlapping.
25
+ *
26
+ * A table rather than a chain of `||` conditions, because a reviewer can check
27
+ * a table against Unicode's EastAsianWidth.txt. The first version of this was
28
+ * a boolean expression and it silently gave U+1F680 (🚀) a width of one: the
29
+ * emoji block was written as ending at 1F64F, and nothing said otherwise.
30
+ */
31
+ const WIDE = [
32
+ [0x1100, 0x115f], // Hangul Jamo
33
+ [0x2329, 0x232a], // angle brackets
34
+ [0x2e80, 0x303e], // CJK radicals, Kangxi, CJK symbols
35
+ [0x3041, 0x33ff], // kana, Hangul compat, CJK compat
36
+ [0x3400, 0x4dbf], // CJK ext A
37
+ [0x4e00, 0x9fff], // CJK unified
38
+ [0xa000, 0xa4cf], // Yi
39
+ [0xa960, 0xa97f], // Hangul Jamo ext A
40
+ [0xac00, 0xd7a3], // Hangul syllables
41
+ [0xf900, 0xfaff], // CJK compat ideographs
42
+ [0xfe10, 0xfe19], // vertical forms
43
+ [0xfe30, 0xfe6f], // CJK compat forms
44
+ [0xff00, 0xff60], // fullwidth forms
45
+ [0xffe0, 0xffe6], // fullwidth signs
46
+ [0x1f300, 0x1f64f], // misc symbols, emoticons
47
+ [0x1f680, 0x1f6ff], // transport and map symbols
48
+ [0x1f7e0, 0x1f7eb], // coloured shapes
49
+ [0x1f900, 0x1f9ff], // supplemental symbols, people
50
+ [0x1fa70, 0x1faff], // extended-A symbols
51
+ [0x20000, 0x2fffd], // CJK ext B onward
52
+ [0x30000, 0x3fffd],
53
+ ];
54
+ export function charWidth(codePoint) {
55
+ // Control characters and combining marks take no space of their own.
56
+ if (codePoint === 0)
57
+ return 0;
58
+ if (codePoint < 32 || (codePoint >= 0x7f && codePoint < 0xa0))
59
+ return 0;
60
+ if (isCombining(codePoint))
61
+ return 0;
62
+ for (const [low, high] of WIDE) {
63
+ if (codePoint < low)
64
+ break; // sorted, so nothing further can match
65
+ if (codePoint <= high)
66
+ return 2;
67
+ }
68
+ return 1;
69
+ }
70
+ function isCombining(codePoint) {
71
+ return ((codePoint >= 0x0300 && codePoint <= 0x036f) ||
72
+ (codePoint >= 0x1ab0 && codePoint <= 0x1aff) ||
73
+ (codePoint >= 0x20d0 && codePoint <= 0x20ff) ||
74
+ (codePoint >= 0xfe00 && codePoint <= 0xfe0f) || // variation selectors
75
+ (codePoint >= 0xfe20 && codePoint <= 0xfe2f));
76
+ }
77
+ /** Columns the string occupies once colour codes are discounted. */
78
+ export function visibleWidth(text) {
79
+ let total = 0;
80
+ for (const char of stripAnsi(text))
81
+ total += charWidth(char.codePointAt(0));
82
+ return total;
83
+ }
84
+ /**
85
+ * Cut a string to at most `columns`, appending an ellipsis when it did not fit.
86
+ *
87
+ * Cuts on character boundaries, never inside a surrogate pair, and never
88
+ * halfway through a wide character — a half-drawn CJK glyph corrupts every
89
+ * column after it on that row.
90
+ */
91
+ export function truncate(text, columns) {
92
+ if (columns <= 0)
93
+ return "";
94
+ if (visibleWidth(text) <= columns)
95
+ return text;
96
+ const budget = columns - 1; // room for the ellipsis
97
+ let width = 0;
98
+ let out = "";
99
+ for (const char of stripAnsi(text)) {
100
+ const w = charWidth(char.codePointAt(0));
101
+ if (width + w > budget)
102
+ break;
103
+ width += w;
104
+ out += char;
105
+ }
106
+ return `${out}…`;
107
+ }
108
+ /**
109
+ * Break text into rows no wider than `columns`.
110
+ *
111
+ * Wraps at word boundaries when it can and mid-word when a single word is
112
+ * longer than the line, which is common for paths and stack traces. Explicit
113
+ * newlines always start a new row.
114
+ */
115
+ export function wrap(text, columns) {
116
+ if (columns <= 0)
117
+ return [""];
118
+ const rows = [];
119
+ for (const paragraph of text.split("\n")) {
120
+ if (paragraph === "") {
121
+ rows.push("");
122
+ continue;
123
+ }
124
+ let row = "";
125
+ let width = 0;
126
+ for (const word of splitWords(paragraph)) {
127
+ const wordWidth = visibleWidth(word);
128
+ // A word longer than the whole line has to be broken; otherwise it would
129
+ // either overflow the row or loop forever looking for a fit.
130
+ if (wordWidth > columns) {
131
+ if (row) {
132
+ rows.push(row);
133
+ row = "";
134
+ width = 0;
135
+ }
136
+ for (const piece of hardBreak(word, columns)) {
137
+ if (visibleWidth(piece) === columns)
138
+ rows.push(piece);
139
+ else {
140
+ row = piece;
141
+ width = visibleWidth(piece);
142
+ }
143
+ }
144
+ continue;
145
+ }
146
+ if (width + wordWidth > columns) {
147
+ rows.push(row);
148
+ row = word.trimStart();
149
+ width = visibleWidth(row);
150
+ }
151
+ else {
152
+ row += word;
153
+ width += wordWidth;
154
+ }
155
+ }
156
+ rows.push(row);
157
+ }
158
+ return rows;
159
+ }
160
+ /** Words with their trailing spaces attached, so wrapping keeps the gaps. */
161
+ function splitWords(text) {
162
+ return text.match(/\S+\s*|\s+/g) ?? [];
163
+ }
164
+ function hardBreak(word, columns) {
165
+ const pieces = [];
166
+ let piece = "";
167
+ let width = 0;
168
+ for (const char of word) {
169
+ const w = charWidth(char.codePointAt(0));
170
+ // A glyph wider than the entire line has no faithful rendering — at one
171
+ // column, a CJK character simply cannot be drawn. Emitting it anyway would
172
+ // produce an over-wide row, and every row count below it would then be
173
+ // wrong. A marker keeps the invariant and still shows something is there.
174
+ if (w > columns) {
175
+ if (piece) {
176
+ pieces.push(piece);
177
+ piece = "";
178
+ width = 0;
179
+ }
180
+ pieces.push("…");
181
+ continue;
182
+ }
183
+ if (width + w > columns) {
184
+ pieces.push(piece);
185
+ piece = char;
186
+ width = w;
187
+ }
188
+ else {
189
+ piece += char;
190
+ width += w;
191
+ }
192
+ }
193
+ if (piece)
194
+ pieces.push(piece);
195
+ return pieces;
196
+ }
197
+ //# sourceMappingURL=width.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"width.js","sourceRoot":"","sources":["../../../src/ui/tui/width.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The brand: the mark from `website/public/logo.svg`, and the name beside it.
3
+ *
4
+ * Kept apart from either frontend because both draw it — the hand-written TUI
5
+ * writes rows into a frame, Ink wraps them in components — and two copies of a
6
+ * letterform drift into two different logos. Neither the mark nor the glyphs
7
+ * carry colour; the caller paints them, because Ink and raw ANSI have no way
8
+ * to share that part.
9
+ */
10
+ /**
11
+ * The mark: a ring broken on the two diagonals, with a dot at its centre.
12
+ *
13
+ * The SVG is two hooked strokes — a top edge rounding into a left edge, and a
14
+ * bottom edge rounding into a right edge — leaving gaps at top-right and
15
+ * bottom-left. Box-drawing reproduces that at three rows; a half-block circle
16
+ * would not, because the gaps are the whole idea.
17
+ */
18
+ export declare const MARK: [string, string, string];
19
+ export declare const MARK_WIDTH = 5;
20
+ /** How the name is spelled everywhere it is drawn. */
21
+ export declare const NAME = "OHarness";
22
+ /** The three rows spelling `text`; characters with no glyph are skipped. */
23
+ export declare function word(text: string): string[];
24
+ /** Gap between the mark and the name, in columns. */
25
+ export declare const MARK_GAP = 3;
26
+ /** The name as three rows, plus the width of mark, gap and name together. */
27
+ export declare function wordmark(): {
28
+ rows: string[];
29
+ width: number;
30
+ };
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The brand: the mark from `website/public/logo.svg`, and the name beside it.
3
+ *
4
+ * Kept apart from either frontend because both draw it — the hand-written TUI
5
+ * writes rows into a frame, Ink wraps them in components — and two copies of a
6
+ * letterform drift into two different logos. Neither the mark nor the glyphs
7
+ * carry colour; the caller paints them, because Ink and raw ANSI have no way
8
+ * to share that part.
9
+ */
10
+ /**
11
+ * The mark: a ring broken on the two diagonals, with a dot at its centre.
12
+ *
13
+ * The SVG is two hooked strokes — a top edge rounding into a left edge, and a
14
+ * bottom edge rounding into a right edge — leaving gaps at top-right and
15
+ * bottom-left. Box-drawing reproduces that at three rows; a half-block circle
16
+ * would not, because the gaps are the whole idea.
17
+ */
18
+ export const MARK = [
19
+ "╭─── ",
20
+ "│ ● │",
21
+ " ───╯",
22
+ ];
23
+ export const MARK_WIDTH = 5;
24
+ /** How the name is spelled everywhere it is drawn. */
25
+ export const NAME = "OHarness";
26
+ /**
27
+ * Drawn with half-block characters rather than figlet-style ASCII: at terminal
28
+ * resolution, slashes and underscores read as noise, while a block letterform
29
+ * reads as type.
30
+ *
31
+ * Each glyph is three rows of four columns, the last being the gap. Sized so
32
+ * the mark and the whole name fit inside eighty columns, which is still the
33
+ * width a terminal is assumed to have.
34
+ */
35
+ const GLYPHS = {
36
+ O: ["█▀▀█", "█ █", "▀▀▀▀"],
37
+ H: ["█ █", "█▀▀█", "▀ ▀"],
38
+ a: ["█▀▀█", "█▀▀█", "▀ ▀"],
39
+ e: ["█▀▀█", "█▀▀▀", "▀▀▀▀"],
40
+ n: ["█▀▀█", "█ █", "▀ ▀"],
41
+ r: ["█▀▀█", "█▀▀ ", "▀ ▀"],
42
+ s: ["█▀▀▀", "▀▀▀█", "▀▀▀▀"],
43
+ };
44
+ /** The three rows spelling `text`; characters with no glyph are skipped. */
45
+ export function word(text) {
46
+ const rows = ["", "", ""];
47
+ for (const char of text) {
48
+ const glyph = GLYPHS[char];
49
+ if (!glyph)
50
+ continue;
51
+ for (let i = 0; i < 3; i++)
52
+ rows[i] += glyph[i] + " ";
53
+ }
54
+ return rows.map((row) => row.trimEnd());
55
+ }
56
+ /** Gap between the mark and the name, in columns. */
57
+ export const MARK_GAP = 3;
58
+ /** The name as three rows, plus the width of mark, gap and name together. */
59
+ export function wordmark() {
60
+ const rows = word(NAME);
61
+ return { rows, width: MARK_WIDTH + MARK_GAP + rows[0].length };
62
+ }
63
+ //# sourceMappingURL=wordmark.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wordmark.js","sourceRoot":"","sources":["../../src/ui/wordmark.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,IAAI,GAA6B;IAC5C,OAAO;IACP,OAAO;IACP,OAAO;CACR,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAE5B,sDAAsD;AACtD,MAAM,CAAC,MAAM,IAAI,GAAG,UAAU,CAAC;AAE/B;;;;;;;;GAQG;AACH,MAAM,MAAM,GAA6C;IACvD,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAC3B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAC3B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAC3B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAC3B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAC3B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAC3B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,4EAA4E;AAC5E,MAAM,UAAU,IAAI,CAAC,IAAY;IAC/B,MAAM,IAAI,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;YAAE,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;IACxD,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,qDAAqD;AACrD,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC;AAE1B,6EAA6E;AAC7E,MAAM,UAAU,QAAQ;IACtB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC,MAAM,EAAE,CAAC;AAClE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "oharness",
3
+ "version": "0.1.0",
4
+ "description": "A model-agnostic agent harness: swappable providers, tool calling, MCP, subagents, compaction, hooks and permissions.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "engines": {
8
+ "node": ">=22.6.0"
9
+ },
10
+ "bin": {
11
+ "oharness": "./dist/ui/main.js",
12
+ "oharness-headless": "./dist/headless/main.js",
13
+ "oharness-web": "./dist/bin/web.js",
14
+ "oharness-sync": "./dist/bin/sync.js"
15
+ },
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "oharness-source": "./src/index.ts",
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ },
24
+ "./providers": {
25
+ "oharness-source": "./src/providers.ts",
26
+ "types": "./dist/providers.d.ts",
27
+ "default": "./dist/providers.js"
28
+ },
29
+ "./tools": {
30
+ "oharness-source": "./src/tools.ts",
31
+ "types": "./dist/tools.d.ts",
32
+ "default": "./dist/tools.js"
33
+ }
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "README.md"
38
+ ],
39
+ "scripts": {
40
+ "build": "rm -rf dist && tsc -p tsconfig.build.json"
41
+ },
42
+ "dependencies": {
43
+ "@oharness/engine": "0.1.0",
44
+ "@oharness/server": "0.1.0",
45
+ "@oharness/sync": "0.1.0",
46
+ "ink": "^7.1.1",
47
+ "react": "^19.2.8"
48
+ }
49
+ }