@raidiant/notifai 0.2.1 → 0.3.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.
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Help that answers "what can I do here", not "what strings does argv accept".
3
+ *
4
+ * The old help listed seventeen commands in one flat column, with the two a new
5
+ * user needs (`init`, `login`) sitting between a platform capability dump and
6
+ * an entry point marked "Internal:". Everything was equally prominent, which is
7
+ * the same as nothing being prominent.
8
+ *
9
+ * Grouping and colour are Commander's own (`commandsGroup`, `optionsGroup`, and
10
+ * the `styleX` hooks it calls when the output has colours); this module only
11
+ * supplies the palette and the group vocabulary. Commander turns its styling
12
+ * off by itself when the output is not a terminal, so piped help stays plain
13
+ * without a second code path.
14
+ */
15
+ import { Help } from 'commander';
16
+ import { glyph, style } from './theme.js';
17
+ /**
18
+ * Group headings, in the order a reader meets them.
19
+ *
20
+ * Ordering is by who needs it and when: first run, then daily use, then the
21
+ * commands agents drive, then the things touched once or never. Commander
22
+ * renders groups in first-use order, so these constants are also the layout.
23
+ */
24
+ export const GROUP = {
25
+ start: 'Getting started:',
26
+ daily: 'Everyday:',
27
+ agent: 'For agents and scripts:',
28
+ advanced: 'Account and wiring:',
29
+ help: 'Help:',
30
+ };
31
+ /** Option groups for `send`, which carries thirty flags. */
32
+ export const SEND_GROUP = {
33
+ content: 'What it says:',
34
+ routing: 'Where it goes:',
35
+ presentation: 'How it arrives:',
36
+ reply: 'Asking for an answer:',
37
+ advanced: 'Advanced:',
38
+ };
39
+ /** Group order, independent of the order commands happen to be registered in. */
40
+ const GROUP_ORDER = [
41
+ GROUP.start,
42
+ GROUP.daily,
43
+ GROUP.agent,
44
+ GROUP.advanced,
45
+ GROUP.help,
46
+ ];
47
+ function groupRank(heading) {
48
+ const index = GROUP_ORDER.indexOf(heading);
49
+ // Anything not named above keeps its position relative to its peers, because
50
+ // the sort is stable — which is what lets the same override run over option
51
+ // groups without needing to know their headings.
52
+ return index === -1 ? GROUP_ORDER.length : index;
53
+ }
54
+ export const helpConfiguration = {
55
+ // Groups already carry the intended order; alphabetising would scatter the
56
+ // dependency between `login` and everything that needs a credential.
57
+ sortSubcommands: false,
58
+ sortOptions: false,
59
+ showGlobalOptions: false,
60
+ /**
61
+ * Commander seeds group order from the raw registration order, which ties
62
+ * how the help reads to where a `program.command(…)` block happens to sit in
63
+ * the file — move one and the help silently reorders. Sorting the finished
64
+ * grouping makes `GROUP_ORDER` the single place that decision is made.
65
+ *
66
+ * The same override runs over option groups, whose headings are not in
67
+ * `GROUP_ORDER` at all. They all rank equal, and `sort` is stable, so they
68
+ * keep the order they were declared in.
69
+ */
70
+ groupItems(unsortedItems, visibleItems, getGroup) {
71
+ // `.call` cannot carry the method's own generic through, so the signature
72
+ // is restated once here instead of widening every caller to
73
+ // `Command | Option`.
74
+ const base = Help.prototype.groupItems;
75
+ const grouped = base.call(this, unsortedItems, visibleItems, getGroup);
76
+ return new Map([...grouped.entries()].sort((a, b) => groupRank(a[0]) - groupRank(b[0])));
77
+ },
78
+ styleTitle: (title) => style.heading(title),
79
+ styleCommandText: (text) => style.accent(text),
80
+ styleSubcommandTerm: (text) => style.code(text),
81
+ styleOptionTerm: (text) => style.code(text),
82
+ styleArgumentTerm: (text) => style.code(text),
83
+ styleDescriptionText: (text) => text,
84
+ styleUsage: (text) => text,
85
+ };
86
+ /**
87
+ * Footer for the root help.
88
+ *
89
+ * Its whole job is to make the interactive app discoverable, because someone
90
+ * reading a wall of flags has already demonstrated they did not know it was
91
+ * there.
92
+ */
93
+ export function rootHelpFooter() {
94
+ const lines = [
95
+ '',
96
+ style.heading('Start here'),
97
+ ` ${style.code('notifai')} ${style.dim(`${glyph.arrow} the interactive app: status, settings, devices, test sends`)}`,
98
+ ` ${style.code('notifai init')} ${style.dim(`${glyph.arrow} set this project up, step by step`)}`,
99
+ '',
100
+ style.dim(`Every command takes ${style.code('--help')}. Machine-readable output: ${style.code('--json')}.`),
101
+ style.dim(`Settings are explained by ${style.code('notifai config show')} and ${style.code('notifai config explain <key>')}.`),
102
+ ];
103
+ return lines.join('\n');
104
+ }
105
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/ui/help.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ /** True when the terminal can render the box-drawing and status glyphs below. */
2
+ export declare const unicode: boolean;
3
+ /** True when 24-bit colour is available, which the banner gradient needs. */
4
+ export declare function supportsTrueColor(env?: NodeJS.ProcessEnv): boolean;
5
+ export declare const color: import("picocolors/types.js").Colors & {
6
+ createColors: (enabled?: boolean) => import("picocolors/types.js").Colors;
7
+ };
8
+ /**
9
+ * Brand ramp, shared with the companion app icon: pink → coral → rose →
10
+ * magenta. Used for the wordmark and for accenting the surfaces a human sees.
11
+ */
12
+ export declare const BRAND_RAMP: readonly ["#FF9EC0", "#FF816B", "#EC5A73", "#B84E93"];
13
+ /**
14
+ * Sample the brand ramp at `t` in [0, 1]. Multi-stop so the gradient keeps the
15
+ * icon's coral midtones instead of washing straight from pink to magenta.
16
+ */
17
+ export declare function rampAt(t: number, ramp?: readonly string[]): string;
18
+ /**
19
+ * Paint `text` across the brand ramp, one escape per character.
20
+ *
21
+ * Falls back to a single flat brand colour without truecolor, and to the bare
22
+ * string with colour off — a gradient is the most decorative thing this CLI
23
+ * does, so it must also be the first thing to degrade quietly.
24
+ */
25
+ export declare function gradient(text: string, ramp?: readonly string[]): string;
26
+ /**
27
+ * Paint each line of a block so the gradient runs left-to-right across the
28
+ * whole block rather than restarting per line. The wordmark is one image, and
29
+ * per-line gradients make it read as several.
30
+ */
31
+ export declare function gradientBlock(lines: readonly string[], ramp?: readonly string[]): string[];
32
+ export declare const style: {
33
+ /** A heading that opens a section. */
34
+ readonly heading: (text: string) => string;
35
+ /** The brand voice — command names, the product name, the selected thing. */
36
+ readonly accent: (text: string) => string;
37
+ /** Secondary text: hints, provenance, units, defaults. */
38
+ readonly dim: (text: string) => string;
39
+ /** Something the reader can type. */
40
+ readonly code: (text: string) => string;
41
+ readonly ok: (text: string) => string;
42
+ readonly warn: (text: string) => string;
43
+ readonly bad: (text: string) => string;
44
+ /** A value as it currently stands. */
45
+ readonly value: (text: string) => string;
46
+ /** A value that is not set, or is inherited rather than chosen. */
47
+ readonly unset: (text: string) => string;
48
+ };
49
+ /**
50
+ * Status marks. The glyph and the colour say the same thing twice on purpose;
51
+ * either alone is enough to read the line.
52
+ */
53
+ export declare const glyph: {
54
+ readonly ok: "●" | "*";
55
+ readonly warn: "▲" | "!";
56
+ readonly bad: "✕" | "x";
57
+ readonly pending: "○" | "o";
58
+ readonly bullet: "•" | "-";
59
+ readonly arrow: "→" | "->";
60
+ readonly chevron: "›" | ">";
61
+ readonly bar: "│" | "|";
62
+ };
63
+ export type Tone = 'ok' | 'warn' | 'bad' | 'pending';
64
+ /** A coloured glyph for a tone; the caller supplies the words. */
65
+ export declare function mark(tone: Tone): string;
66
+ /** Visible width, ignoring ANSI escapes, for alignment maths. */
67
+ export declare function width(text: string): number;
68
+ /** Pad to `size` using visible width, so colour never breaks a column. */
69
+ export declare function pad(text: string, size: number): string;
70
+ /**
71
+ * Usable terminal width: the real one, capped so paragraphs do not run to 200
72
+ * characters on a maximised window.
73
+ *
74
+ * No lower clamp. Raising a narrow terminal to a comfortable minimum sounds
75
+ * harmless and is not — every box drawn to that invented width overflows the
76
+ * real one and wraps, which looks far worse than a cramped box that fits.
77
+ */
78
+ export declare function terminalWidth(fallback?: number): number;
79
+ /**
80
+ * A titled box around `rows`.
81
+ *
82
+ * Hand-drawn rather than delegated, because the obvious library call sizes
83
+ * itself from `process.stdout.columns` and divides by it — a pty that reports
84
+ * zero columns (some CI runners, some `script` invocations) makes the padding
85
+ * negative and throws, taking the whole screen down with it. A status card is
86
+ * decoration; it may degrade, but it must never be what crashes the app.
87
+ *
88
+ * Rows are measured with `width`, so colour inside them does not skew the
89
+ * border, and anything too wide for the terminal is clipped rather than
90
+ * wrapped — a status line that wraps stops being a status line.
91
+ */
92
+ export declare function card(title: string, rows: readonly string[], columns?: number): string[];
93
+ /**
94
+ * Truncate to a visible width, carrying escape sequences through untouched.
95
+ *
96
+ * Counting only printable characters is the whole point: slicing a coloured
97
+ * string by `String.length` cuts through an escape sequence and spills raw
98
+ * `[38;2` into the terminal.
99
+ */
100
+ export declare function clip(text: string, limit: number): string;
101
+ /**
102
+ * Wrap `text` to `columns`, returning bare lines.
103
+ *
104
+ * Indentation is the caller's, deliberately: an earlier version indented
105
+ * continuation lines itself, callers indented every line as well, and each
106
+ * wrapped paragraph stepped further right down the page.
107
+ */
108
+ export declare function wrap(text: string, columns: number): string[];
@@ -0,0 +1,261 @@
1
+ /**
2
+ * One visual language for every human-facing surface: help, `config show`,
3
+ * `doctor`, and the interactive app.
4
+ *
5
+ * Two rules hold everything here together.
6
+ *
7
+ * Colour is decoration, never information. Every state that colour marks also
8
+ * carries a glyph and a word, because the output is read through pipes, on
9
+ * monochrome terminals, by screen readers, and by people who cannot separate
10
+ * red from green. `picocolors` resolves to identity functions when stdout is
11
+ * not a TTY or `NO_COLOR` is set, so the plain path is the same code, not a
12
+ * second implementation that can drift.
13
+ *
14
+ * And an agent's bytes are not ours to restyle. Machine-readable output
15
+ * (`--json`) never routes through this module, and every non-TTY invocation
16
+ * lands on the uncoloured branch by construction.
17
+ */
18
+ import pc from 'picocolors';
19
+ /** True when the terminal can render the box-drawing and status glyphs below. */
20
+ export const unicode = process.platform !== 'win32' ||
21
+ process.env['WT_SESSION'] !== undefined ||
22
+ process.env['TERM_PROGRAM'] === 'vscode' ||
23
+ process.env['ConEmuTask'] === '{cmd::Cmder}';
24
+ /** True when 24-bit colour is available, which the banner gradient needs. */
25
+ export function supportsTrueColor(env = process.env) {
26
+ if (!pc.isColorSupported)
27
+ return false;
28
+ const colorterm = env['COLORTERM'] ?? '';
29
+ if (/^(truecolor|24bit)$/i.test(colorterm))
30
+ return true;
31
+ return env['TERM_PROGRAM'] === 'iTerm.app' || env['TERM_PROGRAM'] === 'vscode';
32
+ }
33
+ export const color = pc;
34
+ /**
35
+ * Brand ramp, shared with the companion app icon: pink → coral → rose →
36
+ * magenta. Used for the wordmark and for accenting the surfaces a human sees.
37
+ */
38
+ export const BRAND_RAMP = ['#FF9EC0', '#FF816B', '#EC5A73', '#B84E93'];
39
+ function hexToRgb(hex) {
40
+ const value = Number.parseInt(hex.slice(1), 16);
41
+ return { r: (value >> 16) & 255, g: (value >> 8) & 255, b: value & 255 };
42
+ }
43
+ function mix(a, b, t) {
44
+ return {
45
+ r: Math.round(a.r + (b.r - a.r) * t),
46
+ g: Math.round(a.g + (b.g - a.g) * t),
47
+ b: Math.round(a.b + (b.b - a.b) * t),
48
+ };
49
+ }
50
+ /**
51
+ * Sample the brand ramp at `t` in [0, 1]. Multi-stop so the gradient keeps the
52
+ * icon's coral midtones instead of washing straight from pink to magenta.
53
+ */
54
+ export function rampAt(t, ramp = BRAND_RAMP) {
55
+ const clamped = Math.min(1, Math.max(0, t));
56
+ const span = ramp.length - 1;
57
+ const scaled = clamped * span;
58
+ const index = Math.min(span - 1, Math.floor(scaled));
59
+ const { r, g, b } = mix(hexToRgb(ramp[index]), hexToRgb(ramp[index + 1]), scaled - index);
60
+ return `[38;2;${r};${g};${b}m`;
61
+ }
62
+ const RESET = '';
63
+ /**
64
+ * SGR escape sequences, in the three shapes the helpers below need: stripping
65
+ * them to measure, splitting around them to slice, and recognising one on its
66
+ * own. Kept together so a change to what counts as an escape lands once.
67
+ */
68
+ const ANSI_GLOBAL = /\[[0-9;]*m/g;
69
+ const ANSI_SPLIT = /(\[[0-9;]*m)/;
70
+ const ANSI_ONLY = /^\[[0-9;]*m$/;
71
+ /**
72
+ * Paint `text` across the brand ramp, one escape per character.
73
+ *
74
+ * Falls back to a single flat brand colour without truecolor, and to the bare
75
+ * string with colour off — a gradient is the most decorative thing this CLI
76
+ * does, so it must also be the first thing to degrade quietly.
77
+ */
78
+ export function gradient(text, ramp = BRAND_RAMP) {
79
+ if (!pc.isColorSupported)
80
+ return text;
81
+ if (!supportsTrueColor())
82
+ return pc.magenta(text);
83
+ const chars = [...text];
84
+ const last = Math.max(1, chars.length - 1);
85
+ return chars.map((char, i) => (char === ' ' ? char : `${rampAt(i / last, ramp)}${char}`)).join('') + RESET;
86
+ }
87
+ /**
88
+ * Paint each line of a block so the gradient runs left-to-right across the
89
+ * whole block rather than restarting per line. The wordmark is one image, and
90
+ * per-line gradients make it read as several.
91
+ */
92
+ export function gradientBlock(lines, ramp = BRAND_RAMP) {
93
+ if (!pc.isColorSupported)
94
+ return [...lines];
95
+ const width = Math.max(1, ...lines.map((line) => [...line].length));
96
+ if (!supportsTrueColor())
97
+ return lines.map((line) => pc.magenta(line));
98
+ return lines.map((line) => [...line]
99
+ .map((char, i) => (char === ' ' ? char : `${rampAt(i / Math.max(1, width - 1), ramp)}${char}`))
100
+ .join('') + RESET);
101
+ }
102
+ // ---------------------------------------------------------------------------
103
+ // Semantic styles
104
+ // ---------------------------------------------------------------------------
105
+ export const style = {
106
+ /** A heading that opens a section. */
107
+ heading: (text) => pc.bold(text),
108
+ /** The brand voice — command names, the product name, the selected thing. */
109
+ accent: (text) => pc.magenta(text),
110
+ /** Secondary text: hints, provenance, units, defaults. */
111
+ dim: (text) => pc.dim(text),
112
+ /** Something the reader can type. */
113
+ code: (text) => pc.cyan(text),
114
+ ok: (text) => pc.green(text),
115
+ warn: (text) => pc.yellow(text),
116
+ bad: (text) => pc.red(text),
117
+ /** A value as it currently stands. */
118
+ value: (text) => pc.bold(pc.white(text)),
119
+ /** A value that is not set, or is inherited rather than chosen. */
120
+ unset: (text) => pc.dim(pc.italic(text)),
121
+ };
122
+ /**
123
+ * Status marks. The glyph and the colour say the same thing twice on purpose;
124
+ * either alone is enough to read the line.
125
+ */
126
+ export const glyph = {
127
+ ok: unicode ? '●' : '*',
128
+ warn: unicode ? '▲' : '!',
129
+ bad: unicode ? '✕' : 'x',
130
+ pending: unicode ? '○' : 'o',
131
+ bullet: unicode ? '•' : '-',
132
+ arrow: unicode ? '→' : '->',
133
+ chevron: unicode ? '›' : '>',
134
+ bar: unicode ? '│' : '|',
135
+ };
136
+ /** A coloured glyph for a tone; the caller supplies the words. */
137
+ export function mark(tone) {
138
+ switch (tone) {
139
+ case 'ok':
140
+ return style.ok(glyph.ok);
141
+ case 'warn':
142
+ return style.warn(glyph.warn);
143
+ case 'bad':
144
+ return style.bad(glyph.bad);
145
+ case 'pending':
146
+ return style.dim(glyph.pending);
147
+ }
148
+ }
149
+ /** Visible width, ignoring ANSI escapes, for alignment maths. */
150
+ export function width(text) {
151
+ return [...text.replace(ANSI_GLOBAL, '')].length;
152
+ }
153
+ /** Pad to `size` using visible width, so colour never breaks a column. */
154
+ export function pad(text, size) {
155
+ return text + ' '.repeat(Math.max(0, size - width(text)));
156
+ }
157
+ /**
158
+ * Usable terminal width: the real one, capped so paragraphs do not run to 200
159
+ * characters on a maximised window.
160
+ *
161
+ * No lower clamp. Raising a narrow terminal to a comfortable minimum sounds
162
+ * harmless and is not — every box drawn to that invented width overflows the
163
+ * real one and wraps, which looks far worse than a cramped box that fits.
164
+ */
165
+ export function terminalWidth(fallback = 80) {
166
+ const columns = process.stdout.columns;
167
+ if (typeof columns !== 'number' || columns <= 0)
168
+ return fallback;
169
+ return Math.min(100, columns);
170
+ }
171
+ /**
172
+ * A titled box around `rows`.
173
+ *
174
+ * Hand-drawn rather than delegated, because the obvious library call sizes
175
+ * itself from `process.stdout.columns` and divides by it — a pty that reports
176
+ * zero columns (some CI runners, some `script` invocations) makes the padding
177
+ * negative and throws, taking the whole screen down with it. A status card is
178
+ * decoration; it may degrade, but it must never be what crashes the app.
179
+ *
180
+ * Rows are measured with `width`, so colour inside them does not skew the
181
+ * border, and anything too wide for the terminal is clipped rather than
182
+ * wrapped — a status line that wraps stops being a status line.
183
+ */
184
+ export function card(title, rows, columns = terminalWidth()) {
185
+ const [tl, tr, bl, br, h, v] = unicode
186
+ ? ['╭', '╮', '╰', '╯', '─', '│']
187
+ : ['+', '+', '+', '+', '-', '|'];
188
+ const inner = Math.max(20, columns - 4);
189
+ const content = rows.map((row) => (width(row) > inner ? clip(row, inner) : row));
190
+ const bodyWidth = Math.max(width(title) + 4, ...content.map((row) => width(row)));
191
+ const boxWidth = Math.min(inner, bodyWidth);
192
+ const heading = `${h} ${style.heading(title)} `;
193
+ const lines = [];
194
+ lines.push(style.dim(tl) + heading + style.dim(h.repeat(Math.max(0, boxWidth - width(heading) + 2))) + style.dim(tr));
195
+ for (const row of content) {
196
+ lines.push(`${style.dim(v)} ${pad(row, boxWidth)} ${style.dim(v)}`);
197
+ }
198
+ lines.push(style.dim(bl + h.repeat(boxWidth + 2) + br));
199
+ return lines;
200
+ }
201
+ /**
202
+ * Truncate to a visible width, carrying escape sequences through untouched.
203
+ *
204
+ * Counting only printable characters is the whole point: slicing a coloured
205
+ * string by `String.length` cuts through an escape sequence and spills raw
206
+ * `[38;2` into the terminal.
207
+ */
208
+ export function clip(text, limit) {
209
+ if (width(text) <= limit)
210
+ return text;
211
+ const parts = text.split(ANSI_SPLIT);
212
+ let out = '';
213
+ let visible = 0;
214
+ for (const part of parts) {
215
+ if (part === undefined || part === '')
216
+ continue;
217
+ if (ANSI_ONLY.test(part)) {
218
+ out += part;
219
+ continue;
220
+ }
221
+ for (const char of part) {
222
+ if (visible >= limit - 1)
223
+ return `${out}\u2026${RESET}`;
224
+ out += char;
225
+ visible += 1;
226
+ }
227
+ }
228
+ return `${out}${RESET}`;
229
+ }
230
+ /**
231
+ * Wrap `text` to `columns`, returning bare lines.
232
+ *
233
+ * Indentation is the caller's, deliberately: an earlier version indented
234
+ * continuation lines itself, callers indented every line as well, and each
235
+ * wrapped paragraph stepped further right down the page.
236
+ */
237
+ export function wrap(text, columns) {
238
+ // Honour the width asked for. A floor here would silently ignore small
239
+ // values and hand back lines wider than the caller reserved room for; a
240
+ // width of zero or less is the only nonsense, and that falls back.
241
+ const limit = columns > 0 ? columns : 80;
242
+ const words = text.split(/\s+/).filter(Boolean);
243
+ if (words.length === 0)
244
+ return [''];
245
+ const lines = [];
246
+ let line = '';
247
+ for (const word of words) {
248
+ const candidate = line === '' ? word : `${line} ${word}`;
249
+ if (width(candidate) > limit && line !== '') {
250
+ lines.push(line);
251
+ line = word;
252
+ }
253
+ else {
254
+ line = candidate;
255
+ }
256
+ }
257
+ if (line !== '')
258
+ lines.push(line);
259
+ return lines;
260
+ }
261
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/ui/theme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,MAAM,YAAY,CAAA;AAE3B,iFAAiF;AACjF,MAAM,CAAC,MAAM,OAAO,GAClB,OAAO,CAAC,QAAQ,KAAK,OAAO;IAC5B,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,SAAS;IACvC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,QAAQ;IACxC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,cAAc,CAAA;AAE9C,6EAA6E;AAC7E,MAAM,UAAU,iBAAiB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACpE,IAAI,CAAC,EAAE,CAAC,gBAAgB;QAAE,OAAO,KAAK,CAAA;IACtC,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,CAAA;IACxC,IAAI,sBAAsB,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAA;IACvD,OAAO,GAAG,CAAC,cAAc,CAAC,KAAK,WAAW,IAAI,GAAG,CAAC,cAAc,CAAC,KAAK,QAAQ,CAAA;AAChF,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,EAAE,CAAA;AAEvB;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAU,CAAA;AAQ/E,SAAS,QAAQ,CAAC,GAAW;IAC3B,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAC/C,OAAO,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,KAAK,GAAG,GAAG,EAAE,CAAA;AAC1E,CAAC;AAED,SAAS,GAAG,CAAC,CAAM,EAAE,CAAM,EAAE,CAAS;IACpC,OAAO;QACL,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACpC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACpC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KACrC,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,CAAS,EAAE,OAA0B,UAAU;IACpE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA;IAC5B,MAAM,MAAM,GAAG,OAAO,GAAG,IAAI,CAAA;IAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;IACpD,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAE,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAE,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,CAAA;IAC3F,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAA;AACjC,CAAC;AAED,MAAM,KAAK,GAAG,OAAO,CAAA;AAErB;;;;GAIG;AACH,MAAM,WAAW,GAAG,cAAc,CAAA;AAClC,MAAM,UAAU,GAAG,eAAe,CAAA;AAClC,MAAM,SAAS,GAAG,eAAe,CAAA;AAEjC;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,OAA0B,UAAU;IACzE,IAAI,CAAC,EAAE,CAAC,gBAAgB;QAAE,OAAO,IAAI,CAAA;IACrC,IAAI,CAAC,iBAAiB,EAAE;QAAE,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IACjD,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,CAAA;IACvB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC1C,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,KAAK,CAAA;AAC5G,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAwB,EAAE,OAA0B,UAAU;IAC1F,IAAI,CAAC,EAAE,CAAC,gBAAgB;QAAE,OAAO,CAAC,GAAG,KAAK,CAAC,CAAA;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IACnE,IAAI,CAAC,iBAAiB,EAAE;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IACtE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACxB,CAAC,GAAG,IAAI,CAAC;SACN,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;SAC9F,IAAI,CAAC,EAAE,CAAC,GAAG,KAAK,CACpB,CAAA;AACH,CAAC;AAED,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,sCAAsC;IACtC,OAAO,EAAE,CAAC,IAAY,EAAU,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;IAChD,6EAA6E;IAC7E,MAAM,EAAE,CAAC,IAAY,EAAU,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAClD,0DAA0D;IAC1D,GAAG,EAAE,CAAC,IAAY,EAAU,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;IAC3C,qCAAqC;IACrC,IAAI,EAAE,CAAC,IAAY,EAAU,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;IAC7C,EAAE,EAAE,CAAC,IAAY,EAAU,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;IAC5C,IAAI,EAAE,CAAC,IAAY,EAAU,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC;IAC/C,GAAG,EAAE,CAAC,IAAY,EAAU,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;IAC3C,sCAAsC;IACtC,KAAK,EAAE,CAAC,IAAY,EAAU,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxD,mEAAmE;IACnE,KAAK,EAAE,CAAC,IAAY,EAAU,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CAChD,CAAA;AAEV;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;IACvB,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;IACzB,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;IACxB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;IAC5B,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;IAC3B,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI;IAC3B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;IAC5B,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;CAChB,CAAA;AAIV,kEAAkE;AAClE,MAAM,UAAU,IAAI,CAAC,IAAU;IAC7B,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,IAAI;YACP,OAAO,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC3B,KAAK,MAAM;YACT,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC/B,KAAK,KAAK;YACR,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC7B,KAAK,SAAS;YACZ,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACnC,CAAC;AACH,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,KAAK,CAAC,IAAY;IAChC,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAA;AAClD,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,IAAY;IAC5C,OAAO,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AAC3D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,QAAQ,GAAG,EAAE;IACzC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAA;IACtC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAA;IAChE,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;AAC/B,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,IAAI,CAAC,KAAa,EAAE,IAAuB,EAAE,OAAO,GAAG,aAAa,EAAE;IACpF,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO;QACpC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;QAChC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;IAClC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC,CAAA;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IAChF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACjF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;IAC3C,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAA;IAC/C,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;IACtH,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IACrE,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAG,GAAG,CAAE,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;IACzD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,KAAa;IAC9C,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK;QAAE,OAAO,IAAI,CAAA;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;IACpC,IAAI,GAAG,GAAG,EAAE,CAAA;IACZ,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE;YAAE,SAAQ;QAC/C,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,GAAG,IAAI,IAAI,CAAA;YACX,SAAQ;QACV,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;YACxB,IAAI,OAAO,IAAI,KAAK,GAAG,CAAC;gBAAE,OAAO,GAAG,GAAG,SAAS,KAAK,EAAE,CAAA;YACvD,GAAG,IAAI,IAAI,CAAA;YACX,OAAO,IAAI,CAAC,CAAA;QACd,CAAC;IACH,CAAC;IACD,OAAO,GAAG,GAAG,GAAG,KAAK,EAAE,CAAA;AACzB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,OAAe;IAChD,uEAAuE;IACvE,wEAAwE;IACxE,mEAAmE;IACnE,MAAM,KAAK,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;IACxC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC/C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,EAAE,CAAC,CAAA;IACnC,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,IAAI,IAAI,GAAG,EAAE,CAAA;IACb,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAA;QACxD,IAAI,KAAK,CAAC,SAAS,CAAC,GAAG,KAAK,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;YAC5C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAChB,IAAI,GAAG,IAAI,CAAA;QACb,CAAC;aAAM,CAAC;YACN,IAAI,GAAG,SAAS,CAAA;QAClB,CAAC;IACH,CAAC;IACD,IAAI,IAAI,KAAK,EAAE;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACjC,OAAO,KAAK,CAAA;AACd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raidiant/notifai",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "Send native phone notifications from agents and local programs",
6
6
  "bin": {
@@ -11,10 +11,16 @@
11
11
  "src",
12
12
  "tsconfig.json"
13
13
  ],
14
+ "scripts": {
15
+ "build": "tsc -p tsconfig.json",
16
+ "typecheck": "tsc -p tsconfig.json --noEmit",
17
+ "test": "vitest run"
18
+ },
14
19
  "dependencies": {
15
20
  "@clack/prompts": "^1.7.0",
16
21
  "@raidiant/notifai-protocol": "0.2.0",
17
22
  "commander": "^14.0.0",
23
+ "picocolors": "^1.1.1",
18
24
  "smol-toml": "^1.4.0"
19
25
  },
20
26
  "devDependencies": {
@@ -47,10 +53,5 @@
47
53
  "ai",
48
54
  "claude",
49
55
  "codex"
50
- ],
51
- "scripts": {
52
- "build": "tsc -p tsconfig.json",
53
- "typecheck": "tsc -p tsconfig.json --noEmit",
54
- "test": "vitest run"
55
- }
56
- }
56
+ ]
57
+ }