dsh-pause-session 0.1.0 → 0.2.1
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/CHANGELOG.md +51 -20
- package/DEVELOPMENT.md +25 -2
- package/README.md +41 -31
- package/README.zh.md +31 -21
- package/REHEARSAL.md +6 -6
- package/lib/client.js +1125 -1375
- package/lib/client.js.map +1 -1
- package/lib/index.js +1107 -1081
- package/lib/index.js.map +1 -1
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +339 -0
- package/lib/typert.remote-client.d.ts +38 -0
- package/lib/typert.remote-client.d.ts.map +1 -0
- package/lib/typert.remote-client.js +244 -0
- package/lib/types/client/control.d.ts +25 -158
- package/lib/types/client/global.d.ts +39 -239
- package/lib/types/client/index.d.ts +6 -5
- package/lib/types/client/locales.d.ts +3 -4
- package/lib/types/client/pill.d.ts +5 -5
- package/lib/types/client/remote.d.ts +77 -0
- package/lib/types/client/view.d.ts +19 -5
- package/lib/types/coldlog.d.ts +1 -1
- package/lib/types/composition.d.ts +35 -61
- package/lib/types/control.d.ts +41 -60
- package/lib/types/global.d.ts +6 -4
- package/lib/types/index.d.ts +2 -2
- package/lib/types/park-state.d.ts +51 -0
- package/lib/types/registry.d.ts +1 -1
- package/lib/types/release-order.d.ts +25 -0
- package/lib/types/remote-adapter.d.ts +22 -0
- package/lib/types/remote.d.ts +158 -0
- package/lib/types/resume-activation.d.ts +36 -0
- package/lib/types/resume-text.d.ts +67 -0
- package/lib/types/resume.d.ts +7 -104
- package/lib/types/shared.d.ts +20 -123
- package/lib/types/snapshot.d.ts +29 -0
- package/lib/types/triage.d.ts +8 -9
- package/package.json +38 -19
- package/lib/types/client/burst.d.ts +0 -253
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native Remote transport for the pause controls.
|
|
3
|
+
*
|
|
4
|
+
* This module is deliberately self-contained: it imports only Cordis and the
|
|
5
|
+
* Typert decorators. The Typert generator analyzes this file alone so a
|
|
6
|
+
* third-party package can emit its Host reflection and Client contribution
|
|
7
|
+
* without pulling the plugin's DSH-typed modules into the generation face.
|
|
8
|
+
*
|
|
9
|
+
* The UI uses this namespace on Web and Desktop alike. No slash command is
|
|
10
|
+
* registered; the stream is the live status channel and the methods below are
|
|
11
|
+
* the button actions.
|
|
12
|
+
* @module dsh-pause-session/remote
|
|
13
|
+
*/
|
|
14
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
15
|
+
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
16
|
+
declare module '@deepseek-ai/dsh-typert-protocol' {
|
|
17
|
+
interface RemoteErrorDetailsMap {
|
|
18
|
+
/** The pause control is personal; only the owner may read or drive it. */
|
|
19
|
+
'pause/owner-only': {};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** The phase a Session reports to the controls. */
|
|
23
|
+
export type PausePhaseWire = 'active' | 'draining' | 'parking' | 'safe' | 'flush-failed';
|
|
24
|
+
/** One Session's pause state. */
|
|
25
|
+
export interface SessionStatusWire {
|
|
26
|
+
readonly phase: PausePhaseWire;
|
|
27
|
+
readonly runningTools: readonly string[];
|
|
28
|
+
readonly rearmGoal?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** The whole-app verdict. */
|
|
31
|
+
export interface GlobalStatusWire {
|
|
32
|
+
readonly verdict: 'idle' | 'waiting' | 'safe';
|
|
33
|
+
readonly registered: number;
|
|
34
|
+
readonly safe: number;
|
|
35
|
+
readonly parkedAt?: string;
|
|
36
|
+
readonly draining: readonly string[];
|
|
37
|
+
readonly parking: number;
|
|
38
|
+
readonly stalled: readonly string[];
|
|
39
|
+
readonly unresumable: readonly string[];
|
|
40
|
+
readonly unreadTrees: readonly string[];
|
|
41
|
+
readonly jobs: readonly string[];
|
|
42
|
+
readonly blind: readonly string[];
|
|
43
|
+
}
|
|
44
|
+
/** One live status snapshot: the aggregate plus every held Session. */
|
|
45
|
+
export interface PauseSnapshotWire {
|
|
46
|
+
readonly global: GlobalStatusWire;
|
|
47
|
+
readonly sessions: Readonly<Record<string, SessionStatusWire>>;
|
|
48
|
+
}
|
|
49
|
+
/** One row in the morning decision list. */
|
|
50
|
+
export interface TriageRowWire {
|
|
51
|
+
readonly sessionId: string;
|
|
52
|
+
readonly phase: 'draining' | 'parking' | 'flush-failed';
|
|
53
|
+
readonly updatedAt: number;
|
|
54
|
+
readonly reading: 'read' | 'unreadable';
|
|
55
|
+
readonly lastEvent?: string;
|
|
56
|
+
readonly turn?: number;
|
|
57
|
+
readonly step?: number;
|
|
58
|
+
readonly traces: readonly {
|
|
59
|
+
readonly tool: string;
|
|
60
|
+
readonly callId: string;
|
|
61
|
+
}[];
|
|
62
|
+
readonly owed: boolean;
|
|
63
|
+
readonly wakeable: boolean;
|
|
64
|
+
readonly rearmGoal: boolean;
|
|
65
|
+
}
|
|
66
|
+
/** One button action. */
|
|
67
|
+
export interface PauseActionRequest {
|
|
68
|
+
readonly action: 'pause' | 'resume' | 'pause-all' | 'resume-all' | 'cancel-all' | 'goal';
|
|
69
|
+
/** The Session the control is addressed through. */
|
|
70
|
+
readonly sessionId: string;
|
|
71
|
+
}
|
|
72
|
+
/** One action outcome. */
|
|
73
|
+
export interface PauseActionResultWire {
|
|
74
|
+
readonly ok: boolean;
|
|
75
|
+
readonly message: string;
|
|
76
|
+
}
|
|
77
|
+
/** One decision-list read. */
|
|
78
|
+
export interface PauseTriageRequest {
|
|
79
|
+
readonly caller: string;
|
|
80
|
+
}
|
|
81
|
+
/** One decision on a listed Session. */
|
|
82
|
+
export interface PauseDecisionRequest {
|
|
83
|
+
readonly caller: string;
|
|
84
|
+
readonly target: string;
|
|
85
|
+
readonly decision: 'continue' | 'note' | 'review' | 'leave' | 'goal';
|
|
86
|
+
}
|
|
87
|
+
export interface PauseRemoteApi {
|
|
88
|
+
snapshot(signal?: AbortSignal): Promise<PauseSnapshotWire>;
|
|
89
|
+
subscribe(listener: () => void): () => void;
|
|
90
|
+
act(request: PauseActionRequest, signal?: AbortSignal): Promise<PauseActionResultWire>;
|
|
91
|
+
triage(request: PauseTriageRequest, signal?: AbortSignal): Promise<readonly TriageRowWire[]>;
|
|
92
|
+
decide(request: PauseDecisionRequest, signal?: AbortSignal): Promise<PauseActionResultWire>;
|
|
93
|
+
}
|
|
94
|
+
declare module '@deepseek-ai/cordis' {
|
|
95
|
+
interface Context {
|
|
96
|
+
pauseSession: PauseRemote;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** Host service exposed to the browser as the `pauseSession` Remote namespace. */
|
|
100
|
+
export declare class PauseRemote extends TypertRemoteService {
|
|
101
|
+
private readonly api;
|
|
102
|
+
/** One snapshot per host version, shared by every connected observer. */
|
|
103
|
+
private snapshotCache;
|
|
104
|
+
/** Bumped by every host notification; each observer compares it to its own cursor. */
|
|
105
|
+
private version;
|
|
106
|
+
/** Observers waiting for the next version. */
|
|
107
|
+
private readonly waiters;
|
|
108
|
+
private readonly unsubscribe;
|
|
109
|
+
/**
|
|
110
|
+
* @param ctx - host context owning the service.
|
|
111
|
+
* @param api - the pause engine behind the wire methods.
|
|
112
|
+
*/
|
|
113
|
+
constructor(ctx: Context, api: PauseRemoteApi);
|
|
114
|
+
/**
|
|
115
|
+
* One exact snapshot, used by tests and by a reconnect that cannot wait for
|
|
116
|
+
* the first stream item.
|
|
117
|
+
* @param signal - carrier cancellation.
|
|
118
|
+
* @returns the current aggregate and session states.
|
|
119
|
+
*/
|
|
120
|
+
snapshot(signal?: AbortSignal): Promise<PauseSnapshotWire>;
|
|
121
|
+
/**
|
|
122
|
+
* The snapshot for one host version, computed once even when several clients
|
|
123
|
+
* are watching. A new notification discards the cached promise.
|
|
124
|
+
* @param version - the host version this snapshot answers.
|
|
125
|
+
* @param signal - stream cancellation.
|
|
126
|
+
* @returns the shared snapshot promise.
|
|
127
|
+
*/
|
|
128
|
+
private snapshotFor;
|
|
129
|
+
/**
|
|
130
|
+
* Live status: the opening snapshot, then one new snapshot whenever the host
|
|
131
|
+
* reports a change.
|
|
132
|
+
* @param signal - stream cancellation.
|
|
133
|
+
* @returns the snapshot stream.
|
|
134
|
+
*/
|
|
135
|
+
observe(signal?: AbortSignal): AsyncIterable<PauseSnapshotWire>;
|
|
136
|
+
/**
|
|
137
|
+
* Pause, resume, press every tree, resume every clean park, or flip one
|
|
138
|
+
* Session's goal re-arm.
|
|
139
|
+
* @param request - the button action.
|
|
140
|
+
* @param signal - carrier cancellation.
|
|
141
|
+
* @returns the user-facing outcome.
|
|
142
|
+
*/
|
|
143
|
+
act(request: PauseActionRequest, signal?: AbortSignal): Promise<PauseActionResultWire>;
|
|
144
|
+
/**
|
|
145
|
+
* Read the morning decision list.
|
|
146
|
+
* @param request - the calling Session whose list is read.
|
|
147
|
+
* @param signal - read cancellation.
|
|
148
|
+
* @returns the listed rows.
|
|
149
|
+
*/
|
|
150
|
+
triage(request: PauseTriageRequest, signal?: AbortSignal): Promise<readonly TriageRowWire[]>;
|
|
151
|
+
/**
|
|
152
|
+
* Take one decision on one listed Session.
|
|
153
|
+
* @param request - the caller, target, and decision.
|
|
154
|
+
* @param signal - load cancellation.
|
|
155
|
+
* @returns the user-facing outcome.
|
|
156
|
+
*/
|
|
157
|
+
decide(request: PauseDecisionRequest, signal?: AbortSignal): Promise<PauseActionResultWire>;
|
|
158
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactivate one parked Session and deliver the wake it owes.
|
|
3
|
+
*
|
|
4
|
+
* The two Session kinds come back through different owners. An ordinary
|
|
5
|
+
* Session is loaded by this plugin and given the route its own log recorded.
|
|
6
|
+
* A subagent child belongs to the subagent runtime: delivering the wake through
|
|
7
|
+
* `ctx.subagents.prompt` is what cold-resumes it as a managed activation, under
|
|
8
|
+
* its live tree root, with its persisted composition and tree membership
|
|
9
|
+
* restored by the runtime itself.
|
|
10
|
+
*
|
|
11
|
+
* Both paths keep the same release order: the durable record goes first, then
|
|
12
|
+
* the gate, so a record that cannot be dropped leaves the Session parked.
|
|
13
|
+
* @module dsh-pause-session/resume-activation
|
|
14
|
+
*/
|
|
15
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
16
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
17
|
+
import type { SessionId } from '@deepseek-ai/dsh-session';
|
|
18
|
+
import type { PauseGate } from './gate.js';
|
|
19
|
+
import type { ParkRegistry } from './registry.js';
|
|
20
|
+
import type { ResumeAttempt, ResumeOptions, WakeRequest } from './resume-text.js';
|
|
21
|
+
/** The activation entry points the resume path composes. */
|
|
22
|
+
export interface Activator {
|
|
23
|
+
activate(sessionId: SessionId, request: WakeRequest, rearm: boolean, signal?: AbortSignal): Promise<ResumeAttempt>;
|
|
24
|
+
ensureRoute(agent: Agent): void;
|
|
25
|
+
wake(agent: Agent, request: WakeRequest): void;
|
|
26
|
+
rearmGoal(agent: Agent): void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build the activation closure.
|
|
30
|
+
* @param ctx - host context carrying the agent store, subagent runtime, and goal service.
|
|
31
|
+
* @param gate - the pause gate released after activation.
|
|
32
|
+
* @param registry - the durable list the release forgets from.
|
|
33
|
+
* @param options - the route knowledge the root wake content depends on.
|
|
34
|
+
* @returns the activation methods the resume path uses.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createActivator(ctx: Context, gate: PauseGate, registry: ParkRegistry, options: ResumeOptions): Activator;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-facing copy and result shapes for the clean resume and tree release.
|
|
3
|
+
* @module dsh-pause-session/resume-text
|
|
4
|
+
*/
|
|
5
|
+
import type { SessionId } from '@deepseek-ai/dsh-session';
|
|
6
|
+
import type { PauseAnswer } from './shared.js';
|
|
7
|
+
/** Route knowledge the clean resume path needs. */
|
|
8
|
+
export interface ResumeOptions {
|
|
9
|
+
/** Provider routes whose request conversion drops an empty user message. */
|
|
10
|
+
readonly silentWakeRoutes: readonly string[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The one wake content a route that keeps an empty user message is given.
|
|
14
|
+
*/
|
|
15
|
+
export declare const WAKE_MARKER = "[pause: resumed from a pause]";
|
|
16
|
+
/** How one resume asks the loop for the request it owes the session. */
|
|
17
|
+
export type WakeRequest = {
|
|
18
|
+
readonly kind: 'silent';
|
|
19
|
+
} | {
|
|
20
|
+
readonly kind: 'message';
|
|
21
|
+
readonly text: string;
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: 'none';
|
|
24
|
+
};
|
|
25
|
+
/** Result copy for a resumed session; the model never sees it. */
|
|
26
|
+
export declare const RESUMED_TEXT = "This session resumed from where it paused.";
|
|
27
|
+
/** Result copy for a registered session whose park did not finish cleanly. */
|
|
28
|
+
export declare const UNCLEAN_TEXT: string;
|
|
29
|
+
/** Result copy when nothing is parked under that session. */
|
|
30
|
+
export declare const NOT_PARKED_TEXT = "pause has no pause recorded for this session.";
|
|
31
|
+
/** Result copy for a session that is parked but could not be loaded back. */
|
|
32
|
+
export declare const ACTIVATION_FAILED_TEXT = "pause could not reopen this session, so it stayed paused.";
|
|
33
|
+
/** Result copy for a one-shot subagent route. */
|
|
34
|
+
export declare const UNRESUMABLE_TEXT = "pause did not resume this session: it is a one-shot subagent route and cannot be resumed.";
|
|
35
|
+
/** Result copy for the review decision. */
|
|
36
|
+
export declare const REVIEW_TEXT: string;
|
|
37
|
+
/** Copy for one goal opt-out change. */
|
|
38
|
+
export declare const REARM_GOAL_ON_TEXT = "pause will re-open this session's goal when it resumes it.";
|
|
39
|
+
export declare const REARM_GOAL_OFF_TEXT = "pause will leave this session's goal closed when it resumes it.";
|
|
40
|
+
/** Why one record did not produce a running session. */
|
|
41
|
+
export type ResumeRefusal = 'not-parked' | 'not-clean' | 'activation-failed' | 'unrecorded' | 'not-activated' | 'unresumable';
|
|
42
|
+
/** What one resume attempt did. */
|
|
43
|
+
export interface ResumeOutcome {
|
|
44
|
+
readonly sessionId: SessionId;
|
|
45
|
+
readonly resumed: boolean;
|
|
46
|
+
readonly refusal?: ResumeRefusal;
|
|
47
|
+
}
|
|
48
|
+
/** One resume attempt plus the answer the caller receives. */
|
|
49
|
+
export interface ResumeAttempt extends ResumeOutcome {
|
|
50
|
+
readonly answer: PauseAnswer;
|
|
51
|
+
}
|
|
52
|
+
/** What releasing one session's registered tree did. */
|
|
53
|
+
export interface ReleaseTreeOutcome {
|
|
54
|
+
readonly members: number;
|
|
55
|
+
readonly resumed: number;
|
|
56
|
+
readonly refusals: readonly {
|
|
57
|
+
readonly sessionId: SessionId;
|
|
58
|
+
readonly refusal: ResumeRefusal;
|
|
59
|
+
}[];
|
|
60
|
+
readonly answer: PauseAnswer;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* How one tree-wide release answers the person who pressed it.
|
|
64
|
+
* @param released - the sessions this release covered, in release order.
|
|
65
|
+
* @returns one sentence about what came back and what did not.
|
|
66
|
+
*/
|
|
67
|
+
export declare function summarizeTreeRelease(released: readonly ResumeAttempt[]): string;
|
package/lib/types/resume.d.ts
CHANGED
|
@@ -32,10 +32,12 @@
|
|
|
32
32
|
* @module dsh-pause-session/resume
|
|
33
33
|
*/
|
|
34
34
|
import type { Context } from '@deepseek-ai/cordis';
|
|
35
|
-
import type { CommandResult } from '@deepseek-ai/dsh-commands';
|
|
36
35
|
import type { SessionId } from '@deepseek-ai/dsh-session';
|
|
37
36
|
import type { PauseGate } from './gate.js';
|
|
38
37
|
import type { ParkRegistry } from './registry.js';
|
|
38
|
+
import type { PauseAnswer } from './shared.js';
|
|
39
|
+
export * from './resume-text.js';
|
|
40
|
+
import type { ReleaseTreeOutcome, ResumeAttempt, ResumeOptions, WakeRequest } from './resume-text.js';
|
|
39
41
|
declare module '@deepseek-ai/dsh-llm' {
|
|
40
42
|
interface MessageSourceMap {
|
|
41
43
|
/**
|
|
@@ -49,78 +51,13 @@ declare module '@deepseek-ai/dsh-llm' {
|
|
|
49
51
|
};
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
|
-
/**
|
|
53
|
-
* The one wake content a route that keeps an empty user message is given. It
|
|
54
|
-
* names its producer, because it lands in the same user turn as the input the
|
|
55
|
-
* model owes an answer to and must not read as part of it.
|
|
56
|
-
*/
|
|
57
|
-
export declare const WAKE_MARKER = "[pause: resumed from a pause]";
|
|
58
|
-
/**
|
|
59
|
-
* How one resume asks the loop for the request it owes the session:
|
|
60
|
-
*
|
|
61
|
-
* - `silent`: the clean path's wake — an empty input on a route the
|
|
62
|
-
* composition declared silent, and the visible marker on any other route.
|
|
63
|
-
* - `message`: the decision list's "continue, and say the tool outcome is
|
|
64
|
-
* unknown" — user-visible text on the wire by construction, and the only
|
|
65
|
-
* resume that is not invisible.
|
|
66
|
-
* - `none`: no wake at all. This is what "leave it for me to read" costs: the
|
|
67
|
-
* session is not activated, nothing is asked of the model, and the park is
|
|
68
|
-
* exactly as it was.
|
|
69
|
-
*/
|
|
70
|
-
export type WakeRequest = {
|
|
71
|
-
readonly kind: 'silent';
|
|
72
|
-
} | {
|
|
73
|
-
readonly kind: 'message';
|
|
74
|
-
readonly text: string;
|
|
75
|
-
} | {
|
|
76
|
-
readonly kind: 'none';
|
|
77
|
-
};
|
|
78
|
-
/** Result copy for a resumed session; the model never sees it. */
|
|
79
|
-
export declare const RESUMED_TEXT = "This session resumed from where it paused.";
|
|
80
|
-
/**
|
|
81
|
-
* Result copy for a registered session this path refuses: its durable state is
|
|
82
|
-
* not the outcome of a completed park, so waking it would be a guess.
|
|
83
|
-
*/
|
|
84
|
-
export declare const UNCLEAN_TEXT: string;
|
|
85
|
-
/** Result copy when nothing is parked under that session. */
|
|
86
|
-
export declare const NOT_PARKED_TEXT = "pause has no pause recorded for this session.";
|
|
87
|
-
/** Result copy for a session that is parked but could not be loaded back. */
|
|
88
|
-
export declare const ACTIVATION_FAILED_TEXT = "pause could not reopen this session, so it stayed paused.";
|
|
89
|
-
/** Result copy for a one-shot subagent route: its Session exists, but no resume may reactivate it. */
|
|
90
|
-
export declare const UNRESUMABLE_TEXT = "pause did not resume this session: it is a one-shot subagent route and cannot be resumed.";
|
|
91
|
-
/**
|
|
92
|
-
* Result copy for the review decision. It is the one answer that promises
|
|
93
|
-
* nothing happened, because opening a session to read it is the user's own
|
|
94
|
-
* action in their session list — and activating its agent here would start a
|
|
95
|
-
* session they asked only to look at.
|
|
96
|
-
*/
|
|
97
|
-
export declare const REVIEW_TEXT: string;
|
|
98
|
-
/** Result copy for a change the durable registry refused to record. */
|
|
99
|
-
export declare const UNRECORDED_TEXT = "pause could not write the pause registry, so it did not change the pause state.";
|
|
100
|
-
/** Copy for one goal opt-out change. */
|
|
101
|
-
export declare const REARM_GOAL_ON_TEXT = "pause will re-open this session's goal when it resumes it.";
|
|
102
|
-
export declare const REARM_GOAL_OFF_TEXT = "pause will leave this session's goal closed when it resumes it.";
|
|
103
|
-
/** Why one record did not produce a running session. */
|
|
104
|
-
export type ResumeRefusal = 'not-parked' | 'not-clean' | 'activation-failed' | 'unrecorded' | 'not-activated' | 'unresumable';
|
|
105
|
-
/** What one resume attempt did. */
|
|
106
|
-
export interface ResumeOutcome {
|
|
107
|
-
readonly sessionId: SessionId;
|
|
108
|
-
/** Whether the session is now running from the point it stopped. */
|
|
109
|
-
readonly resumed: boolean;
|
|
110
|
-
/** Present exactly when `resumed` is false. */
|
|
111
|
-
readonly refusal?: ResumeRefusal;
|
|
112
|
-
}
|
|
113
|
-
/** One resume attempt plus the answer the command that asked for it receives. */
|
|
114
|
-
export interface ResumeAttempt extends ResumeOutcome {
|
|
115
|
-
readonly answer: CommandResult;
|
|
116
|
-
}
|
|
117
54
|
/** How this path is wired into the session control that owns the pause state. */
|
|
118
55
|
export interface ResumeDeps {
|
|
119
56
|
/**
|
|
120
57
|
* Take a live session's pause back: the durable record goes first, then the
|
|
121
58
|
* gate. Owned by the session control so there is one release order.
|
|
122
59
|
*/
|
|
123
|
-
release(sessionId: SessionId, text: string): Promise<
|
|
60
|
+
release(sessionId: SessionId, text: string): Promise<PauseAnswer>;
|
|
124
61
|
/**
|
|
125
62
|
* Whether the pause this process holds was adopted from the registry rather
|
|
126
63
|
* than pressed here. Only an adopted pause is a restart: a press this process
|
|
@@ -128,27 +65,16 @@ export interface ResumeDeps {
|
|
|
128
65
|
*/
|
|
129
66
|
adopted(sessionId: SessionId): boolean;
|
|
130
67
|
}
|
|
131
|
-
/** Route knowledge this path needs from the composition. */
|
|
132
|
-
export interface ResumeOptions {
|
|
133
|
-
/**
|
|
134
|
-
* Provider routes whose request conversion drops an empty user message, so an
|
|
135
|
-
* empty wake never reaches the model. Deployment-owned because it is a
|
|
136
|
-
* property of the adapter behind each route, and a third-party plugin cannot
|
|
137
|
-
* introspect an adapter.
|
|
138
|
-
*/
|
|
139
|
-
readonly silentWakeRoutes: readonly string[];
|
|
140
|
-
}
|
|
141
68
|
/** The clean resume path, as the session control drives it. */
|
|
142
69
|
export interface ResumePath {
|
|
143
70
|
/**
|
|
144
71
|
* Resume one session the registry remembers.
|
|
145
72
|
* @param sessionId - the session to resume.
|
|
146
73
|
* @param request - which wake this resume delivers; see {@link WakeRequest}.
|
|
147
|
-
* @param parentId - the direct parent a batch release already brought back, when there is one.
|
|
148
74
|
* @param signal - cancellation for the cold load and setup.
|
|
149
75
|
* @returns what happened, and the copy for whoever asked.
|
|
150
76
|
*/
|
|
151
|
-
resumeSession(sessionId: SessionId, request: WakeRequest,
|
|
77
|
+
resumeSession(sessionId: SessionId, request: WakeRequest, signal?: AbortSignal): Promise<ResumeAttempt>;
|
|
152
78
|
/**
|
|
153
79
|
* Resume one session the decision list officially owns — a record that is
|
|
154
80
|
* known NOT to be clean, which the clean path above must refuse and this entry
|
|
@@ -159,11 +85,10 @@ export interface ResumePath {
|
|
|
159
85
|
* or only answers it (`'review'`). A review activates nothing and writes
|
|
160
86
|
* nothing: opening a session to read it is the user's own action, not this
|
|
161
87
|
* plugin's.
|
|
162
|
-
* @param parentId - the direct parent a batch release already brought back, when there is one.
|
|
163
88
|
* @param signal - cancellation for the cold load and setup.
|
|
164
89
|
* @returns what happened, and the copy for whoever asked.
|
|
165
90
|
*/
|
|
166
|
-
decideUnclean(sessionId: SessionId, request: WakeRequest, finalize: 'release' | 'review',
|
|
91
|
+
decideUnclean(sessionId: SessionId, request: WakeRequest, finalize: 'release' | 'review', signal?: AbortSignal): Promise<ResumeAttempt>;
|
|
167
92
|
/**
|
|
168
93
|
* Resume every session the registry remembers, clean ones only. One session's
|
|
169
94
|
* failure never stops the others.
|
|
@@ -177,7 +102,7 @@ export interface ResumePath {
|
|
|
177
102
|
* @param rearmGoal - whether the clean resume path may re-arm its goal.
|
|
178
103
|
* @returns the copy for whoever asked.
|
|
179
104
|
*/
|
|
180
|
-
setRearmGoal(sessionId: SessionId, rearmGoal: boolean): Promise<
|
|
105
|
+
setRearmGoal(sessionId: SessionId, rearmGoal: boolean): Promise<PauseAnswer>;
|
|
181
106
|
/**
|
|
182
107
|
* Release one parked session and the registered members of its tree: the
|
|
183
108
|
* counterpart of a press that registered a whole tree.
|
|
@@ -187,28 +112,6 @@ export interface ResumePath {
|
|
|
187
112
|
*/
|
|
188
113
|
releaseTree(sessionId: SessionId, signal?: AbortSignal): Promise<ReleaseTreeOutcome>;
|
|
189
114
|
}
|
|
190
|
-
/** What releasing one session's registered tree did. */
|
|
191
|
-
export interface ReleaseTreeOutcome {
|
|
192
|
-
/** How many sessions this release covered: the session plus its registered descendants. */
|
|
193
|
-
readonly members: number;
|
|
194
|
-
/** How many of them are running again. */
|
|
195
|
-
readonly resumed: number;
|
|
196
|
-
/** How many could not be resumed, and why the release did not take them back. */
|
|
197
|
-
readonly refusals: readonly {
|
|
198
|
-
readonly sessionId: SessionId;
|
|
199
|
-
readonly refusal: ResumeRefusal;
|
|
200
|
-
}[];
|
|
201
|
-
/** The copy for whoever pressed the release. */
|
|
202
|
-
readonly answer: CommandResult;
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* How one tree-wide release answers the person who pressed it. One release, one
|
|
206
|
-
* sentence about all of it: what came back, and — by name, because those rows
|
|
207
|
-
* are what the morning list is for — what did not.
|
|
208
|
-
* @param released - the sessions this release covered, in release order.
|
|
209
|
-
* @returns the result text, e.g. `pause resumed 2 sessions from where they stopped; "child" did not pause completely`.
|
|
210
|
-
*/
|
|
211
|
-
export declare function summarizeTreeRelease(released: readonly ResumeAttempt[]): string;
|
|
212
115
|
/**
|
|
213
116
|
* Build the clean resume path.
|
|
214
117
|
* @param ctx - host context carrying the agent store, the session store, and the goal service when one is mounted.
|
package/lib/types/shared.d.ts
CHANGED
|
@@ -1,81 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The identities both halves of dsh-pause-session name, the
|
|
3
|
-
* share, and the one spelling a host log line gives a caught value.
|
|
2
|
+
* The identities both halves of dsh-pause-session name, the phase vocabulary
|
|
3
|
+
* they share, and the one spelling a host log line gives a caught value.
|
|
4
4
|
*
|
|
5
5
|
* The browser bundle may value-import only the shell's baseline module table,
|
|
6
|
-
* so this module imports nothing
|
|
7
|
-
*
|
|
8
|
-
* identities from the same strings.
|
|
9
|
-
*
|
|
10
|
-
* A third-party plugin's only live channel to the browser is the command
|
|
11
|
-
* registry — it can add neither a `ctx.remote` namespace nor a forwarded event,
|
|
12
|
-
* both of which are compiled into the harness's own API assembly. A command
|
|
13
|
-
* descriptor's only free-form field is its `description`, and a command
|
|
14
|
-
* result's only free-form field is its `text`, so the park state travels as a
|
|
15
|
-
* prefix plus `;`-separated fields on one of those. The text stays
|
|
16
|
-
* human-readable: the same words are what the slash-command menu shows.
|
|
17
|
-
*
|
|
18
|
-
* Every value inside a field is escaped, so a decoded name is the exact name
|
|
19
|
-
* that was encoded. Session ids, tool names, and call ids are the host's own
|
|
20
|
-
* data and may contain the `;`, `,`, `/`, or newline a field is separated by; a
|
|
21
|
-
* folded spelling would decode as a different name — a different row, looked up
|
|
22
|
-
* again.
|
|
6
|
+
* so this module imports nothing. The native Remote payloads are the live
|
|
7
|
+
* vocabulary; there is no command encoding or slash-command surface here.
|
|
23
8
|
* @module dsh-pause-session/shared
|
|
24
9
|
*/
|
|
25
|
-
/**
|
|
26
|
-
export declare const
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
/** Command that reports the receiving session's park state; registered only while it is paused. */
|
|
36
|
-
export declare const STATUS_COMMAND = "pause-state";
|
|
37
|
-
/** Command that turns the receiving session's own goal re-arm on or off; registered only while it is paused. */
|
|
38
|
-
export declare const GOAL_COMMAND = "pause-goal";
|
|
39
|
-
/** Command that reports every session that did not stop cleanly. */
|
|
40
|
-
export declare const TRIAGE_COMMAND = "pause-triage";
|
|
41
|
-
/** Command that resumes one session from the decision list exactly as the clean path would. */
|
|
42
|
-
export declare const TRIAGE_CONTINUE_COMMAND = "pause-triage-continue";
|
|
43
|
-
/** Command that resumes one session from the decision list with the unknown-outcome note. */
|
|
44
|
-
export declare const TRIAGE_NOTE_COMMAND = "pause-triage-note";
|
|
45
|
-
/** Command that opens one session from the decision list without spending a request. */
|
|
46
|
-
export declare const TRIAGE_REVIEW_COMMAND = "pause-triage-review";
|
|
47
|
-
/** Command that leaves one session from the decision list exactly as it is. */
|
|
48
|
-
export declare const TRIAGE_LEAVE_COMMAND = "pause-triage-leave";
|
|
49
|
-
/** Command that turns one listed session's goal re-arm on or off. */
|
|
50
|
-
export declare const TRIAGE_GOAL_COMMAND = "pause-triage-goal";
|
|
51
|
-
/** Stable definition id of the pause command, matched by identity rather than by copy. */
|
|
52
|
-
export declare const PAUSE_DEFINITION_ID = "dsh-pause-session/pause";
|
|
53
|
-
/** Stable definition id of the resume command: the host's own "this session is paused" fact. */
|
|
54
|
-
export declare const RESUME_DEFINITION_ID = "dsh-pause-session/resume";
|
|
55
|
-
/** Stable definition id of the global resume command, matched by identity rather than by copy. */
|
|
56
|
-
export declare const RESUME_ALL_DEFINITION_ID = "dsh-pause-session/resume-all";
|
|
57
|
-
/** Stable definition id of the whole-app pause command. */
|
|
58
|
-
export declare const PAUSE_ALL_DEFINITION_ID = "dsh-pause-session/pause-all";
|
|
59
|
-
/** Stable definition id of the whole-app status read. */
|
|
60
|
-
export declare const STATE_ALL_DEFINITION_ID = "dsh-pause-session/state-all";
|
|
61
|
-
/** Stable definition id of the status read, matched by identity rather than by copy. */
|
|
62
|
-
export declare const STATUS_DEFINITION_ID = "dsh-pause-session/status";
|
|
63
|
-
/** Stable definition id of the paused session's own goal re-arm toggle. */
|
|
64
|
-
export declare const GOAL_DEFINITION_ID = "dsh-pause-session/goal";
|
|
65
|
-
/** Stable definition id of the decision-list read. */
|
|
66
|
-
export declare const TRIAGE_DEFINITION_ID = "dsh-pause-session/triage";
|
|
67
|
-
/** Stable definition id of the decision-list "continue" verb. */
|
|
68
|
-
export declare const TRIAGE_CONTINUE_DEFINITION_ID = "dsh-pause-session/triage-continue";
|
|
69
|
-
/** Stable definition id of the decision-list "continue with the unknown-outcome note" verb. */
|
|
70
|
-
export declare const TRIAGE_NOTE_DEFINITION_ID = "dsh-pause-session/triage-note";
|
|
71
|
-
/** Stable definition id of the decision-list "open without activating" verb. */
|
|
72
|
-
export declare const TRIAGE_REVIEW_DEFINITION_ID = "dsh-pause-session/triage-review";
|
|
73
|
-
/** Stable definition id of the decision-list "leave it alone today" verb. */
|
|
74
|
-
export declare const TRIAGE_LEAVE_DEFINITION_ID = "dsh-pause-session/triage-leave";
|
|
75
|
-
/** Stable definition id of the decision-list goal re-arm toggle. */
|
|
76
|
-
export declare const TRIAGE_GOAL_DEFINITION_ID = "dsh-pause-session/triage-goal";
|
|
77
|
-
/** First token of every encoded status, so a descriptor is never parsed by accident. */
|
|
78
|
-
export declare const STATUS_PREFIX = "pause: ";
|
|
10
|
+
/** Result copy for a press or a release the durable registry refused to record. */
|
|
11
|
+
export declare const UNRECORDED_TEXT = "pause could not write the pause registry, so it did not change the pause state.";
|
|
12
|
+
/**
|
|
13
|
+
* One user-facing answer from an action. The controls render `text` verbatim;
|
|
14
|
+
* `kind` only says whether the press succeeded.
|
|
15
|
+
*/
|
|
16
|
+
export interface PauseAnswer {
|
|
17
|
+
readonly kind: 'success' | 'error';
|
|
18
|
+
readonly text: string;
|
|
19
|
+
}
|
|
79
20
|
/**
|
|
80
21
|
* One log line's text for a caught value.
|
|
81
22
|
* @param error - the caught value.
|
|
@@ -137,24 +78,11 @@ export interface ParkStatus {
|
|
|
137
78
|
*/
|
|
138
79
|
readonly rearmGoal?: boolean;
|
|
139
80
|
}
|
|
140
|
-
/**
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
export declare function encodeParkStatus(status: ParkStatus): string;
|
|
146
|
-
/**
|
|
147
|
-
* Decode a status previously written by {@link encodeParkStatus}.
|
|
148
|
-
* @param text - a command descriptor's description.
|
|
149
|
-
* @returns the status, or `undefined` when this text carries none — a foreign
|
|
150
|
-
* command, or a reading taken before the host published anything.
|
|
151
|
-
*/
|
|
152
|
-
export declare function decodeParkStatus(text: string): ParkStatus | undefined;
|
|
153
|
-
/**
|
|
154
|
-
* First token of every encoded whole-app status. A different prefix from the
|
|
155
|
-
* per-session status on purpose: one decoder must never read the other's text.
|
|
156
|
-
*/
|
|
157
|
-
export declare const GLOBAL_STATUS_PREFIX = "pause all: ";
|
|
81
|
+
/** One JSON snapshot: the whole-app verdict plus every live paused session. */
|
|
82
|
+
export interface PauseSnapshot {
|
|
83
|
+
readonly global: GlobalStatus;
|
|
84
|
+
readonly sessions: Readonly<Record<string, ParkStatus>>;
|
|
85
|
+
}
|
|
158
86
|
/** The whole-app answer to "can I close the lid?". */
|
|
159
87
|
export type GlobalVerdict = 'idle' | 'waiting' | 'safe';
|
|
160
88
|
/** A surface the whole-app report could not read at all. */
|
|
@@ -193,7 +121,7 @@ export interface GlobalStatus {
|
|
|
193
121
|
readonly parkedAt?: string;
|
|
194
122
|
/**
|
|
195
123
|
* Registered sessions still working: a tool is in flight or a turn is between
|
|
196
|
-
* steps. Their park point is announced
|
|
124
|
+
* steps. Their park point is announced on the native stream the park
|
|
197
125
|
* registers, so a reader has nothing to watch here.
|
|
198
126
|
*/
|
|
199
127
|
readonly draining: readonly string[];
|
|
@@ -221,25 +149,6 @@ export interface GlobalStatus {
|
|
|
221
149
|
/** Whole surfaces the report could not read, so their emptiness is not a fact. */
|
|
222
150
|
readonly blind: readonly GlobalBlindSpot[];
|
|
223
151
|
}
|
|
224
|
-
/**
|
|
225
|
-
* Encode one whole-app status for a command result.
|
|
226
|
-
* @param status - the state to publish.
|
|
227
|
-
* @returns the result text, e.g.
|
|
228
|
-
* `pause all: waiting; registered: 3; safe: 1; parked-at: overnight; draining: overnight; parking: 1; stalled: -; unresumable: -; unread-trees: -; jobs: bash-1; blind: -`.
|
|
229
|
-
*/
|
|
230
|
-
export declare function encodeGlobalStatus(status: GlobalStatus): string;
|
|
231
|
-
/**
|
|
232
|
-
* Decode a whole-app status previously written by {@link encodeGlobalStatus}.
|
|
233
|
-
* @param text - a command result's text.
|
|
234
|
-
* @returns the status, or `undefined` when this text carries none.
|
|
235
|
-
*/
|
|
236
|
-
export declare function decodeGlobalStatus(text: string): GlobalStatus | undefined;
|
|
237
|
-
/**
|
|
238
|
-
* First token of every encoded decision list. Separate from the per-session and
|
|
239
|
-
* whole-app status prefixes on purpose, for the same reason those two are
|
|
240
|
-
* separate: one decoder must never read another's text.
|
|
241
|
-
*/
|
|
242
|
-
export declare const TRIAGE_PREFIX = "pause triage: ";
|
|
243
152
|
/** How one decision-list row was read out of the session's own stored log. */
|
|
244
153
|
export type TriageReading = 'read' | 'unreadable';
|
|
245
154
|
/**
|
|
@@ -310,15 +219,3 @@ export interface TriageList {
|
|
|
310
219
|
export declare const TRIAGE_ACTIONS: readonly ["continue", "note", "review", "leave", "goal"];
|
|
311
220
|
/** One decision the list offers. */
|
|
312
221
|
export type TriageAction = (typeof TRIAGE_ACTIONS)[number];
|
|
313
|
-
/**
|
|
314
|
-
* Encode one decision list for a command result.
|
|
315
|
-
* @param list - the rows to publish.
|
|
316
|
-
* @returns the result text, e.g. `pause triage: 1; row: overnight; phase: draining; stopped: tool/call/turn 1 step 1; tools: gated; wake: yes`.
|
|
317
|
-
*/
|
|
318
|
-
export declare function encodeTriageList(list: TriageList): string;
|
|
319
|
-
/**
|
|
320
|
-
* Decode a decision list previously written by {@link encodeTriageList}.
|
|
321
|
-
* @param text - a command result's text.
|
|
322
|
-
* @returns the list, or `undefined` when this text carries none.
|
|
323
|
-
*/
|
|
324
|
-
export declare function decodeTriageList(text: string): TriageList | undefined;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure projection of the durable park and each live tree into the native
|
|
3
|
+
* snapshot. This module owns the phase fold and the goal opt-out; it does not
|
|
4
|
+
* press, release, or decide anything.
|
|
5
|
+
* @module dsh-pause-session/snapshot
|
|
6
|
+
*/
|
|
7
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
8
|
+
import type { SessionId } from '@deepseek-ai/dsh-session';
|
|
9
|
+
import type { ParkWatch } from './park.js';
|
|
10
|
+
import type { ParkRegistry } from './registry.js';
|
|
11
|
+
import type { TreeWalk } from './tree.js';
|
|
12
|
+
import type { ParkMark } from './park-state.js';
|
|
13
|
+
import type { GlobalStatus, PauseSnapshot } from './shared.js';
|
|
14
|
+
/** What the snapshot projection needs from the control. */
|
|
15
|
+
export interface SnapshotDeps {
|
|
16
|
+
readonly ctx: Context;
|
|
17
|
+
readonly marks: ReadonlyMap<SessionId, ParkMark>;
|
|
18
|
+
readonly watch: ParkWatch;
|
|
19
|
+
readonly registry: ParkRegistry;
|
|
20
|
+
/** Read the whole-app aggregate, reusing the walks this projection already paid for. */
|
|
21
|
+
readGlobal(signal?: AbortSignal, walks?: ReadonlyMap<SessionId, TreeWalk>): Promise<GlobalStatus>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read every live mark and the whole-app aggregate in one pass.
|
|
25
|
+
* @param deps - the control-owned marks, watch, registry, and aggregate reader.
|
|
26
|
+
* @param signal - cancellation for the tree walks and aggregate.
|
|
27
|
+
* @returns the native snapshot.
|
|
28
|
+
*/
|
|
29
|
+
export declare function readSnapshot(deps: SnapshotDeps, signal?: AbortSignal): Promise<PauseSnapshot>;
|