@raidiant/notifai 0.2.1 → 0.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.
Files changed (94) hide show
  1. package/README.md +20 -4
  2. package/dist/atomic-file.d.ts +4 -0
  3. package/dist/atomic-file.js +60 -10
  4. package/dist/atomic-file.js.map +1 -1
  5. package/dist/client.d.ts +25 -2
  6. package/dist/client.js +45 -1
  7. package/dist/client.js.map +1 -1
  8. package/dist/commands.d.ts +85 -6
  9. package/dist/commands.js +1133 -322
  10. package/dist/commands.js.map +1 -1
  11. package/dist/config-schema.d.ts +62 -0
  12. package/dist/config-schema.js +312 -0
  13. package/dist/config-schema.js.map +1 -0
  14. package/dist/config.d.ts +38 -3
  15. package/dist/config.js +61 -14
  16. package/dist/config.js.map +1 -1
  17. package/dist/file-lock.d.ts +26 -0
  18. package/dist/file-lock.js +268 -0
  19. package/dist/file-lock.js.map +1 -0
  20. package/dist/harnesses.d.ts +28 -0
  21. package/dist/harnesses.js +40 -0
  22. package/dist/harnesses.js.map +1 -0
  23. package/dist/hook-adapter.d.ts +27 -0
  24. package/dist/hook-adapter.js +188 -0
  25. package/dist/hook-adapter.js.map +1 -0
  26. package/dist/hook-input.d.ts +10 -0
  27. package/dist/hook-input.js +64 -0
  28. package/dist/hook-input.js.map +1 -0
  29. package/dist/hooks.d.ts +66 -10
  30. package/dist/hooks.js +751 -276
  31. package/dist/hooks.js.map +1 -1
  32. package/dist/install-hooks.d.ts +40 -16
  33. package/dist/install-hooks.js +217 -73
  34. package/dist/install-hooks.js.map +1 -1
  35. package/dist/interactive.d.ts +4 -0
  36. package/dist/interactive.js +604 -0
  37. package/dist/interactive.js.map +1 -0
  38. package/dist/logging.d.ts +142 -0
  39. package/dist/logging.js +533 -0
  40. package/dist/logging.js.map +1 -0
  41. package/dist/main.js +201 -51
  42. package/dist/main.js.map +1 -1
  43. package/dist/opencode-plugin.d.ts +7 -7
  44. package/dist/opencode-plugin.js +12 -13
  45. package/dist/opencode-plugin.js.map +1 -1
  46. package/dist/ui/banner.d.ts +22 -0
  47. package/dist/ui/banner.js +87 -0
  48. package/dist/ui/banner.js.map +1 -0
  49. package/dist/ui/config-view.d.ts +32 -0
  50. package/dist/ui/config-view.js +108 -0
  51. package/dist/ui/config-view.js.map +1 -0
  52. package/dist/ui/help.d.ts +46 -0
  53. package/dist/ui/help.js +105 -0
  54. package/dist/ui/help.js.map +1 -0
  55. package/dist/ui/theme.d.ts +108 -0
  56. package/dist/ui/theme.js +261 -0
  57. package/dist/ui/theme.js.map +1 -0
  58. package/package.json +11 -9
  59. package/src/atomic-file.ts +86 -7
  60. package/src/client.test.ts +12 -0
  61. package/src/client.ts +72 -4
  62. package/src/commands.test.ts +971 -44
  63. package/src/commands.ts +1323 -337
  64. package/src/config-schema.test.ts +152 -0
  65. package/src/config-schema.ts +363 -0
  66. package/src/config.test.ts +6 -5
  67. package/src/config.ts +85 -16
  68. package/src/file-lock-process-worker.test.ts +64 -0
  69. package/src/file-lock.test.ts +279 -0
  70. package/src/file-lock.ts +318 -0
  71. package/src/harnesses.test.ts +48 -0
  72. package/src/harnesses.ts +59 -0
  73. package/src/hook-adapter.test.ts +187 -0
  74. package/src/hook-adapter.ts +212 -0
  75. package/src/hook-input.test.ts +39 -0
  76. package/src/hook-input.ts +72 -0
  77. package/src/hooks.test.ts +1318 -240
  78. package/src/hooks.ts +1046 -296
  79. package/src/install-hooks.test.ts +90 -41
  80. package/src/install-hooks.ts +259 -74
  81. package/src/interactive.ts +692 -0
  82. package/src/logging-process-worker.test.ts +39 -0
  83. package/src/logging.test.ts +453 -0
  84. package/src/logging.ts +639 -0
  85. package/src/main.ts +220 -48
  86. package/src/opencode-plugin.ts +15 -16
  87. package/src/session-end-log-lock-worker.test.ts +35 -0
  88. package/src/skill.test.ts +11 -0
  89. package/src/ui/banner.ts +95 -0
  90. package/src/ui/config-view.test.ts +88 -0
  91. package/src/ui/config-view.ts +138 -0
  92. package/src/ui/help.ts +124 -0
  93. package/src/ui/theme.test.ts +92 -0
  94. package/src/ui/theme.ts +279 -0
@@ -0,0 +1,62 @@
1
+ import { type ConfigKey } from './config.js';
2
+ export type ConfigKind = 'string' | 'url' | 'integer' | 'boolean' | 'enum' | 'list';
3
+ /**
4
+ * Which surface a key belongs to. Grouping is the difference between fourteen
5
+ * flat keys and four short lists a reader can hold in their head.
6
+ */
7
+ export type ConfigGroup = 'questions' | 'delivery' | 'project' | 'diagnostics' | 'connection';
8
+ export declare const CONFIG_GROUPS: {
9
+ id: ConfigGroup;
10
+ title: string;
11
+ blurb: string;
12
+ }[];
13
+ export interface ConfigKeyInfo {
14
+ key: ConfigKey;
15
+ /** Human words for the key, used as a list label. */
16
+ label: string;
17
+ group: ConfigGroup;
18
+ kind: ConfigKind;
19
+ /** One line. Must fit beside a value without wrapping on an 80-column terminal. */
20
+ summary: string;
21
+ /** The full explanation, shown when the reader asks about this key. */
22
+ detail: string;
23
+ /** Allowed values for `enum`. */
24
+ choices?: readonly string[];
25
+ /** What a choice means, keyed by choice. */
26
+ choiceHints?: Record<string, string>;
27
+ /** Unit suffix rendered after numbers, e.g. `s`. */
28
+ unit?: string;
29
+ /** What the key means when it holds no value. */
30
+ unsetMeans?: string;
31
+ /** A valid value, for error messages and placeholders. */
32
+ example?: string;
33
+ /**
34
+ * Advanced keys are hidden behind an explicit reveal in the interactive
35
+ * settings screen. They are still listed by `config show` — hiding a value
36
+ * that is in force would be worse than showing one nobody needs.
37
+ */
38
+ advanced?: boolean;
39
+ }
40
+ export declare function configInfo(key: ConfigKey): ConfigKeyInfo;
41
+ /** Every key in its group, in the order a reader should meet them. */
42
+ export declare function configKeysByGroup(group: ConfigGroup): ConfigKeyInfo[];
43
+ /** Bounds rendered the way an error message wants them, or null. */
44
+ export declare function boundsHint(key: ConfigKey): string | null;
45
+ /** What a `config set` caller may legally pass, phrased for an error message. */
46
+ export declare function acceptedValues(key: ConfigKey): string;
47
+ /** How a resolved value should read in a list. */
48
+ export declare function formatValue(key: ConfigKey, value: unknown): string;
49
+ /**
50
+ * Where a value came from, in words rather than in a tagged path.
51
+ *
52
+ * `global:/Users/you/.config/notifai/config.toml` answers "which file" but not
53
+ * "why is this the value" — and the second question is the one someone reading
54
+ * `config show` is actually asking. The path is still available for anyone
55
+ * about to edit the file; it is just no longer the whole answer.
56
+ */
57
+ export declare function describeSource(source: string): {
58
+ label: string;
59
+ path: string | null;
60
+ };
61
+ /** Seconds as something a person reads: `300s` is true, `5m` is legible. */
62
+ export declare function formatDuration(value: number, unit: string): string;
@@ -0,0 +1,312 @@
1
+ /**
2
+ * What every configuration key means, in the reader's words.
3
+ *
4
+ * `config.ts` already documented all fourteen keys carefully — but in TypeScript
5
+ * comments, which is the one audience that never needed them. Someone running
6
+ * `notifai config show` saw `require_idle = true` and had no way to learn what
7
+ * it did short of reading the source, so this module is that knowledge moved to
8
+ * where it can be printed.
9
+ *
10
+ * It is the single source for `config show`, `config set`'s errors, `config
11
+ * explain`, the help footer, and the interactive settings screen. One
12
+ * description, rendered five ways, so the surfaces cannot disagree.
13
+ *
14
+ * `summary` is the one-line form that fits beside a value in a list.
15
+ * `detail` is the paragraph shown once the reader has asked for this key
16
+ * specifically — progressive disclosure, so a list of fourteen settings stays
17
+ * a list and not an essay.
18
+ */
19
+ import { CLI_SOUNDS, INTERRUPTION_LEVELS } from '@raidiant/notifai-protocol';
20
+ import { LOG_LEVELS, configBounds } from './config.js';
21
+ export const CONFIG_GROUPS = [
22
+ {
23
+ id: 'questions',
24
+ title: 'Questions & presence',
25
+ blurb: 'When a question an agent registered is allowed to leave this terminal and reach your devices.',
26
+ },
27
+ {
28
+ id: 'delivery',
29
+ title: 'Delivery defaults',
30
+ blurb: 'What a notification looks and behaves like when a command does not say otherwise.',
31
+ },
32
+ {
33
+ id: 'project',
34
+ title: 'This project',
35
+ blurb: 'How work in this directory identifies itself, and the house rules agents read before notifying.',
36
+ },
37
+ {
38
+ id: 'diagnostics',
39
+ title: 'Local logs',
40
+ blurb: 'What this machine records about its own activity, so an agent can find out afterwards what happened.',
41
+ },
42
+ {
43
+ id: 'connection',
44
+ title: 'Connection',
45
+ blurb: 'Which Notifai service this machine talks to. Most people never change this.',
46
+ },
47
+ ];
48
+ const INFO = {
49
+ ask_notifications: {
50
+ label: 'Send questions to my devices',
51
+ group: 'questions',
52
+ kind: 'boolean',
53
+ summary: 'Whether a registered question may reach your phone and Mac at all',
54
+ detail: 'The master switch for question routing. When this is off, a question an agent registers with `notifai ask` stays in the terminal and never leaves this machine, whatever the presence settings say. Turn it off to stop being reached for a while without uninstalling the harness hooks.',
55
+ example: 'true',
56
+ },
57
+ require_idle: {
58
+ label: 'Only when I have stepped away',
59
+ group: 'questions',
60
+ kind: 'boolean',
61
+ summary: 'Whether sitting at this keyboard holds a question back',
62
+ detail: 'Off (the default) means notify me even while I am using this machine. `ask_grace_seconds` still runs, so the terminal is offered the question first; I just do not need to walk away before it may leave. Turn this on when local keyboard or mouse activity should keep questions in the terminal.\n\nThis is separate from `ask_notifications`, which switches routing off altogether: wanting to be reached only while away is different from not wanting to be reached.',
63
+ example: 'false',
64
+ },
65
+ away_after_seconds: {
66
+ label: 'Away after',
67
+ group: 'questions',
68
+ kind: 'integer',
69
+ unit: 's',
70
+ summary: 'Keyboard and mouse idle time before this machine counts as unattended',
71
+ detail: 'How long the keyboard and mouse must be quiet before you count as away. Only consulted while `require_idle` is on.\n\nWhere the operating system exposes no idle signal, silence since your last prompt is used instead, which is the conservative reading.',
72
+ example: '120',
73
+ },
74
+ ask_grace_seconds: {
75
+ label: 'Terminal-first grace',
76
+ group: 'questions',
77
+ kind: 'integer',
78
+ unit: 's',
79
+ summary: 'Optional delay before a question may reach your devices',
80
+ detail: 'Zero (the default) sends the question to your devices as soon as the agent turn ends. Set a positive duration to offer the terminal an exclusive answer window first; the timer is measured from the moment the agent asked.\n\nA timer and nothing more. It is honoured whether or not presence is consulted at all, because how long to wait and whether anyone is watching are separate questions, and answering one should not answer the other.',
81
+ example: '0',
82
+ },
83
+ hook_reply_timeout_seconds: {
84
+ label: 'Hook wait for an answer',
85
+ group: 'questions',
86
+ kind: 'integer',
87
+ unit: 's',
88
+ summary: 'How long the harness hook blocks waiting for your answer',
89
+ detail: 'After a question has gone out, the harness continuation owner waits up to this long for your answer. The device reply window uses the same bound, so Notifai never accepts an answer after an agent with no dormant-session wake has already returned.\n\nThe ceiling exists because command-hook harnesses bound their Stop processes. Grace plus this value plus installer headroom stays inside that budget.',
90
+ example: '480',
91
+ },
92
+ sound: {
93
+ label: 'Sound',
94
+ group: 'delivery',
95
+ kind: 'enum',
96
+ choices: CLI_SOUNDS,
97
+ choiceHints: {
98
+ default: 'the standard notification tone',
99
+ done: 'the completion chime',
100
+ attention: 'used for questions that want an answer',
101
+ alert: 'the most insistent tone',
102
+ none: 'silent — arrives without a sound',
103
+ },
104
+ summary: 'Override the sound every notification uses',
105
+ detail: 'Normally the sound comes from what the notification is: progress updates are silent, completions get the done chime, questions get the attention tone. Setting this pins one sound for everything sent from here, overriding those profiles.\n\nA common use is `none`, to make a noisy project completely silent.',
106
+ unsetMeans: 'each notification uses the sound for its kind',
107
+ },
108
+ interruption_level: {
109
+ label: 'Interruption level',
110
+ group: 'delivery',
111
+ kind: 'enum',
112
+ choices: INTERRUPTION_LEVELS,
113
+ choiceHints: {
114
+ passive: 'no sound or wake — waits in the notification list',
115
+ active: 'wakes the screen and plays the sound',
116
+ time_sensitive: 'may break through Focus modes',
117
+ },
118
+ summary: 'Override how insistently notifications arrive',
119
+ detail: 'How hard a notification tries to reach you, in the operating system\'s terms. Like the sound, this is normally decided by what the notification is; setting it pins one level for everything.\n\n`time_sensitive` can pierce a Focus mode, so it is worth reserving for the cases that genuinely earn it.',
120
+ unsetMeans: 'each notification uses the level for its kind',
121
+ },
122
+ devices: {
123
+ label: 'Default devices',
124
+ group: 'delivery',
125
+ kind: 'list',
126
+ summary: 'Which of your devices receive by default',
127
+ detail: 'A comma-separated list of device ids. When set, notifications go only to these devices unless a command overrides it.\n\nRun `notifai devices` to see the ids and which of them can currently receive.',
128
+ unsetMeans: 'every device that can receive',
129
+ example: 'dev_abc123,dev_def456',
130
+ },
131
+ ttl_seconds: {
132
+ label: 'Delivery window',
133
+ group: 'delivery',
134
+ kind: 'integer',
135
+ unit: 's',
136
+ summary: 'How long the service keeps trying to deliver before giving up',
137
+ detail: 'A notification for a device that is off or offline is held for this long and delivered when the device reappears. After it lapses the notification is dropped rather than arriving stale.\n\nThe default of 86400 is one day.',
138
+ example: '86400',
139
+ },
140
+ wait_seconds: {
141
+ label: 'Wait for outcomes',
142
+ group: 'delivery',
143
+ kind: 'integer',
144
+ unit: 's',
145
+ summary: 'How long `send` waits to report what happened to a notification',
146
+ detail: 'After a notification is accepted, `notifai send` can wait for the delivery outcome so its exit code reflects what actually happened rather than only that the service took it.\n\nSet to 0 to return as soon as the service accepts, which is the fastest option and the one that tells you least.',
147
+ example: '10',
148
+ },
149
+ collapse_key: {
150
+ label: 'Collapse key',
151
+ group: 'delivery',
152
+ kind: 'string',
153
+ summary: 'Replace earlier notifications carrying the same key',
154
+ detail: 'Two notifications sharing a collapse key do not stack — the newer one replaces the older on the lock screen. This is how a status that changes repeatedly stays one line instead of becoming twenty.\n\nSetting it here applies one key to everything sent from here, which is usually too broad; most uses pass `--collapse-key` per send instead.',
155
+ unsetMeans: 'each notification stands on its own',
156
+ advanced: true,
157
+ },
158
+ project: {
159
+ label: 'Project id',
160
+ group: 'project',
161
+ kind: 'string',
162
+ summary: 'The name this project reports itself as',
163
+ detail: 'Stamped on every notification sent from this directory, and how the companion apps group and filter what arrives. Normally set once in `.notifai/config.toml` and committed, so everyone working on the repository reports the same name.',
164
+ unsetMeans: 'notifications arrive without a project',
165
+ example: 'my-app',
166
+ },
167
+ notify_criteria: {
168
+ label: 'House rules for agents',
169
+ group: 'project',
170
+ kind: 'string',
171
+ summary: 'Free text an agent reads before deciding whether to notify you',
172
+ detail: 'Your own guidance, in your own words, about what is worth a notification in this project — read by agents before they send. Something like "only tell me about failures and finished deploys; never per-file progress".\n\nIt is advice to the agent, not a filter the service enforces.',
173
+ unsetMeans: 'agents fall back to their default judgement',
174
+ example: 'Only failures and completed deploys',
175
+ },
176
+ log_level: {
177
+ label: 'Log level',
178
+ group: 'diagnostics',
179
+ kind: 'enum',
180
+ choices: LOG_LEVELS,
181
+ choiceHints: {
182
+ off: 'record nothing',
183
+ error: 'only failures',
184
+ info: 'commands, notifications, and every question decision',
185
+ debug: 'adds config resolution and per-request detail',
186
+ },
187
+ summary: 'How much this machine records about what it did',
188
+ detail: 'Notifai keeps a local record of what it did — every command, every notification, and in particular every decision a harness hook made about whether a question could leave the terminal. Hooks run headless, so without this there is no account of them at all: `notifai logs` is how an agent finds out afterwards why a question never reached your phone.\n\nThe log never leaves this machine. It is not uploaded, and nothing sends it anywhere.\n\n`debug` also records which config layer won and the detail of each request, which is what to turn on when something is behaving in a way the ordinary log does not explain.',
189
+ example: 'info',
190
+ },
191
+ log_max_bytes: {
192
+ label: 'Log file size',
193
+ group: 'diagnostics',
194
+ kind: 'integer',
195
+ summary: 'How large the log grows before it is rotated',
196
+ detail: 'When the active log reaches this size it is renamed aside and a fresh one starts. Together with the number of files kept, this is the whole disk budget: nothing here grows without a ceiling.',
197
+ advanced: true,
198
+ example: '2000000',
199
+ },
200
+ log_max_files: {
201
+ label: 'Log files kept',
202
+ group: 'diagnostics',
203
+ kind: 'integer',
204
+ summary: 'How many rotated log files are kept before the oldest is deleted',
205
+ detail: 'Counts the active file. At the defaults — three files of two megabytes — the logs occupy about six megabytes, which is weeks of ordinary agent traffic.\n\nRaise it when you need to look further back than the log currently reaches; lower it to one to keep only the file being written.',
206
+ advanced: true,
207
+ example: '3',
208
+ },
209
+ base_url: {
210
+ label: 'Service URL',
211
+ group: 'connection',
212
+ kind: 'url',
213
+ summary: 'Which Notifai service this machine talks to',
214
+ detail: 'Points the CLI at a Notifai service. The default is the hosted service, and signing in stores the URL the credential belongs to, so this rarely needs setting by hand.\n\nChanging it does not move your credential: a URL that does not match the one you paired against will not authenticate.',
215
+ advanced: true,
216
+ example: 'https://notifai.fly.dev',
217
+ },
218
+ };
219
+ export function configInfo(key) {
220
+ return { key, ...INFO[key] };
221
+ }
222
+ /** Every key in its group, in the order a reader should meet them. */
223
+ export function configKeysByGroup(group) {
224
+ return Object.keys(INFO)
225
+ .filter((key) => INFO[key].group === group)
226
+ .map((key) => configInfo(key));
227
+ }
228
+ /** Bounds rendered the way an error message wants them, or null. */
229
+ export function boundsHint(key) {
230
+ const bounds = configBounds(key);
231
+ if (bounds === undefined)
232
+ return null;
233
+ const info = INFO[key];
234
+ const unit = info.unit ?? '';
235
+ return `${bounds.min}${unit}–${bounds.max}${unit}`;
236
+ }
237
+ /** What a `config set` caller may legally pass, phrased for an error message. */
238
+ export function acceptedValues(key) {
239
+ const info = INFO[key];
240
+ switch (info.kind) {
241
+ case 'boolean':
242
+ return 'true or false';
243
+ case 'enum':
244
+ return (info.choices ?? []).join(', ');
245
+ case 'integer': {
246
+ const bounds = boundsHint(key);
247
+ return bounds === null ? 'a whole number' : `a whole number from ${bounds}`;
248
+ }
249
+ case 'list':
250
+ return 'a comma-separated list';
251
+ case 'url':
252
+ return 'a URL';
253
+ case 'string':
254
+ return 'any text';
255
+ }
256
+ }
257
+ /** How a resolved value should read in a list. */
258
+ export function formatValue(key, value) {
259
+ const info = INFO[key];
260
+ if (value === null || value === undefined)
261
+ return info.unsetMeans ?? 'not set';
262
+ if (Array.isArray(value))
263
+ return value.length === 0 ? (info.unsetMeans ?? 'not set') : value.join(', ');
264
+ if (typeof value === 'boolean')
265
+ return value ? 'yes' : 'no';
266
+ if (typeof value === 'number' && info.unit !== undefined)
267
+ return formatDuration(value, info.unit);
268
+ return String(value);
269
+ }
270
+ /**
271
+ * Where a value came from, in words rather than in a tagged path.
272
+ *
273
+ * `global:/Users/you/.config/notifai/config.toml` answers "which file" but not
274
+ * "why is this the value" — and the second question is the one someone reading
275
+ * `config show` is actually asking. The path is still available for anyone
276
+ * about to edit the file; it is just no longer the whole answer.
277
+ */
278
+ export function describeSource(source) {
279
+ if (source === 'default')
280
+ return { label: 'default', path: null };
281
+ if (source === 'flag')
282
+ return { label: 'this command', path: null };
283
+ const separator = source.indexOf(':');
284
+ if (separator === -1)
285
+ return { label: source, path: null };
286
+ const layer = source.slice(0, separator);
287
+ const filePath = source.slice(separator + 1);
288
+ const labels = {
289
+ session: 'this session',
290
+ 'project-local': 'this project (personal)',
291
+ project: 'this project (shared)',
292
+ global: 'this machine',
293
+ };
294
+ return { label: labels[layer] ?? layer, path: filePath === '' ? null : filePath };
295
+ }
296
+ /** Seconds as something a person reads: `300s` is true, `5m` is legible. */
297
+ export function formatDuration(value, unit) {
298
+ if (unit !== 's')
299
+ return `${value}${unit}`;
300
+ if (value === 0)
301
+ return '0s (immediately)';
302
+ if (value < 60)
303
+ return `${value}s`;
304
+ if (value % 86400 === 0)
305
+ return `${value / 86400}d`;
306
+ if (value % 3600 === 0)
307
+ return `${value / 3600}h`;
308
+ if (value % 60 === 0)
309
+ return `${value / 60}m`;
310
+ return `${Math.floor(value / 60)}m ${value % 60}s`;
311
+ }
312
+ //# sourceMappingURL=config-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-schema.js","sourceRoot":"","sources":["../src/config-schema.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -23,6 +23,13 @@ export interface ResolvedValue<T> {
23
23
  }
24
24
  type CliSound = (typeof CLI_SOUNDS)[number];
25
25
  type CliInterruptionLevel = (typeof INTERRUPTION_LEVELS)[number];
26
+ /**
27
+ * How much the local log records. Defined here rather than in `logging.ts`
28
+ * because it is a configuration vocabulary first — `logging.ts` reads config,
29
+ * so the dependency has to point this way.
30
+ */
31
+ export declare const LOG_LEVELS: readonly ["off", "error", "info", "debug"];
32
+ export type LogLevel = (typeof LOG_LEVELS)[number];
26
33
  export interface CliConfig {
27
34
  base_url: ResolvedValue<string>;
28
35
  wait_seconds: ResolvedValue<number>;
@@ -65,8 +72,8 @@ export interface CliConfig {
65
72
  away_after_seconds: ResolvedValue<number>;
66
73
  /**
67
74
  * How long a hook blocks waiting for a companion-device answer before falling through
68
- * to the harness's own prompt. Must stay under the harness hook timeout
69
- * (600s in both Claude Code and Codex) or the harness kills us mid-wait.
75
+ * to the harness's own prompt. Runtime arbitration keeps the complete Stop
76
+ * invocation inside its fixed 480s owner budget and 540s adapter ceiling.
70
77
  */
71
78
  hook_reply_timeout_seconds: ResolvedValue<number>;
72
79
  /**
@@ -80,13 +87,41 @@ export interface CliConfig {
80
87
  * questions, and answering one should not answer the other.
81
88
  */
82
89
  ask_grace_seconds: ResolvedValue<number>;
90
+ /**
91
+ * How much of what this CLI does is recorded to the local log.
92
+ *
93
+ * The log exists for agents: a hook runs headless and its most consequential
94
+ * act is usually a decision to do nothing, which leaves no other trace. `off`
95
+ * disables the sink entirely; `debug` adds config resolution and request
96
+ * detail, which is verbose enough to want a reason.
97
+ */
98
+ log_level: ResolvedValue<LogLevel>;
99
+ /**
100
+ * Bytes the active log file may reach before it is rotated. With
101
+ * `log_max_files` this is the whole disk budget — nothing here grows without
102
+ * a ceiling, because a log that fills a disk is a bug that outlives its
103
+ * usefulness.
104
+ */
105
+ log_max_bytes: ResolvedValue<number>;
106
+ /** Log files kept in total, the active one included. */
107
+ log_max_files: ResolvedValue<number>;
83
108
  }
84
- export declare const CONFIG_KEYS: readonly ["base_url", "wait_seconds", "ttl_seconds", "collapse_key", "devices", "sound", "interruption_level", "project", "notify_criteria", "ask_notifications", "require_idle", "away_after_seconds", "hook_reply_timeout_seconds", "ask_grace_seconds"];
109
+ export declare const CONFIG_KEYS: readonly ["base_url", "wait_seconds", "ttl_seconds", "collapse_key", "devices", "sound", "interruption_level", "project", "notify_criteria", "ask_notifications", "require_idle", "away_after_seconds", "hook_reply_timeout_seconds", "ask_grace_seconds", "log_level", "log_max_bytes", "log_max_files"];
85
110
  export type ConfigKey = (typeof CONFIG_KEYS)[number];
86
111
  /** Keys whose TOML value must parse as a boolean; used by `config set`. */
87
112
  export declare const BOOLEAN_CONFIG_KEYS: readonly ConfigKey[];
88
113
  /** Keys whose TOML value must parse as an integer within its configured bounds. */
89
114
  export declare const NUMERIC_CONFIG_KEYS: readonly ConfigKey[];
115
+ /**
116
+ * Keys whose value must be one of a fixed set.
117
+ *
118
+ * Config is readable from a repository, so an unrecognised value is untrusted
119
+ * input rather than a typo — `coerce` drops it and the layer below wins, which
120
+ * is the same discipline the numeric bounds follow.
121
+ */
122
+ export declare const ENUM_CONFIG_VALUES: Partial<Record<ConfigKey, readonly string[]>>;
123
+ /** The shipped value beneath every user-controlled configuration layer. */
124
+ export declare function configDefaultValue(key: ConfigKey): unknown;
90
125
  export declare function globalConfigDir(env?: NodeJS.ProcessEnv): string;
91
126
  export declare function globalConfigPath(env?: NodeJS.ProcessEnv): string;
92
127
  /**
package/dist/config.js CHANGED
@@ -3,6 +3,13 @@ import { existsSync, readFileSync, realpathSync } from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { parse as parseToml } from 'smol-toml';
6
+ import { HOOK_TIMING } from './harnesses.js';
7
+ /**
8
+ * How much the local log records. Defined here rather than in `logging.ts`
9
+ * because it is a configuration vocabulary first — `logging.ts` reads config,
10
+ * so the dependency has to point this way.
11
+ */
12
+ export const LOG_LEVELS = ['off', 'error', 'info', 'debug'];
6
13
  export const CONFIG_KEYS = [
7
14
  'base_url',
8
15
  'wait_seconds',
@@ -18,6 +25,9 @@ export const CONFIG_KEYS = [
18
25
  'away_after_seconds',
19
26
  'hook_reply_timeout_seconds',
20
27
  'ask_grace_seconds',
28
+ 'log_level',
29
+ 'log_max_bytes',
30
+ 'log_max_files',
21
31
  ];
22
32
  /** Keys whose TOML value must parse as a boolean; used by `config set`. */
23
33
  export const BOOLEAN_CONFIG_KEYS = [
@@ -31,7 +41,19 @@ export const NUMERIC_CONFIG_KEYS = [
31
41
  'away_after_seconds',
32
42
  'hook_reply_timeout_seconds',
33
43
  'ask_grace_seconds',
44
+ 'log_max_bytes',
45
+ 'log_max_files',
34
46
  ];
47
+ /**
48
+ * Keys whose value must be one of a fixed set.
49
+ *
50
+ * Config is readable from a repository, so an unrecognised value is untrusted
51
+ * input rather than a typo — `coerce` drops it and the layer below wins, which
52
+ * is the same discipline the numeric bounds follow.
53
+ */
54
+ export const ENUM_CONFIG_VALUES = {
55
+ log_level: LOG_LEVELS,
56
+ };
35
57
  const DEFAULTS = {
36
58
  base_url: 'https://notifai.fly.dev',
37
59
  wait_seconds: 10,
@@ -45,16 +67,27 @@ const DEFAULTS = {
45
67
  // Installing the hooks is the opt-in; these exist to switch the behaviour
46
68
  // back off for a project or a session without uninstalling anything.
47
69
  ask_notifications: true,
48
- // On by default because it is the less surprising of the two: a question
49
- // appearing on your phone while you are typing the answer into the terminal
50
- // is worse as a default than one that waits for you to leave.
51
- require_idle: true,
70
+ // Questions reach devices immediately by default. Both a terminal-first
71
+ // grace and presence gating remain independent opt-in controls.
72
+ require_idle: false,
52
73
  away_after_seconds: 120,
53
- // 300 + 180 + the installer's 60s headroom = 540, inside the 600s
54
- // command-hook ceiling both harnesses enforce.
55
- hook_reply_timeout_seconds: 180,
56
- ask_grace_seconds: 300,
74
+ // Runtime waits stay inside a 480s budget. Harnesses that require a declared
75
+ // Stop limit use a preference-stable 540s; Codex uses its host-owned Stop
76
+ // default. Neither definition changes when these preferences do.
77
+ hook_reply_timeout_seconds: 480,
78
+ ask_grace_seconds: 0,
79
+ // On by default: the log is the only account of what a headless hook did, and
80
+ // a diagnostic nobody switched on before the thing went wrong is not one.
81
+ log_level: 'info',
82
+ // 2 MB × 3 files caps the logs at roughly 6 MB, which is weeks of ordinary
83
+ // agent traffic and small enough that nobody has to think about it.
84
+ log_max_bytes: 2_000_000,
85
+ log_max_files: 3,
57
86
  };
87
+ /** The shipped value beneath every user-controlled configuration layer. */
88
+ export function configDefaultValue(key) {
89
+ return DEFAULTS[key];
90
+ }
58
91
  export function globalConfigDir(env = process.env) {
59
92
  const xdg = env['XDG_CONFIG_HOME'];
60
93
  const base = xdg && xdg !== '' ? xdg : path.join(os.homedir(), '.config');
@@ -138,17 +171,24 @@ export function findProjectLocalConfigPath(startDir) {
138
171
  * Ranges every layer is clamped to. Config is readable from a repository, so an
139
172
  * out-of-range value is attacker input, not a typo: `away_after_seconds = -1`
140
173
  * would make a user who just typed count as absent, and an oversized reply
141
- * timeout would push the generated hook past the harness's 600s ceiling so the
142
- * hook is killed after the user has already answered.
174
+ * timeout would exhaust the hook process budget and kill it after the user has
175
+ * already answered.
143
176
  */
144
177
  const NUMERIC_BOUNDS = {
145
178
  wait_seconds: { min: 0, max: 300 },
146
179
  ttl_seconds: { min: 0, max: 7 * 24 * 3600 },
147
180
  away_after_seconds: { min: 5, max: 24 * 3600 },
148
- // 540 + the installer's 60s headroom stays inside the 600s command-hook
149
- // budget shared by Claude Code and Codex.
150
- hook_reply_timeout_seconds: { min: 10, max: 540 },
151
- ask_grace_seconds: { min: 0, max: 540 },
181
+ // The runtime clamps grace + reply work below the host process ceiling; this
182
+ // maximum is never copied into the installed definition.
183
+ // The wire protocol's minimum reply window is 60s; matching it prevents the
184
+ // server from accepting an answer after a shorter local wait has returned.
185
+ hook_reply_timeout_seconds: { min: 60, max: 540 },
186
+ ask_grace_seconds: { min: 0, max: HOOK_TIMING.maxGraceSeconds },
187
+ // The floor keeps rotation from thrashing (a file smaller than a handful of
188
+ // records would rotate on nearly every write); the ceiling is the point past
189
+ // which "local diagnostics" has become "a database on your disk".
190
+ log_max_bytes: { min: 64_000, max: 100_000_000 },
191
+ log_max_files: { min: 1, max: 20 },
152
192
  };
153
193
  /** Drops values a layer must not be trusted to supply, rather than throwing. */
154
194
  function coerce(key, value) {
@@ -160,6 +200,10 @@ function coerce(key, value) {
160
200
  }
161
201
  if (BOOLEAN_CONFIG_KEYS.includes(key))
162
202
  return typeof value === 'boolean' ? value : undefined;
203
+ const allowed = ENUM_CONFIG_VALUES[key];
204
+ if (allowed !== undefined) {
205
+ return typeof value === 'string' && allowed.includes(value) ? value : undefined;
206
+ }
163
207
  return value;
164
208
  }
165
209
  export function configBounds(key) {
@@ -219,6 +263,9 @@ export function loadConfig(options) {
219
263
  away_after_seconds: resolve('away_after_seconds'),
220
264
  hook_reply_timeout_seconds: resolve('hook_reply_timeout_seconds'),
221
265
  ask_grace_seconds: resolve('ask_grace_seconds'),
266
+ log_level: resolve('log_level'),
267
+ log_max_bytes: resolve('log_max_bytes'),
268
+ log_max_files: resolve('log_max_files'),
222
269
  };
223
270
  }
224
271
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}