dsh-input-assistant 0.0.0-stage → 0.1.3

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.
@@ -0,0 +1,144 @@
1
+ import { type AssistantConfig, type AssistantStatus, type InputSnapshot, type ModelRoute, type StoredDraft, type TokenSpan } from '../core/types';
2
+ import { type ReferenceOccurrence } from './dom';
3
+ export interface BrowserInput {
4
+ draft: string;
5
+ draftRev: number;
6
+ phase: string;
7
+ attachmentIds: readonly unknown[];
8
+ occurrences: readonly ReferenceOccurrence[];
9
+ }
10
+ export interface BrowserActions {
11
+ captureInsertion(): TokenSpan;
12
+ insertText(text: string, span: TokenSpan): boolean;
13
+ persistDraft?(): void;
14
+ }
15
+ export interface BrowserBinding {
16
+ sessionId: string;
17
+ input: BrowserInput;
18
+ actions: BrowserActions;
19
+ editor: HTMLElement | null;
20
+ running: boolean;
21
+ route?: ModelRoute;
22
+ }
23
+ export interface BrowserTransport {
24
+ call<T>(method: string, data: unknown, signal?: AbortSignal): Promise<T>;
25
+ generation(): string | null;
26
+ }
27
+ export interface Suggestion {
28
+ text: string;
29
+ snapshot: InputSnapshot;
30
+ kind: 'next' | 'complete';
31
+ }
32
+ export interface ChangeRecord {
33
+ before: string;
34
+ after: string;
35
+ beforeTarget: string;
36
+ afterTarget: string;
37
+ span: TokenSpan;
38
+ sourceTurnId: string | null;
39
+ connectionGeneration: string;
40
+ routeKey: string;
41
+ clientGeneration: string | null;
42
+ }
43
+ export interface BrowserState {
44
+ status: AssistantStatus | null;
45
+ settings: AssistantConfig;
46
+ busy: 'optimize' | 'stash' | null;
47
+ notice: string;
48
+ suggestion: Suggestion | null;
49
+ change: ChangeRecord | null;
50
+ drafts: readonly StoredDraft[];
51
+ locked: readonly string[];
52
+ connected: boolean;
53
+ settingsSaving: boolean;
54
+ metrics: UsageMetrics;
55
+ }
56
+ export interface UsageMetrics {
57
+ exposures: number;
58
+ accepted: number;
59
+ editedAcceptances: number;
60
+ editedCharacters: number;
61
+ calls: number;
62
+ totalLatencyMs: number;
63
+ }
64
+ /** One controller per mounted composer. Right/overlay surfaces consume this same store. */
65
+ export declare class InputAssistantController {
66
+ readonly sessionId: string;
67
+ private readonly transport;
68
+ private readonly saveSettings?;
69
+ private state;
70
+ private listeners;
71
+ private binding;
72
+ private active;
73
+ private timer;
74
+ /** Cache key the armed completion timer was scheduled for; null when no timer is armed. */
75
+ private timerKey;
76
+ private poll;
77
+ private polling;
78
+ private lifecycle;
79
+ private disposed;
80
+ private composing;
81
+ private settingsPending;
82
+ private settingsEpoch;
83
+ private nextTurns;
84
+ private nextCache;
85
+ private completionCache;
86
+ private failedCompletionKey;
87
+ private lastCompletionStart;
88
+ private suppressUntilEdit;
89
+ private sequence;
90
+ private clientGeneration;
91
+ private lockedRanges;
92
+ private exposed;
93
+ private acceptance;
94
+ constructor(sessionId: string, transport: BrowserTransport, metrics?: UsageMetrics, saveSettings?: ((update: Partial<AssistantConfig>) => Promise<AssistantConfig>) | undefined);
95
+ getSnapshot: () => BrowserState;
96
+ subscribe: (listener: () => void) => (() => void);
97
+ private patch;
98
+ start(): void;
99
+ dispose(): void;
100
+ bind(binding: BrowserBinding): void;
101
+ notifySelectionChange(): void;
102
+ setComposing(value: boolean): void;
103
+ dismissSuggestion(): void;
104
+ clearNotice(): void;
105
+ notice(text: string): void;
106
+ refresh(): Promise<void>;
107
+ updateSettings(update: Partial<AssistantConfig>): Promise<void>;
108
+ beginSettingsUpdate(): void;
109
+ endSettingsUpdate(): void;
110
+ /** A settings page can update every mounted composer without waiting for its status poll. */
111
+ applySettings(settings: AssistantConfig): void;
112
+ lockSelection(): void;
113
+ clearLocks(): void;
114
+ optimize(): Promise<void>;
115
+ canRestore(): boolean;
116
+ restoreOriginal(): boolean;
117
+ acceptSuggestion(): boolean;
118
+ /** Called only after the overlay has actually rendered a candidate. */
119
+ markExposed(requestId: string): void;
120
+ refreshDrafts(): Promise<void>;
121
+ stash(replaceId?: string): Promise<void>;
122
+ restoreDraft(draft: StoredDraft, mode: 'append' | 'replace'): boolean;
123
+ deleteDraft(id: string): Promise<void>;
124
+ clearDrafts(): Promise<void>;
125
+ private mutateDraft;
126
+ private captureTarget;
127
+ private pureText;
128
+ private eligible;
129
+ private driveSuggestions;
130
+ private requestSuggestion;
131
+ private snapshot;
132
+ private begin;
133
+ private observeAcceptedEdit;
134
+ private isCurrent;
135
+ private validResult;
136
+ private sameCaret;
137
+ private routeKey;
138
+ private completionKey;
139
+ private invalidate;
140
+ private clearTimer;
141
+ private cancelActive;
142
+ private recordLatency;
143
+ private errorMessage;
144
+ }
@@ -0,0 +1,29 @@
1
+ import type { TokenSpan } from '../core/types';
2
+ export interface ReferenceOccurrence {
3
+ offset: number;
4
+ length: number;
5
+ }
6
+ export declare const CHIP_SELECTOR = "[data-composer-chip],[data-composer-text-ref],[data-composer-command]";
7
+ export declare function findEditor(anchor: HTMLElement | null): HTMLElement | null;
8
+ export declare function focusedIn(editor: HTMLElement | null): boolean;
9
+ export declare function referenceOverlaps(span: TokenSpan, references: readonly ReferenceOccurrence[]): boolean;
10
+ /** Public InputState references use clipboard offsets; TokenSpan uses one character per reference. */
11
+ export declare function clipboardOffset(detectOffset: number, references: readonly ReferenceOccurrence[]): number;
12
+ export declare function selectedPlainText(editor: HTMLElement | null, draft: string, span: TokenSpan, references: readonly ReferenceOccurrence[]): {
13
+ text: string;
14
+ clipboardStart: number;
15
+ clipboardEnd: number;
16
+ } | null;
17
+ export interface GhostGeometry {
18
+ left: number;
19
+ top: number;
20
+ width: number;
21
+ maxHeight: number;
22
+ font: string;
23
+ lineHeight: string;
24
+ letterSpacing: string;
25
+ }
26
+ /** Read-only DOM measurements; failure hides the decoration instead of guessing padding. */
27
+ export declare function measureGhost(editor: HTMLElement | null, empty: boolean): GhostGeometry | null;
28
+ export declare function nativeMenuOpen(editor: HTMLElement | null): boolean;
29
+ export declare function canUseTab(event: KeyboardEvent, editor: HTMLElement | null, composing: boolean): boolean;
@@ -0,0 +1,21 @@
1
+ export interface ViewportBounds {
2
+ left: number;
3
+ top: number;
4
+ width: number;
5
+ height: number;
6
+ }
7
+ export interface AnchorBounds {
8
+ left: number;
9
+ top: number;
10
+ right: number;
11
+ bottom: number;
12
+ width: number;
13
+ }
14
+ export interface FloatingPlacement {
15
+ left: number;
16
+ top: number;
17
+ width: number;
18
+ maxHeight: number;
19
+ }
20
+ /** Keep the entire scrollable surface in the visible viewport, independent of composer clipping. */
21
+ export declare function placeFloating(anchor: AnchorBounds, contentHeight: number, viewport: ViewportBounds, preferredWidth?: number): FloatingPlacement;
@@ -0,0 +1,6 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ export declare const name = "input-assistant.client";
3
+ export declare const inject: string[];
4
+ /** Slot registration stays inside the mounted fiber; unloading owns all timers and DOM. */
5
+ export declare function apply(ctx: Context): void;
6
+ export { BrowserRuntime, InputAssistantController } from './public';
@@ -0,0 +1,2 @@
1
+ export { BrowserRuntime } from './runtime';
2
+ export { InputAssistantController } from './controller';
@@ -0,0 +1,53 @@
1
+ import { InputAssistantController, type BrowserTransport } from './controller';
2
+ import type { AssistantConfig } from '../core/types';
3
+ export interface ConnectionFace {
4
+ rpc: {
5
+ call(channel: string, endpoint: string, payload: unknown, signal?: AbortSignal): Promise<{
6
+ ok: true;
7
+ value: unknown;
8
+ } | {
9
+ ok: false;
10
+ error: {
11
+ code?: string;
12
+ message?: string;
13
+ };
14
+ }>;
15
+ };
16
+ generation: {
17
+ getSnapshot(): {
18
+ id: number;
19
+ } | undefined;
20
+ subscribe(listener: () => void): () => void;
21
+ };
22
+ }
23
+ export interface ModelDirectoryFace {
24
+ directoryFor(sessionId: string): {
25
+ store: {
26
+ getSnapshot(): {
27
+ current: {
28
+ provider: string;
29
+ model: string;
30
+ } | null;
31
+ };
32
+ subscribe(listener: () => void): () => void;
33
+ };
34
+ load(): Promise<unknown>;
35
+ };
36
+ }
37
+ export declare class BrowserRuntime {
38
+ readonly connection: ConnectionFace;
39
+ readonly models?: ModelDirectoryFace | undefined;
40
+ private entries;
41
+ private disposed;
42
+ private lifetime;
43
+ private pendingSettings;
44
+ private settingsQueue;
45
+ private metrics;
46
+ readonly transport: BrowserTransport;
47
+ constructor(connection: ConnectionFace, models?: ModelDirectoryFace | undefined);
48
+ controllerFor(sessionId: string): InputAssistantController;
49
+ retain(sessionId: string): () => void;
50
+ applySettings(settings: AssistantConfig): void;
51
+ saveSettings(update: Partial<AssistantConfig>): Promise<AssistantConfig>;
52
+ dispose(): void;
53
+ }
@@ -0,0 +1,8 @@
1
+ import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { BrowserRuntime } from './runtime';
3
+ type SettingsProps = PropsRuntime<'settings.section'> & {
4
+ runtime: BrowserRuntime;
5
+ };
6
+ /** A root-scoped DSH settings section; works even when no composer is mounted. */
7
+ export declare function AssistantSettings({ runtime }: SettingsProps): import("react").JSX.Element;
8
+ export {};
@@ -0,0 +1 @@
1
+ export declare const STYLE_TEXT = "\n.dsh-ia {--dsh-ia-fallback-bg:#fff;--dsh-ia-fallback-fg:#0f1115;--dsh-ia-fallback-muted:#61666b;--dsh-ia-fallback-border:#d7dce2;font-family:var(--dsw-font-family,system-ui,sans-serif);color:var(--dsw-alias-label-primary,var(--dsh-ia-fallback-fg));font-size:13px;line-height:1.5;box-sizing:border-box;color-scheme:light}\nbody[data-ds-dark-theme] .dsh-ia {--dsh-ia-fallback-bg:#232324;--dsh-ia-fallback-fg:#f3f4f6;--dsh-ia-fallback-muted:#adb2b8;--dsh-ia-fallback-border:#43454a;color-scheme:dark}\n.dsh-ia * {box-sizing:border-box}\n.dsh-ia button,.dsh-ia input,.dsh-ia select {font:inherit;color:inherit}\n.dsh-ia button {border:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));border-radius:7px;padding:5px 9px;background:transparent;cursor:pointer}\n.dsh-ia button:hover:not(:disabled) {background:var(--dsw-alias-interactive-bg-hover,#8882)}\n.dsh-ia button:disabled {opacity:.45;cursor:default}\n.dsh-ia button:focus-visible,.dsh-ia input:focus-visible,.dsh-ia select:focus-visible {outline:2px solid var(--dsw-alias-state-business-primary,#4c88e4);outline-offset:2px}\n.dsh-ia-root {display:flex;align-items:center;gap:3px;position:relative}\n.dsh-ia-settings {width:100%;max-width:760px}\n.dsh-ia-settings h2 {font-size:18px;margin:0 0 8px}.dsh-ia-settings h3 {font-size:14px;margin:0 0 10px}\n.dsh-ia-settings fieldset {padding:0;margin:0;border:0;min-width:0}\n.dsh-ia-settings-toggles {display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px}\n.dsh-ia-settings-toggles label {display:flex;align-items:center;gap:7px}\n.dsh-ia-trigger {white-space:nowrap}\n.dsh-ia-menu {position:fixed;width:min(440px,calc(100vw - 24px));max-height:calc(100dvh - 24px);overflow:auto;overscroll-behavior:contain;padding:14px;border:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));border-radius:12px;background:var(--dsw-alias-bg-layer-2,var(--dsh-ia-fallback-bg));box-shadow:0 8px 32px #0003;z-index:1000}\n.dsh-ia-row {display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:8px 0}\n.dsh-ia-row label {display:flex;align-items:center;gap:6px}\n.dsh-ia-field {display:flex;flex-direction:column;gap:4px;margin:8px 0}\n.dsh-ia-field input,.dsh-ia select {border:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));border-radius:6px;background:var(--dsw-alias-bg-layer-1,var(--dsh-ia-fallback-bg));padding:6px}\n.dsh-ia-field input {width:100%}\n.dsh-ia-muted {color:var(--dsw-alias-label-secondary,var(--dsh-ia-fallback-muted));font-size:12px}\n.dsh-ia-notice {position:fixed;max-width:calc(100vw - 24px);overflow:auto;padding:8px 11px;background:var(--dsw-alias-bg-layer-2,var(--dsh-ia-fallback-bg));border:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));border-radius:9px;box-shadow:0 4px 18px #0002;z-index:999}\n.dsh-ia-menu .dsh-ia-notice {position:static;max-width:100%;margin:8px 0;box-shadow:none}\n.dsh-ia-section {border-top:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));margin-top:12px;padding-top:10px}\n.dsh-ia-section h4 {font-size:13px;margin:0 0 8px}\n.dsh-ia-pre {white-space:pre-wrap;overflow-wrap:anywhere;font:inherit;font-size:12px;max-height:190px;overflow:auto;padding:9px;border:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));border-radius:7px;background:var(--dsw-alias-bg-module-platform,#8881)}\n.dsh-ia-diff ins {background:#27a35b26;text-decoration:none}.dsh-ia-diff del {background:#d9454526}\n.dsh-ia-draft {border:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));border-radius:8px;padding:8px;margin:7px 0}\n.dsh-ia-draft summary {cursor:pointer;overflow-wrap:anywhere}\n.dsh-ia-draft time {font-size:11px;opacity:.65}\n.dsh-ia-candidate {position:fixed;display:flex;align-items:center;gap:8px;padding:9px 12px;overflow:auto;border:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));border-radius:10px;background:var(--dsw-alias-bg-layer-2,var(--dsh-ia-fallback-bg));box-shadow:0 4px 16px #0002;pointer-events:auto;z-index:998}\n.dsh-ia-candidate-text {flex:1;white-space:pre-wrap;overflow-wrap:anywhere}\n.dsh-ia-ghost {position:fixed;white-space:pre-wrap;overflow-wrap:anywhere;overflow:hidden;max-height:3lh;pointer-events:none;user-select:none;color:var(--dsw-alias-label-tertiary,#76808d);opacity:.9;z-index:34}\n[data-composer-card]:has([data-dsh-ia-empty-ghost]) [data-composer-placeholder] {visibility:hidden}\n";