@prismer/runtime 1.9.1 → 1.9.7

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +210 -0
  2. package/README.md +363 -229
  3. package/dist/cli.cjs +10274 -0
  4. package/dist/cli.cjs.map +1 -0
  5. package/dist/cli.js +10262 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/index.cjs +10608 -0
  8. package/dist/index.cjs.map +1 -0
  9. package/dist/index.d.cts +1643 -0
  10. package/dist/index.d.ts +1496 -1916
  11. package/dist/index.js +9707 -9177
  12. package/dist/index.js.map +1 -1
  13. package/package.json +31 -33
  14. package/dist/adapter-registry-EMZFKFYK.mjs +0 -8
  15. package/dist/adapter-registry-EMZFKFYK.mjs.map +0 -1
  16. package/dist/artifacts-uploader-N2HNBSTW.mjs +0 -159
  17. package/dist/artifacts-uploader-N2HNBSTW.mjs.map +0 -1
  18. package/dist/auto-register-M4YSPJS6.mjs +0 -204
  19. package/dist/auto-register-M4YSPJS6.mjs.map +0 -1
  20. package/dist/bin/prismer.js +0 -14988
  21. package/dist/chunk-BJTO5JO5.mjs +0 -11
  22. package/dist/chunk-BJTO5JO5.mjs.map +0 -1
  23. package/dist/chunk-JIEDFDVI.mjs +0 -148
  24. package/dist/chunk-JIEDFDVI.mjs.map +0 -1
  25. package/dist/chunk-NDNX2G6O.mjs +0 -68
  26. package/dist/chunk-NDNX2G6O.mjs.map +0 -1
  27. package/dist/chunk-POWV475F.mjs +0 -45
  28. package/dist/chunk-POWV475F.mjs.map +0 -1
  29. package/dist/chunk-VTFKZAUY.mjs +0 -68
  30. package/dist/chunk-VTFKZAUY.mjs.map +0 -1
  31. package/dist/dispatch-mux-MW4HHICS.mjs +0 -8
  32. package/dist/dispatch-mux-MW4HHICS.mjs.map +0 -1
  33. package/dist/dispatch-rpc-J7H6KC2V.mjs +0 -78
  34. package/dist/dispatch-rpc-J7H6KC2V.mjs.map +0 -1
  35. package/dist/fs-rpc-OSHJZYK6.mjs +0 -58
  36. package/dist/fs-rpc-OSHJZYK6.mjs.map +0 -1
  37. package/dist/heartbeat-loop-H2LAI3V5.mjs +0 -95
  38. package/dist/heartbeat-loop-H2LAI3V5.mjs.map +0 -1
  39. package/dist/index.d.mts +0 -2063
  40. package/dist/index.mjs +0 -8807
  41. package/dist/index.mjs.map +0 -1
  42. package/dist/mode-b-DXJ7FJAL.mjs +0 -152
  43. package/dist/mode-b-DXJ7FJAL.mjs.map +0 -1
  44. package/dist/registry-ZYU2HDFL.mjs +0 -12
  45. package/dist/registry-ZYU2HDFL.mjs.map +0 -1
  46. /package/{dist → assets}/icon +0 -0
  47. /package/{dist → assets}/smallicon +0 -0
package/dist/index.d.mts DELETED
@@ -1,2063 +0,0 @@
1
- import * as http from 'node:http';
2
- import { FsContext } from '@prismer/sandbox-runtime';
3
- import { ParaEvent } from '@prismer/wire';
4
- import { EventEmitter } from 'node:events';
5
-
6
- type DaemonState = 'starting' | 'running' | 'shutting_down' | 'stopped';
7
- interface DaemonOptions {
8
- pidFile?: string;
9
- dataDir?: string;
10
- logFile?: string;
11
- installSignalHandlers?: boolean;
12
- }
13
- interface ShutdownHandler {
14
- name: string;
15
- handler: () => Promise<void> | void;
16
- }
17
- declare class DaemonAlreadyRunningError extends Error {
18
- readonly existingPid: number;
19
- readonly pidFile: string;
20
- constructor(pid: number, pidFile: string);
21
- }
22
- declare class DaemonProcess {
23
- private _state;
24
- private readonly _pidFile;
25
- private readonly _dataDir;
26
- private readonly _logFile;
27
- private readonly _installSignalHandlers;
28
- private readonly _shutdownHandlers;
29
- private readonly _signalHistory;
30
- private _shutdownInProgress;
31
- private _sigTermHandler;
32
- private _sigIntHandler;
33
- private _sigHupHandler;
34
- private _signalReceived;
35
- constructor(opts?: DaemonOptions);
36
- get state(): DaemonState;
37
- get pid(): number;
38
- get pidFile(): string;
39
- get dataDir(): string;
40
- get signalHistory(): ReadonlyArray<{
41
- signal: string;
42
- ts: number;
43
- }>;
44
- start(): Promise<void>;
45
- onShutdown(h: ShutdownHandler): void;
46
- shutdown(signal?: NodeJS.Signals | 'manual'): Promise<void>;
47
- reload(): Promise<void>;
48
- static isRunning(pidFile: string): boolean;
49
- static cleanupStalePidFile(pidFile: string): boolean;
50
- private _atomicPidWrite;
51
- private _recordSignal;
52
- private _readPidFromFile;
53
- }
54
-
55
- interface EventBusEnvelope<T = unknown> {
56
- topic: string;
57
- ts: number;
58
- payload: T;
59
- source?: string;
60
- requestId?: string;
61
- }
62
- /**
63
- * Unified subscription handler that accepts EventBusEnvelope.
64
- * This matches the EventBus API expectation.
65
- */
66
- type SubscriptionHandler<T = unknown> = (ev: EventBusEnvelope<T>) => void | Promise<void>;
67
- interface Subscription {
68
- id: string;
69
- pattern: string;
70
- unsubscribe(): void;
71
- }
72
- interface EventBusOptions {
73
- onSubscriberError?: (err: unknown, sub: Subscription, ev: EventBusEnvelope) => void;
74
- queueWarnThreshold?: number;
75
- }
76
- declare class EventBus {
77
- private readonly _subscribers;
78
- private _monotonicTs;
79
- private _totalPublished;
80
- private readonly _onError;
81
- private readonly _warnThreshold;
82
- constructor(opts?: EventBusOptions);
83
- publish<T>(topic: string, payload: T, meta?: {
84
- source?: string;
85
- requestId?: string;
86
- }): void;
87
- subscribe<T>(topic: string, handler: SubscriptionHandler<T>): Subscription;
88
- unsubscribeAll(): void;
89
- get subscriberCount(): number;
90
- get totalPublished(): number;
91
- private _drain;
92
- }
93
-
94
- type AgentState = 'registered' | 'spawning' | 'running' | 'degraded' | 'crashed' | 'backoff' | 'stopping' | 'stopped' | 'failed';
95
- interface AgentDescriptor {
96
- id: string;
97
- name: string;
98
- command: string;
99
- args?: string[];
100
- cwd?: string;
101
- env?: NodeJS.ProcessEnv;
102
- healthCheck?: () => Promise<boolean> | boolean;
103
- backoff?: {
104
- initialMs?: number;
105
- multiplier?: number;
106
- maxMs?: number;
107
- maxRestarts?: number;
108
- resetAfterMs?: number;
109
- };
110
- attachPid?: number;
111
- }
112
- interface AgentStatus {
113
- id: string;
114
- state: AgentState;
115
- pid?: number;
116
- startedAt?: number;
117
- restarts: number;
118
- lastExitCode?: number;
119
- lastSignal?: NodeJS.Signals | null;
120
- lastHealthError?: string;
121
- nextRestartAt?: number;
122
- }
123
- interface SupervisorOptions {
124
- eventBus: EventBus;
125
- healthProbeIntervalMs?: number;
126
- degradedThreshold?: number;
127
- stopTimeoutMs?: number;
128
- }
129
- declare class AgentSupervisor {
130
- private readonly _bus;
131
- private readonly _probeIntervalMs;
132
- private readonly _degradedThreshold;
133
- private readonly _stopTimeoutMs;
134
- private readonly _agents;
135
- constructor(opts: SupervisorOptions);
136
- register(descriptor: AgentDescriptor): void;
137
- unregister(id: string): Promise<void>;
138
- spawn(id: string): Promise<void>;
139
- stop(id: string, reason?: string): Promise<void>;
140
- restart(id: string): Promise<void>;
141
- attach(id: string, pid: number): Promise<void>;
142
- get(id: string): AgentStatus | undefined;
143
- list(): AgentStatus[];
144
- shutdown(): Promise<void>;
145
- private _doSpawn;
146
- private _handleCrash;
147
- private _scheduleRestart;
148
- private _killOwned;
149
- private _cancelBackoff;
150
- private _startProbe;
151
- private _stopProbe;
152
- private _runProbe;
153
- private _pollAttached;
154
- private _require;
155
- private _publish;
156
- }
157
-
158
- /**
159
- * Prismer Runtime — Adapter Registry (Sprint A3, D4 dispatch mux).
160
- *
161
- * One process-wide registry maps adapter `name` → `AdapterImpl`. The
162
- * registry is the data store; selection policy lives in DispatchMux
163
- * (dispatch-mux.ts) so the same registry can drive multiple selectors
164
- * (capability-based, name-based, weighted load, etc.) without coupling.
165
- *
166
- * An adapter advertises:
167
- * - `name` : stable identifier (matches catalog name).
168
- * - `tiersSupported` : PARA Tier numbers it can host (e.g. [1..7]).
169
- * - `capabilityTags` : tags from the task's `requiresCapability`
170
- * vocabulary that this adapter can satisfy.
171
- *
172
- * On register conflict, replace — adapter modules are expected to be
173
- * the only source of truth for their own descriptor.
174
- *
175
- * Adapters typically run as out-of-process workers (Claude Code CLI,
176
- * OpenClaw daemon plug-in, Hermes Python). The `dispatch` boundary
177
- * here is the *runtime side* of that bridge — it returns a Promise
178
- * whose resolution corresponds to the adapter's reported completion.
179
- */
180
- interface AdapterDescriptor {
181
- /** Stable identifier — must match the catalog entry. */
182
- name: string;
183
- /** PARA Tier numbers (L1–L10). */
184
- tiersSupported: number[];
185
- /** Capability tag vocabulary (e.g. ["code.write", "code.review"]). */
186
- capabilityTags: string[];
187
- /** Free-form for telemetry — version, build, etc. */
188
- metadata?: Record<string, unknown>;
189
- }
190
- interface AdapterDispatchInput {
191
- /** Cloud task ID (im_tasks.id). */
192
- taskId: string;
193
- /** Step index when the task is multi-step (route step). */
194
- stepIdx?: number;
195
- /** Capability the cloud asked for — drives adapter selection. */
196
- capability: string;
197
- /** User-facing prompt / instruction. */
198
- prompt: string;
199
- /** Free-form metadata passed through to the adapter. */
200
- metadata?: Record<string, unknown>;
201
- /** Optional deadline (ms epoch). Adapters should respect it best-effort. */
202
- deadlineAt?: number;
203
- }
204
- interface AdapterDispatchResult {
205
- ok: boolean;
206
- /** Output text (stdout, summary, etc.). */
207
- output?: string;
208
- /** Files produced by the adapter (paths are relative to the agent
209
- * workspace; cloud uploads them via the artifact stream). */
210
- artifacts?: Array<{
211
- path: string;
212
- bytes: number;
213
- mime?: string;
214
- }>;
215
- /** Failure reason — must be set when ok=false. */
216
- error?: string;
217
- /** Free-form telemetry — token counts, latency, model, etc. */
218
- metadata?: Record<string, unknown>;
219
- }
220
- interface AdapterImpl extends AdapterDescriptor {
221
- /** Dispatch a task step to this adapter. Should not throw — errors
222
- * belong in the result. */
223
- dispatch(input: AdapterDispatchInput): Promise<AdapterDispatchResult>;
224
- /** Optional: per-adapter health probe. Defaults to "healthy". */
225
- health?(): Promise<{
226
- healthy: boolean;
227
- reason?: string;
228
- }>;
229
- /**
230
- * Reset adapter state for a specific agent (or all agents if undefined).
231
- *
232
- * v1.9.x remote-command `agent_restart` semantic: abort/clear whatever
233
- * per-agent context the adapter holds. For stateless adapters (CLI shim),
234
- * this is a no-op; for Mode B adapters, it's typically a POST /reset to
235
- * the loopback so the adapter host clears its own session state.
236
- *
237
- * NOT a process restart — the adapter is not expected to own a PID.
238
- *
239
- * @param agentName Optional agent name to scope the reset. Undefined = reset all.
240
- * @returns Arbitrary result; ok:true for success, ok:false+reason otherwise.
241
- */
242
- reset?(agentName?: string): Promise<{
243
- ok: boolean;
244
- state?: string;
245
- reason?: string;
246
- [k: string]: unknown;
247
- }>;
248
- }
249
- declare class AdapterRegistry {
250
- private readonly adapters;
251
- register(adapter: AdapterImpl): void;
252
- unregister(name: string): boolean;
253
- has(name: string): boolean;
254
- get(name: string): AdapterImpl | undefined;
255
- list(): AdapterDescriptor[];
256
- size(): number;
257
- /**
258
- * Find adapters that can satisfy the given capability tag.
259
- *
260
- * An adapter matches if `capabilityTags` includes the tag verbatim or
261
- * if the adapter declared a wildcard prefix match (e.g. `code.*` matches
262
- * `code.write`). Returns deterministic ordering — adapters are sorted by
263
- * name so callers see the same result for the same registry state.
264
- */
265
- findByCapability(capability: string): AdapterImpl[];
266
- /**
267
- * Find adapters that can host a given PARA tier.
268
- */
269
- findByTier(tier: number): AdapterImpl[];
270
- }
271
-
272
- /**
273
- * Prismer Runtime — Dispatch Mux (Sprint A3, D4).
274
- *
275
- * Picks an adapter for an incoming task and forwards the dispatch call.
276
- * Selection policy (in priority order):
277
- *
278
- * 1. `preferAdapter` (caller-supplied) wins if registered AND the
279
- * adapter can satisfy the requested capability.
280
- * 2. If exactly one adapter matches the capability, use it.
281
- * 3. If multiple match, pick deterministically — adapters sorted by
282
- * `name` (so the same task always lands on the same adapter when
283
- * multiple are eligible). Future: load/latency-aware ranking.
284
- * 4. None matches → return a structured "no_adapter" failure rather
285
- * than throw — the caller (cloud) decides whether to reroute.
286
- *
287
- * The mux never throws on adapter errors; it always returns a result
288
- * with `ok=false` so the cloud-side TaskRouter can report `step_failed`
289
- * instead of seeing a daemon-side stack trace.
290
- */
291
-
292
- interface DispatchMuxRequest extends AdapterDispatchInput {
293
- /** If set and registered, win selection. */
294
- preferAdapter?: string;
295
- }
296
- interface DispatchMuxResult extends AdapterDispatchResult {
297
- /** Which adapter handled this request. Useful for telemetry +
298
- * debugging when the answer "feels wrong". */
299
- adapter?: string;
300
- }
301
- declare class DispatchMux {
302
- private readonly registry;
303
- constructor(registry: AdapterRegistry);
304
- /**
305
- * Resolve the adapter that would handle a given request without
306
- * actually dispatching. Returned undefined means "no adapter matches".
307
- * Useful for cloud-side capability probing.
308
- */
309
- resolve(req: {
310
- capability: string;
311
- preferAdapter?: string;
312
- }): {
313
- adapter: string;
314
- } | undefined;
315
- dispatch(req: DispatchMuxRequest): Promise<DispatchMuxResult>;
316
- }
317
-
318
- interface PairOfferRecord {
319
- offer: string;
320
- uri: string;
321
- expiresAt: number;
322
- createdAt: number;
323
- paired: boolean;
324
- bindingId?: string;
325
- deviceName?: string;
326
- transport?: 'lan' | 'relay';
327
- clientPubKey?: string;
328
- }
329
- interface PairingStatus {
330
- paired: boolean;
331
- expired: boolean;
332
- bindingId?: string;
333
- deviceName?: string;
334
- transport?: 'lan' | 'relay';
335
- }
336
- declare class PairingManager {
337
- private readonly offers;
338
- createOffer(ttlSec?: number): PairOfferRecord;
339
- getStatus(offer: string): PairingStatus | null;
340
- confirm(offer: string, input?: {
341
- bindingId?: string;
342
- deviceName?: string;
343
- transport?: 'lan' | 'relay';
344
- clientPubKey?: string;
345
- }): PairingStatus;
346
- cleanExpired(): void;
347
- }
348
-
349
- /**
350
- * event-handler.ts — PARA event subscription and processing for Daemon
351
- *
352
- * Implements PARA event subscription, Tier-based event routing, and
353
- * integration with daemon startup workflow.
354
- *
355
- * Reference: docs/version190/04-sandbox-permissions.md §5.3
356
- */
357
-
358
- interface EventHandlerOptions {
359
- bus: EventBus;
360
- supervisor: AgentSupervisor;
361
- /** Optional tier filter for event routing */
362
- tierFilter?: number;
363
- }
364
- declare class EventHandler {
365
- private readonly _bus;
366
- private readonly _supervisor;
367
- private readonly _tierFilter?;
368
- private readonly _subscriptions;
369
- private readonly _blockedEvents;
370
- private _registered;
371
- constructor(opts: EventHandlerOptions);
372
- /**
373
- * Start subscribing to PARA events.
374
- * Must be called after daemon is fully initialized.
375
- */
376
- start(): void;
377
- /**
378
- * Stop all event subscriptions.
379
- */
380
- stop(): void;
381
- /**
382
- * Subscribe to a specific PARA event type with optional tier filter.
383
- */
384
- private _subscribe;
385
- /**
386
- * Unsubscribe from a specific event type.
387
- */
388
- unsubscribe(eventType: string, handler?: SubscriptionHandler<ParaEvent>): void;
389
- /**
390
- * Handle agent registration event
391
- */
392
- private _handleAgentRegister;
393
- /**
394
- * Handle session started event
395
- */
396
- private _handleSessionStarted;
397
- /**
398
- * Handle session ended event
399
- */
400
- private _handleSessionEnded;
401
- /**
402
- * Handle agent state change
403
- */
404
- private _handleAgentState;
405
- /**
406
- * Handle skill activation
407
- */
408
- private _handleSkillActivated;
409
- /**
410
- * Handle skill deactivation
411
- */
412
- private _handleSkillDeactivated;
413
- /**
414
- * Handle approval request
415
- */
416
- private _handleApprovalRequest;
417
- /**
418
- * Handle approval result
419
- */
420
- private _handleApprovalResult;
421
- /**
422
- * Handle task creation
423
- */
424
- private _handleTaskCreated;
425
- /**
426
- * Handle task completion
427
- */
428
- private _handleTaskCompleted;
429
- /**
430
- * Handle LLM pre-request
431
- */
432
- private _handleLlmPre;
433
- /**
434
- * Handle LLM post-request
435
- */
436
- private _handleLlmPost;
437
- }
438
-
439
- /** Authenticated identity returned by the authenticate callback. */
440
- interface AuthenticatedIdentity {
441
- agentId: string;
442
- bearerSub?: string;
443
- }
444
- interface DaemonHttpOptions {
445
- host?: string;
446
- port?: number;
447
- eventBus: EventBus;
448
- supervisor: AgentSupervisor;
449
- fsContextProvider?: (req: {
450
- agentId: string;
451
- workspace?: string;
452
- }) => FsContext | undefined;
453
- pairingManager?: PairingManager;
454
- eventHandler?: EventHandler;
455
- /** When provided, every non-health request must carry a valid Bearer token (null = 401).
456
- * When absent, localhost trust mode: body agentId is used as-is. */
457
- authenticate?: (bearerToken: string | undefined) => AuthenticatedIdentity | null;
458
- }
459
- /** Generic extension-point route handler registered via registerRoute() (Q3). */
460
- type RouteHandler = (req: http.IncomingMessage, res: http.ServerResponse, ctx: {
461
- authed: AuthenticatedIdentity | null;
462
- body: Buffer;
463
- }) => Promise<void> | void;
464
- declare class DaemonHttpServer {
465
- private readonly _host;
466
- private readonly _port;
467
- private readonly _bus;
468
- private readonly _supervisor;
469
- private readonly _fsCtxProvider?;
470
- private readonly _authenticate?;
471
- private readonly _pairingManager;
472
- private readonly _eventHandler?;
473
- private _server;
474
- private _url;
475
- private _running;
476
- private readonly _sseClients;
477
- private readonly _inFlight;
478
- private readonly _startedAt;
479
- private readonly _customRoutes;
480
- constructor(opts: DaemonHttpOptions);
481
- get url(): string | undefined;
482
- get isRunning(): boolean;
483
- /** Register a custom route handler. Built-in routes take precedence. */
484
- registerRoute(method: 'GET' | 'POST' | 'PATCH' | 'DELETE', path: string, handler: RouteHandler): void;
485
- /** Remove a previously registered custom route. */
486
- unregisterRoute(method: string, path: string): void;
487
- private _findCustomRoute;
488
- start(): Promise<{
489
- host: string;
490
- port: number;
491
- }>;
492
- stop(timeoutMs?: number): Promise<void>;
493
- private _handleRequest;
494
- private _handleHealth;
495
- private _handlePairOffer;
496
- private _handlePairStatus;
497
- private _handlePairConfirm;
498
- private _handleTransportStatus;
499
- /** Read-only snapshot of transport state, used by /gui/status. Returns
500
- * null when the multi-path transport isn't enabled. */
501
- private _snapshotTransportStatus;
502
- private _handleLanProbe;
503
- private _handleTransportReprobe;
504
- }
505
-
506
- interface LLMMessage {
507
- role: 'system' | 'user' | 'assistant';
508
- content: string;
509
- }
510
- interface LLMRequest {
511
- messages: LLMMessage[];
512
- maxTokens?: number;
513
- temperature?: number;
514
- maxCostUsd?: number;
515
- maxLatencyMs?: number;
516
- capabilities?: string[];
517
- }
518
- interface LLMResponse {
519
- content: string;
520
- usage: {
521
- promptTokens: number;
522
- completionTokens: number;
523
- totalTokens: number;
524
- };
525
- provider: string;
526
- model: string;
527
- latencyMs: number;
528
- costUsd?: number;
529
- }
530
- interface LLMProvider {
531
- name: string;
532
- model: string;
533
- priority: number;
534
- capabilities?: string[];
535
- pricing?: {
536
- inputPer1kUsd: number;
537
- outputPer1kUsd: number;
538
- };
539
- invoke: (req: LLMRequest, signal: AbortSignal) => Promise<Omit<LLMResponse, 'provider' | 'model' | 'latencyMs'>>;
540
- healthCheck?: () => Promise<boolean>;
541
- }
542
- interface RoutingPolicy {
543
- strategy: 'priority' | 'cheapest' | 'fastest' | 'round-robin';
544
- retryOnFailure?: boolean;
545
- maxRetries?: number;
546
- healthCheckIntervalMs?: number;
547
- timeoutMs?: number;
548
- }
549
- interface ProviderStats {
550
- invocations: number;
551
- successes: number;
552
- failures: number;
553
- p50Ms: number;
554
- p95Ms: number;
555
- avgCostUsd: number;
556
- }
557
- declare class AllProvidersFailedError extends Error {
558
- attempts: Array<{
559
- provider: string;
560
- error: string;
561
- }>;
562
- constructor(attempts: AllProvidersFailedError['attempts']);
563
- }
564
- declare class LLMDispatcher {
565
- private readonly providers;
566
- private policy;
567
- private readonly state;
568
- private rrCounter;
569
- private healthTimer;
570
- constructor(providers: LLMProvider[], policy?: RoutingPolicy);
571
- complete(req: LLMRequest): Promise<LLMResponse>;
572
- get stats(): Record<string, ProviderStats>;
573
- setPolicy(policy: RoutingPolicy): void;
574
- markProviderDown(name: string): void;
575
- markProviderUp(name: string): void;
576
- stopHealthChecks(): void;
577
- private startHealthChecks;
578
- private runHealthChecks;
579
- _runHealthChecksNow(): Promise<void>;
580
- private isDown;
581
- private estimateCostUsd;
582
- private selectProviders;
583
- }
584
-
585
- /**
586
- * Prismer Runtime — Evolution Gateway HTTP API
587
- *
588
- * Exposes evolution gateway operations via HTTP for daemon process.
589
- * Integrates with LLM Dispatcher for distillation triggers.
590
- *
591
- * Endpoints:
592
- * - POST /evolution/signal — Extract signals from tool output / log
593
- * - POST /evolution/record — Record gene execution outcome
594
- * - POST /evolution/analyze — Analyze signals and recommend gene
595
- * - POST /evolution/genes — Create new gene
596
- * - GET /evolution/genes — Query available genes
597
- * - GET /evolution/personality — Get agent personality
598
- * - POST /evolution/distill — Trigger distillation
599
- *
600
- * @see docs/version190/IMPLEMENTATION-PLAN-RUNTIME-GAP.md
601
- */
602
-
603
- interface EvolutionGatewayOptions {
604
- eventBus: EventBus;
605
- supervisor: AgentSupervisor;
606
- llmDispatcher?: LLMDispatcher;
607
- /** Cloud API base URL (default: https://prismer.cloud) */
608
- cloudApiBase?: string;
609
- /** Authenticated identity (from Bearer token or API key) */
610
- authenticate?: (bearerToken: string | undefined) => AuthenticatedIdentity | null;
611
- /**
612
- * v1.9.0 B.7.a — API key used as the Bearer token when forwarding daemon
613
- * requests to the cloud Evolution API. When undefined, outbound requests
614
- * omit the Authorization header (callers get 401 from cloud until the
615
- * daemon is started with `apiKey`).
616
- */
617
- cloudApiKey?: string;
618
- }
619
- interface SignalExtractionRequest {
620
- toolOutput?: {
621
- toolName?: string;
622
- output?: string;
623
- exitCode?: number;
624
- error?: string;
625
- durationMs?: number;
626
- };
627
- logFile?: {
628
- logPath?: string;
629
- logContent?: string;
630
- timestamp?: string;
631
- };
632
- provider?: string;
633
- stage?: string;
634
- severity?: string;
635
- tags?: string[];
636
- }
637
- interface AnalyzeRequest {
638
- signals: string[];
639
- taskCapability?: string;
640
- provider?: string;
641
- stage?: string;
642
- severity?: string;
643
- }
644
- interface RecordRequest {
645
- geneId: string;
646
- signals: string[];
647
- outcome: 'success' | 'failed';
648
- score?: number;
649
- summary?: string;
650
- costCredits?: number;
651
- transitionReason?: 'gene_applied' | 'fallback_relaxed' | 'fallback_neighbor' | 'baseline';
652
- }
653
- interface CreateGeneRequest {
654
- category: 'repair' | 'optimize' | 'innovate' | 'diagnostic';
655
- signalsMatch: string[];
656
- strategy: string[];
657
- preconditions?: string[];
658
- constraints?: {
659
- maxCredits?: number;
660
- maxRetries?: number;
661
- maxExecutionTime?: number;
662
- };
663
- }
664
- interface DistillationRequest {
665
- /** Skip LLM verification and trigger immediately */
666
- dryRun?: boolean;
667
- }
668
- declare class EvolutionGatewayHttpHandler {
669
- private readonly eventBus;
670
- private readonly supervisor;
671
- private readonly llmDispatcher;
672
- private readonly cloudApiBase;
673
- private readonly authenticate;
674
- private readonly cloudApiKey;
675
- private readonly routes;
676
- constructor(opts: EvolutionGatewayOptions);
677
- private cloudAuthHeaders;
678
- private registerRoutes;
679
- /** Get all registered routes */
680
- getRoutes(): Map<string, RouteHandler>;
681
- /** Get a specific route handler */
682
- getRoute(method: string, path: string): RouteHandler | undefined;
683
- /**
684
- * POST /evolution/signal
685
- * Extract signals from tool output or log file.
686
- */
687
- private handleExtractSignal;
688
- /**
689
- * POST /evolution/analyze
690
- * Analyze signals and recommend the best gene.
691
- */
692
- private handleAnalyze;
693
- /**
694
- * POST /evolution/record
695
- * Record gene execution outcome.
696
- */
697
- private handleRecord;
698
- /**
699
- * POST /evolution/genes
700
- * Create a new gene.
701
- */
702
- private handleCreateGene;
703
- /**
704
- * GET /evolution/genes
705
- * Query available genes.
706
- */
707
- private handleQueryGenes;
708
- /**
709
- * GET /evolution/personality
710
- * Get agent personality.
711
- */
712
- private handleGetPersonality;
713
- /**
714
- * POST /evolution/distill
715
- * Trigger gene distillation.
716
- */
717
- private handleDistill;
718
- /**
719
- * GET /evolution/unmatched
720
- * Get unmatched signals (evolution frontier).
721
- */
722
- private handleGetUnmatched;
723
- private parseCloudResponse;
724
- private callCloudAnalyze;
725
- private callCloudRecord;
726
- private callCloudCreateGene;
727
- private callCloudQueryGenes;
728
- private callCloudGetPersonality;
729
- private callCloudDistill;
730
- private callCloudGetUnmatched;
731
- private triggerLocalDistillation;
732
- private extractSignalsLocal;
733
- }
734
-
735
- /**
736
- * Prismer Runtime — Task Router
737
- *
738
- * v1.9.0 Task Router: HTTP API for routing tasks to agents,
739
- * capability matching, and SSE streaming of task state changes.
740
- *
741
- * Integrates with:
742
- * - Cloud API (/api/im/tasks) for persistent task store
743
- * - AgentSupervisor for local agent status
744
- * - EventBus for SSE streaming
745
- *
746
- * Design reference: docs/version190/IMPLEMENTATION-PLAN-RUNTIME-GAP.md §P1
747
- */
748
-
749
- /**
750
- * Task routing state machine per §16.4.
751
- *
752
- * State transitions:
753
- * created → dispatching → step_running → step_completed → (next step or completed)
754
- * step_running → step_failed → retrying (×3) → retry_exhausted → needs_human
755
- * step_running → step_timeout → rerouting → step_running (new agent)
756
- */
757
- declare enum TaskRouteState {
758
- Created = "created",
759
- Dispatching = "dispatching",
760
- StepRunning = "step_running",
761
- StepCompleted = "step_completed",
762
- StepFailed = "step_failed",
763
- StepTimeout = "step_timeout",
764
- Retrying = "retrying",
765
- RetryExhausted = "retry_exhausted",
766
- NeedsHuman = "needs_human",
767
- Rerouting = "rerouting",
768
- Completed = "completed",
769
- Cancelled = "cancelled"
770
- }
771
- interface TaskRouterOptions {
772
- eventBus: EventBus;
773
- supervisor: AgentSupervisor;
774
- cloudBaseUrl?: string;
775
- apiToken?: string;
776
- }
777
- interface TaskInfo {
778
- id: string;
779
- title: string;
780
- status: TaskRouteState | string;
781
- requiresCapability?: string | null;
782
- runtimeRoute?: unknown[] | null;
783
- assigneeId?: string | null;
784
- progress?: number | null;
785
- statusMessage?: string | null;
786
- createdAt: string;
787
- updatedAt: string;
788
- }
789
- interface RouteTaskRequest {
790
- taskId?: string;
791
- priority?: 'high' | 'normal' | 'low';
792
- preferredAgentId?: string;
793
- }
794
- interface RouteTaskResponse {
795
- taskId: string;
796
- agentId: string;
797
- capability: string;
798
- stepIdx: number;
799
- totalSteps: number;
800
- }
801
- interface AssignTaskRequest {
802
- agentId: string;
803
- taskId?: string;
804
- }
805
- interface StepCompletedRequest {
806
- taskId?: string;
807
- stepId: string;
808
- result?: Record<string, unknown>;
809
- metadata?: Record<string, unknown>;
810
- }
811
- interface CancelTaskRequest {
812
- taskId?: string;
813
- reason: string;
814
- }
815
- interface StepFailedRequest {
816
- taskId?: string;
817
- stepId: string;
818
- error?: string;
819
- metadata?: Record<string, unknown>;
820
- }
821
- interface StepTimeoutRequest {
822
- taskId?: string;
823
- stepId: string;
824
- capability?: string;
825
- metadata?: Record<string, unknown>;
826
- }
827
- declare class TaskRouter {
828
- private readonly _bus;
829
- private readonly _supervisor;
830
- private readonly _cloudBaseUrl;
831
- private readonly _apiToken;
832
- private _sseClients;
833
- /** Per-step retry counters: key = `${taskId}:${stepId}` */
834
- private readonly _retryCounters;
835
- constructor(opts: TaskRouterOptions);
836
- /**
837
- * Register HTTP routes with the daemon server.
838
- * Call this from daemon-http.ts to expose task router endpoints.
839
- */
840
- registerRoutes(server: {
841
- registerRoute: (method: 'GET' | 'POST' | 'PATCH' | 'DELETE', path: string, handler: RouteHandler) => void;
842
- }): void;
843
- private _handleRouteTask;
844
- private _handleAssignTask;
845
- private _handleStepCompleted;
846
- private _handleCancelTask;
847
- private _handleStepFailed;
848
- private _handleStepTimeout;
849
- private _handleGetTask;
850
- private _handleListTasks;
851
- /** Publish a task.state event with the given TaskRouteState and optional extra fields. */
852
- private _publishState;
853
- private _callCloudApi;
854
- }
855
-
856
- type KeychainBackend = 'macos-keychain' | 'libsecret' | 'pass' | 'encrypted-file';
857
- interface KeychainAdapter {
858
- name: KeychainBackend;
859
- available(): Promise<boolean>;
860
- get(service: string, account: string): Promise<string | null>;
861
- set(service: string, account: string, value: string): Promise<void>;
862
- delete(service: string, account: string): Promise<void>;
863
- list(service: string): Promise<string[]>;
864
- }
865
- interface KeychainOptions {
866
- preferredBackend?: KeychainBackend;
867
- masterPassphrase?: string;
868
- encryptedFilePath?: string;
869
- }
870
- declare class NoKeychainBackendError extends Error {
871
- constructor();
872
- }
873
- declare class KeychainOperationError extends Error {
874
- constructor(op: string, cause: unknown);
875
- }
876
- declare class Keychain {
877
- private readonly opts;
878
- private resolvedBackend;
879
- private detecting;
880
- constructor(opts?: KeychainOptions);
881
- backend(): Promise<KeychainAdapter>;
882
- private buildCandidateList;
883
- private makeAdapter;
884
- get(service: string, account: string): Promise<string | null>;
885
- set(service: string, account: string, value: string): Promise<void>;
886
- delete(service: string, account: string): Promise<void>;
887
- list(service: string): Promise<string[]>;
888
- }
889
-
890
- interface PrismerConfig {
891
- apiKey?: string;
892
- apiBase?: string;
893
- daemon?: {
894
- host?: string;
895
- port?: number;
896
- };
897
- agents?: Record<string, {
898
- enabled?: boolean;
899
- apiKey?: string;
900
- [key: string]: unknown;
901
- }>;
902
- [key: string]: unknown;
903
- }
904
- interface LoadConfigOptions {
905
- path?: string;
906
- keychain?: Keychain;
907
- resolvePlaceholders?: boolean;
908
- }
909
- declare class ConfigError extends Error {
910
- constructor(message: string);
911
- }
912
- declare function parseKeyringPlaceholder(value: string): {
913
- service: string;
914
- account: string;
915
- } | null;
916
- declare function loadConfig(opts?: LoadConfigOptions): Promise<PrismerConfig>;
917
- declare function writeConfig(config: PrismerConfig, opts?: {
918
- path?: string;
919
- }): Promise<void>;
920
-
921
- interface MigrateStep {
922
- level: 'info' | 'ok' | 'warn' | 'error';
923
- message: string;
924
- detail?: string;
925
- }
926
- interface MigrateSecretsOptions {
927
- configPath?: string;
928
- keychain: Keychain;
929
- dryRun?: boolean;
930
- onStep?: (step: MigrateStep) => void;
931
- }
932
- interface MigrateSecretsResult {
933
- migrated: Array<{
934
- path: string;
935
- service: string;
936
- account: string;
937
- }>;
938
- skipped: Array<{
939
- path: string;
940
- reason: string;
941
- }>;
942
- errors: Array<{
943
- path: string;
944
- error: string;
945
- }>;
946
- }
947
- declare function migrateSecrets(opts: MigrateSecretsOptions): Promise<MigrateSecretsResult>;
948
-
949
- interface DaemonRunnerOptions {
950
- host?: string;
951
- port?: number;
952
- pidFile?: string;
953
- dataDir?: string;
954
- installSignalHandlers?: boolean;
955
- authBearer?: string;
956
- apiKey?: string;
957
- daemonId?: string;
958
- userId?: string;
959
- enableTransport?: boolean;
960
- forceProbe?: boolean;
961
- workspace?: string;
962
- /**
963
- * v1.9.0 B.7.a — cloud base URL (https://prismer.cloud for prod,
964
- * https://cloud.prismer.dev for test). Forwarded to EvolutionGateway so
965
- * daemon→cloud calls hit the same env the API key was issued against.
966
- */
967
- cloudApiBase?: string;
968
- }
969
- interface DaemonRunnerHandle {
970
- stop(): Promise<void>;
971
- readonly url: string;
972
- readonly pid: number;
973
- readonly dataDir: string;
974
- }
975
- declare function startDaemonRunner(opts?: DaemonRunnerOptions): Promise<DaemonRunnerHandle>;
976
-
977
- declare function assertBrandVoice(text: string, label?: string): void;
978
-
979
- type OutputMode = 'pretty' | 'json' | 'quiet';
980
- interface UIOptions {
981
- mode?: OutputMode;
982
- color?: boolean;
983
- stream?: NodeJS.WritableStream;
984
- errStream?: NodeJS.WritableStream;
985
- }
986
- interface TableRow {
987
- [column: string]: string;
988
- }
989
- interface TableOptions {
990
- columns: string[];
991
- maxWidth?: number;
992
- }
993
- interface LegacyTableOptions {
994
- columns: string[];
995
- rows: TableRow[];
996
- maxWidth?: number;
997
- }
998
-
999
- declare class UI {
1000
- readonly mode: OutputMode;
1001
- readonly colorEnabled: boolean;
1002
- private readonly stream;
1003
- private readonly errStream;
1004
- constructor(opts?: UIOptions);
1005
- private ansi;
1006
- private green;
1007
- private red;
1008
- private yellow;
1009
- private cyan;
1010
- private dim;
1011
- private bold;
1012
- private gray;
1013
- private brandMark;
1014
- private colorBrandLine;
1015
- write(text: string): void;
1016
- writeErr(text: string): void;
1017
- header(text: string): void;
1018
- smallHeader(subtitle?: string): void;
1019
- banner(subtitle?: string, opts?: {
1020
- full?: boolean;
1021
- }): void;
1022
- blank(): void;
1023
- line(text: string): void;
1024
- info(text: string): void;
1025
- secondary(text: string, indent?: number): void;
1026
- tip(text: string): void;
1027
- next(text: string): void;
1028
- ok(text: string, detail?: string): void;
1029
- success(text: string, detail?: string): void;
1030
- fail(text: string, detail?: string): void;
1031
- online(text: string): void;
1032
- offline(text: string): void;
1033
- notInstalled(text: string): void;
1034
- pending(text: string): void;
1035
- warn(text: string, detail?: string): void;
1036
- error(what: string, cause?: string, fix?: string): void;
1037
- table(rows: TableRow[], opts: TableOptions): void;
1038
- table(opts: LegacyTableOptions): void;
1039
- spinner(text: string): {
1040
- update(t: string): void;
1041
- stop(final?: string): void;
1042
- };
1043
- progress(text: string, total: number): {
1044
- update(current: number, detail?: string): void;
1045
- stop(final?: string): void;
1046
- };
1047
- json(payload: unknown, opts?: {
1048
- pretty?: boolean;
1049
- }): void;
1050
- result<T>(pretty: () => void, jsonPayload: T): void;
1051
- }
1052
- declare function getUI(): UI;
1053
- declare function setUI(ui: UI): void;
1054
- declare function applyCommonFlags(argv: string[]): {
1055
- mode: OutputMode;
1056
- color: boolean;
1057
- restArgv: string[];
1058
- };
1059
-
1060
- interface CliContext {
1061
- ui: UI;
1062
- keychain: Keychain;
1063
- cwd: string;
1064
- argv: string[];
1065
- }
1066
- declare function createCliContext(opts?: {
1067
- argv?: string[];
1068
- ui?: UI;
1069
- }): Promise<CliContext>;
1070
-
1071
- interface AgentCatalogEntry {
1072
- name: string;
1073
- displayName: string;
1074
- packPackage: string;
1075
- packVersionRange: string;
1076
- hookConfigPath: string;
1077
- mcpConfigPath?: string;
1078
- upstreamBinary: string;
1079
- upstreamVersionRange?: string;
1080
- localSourcePath?: string;
1081
- installCommand?: string;
1082
- tiersSupported: number[];
1083
- capabilityTags: string[];
1084
- detect: () => Promise<{
1085
- found: boolean;
1086
- binaryPath?: string;
1087
- version?: string;
1088
- }>;
1089
- }
1090
- declare const AGENT_CATALOG: AgentCatalogEntry[];
1091
- declare function getAgent(name: string): AgentCatalogEntry | undefined;
1092
-
1093
- type HookFormat = 'v1.8' | 'v1.9';
1094
- interface HookEntry {
1095
- command?: string;
1096
- webhook?: string;
1097
- enabled?: boolean;
1098
- [key: string]: unknown;
1099
- }
1100
- interface HookConfig {
1101
- hooks: Record<string, HookEntry | HookEntry[]>;
1102
- [key: string]: unknown;
1103
- }
1104
- interface MergeResult {
1105
- merged: HookConfig;
1106
- added: string[];
1107
- preserved: string[];
1108
- replaced: string[];
1109
- backupPath?: string;
1110
- }
1111
- interface MergeOptions {
1112
- daemonUrl: string;
1113
- dryRun?: boolean;
1114
- /** Absolute path to the installed claude-code-plugin root (contains hooks/para-emit.mjs). */
1115
- pluginRoot?: string;
1116
- }
1117
- declare function mergeHooks(existing: HookConfig | null, opts: MergeOptions): MergeResult;
1118
- declare function readHookConfig(filePath: string): Promise<HookConfig | null>;
1119
- declare function writeHookConfig(filePath: string, cfg: HookConfig): Promise<void>;
1120
- declare function installHooks(configPath: string, existing: HookConfig | null, opts: MergeOptions): Promise<MergeResult>;
1121
- declare function rollbackHooks(configPath: string): Promise<{
1122
- restored: boolean;
1123
- fromBackup: string | null;
1124
- }>;
1125
-
1126
- interface PairOffer {
1127
- offer: string;
1128
- uri: string;
1129
- expiresAt: number;
1130
- relayUrl?: string;
1131
- lanHost?: string;
1132
- lanPort?: number;
1133
- }
1134
- interface PairedDevice {
1135
- id: string;
1136
- name: string;
1137
- method: 'qr' | 'api-key';
1138
- transport: 'lan' | 'relay';
1139
- lastSeenAt: number;
1140
- pairedAt: number;
1141
- }
1142
-
1143
- interface MigrateOptions {
1144
- dryRun?: boolean;
1145
- configPath?: string;
1146
- homeDir?: string;
1147
- yes?: boolean;
1148
- /**
1149
- * Dependency-injection hook for tests — override the TTY confirmation prompt.
1150
- * When provided, replaces the readline-based promptConfirm call entirely.
1151
- */
1152
- confirmer?: () => Promise<boolean>;
1153
- }
1154
- interface MigrateResult {
1155
- apiKeyMigrated: boolean;
1156
- hooksBackedUp: string[];
1157
- hooksRedirected: string[];
1158
- memoryFilesImported: number;
1159
- networkEndpointsRewritten: Array<{
1160
- file: string;
1161
- rewrites: number;
1162
- backupPath: string;
1163
- }>;
1164
- errors: Array<{
1165
- step: string;
1166
- error: string;
1167
- }>;
1168
- }
1169
-
1170
- interface EncryptionConfig {
1171
- enabled: boolean;
1172
- key?: Buffer;
1173
- }
1174
- interface MemoryFile {
1175
- id: string;
1176
- ownerId: string;
1177
- ownerType: 'user' | 'agent';
1178
- scope: string;
1179
- path: string;
1180
- content: string;
1181
- version: number;
1182
- memoryType?: string;
1183
- description?: string;
1184
- contentHash: string;
1185
- createdAt: string;
1186
- updatedAt: string;
1187
- stale: boolean;
1188
- }
1189
- interface MemoryFileVersion {
1190
- id: string;
1191
- fileId: string;
1192
- version: number;
1193
- content: string;
1194
- createdAt: string;
1195
- }
1196
- interface DreamCompaction {
1197
- id: string;
1198
- ownerId: string;
1199
- scope: string;
1200
- summary: string;
1201
- createdAt: string;
1202
- }
1203
- interface WriteMemoryFileInput {
1204
- ownerId: string;
1205
- ownerType: 'user' | 'agent';
1206
- scope?: string;
1207
- path: string;
1208
- content: string;
1209
- memoryType?: string;
1210
- description?: string;
1211
- }
1212
- interface MemoryFileFilters {
1213
- ownerId?: string;
1214
- scope?: string;
1215
- path?: string;
1216
- memoryType?: string;
1217
- stale?: boolean;
1218
- limit?: number;
1219
- offset?: number;
1220
- }
1221
- interface MemorySearchResult extends MemoryFile {
1222
- relevance: number;
1223
- snippet?: string;
1224
- }
1225
- interface MemoryStats {
1226
- fileCount: number;
1227
- totalSize: number;
1228
- totalBytes: number;
1229
- staleFiles: number;
1230
- ftsIndexed: number;
1231
- recallP95: number;
1232
- }
1233
- declare class MemoryDB {
1234
- private readonly filePath;
1235
- private readonly db;
1236
- private readonly crypto;
1237
- constructor(_encryptionConfig?: EncryptionConfig, opts?: {
1238
- filePath?: string;
1239
- });
1240
- writeMemoryFile(input: WriteMemoryFileInput): MemoryFile;
1241
- getMemoryFileById(id: string): MemoryFile | null;
1242
- deleteMemoryFile(id: string): boolean;
1243
- listMemoryFiles(filters?: MemoryFileFilters): MemoryFile[];
1244
- searchMemoryFiles(keyword: string, filters?: MemoryFileFilters): MemorySearchResult[];
1245
- getStats(ownerId?: string): MemoryStats;
1246
- close(): void;
1247
- }
1248
- declare function getMemoryDB(): MemoryDB;
1249
- declare function closeMemoryDB(): void;
1250
- declare function generateSalt(): Buffer;
1251
- declare function deriveKey(password: string, salt: Buffer): Buffer;
1252
- declare function encrypt(plaintext: string, key: Buffer): string;
1253
- declare function decrypt(encoded: string, key: Buffer): string;
1254
-
1255
- interface WriteMemoryRequest {
1256
- ownerId: string;
1257
- ownerType: 'user' | 'agent';
1258
- path: string;
1259
- content: string;
1260
- scope?: string;
1261
- memoryType?: string;
1262
- description?: string;
1263
- encrypt?: boolean;
1264
- }
1265
- interface RecallRequest {
1266
- keyword: string;
1267
- ownerId?: string;
1268
- scope?: string;
1269
- limit?: number;
1270
- useCloudFallback?: boolean;
1271
- }
1272
- interface ListMemoryRequest {
1273
- ownerId?: string;
1274
- scope?: string;
1275
- path?: string;
1276
- memoryType?: string;
1277
- stale?: boolean;
1278
- limit?: number;
1279
- offset?: number;
1280
- }
1281
- interface MemoryResponse {
1282
- success: boolean;
1283
- data?: unknown;
1284
- error?: {
1285
- code: string;
1286
- message: string;
1287
- };
1288
- }
1289
-
1290
- interface DreamResult {
1291
- ok: boolean;
1292
- compactedFiles: number;
1293
- summary?: DreamCompaction;
1294
- }
1295
- interface DreamSchedulerOptions {
1296
- ownerId?: string;
1297
- scope?: string;
1298
- intervalMs?: number;
1299
- }
1300
- declare class DreamScheduler {
1301
- private readonly opts;
1302
- private timer;
1303
- constructor(opts?: DreamSchedulerOptions);
1304
- start(): void;
1305
- stop(): void;
1306
- }
1307
- declare function createDreamScheduler(opts?: DreamSchedulerOptions): DreamScheduler;
1308
- declare function runDream(opts?: DreamSchedulerOptions): Promise<DreamResult>;
1309
-
1310
- /**
1311
- * PARA L8 — Session Export Trace Writer
1312
- *
1313
- * Per PARA spec §4.2 L8 (docs/version190/03-para-spec.md):
1314
- * session export 必须是 pre-compaction 的原始 trace。compaction 会把历史消息替换为 summary——
1315
- * 这种 adapter 必须额外持久化原始 trace 到 `.prismer/trace/<sessionId>.jsonl.zst`
1316
- * (append-only + zstd 压缩),compaction 只影响 working memory,不动 trace。
1317
- *
1318
- * Implementation:
1319
- * - Each `append()` JSON-stringifies the envelope, adds '\n', zstd-compresses it,
1320
- * then sync-appends the compressed bytes to the trace file.
1321
- * - zstd supports concatenated frames — multiple independent compressed blobs
1322
- * catenated together decompress back to the concatenation of their inputs.
1323
- * This is what makes append-only valid without holding a long-lived stream.
1324
- * - File mode 0o600 (trace may contain sensitive payloads).
1325
- * - Node 22+ gives us native `zlib.zstdCompressSync`. Older Node: append is a no-op
1326
- * and a single stderr warning is emitted at construction time. We do NOT throw
1327
- * or crash the daemon — daemon must still start on Node 20.
1328
- */
1329
-
1330
- interface TraceWriterOptions {
1331
- sessionId: string;
1332
- /**
1333
- * Override home directory; trace file will live at
1334
- * `<homeDir>/.prismer/trace/<sessionId>.jsonl.zst`. Defaults to `os.homedir()`.
1335
- */
1336
- homeDir?: string;
1337
- /**
1338
- * Explicit trace directory. Overrides homeDir if provided. Useful when the
1339
- * daemon runs with a non-default `dataDir`.
1340
- */
1341
- traceDir?: string;
1342
- }
1343
- declare class TraceWriter {
1344
- private readonly _sessionId;
1345
- private readonly _filePath;
1346
- private readonly _compress;
1347
- private _bytesWritten;
1348
- private _warnedAppendError;
1349
- private _closed;
1350
- constructor(opts: TraceWriterOptions);
1351
- /** Absolute path of the trace file: `<home>/.prismer/trace/<sessionId>.jsonl.zst`. */
1352
- get filePath(): string;
1353
- /** Session ID this writer is bound to. */
1354
- get sessionId(): string;
1355
- /** Total compressed bytes appended since construction. */
1356
- get bytesWritten(): number;
1357
- /** True if zstd is unavailable (Node < 22); append() is a no-op. */
1358
- get disabled(): boolean;
1359
- /**
1360
- * Synchronously append one event envelope to the trace as a new zstd frame.
1361
- * Safe to call after close() — becomes a no-op. Errors are logged once and swallowed.
1362
- */
1363
- append(event: EventBusEnvelope): void;
1364
- /**
1365
- * Close the writer. Currently a no-op because we use sync append with one
1366
- * self-contained zstd frame per event. The API exists so callers can switch to
1367
- * a streaming implementation later without changing integration code.
1368
- */
1369
- close(): void;
1370
- }
1371
- interface TraceWriterManagerOptions {
1372
- /** Override home directory (tests). Defaults to os.homedir(). */
1373
- homeDir?: string;
1374
- /** Explicit trace directory — takes precedence over homeDir when set. */
1375
- traceDir?: string;
1376
- }
1377
- /**
1378
- * Routes events from the EventBus (`bus.subscribe('*', ...)`) to the per-session
1379
- * TraceWriter.
1380
- *
1381
- * agent.session.started → open writer for payload.sessionId
1382
- * agent.session.ended → close + remove writer
1383
- * any other event → pick the writer by payload.sessionId if present;
1384
- * events without sessionId are skipped (not guessed)
1385
- */
1386
- declare class TraceWriterManager {
1387
- private readonly _writers;
1388
- private readonly _homeDir;
1389
- private readonly _traceDir;
1390
- private readonly _warnedOpenFailures;
1391
- constructor(opts?: TraceWriterManagerOptions);
1392
- /** Event-bus subscription handler. Pass via `bus.subscribe('*', mgr.handle)`. */
1393
- readonly handle: (ev: EventBusEnvelope) => void;
1394
- /** Close all writers — call on daemon shutdown. */
1395
- shutdown(): void;
1396
- /** Test / introspection helper. */
1397
- activeSessions(): string[];
1398
- private _openWriter;
1399
- private _closeWriter;
1400
- }
1401
-
1402
- /**
1403
- * Prismer Runtime — E2EE Crypto Module (v1.9.0)
1404
- *
1405
- * End-to-end encryption for LAN direct connections.
1406
- * Uses X25519 for key exchange and XSalsa20-Poly1305 for encryption.
1407
- *
1408
- * Security model:
1409
- * - Daemon and mobile each generate X25519 keypair
1410
- * - Keys are exchanged via QR code or relay (out-of-band)
1411
- * - Each session derives unique encryption key via HKDF
1412
- * - All LAN traffic is encrypted - relay never sees plaintext
1413
- *
1414
- * This implementation uses Node.js built-in crypto module for
1415
- * compatibility and no external dependencies.
1416
- */
1417
- interface KeyPair {
1418
- publicKey: Buffer;
1419
- privateKey: Buffer;
1420
- }
1421
- interface E2EEContext {
1422
- localKeyPair: KeyPair;
1423
- remotePublicKey: Buffer;
1424
- sharedSecret: Buffer;
1425
- sendKey: Buffer;
1426
- recvKey: Buffer;
1427
- sendNonce: Buffer;
1428
- recvNonce: Buffer;
1429
- }
1430
- interface EncryptedEnvelope {
1431
- version: number;
1432
- nonce: Buffer;
1433
- ciphertext: Buffer;
1434
- authTag: Buffer;
1435
- }
1436
- /**
1437
- * Generate X25519 keypair for E2EE
1438
- */
1439
- declare function generateKeyPair(): KeyPair;
1440
- /**
1441
- * Derive shared secret from local private key and remote public key (X25519)
1442
- */
1443
- declare function deriveSharedSecret(localPrivateKey: Buffer, remotePublicKey: Buffer): Buffer;
1444
- /**
1445
- * Derive send/recv keys from shared secret using HKDF-SHA256.
1446
- *
1447
- * Role is determined by lexicographic comparison of the two public keys
1448
- * so both peers agree without an explicit role flag. Without the keys
1449
- * (legacy single-context callers), defaults to the "A" role.
1450
- */
1451
- declare function deriveSessionKeys(sharedSecret: Buffer, localPublicKey?: Buffer, remotePublicKey?: Buffer): {
1452
- sendKey: Buffer;
1453
- recvKey: Buffer;
1454
- };
1455
- /**
1456
- * Serialize encrypted envelope to buffer
1457
- */
1458
- declare function serializeEnvelope(envelope: EncryptedEnvelope): Buffer;
1459
- /**
1460
- * Deserialize encrypted envelope from buffer
1461
- */
1462
- declare function deserializeEnvelope(data: Buffer): EncryptedEnvelope;
1463
- /**
1464
- * Create E2EE context for a session
1465
- */
1466
- declare function createE2EEContext(localKeyPair: KeyPair, remotePublicKey: Buffer): E2EEContext;
1467
- /**
1468
- * Encrypt message using E2EE context
1469
- */
1470
- declare function encryptMessage(context: E2EEContext, plaintext: Buffer): Buffer;
1471
- /**
1472
- * Decrypt message using E2EE context
1473
- */
1474
- declare function decryptMessage(context: E2EEContext, data: Buffer): Buffer;
1475
-
1476
- /**
1477
- * Prismer Runtime — E2EE Key Storage (v1.9.0)
1478
- *
1479
- * Secure storage for E2EE keys on daemon side.
1480
- * Uses keychain backend with encrypted JSON fallback for offline/keyless systems.
1481
- *
1482
- * Storage model:
1483
- * - Primary: Keychain (macOS Keychain / libsecret / pass)
1484
- * - Fallback: Encrypted JSON file (~/.prismer/e2ee-keys.json)
1485
- * - Per-session keys with TTL (30 min default)
1486
- * - Automatic cleanup of expired keys
1487
- *
1488
- * Security:
1489
- * - Keys encrypted at rest (keychain or encrypted file)
1490
- * - Master passphrase required for file fallback
1491
- * - Automatic key rotation on session expiry
1492
- * - Forward secrecy: ephemeral keys discarded after session
1493
- */
1494
-
1495
- interface E2EEKeyEntry {
1496
- /** Session ID (userId:daemonId or userId:deviceId) */
1497
- sessionId: string;
1498
- /** User ID who owns this key */
1499
- userId: string;
1500
- /** Daemon ID or Device ID */
1501
- endpointId: string;
1502
- /** Local keypair (ephemeral) */
1503
- keyPair: {
1504
- publicKey: string;
1505
- privateKey: string;
1506
- };
1507
- /** Remote public key */
1508
- remotePublicKey: string;
1509
- /** When this key was created */
1510
- createdAt: number;
1511
- /** When this key expires (unix timestamp) */
1512
- expiresAt: number;
1513
- /** Current sequence number */
1514
- seq: number;
1515
- }
1516
- interface E2EEStorageStats {
1517
- totalKeys: number;
1518
- activeKeys: number;
1519
- expiredKeys: number;
1520
- oldestKeyAge: number;
1521
- newestKeyAge: number;
1522
- }
1523
- declare class E2EEKeyStorage {
1524
- private keychain;
1525
- private useEncryptedFile;
1526
- private masterPassphrase?;
1527
- private cleanupInterval?;
1528
- constructor(options?: {
1529
- masterPassphrase?: string;
1530
- });
1531
- /**
1532
- * Initialize storage (try keychain, fallback to encrypted file)
1533
- */
1534
- initialize(): Promise<void>;
1535
- /**
1536
- * Store E2EE key for a session
1537
- */
1538
- storeKey(entry: E2EEKeyEntry): Promise<void>;
1539
- /**
1540
- * Retrieve E2EE key for a session
1541
- */
1542
- getKey(sessionId: string): Promise<E2EEKeyEntry | null>;
1543
- /**
1544
- * Remove E2EE key for a session
1545
- */
1546
- removeKey(sessionId: string): Promise<void>;
1547
- /**
1548
- * Get all keys for a user (for recovery)
1549
- */
1550
- getAllKeysForUser(userId: string): Promise<E2EEKeyEntry[]>;
1551
- /**
1552
- * Get storage statistics
1553
- */
1554
- getStats(userId?: string): Promise<E2EEStorageStats>;
1555
- /**
1556
- * Cleanup expired keys
1557
- */
1558
- cleanupExpiredKeys(): Promise<void>;
1559
- /**
1560
- * Shutdown storage (cleanup interval)
1561
- */
1562
- destroy(): void;
1563
- private ensureStorageFile;
1564
- private readEncryptedFile;
1565
- private writeEncryptedFile;
1566
- private encryptFile;
1567
- private decryptFile;
1568
- private storeInEncryptedFile;
1569
- private getFromEncryptedFile;
1570
- private removeFromEncryptedFile;
1571
- private getAllFromEncryptedFile;
1572
- private storeInKeychain;
1573
- private getFromKeychain;
1574
- private removeFromKeychain;
1575
- private getAllFromKeychain;
1576
- }
1577
- /**
1578
- * Generate session ID for E2EE storage
1579
- * Format: {userId}:{endpointId}
1580
- */
1581
- declare function generateSessionId(userId: string, endpointId: string): string;
1582
- /**
1583
- * Parse session ID into components
1584
- */
1585
- declare function parseSessionId(sessionId: string): {
1586
- userId: string;
1587
- endpointId: string;
1588
- };
1589
- /**
1590
- * Create E2EE key entry from runtime context
1591
- */
1592
- declare function createKeyEntry(userId: string, endpointId: string, keyPair: KeyPair, remotePublicKey: string, seq?: number): E2EEKeyEntry;
1593
-
1594
- /**
1595
- * secret-scan — local-side secret detection for memory team sync.
1596
- *
1597
- * Mirror of src/im/services/memory/team-sync.service.ts SECRET_PATTERNS.
1598
- * Kept in sync by convention — if you add a pattern there, add it here.
1599
- *
1600
- * Used by memory-team-sync.ts before POSTing bytes to the server (so secrets
1601
- * never leave the device). Server has its own independent scanner (defense
1602
- * in depth).
1603
- *
1604
- * Design: docs/version190/14e-memory-cc-compat.md §8.5
1605
- */
1606
- interface SecretHit {
1607
- /** Pattern name (e.g. 'aws-access-key'). */
1608
- pattern: string;
1609
- /** Truncated match (never more than 80 chars — no full secret echo). */
1610
- match: string;
1611
- /** 1-based line number. */
1612
- line: number;
1613
- /**
1614
- * If true, this hit is informational only — not strong enough evidence
1615
- * to block a push on its own (e.g. JWT-shaped strings).
1616
- */
1617
- warnOnly: boolean;
1618
- }
1619
- /** Scan content for known secret patterns. Returns the list of hits. */
1620
- declare function scanForSecrets(content: string): SecretHit[];
1621
- /**
1622
- * Convenience: true if content has at least one blocking (non-warnOnly) hit.
1623
- */
1624
- declare function hasBlockingSecret(content: string): boolean;
1625
-
1626
- /**
1627
- * memory-team-sync — client-side delta push + server-wins pull for team memory.
1628
- *
1629
- * Walks a local directory (typically `~/.claude/memory/team/<owner>/<repo>/`),
1630
- * diffs content hashes against a persisted `last-sync.json`, pushes only the
1631
- * changed files, and writes any server-side-newer rows back to disk.
1632
- *
1633
- * Design: docs/version190/14e-memory-cc-compat.md §8.5
1634
- *
1635
- * Secret scanning (local): any file whose content matches a blocking pattern
1636
- * is rejected before it leaves the device. The server also scans (defense in
1637
- * depth).
1638
- */
1639
- /** Per-file content size limit (matches server). */
1640
- declare const MEMORY_TEAM_SYNC_MAX_BYTES: number;
1641
- /** Name of the sidecar state file. */
1642
- declare const LAST_SYNC_FILE = ".prismer-team-sync.json";
1643
- interface SyncTeamMemoryOptions {
1644
- /** Team identifier, e.g. `'acme/widgets'`. */
1645
- team: string;
1646
- /** Root directory to sync (scanned recursively). */
1647
- rootDir: string;
1648
- /** Prismer API key (Bearer). */
1649
- apiKey: string;
1650
- /**
1651
- * Base URL for the IM API — typically the cloud host.
1652
- * e.g. `'https://prismer.cloud/api/im'` or `'http://localhost:3000/api/im'`.
1653
- */
1654
- baseUrl: string;
1655
- /**
1656
- * Optional override of the since timestamp. Normally we read this from the
1657
- * sidecar state file and ignore this param. Exposed mainly for testing.
1658
- */
1659
- since?: string;
1660
- /**
1661
- * Custom fetch (for tests). Defaults to the global fetch.
1662
- */
1663
- fetchImpl?: typeof fetch;
1664
- /**
1665
- * If true, do not write pulled[] rows to disk and do not update sidecar.
1666
- * Useful for dry-run/preflight.
1667
- */
1668
- dryRun?: boolean;
1669
- }
1670
- interface SyncTeamMemoryResult {
1671
- pushed: number;
1672
- pulled: number;
1673
- rejected: Array<{
1674
- path: string;
1675
- reason: string;
1676
- detail?: string;
1677
- }>;
1678
- skippedLocalSecrets: Array<{
1679
- path: string;
1680
- pattern: string;
1681
- line: number;
1682
- }>;
1683
- serverTime: string;
1684
- }
1685
- /** Walk rootDir recursively for .md files (only). Returns POSIX-style rel paths. */
1686
- declare function listMarkdownFiles(rootDir: string): string[];
1687
- /**
1688
- * Sync a team-memory directory with the cloud.
1689
- *
1690
- * 1. Walk rootDir for .md files
1691
- * 2. Hash each; diff against last-sync.json → push[] candidates
1692
- * 3. Local secret scan → any hits are skipped (not pushed)
1693
- * 4. POST /memory/team/sync with push[] and since
1694
- * 5. Write pulled[] to disk (server wins)
1695
- * 6. Update last-sync.json
1696
- */
1697
- declare function syncTeamMemory(opts: SyncTeamMemoryOptions): Promise<SyncTeamMemoryResult>;
1698
- /**
1699
- * Remove the sidecar state file — forces the next sync to re-push everything.
1700
- * Useful from CLI tooling.
1701
- */
1702
- declare function resetTeamSyncState(rootDir: string): void;
1703
-
1704
- /**
1705
- * Shamir Secret Sharing over GF(256) — byte-oriented implementation.
1706
- *
1707
- * Split a secret Buffer into N shares such that any M (threshold) shares can
1708
- * reconstruct the original, but fewer than M reveal zero information.
1709
- *
1710
- * Field: GF(256) with AES irreducible polynomial 0x11B.
1711
- * Addition = XOR. Multiplication = carryless multiply mod 0x11B.
1712
- * Share-id x ∈ {1..255} (x=0 is the secret itself).
1713
- *
1714
- * Each byte of the secret is split independently using a polynomial of degree
1715
- * m-1: P(x) = s + a_1*x + a_2*x^2 + ... + a_{m-1}*x^{m-1} (all arithmetic in GF(256))
1716
- * where s is the secret byte and a_1..a_{m-1} are uniformly random.
1717
- *
1718
- * Recovery uses Lagrange interpolation evaluated at x=0.
1719
- *
1720
- * Mnemonic format: Crockford base32 with 1-byte version header (0x01) and
1721
- * CRC-16/CCITT-FALSE checksum. Groups of 4 characters separated by hyphens.
1722
- *
1723
- * No external npm dependencies.
1724
- *
1725
- * See: Shamir, "How to Share a Secret", 1979. GF(256) byte-level variant used
1726
- * by industry (Trezor Shamir Backup, HashiCorp Vault, etc.).
1727
- */
1728
- /**
1729
- * Branded `Buffer` that has been validated as a Shamir share by this module.
1730
- *
1731
- * Nominal typing prevents accidentally passing an arbitrary `Buffer` (e.g.
1732
- * `Buffer.from('hello')`) into {@link combineShares} or
1733
- * {@link encodeShareAsMnemonic}. TypeScript structural equality is defeated
1734
- * by the `__brand` phantom field, so the only path to a `ShamirShare` value
1735
- * is through this module's own functions (`splitSecret`,
1736
- * `decodeShareFromMnemonic`) or the explicit escape hatch
1737
- * {@link unsafeAsShamirShare}.
1738
- *
1739
- * This is a compile-time guard only; runtime validation (duplicate ids,
1740
- * inconsistent lengths, CRC) still happens inside `combineShares` /
1741
- * `decodeShareFromMnemonic`.
1742
- */
1743
- type ShamirShare = Buffer & {
1744
- readonly __brand: unique symbol;
1745
- };
1746
- /**
1747
- * Escape hatch for interop paths that already hold raw share Buffers
1748
- * (e.g. legacy callers that read bytes off the wire themselves and cannot
1749
- * route through {@link decodeShareFromMnemonic}).
1750
- *
1751
- * This is a **sharp edge**: the caller is asserting the buffer is a
1752
- * well-formed share byte string (`[share_id, y_byte_1, y_byte_2, ...]` with
1753
- * `share_id ∈ 1..255`). Passing an arbitrary buffer here will compile, and
1754
- * will pass length / id / duplicate checks inside `combineShares`, but will
1755
- * reconstruct a plausibly-shaped yet **semantically wrong** secret.
1756
- *
1757
- * Prefer `decodeShareFromMnemonic` wherever possible — the CRC-16 check
1758
- * there catches tampered or wrong-batch shares.
1759
- */
1760
- declare function unsafeAsShamirShare(buf: Buffer): ShamirShare;
1761
- /**
1762
- * Split a secret into n shares; any m can recombine.
1763
- *
1764
- * Each returned share Buffer is [share_id_byte, y_byte_1, y_byte_2, ...].
1765
- * The share-id is 1..n (never 0).
1766
- *
1767
- * @param secret plaintext bytes
1768
- * @param n total shares (2..255)
1769
- * @param m threshold (2..n)
1770
- */
1771
- declare function splitSecret(secret: Buffer, n: number, m: number): ShamirShare[];
1772
- /**
1773
- * Combine shares to recover the secret. Any m of n suffice (where m is the
1774
- * threshold used at split time).
1775
- *
1776
- * @param shares array of share Buffers (each [x_byte, y_bytes...])
1777
- * @returns recovered secret
1778
- */
1779
- declare function combineShares(shares: ShamirShare[]): Buffer;
1780
- /**
1781
- * Encode a share as a mnemonic string.
1782
- *
1783
- * Framing (before base32 encoding):
1784
- * [0x01 version] [share bytes...] [CRC-16/CCITT-FALSE of (version||share)]
1785
- *
1786
- * Output is Crockford base32, grouped in blocks of 4 characters separated by
1787
- * hyphens for readability. Case-insensitive on decode.
1788
- */
1789
- declare function encodeShareAsMnemonic(share: ShamirShare): string;
1790
- /**
1791
- * Decode a mnemonic string back into a share Buffer. Strips whitespace,
1792
- * hyphens, and normalizes case. Validates the version byte and CRC-16.
1793
- */
1794
- declare function decodeShareFromMnemonic(encoded: string): ShamirShare;
1795
-
1796
- interface TimelineEntry {
1797
- seq: number;
1798
- opcode: number;
1799
- slot: number;
1800
- payload: Buffer;
1801
- createdAt: number;
1802
- }
1803
- interface OutboxEntry {
1804
- id: number;
1805
- seq: number;
1806
- frame: Buffer;
1807
- createdAt: number;
1808
- attempts: number;
1809
- }
1810
- interface DeadLetterEntry {
1811
- id: number;
1812
- originalId: number;
1813
- seq: number;
1814
- createdAt: number;
1815
- failedAt: number;
1816
- attempts: number;
1817
- }
1818
- interface DroppedFrame {
1819
- id: number;
1820
- seq: number;
1821
- attempts: number;
1822
- }
1823
- interface DaemonOutboxOptions {
1824
- bindingId: string;
1825
- dataDir?: string;
1826
- timelineCap?: number;
1827
- outboxCap?: number;
1828
- maxAttempts?: number;
1829
- onDrop?: (entries: DroppedFrame[]) => void;
1830
- }
1831
- declare class DaemonOutbox {
1832
- private db;
1833
- private bindingId;
1834
- private timelineCap;
1835
- private outboxCap;
1836
- private maxAttempts;
1837
- private onDrop?;
1838
- private currentSeq;
1839
- private droppedCount;
1840
- constructor(opts: DaemonOutboxOptions);
1841
- private initSchema;
1842
- appendSent(opcode: number, slot: number, payload: Buffer): number;
1843
- getTimelineSince(lastSeq: number, limit?: number): TimelineEntry[];
1844
- getCurrentSeq(): number;
1845
- private enforceTimelineCap;
1846
- queue(seq: number, frame: Buffer): number;
1847
- drain(limit?: number): OutboxEntry[];
1848
- ack(outboxId: number): void;
1849
- bumpAttempts(outboxId: number): {
1850
- attempts: number;
1851
- deadLettered: boolean;
1852
- };
1853
- private moveToDeadLetter;
1854
- getDeadLetterCount(): number;
1855
- getDeadLetterEntries(limit?: number, includeFrame?: boolean): (DeadLetterEntry & {
1856
- frame?: Buffer;
1857
- })[];
1858
- pendingCount(): number;
1859
- getDroppedCount(): number;
1860
- private enforceOutboxCap;
1861
- close(): void;
1862
- }
1863
- /** 2-byte header + payload per §5.6.4 */
1864
- declare function frameFromParts(opcode: number, slot: number, payload: Buffer): Buffer;
1865
-
1866
- /**
1867
- * Prismer Runtime — WSS Relay Client (v1.9.0)
1868
- *
1869
- * WebSocket client for cloud relay communication. Connects to the main
1870
- * cloud host (derived from `cloudApiBase`) under the `/ws/daemon/*` path
1871
- * prefix — there is no separate relay subdomain.
1872
- *
1873
- * Responsibilities:
1874
- * - Register daemon binding with API key
1875
- * - Receive remote command pushes (control channel)
1876
- * - Route encrypted envelopes (data channel)
1877
- * - Heartbeat keepalive (30s interval)
1878
- * - Auto-reconnect with exponential backoff
1879
- */
1880
-
1881
- declare const OPCODE: {
1882
- readonly JSON_CONTROL: 0;
1883
- readonly AGENT_OUTPUT: 1;
1884
- readonly TERMINAL_IO: 2;
1885
- readonly FILE_CHUNK: 3;
1886
- readonly AUDIT_TAP: 4;
1887
- readonly BACKFILL_REQUEST: 5;
1888
- readonly BACKFILL_CHUNK: 6;
1889
- };
1890
- interface RelayClientOptions {
1891
- apiKey: string;
1892
- daemonId: string;
1893
- userId: string;
1894
- /**
1895
- * Base WSS URL for the relay (e.g. `wss://cloud.prismer.dev`). The client
1896
- * appends `/ws/daemon/control` and `/ws/daemon/data` to this base. Callers
1897
- * typically derive it from `cloudApiBase` via `deriveWsFromHttp()`.
1898
- */
1899
- relayUrl: string;
1900
- heartbeatIntervalMs?: number;
1901
- reconnectDelayMs?: number;
1902
- maxReconnectDelayMs?: number;
1903
- autoReconnect?: boolean;
1904
- /** v1.9.0 — bindingId enables daemon-side outbox + timeline backfill (§5.6.5). */
1905
- bindingId?: string;
1906
- /** Override outbox location (for tests); defaults to ~/.prismer/daemon/{bindingId}. */
1907
- outboxDataDir?: string;
1908
- }
1909
- interface RelayState {
1910
- connected: boolean;
1911
- channel: 'control' | 'data' | null;
1912
- lastHeartbeat?: number;
1913
- reconnectAttempts: number;
1914
- lastError?: string;
1915
- }
1916
- interface RemoteCommand {
1917
- id: string;
1918
- type: string;
1919
- payload: Record<string, unknown>;
1920
- createdAt: number;
1921
- }
1922
- declare class RelayClient extends EventEmitter {
1923
- private apiKey;
1924
- private daemonId;
1925
- private userId;
1926
- private relayUrl;
1927
- private heartbeatIntervalMs;
1928
- private reconnectDelayMs;
1929
- private maxReconnectDelayMs;
1930
- private autoReconnect;
1931
- private controlWs;
1932
- private dataWs;
1933
- private heartbeatInterval?;
1934
- private heartbeatTimer?;
1935
- private reconnectTimer?;
1936
- private state;
1937
- private isShuttingDown;
1938
- private outbox?;
1939
- constructor(opts: RelayClientOptions);
1940
- /**
1941
- * Connect to relay server (both control and data channels)
1942
- */
1943
- connect(): Promise<void>;
1944
- /**
1945
- * Disconnect from relay server
1946
- */
1947
- disconnect(): Promise<void>;
1948
- /**
1949
- * Send command to mobile client via relay (data channel).
1950
- *
1951
- * v1.9.0 — if bindingId was provided, every tracked data-plane frame
1952
- * (AGENT_OUTPUT / TERMINAL_IO / FILE_CHUNK) is recorded in the local
1953
- * timeline before send. If the data channel is down, the frame is queued
1954
- * to the outbox and will be replayed on next successful connect.
1955
- */
1956
- /**
1957
- * Send JSON control message to cloud via the control channel.
1958
- * v1.9.x — used by daemon to ack remote commands (e.g. command.result).
1959
- * Returns false silently if control channel is not connected.
1960
- */
1961
- sendControl(message: unknown): boolean;
1962
- sendCommand(data: Buffer | string): boolean;
1963
- /**
1964
- * Get current connection state
1965
- */
1966
- getState(): RelayState;
1967
- /**
1968
- * Get connection status summary
1969
- */
1970
- getStatus(): {
1971
- controlConnected: boolean;
1972
- dataConnected: boolean;
1973
- lastHeartbeat?: number;
1974
- reconnectAttempts: number;
1975
- };
1976
- /**
1977
- * Connect to control channel (/ws/daemon/control)
1978
- */
1979
- private connectControlChannel;
1980
- /**
1981
- * Connect to data channel (/ws/daemon/data)
1982
- */
1983
- private connectDataChannel;
1984
- private relayEndpoint;
1985
- /**
1986
- * Register daemon with relay server
1987
- */
1988
- private registerDaemon;
1989
- /**
1990
- * Handle incoming control channel messages
1991
- */
1992
- private handleControlMessage;
1993
- /** RPC method handlers registered by the daemon process. Keyed by method
1994
- * name (e.g. 'fs.read'). Result is serialized into the rpc.response
1995
- * envelope. Thrown errors → `error` field. */
1996
- private rpcHandlers;
1997
- /** Register an RPC handler. Daemon code calls this at startup for each
1998
- * method it wants to expose to cloud relay (mobile → cloud → daemon). */
1999
- registerRpcHandler(method: string, handler: (params: unknown) => Promise<unknown>): void;
2000
- private handleRpcRequest;
2001
- private sendRpcResponse;
2002
- /**
2003
- * Handle incoming data channel messages.
2004
- *
2005
- * v1.9.0 — intercept backfill-request (opcode 0x05) from the cloud
2006
- * (cloud forwards it on behalf of a reconnecting mobile client) and
2007
- * respond with backfill-chunk frames (opcode 0x06) for every timeline
2008
- * entry with seq > payload.lastSeq.
2009
- */
2010
- private handleDataMessage;
2011
- /**
2012
- * Drain outbox by replaying queued frames over the data channel.
2013
- * Called after reconnect() succeeds. Stops on the first send failure
2014
- * to preserve ordering.
2015
- */
2016
- private replayOutbox;
2017
- /** Pending count for status reporting. */
2018
- getOutboxPending(): number;
2019
- /**
2020
- * Handle remote command from mobile
2021
- */
2022
- private handleRemoteCommand;
2023
- /**
2024
- * Start heartbeat interval
2025
- */
2026
- private startHeartbeat;
2027
- /**
2028
- * Clear heartbeat timers
2029
- */
2030
- private clearHeartbeat;
2031
- /**
2032
- * Send heartbeat to relay
2033
- */
2034
- private sendHeartbeat;
2035
- /**
2036
- * Acknowledge heartbeat from relay
2037
- */
2038
- private sendHeartbeatAck;
2039
- /**
2040
- * Handle disconnection from one or both channels
2041
- */
2042
- private handleDisconnect;
2043
- /**
2044
- * Schedule reconnection with exponential backoff
2045
- */
2046
- private scheduleReconnect;
2047
- /**
2048
- * Clear reconnect timer
2049
- */
2050
- private clearReconnectTimer;
2051
- /**
2052
- * Close control channel
2053
- */
2054
- private closeControlChannel;
2055
- /**
2056
- * Close data channel
2057
- */
2058
- private closeDataChannel;
2059
- }
2060
-
2061
- declare const RUNTIME_VERSION = "1.9.0";
2062
-
2063
- export { AGENT_CATALOG, type AdapterDescriptor, type AdapterDispatchInput, type AdapterDispatchResult, type AdapterImpl, AdapterRegistry, type AgentCatalogEntry, type AgentDescriptor, type AgentState, type AgentStatus, AgentSupervisor, AllProvidersFailedError, type AnalyzeRequest, type AssignTaskRequest, type AuthenticatedIdentity, type CancelTaskRequest, type CliContext, ConfigError, type CreateGeneRequest, DaemonAlreadyRunningError, type DaemonHttpOptions, DaemonHttpServer, type DaemonOptions, DaemonOutbox, type DaemonOutboxOptions, DaemonProcess, type DaemonRunnerHandle, type DaemonRunnerOptions, type DaemonState, DispatchMux, type DispatchMuxRequest, type DispatchMuxResult, type DistillationRequest, type DreamCompaction, type DreamResult, DreamScheduler, type DreamSchedulerOptions, type E2EEContext, type E2EEKeyEntry, type KeyPair as E2EEKeyPair, E2EEKeyStorage, type E2EEStorageStats, type EncryptedEnvelope, type EncryptionConfig, EventBus, type EventBusEnvelope, type EventBusOptions, EvolutionGatewayHttpHandler, type EvolutionGatewayOptions, type HookConfig, type HookEntry, type HookFormat, Keychain, type KeychainAdapter, type KeychainBackend, KeychainOperationError, type KeychainOptions, LAST_SYNC_FILE, LLMDispatcher, type LLMMessage, type LLMProvider, type LLMRequest, type LLMResponse, type ListMemoryRequest, type LoadConfigOptions, MEMORY_TEAM_SYNC_MAX_BYTES, MemoryDB, type MemoryFile, type MemoryFileVersion, type MemoryResponse, type MergeOptions, type MergeResult, type MigrateOptions, type MigrateResult, type MigrateSecretsOptions, type MigrateSecretsResult, NoKeychainBackendError, OPCODE, type OutboxEntry, type OutputMode, type PairOffer, type PairedDevice, type PrismerConfig, type ProviderStats, RUNTIME_VERSION, type RecallRequest, type RecordRequest, RelayClient, type RelayClientOptions, type RelayState, type RemoteCommand, type RouteHandler, type RouteTaskRequest, type RouteTaskResponse, type RoutingPolicy, type SecretHit, type ShamirShare, type ShutdownHandler, type SignalExtractionRequest, type StepCompletedRequest, type StepFailedRequest, type StepTimeoutRequest, type Subscription, type SubscriptionHandler, type SupervisorOptions, type SyncTeamMemoryOptions, type SyncTeamMemoryResult, type TableOptions, type TableRow, type TaskInfo, TaskRouteState, TaskRouter, type TaskRouterOptions, type TimelineEntry, TraceWriter, TraceWriterManager, type TraceWriterManagerOptions, type TraceWriterOptions, UI, type UIOptions, type WriteMemoryRequest, applyCommonFlags, assertBrandVoice, closeMemoryDB, combineShares, createCliContext, createDreamScheduler, createE2EEContext, createKeyEntry, decodeShareFromMnemonic, decrypt, decryptMessage, deriveKey, deriveSessionKeys, deriveSharedSecret, deserializeEnvelope, encodeShareAsMnemonic, encrypt, encryptMessage, frameFromParts, generateKeyPair as generateE2EEKeyPair, generateSalt, generateSessionId, getAgent, getMemoryDB, getUI, hasBlockingSecret, installHooks, listMarkdownFiles, loadConfig, mergeHooks, migrateSecrets, parseKeyringPlaceholder, parseSessionId, readHookConfig, resetTeamSyncState, rollbackHooks, runDream, scanForSecrets, serializeEnvelope, setUI, splitSecret, startDaemonRunner, syncTeamMemory, unsafeAsShamirShare, writeConfig, writeHookConfig };