@deepwatch/dsh-contracts 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/LICENSE +21 -0
- package/README.md +77 -0
- package/lib/approval.d.ts +114 -0
- package/lib/approval.js +108 -0
- package/lib/bindings.d.ts +248 -0
- package/lib/bindings.js +333 -0
- package/lib/digests.d.ts +77 -0
- package/lib/digests.js +103 -0
- package/lib/execution.d.ts +259 -0
- package/lib/execution.js +213 -0
- package/lib/failures.d.ts +145 -0
- package/lib/failures.js +204 -0
- package/lib/identity.d.ts +54 -0
- package/lib/identity.js +74 -0
- package/lib/index.d.ts +382 -0
- package/lib/index.js +79 -0
- package/lib/language.d.ts +158 -0
- package/lib/language.js +202 -0
- package/lib/paths.d.ts +194 -0
- package/lib/paths.js +286 -0
- package/lib/presentation.d.ts +90 -0
- package/lib/presentation.js +158 -0
- package/lib/query/validate.d.ts +74 -0
- package/lib/query/validate.js +243 -0
- package/lib/query/wire.d.ts +409 -0
- package/lib/query/wire.js +37 -0
- package/lib/query.d.ts +362 -0
- package/lib/query.js +431 -0
- package/lib/readiness.d.ts +198 -0
- package/lib/readiness.js +209 -0
- package/lib/workspace.d.ts +141 -0
- package/lib/workspace.js +158 -0
- package/package.json +60 -0
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Watch Bridge wire contracts.
|
|
3
|
+
*
|
|
4
|
+
* Watch Core's Pydantic models are the semantic source of truth (ADR-004).
|
|
5
|
+
* CI in `watch-skill` emits JSON Schema 2020-12 with a version and digest, and
|
|
6
|
+
* the types below are the TypeScript face of that schema. Until the generator
|
|
7
|
+
* lands, these are maintained by hand against the same contract and the
|
|
8
|
+
* handshake carries `schemaDigest` so a drift is a negotiated, visible failure
|
|
9
|
+
* rather than a runtime surprise.
|
|
10
|
+
*
|
|
11
|
+
* This package is browser-safe on purpose: no Node imports, no runtime
|
|
12
|
+
* identity to share (no Symbol, no instanceof, no singleton state), so a
|
|
13
|
+
* client bundle can inline it without duplicating a shared instance.
|
|
14
|
+
*
|
|
15
|
+
* @module @deepwatch/dsh-contracts
|
|
16
|
+
*/
|
|
17
|
+
/** The Bridge protocol version this build of the Workspace speaks. */
|
|
18
|
+
export declare const WATCH_PROTOCOL_VERSION = 1;
|
|
19
|
+
/** The protocol range this build can negotiate down to. */
|
|
20
|
+
export declare const WATCH_PROTOCOL_MIN = 1;
|
|
21
|
+
/**
|
|
22
|
+
* How much is actually known about a capability.
|
|
23
|
+
*
|
|
24
|
+
* The distinction is the point: a package existing on disk, a model appearing
|
|
25
|
+
* in a catalog, and a real request succeeding are three different facts, and
|
|
26
|
+
* the UI is never allowed to render the first as if it were the third.
|
|
27
|
+
*/
|
|
28
|
+
export type CapabilityStatus =
|
|
29
|
+
/** Code exists and is wired, but nothing has been executed against it. */
|
|
30
|
+
'implemented'
|
|
31
|
+
/** A real request ran on this machine and succeeded. */
|
|
32
|
+
| 'machine_tested'
|
|
33
|
+
/** A cheap probe (version query, binary present, endpoint reachable) passed. */
|
|
34
|
+
| 'probed'
|
|
35
|
+
/** Known to be unusable here, with a reason. */
|
|
36
|
+
| 'unavailable'
|
|
37
|
+
/** Never checked. Not the same as unavailable. */
|
|
38
|
+
| 'not_tested';
|
|
39
|
+
/** One capability's truth, as reported by Watch Core's doctor. */
|
|
40
|
+
export interface CapabilityTruth {
|
|
41
|
+
readonly capabilityId: string;
|
|
42
|
+
/** Owning plugin or engine, and its version when one is known. */
|
|
43
|
+
readonly provider: string | null;
|
|
44
|
+
readonly providerVersion: string | null;
|
|
45
|
+
readonly status: CapabilityStatus;
|
|
46
|
+
/** What the capability needs, and what was actually detected. */
|
|
47
|
+
readonly requirements: readonly string[];
|
|
48
|
+
readonly detected: Readonly<Record<string, string>>;
|
|
49
|
+
readonly missing: readonly string[];
|
|
50
|
+
/** Concrete next steps. Never a bare "setup failed". */
|
|
51
|
+
readonly fixes: readonly string[];
|
|
52
|
+
/** ISO-8601. Null when the capability has never been checked. */
|
|
53
|
+
readonly lastCheckedAt: string | null;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* What Watch Core returns when the Bridge connects.
|
|
57
|
+
*
|
|
58
|
+
* A protocol mismatch disables only the affected Watch features. The rest of
|
|
59
|
+
* the Workspace stays openable in degraded or review mode, and the reported
|
|
60
|
+
* versions are what the UI shows instead of a generic failure.
|
|
61
|
+
*/
|
|
62
|
+
export interface HandshakeResult {
|
|
63
|
+
readonly coreVersion: string;
|
|
64
|
+
readonly coreBuild: string | null;
|
|
65
|
+
/** The version both sides agreed on, within [WATCH_PROTOCOL_MIN, requested]. */
|
|
66
|
+
readonly protocolVersion: number;
|
|
67
|
+
readonly capabilities: readonly CapabilityTruth[];
|
|
68
|
+
/** Digest per contract family, so schema drift is detectable at connect time. */
|
|
69
|
+
readonly schemaDigests: Readonly<Record<string, string>>;
|
|
70
|
+
readonly policy: PolicySummary;
|
|
71
|
+
readonly limits: BridgeLimits;
|
|
72
|
+
}
|
|
73
|
+
/** The policy Watch Core is enforcing, surfaced so the UI never misstates it. */
|
|
74
|
+
export interface PolicySummary {
|
|
75
|
+
/** When true, no non-loopback egress is permitted from any role. */
|
|
76
|
+
readonly offlineOnly: boolean;
|
|
77
|
+
/** Cloud perception is a separate consent from holding a provider API key. */
|
|
78
|
+
readonly cloudPerceptionOptIn: boolean;
|
|
79
|
+
/** Durable personal memory mode chosen by the user. */
|
|
80
|
+
readonly memoryMode: MemoryMode;
|
|
81
|
+
/** Retention class defaults applied to newly captured artifacts. */
|
|
82
|
+
readonly defaultRetentionClass: string;
|
|
83
|
+
}
|
|
84
|
+
/** Durable memory modes a profile can be in (ADR-006). */
|
|
85
|
+
export type MemoryMode = 'off' | 'session_only' | 'local_personal' | 'workspace_shared';
|
|
86
|
+
/** Transport limits the client must respect. */
|
|
87
|
+
export interface BridgeLimits {
|
|
88
|
+
readonly maxRequestBytes: number;
|
|
89
|
+
readonly maxInFlight: number;
|
|
90
|
+
/** Milliseconds. A request without its own deadline inherits this one. */
|
|
91
|
+
readonly defaultDeadlineMs: number;
|
|
92
|
+
}
|
|
93
|
+
/** Connection state of the Bridge, as the Workspace understands it. */
|
|
94
|
+
export type BridgePhase = 'disconnected' | 'connecting' | 'ready'
|
|
95
|
+
/** Connected, but the negotiated protocol excludes some requested features. */
|
|
96
|
+
| 'degraded' | 'failed';
|
|
97
|
+
/**
|
|
98
|
+
* Why Watch Core is not usable, in one word a screen can act on.
|
|
99
|
+
*
|
|
100
|
+
* The taxonomy exists because "disconnected" is not an answer anybody can do
|
|
101
|
+
* anything with. Each of these implies a different next step, and telling them
|
|
102
|
+
* apart is the difference between "install Watch Core" and "your Workspace and
|
|
103
|
+
* your engine are different versions".
|
|
104
|
+
*
|
|
105
|
+
* `connected` is in the same union deliberately: a health object always
|
|
106
|
+
* carries a blocker, so no screen has to infer readiness from the absence of
|
|
107
|
+
* a field.
|
|
108
|
+
*/
|
|
109
|
+
export type BridgeBlocker =
|
|
110
|
+
/** Handshake succeeded and the contract matched. Nothing is blocked. */
|
|
111
|
+
'connected'
|
|
112
|
+
/** The configured executable is not on this machine. */
|
|
113
|
+
| 'core_missing'
|
|
114
|
+
/** The executable exists but has no `bridge` command. */
|
|
115
|
+
| 'bridge_surface_missing'
|
|
116
|
+
/** The process started and the handshake did not complete. */
|
|
117
|
+
| 'handshake_failed'
|
|
118
|
+
/** Both sides ran, and cannot speak the same protocol version. */
|
|
119
|
+
| 'protocol_mismatch'
|
|
120
|
+
/** Protocol matched; one or more contract families did not. */
|
|
121
|
+
| 'contract_mismatch'
|
|
122
|
+
/** The process died after connecting. */
|
|
123
|
+
| 'core_crashed'
|
|
124
|
+
/** The process is alive and did not answer in time. */
|
|
125
|
+
| 'core_timeout'
|
|
126
|
+
/** The breaker is open after repeated failures. */
|
|
127
|
+
| 'circuit_open'
|
|
128
|
+
/** A test or fixture explicitly selected the mock backend. */
|
|
129
|
+
| 'test_only_mock';
|
|
130
|
+
/** The health projection the browser half renders. */
|
|
131
|
+
export interface WatchCoreHealth {
|
|
132
|
+
readonly phase: BridgePhase;
|
|
133
|
+
/** Which transport is in use, so the UI never guesses. */
|
|
134
|
+
readonly transport: 'stdio' | 'https' | 'mock' | null;
|
|
135
|
+
readonly handshake: HandshakeResult | null;
|
|
136
|
+
/** Populated when phase is 'failed' or 'degraded'. */
|
|
137
|
+
readonly error: WatchError | null;
|
|
138
|
+
/**
|
|
139
|
+
* Why the product is in this state, whatever the phase says.
|
|
140
|
+
*
|
|
141
|
+
* Carried separately from `error` because a screen needs to branch on it,
|
|
142
|
+
* and branching on a message string is how a UI comes to depend on prose.
|
|
143
|
+
*/
|
|
144
|
+
readonly blocker: BridgeBlocker;
|
|
145
|
+
/**
|
|
146
|
+
* True only when the backend is the in-process mock.
|
|
147
|
+
*
|
|
148
|
+
* Every surface that could present data as observed reads this first. It is
|
|
149
|
+
* a separate field rather than `transport === 'mock'` so that adding a
|
|
150
|
+
* second fake backend cannot quietly bypass the check.
|
|
151
|
+
*/
|
|
152
|
+
readonly isTestOnlyMock: boolean;
|
|
153
|
+
/** ISO-8601 of the last successful handshake, null if there has never been one. */
|
|
154
|
+
readonly lastHandshakeAt: string | null;
|
|
155
|
+
/** How many times the Bridge has started a Core process this session. */
|
|
156
|
+
readonly restartCount: number;
|
|
157
|
+
/** ISO-8601 of the last state change. */
|
|
158
|
+
readonly changedAt: string;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* The structured error contract shared with Watch Core.
|
|
162
|
+
*
|
|
163
|
+
* `fix` is not optional prose: a failure the user cannot act on is a failure
|
|
164
|
+
* the product has not finished reporting.
|
|
165
|
+
*/
|
|
166
|
+
export interface WatchError {
|
|
167
|
+
/** Dotted, stable, machine-readable. For example `live.cursor_expired`. */
|
|
168
|
+
readonly error: string;
|
|
169
|
+
readonly message: string;
|
|
170
|
+
readonly fix: string;
|
|
171
|
+
readonly details: Readonly<Record<string, unknown>>;
|
|
172
|
+
readonly retryable: boolean;
|
|
173
|
+
readonly correlationId: string | null;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* The failure arm of {@link WatchResult}.
|
|
177
|
+
*
|
|
178
|
+
* Named separately so a helper that only ever fails can say so in its return
|
|
179
|
+
* type, and callers can read `.error` without narrowing a union first.
|
|
180
|
+
*/
|
|
181
|
+
export interface WatchFailure {
|
|
182
|
+
readonly ok: false;
|
|
183
|
+
readonly error: WatchError;
|
|
184
|
+
}
|
|
185
|
+
/** Result envelope used across the Bridge; mirrors the DSH Remote convention. */
|
|
186
|
+
export type WatchResult<T> = {
|
|
187
|
+
readonly ok: true;
|
|
188
|
+
readonly value: T;
|
|
189
|
+
} | WatchFailure;
|
|
190
|
+
/** How a piece of evidence came to exist. Inference is never an observation. */
|
|
191
|
+
export type EvidenceProvenance = 'observation' | 'deterministic_derivation' | 'inference';
|
|
192
|
+
/** A half-open time range on a source's own clock, in milliseconds. */
|
|
193
|
+
export interface TemporalRange {
|
|
194
|
+
readonly startMs: number;
|
|
195
|
+
readonly endMs: number;
|
|
196
|
+
}
|
|
197
|
+
/** A rectangle in a frame's coordinate space. */
|
|
198
|
+
export interface SpatialRegion {
|
|
199
|
+
readonly x: number;
|
|
200
|
+
readonly y: number;
|
|
201
|
+
readonly width: number;
|
|
202
|
+
readonly height: number;
|
|
203
|
+
}
|
|
204
|
+
/** Whether an observation still describes the current state of its source. */
|
|
205
|
+
export type Freshness = 'current' | 'stale' | 'gap' | 'expired' | 'unavailable';
|
|
206
|
+
/**
|
|
207
|
+
* The minimum an evidence record carries.
|
|
208
|
+
*
|
|
209
|
+
* Minted by Watch Core only (ADR-002). A plugin submits a candidate; it never
|
|
210
|
+
* constructs one of these as fact. `confidence` is deliberately allowed to be
|
|
211
|
+
* null: a producer with no calibrated confidence must not invent one.
|
|
212
|
+
*/
|
|
213
|
+
export interface EvidenceRecord {
|
|
214
|
+
readonly evidenceId: string;
|
|
215
|
+
readonly sourceRevisionId: string;
|
|
216
|
+
readonly artifactIds: readonly string[];
|
|
217
|
+
readonly temporalRange: TemporalRange | null;
|
|
218
|
+
readonly spatialRegion: SpatialRegion | null;
|
|
219
|
+
readonly modality: 'visual' | 'text' | 'audio' | 'dom' | 'network' | 'filesystem';
|
|
220
|
+
readonly provenance: EvidenceProvenance;
|
|
221
|
+
readonly producer: string;
|
|
222
|
+
readonly producerVersion: string;
|
|
223
|
+
readonly captureQuality: string | null;
|
|
224
|
+
readonly gaps: readonly TemporalRange[];
|
|
225
|
+
readonly freshness: Freshness;
|
|
226
|
+
readonly contentDigest: string;
|
|
227
|
+
readonly retentionClass: string;
|
|
228
|
+
readonly confidence: number | null;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* The verdict taxonomy.
|
|
232
|
+
*
|
|
233
|
+
* `VERIFIED` is not a synonym for "the agent finished". Confidence never
|
|
234
|
+
* promotes `UNVERIFIED` to `VERIFIED`, at any value.
|
|
235
|
+
*/
|
|
236
|
+
export type Verdict =
|
|
237
|
+
/** An executable expectation passed against valid evidence. */
|
|
238
|
+
'VERIFIED'
|
|
239
|
+
/** A required check failed. */
|
|
240
|
+
| 'FAILED'
|
|
241
|
+
/** No executable expectation, or not enough evidence to decide. */
|
|
242
|
+
| 'UNVERIFIED'
|
|
243
|
+
/** Evidence conflicts, or its quality is insufficient. */
|
|
244
|
+
| 'INCONCLUSIVE'
|
|
245
|
+
/** The evidence no longer describes the current source revision. */
|
|
246
|
+
| 'STALE'
|
|
247
|
+
/** Policy, permission or a missing dependency prevented verification. */
|
|
248
|
+
| 'BLOCKED';
|
|
249
|
+
/** Agent execution state — deliberately separate from evidence and verdict. */
|
|
250
|
+
export type AgentExecutionState = 'queued' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
251
|
+
/** One check inside a verification contract. */
|
|
252
|
+
export interface VerificationCheck {
|
|
253
|
+
readonly checkId: string;
|
|
254
|
+
readonly kind: string;
|
|
255
|
+
readonly description: string;
|
|
256
|
+
readonly passed: boolean | null;
|
|
257
|
+
readonly evidenceRefs: readonly string[];
|
|
258
|
+
readonly detail: string | null;
|
|
259
|
+
}
|
|
260
|
+
/** The outcome of running a verification contract. */
|
|
261
|
+
export interface VerificationOutcome {
|
|
262
|
+
readonly verificationId: string;
|
|
263
|
+
readonly verdict: Verdict;
|
|
264
|
+
/** Why the verdict is what it is, in one sentence the UI can show verbatim. */
|
|
265
|
+
readonly reason: string;
|
|
266
|
+
readonly checks: readonly VerificationCheck[];
|
|
267
|
+
readonly contractDigest: string;
|
|
268
|
+
readonly evaluatedAt: string;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* The receipt for one side-effecting action.
|
|
272
|
+
*
|
|
273
|
+
* A successful dispatch is not a successful effect. The receipt is what makes
|
|
274
|
+
* that distinction inspectable after the fact.
|
|
275
|
+
*/
|
|
276
|
+
export interface ActionReceipt {
|
|
277
|
+
readonly receiptId: string;
|
|
278
|
+
readonly operationId: string;
|
|
279
|
+
readonly idempotencyKey: string;
|
|
280
|
+
readonly inputDigest: string;
|
|
281
|
+
readonly approvalId: string | null;
|
|
282
|
+
readonly preObservationEvidenceIds: readonly string[];
|
|
283
|
+
readonly postObservationEvidenceIds: readonly string[];
|
|
284
|
+
/** Every candidate the resolver considered, so ambiguity is auditable. */
|
|
285
|
+
readonly targetCandidates: readonly string[];
|
|
286
|
+
readonly resolvedTarget: string | null;
|
|
287
|
+
/** Populated when the action was refused rather than dispatched. */
|
|
288
|
+
readonly ambiguityReason: string | null;
|
|
289
|
+
readonly verification: VerificationOutcome | null;
|
|
290
|
+
readonly retries: number;
|
|
291
|
+
readonly terminalState: 'dispatched' | 'refused' | 'cancel_requested' | 'unknown';
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* The one selection every surface responds to.
|
|
295
|
+
*
|
|
296
|
+
* A tool card, a citation, the player, the timeline, Trajectory and the
|
|
297
|
+
* inspector are projections of this single value, which is also what a deep
|
|
298
|
+
* link serializes. There is no separate "media timeline" truth.
|
|
299
|
+
*/
|
|
300
|
+
export interface WatchSelection {
|
|
301
|
+
readonly workspaceId: string;
|
|
302
|
+
readonly sessionId: string;
|
|
303
|
+
readonly runId: string | null;
|
|
304
|
+
readonly eventId: string | null;
|
|
305
|
+
readonly evidenceId: string | null;
|
|
306
|
+
readonly temporalRange: TemporalRange | null;
|
|
307
|
+
readonly artifactId: string | null;
|
|
308
|
+
readonly inspectorTab: string | null;
|
|
309
|
+
/** Which surface initiated the change, so a surface can skip echoing itself. */
|
|
310
|
+
readonly origin: string;
|
|
311
|
+
/** Whether this selection is being replayed rather than followed live. */
|
|
312
|
+
readonly historyMode: boolean;
|
|
313
|
+
}
|
|
314
|
+
/** A JSON-RPC 2.0 request as the Bridge sends it. */
|
|
315
|
+
export interface JsonRpcRequest {
|
|
316
|
+
readonly jsonrpc: '2.0';
|
|
317
|
+
readonly id: number | string;
|
|
318
|
+
readonly method: string;
|
|
319
|
+
readonly params?: unknown;
|
|
320
|
+
}
|
|
321
|
+
/** A JSON-RPC 2.0 notification (no response expected). */
|
|
322
|
+
export interface JsonRpcNotification {
|
|
323
|
+
readonly jsonrpc: '2.0';
|
|
324
|
+
readonly method: string;
|
|
325
|
+
readonly params?: unknown;
|
|
326
|
+
}
|
|
327
|
+
/** A JSON-RPC 2.0 response as Watch Core returns it. */
|
|
328
|
+
export interface JsonRpcResponse {
|
|
329
|
+
readonly jsonrpc: '2.0';
|
|
330
|
+
readonly id: number | string | null;
|
|
331
|
+
readonly result?: unknown;
|
|
332
|
+
readonly error?: {
|
|
333
|
+
readonly code: number;
|
|
334
|
+
readonly message: string;
|
|
335
|
+
readonly data?: unknown;
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* JSON-RPC error codes the Bridge assigns meaning to.
|
|
340
|
+
*
|
|
341
|
+
* The reserved range is JSON-RPC's own; the Watch range starts at -32000 and
|
|
342
|
+
* is what carries a {@link WatchError} in `data`.
|
|
343
|
+
*/
|
|
344
|
+
export declare const JSON_RPC: {
|
|
345
|
+
readonly PARSE_ERROR: -32700;
|
|
346
|
+
readonly INVALID_REQUEST: -32600;
|
|
347
|
+
readonly METHOD_NOT_FOUND: -32601;
|
|
348
|
+
readonly INVALID_PARAMS: -32602;
|
|
349
|
+
readonly INTERNAL_ERROR: -32603;
|
|
350
|
+
/** Application error: `data` is a {@link WatchError}. */
|
|
351
|
+
readonly WATCH_ERROR: -32000;
|
|
352
|
+
};
|
|
353
|
+
/** Construct a well-formed error result without repeating the envelope shape. */
|
|
354
|
+
export declare function watchError(error: string, message: string, fix: string, options?: {
|
|
355
|
+
readonly details?: Readonly<Record<string, unknown>>;
|
|
356
|
+
readonly retryable?: boolean;
|
|
357
|
+
readonly correlationId?: string | null;
|
|
358
|
+
}): WatchFailure;
|
|
359
|
+
/**
|
|
360
|
+
* Whether a verdict may be rendered with the success affordance.
|
|
361
|
+
*
|
|
362
|
+
* Kept here rather than in each surface so no renderer can quietly widen it.
|
|
363
|
+
* `INCONCLUSIVE`, `STALE` and `UNVERIFIED` are honest outcomes, not degrees of
|
|
364
|
+
* success, and never turn green.
|
|
365
|
+
*/
|
|
366
|
+
export declare function isSuccessVerdict(verdict: Verdict): boolean;
|
|
367
|
+
/**
|
|
368
|
+
* Negotiate a protocol version against what the peer offers.
|
|
369
|
+
* @returns the agreed version, or null when the ranges do not overlap.
|
|
370
|
+
*/
|
|
371
|
+
export declare function negotiateProtocol(peerMin: number, peerMax: number): number | null;
|
|
372
|
+
export * from './presentation.js';
|
|
373
|
+
export * from './digests.js';
|
|
374
|
+
export * from './language.js';
|
|
375
|
+
export * from './approval.js';
|
|
376
|
+
export * from './readiness.js';
|
|
377
|
+
export * from './bindings.js';
|
|
378
|
+
export * from './failures.js';
|
|
379
|
+
export * from './paths.js';
|
|
380
|
+
export * from './execution.js';
|
|
381
|
+
export * from './workspace.js';
|
|
382
|
+
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Watch Bridge wire contracts.
|
|
3
|
+
*
|
|
4
|
+
* Watch Core's Pydantic models are the semantic source of truth (ADR-004).
|
|
5
|
+
* CI in `watch-skill` emits JSON Schema 2020-12 with a version and digest, and
|
|
6
|
+
* the types below are the TypeScript face of that schema. Until the generator
|
|
7
|
+
* lands, these are maintained by hand against the same contract and the
|
|
8
|
+
* handshake carries `schemaDigest` so a drift is a negotiated, visible failure
|
|
9
|
+
* rather than a runtime surprise.
|
|
10
|
+
*
|
|
11
|
+
* This package is browser-safe on purpose: no Node imports, no runtime
|
|
12
|
+
* identity to share (no Symbol, no instanceof, no singleton state), so a
|
|
13
|
+
* client bundle can inline it without duplicating a shared instance.
|
|
14
|
+
*
|
|
15
|
+
* @module @deepwatch/dsh-contracts
|
|
16
|
+
*/
|
|
17
|
+
/** The Bridge protocol version this build of the Workspace speaks. */
|
|
18
|
+
export const WATCH_PROTOCOL_VERSION = 1;
|
|
19
|
+
/** The protocol range this build can negotiate down to. */
|
|
20
|
+
export const WATCH_PROTOCOL_MIN = 1;
|
|
21
|
+
/**
|
|
22
|
+
* JSON-RPC error codes the Bridge assigns meaning to.
|
|
23
|
+
*
|
|
24
|
+
* The reserved range is JSON-RPC's own; the Watch range starts at -32000 and
|
|
25
|
+
* is what carries a {@link WatchError} in `data`.
|
|
26
|
+
*/
|
|
27
|
+
export const JSON_RPC = {
|
|
28
|
+
PARSE_ERROR: -32700,
|
|
29
|
+
INVALID_REQUEST: -32600,
|
|
30
|
+
METHOD_NOT_FOUND: -32601,
|
|
31
|
+
INVALID_PARAMS: -32602,
|
|
32
|
+
INTERNAL_ERROR: -32603,
|
|
33
|
+
/** Application error: `data` is a {@link WatchError}. */
|
|
34
|
+
WATCH_ERROR: -32000,
|
|
35
|
+
};
|
|
36
|
+
// ── helpers ─────────────────────────────────────────────────────────────────
|
|
37
|
+
/** Construct a well-formed error result without repeating the envelope shape. */
|
|
38
|
+
export function watchError(error, message, fix, options = {}) {
|
|
39
|
+
return {
|
|
40
|
+
ok: false,
|
|
41
|
+
error: {
|
|
42
|
+
error,
|
|
43
|
+
message,
|
|
44
|
+
fix,
|
|
45
|
+
details: options.details ?? {},
|
|
46
|
+
retryable: options.retryable ?? false,
|
|
47
|
+
correlationId: options.correlationId ?? null,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Whether a verdict may be rendered with the success affordance.
|
|
53
|
+
*
|
|
54
|
+
* Kept here rather than in each surface so no renderer can quietly widen it.
|
|
55
|
+
* `INCONCLUSIVE`, `STALE` and `UNVERIFIED` are honest outcomes, not degrees of
|
|
56
|
+
* success, and never turn green.
|
|
57
|
+
*/
|
|
58
|
+
export function isSuccessVerdict(verdict) {
|
|
59
|
+
return verdict === 'VERIFIED';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Negotiate a protocol version against what the peer offers.
|
|
63
|
+
* @returns the agreed version, or null when the ranges do not overlap.
|
|
64
|
+
*/
|
|
65
|
+
export function negotiateProtocol(peerMin, peerMax) {
|
|
66
|
+
const agreed = Math.min(peerMax, WATCH_PROTOCOL_VERSION);
|
|
67
|
+
return agreed >= Math.max(peerMin, WATCH_PROTOCOL_MIN) ? agreed : null;
|
|
68
|
+
}
|
|
69
|
+
export * from './presentation.js';
|
|
70
|
+
export * from './digests.js';
|
|
71
|
+
export * from './language.js';
|
|
72
|
+
export * from './approval.js';
|
|
73
|
+
export * from './readiness.js';
|
|
74
|
+
export * from './bindings.js';
|
|
75
|
+
export * from './failures.js';
|
|
76
|
+
export * from './paths.js';
|
|
77
|
+
export * from './execution.js';
|
|
78
|
+
export * from './workspace.js';
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Language-aware evidence.
|
|
3
|
+
*
|
|
4
|
+
* The correction this module encodes (spec §37): Watch is not an English
|
|
5
|
+
* product with translations bolted on, and it is not an Arabic one either. It
|
|
6
|
+
* is language-independent architecture with a *measured* support matrix — and
|
|
7
|
+
* the two claims are very different. "Handles Unicode" is architecture.
|
|
8
|
+
* "Reads Thai subtitles well" is a measurement, and it belongs to a
|
|
9
|
+
* qualification result rather than to a type.
|
|
10
|
+
*
|
|
11
|
+
* Five things are kept separate that products routinely conflate:
|
|
12
|
+
*
|
|
13
|
+
* ```
|
|
14
|
+
* UI locale what the interface is in
|
|
15
|
+
* source language(s) what the material is in
|
|
16
|
+
* script(s) what alphabet it is written in
|
|
17
|
+
* response language what the agent answers in
|
|
18
|
+
* translation target an optional derived view
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* Changing the interface language must not translate evidence. A source can
|
|
22
|
+
* contain several languages in one frame. And a translation is *derived data
|
|
23
|
+
* with its own provenance* — the original text stays the evidence, because a
|
|
24
|
+
* citation that resolved to a translation would be citing something no one
|
|
25
|
+
* ever said.
|
|
26
|
+
*
|
|
27
|
+
* @module @deepwatch/dsh-contracts/language
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* Which way a span reads.
|
|
31
|
+
*
|
|
32
|
+
* Per span, not per page. One frame can hold an Arabic sentence with a Latin
|
|
33
|
+
* product name and a timestamp inside it, and a page-level direction would get
|
|
34
|
+
* two of those three wrong.
|
|
35
|
+
*/
|
|
36
|
+
export type TextDirection = 'ltr' | 'rtl' | 'mixed' | 'unknown';
|
|
37
|
+
/** Unicode script identity, as the OCR and ASR contracts report it. */
|
|
38
|
+
export type ScriptTag = 'Latin' | 'Arabic' | 'Hebrew' | 'Cyrillic' | 'Greek' | 'Han' | 'Hiragana' | 'Katakana' | 'Hangul' | 'Devanagari' | 'Thai' | 'Lao' | 'Khmer' | 'Myanmar' | 'Tibetan' | 'Unknown';
|
|
39
|
+
/**
|
|
40
|
+
* Detect the scripts present in a string.
|
|
41
|
+
*
|
|
42
|
+
* Range-based rather than library-based on purpose: this runs on the browser
|
|
43
|
+
* side of an evidence panel, and pulling a full ICU table into a bundle to
|
|
44
|
+
* answer "is there Arabic in here" is not a trade worth making. It is
|
|
45
|
+
* deliberately coarse — it reports which scripts appear, which is what
|
|
46
|
+
* direction and routing need, not a language identification.
|
|
47
|
+
*/
|
|
48
|
+
export declare function detectScripts(text: string): readonly ScriptTag[];
|
|
49
|
+
/**
|
|
50
|
+
* Which way a string reads.
|
|
51
|
+
*
|
|
52
|
+
* `mixed` is a real answer, not a failure to decide. A layout that renders
|
|
53
|
+
* mixed content as though it were uniformly one direction produces text that
|
|
54
|
+
* is technically present and unreadable.
|
|
55
|
+
*/
|
|
56
|
+
export declare function detectDirection(text: string): TextDirection;
|
|
57
|
+
/**
|
|
58
|
+
* A translation of an evidence span.
|
|
59
|
+
*
|
|
60
|
+
* Derived data with its own provenance, deliberately shaped so it can never be
|
|
61
|
+
* mistaken for the original: it names the engine that produced it and carries
|
|
62
|
+
* no evidence id of its own.
|
|
63
|
+
*/
|
|
64
|
+
export interface DerivedTranslation {
|
|
65
|
+
readonly targetLanguage: string;
|
|
66
|
+
readonly text: string;
|
|
67
|
+
readonly engine: string;
|
|
68
|
+
readonly engineVersion: string;
|
|
69
|
+
readonly translatedAt: string;
|
|
70
|
+
/** Null unless the engine produces a calibrated score. */
|
|
71
|
+
readonly confidence: number | null;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The language-aware text of one piece of evidence.
|
|
75
|
+
*
|
|
76
|
+
* `originalText` is the evidence. Everything else is a view of it.
|
|
77
|
+
*/
|
|
78
|
+
export interface LanguageAwareText {
|
|
79
|
+
/**
|
|
80
|
+
* Exactly what was observed, byte for byte.
|
|
81
|
+
*
|
|
82
|
+
* The evidence authority. Never normalized in place, never replaced by a
|
|
83
|
+
* translation, and what a citation resolves to.
|
|
84
|
+
*/
|
|
85
|
+
readonly originalText: string;
|
|
86
|
+
/**
|
|
87
|
+
* A folded form for retrieval only.
|
|
88
|
+
*
|
|
89
|
+
* Case-folded, diacritic-stripped, width-normalized — whatever the index
|
|
90
|
+
* needs to match a query someone typed differently from how it appears.
|
|
91
|
+
* Never displayed, never cited, and never the thing a verdict is about.
|
|
92
|
+
*/
|
|
93
|
+
readonly normalizedText: string | null;
|
|
94
|
+
/** BCP-47 tags where known. Empty rather than guessed. */
|
|
95
|
+
readonly languageTags: readonly string[];
|
|
96
|
+
readonly scripts: readonly ScriptTag[];
|
|
97
|
+
readonly direction: TextDirection;
|
|
98
|
+
/** Null unless the detector is calibrated. */
|
|
99
|
+
readonly languageConfidence: number | null;
|
|
100
|
+
readonly producer: string;
|
|
101
|
+
readonly producerVersion: string;
|
|
102
|
+
/** Derived views. A citation never resolves to one of these. */
|
|
103
|
+
readonly translations: readonly DerivedTranslation[];
|
|
104
|
+
readonly qualityWarnings: readonly string[];
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Normalize text for retrieval.
|
|
108
|
+
*
|
|
109
|
+
* NFKC plus case folding plus combining-mark removal: enough that a query
|
|
110
|
+
* typed without diacritics finds text written with them, and that half-width
|
|
111
|
+
* and full-width forms match. Deliberately not stemming or transliteration —
|
|
112
|
+
* those change what a word means, and an index that matched across them would
|
|
113
|
+
* return hits a person cannot see the reason for.
|
|
114
|
+
*/
|
|
115
|
+
export declare function normalizeForRetrieval(text: string): string;
|
|
116
|
+
/**
|
|
117
|
+
* Build the language-aware text for an observed span.
|
|
118
|
+
*
|
|
119
|
+
* The normalized form is computed here rather than accepted from a caller, so
|
|
120
|
+
* every index in the product folds text the same way. Two normalizers that
|
|
121
|
+
* disagree produce a search that finds a result in one surface and not in
|
|
122
|
+
* another, for reasons nobody can see.
|
|
123
|
+
*/
|
|
124
|
+
export declare function describeText(originalText: string, producer: string, producerVersion: string, options?: {
|
|
125
|
+
readonly languageTags?: readonly string[];
|
|
126
|
+
readonly languageConfidence?: number | null;
|
|
127
|
+
readonly qualityWarnings?: readonly string[];
|
|
128
|
+
}): LanguageAwareText;
|
|
129
|
+
/**
|
|
130
|
+
* Attach a translation without disturbing the original.
|
|
131
|
+
*
|
|
132
|
+
* Returns a new value. The original text is unchanged and stays first, because
|
|
133
|
+
* the moment a translation could overwrite it, a citation would resolve to
|
|
134
|
+
* something nobody said.
|
|
135
|
+
*/
|
|
136
|
+
export declare function withTranslation(text: LanguageAwareText, translation: DerivedTranslation): LanguageAwareText;
|
|
137
|
+
/**
|
|
138
|
+
* What a surface should display, given a reader's preference.
|
|
139
|
+
*
|
|
140
|
+
* Returns the original unless a translation for the requested language exists,
|
|
141
|
+
* and always says which it returned. A caller that renders this without
|
|
142
|
+
* showing `isOriginal` is presenting derived text as observed text.
|
|
143
|
+
*/
|
|
144
|
+
export declare function displayText(text: LanguageAwareText, preferredLanguage: string | null): {
|
|
145
|
+
readonly text: string;
|
|
146
|
+
readonly isOriginal: boolean;
|
|
147
|
+
readonly direction: TextDirection;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Whether a span must be isolated from the surrounding text direction.
|
|
151
|
+
*
|
|
152
|
+
* Code, URLs, identifiers and timestamps read left to right inside an
|
|
153
|
+
* otherwise right-to-left paragraph, and without isolation the bidi algorithm
|
|
154
|
+
* reorders them into something that looks plausible and is wrong — a path with
|
|
155
|
+
* its segments reversed, a timestamp reading 30:2.
|
|
156
|
+
*/
|
|
157
|
+
export declare function needsDirectionIsolation(kind: string): boolean;
|
|
158
|
+
//# sourceMappingURL=language.d.ts.map
|