@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.
- package/README.md +20 -4
- package/dist/atomic-file.d.ts +4 -0
- package/dist/atomic-file.js +60 -10
- package/dist/atomic-file.js.map +1 -1
- package/dist/client.d.ts +25 -2
- package/dist/client.js +45 -1
- package/dist/client.js.map +1 -1
- package/dist/commands.d.ts +85 -6
- package/dist/commands.js +1133 -322
- package/dist/commands.js.map +1 -1
- package/dist/config-schema.d.ts +62 -0
- package/dist/config-schema.js +312 -0
- package/dist/config-schema.js.map +1 -0
- package/dist/config.d.ts +38 -3
- package/dist/config.js +61 -14
- package/dist/config.js.map +1 -1
- package/dist/file-lock.d.ts +26 -0
- package/dist/file-lock.js +268 -0
- package/dist/file-lock.js.map +1 -0
- package/dist/harnesses.d.ts +28 -0
- package/dist/harnesses.js +40 -0
- package/dist/harnesses.js.map +1 -0
- package/dist/hook-adapter.d.ts +27 -0
- package/dist/hook-adapter.js +188 -0
- package/dist/hook-adapter.js.map +1 -0
- package/dist/hook-input.d.ts +10 -0
- package/dist/hook-input.js +64 -0
- package/dist/hook-input.js.map +1 -0
- package/dist/hooks.d.ts +66 -10
- package/dist/hooks.js +751 -276
- package/dist/hooks.js.map +1 -1
- package/dist/install-hooks.d.ts +40 -16
- package/dist/install-hooks.js +217 -73
- package/dist/install-hooks.js.map +1 -1
- package/dist/interactive.d.ts +4 -0
- package/dist/interactive.js +604 -0
- package/dist/interactive.js.map +1 -0
- package/dist/logging.d.ts +142 -0
- package/dist/logging.js +533 -0
- package/dist/logging.js.map +1 -0
- package/dist/main.js +201 -51
- package/dist/main.js.map +1 -1
- package/dist/opencode-plugin.d.ts +7 -7
- package/dist/opencode-plugin.js +12 -13
- package/dist/opencode-plugin.js.map +1 -1
- package/dist/ui/banner.d.ts +22 -0
- package/dist/ui/banner.js +87 -0
- package/dist/ui/banner.js.map +1 -0
- package/dist/ui/config-view.d.ts +32 -0
- package/dist/ui/config-view.js +108 -0
- package/dist/ui/config-view.js.map +1 -0
- package/dist/ui/help.d.ts +46 -0
- package/dist/ui/help.js +105 -0
- package/dist/ui/help.js.map +1 -0
- package/dist/ui/theme.d.ts +108 -0
- package/dist/ui/theme.js +261 -0
- package/dist/ui/theme.js.map +1 -0
- package/package.json +11 -9
- package/src/atomic-file.ts +86 -7
- package/src/client.test.ts +12 -0
- package/src/client.ts +72 -4
- package/src/commands.test.ts +971 -44
- package/src/commands.ts +1323 -337
- package/src/config-schema.test.ts +152 -0
- package/src/config-schema.ts +363 -0
- package/src/config.test.ts +6 -5
- package/src/config.ts +85 -16
- package/src/file-lock-process-worker.test.ts +64 -0
- package/src/file-lock.test.ts +279 -0
- package/src/file-lock.ts +318 -0
- package/src/harnesses.test.ts +48 -0
- package/src/harnesses.ts +59 -0
- package/src/hook-adapter.test.ts +187 -0
- package/src/hook-adapter.ts +212 -0
- package/src/hook-input.test.ts +39 -0
- package/src/hook-input.ts +72 -0
- package/src/hooks.test.ts +1318 -240
- package/src/hooks.ts +1046 -296
- package/src/install-hooks.test.ts +90 -41
- package/src/install-hooks.ts +259 -74
- package/src/interactive.ts +692 -0
- package/src/logging-process-worker.test.ts +39 -0
- package/src/logging.test.ts +453 -0
- package/src/logging.ts +639 -0
- package/src/main.ts +220 -48
- package/src/opencode-plugin.ts +15 -16
- package/src/session-end-log-lock-worker.test.ts +35 -0
- package/src/skill.test.ts +11 -0
- package/src/ui/banner.ts +95 -0
- package/src/ui/config-view.test.ts +88 -0
- package/src/ui/config-view.ts +138 -0
- package/src/ui/help.ts +124 -0
- package/src/ui/theme.test.ts +92 -0
- package/src/ui/theme.ts +279 -0
package/README.md
CHANGED
|
@@ -42,10 +42,10 @@ The agent registers the question, ends its turn, and your answer comes
|
|
|
42
42
|
back on its next turn. On iPhone the choices are buttons on the banner
|
|
43
43
|
itself.
|
|
44
44
|
|
|
45
|
-
By default a question
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
By default a question reaches your devices when the agent turn ends, even if
|
|
46
|
+
you are at the keyboard (`require_idle = false`, `ask_grace_seconds = 0`). Turn
|
|
47
|
+
on `require_idle` if you want active keyboard or mouse use to keep questions in
|
|
48
|
+
the terminal, or set a positive grace period for a terminal-only answer window.
|
|
49
49
|
|
|
50
50
|
For a harness that cannot resume an idle agent turn, `notifai send
|
|
51
51
|
--reply` blocks and waits for the answer instead.
|
|
@@ -61,6 +61,22 @@ is what lets an agent's question reach your phone without the agent
|
|
|
61
61
|
having to cooperate — no question detection, no state in a context window
|
|
62
62
|
that compaction will eat.
|
|
63
63
|
|
|
64
|
+
Every harness definition calls one stable user-level adapter at
|
|
65
|
+
`~/.notifai/bin/hook-adapter`. Node, package manager, CLI version, checkout,
|
|
66
|
+
XDG directories, and notification preferences are resolved behind it, so
|
|
67
|
+
upgrades and configuration changes do not rewrite trusted hook definitions.
|
|
68
|
+
The first migration may require one Codex `/hooks` approval; later repairs keep
|
|
69
|
+
the same identity. Codex's Stop definition omits its timeout so the host default
|
|
70
|
+
remains authoritative; prompt-submit and session-end retain fixed short limits.
|
|
71
|
+
|
|
72
|
+
`notifai doctor` compares Codex trust on a best-effort basis against Codex's
|
|
73
|
+
current persisted representation. Notifai never writes that trust store;
|
|
74
|
+
Codex's `/hooks` review is authoritative if the diagnostic and UI disagree.
|
|
75
|
+
|
|
76
|
+
Uninstall removes only the selected harness definition. It intentionally keeps
|
|
77
|
+
the shared adapter because definitions for other harnesses or projects may
|
|
78
|
+
still invoke it and cannot all be discovered from one working directory.
|
|
79
|
+
|
|
64
80
|
## Checking it works
|
|
65
81
|
|
|
66
82
|
```sh
|
package/dist/atomic-file.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export interface AtomicWriteOptions {
|
|
2
2
|
/** Mode for a newly created file. Existing regular files keep their mode. */
|
|
3
3
|
mode?: number;
|
|
4
|
+
/** False when a managed executable must keep the requested mode on repair. */
|
|
5
|
+
preserveMode?: boolean;
|
|
6
|
+
/** Reject a target owned by another user instead of replacing it. */
|
|
7
|
+
requireCurrentUserOwner?: boolean;
|
|
4
8
|
}
|
|
5
9
|
/**
|
|
6
10
|
* Replace one regular file without exposing a truncated intermediate state.
|
package/dist/atomic-file.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
|
-
import { closeSync, fsyncSync, lstatSync, mkdirSync, openSync, renameSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
2
|
+
import { chmodSync, closeSync, fsyncSync, lstatSync, mkdirSync, openSync, renameSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
/**
|
|
5
5
|
* Replace one regular file without exposing a truncated intermediate state.
|
|
@@ -9,16 +9,21 @@ import path from 'node:path';
|
|
|
9
9
|
* symlink target is refused instead of silently writing through it.
|
|
10
10
|
*/
|
|
11
11
|
export function atomicWriteFileSync(file, contents, options = {}) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
12
|
+
const directory = path.dirname(file);
|
|
13
|
+
mkdirSync(directory, { recursive: true });
|
|
14
|
+
const parent = safeDirectory(directory, options.requireCurrentUserOwner ?? false);
|
|
15
|
+
const target = targetMetadata(file, options.mode ?? 0o600, options.preserveMode ?? true, options.requireCurrentUserOwner ?? false);
|
|
16
|
+
const temp = path.join(directory, `.${path.basename(file)}.notifai-${process.pid}-${randomBytes(6).toString('hex')}.tmp`);
|
|
15
17
|
let handle;
|
|
16
18
|
try {
|
|
17
|
-
handle = openSync(temp, 'wx', mode);
|
|
19
|
+
handle = openSync(temp, 'wx', target.mode);
|
|
18
20
|
writeFileSync(handle, contents);
|
|
19
21
|
fsyncSync(handle);
|
|
20
22
|
closeSync(handle);
|
|
21
23
|
handle = undefined;
|
|
24
|
+
chmodSync(temp, target.mode);
|
|
25
|
+
assertSameDirectory(directory, parent);
|
|
26
|
+
assertUnchangedTarget(file, target);
|
|
22
27
|
renameSync(temp, file);
|
|
23
28
|
}
|
|
24
29
|
catch (err) {
|
|
@@ -33,15 +38,15 @@ export function atomicWriteFileSync(file, contents, options = {}) {
|
|
|
33
38
|
throw err;
|
|
34
39
|
}
|
|
35
40
|
}
|
|
36
|
-
|
|
37
|
-
function targetMode(file, fallback) {
|
|
41
|
+
function targetMetadata(file, fallback, preserveMode, requireCurrentUserOwner) {
|
|
38
42
|
let stat;
|
|
39
43
|
try {
|
|
40
44
|
stat = lstatSync(file);
|
|
41
45
|
}
|
|
42
46
|
catch (err) {
|
|
43
|
-
if (err.code === 'ENOENT')
|
|
44
|
-
return fallback;
|
|
47
|
+
if (err.code === 'ENOENT') {
|
|
48
|
+
return { mode: fallback, identity: null };
|
|
49
|
+
}
|
|
45
50
|
throw err;
|
|
46
51
|
}
|
|
47
52
|
if (stat.isSymbolicLink()) {
|
|
@@ -50,6 +55,51 @@ function targetMode(file, fallback) {
|
|
|
50
55
|
}
|
|
51
56
|
if (!stat.isFile())
|
|
52
57
|
throw new Error(`${file} is not a regular file; refusing to replace it.`);
|
|
53
|
-
|
|
58
|
+
if (requireCurrentUserOwner)
|
|
59
|
+
assertCurrentUserOwns(file, stat.uid);
|
|
60
|
+
return {
|
|
61
|
+
mode: preserveMode ? stat.mode & 0o777 : fallback,
|
|
62
|
+
identity: { dev: stat.dev, ino: stat.ino },
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function assertUnchangedTarget(file, target) {
|
|
66
|
+
let current;
|
|
67
|
+
try {
|
|
68
|
+
current = lstatSync(file);
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
if (err.code === 'ENOENT' && target.identity === null)
|
|
72
|
+
return;
|
|
73
|
+
throw new Error(`${file} changed during the atomic write; refusing to replace it.`);
|
|
74
|
+
}
|
|
75
|
+
if (target.identity === null ||
|
|
76
|
+
current.dev !== target.identity.dev ||
|
|
77
|
+
current.ino !== target.identity.ino) {
|
|
78
|
+
throw new Error(`${file} changed during the atomic write; refusing to replace it.`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function safeDirectory(directory, requireCurrentUserOwner) {
|
|
82
|
+
const stat = lstatSync(directory);
|
|
83
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
84
|
+
throw new Error(`${directory} is not a regular directory; refusing to write inside it.`);
|
|
85
|
+
}
|
|
86
|
+
if (requireCurrentUserOwner)
|
|
87
|
+
assertCurrentUserOwns(directory, stat.uid);
|
|
88
|
+
return { dev: stat.dev, ino: stat.ino };
|
|
89
|
+
}
|
|
90
|
+
function assertSameDirectory(directory, expected) {
|
|
91
|
+
const current = lstatSync(directory);
|
|
92
|
+
if (current.isSymbolicLink() ||
|
|
93
|
+
!current.isDirectory() ||
|
|
94
|
+
current.dev !== expected.dev ||
|
|
95
|
+
current.ino !== expected.ino) {
|
|
96
|
+
throw new Error(`${directory} changed during the write; refusing to publish the file.`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function assertCurrentUserOwns(file, owner) {
|
|
100
|
+
const uid = typeof process.getuid === 'function' ? process.getuid() : undefined;
|
|
101
|
+
if (uid !== undefined && owner !== uid) {
|
|
102
|
+
throw new Error(`${file} is owned by uid ${owner}, not the current user; refusing to replace it.`);
|
|
103
|
+
}
|
|
54
104
|
}
|
|
55
105
|
//# sourceMappingURL=atomic-file.js.map
|
package/dist/atomic-file.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atomic-file.js","sourceRoot":"","sources":["../src/atomic-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EACL,SAAS,EACT,SAAS,EACT,SAAS,EACT,SAAS,EACT,QAAQ,EACR,UAAU,EACV,UAAU,EACV,aAAa,GACd,MAAM,SAAS,CAAA;AAChB,OAAO,IAAI,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"atomic-file.js","sourceRoot":"","sources":["../src/atomic-file.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AccountAccessResponse, BeginPairingResponse, CapabilityDocument, CreateMediaUploadRequestT, CreateMediaUploadResponse, EvidenceSnapshot, ListDevicesResponse, ListRepliesResponse, Platform, PollPairingResponse, SubmissionReceipt, SubmitNotificationRequestT } from '@raidiant/notifai-protocol';
|
|
2
|
+
import type { Logger } from './logging.js';
|
|
2
3
|
export declare class ApiCallError extends Error {
|
|
3
4
|
status: number;
|
|
4
5
|
code: string;
|
|
@@ -8,6 +9,13 @@ export declare class ApiCallError extends Error {
|
|
|
8
9
|
}
|
|
9
10
|
export declare class NetworkError extends Error {
|
|
10
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Whether a replies-poll failure is temporary while the durable request stays
|
|
14
|
+
* live. Transport faults, throttling, request timeouts, and server failures
|
|
15
|
+
* can recover on a later poll; client errors cannot be repaired by retrying
|
|
16
|
+
* the same authenticated request.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isRetryableReplyPollError(err: unknown): boolean;
|
|
11
19
|
export interface ApiClient {
|
|
12
20
|
beginPairing(body: {
|
|
13
21
|
machine_name: string;
|
|
@@ -24,8 +32,8 @@ export interface ApiClient {
|
|
|
24
32
|
waitSeconds: number;
|
|
25
33
|
afterSeq: number;
|
|
26
34
|
}): Promise<ListRepliesResponse>;
|
|
27
|
-
/** Retire a question
|
|
28
|
-
closeReplies(requestId: string): Promise<
|
|
35
|
+
/** Retire a question and return the replies committed before the close fence. */
|
|
36
|
+
closeReplies(requestId: string): Promise<ListRepliesResponse>;
|
|
29
37
|
createMediaUpload(body: CreateMediaUploadRequestT): Promise<CreateMediaUploadResponse>;
|
|
30
38
|
uploadMedia(grant: CreateMediaUploadResponse, bytes: Uint8Array): Promise<void>;
|
|
31
39
|
health(): Promise<boolean>;
|
|
@@ -37,5 +45,20 @@ export interface ClientOptions {
|
|
|
37
45
|
* whole network path stays inside the budget the harness allows them.
|
|
38
46
|
*/
|
|
39
47
|
timeoutMs?: number;
|
|
48
|
+
/**
|
|
49
|
+
* Absolute wall-clock ceiling for the caller's whole operation. This is
|
|
50
|
+
* intentionally separate from `timeoutMs`: a late long poll must not get a
|
|
51
|
+
* fresh per-request allowance after its owning harness hook is nearly done.
|
|
52
|
+
*/
|
|
53
|
+
deadlineAt?: number;
|
|
54
|
+
/** Test seam for `deadlineAt`; production uses the wall clock. */
|
|
55
|
+
now?: () => number;
|
|
56
|
+
/**
|
|
57
|
+
* Records each call locally. Worth having because the two failures that cost
|
|
58
|
+
* the most time — a server older than this CLI, and a network path that only
|
|
59
|
+
* fails inside a hook — both look identical from outside and are told apart
|
|
60
|
+
* instantly by a status code and a duration.
|
|
61
|
+
*/
|
|
62
|
+
logger?: Pick<Logger, 'debug' | 'error'>;
|
|
40
63
|
}
|
|
41
64
|
export declare function createClient(baseUrl: string, bearer: string | null, options?: ClientOptions): ApiClient;
|
package/dist/client.js
CHANGED
|
@@ -13,6 +13,19 @@ export class ApiCallError extends Error {
|
|
|
13
13
|
}
|
|
14
14
|
export class NetworkError extends Error {
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Whether a replies-poll failure is temporary while the durable request stays
|
|
18
|
+
* live. Transport faults, throttling, request timeouts, and server failures
|
|
19
|
+
* can recover on a later poll; client errors cannot be repaired by retrying
|
|
20
|
+
* the same authenticated request.
|
|
21
|
+
*/
|
|
22
|
+
export function isRetryableReplyPollError(err) {
|
|
23
|
+
if (err instanceof NetworkError)
|
|
24
|
+
return true;
|
|
25
|
+
if (!(err instanceof ApiCallError))
|
|
26
|
+
return false;
|
|
27
|
+
return err.status >= 500 || err.status === 429 || err.status === 408;
|
|
28
|
+
}
|
|
16
29
|
/**
|
|
17
30
|
* A deadline that fired reads as an abort, which says nothing useful on its
|
|
18
31
|
* own. Naming the timeout is what lets someone tell a hung server apart from a
|
|
@@ -30,14 +43,45 @@ const DEFAULT_TIMEOUT_MS = 20_000;
|
|
|
30
43
|
export function createClient(baseUrl, bearer, options = {}) {
|
|
31
44
|
const root = baseUrl.replace(/\/$/, '');
|
|
32
45
|
const budgetMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
46
|
+
const now = options.now ?? Date.now;
|
|
47
|
+
const logger = options.logger;
|
|
33
48
|
async function call(method, apiPath, body,
|
|
34
49
|
/** Seconds the server was asked to hold the connection open. */
|
|
35
50
|
serverWaitSeconds = 0) {
|
|
51
|
+
const startedAt = Date.now();
|
|
52
|
+
try {
|
|
53
|
+
const result = await callOnce(method, apiPath, body, serverWaitSeconds);
|
|
54
|
+
logger?.debug('http.call', {
|
|
55
|
+
method,
|
|
56
|
+
path: apiPath,
|
|
57
|
+
ok: true,
|
|
58
|
+
duration_ms: Date.now() - startedAt,
|
|
59
|
+
});
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
logger?.error('http.call', {
|
|
64
|
+
method,
|
|
65
|
+
path: apiPath,
|
|
66
|
+
ok: false,
|
|
67
|
+
duration_ms: Date.now() - startedAt,
|
|
68
|
+
...(err instanceof ApiCallError
|
|
69
|
+
? { status: err.status, code: err.code, message: err.message, details: err.details }
|
|
70
|
+
: { message: String(err) }),
|
|
71
|
+
});
|
|
72
|
+
throw err;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function callOnce(method, apiPath, body, serverWaitSeconds = 0) {
|
|
36
76
|
// Without this, a server that accepts the connection and then never answers
|
|
37
77
|
// hangs until the harness kills the whole hook — and the reply-poll deadline
|
|
38
78
|
// cannot interrupt an individual fetch. The signal covers the
|
|
39
79
|
// body read too, not just the response headers.
|
|
40
|
-
const
|
|
80
|
+
const requestBudgetMs = budgetMs + serverWaitSeconds * 1000;
|
|
81
|
+
const remainingMs = options.deadlineAt === undefined
|
|
82
|
+
? requestBudgetMs
|
|
83
|
+
: Math.max(1, options.deadlineAt - now());
|
|
84
|
+
const limitMs = Math.max(1, Math.min(requestBudgetMs, remainingMs));
|
|
41
85
|
const signal = AbortSignal.timeout(limitMs);
|
|
42
86
|
let response;
|
|
43
87
|
try {
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/commands.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { type ListRepliesResponse, type Platform, type QuestionT, type ReplyView } from '@raidiant/notifai-protocol';
|
|
1
|
+
import { type ListRepliesResponse, type Platform, type QuestionT, type ReplyView, type RoutableDevice } from '@raidiant/notifai-protocol';
|
|
2
2
|
import { type ApiClient, type ClientOptions } from './client.js';
|
|
3
3
|
import type { CredentialStore } from './credentials.js';
|
|
4
4
|
import { type Readiness } from './readiness.js';
|
|
5
|
+
import type { Tone } from './ui/theme.js';
|
|
5
6
|
import { type HookHarness } from './hooks.js';
|
|
7
|
+
import { type Logger } from './logging.js';
|
|
6
8
|
import { type SendFlags } from './send.js';
|
|
7
9
|
import type { NativeSkills, SkillScope } from './native-skills.js';
|
|
8
10
|
export interface CommandIo {
|
|
@@ -28,7 +30,13 @@ export interface CommandIo {
|
|
|
28
30
|
outro?(message: string): Promise<void>;
|
|
29
31
|
note?(message: string, title?: string): Promise<void>;
|
|
30
32
|
spinner?(message: string): Promise<CommandSpinner | null>;
|
|
31
|
-
|
|
33
|
+
/**
|
|
34
|
+
* A report line. `tone` distinguishes the two states that are neither pass
|
|
35
|
+
* nor fail — something optional the user declined, and something that was
|
|
36
|
+
* never evaluated — which a boolean has to round to one or the other.
|
|
37
|
+
* Optional so existing implementations keep type-checking.
|
|
38
|
+
*/
|
|
39
|
+
check?(ok: boolean, message: string, tone?: Tone): Promise<void>;
|
|
32
40
|
}
|
|
33
41
|
export interface CommandSpinner {
|
|
34
42
|
message(message: string): void;
|
|
@@ -40,6 +48,8 @@ export interface CommandDeps {
|
|
|
40
48
|
store: CredentialStore;
|
|
41
49
|
env: NodeJS.ProcessEnv;
|
|
42
50
|
cwd: string;
|
|
51
|
+
/** Test seam; production fixes the hook adapter under os.homedir(). */
|
|
52
|
+
hookAdapterHome?: string;
|
|
43
53
|
/** Test seam; production uses fetch against base_url. */
|
|
44
54
|
clientFactory?: (baseUrl: string, bearer: string | null, options?: ClientOptions) => ApiClient;
|
|
45
55
|
/** Test seam for bounded polling without wall-clock sleeps. */
|
|
@@ -50,7 +60,14 @@ export interface CommandDeps {
|
|
|
50
60
|
idleSeconds?: () => number | null;
|
|
51
61
|
/** Test seam and production adapter for the external native skills installer. */
|
|
52
62
|
nativeSkills?: NativeSkills;
|
|
63
|
+
/**
|
|
64
|
+
* The local record of what this invocation did. Optional so a test fake need
|
|
65
|
+
* not carry one; `log(deps)` supplies a logger that records nothing.
|
|
66
|
+
*/
|
|
67
|
+
logger?: Logger;
|
|
53
68
|
}
|
|
69
|
+
/** The invocation's logger, or one that discards everything. */
|
|
70
|
+
export declare function log(deps: CommandDeps): Logger;
|
|
54
71
|
export declare const EXIT: {
|
|
55
72
|
readonly ok: 0;
|
|
56
73
|
readonly failed: 1;
|
|
@@ -75,6 +92,18 @@ export declare function accessStatusCommand(deps: CommandDeps, flags: {
|
|
|
75
92
|
export declare function devicesCommand(deps: CommandDeps, flags: {
|
|
76
93
|
json?: boolean;
|
|
77
94
|
}): Promise<number>;
|
|
95
|
+
/**
|
|
96
|
+
* Devices as data, for surfaces that render them themselves.
|
|
97
|
+
*
|
|
98
|
+
* `devicesCommand` prints and returns an exit code, which is the right shape
|
|
99
|
+
* for a command and the wrong one for a menu that wants to show names beside
|
|
100
|
+
* checkboxes. Silent on every failure by design: the interactive app already
|
|
101
|
+
* shows the credential and connectivity state on its status card, so a second
|
|
102
|
+
* error line here would be reporting the same fault twice.
|
|
103
|
+
*/
|
|
104
|
+
export declare function deviceInventory(deps: CommandDeps): Promise<RoutableDevice[] | null>;
|
|
105
|
+
/** Whether a device is in a state where a notification would actually arrive. */
|
|
106
|
+
export declare function canDeviceReceive(device: RoutableDevice): boolean;
|
|
78
107
|
export declare function capabilitiesCommand(deps: CommandDeps, flags: {
|
|
79
108
|
json?: boolean;
|
|
80
109
|
platform?: Platform;
|
|
@@ -128,6 +157,8 @@ export declare function statusCommand(deps: CommandDeps, requestId: string, flag
|
|
|
128
157
|
}): Promise<number>;
|
|
129
158
|
export declare const HOOK_EVENTS: readonly ["user-prompt-submit", "stop", "session-end"];
|
|
130
159
|
export type HookEvent = (typeof HOOK_EVENTS)[number];
|
|
160
|
+
/** SessionEnd cleanup must precede every diagnostic that can wait on a file lock. */
|
|
161
|
+
export declare function hookDefersDiagnosticsUntilAfterCleanup(event: unknown): event is 'session-end';
|
|
131
162
|
/**
|
|
132
163
|
* Runs one harness hook. Contract with every harness: hook JSON arrives on
|
|
133
164
|
* stdin, the decision (if any) goes to stdout, diagnostics go to stderr, and
|
|
@@ -178,9 +209,9 @@ export declare function buildQuestions(flags: AskFlags, question: string | undef
|
|
|
178
209
|
};
|
|
179
210
|
/**
|
|
180
211
|
* Registers a question for turn-end routing under the user's presence config.
|
|
181
|
-
* Returns immediately so the agent can ask in prose and end its turn.
|
|
182
|
-
*
|
|
183
|
-
*
|
|
212
|
+
* Returns immediately so the agent can ask in prose and end its turn. Presence
|
|
213
|
+
* does not block the shipped default; `require_idle = true` intentionally keeps
|
|
214
|
+
* the question local while the user is active.
|
|
184
215
|
*/
|
|
185
216
|
export declare function askCommand(deps: CommandDeps, question: string | undefined, flags: AskFlags): number;
|
|
186
217
|
/** Retire a question so a late answer is rejected rather than silently lost. */
|
|
@@ -197,6 +228,18 @@ export declare function hooksUninstallCommand(deps: CommandDeps, flags: HooksIns
|
|
|
197
228
|
export declare function configShowCommand(deps: CommandDeps, flags: {
|
|
198
229
|
json?: boolean;
|
|
199
230
|
explain?: boolean;
|
|
231
|
+
plain?: boolean;
|
|
232
|
+
}): number;
|
|
233
|
+
/**
|
|
234
|
+
* One setting, explained in full.
|
|
235
|
+
*
|
|
236
|
+
* The gap this closes: `config show` prints a value and provenance but that is
|
|
237
|
+
* not enough to explain the setting's consequences. Every key already had a
|
|
238
|
+
* careful explanation — in a TypeScript comment, read by everyone except the
|
|
239
|
+
* person who needed it.
|
|
240
|
+
*/
|
|
241
|
+
export declare function configExplainCommand(deps: CommandDeps, key: string, flags?: {
|
|
242
|
+
json?: boolean;
|
|
200
243
|
}): number;
|
|
201
244
|
export declare function configSetCommand(deps: CommandDeps, key: string, rawValue: string, flags: {
|
|
202
245
|
project?: boolean;
|
|
@@ -204,12 +247,48 @@ export declare function configSetCommand(deps: CommandDeps, key: string, rawValu
|
|
|
204
247
|
session?: string;
|
|
205
248
|
yes?: boolean;
|
|
206
249
|
}): Promise<number>;
|
|
250
|
+
type ConfigMutationFlags = {
|
|
251
|
+
project?: boolean;
|
|
252
|
+
local?: boolean;
|
|
253
|
+
session?: string;
|
|
254
|
+
yes?: boolean;
|
|
255
|
+
};
|
|
256
|
+
export declare function configUnsetCommand(deps: CommandDeps, key: string, flags: ConfigMutationFlags): Promise<number>;
|
|
257
|
+
export interface LogsFlags {
|
|
258
|
+
json?: boolean;
|
|
259
|
+
limit?: number;
|
|
260
|
+
all?: boolean;
|
|
261
|
+
since?: string;
|
|
262
|
+
level?: string;
|
|
263
|
+
event?: string[];
|
|
264
|
+
run?: string;
|
|
265
|
+
request?: string;
|
|
266
|
+
session?: string;
|
|
267
|
+
project?: string;
|
|
268
|
+
allProjects?: boolean;
|
|
269
|
+
grep?: string;
|
|
270
|
+
path?: boolean;
|
|
271
|
+
clear?: boolean;
|
|
272
|
+
}
|
|
273
|
+
/** `10m`, `2h`, `1d`, or an ISO 8601 instant. */
|
|
274
|
+
export declare function parseSince(raw: string, now: number): number | null;
|
|
275
|
+
/**
|
|
276
|
+
* What this machine recorded about itself.
|
|
277
|
+
*
|
|
278
|
+
* The retrieval half of the local log, and the half that decides whether the
|
|
279
|
+
* log is worth having. Three things make it usable by an agent rather than
|
|
280
|
+
* merely available to one: the default is bounded and scoped to this project,
|
|
281
|
+
* the filters match the questions actually asked ("that run", "that
|
|
282
|
+
* notification", "just the failures"), and `--json` gives the machine the
|
|
283
|
+
* records untouched on stdout while every word of explanation goes to stderr.
|
|
284
|
+
*/
|
|
285
|
+
export declare function logsCommand(deps: CommandDeps, flags: LogsFlags): number;
|
|
207
286
|
/**
|
|
208
287
|
* Where `npx skills add` fetches the optional agent skill from. In skills CLI
|
|
209
288
|
* 1.5.x, `owner/repo@name` selects a skill; a Git ref belongs after `#`.
|
|
210
289
|
* Keep this immutable and public because the command is printed to users.
|
|
211
290
|
*/
|
|
212
|
-
export declare const SKILLS_SOURCE = "Raidiant-io/notifai#v0.
|
|
291
|
+
export declare const SKILLS_SOURCE = "Raidiant-io/notifai#v0.4.0";
|
|
213
292
|
/** Derive a contract-valid project slug from a directory name. */
|
|
214
293
|
export declare function projectSlugFrom(name: string): string;
|
|
215
294
|
export interface InitFlags {
|