@itookit/dsht 0.3.8 → 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 +33 -12
- package/README.zh.md +35 -14
- 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 +206 -18
- package/dist/cli/startup.d.ts +40 -0
- package/dist/cli/startup.js +314 -0
- package/dist/cli/trace-summary.d.ts +78 -0
- package/dist/cli/trace-summary.js +241 -0
- package/dist/cli/verifier.d.ts +64 -0
- package/dist/cli/verifier.js +265 -0
- package/dist/contracts.d.ts +359 -0
- package/dist/contracts.js +1 -0
- package/dist/controller/commands.d.ts +47 -0
- package/dist/controller/commands.js +322 -0
- package/dist/controller/connection-streams.d.ts +22 -0
- package/dist/controller/connection-streams.js +105 -0
- package/dist/controller/connection.d.ts +24 -31
- package/dist/controller/connection.js +48 -111
- package/dist/controller/controller.d.ts +412 -178
- package/dist/controller/controller.js +713 -167
- package/dist/controller/foreground.d.ts +44 -0
- package/dist/controller/foreground.js +79 -0
- package/dist/controller/index.d.ts +8 -1
- package/dist/controller/index.js +5 -0
- package/dist/controller/loop-contract.d.ts +136 -0
- package/dist/controller/loop-contract.js +308 -0
- package/dist/controller/loop-coordinator.d.ts +48 -0
- package/dist/controller/loop-coordinator.js +647 -0
- package/dist/controller/loop-prompts-schema.d.ts +56 -0
- package/dist/controller/loop-prompts-schema.js +144 -0
- package/dist/controller/loop-prompts.d.ts +55 -0
- package/dist/controller/loop-prompts.generated.d.ts +104 -0
- package/dist/controller/loop-prompts.generated.js +185 -0
- package/dist/controller/loop-prompts.js +104 -0
- package/dist/controller/loop-protocols.d.ts +39 -0
- package/dist/controller/loop-protocols.js +115 -0
- package/dist/controller/loop.d.ts +275 -0
- package/dist/controller/loop.js +378 -0
- package/dist/controller/prompts.d.ts +54 -0
- package/dist/controller/prompts.js +162 -0
- package/dist/controller/trace-log.d.ts +45 -0
- package/dist/controller/trace-log.js +144 -0
- package/dist/controller/verifier.d.ts +130 -0
- package/dist/controller/verifier.js +75 -0
- package/dist/cost/controller.d.ts +1 -1
- package/dist/cost/controller.js +12 -5
- package/dist/cost/index.d.ts +1 -1
- package/dist/cost/index.js +1 -1
- package/dist/cost/ledger.d.ts +0 -1
- package/dist/cost/ledger.js +0 -1
- package/dist/cost/scanner.js +1 -0
- package/dist/json.d.ts +18 -0
- package/dist/json.js +19 -0
- package/dist/references.d.ts +25 -0
- package/dist/references.js +26 -0
- package/dist/session/connection-view.d.ts +2 -11
- package/dist/session/controller.d.ts +94 -105
- package/dist/session/controller.js +262 -536
- package/dist/session/history-reader.d.ts +32 -0
- package/dist/session/history-reader.js +170 -0
- package/dist/session/history.d.ts +6 -18
- package/dist/session/history.js +1 -24
- package/dist/session/index.d.ts +9 -4
- package/dist/session/index.js +7 -3
- package/dist/session/info.d.ts +20 -82
- package/dist/session/info.js +52 -25
- package/dist/session/interactions.d.ts +26 -0
- package/dist/session/interactions.js +75 -0
- package/dist/session/markdown.js +1 -1
- package/dist/session/math.js +1 -1
- package/dist/session/mutation-gate.d.ts +51 -0
- package/dist/session/mutation-gate.js +73 -0
- package/dist/session/navigation.d.ts +2 -89
- package/dist/session/navigation.js +2 -129
- package/dist/session/navigator.d.ts +47 -0
- package/dist/session/navigator.js +158 -0
- package/dist/session/peek.d.ts +38 -0
- package/dist/session/peek.js +103 -0
- package/dist/session/prompt-backfill.d.ts +23 -0
- package/dist/session/prompt-backfill.js +88 -0
- package/dist/session/references.d.ts +2 -20
- package/dist/session/references.js +1 -26
- package/dist/session/runtime.d.ts +26 -0
- package/dist/session/runtime.js +28 -0
- package/dist/session/state.d.ts +20 -0
- package/dist/session/state.js +1 -0
- package/dist/session/telemetry.d.ts +25 -17
- package/dist/session/telemetry.js +66 -60
- package/dist/session/transcript.d.ts +5 -7
- package/dist/session/transcript.js +2 -15
- package/dist/session/types.d.ts +25 -0
- package/dist/session/types.js +0 -1
- package/dist/session-title.d.ts +9 -0
- package/dist/session-title.js +21 -0
- package/dist/shell/controller.d.ts +31 -1
- package/dist/shell/controller.js +34 -2
- package/dist/shell/index.d.ts +3 -3
- package/dist/shell/index.js +2 -2
- package/dist/shell/runner.d.ts +10 -0
- package/dist/shell/runner.js +48 -9
- package/dist/slash/index.d.ts +10 -0
- package/dist/slash/index.js +7 -0
- package/dist/slash/parse.d.ts +42 -0
- package/dist/slash/parse.js +259 -0
- package/dist/slash/pipeline.d.ts +140 -0
- package/dist/slash/pipeline.js +115 -0
- package/dist/slash/registry.d.ts +88 -0
- package/dist/slash/registry.js +177 -0
- package/dist/slash/types.d.ts +126 -0
- package/dist/slash/types.js +1 -0
- package/dist/state.d.ts +16 -18
- package/dist/state.js +4 -3
- package/dist/text.d.ts +28 -0
- package/dist/text.js +55 -0
- package/dist/transport/client.d.ts +4 -3
- package/dist/transport/client.js +71 -25
- package/dist/transport/events.d.ts +104 -0
- package/dist/transport/events.js +149 -0
- package/dist/transport/wire.d.ts +9 -17
- package/dist/transport/wire.js +2 -27
- package/dist/ui/app.js +750 -550
- package/dist/ui/chat/header.js +1 -1
- package/dist/ui/chat/history-view.d.ts +1 -1
- package/dist/ui/chat/loop-status.d.ts +11 -0
- package/dist/ui/chat/loop-status.js +28 -0
- package/dist/ui/chat/navigation-model.d.ts +86 -0
- package/dist/ui/chat/navigation-model.js +107 -0
- package/dist/ui/chat/shell-view.d.ts +17 -2
- package/dist/ui/chat/shell-view.js +45 -3
- package/dist/ui/chat/status.d.ts +47 -3
- package/dist/ui/chat/status.js +65 -50
- package/dist/ui/chat/use-history-view.d.ts +69 -0
- package/dist/ui/chat/use-history-view.js +123 -0
- package/dist/ui/chat/viewport.d.ts +1 -1
- package/dist/ui/dialogs/cost.d.ts +21 -4
- package/dist/ui/dialogs/cost.js +7 -12
- package/dist/ui/dialogs/index.d.ts +22 -5
- package/dist/ui/dialogs/index.js +19 -3
- package/dist/ui/dialogs/loop.d.ts +43 -0
- package/dist/ui/dialogs/loop.js +224 -0
- package/dist/ui/dialogs/peek.d.ts +25 -0
- package/dist/ui/dialogs/peek.js +35 -0
- package/dist/ui/dialogs/picker.d.ts +2 -0
- package/dist/ui/dialogs/picker.js +4 -2
- package/dist/ui/dialogs/use-panels.d.ts +53 -0
- package/dist/ui/dialogs/use-panels.js +51 -0
- package/dist/ui/input/mouse.d.ts +12 -2
- package/dist/ui/input/mouse.js +20 -7
- package/dist/ui/input/references.d.ts +1 -1
- 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/dist/ui/status/model.d.ts +7 -0
- package/dist/ui/status/model.js +5 -0
- package/dist/ui/theme/index.d.ts +1 -1
- package/package.json +6 -4
- package/dist/ui/commands/parse.d.ts +0 -104
- package/dist/ui/commands/parse.js +0 -135
- package/dist/ui/commands/registry.d.ts +0 -33
- package/dist/ui/commands/registry.js +0 -73
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
/** Owns the physical connection, its generations, and the host event subscriptions. */
|
|
2
2
|
import { setTimeout as delay } from 'node:timers/promises';
|
|
3
3
|
import { AuthenticationRequired } from "../transport/auth.js";
|
|
4
|
-
import { HttpError
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
import { HttpError } from "../transport/client.js";
|
|
5
|
+
import { errorText } from "../transport/wire.js";
|
|
6
|
+
import { ConnectionStreams } from "./connection-streams.js";
|
|
7
|
+
/** Owns the physical connection: reconnects, subscriptions and generation lifecycle.
|
|
8
|
+
*
|
|
9
|
+
* Host running state, projections and interactions belong to the session domain; this class only
|
|
10
|
+
* decodes wire frames into `HostEvent` and hands them to the application, which routes them on.
|
|
11
|
+
* User commands remain single-attempt operations.
|
|
12
|
+
*/
|
|
12
13
|
export class ConnectionController {
|
|
13
14
|
store;
|
|
14
15
|
options;
|
|
15
16
|
listener;
|
|
16
|
-
telemetry = new Telemetry(RETAINED_PROJECTIONS);
|
|
17
17
|
clientId = '';
|
|
18
|
-
runningUpdates = new Map();
|
|
19
|
-
observedRunningAt = new Map();
|
|
20
18
|
current;
|
|
21
19
|
abort = new AbortController();
|
|
22
20
|
runTask;
|
|
@@ -47,119 +45,72 @@ export class ConnectionController {
|
|
|
47
45
|
online() { return this.store.state.online; }
|
|
48
46
|
/** @returns The client lifetime signal. */
|
|
49
47
|
signal() { return this.abort.signal; }
|
|
50
|
-
/** @returns The projection store of the current generation. */
|
|
51
|
-
telemetryView() { return this.telemetry; }
|
|
52
|
-
/** @returns Cached host running state, or undefined when never reported. */
|
|
53
|
-
runningFor(sessionId) { return this.runningUpdates.get(sessionId); }
|
|
54
|
-
/** @returns When this client first observed the session, for the elapsed-time fallback. */
|
|
55
|
-
observedAt(sessionId) { return this.observedRunningAt.get(sessionId); }
|
|
56
|
-
/** Record an observation start for a session this client just opened. */
|
|
57
|
-
observe(sessionId) { if (!this.observedRunningAt.has(sessionId))
|
|
58
|
-
this.observedRunningAt.set(sessionId, Date.now()); }
|
|
59
48
|
/** Fail the current generation, so the controller reopens a snapshot. */
|
|
60
49
|
fail(error) { this.generationFailed?.(error); }
|
|
61
50
|
/** Answer one retained host waterfall through the event-result endpoint. */
|
|
62
|
-
async reply(
|
|
63
|
-
await this.require().call('$events/result', { clientId: this.clientId, eventId
|
|
51
|
+
async reply(eventId, outcome) {
|
|
52
|
+
await this.require().call('$events/result', { clientId: this.clientId, eventId, outcome });
|
|
64
53
|
}
|
|
65
54
|
/** Run one generation, then retry with bounded jittered backoff until stopped. */
|
|
66
55
|
async run() {
|
|
67
56
|
let attempt = 0;
|
|
68
57
|
while (!this.abort.signal.aborted) {
|
|
69
|
-
this.runningUpdates.clear();
|
|
70
|
-
this.observedRunningAt.clear();
|
|
71
|
-
this.telemetry = new Telemetry(RETAINED_PROJECTIONS);
|
|
72
58
|
this.listener.begin();
|
|
59
|
+
if (this.abort.signal.aborted)
|
|
60
|
+
break;
|
|
73
61
|
const client = this.options.makeClient();
|
|
74
62
|
this.current = client;
|
|
63
|
+
const generation = new AbortController();
|
|
64
|
+
const signal = AbortSignal.any([this.abort.signal, generation.signal]);
|
|
65
|
+
let disconnect;
|
|
66
|
+
const disconnected = new Promise(resolve => { disconnect = resolve; });
|
|
67
|
+
const fail = (error) => {
|
|
68
|
+
if (generation.signal.aborted)
|
|
69
|
+
return;
|
|
70
|
+
generation.abort(error);
|
|
71
|
+
disconnect(error);
|
|
72
|
+
// End HTTP as well as streams, including requests the ready callback is awaiting.
|
|
73
|
+
void client.close();
|
|
74
|
+
};
|
|
75
|
+
this.generationFailed = fail;
|
|
76
|
+
const streams = new ConnectionStreams(client, {
|
|
77
|
+
identified: id => { this.clientId = id; }, event: event => this.listener.event(event),
|
|
78
|
+
changed: () => this.store.update({}), degraded: controlError => this.store.update({ controlError }), fail,
|
|
79
|
+
}, signal);
|
|
75
80
|
try {
|
|
81
|
+
signal.throwIfAborted();
|
|
76
82
|
await this.options.authenticate(client);
|
|
83
|
+
signal.throwIfAborted();
|
|
77
84
|
await client.connect();
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const ready = new Promise((resolve, reject) => {
|
|
82
|
-
const timer = setTimeout(() => reject(new Error('Host ready timed out')), client.timeoutMs);
|
|
83
|
-
client.subscribe('$events', {}, {
|
|
84
|
-
item: value => {
|
|
85
|
-
const frame = object(value);
|
|
86
|
-
if (frame.type === 'ready') {
|
|
87
|
-
this.clientId = string(frame.clientId);
|
|
88
|
-
clearTimeout(timer);
|
|
89
|
-
resolve();
|
|
90
|
-
}
|
|
91
|
-
else if (frame.type === 'waterfall') {
|
|
92
|
-
if (this.listener.waterfall(frame))
|
|
93
|
-
return;
|
|
94
|
-
void client.call('$events/result', { clientId: this.clientId,
|
|
95
|
-
eventId: string(frame.eventId), outcome: { kind: 'next' } }).catch(error => fail(new Error(errorText(error))));
|
|
96
|
-
}
|
|
97
|
-
else if (frame.type === 'cancel') {
|
|
98
|
-
this.listener.cancelled(string(frame.eventId));
|
|
99
|
-
}
|
|
100
|
-
else if (frame.type === 'emit' && frame.event === 'api-session/status') {
|
|
101
|
-
this.acceptStatus(array(frame.args));
|
|
102
|
-
}
|
|
103
|
-
else if (frame.type === 'emit' && CATALOG_EVENTS.includes(String(frame.event))) {
|
|
104
|
-
this.listener.invalidated();
|
|
105
|
-
}
|
|
106
|
-
else if (frame.type === 'emit' && frame.event === 'api-session/error') {
|
|
107
|
-
const args = array(frame.args);
|
|
108
|
-
this.listener.error(args[0], args[1]);
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
end: error => { clearTimeout(timer); const reason = error ?? new Error('Event stream ended'); reject(reason); fail(reason); },
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
await ready;
|
|
115
|
-
await new Promise((resolve, reject) => {
|
|
116
|
-
const timer = setTimeout(() => reject(new Error('Session control baseline timed out')), client.timeoutMs);
|
|
117
|
-
client.subscribe('session/control', {}, {
|
|
118
|
-
item: value => {
|
|
119
|
-
try {
|
|
120
|
-
this.telemetry.accept(value);
|
|
121
|
-
this.store.update({});
|
|
122
|
-
clearTimeout(timer);
|
|
123
|
-
resolve();
|
|
124
|
-
}
|
|
125
|
-
catch (error) {
|
|
126
|
-
clearTimeout(timer);
|
|
127
|
-
reject(error);
|
|
128
|
-
fail(new Error(errorText(error)));
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
end: error => {
|
|
132
|
-
clearTimeout(timer);
|
|
133
|
-
if (error instanceof RemoteError && error.code === 'gateway/method-unavailable') {
|
|
134
|
-
this.store.update({ controlError: 'Live metrics unavailable on this host' });
|
|
135
|
-
resolve();
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
const reason = error ?? new Error('Session control stream ended');
|
|
139
|
-
reject(reason);
|
|
140
|
-
fail(reason);
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
});
|
|
144
|
-
});
|
|
85
|
+
signal.throwIfAborted();
|
|
86
|
+
await streams.start();
|
|
87
|
+
signal.throwIfAborted();
|
|
145
88
|
await this.listener.ready();
|
|
89
|
+
signal.throwIfAborted();
|
|
146
90
|
attempt = 0;
|
|
147
91
|
const error = await disconnected;
|
|
148
92
|
if (!this.abort.signal.aborted)
|
|
149
93
|
throw error;
|
|
150
94
|
}
|
|
151
95
|
catch (error) {
|
|
152
|
-
if (
|
|
153
|
-
|
|
96
|
+
if (this.abort.signal.aborted)
|
|
97
|
+
break;
|
|
98
|
+
const reason = generation.signal.aborted ? generation.signal.reason : error;
|
|
99
|
+
if (reason instanceof AuthenticationRequired || reason instanceof HttpError && [401, 403].includes(reason.status)) {
|
|
100
|
+
this.store.update({ lastFailure: `${errorText(reason)}. Set DSH_TOKEN and restart to log in.`, status: 'Login required' });
|
|
154
101
|
return;
|
|
155
102
|
}
|
|
156
|
-
|
|
157
|
-
this.store.update({ error: errorText(error), status: 'Reconnecting…' });
|
|
103
|
+
this.store.update({ lastFailure: errorText(reason), status: 'Reconnecting…' });
|
|
158
104
|
}
|
|
159
105
|
finally {
|
|
160
106
|
this.generationFailed = undefined;
|
|
161
|
-
|
|
107
|
+
generation.abort();
|
|
108
|
+
streams.close();
|
|
109
|
+
this.clientId = '';
|
|
110
|
+
this.store.update({ online: false });
|
|
162
111
|
await client.close();
|
|
112
|
+
if (this.current === client)
|
|
113
|
+
this.current = undefined;
|
|
163
114
|
await this.listener.ended();
|
|
164
115
|
}
|
|
165
116
|
if (!this.abort.signal.aborted) {
|
|
@@ -173,18 +124,4 @@ export class ConnectionController {
|
|
|
173
124
|
}
|
|
174
125
|
}
|
|
175
126
|
}
|
|
176
|
-
/** Apply one `api-session/status` notification to the running maps and the session view. */
|
|
177
|
-
acceptStatus(args) {
|
|
178
|
-
const sessionId = string(args[0]);
|
|
179
|
-
if (typeof args[1] !== 'boolean')
|
|
180
|
-
throw new Error('Invalid session running state');
|
|
181
|
-
if (args[1] && !this.runningUpdates.get(sessionId))
|
|
182
|
-
this.observedRunningAt.set(sessionId, Date.now());
|
|
183
|
-
if (!args[1])
|
|
184
|
-
this.observedRunningAt.delete(sessionId);
|
|
185
|
-
this.runningUpdates.set(sessionId, args[1]);
|
|
186
|
-
this.listener.status(sessionId, args[1]);
|
|
187
|
-
if (!args[1])
|
|
188
|
-
this.listener.idle();
|
|
189
|
-
}
|
|
190
127
|
}
|