soulnet-dsh 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.
Files changed (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +64 -0
  3. package/cordis.patch.yml +40 -0
  4. package/lib/client.js +5427 -0
  5. package/lib/client.js.map +1 -0
  6. package/lib/commands.js +94 -0
  7. package/lib/commands.js.map +1 -0
  8. package/lib/events-Cz7g9aXF.js +134 -0
  9. package/lib/events-Cz7g9aXF.js.map +1 -0
  10. package/lib/events-DHPK3pow.js +134 -0
  11. package/lib/events-DHPK3pow.js.map +1 -0
  12. package/lib/events-DViXNRAZ.js +9 -0
  13. package/lib/events-DViXNRAZ.js.map +1 -0
  14. package/lib/index.js +2547 -0
  15. package/lib/index.js.map +1 -0
  16. package/lib/policy-HQKLctKr.js +96 -0
  17. package/lib/policy-HQKLctKr.js.map +1 -0
  18. package/lib/send-BL_Yr40O.js +33 -0
  19. package/lib/send-BL_Yr40O.js.map +1 -0
  20. package/lib/send-DcYQC5CC.js +127 -0
  21. package/lib/send-DcYQC5CC.js.map +1 -0
  22. package/lib/sessions.js +1197 -0
  23. package/lib/sessions.js.map +1 -0
  24. package/lib/tools.js +342 -0
  25. package/lib/tools.js.map +1 -0
  26. package/lib/types/alter-state.d.ts +185 -0
  27. package/lib/types/api/index.d.ts +52 -0
  28. package/lib/types/client/A2ANode.d.ts +4 -0
  29. package/lib/types/client/AlterPane.d.ts +9 -0
  30. package/lib/types/client/ChatPane.d.ts +13 -0
  31. package/lib/types/client/DraftCard.d.ts +11 -0
  32. package/lib/types/client/FriendComposer.d.ts +20 -0
  33. package/lib/types/client/FriendList.d.ts +12 -0
  34. package/lib/types/client/FriendPane.d.ts +13 -0
  35. package/lib/types/client/Inbox.d.ts +9 -0
  36. package/lib/types/client/InboxOverlay.d.ts +8 -0
  37. package/lib/types/client/Onboarding.d.ts +4 -0
  38. package/lib/types/client/SettingsSection.d.ts +29 -0
  39. package/lib/types/client/SidebarEntry.d.ts +9 -0
  40. package/lib/types/client/SoulmirrorPage.d.ts +12 -0
  41. package/lib/types/client/SoulmirrorView.d.ts +5 -0
  42. package/lib/types/client/a2a-node.d.ts +46 -0
  43. package/lib/types/client/alter-ui.d.ts +35 -0
  44. package/lib/types/client/api.d.ts +424 -0
  45. package/lib/types/client/inbox-state.d.ts +57 -0
  46. package/lib/types/client/index.d.ts +30 -0
  47. package/lib/types/client/locales.d.ts +239 -0
  48. package/lib/types/client/page-state.d.ts +116 -0
  49. package/lib/types/client/page-store.d.ts +96 -0
  50. package/lib/types/client/panel-store.d.ts +30 -0
  51. package/lib/types/client/styles.d.ts +2 -0
  52. package/lib/types/commands/index.d.ts +24 -0
  53. package/lib/types/drafts.d.ts +50 -0
  54. package/lib/types/events.d.ts +61 -0
  55. package/lib/types/friend-settings.d.ts +41 -0
  56. package/lib/types/index.d.ts +43 -0
  57. package/lib/types/network/fake.d.ts +10 -0
  58. package/lib/types/network/jsonrpc.d.ts +52 -0
  59. package/lib/types/network/send.d.ts +19 -0
  60. package/lib/types/network/soulnet.d.ts +123 -0
  61. package/lib/types/network/types.d.ts +203 -0
  62. package/lib/types/persona.d.ts +45 -0
  63. package/lib/types/policy.d.ts +105 -0
  64. package/lib/types/sessions/index.d.ts +182 -0
  65. package/lib/types/settings.d.ts +58 -0
  66. package/lib/types/tools/define.d.ts +35 -0
  67. package/lib/types/tools/index.d.ts +57 -0
  68. package/lib/types-zwvjR1n5.js +29 -0
  69. package/lib/types-zwvjR1n5.js.map +1 -0
  70. package/package.json +133 -0
  71. package/presets/soulmirror-chat/agent.cordis.yml +24 -0
  72. package/presets/soulmirror-chat/preset.yml +3 -0
@@ -0,0 +1,185 @@
1
+ /**
2
+ * What the owner needs to know about their alter, folded from the alter
3
+ * session's durable event log (P3, reshaped in P4 for ONE alter session) —
4
+ * pure, unit-tested in test/alter-state.test.ts:
5
+ *
6
+ * - `triggerOf(events)`: what woke the CURRENT turn — the owner (a
7
+ * `user/message` with `source.kind === 'user'`), mail from a friend (the
8
+ * relay `user/message` the sessions plugin delivers; the trigger carries
9
+ * that friend's fingerprint / name), an auto-flagged mail, or unknown.
10
+ * `soulmirror_send_message` reads this to decide send-now vs draft
11
+ * (src/policy.ts `sendGate`); the persona variables resolve the per-turn
12
+ * friend context from it.
13
+ * - `latestFromEvents(events)`: the alter's latest state — its latest words
14
+ * to the owner (last assistant text), the last owner instruction, the
15
+ * last `soulmirror_send_message` call and its outcome (sent / draft
16
+ * queued / refused), and how the last turn ended.
17
+ * - `chatFromEvents(events)`: the transcript the SoulMirror page renders
18
+ * for "My alter": owner messages, the alter's replies, inbound mail from
19
+ * friends (with the friend context), what the alter sent / queued, the
20
+ * plugin's notes (draft decisions) and failed turns.
21
+ *
22
+ * The fold reads plain event envelopes (`{ type, seq, time, data }`) so it
23
+ * needs no dsh value import; `Session.events` satisfies the shape.
24
+ */
25
+ import type { TurnTrigger } from './policy.ts';
26
+ import { type A2ANoteKind } from './events.ts';
27
+ export interface EventLike {
28
+ readonly type: string;
29
+ readonly seq: number;
30
+ readonly time: number;
31
+ readonly data: unknown;
32
+ }
33
+ export interface AlterNote {
34
+ readonly text: string;
35
+ readonly ts: number;
36
+ readonly seq: number;
37
+ readonly turn: number;
38
+ }
39
+ export interface AlterInstruction {
40
+ readonly text: string;
41
+ readonly ts: number;
42
+ readonly seq: number;
43
+ }
44
+ /** Outcome of a `soulmirror_send_message` call as the tool reported it. */
45
+ export type SendOutcome = 'sent' | 'draft-queued' | 'refused' | 'failed';
46
+ export interface AlterSend {
47
+ readonly body: string;
48
+ readonly fingerprint?: string;
49
+ readonly ts: number;
50
+ /** Undefined while the tool result is pending. */
51
+ readonly outcome?: SendOutcome;
52
+ /** The gate reason the tool reported (`owner-initiated`, `draft-tier`, …). */
53
+ readonly gate?: string;
54
+ /** Draft id when the outcome is `draft-queued`. */
55
+ readonly draftId?: string;
56
+ /** Error / refusal text when not sent. */
57
+ readonly detail?: string;
58
+ }
59
+ export interface AlterTurn {
60
+ readonly turn: number;
61
+ readonly reason: string;
62
+ readonly failed: boolean;
63
+ readonly ts: number;
64
+ readonly message?: string;
65
+ /** The turn is still open (no `turn/end` yet). */
66
+ readonly open: boolean;
67
+ }
68
+ export interface AlterLatest {
69
+ /** The last owner instruction in the log. */
70
+ readonly instruction?: AlterInstruction;
71
+ /** The alter's latest words to the owner (last assistant text). */
72
+ readonly note?: AlterNote;
73
+ /** The last `soulmirror_send_message` call. */
74
+ readonly sent?: AlterSend;
75
+ /** The latest turn (open or closed). */
76
+ readonly turn?: AlterTurn;
77
+ /** What woke the latest turn. */
78
+ readonly trigger: TurnTrigger;
79
+ /** Number of events folded (the page uses it as a change marker). */
80
+ readonly seq: number;
81
+ }
82
+ export declare const EMPTY_LATEST: AlterLatest;
83
+ /** Concatenate the text blocks of a message's content. */
84
+ export declare function textOf(content: unknown): string;
85
+ /** The relay `a2a` block of a user/message, when the source is ours. */
86
+ export declare function relayMetaOf(data: unknown): {
87
+ fp: string;
88
+ id: string;
89
+ ts: number;
90
+ name: string;
91
+ auto: boolean;
92
+ type?: string;
93
+ note?: A2ANoteKind;
94
+ draftId?: string;
95
+ } | undefined;
96
+ /** Classify one `user/message` by its source: owner / inbound / inbound-auto / note (ours, not mail) / other. */
97
+ export declare function classifyUserMessage(data: unknown): 'owner' | 'inbound' | 'inbound-auto' | 'note' | 'other';
98
+ /**
99
+ * What woke the current (latest) turn: the first attributable `user/message`
100
+ * after the last `turn/start`. No turn, or only tool results / injected
101
+ * context / plugin notes in it → `unknown`.
102
+ */
103
+ export declare function triggerOf(events: readonly EventLike[]): TurnTrigger;
104
+ /** Fold the whole log (or a suffix of it) into the latest alter state. */
105
+ export declare function latestFromEvents(events: readonly EventLike[]): AlterLatest;
106
+ export type AlterChatItem =
107
+ /** The owner spoke (page composer or dsh's input bar); `revise` when it was the page's "let the alter revise" feedback on a draft. */
108
+ {
109
+ readonly kind: 'owner';
110
+ readonly key: string;
111
+ readonly ts: number;
112
+ readonly text: string;
113
+ readonly revise?: {
114
+ readonly name: string;
115
+ readonly fp: string;
116
+ };
117
+ }
118
+ /** The alter answered the owner (assistant text). */
119
+ | {
120
+ readonly kind: 'alter';
121
+ readonly key: string;
122
+ readonly ts: number;
123
+ readonly text: string;
124
+ readonly turn: number;
125
+ }
126
+ /** Mail from a friend reached the alter (relayed into the session). */
127
+ | {
128
+ readonly kind: 'inbound';
129
+ readonly key: string;
130
+ readonly ts: number;
131
+ readonly fp: string;
132
+ readonly name: string;
133
+ readonly id: string;
134
+ readonly body: string;
135
+ readonly auto: boolean;
136
+ readonly type?: string;
137
+ }
138
+ /** The alter called `soulmirror_send_message`. */
139
+ | {
140
+ readonly kind: 'send';
141
+ readonly key: string;
142
+ readonly ts: number;
143
+ readonly fp: string;
144
+ readonly body: string;
145
+ readonly outcome?: SendOutcome;
146
+ readonly gate?: string;
147
+ readonly draftId?: string;
148
+ readonly detail?: string;
149
+ readonly auto: boolean;
150
+ }
151
+ /** The plugin's own note (the owner decided a draft). */
152
+ | {
153
+ readonly kind: 'note';
154
+ readonly key: string;
155
+ readonly ts: number;
156
+ readonly note: A2ANoteKind;
157
+ readonly fp: string;
158
+ readonly text: string;
159
+ readonly draftId?: string;
160
+ }
161
+ /** A turn ended without completing (no model, provider error, cancelled …). */
162
+ | {
163
+ readonly kind: 'turn-failed';
164
+ readonly key: string;
165
+ readonly ts: number;
166
+ readonly turn: number;
167
+ readonly reason: string;
168
+ readonly message?: string;
169
+ };
170
+ export interface AlterChat {
171
+ readonly items: readonly AlterChatItem[];
172
+ /** A turn is open (its `turn/end` has not been logged). */
173
+ readonly running: boolean;
174
+ /** Change marker (last seq + 1). */
175
+ readonly seq: number;
176
+ }
177
+ export declare const EMPTY_CHAT: AlterChat;
178
+ /** The owner instruction the sessions plugin writes for "let the alter revise" (name, fp, feedback). */
179
+ export declare const REVISE_INSTRUCTION: RegExp;
180
+ /** Strip the host's model-facing preamble (first line) so the bubble shows the mail body only. */
181
+ export declare function bodyOfRelayText(text: string): string;
182
+ /** Fold the alter session log into the transcript the page renders. */
183
+ export declare function chatFromEvents(events: readonly EventLike[]): AlterChat;
184
+ /** Event types that change what the folds answer (the sessions plugin broadcasts on these). */
185
+ export declare const ALTER_EVENT_TYPES: ReadonlySet<string>;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Browser-facing HTTP API of the host half, mounted on dsh's web server
3
+ * (`ctx.webServer.register`, prefix `/soulmirror/api/`). The client bundle
4
+ * uses it for everything the SoulMirror page / settings / onboarding need
5
+ * that is not a session event: identity, card, friends, pending requests,
6
+ * read cursors, the conversation archive, presence, the debug direct send,
7
+ * the owner → alter channel (P4: `alter.instruct {text}`, `session.latest`,
8
+ * `session.history`), pending drafts (`drafts.list`, `drafts.decide`),
9
+ * per-friend settings (`friends.set` with tier / protocol override), the
10
+ * global diplomacy protocol (`protocol.get` / `protocol.set`), and a
11
+ * Server-Sent-Events stream of live events (inbound mail, outbound archive,
12
+ * typing, friend requests, presence, backend status, `alter` = the alter's
13
+ * state changed, `draft` = a draft was stored / decided).
14
+ *
15
+ * Why not dsh's Typert remotes: those are generated build artifacts selected
16
+ * by the web app at build time; an out-of-repo plugin cannot add one (see
17
+ * dsh-api-remotes README "capability set is fixed by explicit build-time
18
+ * value imports"). Why not `ctx.sessionProjections` for typing: projections
19
+ * are pure folds over COMMITTED session events and typing must not be logged
20
+ * (SPIKE.md §1), so there is no event to fold. This route is the plugin's own
21
+ * channel; it is served by the same loopback web server as `/api`.
22
+ */
23
+ import type { IncomingMessage, ServerResponse } from 'node:http';
24
+ import type { Context } from '@deepseek-ai/cordis';
25
+ import { type NetworkClient, type NetworkEvent } from '../network/types.ts';
26
+ import type { AlterSessions, SessionsEvent } from '../sessions/index.ts';
27
+ import type { SoulmirrorSettings } from '../settings.ts';
28
+ export declare const API_PREFIX = "/soulmirror/api/";
29
+ /**
30
+ * What the SSE stream carries: every NetworkEvent of the backend plus the
31
+ * sessions plugin's own frames (`outbound`, `alter`, `draft`).
32
+ */
33
+ export type ApiFrame = NetworkEvent | SessionsEvent;
34
+ export interface ApiOptions {
35
+ readonly client: NetworkClient;
36
+ readonly home: string;
37
+ readonly settingsNamespace: string;
38
+ /** Resolved lazily: the sessions plugin may mount after the network plugin. */
39
+ readonly sessions: () => AlterSessions | undefined;
40
+ /** Live settings (the alter fields apply without restart). */
41
+ readonly settings: () => SoulmirrorSettings;
42
+ readonly log: (level: 'info' | 'warn' | 'error', message: string) => void;
43
+ }
44
+ export interface ApiHandler {
45
+ (req: IncomingMessage, res: ServerResponse): Promise<void>;
46
+ /** Push one frame to every SSE client (the sessions plugin's events are forwarded through this). */
47
+ broadcast(frame: ApiFrame): void;
48
+ dispose(): void;
49
+ }
50
+ export declare function createApiHandler(options: ApiOptions): ApiHandler;
51
+ /** Mount the API on `ctx.webServer` when (and for as long as) that service exists. */
52
+ export declare function mountApi(ctx: Context, options: ApiOptions): void;
@@ -0,0 +1,4 @@
1
+ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { NS } from './locales.ts';
3
+ export type A2ANodeProps = PropsRuntime<'conversation.chat.node', 'a2a-message'> & PropsLocale<typeof NS>;
4
+ export declare function A2ANode({ node, t }: A2ANodeProps): import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import type { Translate } from './Inbox.tsx';
2
+ export interface AlterPaneProps {
3
+ t: Translate;
4
+ /** Open the alter's dsh session (closes the page). */
5
+ onOpenSession: (sessionId: string) => void;
6
+ /** Jump to a friend's read-only thread. */
7
+ onGoFriend: (fp: string) => void;
8
+ }
9
+ export declare function AlterPane({ t, onOpenSession, onGoFriend }: AlterPaneProps): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import type { Translate } from './Inbox.tsx';
2
+ import { type InboxFriend } from './inbox-state.ts';
3
+ export interface ChatPaneProps {
4
+ t: Translate;
5
+ friend: InboxFriend;
6
+ /** Whether the page is visible (mark-read only then). */
7
+ visible: boolean;
8
+ /** Open the friend's dsh session (resolves fp → session id first) and close the page. */
9
+ onOpenSession: (fp: string) => void;
10
+ /** Debug setting: offer "Send as myself" (direct send through the peer). */
11
+ directSend: boolean;
12
+ }
13
+ export declare function ChatPane({ t, friend, visible, onOpenSession, directSend }: ChatPaneProps): import("react").JSX.Element;
@@ -0,0 +1,11 @@
1
+ import type { ApiDraft } from './api.ts';
2
+ import type { Translate } from './Inbox.tsx';
3
+ export declare function reasonLabel(t: Translate, reason: string): string;
4
+ export declare function DraftCard({ draft, t, showTarget, onGoFriend }: {
5
+ draft: ApiDraft;
6
+ t: Translate;
7
+ /** Name the target in the head (the alter chat lists drafts to every friend). */
8
+ showTarget?: boolean;
9
+ /** Jump to the friend's read-only thread. */
10
+ onGoFriend?: (fp: string) => void;
11
+ }): import("react").JSX.Element;
@@ -0,0 +1,20 @@
1
+ import type { ComposerChainProps } from '@deepseek-ai/dsh-client-ui-conversation/client';
2
+ import type { SettingsScope } from '@deepseek-ai/dsh-client-runtime/client';
3
+ import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
4
+ import type { NS } from './locales.ts';
5
+ import type { SoulmirrorSettingsValues } from './SettingsSection.tsx';
6
+ export interface FriendMatch {
7
+ readonly sessionId: string;
8
+ readonly friendName: string;
9
+ /** `preset`: the session composes `soulmirror-chat`; `map`: the host's fp → session map names it. */
10
+ readonly reason: 'preset' | 'map';
11
+ }
12
+ export interface FriendComposerInjected {
13
+ /** Bound settings scope of the `soulmirror` namespace (reads `directSend` live). */
14
+ scope: SettingsScope<SoulmirrorSettingsValues>;
15
+ }
16
+ export type FriendComposerProps = PropsRuntime<'conversation.composer'> & {
17
+ matched: FriendMatch;
18
+ } & InjectFace<FriendComposerInjected> & PropsLocale<typeof NS>;
19
+ export type FriendSelector = (owner: ComposerChainProps) => FriendMatch | null;
20
+ export declare function FriendComposer({ matched, scope, t }: FriendComposerProps): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import type { Translate } from './Inbox.tsx';
2
+ export interface FriendListProps {
3
+ t: Translate;
4
+ /** `ALTER_KEY` or the selected friend's fingerprint. */
5
+ selected: string;
6
+ onSelect: (key: string) => void;
7
+ /** A pending request was accepted: the new friend's fp. */
8
+ onAccepted?: (fp: string) => void;
9
+ /** Close the page (back to dsh). */
10
+ onClose: () => void;
11
+ }
12
+ export declare function FriendList({ t, selected, onSelect, onAccepted, onClose }: FriendListProps): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import type { Translate } from './Inbox.tsx';
2
+ import { type InboxFriend } from './inbox-state.ts';
3
+ export interface FriendPaneProps {
4
+ t: Translate;
5
+ friend: InboxFriend;
6
+ /** Whether the page is visible (mark-read only then). */
7
+ visible: boolean;
8
+ /** Jump to "My alter". */
9
+ onGoAlter: () => void;
10
+ /** Debug setting: offer the direct-send row (bypasses the alter). */
11
+ directSend: boolean;
12
+ }
13
+ export declare function FriendPane({ t, friend, visible, onGoAlter, directSend }: FriendPaneProps): import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { NS } from './locales.ts';
3
+ export type Translate = PropsLocale<typeof NS>['t'];
4
+ export interface InboxProps {
5
+ t: Translate;
6
+ /** A friend row was clicked (or a request accepted): open the SoulMirror page on that friend. */
7
+ onOpenFriend: (fp: string) => void;
8
+ }
9
+ export declare function Inbox({ t, onOpenFriend }: InboxProps): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { NS } from './locales.ts';
3
+ export interface InboxOverlayInjected {
4
+ /** The session currently on screen (ctx.sessions.list current), for the new-mail cue. */
5
+ currentSessionId: () => string | undefined;
6
+ }
7
+ export type InboxOverlayProps = InboxOverlayInjected & PropsLocale<typeof NS>;
8
+ export declare function InboxOverlay({ currentSessionId, t }: InboxOverlayProps): import("react").JSX.Element;
@@ -0,0 +1,4 @@
1
+ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { NS } from './locales.ts';
3
+ export type OnboardingProps = PropsRuntime<'settings.onboarding'> & PropsLocale<typeof NS>;
4
+ export declare function SoulmirrorOnboarding({ complete, openSection, t }: OnboardingProps): import("react").JSX.Element | null;
@@ -0,0 +1,29 @@
1
+ import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { SettingsScope } from '@deepseek-ai/dsh-client-runtime/client';
3
+ import { type ReplyTier } from './api.ts';
4
+ import type { NS } from './locales.ts';
5
+ type SettingsSectionProps = PropsRuntime<'settings.section'>;
6
+ export interface SoulmirrorSettingsValues {
7
+ relay?: string;
8
+ displayName?: string;
9
+ backend?: string;
10
+ peerBinary?: string;
11
+ home?: string;
12
+ defaultTier?: ReplyTier;
13
+ autoReplyPerHour?: number;
14
+ directSend?: boolean;
15
+ }
16
+ export interface SoulmirrorSettingsInjected {
17
+ /** Select a session as current (ctx.sessions.open) — used for "Open the alter session in dsh". */
18
+ openSession: (id: string) => void;
19
+ /** Bound settings scope of the `soulmirror` namespace. */
20
+ scope: SettingsScope<SoulmirrorSettingsValues>;
21
+ }
22
+ export type SoulmirrorSettingsProps = SettingsSectionProps & InjectFace<SoulmirrorSettingsInjected> & PropsLocale<typeof NS>;
23
+ export declare function CardBlock({ cardUri, home, t }: {
24
+ cardUri: string;
25
+ home: string;
26
+ t: SoulmirrorSettingsProps['t'];
27
+ }): import("react").JSX.Element;
28
+ export declare function SoulmirrorSettingsSection({ openSession, scope, t }: SoulmirrorSettingsProps): import("react").JSX.Element;
29
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { SidebarFooterActionOwnerProps } from '@deepseek-ai/dsh-client-ui-sidebar/client';
2
+ import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
3
+ import type { NS } from './locales.ts';
4
+ export type SidebarEntryProps = SidebarFooterActionOwnerProps & PropsLocale<typeof NS>;
5
+ /** The SoulMirror glyph: a mirror (rounded frame) with a reflected spark. */
6
+ export declare function SoulMirrorIcon({ size }: {
7
+ size?: number;
8
+ }): import("react").JSX.Element;
9
+ export declare function SidebarEntry({ wide, t }: SidebarEntryProps): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import type { SettingsScope } from '@deepseek-ai/dsh-client-runtime/client';
2
+ import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
3
+ import type { NS } from './locales.ts';
4
+ import type { SoulmirrorSettingsValues } from './SettingsSection.tsx';
5
+ export interface SoulmirrorPageInjected {
6
+ /** Select a session as current (ctx.sessions.open). */
7
+ openSession: (sessionId: string) => void;
8
+ /** Bound settings scope of the `soulmirror` namespace (the page reads the debug `directSend` toggle live). */
9
+ scope: SettingsScope<SoulmirrorSettingsValues>;
10
+ }
11
+ export type SoulmirrorPageProps = SoulmirrorPageInjected & PropsLocale<typeof NS>;
12
+ export declare function SoulmirrorPage({ openSession, scope, t }: SoulmirrorPageProps): import("react").JSX.Element | null;
@@ -0,0 +1,5 @@
1
+ import type { ConvViewProps } from '@deepseek-ai/dsh-client-ui-conversation/client';
2
+ import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
3
+ import type { NS } from './locales.ts';
4
+ export type SoulmirrorViewProps = ConvViewProps & PropsLocale<typeof NS>;
5
+ export declare function SoulmirrorView({ sessionId, t }: SoulmirrorViewProps): import("react").JSX.Element;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Conversation Node Definition for SoulMirror relayed rows in the NATIVE dsh
3
+ * view of the alter session.
4
+ *
5
+ * The host writes each inbound A2A message as a `user/message` whose source is
6
+ * `{ kind:'plugin', plugin:'soulmirror', form:'relay', senderSessionId, a2a:{…} }`
7
+ * (see ../sessions/index.ts and SPIKE.md §1) — and, since P4, its own NOTES
8
+ * (the owner decided a draft) with the same source plus `a2a.note`. This
9
+ * definition folds exactly those events into `a2a-message` chat nodes that
10
+ * ./A2ANode.tsx paints as a bubble (mail) or a system line (note).
11
+ * ui-conversation's own `input-message` definition also renders the same
12
+ * event as a collapsed "Context injection · soulmirror" row; shadowing that
13
+ * row (keyed `context` renderer at priority -1) is still open.
14
+ */
15
+ import type { ConversationNodeDefinition } from '@deepseek-ai/dsh-client-runtime/client';
16
+ import type { A2AMessageData, A2ASourceMeta } from '../events.ts';
17
+ /** Renderer payload: the message plus the seq of the event that produced the node. */
18
+ export interface A2AChatData extends A2AMessageData {
19
+ readonly seq: number;
20
+ readonly type?: string;
21
+ }
22
+ declare module '@deepseek-ai/dsh-client-ui-conversation/client' {
23
+ interface ChatNodeDataMap {
24
+ 'a2a-message': A2AChatData;
25
+ }
26
+ }
27
+ declare module '@deepseek-ai/dsh-client-runtime/client' {
28
+ interface ConversationStepDataMap {
29
+ 'a2a-message': A2AChatData;
30
+ }
31
+ }
32
+ interface RelaySource {
33
+ kind?: unknown;
34
+ plugin?: unknown;
35
+ form?: unknown;
36
+ senderSessionId?: unknown;
37
+ a2a?: Partial<A2ASourceMeta>;
38
+ }
39
+ /** Whether a `user/message` source is a SoulMirror relayed row (mail or note). */
40
+ export declare function isSoulmirrorRelaySource(source: unknown): source is RelaySource & {
41
+ a2a?: Partial<A2ASourceMeta>;
42
+ };
43
+ /** Strip the host's model-facing preamble (first line) so the bubble shows the mail body only. */
44
+ export declare function bodyOfRelayText(text: string): string;
45
+ export declare const a2aRelayDefinition: ConversationNodeDefinition<A2AChatData>;
46
+ export {};
@@ -0,0 +1,35 @@
1
+ import { type ReplyTier } from './api.ts';
2
+ import type { Translate } from './Inbox.tsx';
3
+ export declare const TIERS: readonly ReplyTier[];
4
+ export declare function tierLabel(t: Translate, tier: ReplyTier): string;
5
+ export declare function tierShort(t: Translate, tier: ReplyTier): string;
6
+ export declare function TierPill({ tier, t }: {
7
+ tier: ReplyTier;
8
+ t: Translate;
9
+ }): import("react").JSX.Element;
10
+ export declare function TierSelect({ value, defaultTier, onChange, t, disabled, id }: {
11
+ /** Stored tier; undefined = the global default applies. */
12
+ value: ReplyTier | undefined;
13
+ defaultTier: ReplyTier;
14
+ onChange: (tier: ReplyTier | undefined) => void;
15
+ t: Translate;
16
+ disabled?: boolean;
17
+ id?: string;
18
+ }): import("react").JSX.Element;
19
+ /** Per-friend alter settings: reply tier + protocol override (friend pane, above the action bar). */
20
+ export declare function FriendSettingsPanel({ fp, name, tier, tierExplicit, protocol, defaultTier, perHour, t, onClose }: {
21
+ fp: string;
22
+ name: string;
23
+ tier: ReplyTier | undefined;
24
+ tierExplicit: boolean;
25
+ protocol: string | undefined;
26
+ defaultTier: ReplyTier;
27
+ perHour: number;
28
+ t: Translate;
29
+ onClose?: () => void;
30
+ }): import("react").JSX.Element;
31
+ /** The global diplomacy protocol editor (protocol.md), used by the friend list and the settings section. */
32
+ export declare function ProtocolEditor({ t, compact }: {
33
+ t: Translate;
34
+ compact?: boolean;
35
+ }): import("react").JSX.Element;