@itookit/dsht 0.5.1 → 0.5.2
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/README.i18n.yaml +2 -2
- package/README.md +4 -2
- package/README.zh.md +6 -4
- package/dist/catalog/controller.d.ts +26 -6
- package/dist/catalog/controller.js +73 -45
- package/dist/catalog/index.d.ts +1 -0
- package/dist/cli/dsht.js +4 -1
- package/dist/cli/startup.js +30 -11
- package/dist/cli/verifier.d.ts +4 -0
- package/dist/cli/verifier.js +28 -5
- package/dist/contracts.d.ts +20 -5
- package/dist/controller/connection-streams.d.ts +22 -0
- package/dist/controller/connection-streams.js +105 -0
- package/dist/controller/connection.d.ts +14 -3
- package/dist/controller/connection.js +40 -69
- package/dist/controller/controller.d.ts +17 -233
- package/dist/controller/controller.js +108 -811
- package/dist/controller/foreground.d.ts +44 -0
- package/dist/controller/foreground.js +79 -0
- package/dist/controller/loop-coordinator.d.ts +48 -0
- package/dist/controller/loop-coordinator.js +647 -0
- package/dist/controller/verifier.d.ts +4 -0
- package/dist/cost/controller.d.ts +1 -1
- package/dist/cost/controller.js +12 -5
- package/dist/cost/scanner.js +1 -0
- package/dist/session/controller.d.ts +23 -35
- package/dist/session/controller.js +113 -363
- package/dist/session/history-reader.d.ts +32 -0
- package/dist/session/history-reader.js +170 -0
- package/dist/session/index.d.ts +1 -1
- package/dist/session/info.d.ts +3 -38
- package/dist/session/info.js +14 -1
- package/dist/session/interactions.d.ts +26 -0
- package/dist/session/interactions.js +75 -0
- package/dist/session/navigator.d.ts +47 -0
- package/dist/session/navigator.js +158 -0
- package/dist/session/prompt-backfill.d.ts +23 -0
- package/dist/session/prompt-backfill.js +88 -0
- package/dist/session/state.d.ts +20 -0
- package/dist/session/state.js +1 -0
- package/dist/session/telemetry.d.ts +15 -6
- package/dist/session/telemetry.js +44 -7
- package/dist/session/transcript.d.ts +5 -1
- package/dist/slash/index.d.ts +1 -1
- package/dist/slash/parse.d.ts +2 -126
- package/dist/slash/registry.d.ts +1 -1
- package/dist/slash/types.d.ts +126 -0
- package/dist/slash/types.js +1 -0
- package/dist/state.d.ts +5 -17
- package/dist/state.js +1 -1
- package/dist/transport/client.d.ts +4 -3
- package/dist/transport/client.js +71 -25
- package/dist/ui/app.js +86 -301
- package/dist/ui/chat/shell-view.d.ts +2 -0
- package/dist/ui/chat/shell-view.js +8 -0
- package/dist/ui/chat/use-history-view.d.ts +69 -0
- package/dist/ui/chat/use-history-view.js +123 -0
- package/dist/ui/dialogs/use-panels.d.ts +53 -0
- package/dist/ui/dialogs/use-panels.js +51 -0
- package/dist/ui/input/use-composer.d.ts +35 -0
- package/dist/ui/input/use-composer.js +109 -0
- package/dist/ui/input/use-deferred-lines.d.ts +16 -0
- package/dist/ui/input/use-deferred-lines.js +54 -0
- package/dist/ui/input/use-history-recall.d.ts +20 -0
- package/dist/ui/input/use-history-recall.js +47 -0
- package/package.json +1 -1
package/dist/cost/controller.js
CHANGED
|
@@ -30,10 +30,11 @@ export class CostController {
|
|
|
30
30
|
this.timer = setInterval(() => { if (this.host.online())
|
|
31
31
|
void this.refresh().catch(() => undefined); }, REFRESH_INTERVAL_MS);
|
|
32
32
|
}
|
|
33
|
-
/**
|
|
33
|
+
/** Cancel the timer and active scan, then wait for cleanup; keep already folded totals. */
|
|
34
34
|
async stop() {
|
|
35
35
|
clearInterval(this.timer);
|
|
36
36
|
this.timer = undefined;
|
|
37
|
+
this.abort?.abort();
|
|
37
38
|
await this.task;
|
|
38
39
|
}
|
|
39
40
|
/** Refresh after the host reports a turn complete. */
|
|
@@ -45,8 +46,11 @@ export class CostController {
|
|
|
45
46
|
* @param signal - Optional cancellation for an explicit `/cost` refresh.
|
|
46
47
|
*/
|
|
47
48
|
async refresh(signal = this.host.signal()) {
|
|
49
|
+
signal.throwIfAborted();
|
|
50
|
+
this.host.signal().throwIfAborted();
|
|
48
51
|
if (this.task) {
|
|
49
|
-
const
|
|
52
|
+
const scanAbort = this.abort;
|
|
53
|
+
const cancel = () => scanAbort?.abort();
|
|
50
54
|
signal.addEventListener('abort', cancel, { once: true });
|
|
51
55
|
try {
|
|
52
56
|
await this.task;
|
|
@@ -64,9 +68,9 @@ export class CostController {
|
|
|
64
68
|
const ledger = this.ledger;
|
|
65
69
|
ledger.scanning = true;
|
|
66
70
|
ledger.error = '';
|
|
67
|
-
|
|
68
|
-
const task = (async () => {
|
|
71
|
+
const task = Promise.resolve().then(async () => {
|
|
69
72
|
try {
|
|
73
|
+
combined.throwIfAborted();
|
|
70
74
|
const sessions = array(object(await client.call('session/list', { _request: {} }, combined)).items).map(object);
|
|
71
75
|
combined.throwIfAborted();
|
|
72
76
|
const failures = [];
|
|
@@ -82,6 +86,7 @@ export class CostController {
|
|
|
82
86
|
scanned++;
|
|
83
87
|
events += history.events.length;
|
|
84
88
|
await ledger.replace(sessionId, history.cursor, history.events);
|
|
89
|
+
combined.throwIfAborted();
|
|
85
90
|
if (!session.running && typeof session.updatedAt === 'number')
|
|
86
91
|
this.updates.set(sessionId, session.updatedAt);
|
|
87
92
|
this.host.publish();
|
|
@@ -103,8 +108,10 @@ export class CostController {
|
|
|
103
108
|
ledger.scanning = false;
|
|
104
109
|
this.host.publish();
|
|
105
110
|
}
|
|
106
|
-
})
|
|
111
|
+
});
|
|
107
112
|
this.task = task;
|
|
113
|
+
// Publish only after reserving the scan: an observer may synchronously join or cancel it.
|
|
114
|
+
this.host.publish();
|
|
108
115
|
try {
|
|
109
116
|
await task;
|
|
110
117
|
}
|
package/dist/cost/scanner.js
CHANGED
|
@@ -45,6 +45,7 @@ export async function sessionCostHistory(client, session, signal, onPage, onReco
|
|
|
45
45
|
}
|
|
46
46
|
/** Page one addressed session's history into the billing events the ledger folds. */
|
|
47
47
|
async function readCostHistory(client, address, signal, onPage, onRecords) {
|
|
48
|
+
signal.throwIfAborted();
|
|
48
49
|
onPage?.();
|
|
49
50
|
const snapshot = await new Promise((resolve, reject) => {
|
|
50
51
|
let sub;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { HostAccess } from '../transport/host.ts';
|
|
2
2
|
import { type Json, type ObjectValue } from '../transport/wire.ts';
|
|
3
|
-
import type {
|
|
3
|
+
import type { SessionStore } from './state.ts';
|
|
4
4
|
import { type SessionRender } from './history.ts';
|
|
5
5
|
import type { HistoryLimits } from './memory.ts';
|
|
6
6
|
import { type FileReference } from './references.ts';
|
|
@@ -19,16 +19,18 @@ export declare class SessionController {
|
|
|
19
19
|
private readonly connection;
|
|
20
20
|
private readonly historyLimits;
|
|
21
21
|
private follow;
|
|
22
|
-
private
|
|
22
|
+
private readonly history;
|
|
23
|
+
private readonly interactions;
|
|
24
|
+
private readonly navigation;
|
|
23
25
|
/** Reading protection: reclamation pauses while the reader is away from the live end. */
|
|
24
26
|
private historyPinned;
|
|
25
27
|
/** Host runtime mirrors for every session this connection has seen. */
|
|
26
28
|
private readonly runtime;
|
|
27
29
|
/** Cancels the background prompt backfill of the previous selection. */
|
|
28
|
-
private promptBackfill
|
|
30
|
+
private readonly promptBackfill;
|
|
29
31
|
/** Prompts of sessions this process has already read, so re-opening one costs no page request. */
|
|
30
32
|
private readonly promptCache;
|
|
31
|
-
/** Prompt index,
|
|
33
|
+
/** Prompt index, record, history window and interaction state of the selected session. */
|
|
32
34
|
private get info();
|
|
33
35
|
private get prompts();
|
|
34
36
|
private stoppingSession?;
|
|
@@ -36,13 +38,13 @@ export declare class SessionController {
|
|
|
36
38
|
private admission;
|
|
37
39
|
/** Admission order of this session's writes, so two concurrent decisions cannot interleave. */
|
|
38
40
|
private readonly mutations;
|
|
39
|
-
constructor(store:
|
|
41
|
+
constructor(store: SessionStore, host: HostAccess, connection: ConnectionView, historyLimits: HistoryLimits, report?: (admission: MutationAdmission) => void);
|
|
40
42
|
/** Host running state covers model generation, tools, and waits between assistant attempts. */
|
|
41
43
|
get running(): boolean;
|
|
42
44
|
/** Current title projection, falling back to the list title and then the session ID. */
|
|
43
45
|
get sessionName(): string | undefined;
|
|
44
46
|
/** Current agent-preset name, matching the web header's built-in labels and custom metadata. */
|
|
45
|
-
|
|
47
|
+
sessionMode(presets?: readonly ObjectValue[]): string | undefined;
|
|
46
48
|
/** Epoch start from the retained turn log, or when this client first observed the run. */
|
|
47
49
|
get workingSince(): number | undefined;
|
|
48
50
|
/** Present only sessions explicitly accounted to the selected workspace. */
|
|
@@ -76,15 +78,15 @@ export declare class SessionController {
|
|
|
76
78
|
beginGeneration(): void;
|
|
77
79
|
/** Invalidate in-flight work and drop transient interactions when a generation ends. */
|
|
78
80
|
endGeneration(): void;
|
|
79
|
-
/** Wait for
|
|
81
|
+
/** Wait for cancellation and foreground history tasks before releasing their records. */
|
|
80
82
|
settle(): Promise<void>;
|
|
81
83
|
/** Release the selected transcript and its layout caches. */
|
|
82
84
|
release(): void;
|
|
83
85
|
/** Pending interactions for the selected chat session, derived independently of frame order.
|
|
84
|
-
* @param
|
|
86
|
+
* @param sessionId - Session whose pending interactions are being published.
|
|
85
87
|
* @returns Retained question and approval frames for that session.
|
|
86
88
|
*/
|
|
87
|
-
pendingFor(
|
|
89
|
+
pendingFor(sessionId: string | undefined): PendingInteraction[];
|
|
88
90
|
/** Unanswered interactions by session, so a list can show who is waiting without opening them.
|
|
89
91
|
*
|
|
90
92
|
* The host delivers approval and question waterfalls for every session on one stream, and this
|
|
@@ -127,7 +129,9 @@ export declare class SessionController {
|
|
|
127
129
|
/** Refresh both lists from the host, then show the requested picker.
|
|
128
130
|
* @param screen - Picker to display after the refresh.
|
|
129
131
|
*/
|
|
130
|
-
showPicker(screen: 'workspaces' | 'sessions'): Promise<void>;
|
|
132
|
+
showPicker(screen: 'workspaces' | 'sessions', signal?: AbortSignal): Promise<void>;
|
|
133
|
+
/** Refresh navigation data without taking the reader to another screen. */
|
|
134
|
+
refreshLists(): Promise<void>;
|
|
131
135
|
/** Return to the selected conversation without re-selecting it.
|
|
132
136
|
*
|
|
133
137
|
* A picker opened over a conversation is a detour: leaving it must not re-subscribe, reload the
|
|
@@ -152,11 +156,11 @@ export declare class SessionController {
|
|
|
152
156
|
/** Open a workspace picker, or resolve a workspace by ID, exact title/path, or unique ID prefix.
|
|
153
157
|
* @param query - Workspace target, if any.
|
|
154
158
|
*/
|
|
155
|
-
switchWorkspace(query?: string): Promise<void>;
|
|
159
|
+
switchWorkspace(query?: string, signal?: AbortSignal): Promise<void>;
|
|
156
160
|
/** Guide workspace selection, list all sessions with `all`, or resolve an exact session target.
|
|
157
161
|
* @param query - Session target, `all`, or nothing for the guided picker.
|
|
158
162
|
*/
|
|
159
|
-
switchSession(query?: string): Promise<void>;
|
|
163
|
+
switchSession(query?: string, signal?: AbortSignal): Promise<void>;
|
|
160
164
|
/** Prompt for a host path without starting a local agent. */
|
|
161
165
|
enterPath(): void;
|
|
162
166
|
/** Adopt the workspace whose registered path contains the directory this client runs in.
|
|
@@ -171,9 +175,9 @@ export declare class SessionController {
|
|
|
171
175
|
/** Register a host directory and move to its session picker.
|
|
172
176
|
* @param path - Absolute directory path on the host.
|
|
173
177
|
*/
|
|
174
|
-
createWorkspace(path: string): Promise<void>;
|
|
178
|
+
createWorkspace(path: string, signal?: AbortSignal): Promise<void>;
|
|
175
179
|
/** Create a session only after the user explicitly selects New session. */
|
|
176
|
-
createSession(): Promise<void>;
|
|
180
|
+
createSession(signal?: AbortSignal): Promise<void>;
|
|
177
181
|
/** Create a session for another purpose without selecting it, named so a reader can tell it apart.
|
|
178
182
|
*
|
|
179
183
|
* A verifier runs in its own session while the reviewed session stays selected, so this never
|
|
@@ -193,6 +197,9 @@ export declare class SessionController {
|
|
|
193
197
|
* @param sessionId - Session to follow.
|
|
194
198
|
*/
|
|
195
199
|
selectSession(sessionId: string): Promise<void>;
|
|
200
|
+
/** Reattach the selected conversation after reconnect, keeping the current navigation context. */
|
|
201
|
+
restoreSelectedSession(): void;
|
|
202
|
+
private followSession;
|
|
196
203
|
/** Wait for the selected follow snapshot, failing on disconnect or cancellation.
|
|
197
204
|
* @param signal - Cancels waiting without closing the session.
|
|
198
205
|
*/
|
|
@@ -311,11 +318,6 @@ export declare class SessionController {
|
|
|
311
318
|
* @returns Whether any older prompt was recovered.
|
|
312
319
|
*/
|
|
313
320
|
refillRecall(): boolean;
|
|
314
|
-
/** Seed recall from a complete cached entry, so an open that follows a scan costs no request.
|
|
315
|
-
* @param sessionId - Session being opened.
|
|
316
|
-
* @returns Whether the cache covered this session.
|
|
317
|
-
*/
|
|
318
|
-
private adoptCachedPrompts;
|
|
319
321
|
/** Fold one history page the cost scan already read into the prompt cache.
|
|
320
322
|
*
|
|
321
323
|
* The scan reads every session's whole history on connect, so this is where two readers stop
|
|
@@ -328,29 +330,17 @@ export declare class SessionController {
|
|
|
328
330
|
* @param sessionId - Session the scan finished.
|
|
329
331
|
*/
|
|
330
332
|
rememberScanDone(sessionId: string): void;
|
|
331
|
-
/** Fold every prompt the host still holds into the recall index, in the background.
|
|
332
|
-
*
|
|
333
|
-
* Session start delivers only the newest window, so without this the arrows could reach older
|
|
334
|
-
* prompts but not show them without paging first. Each page is parsed into a temporary transcript
|
|
335
|
-
* and only its prompts are kept, so the live record, its memory window and the row cache never
|
|
336
|
-
* grow. The walk is bounded and the next selection cancels it; anything past the bound is still
|
|
337
|
-
* reachable through the lazy backward step.
|
|
338
|
-
* @param sessionId - Session being opened.
|
|
339
|
-
* @param selection - Selector generation that must still be current.
|
|
340
|
-
*/
|
|
341
|
-
private backfillPrompts;
|
|
342
333
|
/** Search one page at a time, preserving only the first 200 matches and releasing temporary content.
|
|
343
334
|
* @param query - Literal, case-insensitive text including folded reasoning.
|
|
344
335
|
* @param signal - Cancels HTTP and processing without cancelling the agent.
|
|
345
336
|
* @returns Newest-first bounded summaries and an explicit truncation flag.
|
|
346
337
|
*/
|
|
347
338
|
searchHistory(query: string, signal: AbortSignal): Promise<HistorySearch>;
|
|
348
|
-
/**
|
|
339
|
+
/** Select a readable window by sequence; temporary records never escape to the UI.
|
|
349
340
|
* @param target - Durable message sequence to display.
|
|
350
341
|
* @param signal - Cancels the target-page request.
|
|
351
|
-
* @returns A caller-owned historical window that must be disposed when closed.
|
|
352
342
|
*/
|
|
353
|
-
|
|
343
|
+
openHistory(target: number, signal: AbortSignal): Promise<void>;
|
|
354
344
|
/** Load the prefix required for an explicit history jump; never loop on an unadvancing page.
|
|
355
345
|
* @param target - Visible record sequence, or first for the oldest available history.
|
|
356
346
|
* @param signal - Cancels local paging without interrupting the remote agent.
|
|
@@ -364,6 +354,4 @@ export declare class SessionController {
|
|
|
364
354
|
private releaseTranscript;
|
|
365
355
|
/** @returns The selected session identity, or a `Select a session first` failure. */
|
|
366
356
|
private get sessionId();
|
|
367
|
-
/** Answer one retained waterfall through the connection's event-result endpoint. */
|
|
368
|
-
private reply;
|
|
369
357
|
}
|