@raidiant/notifai 0.5.0 → 1.0.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/CHANGELOG.md +165 -0
- package/README.md +11 -4
- package/dist/claude-wake.d.ts +101 -0
- package/dist/claude-wake.js +397 -0
- package/dist/claude-wake.js.map +1 -0
- package/dist/codex-wake.d.ts +84 -0
- package/dist/codex-wake.js +238 -0
- package/dist/codex-wake.js.map +1 -0
- package/dist/commands.d.ts +31 -11
- package/dist/commands.js +679 -232
- package/dist/commands.js.map +1 -1
- package/dist/config-schema.d.ts +3 -3
- package/dist/config-schema.js +11 -49
- package/dist/config-schema.js.map +1 -1
- package/dist/config.d.ts +23 -45
- package/dist/config.js +61 -39
- package/dist/config.js.map +1 -1
- package/dist/harnesses.d.ts +4 -13
- package/dist/harnesses.js +12 -17
- package/dist/harnesses.js.map +1 -1
- package/dist/hook-adapter.d.ts +10 -1
- package/dist/hook-adapter.js +79 -10
- package/dist/hook-adapter.js.map +1 -1
- package/dist/hooks.d.ts +119 -65
- package/dist/hooks.js +330 -285
- package/dist/hooks.js.map +1 -1
- package/dist/install-hooks.d.ts +76 -24
- package/dist/install-hooks.js +301 -125
- package/dist/install-hooks.js.map +1 -1
- package/dist/interactive.d.ts +32 -1
- package/dist/interactive.js +165 -51
- package/dist/interactive.js.map +1 -1
- package/dist/main.js +14 -21
- package/dist/main.js.map +1 -1
- package/dist/native-skills.d.ts +1 -1
- package/dist/native-skills.js +23 -58
- package/dist/native-skills.js.map +1 -1
- package/dist/pack-feedback-slice.d.ts +35 -0
- package/dist/pack-feedback-slice.js +126 -0
- package/dist/pack-feedback-slice.js.map +1 -0
- package/dist/readiness.d.ts +20 -0
- package/dist/readiness.js +24 -0
- package/dist/readiness.js.map +1 -1
- package/dist/release.d.ts +31 -0
- package/dist/release.js +52 -0
- package/dist/release.js.map +1 -0
- package/dist/ui/theme.d.ts +1 -1
- package/package.json +11 -10
- package/src/commands.test.ts +386 -36
- package/src/commands.ts +473 -182
- package/src/config-schema.ts +2 -17
- package/src/config.test.ts +29 -4
- package/src/config.ts +67 -11
- package/src/harnesses.ts +7 -0
- package/src/hook-adapter.test.ts +43 -1
- package/src/hook-adapter.ts +83 -11
- package/src/hooks.test.ts +4 -5
- package/src/install-hooks.test.ts +154 -2
- package/src/install-hooks.ts +231 -44
- package/src/interactive.test.ts +338 -0
- package/src/interactive.ts +221 -49
- package/src/main.ts +14 -20
- package/src/native-skills.test.ts +75 -0
- package/src/native-skills.ts +31 -75
- package/src/pack-feedback-slice.test.ts +212 -0
- package/src/pack-feedback-slice.ts +187 -0
- package/src/readiness.test.ts +25 -0
- package/src/readiness.ts +38 -0
- package/src/release.ts +51 -0
- package/src/skill.test.ts +43 -0
- package/src/ui/config-view.test.ts +5 -4
- package/dist/idle.d.ts +0 -16
- package/dist/idle.js +0 -44
- package/dist/idle.js.map +0 -1
package/src/skill.test.ts
CHANGED
|
@@ -20,6 +20,33 @@ describe('Notifai agent skill', () => {
|
|
|
20
20
|
expect(skill).toContain('| question (`--reply`) | `attention` | `active` |')
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
+
it('makes the agent the setup wizard', () => {
|
|
24
|
+
expect(skill.indexOf('## Set Notifai up')).toBeGreaterThan(skill.indexOf('## When to notify'))
|
|
25
|
+
expect(skill.indexOf('## Set Notifai up')).toBeLessThan(skill.indexOf('## Compose and send'))
|
|
26
|
+
expect(skill).toContain('Never tell the user to run')
|
|
27
|
+
expect(skill).toContain('notifai init')
|
|
28
|
+
expect(skill).toContain('notifai hooks install')
|
|
29
|
+
expect(skill).toContain('notifai doctor')
|
|
30
|
+
expect(skill).toContain('notifai login')
|
|
31
|
+
expect(skill).toContain('Ask the user only for decisions a process cannot make')
|
|
32
|
+
expect(skill).not.toContain('relay the exact action')
|
|
33
|
+
expect(harnessReference).toContain('install hooks yourself')
|
|
34
|
+
expect(harnessReference).toContain('run `notifai login` yourself')
|
|
35
|
+
expect(harnessReference).not.toContain('the user must run `notifai login`')
|
|
36
|
+
expect(harnessReference).not.toContain('do not install them without being asked')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('treats --sound and --level as overrides, not completeness', () => {
|
|
40
|
+
expect(skill).toMatch(/Never pass `--sound` or `--level` unless/)
|
|
41
|
+
const examples = [...skill.matchAll(/```(?:bash)?\n([\s\S]*?)```/g)].map((match) => match[1])
|
|
42
|
+
const sendExamples = examples.filter((example) => example.includes('notifai send'))
|
|
43
|
+
expect(sendExamples.length).toBeGreaterThan(0)
|
|
44
|
+
for (const example of sendExamples) {
|
|
45
|
+
expect(example).not.toMatch(/(^|\s)--sound\b/)
|
|
46
|
+
expect(example).not.toMatch(/(^|\s)--level\b/)
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
|
|
23
50
|
it('documents reply lifecycle, routing, session minting, and doctor exits', () => {
|
|
24
51
|
for (const required of [
|
|
25
52
|
'--reply-choice',
|
|
@@ -57,6 +84,22 @@ describe('Notifai agent skill', () => {
|
|
|
57
84
|
expect(askGuidance).toMatch(/without asking the user to\s+confirm again/)
|
|
58
85
|
})
|
|
59
86
|
|
|
87
|
+
it('teaches agents to report config JSON fields instead of paraphrasing defaults', () => {
|
|
88
|
+
expect(skill).toContain('notifai config show --json')
|
|
89
|
+
expect(skill).toContain('{ value, source, summary }')
|
|
90
|
+
expect(skill).toContain('Do not paraphrase')
|
|
91
|
+
expect(skill).not.toContain('config.local.toml')
|
|
92
|
+
expect(skill).toContain('outside the repository')
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('mentions npx only as a pinned alternative to a real install', () => {
|
|
96
|
+
expect(skill).toContain('npm install -g @raidiant/notifai')
|
|
97
|
+
expect(skill.indexOf('npm install -g @raidiant/notifai')).toBeLessThan(
|
|
98
|
+
skill.indexOf('npx --yes @raidiant/notifai@'),
|
|
99
|
+
)
|
|
100
|
+
expect(skill).toContain('do not present npx as the default')
|
|
101
|
+
})
|
|
102
|
+
|
|
60
103
|
it('tells the agent where to look when something did not happen', () => {
|
|
61
104
|
// The log's whole value is diagnostic, so the skill has to name the case
|
|
62
105
|
// that produces it — a question that was registered and never travelled.
|
|
@@ -18,14 +18,14 @@ describe('renderConfigPlain', () => {
|
|
|
18
18
|
// an audience that cannot see the styling.
|
|
19
19
|
const lines = renderConfigPlain(config, false)
|
|
20
20
|
expect(lines).toHaveLength(CONFIG_KEYS.length)
|
|
21
|
-
expect(lines[0]).toBe(`
|
|
21
|
+
expect(lines[0]).toBe(`wait_seconds = ${JSON.stringify(config.wait_seconds.value)}`)
|
|
22
22
|
for (const line of lines) expect(line).toMatch(/^[a-z_]+ = /)
|
|
23
23
|
})
|
|
24
24
|
|
|
25
25
|
it('appends the raw source tag under --explain', () => {
|
|
26
26
|
const lines = renderConfigPlain(config, true)
|
|
27
27
|
expect(lines[0]).toBe(
|
|
28
|
-
`
|
|
28
|
+
`wait_seconds = ${JSON.stringify(config.wait_seconds.value)} [${config.wait_seconds.source}]`,
|
|
29
29
|
)
|
|
30
30
|
})
|
|
31
31
|
|
|
@@ -50,8 +50,9 @@ describe('renderConfigList', () => {
|
|
|
50
50
|
})
|
|
51
51
|
|
|
52
52
|
it('reveals advanced keys only when asked', () => {
|
|
53
|
-
expect(renderConfigList(config).join('\n')).not.toContain('
|
|
54
|
-
expect(renderConfigList(config, { showAdvanced: true }).join('\n')).toContain('
|
|
53
|
+
expect(renderConfigList(config).join('\n')).not.toContain('collapse_key')
|
|
54
|
+
expect(renderConfigList(config, { showAdvanced: true }).join('\n')).toContain('collapse_key')
|
|
55
|
+
expect(renderConfigList(config, { showAdvanced: true }).join('\n')).not.toContain('base_url')
|
|
55
56
|
})
|
|
56
57
|
|
|
57
58
|
it('fits the terminal, so no row wraps into the next', () => {
|
package/dist/idle.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Seconds since the user last touched the keyboard or mouse, or null when this
|
|
3
|
-
* machine cannot say.
|
|
4
|
-
*
|
|
5
|
-
* The hooks need to know whether the user is at their desk, and the only signal
|
|
6
|
-
* they had was silence since the last prompt — which includes the agent's own
|
|
7
|
-
* turn, so a user watching a long build was indistinguishable from a user who
|
|
8
|
-
* had left. This is the corroborating signal.
|
|
9
|
-
*
|
|
10
|
-
* null is a first-class answer, not a failure: on a machine with no idle source
|
|
11
|
-
* the caller keeps its previous behaviour rather than guessing. That is why
|
|
12
|
-
* every error path here returns null instead of throwing.
|
|
13
|
-
*/
|
|
14
|
-
export declare function readIdleSeconds(platform?: NodeJS.Platform): number | null;
|
|
15
|
-
/** Exported for tests: HIDIdleTime is nanoseconds since the last HID event. */
|
|
16
|
-
export declare function parseIdleSeconds(ioregOutput: string): number | null;
|
package/dist/idle.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from 'node:child_process';
|
|
2
|
-
/**
|
|
3
|
-
* Seconds since the user last touched the keyboard or mouse, or null when this
|
|
4
|
-
* machine cannot say.
|
|
5
|
-
*
|
|
6
|
-
* The hooks need to know whether the user is at their desk, and the only signal
|
|
7
|
-
* they had was silence since the last prompt — which includes the agent's own
|
|
8
|
-
* turn, so a user watching a long build was indistinguishable from a user who
|
|
9
|
-
* had left. This is the corroborating signal.
|
|
10
|
-
*
|
|
11
|
-
* null is a first-class answer, not a failure: on a machine with no idle source
|
|
12
|
-
* the caller keeps its previous behaviour rather than guessing. That is why
|
|
13
|
-
* every error path here returns null instead of throwing.
|
|
14
|
-
*/
|
|
15
|
-
export function readIdleSeconds(platform = process.platform) {
|
|
16
|
-
if (platform !== 'darwin')
|
|
17
|
-
return null;
|
|
18
|
-
try {
|
|
19
|
-
// -r -k narrows the dump to the one node carrying the key (~5KB), so this
|
|
20
|
-
// stays a ~20ms call on the hot path of every Stop hook.
|
|
21
|
-
const out = execFileSync('ioreg', ['-c', 'IOHIDSystem', '-r', '-k', 'HIDIdleTime'], {
|
|
22
|
-
encoding: 'utf8',
|
|
23
|
-
timeout: 2000,
|
|
24
|
-
maxBuffer: 1_000_000,
|
|
25
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
26
|
-
});
|
|
27
|
-
return parseIdleSeconds(out);
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
// Missing binary, sandbox denial, timeout — all mean "no signal".
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
/** Exported for tests: HIDIdleTime is nanoseconds since the last HID event. */
|
|
35
|
-
export function parseIdleSeconds(ioregOutput) {
|
|
36
|
-
const match = /"HIDIdleTime"\s*=\s*(\d+)/.exec(ioregOutput);
|
|
37
|
-
if (match?.[1] === undefined)
|
|
38
|
-
return null;
|
|
39
|
-
const nanos = Number(match[1]);
|
|
40
|
-
if (!Number.isFinite(nanos) || nanos < 0)
|
|
41
|
-
return null;
|
|
42
|
-
return nanos / 1e9;
|
|
43
|
-
}
|
|
44
|
-
//# sourceMappingURL=idle.js.map
|
package/dist/idle.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"idle.js","sourceRoot":"","sources":["../src/idle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,WAA4B,OAAO,CAAC,QAAQ;IAC1E,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IACtC,IAAI,CAAC;QACH,0EAA0E;QAC1E,yDAAyD;QACzD,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,CAAC,EAAE;YAClF,QAAQ,EAAE,MAAM;YAChB,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,SAAS;YACpB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAA;QACF,OAAO,gBAAgB,CAAC,GAAG,CAAC,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,kEAAkE;QAClE,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,gBAAgB,CAAC,WAAmB;IAClD,MAAM,KAAK,GAAG,2BAA2B,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IAC3D,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS;QAAE,OAAO,IAAI,CAAA;IACzC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IACrD,OAAO,KAAK,GAAG,GAAG,CAAA;AACpB,CAAC"}
|