dsh-deeppilot 0.3.0 → 0.5.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/lib/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { IncomingMessage } from "node:http";
2
1
  import z from "@deepseek-ai/schemastery";
3
2
  import { Context } from "@deepseek-ai/cordis";
4
3
  //#region src/protocol.d.ts
@@ -26,6 +25,51 @@ interface SessionSummary {
26
25
  workspaceId?: string | null;
27
26
  workspacePath?: string | null;
28
27
  }
28
+ type MessageRole = 'user' | 'assistant' | 'tool' | 'system' | 'error';
29
+ type ToolState = 'running' | 'ok' | 'error';
30
+ /** Provenance of host-injected context; present only on `role: "system"` rows.
31
+ * Mirrors the durable DSH message source (`dsh-llm` MessageSource): `label`
32
+ * names the producer (plugin name, skill name, instruction paths…), `form` is
33
+ * the semantic ContextForm vocabulary ('instructions' | 'catalog' | 'snapshot'
34
+ * | 'notice' | 'relay' | 'recall'). Both degrade gracefully — clients must
35
+ * tolerate absent fields and unknown values. */
36
+ interface MessageContextInfo {
37
+ label?: string;
38
+ form?: string;
39
+ }
40
+ /** One image carried by a user message. `attachmentId` keys the read-back RPC
41
+ * (c2s.session.attachment); width/height let clients reserve layout space. */
42
+ interface MessageAttachment {
43
+ kind: 'image';
44
+ name?: string;
45
+ mediaType?: string;
46
+ attachmentId?: string;
47
+ width?: number;
48
+ height?: number;
49
+ }
50
+ interface MessageProjection {
51
+ /** Durable row identity; unique within one session/page. */
52
+ seq: number;
53
+ role: MessageRole;
54
+ text?: string;
55
+ /** Reasoning ("thinking") text accompanying the answer, when present. */
56
+ thinking?: string;
57
+ streaming?: boolean;
58
+ tool?: {
59
+ name: string;
60
+ state: ToolState;
61
+ summary: string;
62
+ };
63
+ attachments?: MessageAttachment[];
64
+ /** Present only on system rows: provenance of the injected context.
65
+ * The DSH host logs synthetic agent.inject() content (runtime-context
66
+ * snapshots, background-job notices, workspace instructions…) as user-role
67
+ * messages whose `source.kind` is not 'user'; those project here as
68
+ * `role: "system"` so clients never show them as human prompts. */
69
+ context?: MessageContextInfo;
70
+ ts: number;
71
+ truncated?: boolean;
72
+ }
29
73
  type NotifyCategory = 'turn.completed' | 'approval.required' | 'question.asked' | 'session.error';
30
74
  /**
31
75
  * One offline-push-worthy event (same facts as s2c.notify / pending frames,
@@ -66,7 +110,7 @@ interface PendingSnapshotPayload {
66
110
  questions: PendingQuestionPayload[];
67
111
  }
68
112
  //#endregion
69
- //#region src/host-bridge.d.ts
113
+ //#region src/host-api.d.ts
70
114
  interface RpcOk<T> {
71
115
  ok: true;
72
116
  value: T;
@@ -250,7 +294,9 @@ interface PhoneSessionRow {
250
294
  sessionId: string;
251
295
  updatedAt: number;
252
296
  running: boolean;
253
- blank: boolean;
297
+ /** Host marks never-prompted sessions as blank; informational only — the
298
+ * summary projects them as idle (see toSummary) so phones can send. */
299
+ blank?: boolean;
254
300
  cwd?: string;
255
301
  origin?: string;
256
302
  parentSessionId?: string;
@@ -355,6 +401,8 @@ interface PushOutlet {
355
401
  */
356
402
  isAvailable(): boolean;
357
403
  }
404
+ //#endregion
405
+ //#region src/host-bridge.d.ts
358
406
  declare class HostBridge {
359
407
  private readonly apiProxy;
360
408
  private readonly historyBufferMax;
@@ -367,7 +415,10 @@ declare class HostBridge {
367
415
  private sinks;
368
416
  private ring;
369
417
  private cursor;
418
+ private userReceiptSeq;
370
419
  private abort;
420
+ private started;
421
+ private disposed;
371
422
  constructor(apiProxy: ApiProxyLike, historyBufferMax?: number);
372
423
  private pushOutlet;
373
424
  /**
@@ -381,6 +432,7 @@ declare class HostBridge {
381
432
  approvals: boolean;
382
433
  questions: boolean;
383
434
  pendingSnapshot: boolean;
435
+ notifyAllCategories: boolean;
384
436
  models: boolean;
385
437
  sessionManagement: boolean;
386
438
  projectSelection: boolean;
@@ -399,6 +451,12 @@ declare class HostBridge {
399
451
  markSinkClosed(sink: BridgeSink, sessionId: string): void;
400
452
  dropSinkSessions(sink: BridgeSink): void;
401
453
  private isViewedBy;
454
+ /** F-9: when a notification-worthy event fires, mirror it to every
455
+ * online device that is not currently viewing the session (the s2c.notify
456
+ * frame counts toward the seq cursor and joins the replay ring per
457
+ * PROTOCOL §6 + §7), then fan the same payload out to offline devices
458
+ * holding an APNs token. */
459
+ private emitNotify;
402
460
  /** F-9: when a turn completes, notify every device not viewing the session. */
403
461
  private emitTurnCompletedNotify;
404
462
  /**
@@ -438,7 +496,11 @@ declare class HostBridge {
438
496
  pendingSnapshot(): PendingSnapshotPayload;
439
497
  /** Tail history for an opened session; pushes s2c.session.tail to the sink. */
440
498
  openSession(sink: BridgeSink, sessionId: string, tailCount: number): Promise<boolean>;
441
- historyPage(sink: BridgeSink, sessionId: string, beforeSeq: number, limit: number): Promise<boolean>;
499
+ historyPage(sessionId: string, beforeSeq: number, limit: number): Promise<{
500
+ sessionId: string;
501
+ messages: MessageProjection[];
502
+ hasMore: boolean;
503
+ } | null>;
442
504
  /** Result of one attachment read-back for the phone. */
443
505
  attachmentData(sessionId: string, attachmentId: string): Promise<{
444
506
  mediaType?: string;
@@ -480,29 +542,11 @@ declare class HostBridge {
480
542
  respondQuestion(requestId: string, answers: unknown): Promise<PendingResponseOutcome>;
481
543
  }
482
544
  //#endregion
483
- //#region src/index.d.ts
484
- /**
485
- * dsh-deeppilot — data bridge between the DSH host and DeepPilot
486
- * clients. Registers exactly one WebSocket upgrade route (/phone) plus an
487
- * optional health probe (/phone/health) on the existing web server. The web
488
- * UI is never touched.
489
- *
490
- * Data plane: an in-process HostBridge consumes apiProxy.events.mux()/host()
491
- * streams, mirrors session summaries, tracks pending approvals/questions,
492
- * and fans projected protocol-v1 pushes out to every connected device.
493
- *
494
- * Protocol: src/protocol.ts, v1. The private app repository carries the
495
- * matching normative document and Swift models.
496
- */
497
- declare const name = "deeppilot";
498
- /** No eager service requirement: profiles without a web stack simply skip. */
499
- declare const inject: string[];
545
+ //#region src/config.d.ts
500
546
  interface Config {
501
547
  /** Master switch; when false the plugin activates and does nothing. */
502
548
  enabled?: boolean;
503
- /** Pairing token file (0600); generated on first boot when missing. */
504
- authTokenPath?: string;
505
- /** Paired-device registry JSON path. */
549
+ /** Protocol-v2 device registry JSON path. */
506
550
  devicesPath?: string;
507
551
  /** Replay ring buffer bound (frames) per deployment. */
508
552
  historyBufferMax?: number;
@@ -511,35 +555,32 @@ interface Config {
511
555
  /** Optional embedded remote transport. Reconciled when settings change. */
512
556
  remote?: {
513
557
  enabled?: boolean;
514
- provider?: string;
558
+ provider?: 'tailscale-funnel';
515
559
  hostname?: string;
516
560
  statePath?: string;
517
561
  helperPath?: string;
518
- funnelPort?: number;
562
+ funnelPort?: 443 | 8443 | 10000;
563
+ /** Concurrent Funnel WebSockets allowed from one public source address. */
564
+ maxConnectionsPerSource?: number;
519
565
  };
520
566
  /**
521
- * Offline push (F-9). provider 'apns' sends direct Apple Push Notification
522
- * deliveries from this Mac outbound-only, no relay server, requires the
523
- * user's own Apple developer credentials. provider 'relay' forwards notify
524
- * projections to an operator-run relay (relay/server.js) holding the
525
- * distributor's key — used when the App ships via TestFlight/App Store.
526
- *
527
- * Deliberately NO environment knob here: each device reports its own
528
- * environment when registering (derived from its build kind), and
529
- * deliveries route per device — mixed dev/TestFlight phones coexist.
567
+ * Offline push (F-9). `apns` sends directly from the Mac with the user's
568
+ * Apple credentials. `relay` sends notify projections to an operator-run
569
+ * relay for distributed builds. The device reports its own APNs environment,
570
+ * so development and TestFlight/App Store devices may coexist.
530
571
  */
531
572
  push?: {
532
- /** 'none' (default) | 'apns' | 'relay'. */
533
- provider?: string;
573
+ /** `none` (default), `apns`, or `relay`. */
574
+ provider?: 'none' | 'apns' | 'relay';
534
575
  /** Apple Developer team id (JWT iss claim). */
535
576
  teamId?: string;
536
577
  /** APNs auth key id (JWT kid header). */
537
578
  keyId?: string;
538
- /** .p8 private key path; generated keys live under the bridge data dir. */
579
+ /** `.p8` private key path. */
539
580
  keyPath?: string;
540
581
  /** App bundle id — the apns-topic header. */
541
582
  bundleId?: string;
542
- /** Relay base URL (https). See relay/README.md. */
583
+ /** Relay base URL. */
543
584
  relayUrl?: string;
544
585
  /** Per-user bearer token issued by the relay operator. */
545
586
  relayToken?: string;
@@ -547,27 +588,28 @@ interface Config {
547
588
  }
548
589
  declare const Config: z<Schemastery.ObjectS<{
549
590
  enabled: z<boolean, boolean>;
550
- authTokenPath: z<string, string>;
551
591
  devicesPath: z<string, string>;
552
592
  historyBufferMax: z<number, number>;
553
593
  debug: z<boolean, boolean>;
554
594
  remote: z<Schemastery.ObjectS<{
555
595
  enabled: z<boolean, boolean>;
556
- provider: z<string, string>;
596
+ provider: z<"tailscale-funnel", "tailscale-funnel">;
557
597
  hostname: z<string, string>;
558
598
  statePath: z<string, string>;
559
599
  helperPath: z<string, string>;
560
- funnelPort: z<number, number>;
600
+ funnelPort: z<443 | 8443 | 10000, 443 | 8443 | 10000>;
601
+ maxConnectionsPerSource: z<number, number>;
561
602
  }>, Schemastery.ObjectT<{
562
603
  enabled: z<boolean, boolean>;
563
- provider: z<string, string>;
604
+ provider: z<"tailscale-funnel", "tailscale-funnel">;
564
605
  hostname: z<string, string>;
565
606
  statePath: z<string, string>;
566
607
  helperPath: z<string, string>;
567
- funnelPort: z<number, number>;
608
+ funnelPort: z<443 | 8443 | 10000, 443 | 8443 | 10000>;
609
+ maxConnectionsPerSource: z<number, number>;
568
610
  }>>;
569
611
  push: z<Schemastery.ObjectS<{
570
- provider: z<string, string>;
612
+ provider: z<"none" | "apns" | "relay", "none" | "apns" | "relay">;
571
613
  teamId: z<string, string>;
572
614
  keyId: z<string, string>;
573
615
  keyPath: z<string, string>;
@@ -575,7 +617,7 @@ declare const Config: z<Schemastery.ObjectS<{
575
617
  relayUrl: z<string, string>;
576
618
  relayToken: z<string, string>;
577
619
  }>, Schemastery.ObjectT<{
578
- provider: z<string, string>;
620
+ provider: z<"none" | "apns" | "relay", "none" | "apns" | "relay">;
579
621
  teamId: z<string, string>;
580
622
  keyId: z<string, string>;
581
623
  keyPath: z<string, string>;
@@ -585,27 +627,28 @@ declare const Config: z<Schemastery.ObjectS<{
585
627
  }>>;
586
628
  }>, Schemastery.ObjectT<{
587
629
  enabled: z<boolean, boolean>;
588
- authTokenPath: z<string, string>;
589
630
  devicesPath: z<string, string>;
590
631
  historyBufferMax: z<number, number>;
591
632
  debug: z<boolean, boolean>;
592
633
  remote: z<Schemastery.ObjectS<{
593
634
  enabled: z<boolean, boolean>;
594
- provider: z<string, string>;
635
+ provider: z<"tailscale-funnel", "tailscale-funnel">;
595
636
  hostname: z<string, string>;
596
637
  statePath: z<string, string>;
597
638
  helperPath: z<string, string>;
598
- funnelPort: z<number, number>;
639
+ funnelPort: z<443 | 8443 | 10000, 443 | 8443 | 10000>;
640
+ maxConnectionsPerSource: z<number, number>;
599
641
  }>, Schemastery.ObjectT<{
600
642
  enabled: z<boolean, boolean>;
601
- provider: z<string, string>;
643
+ provider: z<"tailscale-funnel", "tailscale-funnel">;
602
644
  hostname: z<string, string>;
603
645
  statePath: z<string, string>;
604
646
  helperPath: z<string, string>;
605
- funnelPort: z<number, number>;
647
+ funnelPort: z<443 | 8443 | 10000, 443 | 8443 | 10000>;
648
+ maxConnectionsPerSource: z<number, number>;
606
649
  }>>;
607
650
  push: z<Schemastery.ObjectS<{
608
- provider: z<string, string>;
651
+ provider: z<"none" | "apns" | "relay", "none" | "apns" | "relay">;
609
652
  teamId: z<string, string>;
610
653
  keyId: z<string, string>;
611
654
  keyPath: z<string, string>;
@@ -613,7 +656,7 @@ declare const Config: z<Schemastery.ObjectS<{
613
656
  relayUrl: z<string, string>;
614
657
  relayToken: z<string, string>;
615
658
  }>, Schemastery.ObjectT<{
616
- provider: z<string, string>;
659
+ provider: z<"none" | "apns" | "relay", "none" | "apns" | "relay">;
617
660
  teamId: z<string, string>;
618
661
  keyId: z<string, string>;
619
662
  keyPath: z<string, string>;
@@ -622,9 +665,41 @@ declare const Config: z<Schemastery.ObjectS<{
622
665
  relayToken: z<string, string>;
623
666
  }>>;
624
667
  }>>;
625
- /** Authorization is preferred; the query form remains for older app builds. */
626
- declare function requestToken(req: Pick<IncomingMessage, 'url' | 'headers'>): string | null;
668
+ //#endregion
669
+ //#region src/push-policy.d.ts
670
+ /** Prune only when the provider supplies an authoritative token-lifecycle verdict. */
671
+ declare function shouldPrunePushToken(outcome: 'sent' | 'invalid-token' | 'failed', reason?: string): boolean;
672
+ /**
673
+ * Zero-touch relay self-heal: HTTP 401 means the relay no longer honors the
674
+ * cached credential. Only auto-enrolled cells with a still-current token may
675
+ * re-derive it; an explicitly configured relay token remains user-owned
676
+ * configuration and is never silently rewritten.
677
+ */
678
+ declare function shouldReEnrollRelayToken(transport: 'apns' | 'relay', outcome: 'sent' | 'invalid-token' | 'failed', reason: string | undefined, opts: {
679
+ usedCellToken: boolean;
680
+ hasEnrollKey: boolean;
681
+ tokenStillCurrent: boolean;
682
+ }): boolean;
683
+ //#endregion
684
+ //#region src/index.d.ts
685
+ /**
686
+ * dsh-deeppilot — data bridge between the DSH host and DeepPilot
687
+ * clients. Registers exactly one WebSocket upgrade route (/phone) plus an
688
+ * optional health probe (/phone/health) on the existing web server. The web
689
+ * UI is never touched.
690
+ *
691
+ * Data plane: an in-process HostBridge consumes a local compatibility façade
692
+ * over DSH 0.1.2 Session/Workspace controllers, mirrors session summaries,
693
+ * tracks pending approvals/questions, and fans projected protocol-v2 pushes
694
+ * out to every connected device.
695
+ *
696
+ * Protocol: PROTOCOL.md is normative; src/protocol.ts and the private app's
697
+ * Swift models mirror that v2 contract.
698
+ */
699
+ declare const name = "deeppilot";
700
+ /** No eager service requirement: profiles without a web stack simply skip. */
701
+ declare const inject: string[];
627
702
  declare function apply(ctx: Context, options: unknown): void;
628
703
  //#endregion
629
- export { Config, HostBridge, apply, inject, name, requestToken };
704
+ export { Config, HostBridge, apply, inject, name, shouldPrunePushToken, shouldReEnrollRelayToken };
630
705
  //# sourceMappingURL=index.d.ts.map