@raidiant/notifai 10.1.1 → 10.1.3
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 +35 -0
- package/dist/commands-core.d.ts +4 -1
- package/dist/commands-core.js.map +1 -1
- package/dist/commands-doctor.js +2 -7
- package/dist/commands-doctor.js.map +1 -1
- package/dist/commands-hooks.d.ts +12 -0
- package/dist/commands-hooks.js +15 -1
- package/dist/commands-hooks.js.map +1 -1
- package/dist/commands-init.js +9 -6
- package/dist/commands-init.js.map +1 -1
- package/dist/commands-send-support.js +10 -11
- package/dist/commands-send-support.js.map +1 -1
- package/dist/commands-skill.js +72 -54
- package/dist/commands-skill.js.map +1 -1
- package/dist/harness-session-title.d.ts +22 -0
- package/dist/harness-session-title.js +74 -0
- package/dist/harness-session-title.js.map +1 -0
- package/dist/invocation-context.d.ts +1 -0
- package/dist/invocation-context.js +15 -1
- package/dist/invocation-context.js.map +1 -1
- package/dist/native-skills.d.ts +13 -3
- package/dist/native-skills.js +51 -12
- package/dist/native-skills.js.map +1 -1
- package/dist/node-floor.d.ts +2 -1
- package/dist/node-floor.js +9 -5
- package/dist/node-floor.js.map +1 -1
- package/dist/orca-session-title.d.ts +5 -4
- package/dist/orca-session-title.js +32 -19
- package/dist/orca-session-title.js.map +1 -1
- package/dist/platform.d.ts +11 -17
- package/dist/platform.js +20 -23
- package/dist/platform.js.map +1 -1
- package/dist/release.d.ts +5 -5
- package/dist/release.js +5 -5
- package/dist/session-labels.d.ts +2 -0
- package/dist/session-labels.js +20 -9
- package/dist/session-labels.js.map +1 -1
- package/dist/setup-destinations.js +1 -1
- package/dist/setup-destinations.js.map +1 -1
- package/dist/skill-integrity.d.ts +49 -0
- package/dist/skill-integrity.js +154 -0
- package/dist/skill-integrity.js.map +1 -0
- package/dist/skill-source/manifest.json +16 -0
- package/dist/skill-source/notifai/SKILL.md +390 -0
- package/dist/skill-source/notifai/references/harness-setup.md +220 -0
- package/package.json +11 -14
- package/src/atomic-file.ts +0 -198
- package/src/claude-wake.test.ts +0 -321
- package/src/claude-wake.ts +0 -499
- package/src/cli-bin.test.ts +0 -176
- package/src/cli-bin.ts +0 -233
- package/src/cli-release.test.ts +0 -46
- package/src/cli-release.ts +0 -78
- package/src/cli-update-contract.ts +0 -9
- package/src/cli-update.test.ts +0 -125
- package/src/client.test.ts +0 -390
- package/src/client.ts +0 -352
- package/src/codex-wake.test.ts +0 -254
- package/src/codex-wake.ts +0 -301
- package/src/command-session.ts +0 -38
- package/src/commands-agent-sessions.ts +0 -72
- package/src/commands-auth.ts +0 -238
- package/src/commands-config.ts +0 -336
- package/src/commands-core.ts +0 -312
- package/src/commands-devices.ts +0 -180
- package/src/commands-doctor.ts +0 -1501
- package/src/commands-guidance.ts +0 -181
- package/src/commands-harness-context.ts +0 -207
- package/src/commands-hook-shape.ts +0 -69
- package/src/commands-hooks.ts +0 -2318
- package/src/commands-init.ts +0 -1055
- package/src/commands-io.ts +0 -108
- package/src/commands-logs.ts +0 -243
- package/src/commands-project.ts +0 -47
- package/src/commands-send-support.test.ts +0 -156
- package/src/commands-send-support.ts +0 -311
- package/src/commands-send.ts +0 -875
- package/src/commands-setup-proof.test.ts +0 -72
- package/src/commands-setup-proof.ts +0 -124
- package/src/commands-skill.test.ts +0 -44
- package/src/commands-skill.ts +0 -204
- package/src/commands-sounds.test.ts +0 -106
- package/src/commands-sounds.ts +0 -49
- package/src/commands-update.ts +0 -180
- package/src/commands.test.ts +0 -8297
- package/src/commands.ts +0 -77
- package/src/config-schema.test.ts +0 -153
- package/src/config-schema.ts +0 -349
- package/src/config.test.ts +0 -581
- package/src/config.ts +0 -475
- package/src/credentials.test.ts +0 -403
- package/src/credentials.ts +0 -403
- package/src/file-lock-process-worker.test.ts +0 -64
- package/src/file-lock.test.ts +0 -320
- package/src/file-lock.ts +0 -393
- package/src/fixtures/hermes-0.20.6-classic-cli-local.json +0 -50
- package/src/fixtures/openclaw-2026.7.1-2-agent-local.json +0 -57
- package/src/generated-session-label.ts +0 -155
- package/src/guidance-content.ts +0 -278
- package/src/guidance-render.ts +0 -56
- package/src/guidance.test.ts +0 -327
- package/src/guidance.ts +0 -233
- package/src/harness-integration.test.ts +0 -294
- package/src/harnesses.test.ts +0 -149
- package/src/harnesses.ts +0 -164
- package/src/hook-adapter.test.ts +0 -496
- package/src/hook-adapter.ts +0 -424
- package/src/hook-input.test.ts +0 -39
- package/src/hook-input.ts +0 -72
- package/src/hooks.test.ts +0 -5824
- package/src/hooks.ts +0 -4011
- package/src/install-hooks.test.ts +0 -1614
- package/src/install-hooks.ts +0 -1501
- package/src/interactive.test.ts +0 -387
- package/src/interactive.ts +0 -858
- package/src/invocation-context.test.ts +0 -352
- package/src/invocation-context.ts +0 -197
- package/src/logging-process-worker.test.ts +0 -45
- package/src/logging.test.ts +0 -544
- package/src/logging.ts +0 -698
- package/src/main-run.ts +0 -45
- package/src/main.ts +0 -12
- package/src/native-skills.test.ts +0 -115
- package/src/native-skills.ts +0 -162
- package/src/node-floor.test.ts +0 -27
- package/src/node-floor.ts +0 -37
- package/src/onboarding-docs.test.ts +0 -25
- package/src/openclaw-plugin.ts +0 -409
- package/src/opencode-plugin.ts +0 -298
- package/src/orca-session-title.test.ts +0 -54
- package/src/orca-session-title.ts +0 -103
- package/src/pack-feedback-slice.test.ts +0 -212
- package/src/pack-feedback-slice.ts +0 -187
- package/src/platform.test.ts +0 -152
- package/src/platform.ts +0 -173
- package/src/program.test.ts +0 -317
- package/src/program.ts +0 -842
- package/src/project-enablement.test.ts +0 -55
- package/src/project-enablement.ts +0 -99
- package/src/question-caps.test.ts +0 -49
- package/src/question-settlement-process.ts +0 -47
- package/src/question-timing.ts +0 -56
- package/src/readiness.test.ts +0 -25
- package/src/readiness.ts +0 -212
- package/src/release.ts +0 -51
- package/src/send-attempts.test.ts +0 -143
- package/src/send-attempts.ts +0 -188
- package/src/send.test.ts +0 -28
- package/src/send.ts +0 -436
- package/src/session-activation.ts +0 -61
- package/src/session-end-log-lock-worker.test.ts +0 -35
- package/src/session-labels.test.ts +0 -490
- package/src/session-labels.ts +0 -474
- package/src/setup-destinations.test.ts +0 -41
- package/src/setup-destinations.ts +0 -50
- package/src/skill.test.ts +0 -426
- package/src/sound-ref.test.ts +0 -31
- package/src/sound-ref.ts +0 -34
- package/src/trust-policy.test.ts +0 -701
- package/src/ui/banner.ts +0 -95
- package/src/ui/config-view.test.ts +0 -90
- package/src/ui/config-view.ts +0 -138
- package/src/ui/help.test.ts +0 -16
- package/src/ui/help.ts +0 -128
- package/src/ui/theme.test.ts +0 -92
- package/src/ui/theme.ts +0 -265
- package/src/url-policy.ts +0 -399
- package/tsconfig.json +0 -10
package/src/program.test.ts
DELETED
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
import { mkdtempSync, writeFileSync } from 'node:fs'
|
|
2
|
-
import os from 'node:os'
|
|
3
|
-
import path from 'node:path'
|
|
4
|
-
import { describe, expect, it } from 'vitest'
|
|
5
|
-
import { buildProgram, type ProgramRunners } from './program.js'
|
|
6
|
-
import type { CommandDeps } from './commands.js'
|
|
7
|
-
import { QUESTION_SETTLEMENT_INPUT_ENV } from './question-settlement-process.js'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* The layer these tests own is the argv boundary: what a real command line
|
|
11
|
-
* turns into by the time a command implementation receives it. Collector
|
|
12
|
-
* defaults, `--no-wait` disentangling, `--body-file` reading — none of that is
|
|
13
|
-
* visible to the unit tests on the commands themselves, and it used to be
|
|
14
|
-
* covered by nothing but reading `program.ts` with human eyes.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
class ExitSentinel extends Error {
|
|
18
|
-
constructor(readonly code: number) {
|
|
19
|
-
super(`exit ${code}`)
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function makeDeps(): CommandDeps & { outLines: string[]; errLines: string[] } {
|
|
24
|
-
const outLines: string[] = []
|
|
25
|
-
const errLines: string[] = []
|
|
26
|
-
return {
|
|
27
|
-
io: {
|
|
28
|
-
out: (line: string) => outLines.push(line),
|
|
29
|
-
err: (line: string) => errLines.push(line),
|
|
30
|
-
confirm: async () => false,
|
|
31
|
-
openUrl: () => {},
|
|
32
|
-
},
|
|
33
|
-
store: {
|
|
34
|
-
load: () => null,
|
|
35
|
-
save: () => {},
|
|
36
|
-
clear: () => {},
|
|
37
|
-
describe: () => 'test credential store',
|
|
38
|
-
},
|
|
39
|
-
env: {},
|
|
40
|
-
cwd: os.tmpdir(),
|
|
41
|
-
outLines,
|
|
42
|
-
errLines,
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Parse a real command line and capture what would have been dispatched.
|
|
48
|
-
* `exit` throws so post-exit code cannot run — the same property
|
|
49
|
-
* `process.exit` gives production.
|
|
50
|
-
*/
|
|
51
|
-
async function parse(
|
|
52
|
-
argv: string[],
|
|
53
|
-
runners: Partial<ProgramRunners>,
|
|
54
|
-
deps = makeDeps(),
|
|
55
|
-
): Promise<{ exitCode: number | undefined; deps: ReturnType<typeof makeDeps> }> {
|
|
56
|
-
let exitCode: number | undefined
|
|
57
|
-
const program = buildProgram(deps, {
|
|
58
|
-
runners,
|
|
59
|
-
exit: (code: number) => {
|
|
60
|
-
exitCode = code
|
|
61
|
-
throw new ExitSentinel(code)
|
|
62
|
-
},
|
|
63
|
-
})
|
|
64
|
-
try {
|
|
65
|
-
await program.parseAsync(['node', 'notifai', ...argv])
|
|
66
|
-
} catch (err) {
|
|
67
|
-
if (!(err instanceof ExitSentinel)) throw err
|
|
68
|
-
}
|
|
69
|
-
return { exitCode, deps }
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
describe('program argv parsing', () => {
|
|
73
|
-
it('maps a full send command line onto sendCommand flags', async () => {
|
|
74
|
-
let seen: Record<string, unknown> | undefined
|
|
75
|
-
const { exitCode } = await parse(
|
|
76
|
-
[
|
|
77
|
-
'send',
|
|
78
|
-
'--kind', 'done',
|
|
79
|
-
'--title', 'Build finished',
|
|
80
|
-
'--body', 'All green.',
|
|
81
|
-
'--choice', 'Ship it',
|
|
82
|
-
'--choice', 'Hold',
|
|
83
|
-
'--multi',
|
|
84
|
-
'--reply',
|
|
85
|
-
'--reply-timeout', '30',
|
|
86
|
-
],
|
|
87
|
-
{ send: (async (_deps, flags) => ((seen = flags as Record<string, unknown>), 0)) as ProgramRunners['send'] },
|
|
88
|
-
)
|
|
89
|
-
expect(exitCode).toBe(0)
|
|
90
|
-
expect(seen).toMatchObject({
|
|
91
|
-
kind: 'done',
|
|
92
|
-
title: 'Build finished',
|
|
93
|
-
body: 'All green.',
|
|
94
|
-
choice: ['Ship it', 'Hold'],
|
|
95
|
-
multi: true,
|
|
96
|
-
reply: true,
|
|
97
|
-
replyTimeout: 30,
|
|
98
|
-
noWait: false,
|
|
99
|
-
})
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
it('preserves deliberate Projectless send intent at the argv boundary', async () => {
|
|
103
|
-
let seen: Record<string, unknown> | undefined
|
|
104
|
-
await parse(
|
|
105
|
-
['send', '--kind', 'done', '--title', 'T', '--body', 'B', '--projectless'],
|
|
106
|
-
{ send: (async (_deps, flags) => ((seen = flags as Record<string, unknown>), 0)) as ProgramRunners['send'] },
|
|
107
|
-
)
|
|
108
|
-
expect(seen).toMatchObject({ projectless: true })
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
it('dispatches User-owned Project enablement commands', async () => {
|
|
112
|
-
let enabled = 0
|
|
113
|
-
const result = await parse(['project', 'enable'], {
|
|
114
|
-
projectEnable: ((_deps) => (enabled += 1, 0)) as ProgramRunners['projectEnable'],
|
|
115
|
-
})
|
|
116
|
-
expect(result.exitCode).toBe(0)
|
|
117
|
-
expect(enabled).toBe(1)
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
it('dispatches the current Agent Session rename without exposing an id override', async () => {
|
|
121
|
-
let label: string | undefined
|
|
122
|
-
const result = await parse(['session', 'rename', 'Hermes Support'], {
|
|
123
|
-
agentSessionRename: (async (_deps, value) => ((label = value), 0)) as ProgramRunners['agentSessionRename'],
|
|
124
|
-
})
|
|
125
|
-
expect(result.exitCode).toBe(0)
|
|
126
|
-
expect(label).toBe('Hermes Support')
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
it('hands the detached settlement input to the internal hook owner', async () => {
|
|
130
|
-
const deps = makeDeps()
|
|
131
|
-
const input = JSON.stringify({ session_id: 'session-1', cwd: '/tmp/project' })
|
|
132
|
-
deps.env[QUESTION_SETTLEMENT_INPUT_ENV] = input
|
|
133
|
-
let seen:
|
|
134
|
-
| { event: string; input: string; harness: string | undefined }
|
|
135
|
-
| undefined
|
|
136
|
-
|
|
137
|
-
const result = await parse(
|
|
138
|
-
['hook', 'question-settlement', '--owner', 'notifai', '--harness', 'codex'],
|
|
139
|
-
{
|
|
140
|
-
hookRun: (async (_deps, event, readInput, harness) => {
|
|
141
|
-
seen = { event, input: await readInput(), harness }
|
|
142
|
-
return 0
|
|
143
|
-
}) as ProgramRunners['hookRun'],
|
|
144
|
-
},
|
|
145
|
-
deps,
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
expect(result.exitCode).toBe(0)
|
|
149
|
-
expect(seen).toEqual({ event: 'question-settlement', input, harness: 'codex' })
|
|
150
|
-
expect(deps.env[QUESTION_SETTLEMENT_INPUT_ENV]).toBeUndefined()
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
it('dispatches sounds --json onto soundsCommand', async () => {
|
|
154
|
-
let seen: Record<string, unknown> | undefined
|
|
155
|
-
const result = await parse(['sounds', '--json'], {
|
|
156
|
-
sounds: (async (_deps, flags) => ((seen = flags as Record<string, unknown>), 0)) as ProgramRunners['sounds'],
|
|
157
|
-
})
|
|
158
|
-
expect(result.exitCode).toBe(0)
|
|
159
|
-
expect(seen).toMatchObject({ json: true })
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
it('passes a custom sound name through --sound', async () => {
|
|
163
|
-
let seen: Record<string, unknown> | undefined
|
|
164
|
-
await parse(
|
|
165
|
-
['send', '--kind', 'done', '--title', 'T', '--body', 'B', '--sound', 'Kitchen timer'],
|
|
166
|
-
{ send: (async (_deps, flags) => ((seen = flags as Record<string, unknown>), 0)) as ProgramRunners['send'] },
|
|
167
|
-
)
|
|
168
|
-
expect(seen).toMatchObject({ sound: 'Kitchen timer' })
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
it('drops empty collector defaults so "not passed" stays absent', async () => {
|
|
172
|
-
let seen: Record<string, unknown> | undefined
|
|
173
|
-
await parse(
|
|
174
|
-
['send', '--kind', 'update', '--title', 'T', '--body', 'B'],
|
|
175
|
-
{ send: (async (_deps, flags) => ((seen = flags as Record<string, unknown>), 0)) as ProgramRunners['send'] },
|
|
176
|
-
)
|
|
177
|
-
expect(seen).toBeDefined()
|
|
178
|
-
expect(seen).not.toHaveProperty('choice')
|
|
179
|
-
expect(seen).not.toHaveProperty('image')
|
|
180
|
-
expect(seen).not.toHaveProperty('imageAlt')
|
|
181
|
-
expect(seen).not.toHaveProperty('wait')
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
it('maps init --setup-scope onto the command flags', async () => {
|
|
185
|
-
let seen: Record<string, unknown> | undefined
|
|
186
|
-
const { exitCode } = await parse(
|
|
187
|
-
['init', '--skills', '--setup-scope', 'global', '--no-hooks'],
|
|
188
|
-
{ init: (async (_deps, flags) => ((seen = flags as Record<string, unknown>), 0)) as ProgramRunners['init'] },
|
|
189
|
-
)
|
|
190
|
-
expect(exitCode).toBe(0)
|
|
191
|
-
expect(seen).toMatchObject({ skills: true, setupScope: 'global', hooks: false })
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
it('dispatches update --json onto the local CLI recovery', async () => {
|
|
195
|
-
let seen: Record<string, unknown> | undefined
|
|
196
|
-
const { exitCode } = await parse(
|
|
197
|
-
['update', '--json'],
|
|
198
|
-
{ update: ((_deps, flags) => ((seen = flags as Record<string, unknown>), 0)) as ProgramRunners['update'] },
|
|
199
|
-
)
|
|
200
|
-
expect(exitCode).toBe(0)
|
|
201
|
-
expect(seen).toEqual({ json: true })
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
it('disentangles --no-wait and --wait from their shared commander flag', async () => {
|
|
205
|
-
const capture = (sink: Record<string, unknown>[]): ProgramRunners['send'] =>
|
|
206
|
-
(async (_deps, flags) => (sink.push(flags as Record<string, unknown>), 0)) as ProgramRunners['send']
|
|
207
|
-
const seen: Record<string, unknown>[] = []
|
|
208
|
-
await parse(['send', '--kind', 'update', '--title', 'T', '--body', 'B', '--no-wait'], { send: capture(seen) })
|
|
209
|
-
await parse(['send', '--kind', 'update', '--title', 'T', '--body', 'B', '--wait', '5'], { send: capture(seen) })
|
|
210
|
-
expect(seen[0]).toMatchObject({ noWait: true })
|
|
211
|
-
expect(seen[0]).not.toHaveProperty('wait')
|
|
212
|
-
expect(seen[1]).toMatchObject({ noWait: false, wait: 5 })
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
it('reads --body-file and refuses it alongside --body', async () => {
|
|
216
|
-
const dir = mkdtempSync(path.join(os.tmpdir(), 'notifai-program-test-'))
|
|
217
|
-
const file = path.join(dir, 'body.md')
|
|
218
|
-
writeFileSync(file, 'From a file.\n')
|
|
219
|
-
let seen: Record<string, unknown> | undefined
|
|
220
|
-
const send = (async (_deps, flags) => ((seen = flags as Record<string, unknown>), 0)) as ProgramRunners['send']
|
|
221
|
-
|
|
222
|
-
const ok = await parse(['send', '--kind', 'update', '--title', 'T', '--body-file', file], { send })
|
|
223
|
-
expect(ok.exitCode).toBe(0)
|
|
224
|
-
expect(seen).toMatchObject({ body: 'From a file.\n' })
|
|
225
|
-
expect(seen).not.toHaveProperty('bodyFile')
|
|
226
|
-
|
|
227
|
-
const both = await parse(
|
|
228
|
-
['send', '--kind', 'update', '--title', 'T', '--body', 'B', '--body-file', file],
|
|
229
|
-
{ send },
|
|
230
|
-
)
|
|
231
|
-
expect(both.exitCode).toBe(2)
|
|
232
|
-
expect(both.deps.errLines.join('\n')).toContain('either --body or --body-file')
|
|
233
|
-
|
|
234
|
-
const missing = await parse(
|
|
235
|
-
['send', '--kind', 'update', '--title', 'T', '--body-file', path.join(dir, 'absent.md')],
|
|
236
|
-
{ send },
|
|
237
|
-
)
|
|
238
|
-
expect(missing.exitCode).toBe(2)
|
|
239
|
-
expect(missing.deps.errLines.join('\n')).toContain('Could not read')
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
it('builds ask flags without empty collectors and passes the question through', async () => {
|
|
243
|
-
let seenQuestion: string | undefined
|
|
244
|
-
let seenFlags: Record<string, unknown> | undefined
|
|
245
|
-
const ask = (async (_deps, question, flags) => {
|
|
246
|
-
seenQuestion = question
|
|
247
|
-
seenFlags = flags as Record<string, unknown>
|
|
248
|
-
return 0
|
|
249
|
-
}) as ProgramRunners['ask']
|
|
250
|
-
|
|
251
|
-
await parse(
|
|
252
|
-
['ask', 'Deploy where?', '--choice', 'Staging', '--choice', 'Production', '--session-label', 'release run', '--json'],
|
|
253
|
-
{ ask },
|
|
254
|
-
)
|
|
255
|
-
expect(seenQuestion).toBe('Deploy where?')
|
|
256
|
-
expect(seenFlags).toEqual({
|
|
257
|
-
choice: ['Staging', 'Production'],
|
|
258
|
-
sessionLabel: 'release run',
|
|
259
|
-
json: true,
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
await parse(['ask', 'Free text?'], { ask })
|
|
263
|
-
expect(seenFlags).toEqual({})
|
|
264
|
-
})
|
|
265
|
-
|
|
266
|
-
it('rejects --no-block as unknown: the flag is gone, not tombstoned', async () => {
|
|
267
|
-
const { exitCode, deps } = await parse(
|
|
268
|
-
['send', '--kind', 'update', '--title', 'T', '--body', 'B', '--no-block'],
|
|
269
|
-
{ send: (async () => 0) as ProgramRunners['send'] },
|
|
270
|
-
)
|
|
271
|
-
expect(exitCode).toBe(2)
|
|
272
|
-
expect(deps.errLines).toHaveLength(0)
|
|
273
|
-
})
|
|
274
|
-
|
|
275
|
-
it('names an unknown command and exits 2', async () => {
|
|
276
|
-
const { exitCode, deps } = await parse(['sendd'], {})
|
|
277
|
-
expect(exitCode).toBe(2)
|
|
278
|
-
expect(deps.errLines.join('\n')).toContain('Unknown command "sendd"')
|
|
279
|
-
expect(deps.errLines.join('\n')).toContain('send')
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
it('rejects send --event now that the public event field is gone', async () => {
|
|
283
|
-
const { exitCode, deps } = await parse(
|
|
284
|
-
['send', '--kind', 'done', '--title', 'T', '--body', 'B', '--event', 'tests_passed'],
|
|
285
|
-
{ send: (async () => 0) as ProgramRunners['send'] },
|
|
286
|
-
)
|
|
287
|
-
expect(exitCode).toBe(2)
|
|
288
|
-
expect(deps.errLines).toHaveLength(0)
|
|
289
|
-
})
|
|
290
|
-
|
|
291
|
-
it('drops the empty --event collector for logs', async () => {
|
|
292
|
-
let seen: Record<string, unknown> | undefined
|
|
293
|
-
const logs = ((_deps, flags) => ((seen = flags as Record<string, unknown>), 0)) as ProgramRunners['logs']
|
|
294
|
-
await parse(['logs'], { logs })
|
|
295
|
-
expect(seen).not.toHaveProperty('event')
|
|
296
|
-
await parse(['logs', '--event', 'send.submitted'], { logs })
|
|
297
|
-
expect(seen).toMatchObject({ event: ['send.submitted'] })
|
|
298
|
-
})
|
|
299
|
-
|
|
300
|
-
it('passes close --pending without inventing a request id', async () => {
|
|
301
|
-
let seenId: string | undefined
|
|
302
|
-
let seenFlags: Record<string, unknown> | undefined
|
|
303
|
-
const close = (async (_deps, requestId, flags) => {
|
|
304
|
-
seenId = requestId
|
|
305
|
-
seenFlags = flags as Record<string, unknown>
|
|
306
|
-
return 0
|
|
307
|
-
}) as ProgramRunners['close']
|
|
308
|
-
|
|
309
|
-
await parse(['close', '--pending', '--json'], { close })
|
|
310
|
-
expect(seenId).toBeUndefined()
|
|
311
|
-
expect(seenFlags).toEqual({ pending: true, json: true })
|
|
312
|
-
|
|
313
|
-
await parse(['close', 'req_abc'], { close })
|
|
314
|
-
expect(seenId).toBe('req_abc')
|
|
315
|
-
expect(seenFlags).toEqual({})
|
|
316
|
-
})
|
|
317
|
-
})
|