@tinycloud/courier 0.2.0-beta.37 → 0.2.0-beta.39
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 +369 -12
- package/dist/a2a.d.ts +6 -0
- package/dist/a2a.js +10 -0
- package/dist/a2a.js.map +1 -1
- package/dist/approval.d.ts +6 -5
- package/dist/approval.js +7 -16
- package/dist/approval.js.map +1 -1
- package/dist/args.js +1 -1
- package/dist/args.js.map +1 -1
- package/dist/broker-config.d.ts +24 -0
- package/dist/broker-config.js +99 -0
- package/dist/broker-config.js.map +1 -0
- package/dist/broker.d.ts +77 -0
- package/dist/broker.js +253 -0
- package/dist/broker.js.map +1 -0
- package/dist/commands.js +5 -2
- package/dist/commands.js.map +1 -1
- package/dist/consumed.d.ts +10 -0
- package/dist/consumed.js +54 -0
- package/dist/consumed.js.map +1 -0
- package/dist/guard/binaries.d.ts +17 -0
- package/dist/guard/binaries.js +89 -0
- package/dist/guard/binaries.js.map +1 -0
- package/dist/guard/cleanhome.d.ts +27 -0
- package/dist/guard/cleanhome.js +111 -0
- package/dist/guard/cleanhome.js.map +1 -0
- package/dist/guard/command.d.ts +13 -0
- package/dist/guard/command.js +158 -0
- package/dist/guard/command.js.map +1 -0
- package/dist/guard/expansion.d.ts +10 -0
- package/dist/guard/expansion.js +74 -0
- package/dist/guard/expansion.js.map +1 -0
- package/dist/guard/hook.d.ts +38 -0
- package/dist/guard/hook.js +124 -0
- package/dist/guard/hook.js.map +1 -0
- package/dist/guard/install.d.ts +67 -0
- package/dist/guard/install.js +193 -0
- package/dist/guard/install.js.map +1 -0
- package/dist/guard/network.d.ts +7 -0
- package/dist/guard/network.js +78 -0
- package/dist/guard/network.js.map +1 -0
- package/dist/guard/normalize.d.ts +28 -0
- package/dist/guard/normalize.js +257 -0
- package/dist/guard/normalize.js.map +1 -0
- package/dist/guard/paseo.d.ts +30 -0
- package/dist/guard/paseo.js +148 -0
- package/dist/guard/paseo.js.map +1 -0
- package/dist/guard/paths.d.ts +31 -0
- package/dist/guard/paths.js +180 -0
- package/dist/guard/paths.js.map +1 -0
- package/dist/guard/policy.d.ts +65 -0
- package/dist/guard/policy.js +1179 -0
- package/dist/guard/policy.js.map +1 -0
- package/dist/guard/shell.d.ts +55 -0
- package/dist/guard/shell.js +727 -0
- package/dist/guard/shell.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/keys.d.ts +4 -1
- package/dist/keys.js +7 -2
- package/dist/keys.js.map +1 -1
- package/dist/main.js +44 -4
- package/dist/main.js.map +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +3 -3
- package/dist/node.js.map +1 -1
- package/dist/notify.d.ts +43 -0
- package/dist/notify.js +92 -0
- package/dist/notify.js.map +1 -0
- package/dist/pause.d.ts +32 -0
- package/dist/pause.js +111 -0
- package/dist/pause.js.map +1 -0
- package/dist/profile.d.ts +3 -3
- package/dist/profile.js +12 -12
- package/dist/profile.js.map +1 -1
- package/dist/wake.d.ts +17 -0
- package/dist/wake.js +74 -13
- package/dist/wake.js.map +1 -1
- package/dist/watch-cmd.d.ts +3 -0
- package/dist/watch-cmd.js +56 -2
- package/dist/watch-cmd.js.map +1 -1
- package/dist/watch.d.ts +134 -0
- package/dist/watch.js +697 -13
- package/dist/watch.js.map +1 -1
- package/package.json +1 -1
- package/skills/courier/SKILL.md +119 -8
package/dist/watch.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { HookSubscription } from '@tinycloud/node-sdk';
|
|
|
2
2
|
import type { StoredPeer } from './profile.js';
|
|
3
3
|
import { type KV } from './inbox.js';
|
|
4
4
|
import type { WakeApproval, WakeMessage, Waker, WatchLog } from './wake.js';
|
|
5
|
+
import { type Notice, type Notifier } from './notify.js';
|
|
5
6
|
export interface PendingWake {
|
|
6
7
|
peer: string;
|
|
7
8
|
threadId: string;
|
|
@@ -12,6 +13,38 @@ export interface PendingWake {
|
|
|
12
13
|
firstSeenAt: number;
|
|
13
14
|
lastSeenAt: number;
|
|
14
15
|
}
|
|
16
|
+
interface NoticeRetry {
|
|
17
|
+
/** Six digits while dispatching, otherwise six dashes; independent of the display count. */
|
|
18
|
+
dispatchArrivals: string;
|
|
19
|
+
tries: number;
|
|
20
|
+
nextAttemptAt: number;
|
|
21
|
+
logged: boolean;
|
|
22
|
+
}
|
|
23
|
+
type NeedsKind = 'message' | 'approval';
|
|
24
|
+
interface NeedsSlot extends NoticeRetry {
|
|
25
|
+
threadId: string;
|
|
26
|
+
eventId: string;
|
|
27
|
+
count: string;
|
|
28
|
+
firstSeenAt: string;
|
|
29
|
+
arrivalFirstSeenAt: string;
|
|
30
|
+
}
|
|
31
|
+
interface PauseEpisode extends NoticeRetry {
|
|
32
|
+
kind: '' | 'paused' | 'peer-paused';
|
|
33
|
+
eventId: string;
|
|
34
|
+
/** Fixed-width saturating count of additional transitions represented by this slot. */
|
|
35
|
+
repeats: string;
|
|
36
|
+
}
|
|
37
|
+
/** Allocated only from our own thread/wake/pause records, never from incoming notice ids. */
|
|
38
|
+
interface ThreadNoticeState {
|
|
39
|
+
ourPaused: boolean;
|
|
40
|
+
peerPaused: boolean;
|
|
41
|
+
lastPeerNoticeId: string;
|
|
42
|
+
lastNoticeSentAt: string;
|
|
43
|
+
ourMarkerId: string;
|
|
44
|
+
episodes: [PauseEpisode, PauseEpisode];
|
|
45
|
+
informPending: boolean;
|
|
46
|
+
informText: string;
|
|
47
|
+
}
|
|
15
48
|
export interface WatchState {
|
|
16
49
|
v: 1;
|
|
17
50
|
/** Keyed `<peer>/<threadId>`. */
|
|
@@ -19,11 +52,61 @@ export interface WatchState {
|
|
|
19
52
|
/** Recently woken message ids, so a receipt write that failed cannot cause a second wake. */
|
|
20
53
|
woken: string[];
|
|
21
54
|
approvalsSeen: string[];
|
|
55
|
+
/** Message wake attempts today (UTC), per `<peer>/<threadId>`, as epoch ms (approval wakes do not count). */
|
|
56
|
+
wakes: Record<string, number[]>;
|
|
57
|
+
/** Threads this watcher has seen paused; a marker that vanishes from this list means the human resumed it. */
|
|
58
|
+
paused: string[];
|
|
59
|
+
/** Failed wake count and completion-based backoff, retained across watcher restarts. */
|
|
60
|
+
wakeRetries: Record<string, {
|
|
61
|
+
failures: number;
|
|
62
|
+
nextAttemptAt: number;
|
|
63
|
+
}>;
|
|
64
|
+
approvalRetries: Record<string, {
|
|
65
|
+
failures: number;
|
|
66
|
+
nextAttemptAt: number;
|
|
67
|
+
}>;
|
|
68
|
+
/** Posts and notifications that must happen exactly-ish once and survive a restart (retried until they succeed). */
|
|
69
|
+
outbox: OutboxItem[];
|
|
70
|
+
held: Record<string, HeldBacklog>;
|
|
71
|
+
/** One fixed record per locally known thread. Peer ids are values, never keys. */
|
|
72
|
+
threadNotices: Record<string, ThreadNoticeState>;
|
|
73
|
+
/** Two coalescing needs-you slots per locally paired peer, allocated only from local configuration. */
|
|
74
|
+
peerNotices: Record<string, Record<NeedsKind, NeedsSlot>>;
|
|
75
|
+
noticeGlobalLog: number[];
|
|
76
|
+
/** Every dispatch attempt, success or failure, per peer for the shared rolling-hour cap. */
|
|
77
|
+
noticeLog: Record<string, number[]>;
|
|
78
|
+
}
|
|
79
|
+
/** `tries`: notification dispatch attempts (max 3), or failed inform attempts (max 8). */
|
|
80
|
+
export type OutboxItem = {
|
|
81
|
+
id: string;
|
|
82
|
+
kind: 'inform';
|
|
83
|
+
peer: string;
|
|
84
|
+
threadId: string;
|
|
85
|
+
text: string;
|
|
86
|
+
pauseId?: string;
|
|
87
|
+
tries?: number;
|
|
88
|
+
nextAttemptAt?: number;
|
|
89
|
+
} | {
|
|
90
|
+
id: string;
|
|
91
|
+
kind: 'notify';
|
|
92
|
+
notice: Notice;
|
|
93
|
+
tries?: number;
|
|
94
|
+
nextAttemptAt?: number;
|
|
95
|
+
logged?: boolean;
|
|
96
|
+
};
|
|
97
|
+
/** Messages that arrived while a thread was paused; they wake the agent once, together, after `courier resume`. */
|
|
98
|
+
export interface HeldBacklog {
|
|
99
|
+
peer: string;
|
|
100
|
+
threadId: string;
|
|
101
|
+
subject: string;
|
|
102
|
+
messages: WakeMessage[];
|
|
22
103
|
}
|
|
23
104
|
export interface WatchOptions {
|
|
24
105
|
debounceMs: number;
|
|
25
106
|
pollMs: number;
|
|
26
107
|
ticketSeconds: number;
|
|
108
|
+
/** Spec §8: at most this many wakes per side per thread per 24 h, then the thread pauses. */
|
|
109
|
+
wakeBudget: number;
|
|
27
110
|
}
|
|
28
111
|
export declare const WATCH_DEFAULTS: WatchOptions;
|
|
29
112
|
interface HookEventLike {
|
|
@@ -48,6 +131,14 @@ export interface WatchDeps {
|
|
|
48
131
|
kvFor(peer: StoredPeer): Promise<KV>;
|
|
49
132
|
wake: Waker;
|
|
50
133
|
log: WatchLog;
|
|
134
|
+
/** Posts the `thread-paused` inform to a peer (own space, `to/<peer>/threads/<id>/msg/`). Default: nothing. */
|
|
135
|
+
postInform?(peer: string, threadId: string, text: string, pauseId?: string): Promise<void>;
|
|
136
|
+
/** Tells this side's human without a model (desktop notification or operator command). Default: log only. */
|
|
137
|
+
notify?: Notifier;
|
|
138
|
+
/** Local bounded notification log; omitted by library callers that want no disk output. */
|
|
139
|
+
notificationHome?: string;
|
|
140
|
+
/** D mode mirrors and receipts, then notifies without invoking a wake adapter. */
|
|
141
|
+
notifyOnly?: boolean;
|
|
51
142
|
/**
|
|
52
143
|
* Who this watcher is, for wake claims. `profileId` is stable for this profile on this machine (a restart keeps it,
|
|
53
144
|
* a second profile or machine differs); `pid` and `isAlive` tell a restarted watcher its predecessor is dead.
|
|
@@ -71,6 +162,11 @@ export declare class Watcher {
|
|
|
71
162
|
private readonly retryAt;
|
|
72
163
|
private readonly waking;
|
|
73
164
|
private approvalsRunning;
|
|
165
|
+
/** Thread keys currently paused: markers under me/state/paused/ plus those this watcher just wrote. */
|
|
166
|
+
private pausedKeys;
|
|
167
|
+
/** Serialises everything that reads or writes pause markers, so a stale listing cannot drop a pause just written. */
|
|
168
|
+
private pausedLock;
|
|
169
|
+
private readonly outboxBusy;
|
|
74
170
|
private approvalsAgain;
|
|
75
171
|
/** Unique to this run: a claim with this id is this process's own. */
|
|
76
172
|
private readonly runId;
|
|
@@ -120,6 +216,8 @@ export declare class Watcher {
|
|
|
120
216
|
/** Serialises syncs per peer; a request that arrives mid-sync reruns once after it. */
|
|
121
217
|
sync(peer: StoredPeer, via: Via): Promise<void>;
|
|
122
218
|
private syncPeer;
|
|
219
|
+
/** Only locally authored meta/messages/tasks, or a local wake/pause witness, establish a known thread. */
|
|
220
|
+
private syncKnownThreads;
|
|
123
221
|
private mirrorCreate;
|
|
124
222
|
/**
|
|
125
223
|
* meta.json is immutable (create-only); tasks are mutable, so copy the latest until they are terminal. Runs after
|
|
@@ -137,7 +235,43 @@ export declare class Watcher {
|
|
|
137
235
|
private approvalWake;
|
|
138
236
|
/** Wake every thread whose debounce has elapsed (`force`: all of them now). Threads wake in parallel, one wake per thread at a time. */
|
|
139
237
|
tick(force?: boolean): Promise<void>;
|
|
238
|
+
/** Spec §8: the budget is per side, per thread, per day. A day is the UTC calendar day, so it is easy to state and to check. */
|
|
239
|
+
private recentWakes;
|
|
140
240
|
private wakeThread;
|
|
241
|
+
/** Budget reached: pause this side's wakes for the thread, tell the peer (inform), tell this side's human. */
|
|
242
|
+
private pauseThread;
|
|
243
|
+
private exclusive;
|
|
244
|
+
/** Called inside `mutate`: parks a message that arrived while its thread is paused (bounded). */
|
|
245
|
+
private hold;
|
|
246
|
+
/** Two episode values per known thread. Additional transitions coalesce, without allocating another slot. */
|
|
247
|
+
private queueEpisode;
|
|
248
|
+
/** Only the paired handles in our local configuration allocate needs-you state. */
|
|
249
|
+
private syncNoticePeers;
|
|
250
|
+
/** Bounded values only: a later delivery updates the same paired-peer slot. Called inside mutate. */
|
|
251
|
+
private queueNeeds;
|
|
252
|
+
private noticeSlot;
|
|
253
|
+
private rememberNotice;
|
|
254
|
+
/** Earliest rolling-hour retry under the global allowance and each paired peer's share. */
|
|
255
|
+
private noticeRateDeadline;
|
|
256
|
+
/** -1 appends; a nonnegative index yields that place; undefined leaves the pending slot alone. */
|
|
257
|
+
private admissionIndex;
|
|
258
|
+
/** Queue places can yield; the two fixed episode records retain all retry metadata. */
|
|
259
|
+
private enqueue;
|
|
260
|
+
private outboxCandidates;
|
|
261
|
+
/** Admit local work first, allowing eligible peers to pass deferred entries in a full queue. */
|
|
262
|
+
private fillOutbox;
|
|
263
|
+
private fairOutbox;
|
|
264
|
+
/** Completion matches both the fixed slot and episode ULID; another queued episode is independent. */
|
|
265
|
+
private finishOutbox;
|
|
266
|
+
/**
|
|
267
|
+
* Markers under me/state/paused/ are the truth. A marker that disappeared means the human resumed: the budget starts
|
|
268
|
+
* over and what arrived meanwhile wakes the agent once. Serialised, so overlapping calls never apply a stale listing.
|
|
269
|
+
*/
|
|
270
|
+
syncPaused(): Promise<void>;
|
|
271
|
+
/** State that only matters for a day or an hour is dropped, so it cannot grow without bound. */
|
|
272
|
+
private pruneState;
|
|
273
|
+
/** Informs and notifications queued in state; failures back off (1, 2, 4 ... 15 minutes) and give up after 3 notification attempts or 8 inform failures. */
|
|
274
|
+
private runOutbox;
|
|
141
275
|
pollOnce(via: Via): Promise<void>;
|
|
142
276
|
/**
|
|
143
277
|
* Runs until `signal` aborts. With `once`, does one catch-up and wakes everything immediately. Throws
|