@maolon/pi-watcher 0.0.0-stage → 0.1.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 +18 -0
- package/LICENSE +21 -0
- package/README.md +255 -2
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +369 -0
- package/dist/contracts/interfaces.d.ts +262 -0
- package/dist/contracts/interfaces.js +1 -0
- package/dist/contracts/policy-defaults.json +61 -0
- package/dist/contracts/relay-next.interfaces.d.ts +160 -0
- package/dist/contracts/relay-next.interfaces.js +1 -0
- package/dist/engine/cards.d.ts +68 -0
- package/dist/engine/cards.js +76 -0
- package/dist/engine/engine.d.ts +178 -0
- package/dist/engine/engine.js +1162 -0
- package/dist/engine/hard-rules.d.ts +53 -0
- package/dist/engine/hard-rules.js +96 -0
- package/dist/engine/semantic.d.ts +49 -0
- package/dist/engine/semantic.js +125 -0
- package/dist/engine/service.d.ts +62 -0
- package/dist/engine/service.js +587 -0
- package/dist/engine/tool-actions.d.ts +35 -0
- package/dist/engine/tool-actions.js +348 -0
- package/dist/engine/widget.d.ts +29 -0
- package/dist/engine/widget.js +52 -0
- package/dist/ipc/client.d.ts +26 -0
- package/dist/ipc/client.js +106 -0
- package/dist/ipc/server.d.ts +78 -0
- package/dist/ipc/server.js +105 -0
- package/dist/jev/client.d.ts +38 -0
- package/dist/jev/client.js +239 -0
- package/dist/jev/consent.d.ts +12 -0
- package/dist/jev/consent.js +37 -0
- package/dist/jev/index.d.ts +9 -0
- package/dist/jev/index.js +9 -0
- package/dist/jev/mock.d.ts +30 -0
- package/dist/jev/mock.js +77 -0
- package/dist/jev/pi-registry.d.ts +66 -0
- package/dist/jev/pi-registry.js +127 -0
- package/dist/jev/questions.d.ts +15 -0
- package/dist/jev/questions.js +76 -0
- package/dist/jev/sanitizer.d.ts +10 -0
- package/dist/jev/sanitizer.js +59 -0
- package/dist/jev/types.d.ts +78 -0
- package/dist/jev/types.js +54 -0
- package/dist/pi-extension.d.ts +123 -0
- package/dist/pi-extension.js +687 -0
- package/dist/relay/managed.d.ts +120 -0
- package/dist/relay/managed.js +482 -0
- package/dist/relay/negotiate.d.ts +39 -0
- package/dist/relay/negotiate.js +112 -0
- package/dist/runtime.d.ts +74 -0
- package/dist/runtime.js +246 -0
- package/dist/source/agent-check/adapter.d.ts +57 -0
- package/dist/source/agent-check/adapter.js +224 -0
- package/dist/source/agent-file/adapter.d.ts +57 -0
- package/dist/source/agent-file/adapter.js +217 -0
- package/dist/source/task-status-v1/adapter.d.ts +36 -0
- package/dist/source/task-status-v1/adapter.js +263 -0
- package/dist/source/task-status-v1/producer.d.ts +81 -0
- package/dist/source/task-status-v1/producer.js +127 -0
- package/dist/storage/lock.d.ts +14 -0
- package/dist/storage/lock.js +66 -0
- package/dist/storage/schema.sql +166 -0
- package/dist/storage/store.d.ts +352 -0
- package/dist/storage/store.js +555 -0
- package/dist/util/clock.d.ts +23 -0
- package/dist/util/clock.js +34 -0
- package/dist/util/ids.d.ts +8 -0
- package/dist/util/ids.js +29 -0
- package/dist/util/result.d.ts +28 -0
- package/dist/util/result.js +54 -0
- package/package.json +101 -4
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WatchEngine: inspection pipeline (deterministic V1 subset of the design 5.2 processing order).
|
|
3
|
+
* 1) validate active/validity -> 2) read events/state (T2 ingest) -> 3) hard rules
|
|
4
|
+
* -> 4) episode supersede + result card (durable outbox + local display copy).
|
|
5
|
+
* The Jev semantic layer is wired in at V2 (JudgePort is ready); V1 has deterministic facts only.
|
|
6
|
+
*/
|
|
7
|
+
import type { Observation, SourceAdapter, Probe, JudgePort, ManagedDeliveryPort } from '../contracts/interfaces.js';
|
|
8
|
+
import type { WatchStore, WatchRow, WatchSnapshot } from '../storage/store.js';
|
|
9
|
+
import type { Clock } from '../util/clock.js';
|
|
10
|
+
import { type SemanticThresholds } from './semantic.js';
|
|
11
|
+
export interface WatchEngineOptions {
|
|
12
|
+
clock: Clock;
|
|
13
|
+
store: WatchStore;
|
|
14
|
+
adapters: Map<string, SourceAdapter>;
|
|
15
|
+
requiredCheckIds?: ReadonlyMap<string, readonly string[]>;
|
|
16
|
+
/** V2 hook: shadow/active semantic judgment; may be omitted in V1 */
|
|
17
|
+
judge?: JudgePort;
|
|
18
|
+
/** Note for the local display copy of the result card */
|
|
19
|
+
displayNote?: string;
|
|
20
|
+
/** V2 semantic-layer config (defaults to policy-defaults) */
|
|
21
|
+
semantic?: SemanticEngineConfig;
|
|
22
|
+
/** Data egress consent (required for live Jev; Mock does not export locally, tests may set judgeRequiresConsent=false) */
|
|
23
|
+
semanticConsent?: boolean | (() => boolean);
|
|
24
|
+
/** Whether the judge is egress-type (needs consent); pass false for Mock local judgment */
|
|
25
|
+
judgeRequiresConsent?: boolean;
|
|
26
|
+
/** V1 closed loop: relay managed delivery port (static or live reference; upgraded after mid-session bind) */
|
|
27
|
+
delivery?: ManagedDeliveryPort | (() => ManagedDeliveryPort | undefined);
|
|
28
|
+
/** Notification hook after attention lands in the outbox (for the display layer; does not block the engine) */
|
|
29
|
+
onAttention?: (notice: AttentionNotice) => void;
|
|
30
|
+
/** Judgment-complete notice (display layer; fires after an accepted judgment, must not block the engine) */
|
|
31
|
+
onJudgment?: (notice: JudgmentNotice) => void;
|
|
32
|
+
}
|
|
33
|
+
/** Attention notification published by the engine (passed across layers to the display layer / session toast). */
|
|
34
|
+
export interface AttentionNotice {
|
|
35
|
+
watchId: string;
|
|
36
|
+
ownerSession?: string;
|
|
37
|
+
episodeId: string;
|
|
38
|
+
reasonCode: string;
|
|
39
|
+
summary: string;
|
|
40
|
+
transport: 'relay-managed' | 'local-display' | 'relay-failed';
|
|
41
|
+
/** Failure reason when transport=relay-failed (same source as outbox admission_json.error) */
|
|
42
|
+
relayError?: string;
|
|
43
|
+
/** Deadline until which the envelope is still valid (ms epoch) */
|
|
44
|
+
validUntil: number;
|
|
45
|
+
}
|
|
46
|
+
/** Accepted-judgment-complete notification (display-layer notice; judge review must be visible) */
|
|
47
|
+
export interface JudgmentNotice {
|
|
48
|
+
watchId: string;
|
|
49
|
+
ownerSession?: string;
|
|
50
|
+
objective: string;
|
|
51
|
+
/** shadow = record only; active = may create episode/attention */
|
|
52
|
+
mode: 'shadow' | 'active';
|
|
53
|
+
/** Candidates that hit the threshold (none -> everything normal, no action needed) */
|
|
54
|
+
candidates: Array<{
|
|
55
|
+
reason: string;
|
|
56
|
+
probability: number;
|
|
57
|
+
note: string | null;
|
|
58
|
+
}>;
|
|
59
|
+
probabilities: Record<string, number>;
|
|
60
|
+
}
|
|
61
|
+
export interface SemanticEngineConfig {
|
|
62
|
+
thresholds: SemanticThresholds;
|
|
63
|
+
maxJudgeRequestsPerRootDay: number;
|
|
64
|
+
maxProbesPerInspection: number;
|
|
65
|
+
maxProbesPerEpisode: number;
|
|
66
|
+
maxEvidenceEvents: number;
|
|
67
|
+
stateMaxBytes: number;
|
|
68
|
+
}
|
|
69
|
+
export declare const DEFAULT_SEMANTIC_CONFIG: SemanticEngineConfig;
|
|
70
|
+
/** Default attention envelope validity: real wake latency includes safety-net ticks / long turns,
|
|
71
|
+
* 300s is not enough; also bounds the fast-close line. */
|
|
72
|
+
export declare const DEFAULT_ATTENTION_TTL_MS = 1800000;
|
|
73
|
+
export interface InspectionOutcome {
|
|
74
|
+
inspectionId: string;
|
|
75
|
+
watchId: string;
|
|
76
|
+
ingested: number;
|
|
77
|
+
produced: {
|
|
78
|
+
episodes: string[];
|
|
79
|
+
resultCards: string[];
|
|
80
|
+
};
|
|
81
|
+
health: WatchRow['health'];
|
|
82
|
+
lifecycleAfter: WatchRow['lifecycle'];
|
|
83
|
+
}
|
|
84
|
+
export declare class WatchEngine {
|
|
85
|
+
private readonly clock;
|
|
86
|
+
private readonly store;
|
|
87
|
+
private readonly adapters;
|
|
88
|
+
private readonly requiredCheckIds;
|
|
89
|
+
private readonly judge?;
|
|
90
|
+
private readonly displayNote;
|
|
91
|
+
private readonly semanticConfig;
|
|
92
|
+
private readonly semanticConsentRef;
|
|
93
|
+
private readonly judgeRequiresConsent;
|
|
94
|
+
private readonly deliveryRef;
|
|
95
|
+
private readonly onAttention?;
|
|
96
|
+
private readonly onJudgment?;
|
|
97
|
+
/** Single-flight per Watch (design 5.6) */
|
|
98
|
+
private readonly semanticInFlight;
|
|
99
|
+
/** After 401/403, egress is disabled within this process (design 5.6) */
|
|
100
|
+
private judgeDisabled;
|
|
101
|
+
constructor(options: WatchEngineOptions);
|
|
102
|
+
/** Consent is read live: the user may grant or revoke it mid-session (/watcher jev consent). */
|
|
103
|
+
private get semanticConsent();
|
|
104
|
+
private get delivery();
|
|
105
|
+
/** Run due inspections: returns the list of executed inspectionIds. */
|
|
106
|
+
runDue(limit?: number): Promise<string[]>;
|
|
107
|
+
inspectWatch(watchId: string, signal?: AbortSignal): Promise<InspectionOutcome | null>;
|
|
108
|
+
/**
|
|
109
|
+
* V2 semantic inspection (design 5.2 steps 3-5 / 5.5 / 5.6).
|
|
110
|
+
* Network calls do not hold a SQL write transaction; single-flight per Watch; late results are discarded after version check.
|
|
111
|
+
*/
|
|
112
|
+
private runSemanticPass;
|
|
113
|
+
/** V3: group (design 3.x watch-group) -- reads committed child Watch state. */
|
|
114
|
+
private inspectGroup;
|
|
115
|
+
/** V3: explicit follow-up obligation (pi-obligation-v1 semantics; pure time reminder = obligation without dependencies). */
|
|
116
|
+
private inspectObligation;
|
|
117
|
+
/** Unified attention publishing for hard facts / semantic candidates: truth lands in the outbox first, then publishes via relay managed delivery (I6). */
|
|
118
|
+
private publishEpisodeAttention;
|
|
119
|
+
/**
|
|
120
|
+
* Publishes an attention through the relay managed path; only advances admission, never the
|
|
121
|
+
* frozen truth (I06). The scope used is recorded in admission_json so a retry re-sends the
|
|
122
|
+
* identical (event, options) pair. Never throws: returns status for loud failure handling.
|
|
123
|
+
*/
|
|
124
|
+
private publishAttention;
|
|
125
|
+
/** Records that an attention could not be published yet (scope control unconfirmed). */
|
|
126
|
+
private deferAttention;
|
|
127
|
+
/**
|
|
128
|
+
* Returns the watch's relay scope, creating it on first use (expectedRevision=0 ->
|
|
129
|
+
* nextRevision=1, design 9.6). Unconfirmed control ops for the watch are drained first;
|
|
130
|
+
* if any remain open, or the scope is not active, publishing is blocked (design 7.7).
|
|
131
|
+
* scopeId = scope-<watchId>-g<generation>-e<bindingEpoch>: a generation or owner-binding
|
|
132
|
+
* change yields a new scope, and the old one is never reused.
|
|
133
|
+
*/
|
|
134
|
+
private ensureRelayScope;
|
|
135
|
+
/**
|
|
136
|
+
* Drains the durable control outbox (design 7.3 T6 / 7.7): scope advances FIFO per watch,
|
|
137
|
+
* then pending event withdraws. Each op is retried under its original operationId; the
|
|
138
|
+
* relay dedupes by operationId + request digest. Deterministic relay refusals are recorded
|
|
139
|
+
* as rejected (no retry); anything else stays unknown and is retried on the next sweep.
|
|
140
|
+
*/
|
|
141
|
+
drainControl(watchId?: string): Promise<void>;
|
|
142
|
+
/**
|
|
143
|
+
* Delivery health: for attentions that are unknown (publish failed)
|
|
144
|
+
* or deferred (scope control unconfirmed) while the episode is still open, each sweep
|
|
145
|
+
* (a) retries once if the envelope is still valid, re-sending the same (event, options);
|
|
146
|
+
* (b) otherwise only reports loudly (the host must inspect).
|
|
147
|
+
* Withdrawn events are never re-published; an event whose recorded scope has since
|
|
148
|
+
* advanced is fenced and marked rejected instead of being re-sent under a new scope.
|
|
149
|
+
*/
|
|
150
|
+
private checkDeliveryHealth;
|
|
151
|
+
/** Terminal-state watch auto-close: supersede open episodes -> superseded, lifecycle -> closed (does not touch controlRevision CAS semantics). */
|
|
152
|
+
private autoCloseTerminal;
|
|
153
|
+
private degrade;
|
|
154
|
+
/**
|
|
155
|
+
* Delivery guard: there is a wake the host never confirmed -- episode still open and its
|
|
156
|
+
* attention admission is in {unknown, pending, publishing} (publish unconfirmed) or =source-staged
|
|
157
|
+
* and the envelope has not expired (relay delivery in flight) -> returns true, blocking ttlElapsed auto-close.
|
|
158
|
+
*/
|
|
159
|
+
private hasUndeliveredWake;
|
|
160
|
+
/** slot = (watchId, generation, kind, checkpointId); at most one active episode per slot (design 3.3). */
|
|
161
|
+
private openEpisode;
|
|
162
|
+
private ensureMonitorEpisode;
|
|
163
|
+
/** Result card: truth = durable outbox (I6: event bytes/ID/expiry frozen); the display copy is persisted separately (I16). */
|
|
164
|
+
private commitResultCard;
|
|
165
|
+
/** probes delegation (trusted candidates, design 4.4) */
|
|
166
|
+
listProbes(watchId: string): Promise<readonly Probe[]>;
|
|
167
|
+
executeProbe(watchId: string, probeId: string, signal?: AbortSignal): Promise<Observation[]>;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Projects one identity-checked observation onto the snapshot. Shared by ingest and probe
|
|
171
|
+
* ingestion so both paths derive the same state from the same evidence. activityAtMs is set
|
|
172
|
+
* when the observation counts as task activity (status/heartbeat/log_delta) for the silence
|
|
173
|
+
* rule; validation/artifact observations do not.
|
|
174
|
+
*/
|
|
175
|
+
export declare function applyObservationToSnapshot(snapshot: WatchSnapshot, obs: Observation, now: number): {
|
|
176
|
+
snapshot: WatchSnapshot;
|
|
177
|
+
activityAtMs: number | null;
|
|
178
|
+
};
|