dsh-watcher 0.6.0 → 0.8.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.
- package/README.en.md +44 -13
- package/README.md +44 -13
- package/lib/client.js +1110 -901
- package/lib/client.js.map +1 -1
- package/lib/dsh-watcher.js +53 -5
- package/lib/types/client/Insights.d.ts +18 -0
- package/lib/types/client/SidebarTab.d.ts +52 -0
- package/lib/types/client/TimingPanel.d.ts +7 -0
- package/lib/types/client/Watcher.d.ts +56 -0
- package/lib/types/client/disclosure-depth.d.ts +22 -0
- package/lib/types/client/history-loader.d.ts +23 -0
- package/lib/types/client/index.d.ts +9 -0
- package/lib/types/client/model-trace-definition.d.ts +11 -0
- package/lib/types/client/step-timeline.d.ts +15 -0
- package/lib/types/dsh-watcher.d.ts +6 -0
- package/lib/types/hub/aggregation.d.ts +40 -0
- package/lib/types/hub/follow.d.ts +29 -0
- package/lib/types/hub/history.d.ts +30 -0
- package/lib/types/hub/overview.d.ts +10 -0
- package/lib/types/hub/watcher.d.ts +4 -0
- package/lib/types/insights/projection.d.ts +283 -0
- package/lib/types/observation/fold.d.ts +207 -0
- package/lib/types/observation/model-trace.d.ts +96 -0
- package/lib/types/observation/performance.d.ts +67 -0
- package/package.json +25 -24
package/lib/dsh-watcher.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
//#region src/insights/engine.mjs
|
|
4
|
-
/** Read-only DSH 0.
|
|
4
|
+
/** Read-only DSH 0.2.0-rc.2 log fold. No prompt, reasoning or tool body is retained. */
|
|
5
|
+
const DAY_CAP = 400;
|
|
6
|
+
const localDayKey = (ms) => {
|
|
7
|
+
const d = new Date(ms);
|
|
8
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
9
|
+
};
|
|
5
10
|
const record = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
6
11
|
const count = (v) => Number.isSafeInteger(v) && v >= 0;
|
|
7
12
|
const elapsed = (start, end) => start === null ? 0 : Math.max(0, end - start);
|
|
@@ -31,7 +36,7 @@ function emptyStats() {
|
|
|
31
36
|
}
|
|
32
37
|
function initialState(header = {}, inherited = 0) {
|
|
33
38
|
return {
|
|
34
|
-
version:
|
|
39
|
+
version: 2,
|
|
35
40
|
sessionId: String(header.id ?? ""),
|
|
36
41
|
skip: inherited,
|
|
37
42
|
seq: -1,
|
|
@@ -42,6 +47,7 @@ function initialState(header = {}, inherited = 0) {
|
|
|
42
47
|
},
|
|
43
48
|
totals: emptyStats(),
|
|
44
49
|
models: [],
|
|
50
|
+
days: [],
|
|
45
51
|
turn: null,
|
|
46
52
|
open: null,
|
|
47
53
|
tools: [],
|
|
@@ -112,6 +118,33 @@ function books(s, route = s.route) {
|
|
|
112
118
|
...s.turn ? [s.turn.stats] : []
|
|
113
119
|
];
|
|
114
120
|
}
|
|
121
|
+
function creditDay(s, time, route, u) {
|
|
122
|
+
const key = localDayKey(time);
|
|
123
|
+
let day = s.days.find((d) => d.key === key);
|
|
124
|
+
if (!day) {
|
|
125
|
+
day = {
|
|
126
|
+
key,
|
|
127
|
+
tokens: 0,
|
|
128
|
+
models: []
|
|
129
|
+
};
|
|
130
|
+
s.days.push(day);
|
|
131
|
+
s.days.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
|
|
132
|
+
}
|
|
133
|
+
day.tokens += u.tokens;
|
|
134
|
+
const effort = typeof route?.effort === "string" ? route.effort : null;
|
|
135
|
+
let row = day.models.find((m) => m.provider === route.provider && m.model === route.model && (m.effort ?? null) === effort);
|
|
136
|
+
if (!row) {
|
|
137
|
+
row = {
|
|
138
|
+
provider: route.provider,
|
|
139
|
+
model: route.model,
|
|
140
|
+
...effort ? { effort } : {},
|
|
141
|
+
tokens: 0
|
|
142
|
+
};
|
|
143
|
+
day.models.push(row);
|
|
144
|
+
}
|
|
145
|
+
row.tokens += u.tokens;
|
|
146
|
+
if (s.days.length > DAY_CAP) s.days = s.days.slice(s.days.length - DAY_CAP);
|
|
147
|
+
}
|
|
115
148
|
function begin(s, d, time, uncertain = false) {
|
|
116
149
|
s.open = {
|
|
117
150
|
turn: d.turn,
|
|
@@ -162,6 +195,7 @@ function settle(s, time, usage, source) {
|
|
|
162
195
|
}
|
|
163
196
|
}
|
|
164
197
|
}
|
|
198
|
+
if (u) creditDay(s, time, route, u);
|
|
165
199
|
s.open = null;
|
|
166
200
|
}
|
|
167
201
|
function applyChunk(open, chunk, time) {
|
|
@@ -368,6 +402,7 @@ function buildView(s) {
|
|
|
368
402
|
updatedAt: s.updatedAt,
|
|
369
403
|
totals: s.totals,
|
|
370
404
|
models: s.models,
|
|
405
|
+
days: s.days,
|
|
371
406
|
turn: s.turn,
|
|
372
407
|
pending: s.open ? {
|
|
373
408
|
turn: s.open.turn,
|
|
@@ -445,8 +480,19 @@ const pending = z.object({
|
|
|
445
480
|
reasoningLast: nullableTime,
|
|
446
481
|
lastContentAt: nullableTime
|
|
447
482
|
}).nullable();
|
|
483
|
+
const dayModels = z.array(z.object({
|
|
484
|
+
provider: z.string(),
|
|
485
|
+
model: z.string(),
|
|
486
|
+
effort: z.string().optional(),
|
|
487
|
+
tokens: number
|
|
488
|
+
}));
|
|
489
|
+
const days = z.array(z.object({
|
|
490
|
+
key: z.string(),
|
|
491
|
+
tokens: number,
|
|
492
|
+
models: dayModels
|
|
493
|
+
}));
|
|
448
494
|
const viewSchema = z.object({
|
|
449
|
-
version: z.literal(
|
|
495
|
+
version: z.literal(2),
|
|
450
496
|
sessionId: z.string(),
|
|
451
497
|
seq: z.number().int().min(-1),
|
|
452
498
|
updatedAt: z.number().finite(),
|
|
@@ -456,6 +502,7 @@ const viewSchema = z.object({
|
|
|
456
502
|
model: z.string(),
|
|
457
503
|
effort: z.string().optional()
|
|
458
504
|
})),
|
|
505
|
+
days,
|
|
459
506
|
turn,
|
|
460
507
|
pending,
|
|
461
508
|
findings: z.array(finding).max(30),
|
|
@@ -471,7 +518,7 @@ const usage = z.object({
|
|
|
471
518
|
exact: z.boolean()
|
|
472
519
|
}).nullable();
|
|
473
520
|
const stateSchema = z.object({
|
|
474
|
-
version: z.literal(
|
|
521
|
+
version: z.literal(2),
|
|
475
522
|
sessionId: z.string(),
|
|
476
523
|
skip: number,
|
|
477
524
|
seq: z.number().int().min(-1),
|
|
@@ -482,6 +529,7 @@ const stateSchema = z.object({
|
|
|
482
529
|
provider: z.string(),
|
|
483
530
|
model: z.string()
|
|
484
531
|
})),
|
|
532
|
+
days,
|
|
485
533
|
turn,
|
|
486
534
|
open: z.object({
|
|
487
535
|
turn: number,
|
|
@@ -516,7 +564,7 @@ const stateSchema = z.object({
|
|
|
516
564
|
function installProjection(ctx) {
|
|
517
565
|
ctx.sessionProjections.register({
|
|
518
566
|
key: "watcherInsights",
|
|
519
|
-
stateVersion:
|
|
567
|
+
stateVersion: 2,
|
|
520
568
|
stateSchema,
|
|
521
569
|
init: (header, inherited) => stateSchema.parse(initialState(header, inherited)),
|
|
522
570
|
apply: (state, event) => reduceEvent(state, event),
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { InsightsView } from '../insights/projection.ts';
|
|
2
|
+
type Evidence = {
|
|
3
|
+
turn: number;
|
|
4
|
+
steps: number[];
|
|
5
|
+
seqs: number[];
|
|
6
|
+
};
|
|
7
|
+
export declare function SessionInsights({ value, now, running, waiting, onEvidence }: {
|
|
8
|
+
value: InsightsView | undefined;
|
|
9
|
+
now: number;
|
|
10
|
+
running: boolean;
|
|
11
|
+
waiting: boolean;
|
|
12
|
+
onEvidence: (e: Evidence) => void;
|
|
13
|
+
}): import("react").JSX.Element | null;
|
|
14
|
+
export declare function InsightsSettings(props: {
|
|
15
|
+
remote?: any;
|
|
16
|
+
}): import("react").JSX.Element;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=Insights.d.ts.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
3
|
+
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
4
|
+
/**
|
|
5
|
+
* Minimal structural description of the optional `dsh-better-sidebar` tab
|
|
6
|
+
* registration service (published as `ctx.betterSidebar`, see the peer's
|
|
7
|
+
* `client/service.d.ts`). Declared locally on purpose: this package must
|
|
8
|
+
* typecheck and build without the peer installed, so neither values nor types
|
|
9
|
+
* may be imported from it. Semantics mirrored here: `registerTab` takes one
|
|
10
|
+
* descriptor and returns a disposer that unregisters the tab type — hand it to
|
|
11
|
+
* `ctx.effect` so hot reload cannot register it twice.
|
|
12
|
+
*/
|
|
13
|
+
export interface WatcherSidebarDescriptor {
|
|
14
|
+
/** Unique tab type id; also the host tab's `type` value. */
|
|
15
|
+
id: string;
|
|
16
|
+
title: string;
|
|
17
|
+
/** Single-instance sugar: opening the tab focuses an existing one. */
|
|
18
|
+
single?: boolean;
|
|
19
|
+
/** + menu sort order (ascending); the host default is 100. */
|
|
20
|
+
order?: number;
|
|
21
|
+
component: (props: WatcherSidebarTabProps) => ReactNode;
|
|
22
|
+
}
|
|
23
|
+
/** The subset of the host's tab component props the Watcher page reads. */
|
|
24
|
+
export interface WatcherSidebarTabProps {
|
|
25
|
+
ctx: ClientContext;
|
|
26
|
+
scope: {
|
|
27
|
+
sessionId: string;
|
|
28
|
+
};
|
|
29
|
+
/** Whether this tab is the active one AND the sidebar panel is open. */
|
|
30
|
+
visible: boolean;
|
|
31
|
+
}
|
|
32
|
+
/** Structural face of `ctx.betterSidebar` relevant to this plugin. */
|
|
33
|
+
export interface BetterSidebarService {
|
|
34
|
+
registerTab?: (descriptor: WatcherSidebarDescriptor) => () => void;
|
|
35
|
+
}
|
|
36
|
+
/** Read the optional service off a context without importing the peer. */
|
|
37
|
+
export declare function betterSidebarServiceOf(ctx: ClientContext): BetterSidebarService | undefined;
|
|
38
|
+
/** The Watcher tab descriptor registered into dsh-better-sidebar. */
|
|
39
|
+
export declare function watcherSidebarDescriptor(): WatcherSidebarDescriptor;
|
|
40
|
+
/**
|
|
41
|
+
* The Better Sidebar tab body: the session-header overlay's work picture,
|
|
42
|
+
* ported onto `scope.sessionId` without the portal, the trigger, or the drag
|
|
43
|
+
* frame. Reads the same Session/Conversation stores through their binding
|
|
44
|
+
* faces; the cost/performance HUD and whole-history paging stay explicit (and
|
|
45
|
+
* `visible: false` never starts a load — only the button does).
|
|
46
|
+
*/
|
|
47
|
+
export declare function WatcherSidebarTab({ ctx, sessionId, visible }: {
|
|
48
|
+
ctx: ClientContext;
|
|
49
|
+
sessionId: SessionId;
|
|
50
|
+
visible: boolean;
|
|
51
|
+
}): ReactNode;
|
|
52
|
+
//# sourceMappingURL=SidebarTab.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { InsightsView } from '../insights/projection.ts';
|
|
2
|
+
export declare function TimingPanel({ stats, scope, tokensPerSecond, }: {
|
|
3
|
+
stats: InsightsView['totals'];
|
|
4
|
+
scope: 'turn' | 'session';
|
|
5
|
+
tokensPerSecond?: number | null;
|
|
6
|
+
}): import("react").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=TimingPanel.d.ts.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
2
|
+
import type { CompleteHistoryResult } from '../hub/history.ts';
|
|
3
|
+
import { type WorkPicture, type WatcherSnapshot } from '../observation/fold.ts';
|
|
4
|
+
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
5
|
+
import type { InsightsView } from '../insights/projection.ts';
|
|
6
|
+
import { type TurnPerformance } from '../observation/performance.ts';
|
|
7
|
+
export interface WatcherInjected {
|
|
8
|
+
loadAllHistory: (signal: AbortSignal) => Promise<CompleteHistoryResult>;
|
|
9
|
+
}
|
|
10
|
+
export type WatcherProps = PropsRuntime<'conversation.session.header.utilities'> & WatcherInjected;
|
|
11
|
+
/** Native session-header utility: exact work picture, typed evidence, no steering. */
|
|
12
|
+
export declare function Watcher(props: WatcherProps): import("react").JSX.Element;
|
|
13
|
+
/**
|
|
14
|
+
* Folds one Session snapshot into the work picture, merging observations that
|
|
15
|
+
* outlive the loaded window. Shared by the session-header overlay and the
|
|
16
|
+
* Better Sidebar tab so both surfaces read the same projection.
|
|
17
|
+
*/
|
|
18
|
+
export declare function useObservedPicture(sessionId: string, snapshot: WatcherSnapshot): {
|
|
19
|
+
picture: WorkPicture;
|
|
20
|
+
performanceByTurn: ReadonlyMap<number, TurnPerformance>;
|
|
21
|
+
};
|
|
22
|
+
export interface WorkPicturePanelProps {
|
|
23
|
+
/** Owning Session identity; changing it resets follow, selection, and history state. */
|
|
24
|
+
sessionId: SessionId;
|
|
25
|
+
/** Folded work picture from {@link useObservedPicture}. */
|
|
26
|
+
picture: WorkPicture;
|
|
27
|
+
performanceByTurn: ReadonlyMap<number, TurnPerformance>;
|
|
28
|
+
/** Whether older history pages remain on the Session. */
|
|
29
|
+
hasMore: boolean;
|
|
30
|
+
/** Whole-session projection totals, when the Host projection is available. */
|
|
31
|
+
stats: {
|
|
32
|
+
turns: number;
|
|
33
|
+
steps: number;
|
|
34
|
+
} | undefined;
|
|
35
|
+
/** Cost/performance HUD input; the header overlay always renders it. */
|
|
36
|
+
insights: InsightsView | undefined;
|
|
37
|
+
/** Never mount the cost/performance HUD (the sidebar tab omits it). */
|
|
38
|
+
hideInsights?: boolean;
|
|
39
|
+
/** Explicit whole-history loader; absent when no Session face is available. */
|
|
40
|
+
loadAllHistory?: (signal: AbortSignal) => Promise<CompleteHistoryResult>;
|
|
41
|
+
/** Gates the live clock: the overlay's open state, or the sidebar tab's visibility. */
|
|
42
|
+
live: boolean;
|
|
43
|
+
/** Overlay-only: freeze the floating panel frame across inspector transitions. */
|
|
44
|
+
onInspectorFrameChange?: () => void;
|
|
45
|
+
/** DOM id prefix for turn landmarks; coexisting surfaces must not share ids. */
|
|
46
|
+
domIdPrefix?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The work picture itself: the docked inspector column plus the turns rail.
|
|
50
|
+
* Extracted from the session-header overlay so the Better Sidebar tab can
|
|
51
|
+
* render the same picture without the portal, the trigger, or the drag frame.
|
|
52
|
+
* Owns every picture-local concern (follow, disclosure, observation mode,
|
|
53
|
+
* history load, inspector lifecycle); positioning stays with the host.
|
|
54
|
+
*/
|
|
55
|
+
export declare function WorkPicturePanel({ sessionId, picture, performanceByTurn, hasMore, stats, insights, hideInsights, loadAllHistory, live, onInspectorFrameChange, domIdPrefix, }: WorkPicturePanelProps): import("react").JSX.Element;
|
|
56
|
+
//# sourceMappingURL=Watcher.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type DisclosureDepth = 'overview' | 'detail';
|
|
2
|
+
export type DisclosureLayer = 'phase' | 'step' | 'cluster' | 'model' | 'reasoning';
|
|
3
|
+
type LayerOverrides = Readonly<Record<DisclosureLayer, Readonly<Record<string, boolean>>>>;
|
|
4
|
+
export interface DisclosureState {
|
|
5
|
+
readonly depth: DisclosureDepth;
|
|
6
|
+
readonly turns: Readonly<Record<number, boolean>>;
|
|
7
|
+
readonly layers: LayerOverrides;
|
|
8
|
+
}
|
|
9
|
+
export declare function createDisclosureState(depth?: DisclosureDepth): DisclosureState;
|
|
10
|
+
/** Overview keeps the automatic Turn policy; detail opens every Turn by default. */
|
|
11
|
+
export declare function turnDisclosureOpen(state: DisclosureState, turn: number, overviewDefaultOpen: boolean): boolean;
|
|
12
|
+
/** Overview stops at phase headers; detail opens every nested level by default. */
|
|
13
|
+
export declare function layerDisclosureOpen(state: DisclosureState, layer: DisclosureLayer, key: string): boolean;
|
|
14
|
+
export declare function setLayerDisclosure(state: DisclosureState, layer: DisclosureLayer, key: string, open: boolean): DisclosureState;
|
|
15
|
+
export declare function toggleTurnDisclosure(state: DisclosureState, turn: number, overviewDefaultOpen: boolean): DisclosureState;
|
|
16
|
+
export declare function toggleLayerDisclosure(state: DisclosureState, layer: DisclosureLayer, key: string): DisclosureState;
|
|
17
|
+
/** Choosing a depth applies it immediately instead of inheriting stale manual folds. */
|
|
18
|
+
export declare function chooseDisclosureDepth(depth: DisclosureDepth): DisclosureState;
|
|
19
|
+
/** Session-specific ids may change, while the user's chosen depth remains useful. */
|
|
20
|
+
export declare function resetDisclosureOverrides(state: DisclosureState): DisclosureState;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=disclosure-depth.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
3
|
+
import { type CompleteHistoryResult } from '../hub/history.ts';
|
|
4
|
+
/**
|
|
5
|
+
* The paging verbs the shared loader needs from one Session face. The
|
|
6
|
+
* session-header injection and the Better Sidebar tab both satisfy it from
|
|
7
|
+
* `sessions.binding(id).session`.
|
|
8
|
+
*/
|
|
9
|
+
export interface WatcherHistorySession {
|
|
10
|
+
loadOlder: () => Promise<void>;
|
|
11
|
+
getSnapshot: () => {
|
|
12
|
+
hasMore: boolean;
|
|
13
|
+
loadingOlder: boolean;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Build the explicit whole-history loader for one Session: repeat the
|
|
18
|
+
* Session's public, read-only paging verb until the head stops moving, using
|
|
19
|
+
* the same conversation head key the header overlay reports. Nothing starts
|
|
20
|
+
* it automatically — only a user action does.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createCompleteHistoryLoader(ctx: ClientContext, sessionId: SessionId, session: WatcherHistorySession): (signal: AbortSignal) => Promise<CompleteHistoryResult>;
|
|
23
|
+
//# sourceMappingURL=history-loader.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
2
|
+
export declare const name = "dsh-watcher-client";
|
|
3
|
+
export declare const inject: string[];
|
|
4
|
+
/**
|
|
5
|
+
* Native session-header utility. Order 50 sits after Session log (0)
|
|
6
|
+
* and before the files-panel toggle (110). No overlay glyph.
|
|
7
|
+
*/
|
|
8
|
+
export declare function apply(ctx: ClientContext): void;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
2
|
+
import { type ModelStepTrace } from '../observation/model-trace.ts';
|
|
3
|
+
declare module '@deepseek-ai/dsh-client-ui-conversation/client' {
|
|
4
|
+
interface ConversationStepDataMap {
|
|
5
|
+
/** Provider-exposed model activity retained for one Step. */
|
|
6
|
+
'dsh-watcher-model-stage': ModelStepTrace;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/** Register the Step-scoped, read-only model-stage projection. */
|
|
10
|
+
export declare function registerModelTraceDefinition(ctx: ClientContext): void;
|
|
11
|
+
//# sourceMappingURL=model-trace-definition.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { WorkItem, WorkStep } from '../observation/fold.ts';
|
|
2
|
+
import type { ModelStepTrace } from '../observation/model-trace.ts';
|
|
3
|
+
type StepTimelineOccurrence = {
|
|
4
|
+
readonly kind: 'occurrence';
|
|
5
|
+
readonly item: WorkItem;
|
|
6
|
+
readonly occurrenceIndex: number;
|
|
7
|
+
};
|
|
8
|
+
export type StepTimelineEntry = StepTimelineOccurrence | {
|
|
9
|
+
readonly kind: 'model';
|
|
10
|
+
readonly trace: ModelStepTrace;
|
|
11
|
+
};
|
|
12
|
+
/** Compose the visible rows owned by one authoritative DSH Step. */
|
|
13
|
+
export declare function stepTimelineEntries(step: Pick<WorkStep, 'items' | 'model'>): readonly StepTimelineEntry[];
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=step-timeline.d.ts.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
export declare const name = "dsh-watcher";
|
|
3
|
+
export declare const inject: string[];
|
|
4
|
+
/** Host-owned replayable statistics; no new transport or model-facing writes. */
|
|
5
|
+
export declare function apply(ctx: Context): void;
|
|
6
|
+
//# sourceMappingURL=dsh-watcher.d.ts.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { WorkItem, WorkStatus } from '../observation/fold.ts';
|
|
2
|
+
export type WorkClusterBasis = 'mutable-target' | 'shared-target' | 'exact-call' | 'single';
|
|
3
|
+
export interface WorkStatusCounts {
|
|
4
|
+
running: number;
|
|
5
|
+
waiting: number;
|
|
6
|
+
success: number;
|
|
7
|
+
failure: number;
|
|
8
|
+
returned: number;
|
|
9
|
+
interrupted: number;
|
|
10
|
+
unknown: number;
|
|
11
|
+
}
|
|
12
|
+
export type NonEmptyWorkItems = readonly [WorkItem, ...WorkItem[]];
|
|
13
|
+
/** A reversible analysis projection. `items` always retains the source records. */
|
|
14
|
+
export interface WorkCluster {
|
|
15
|
+
id: string;
|
|
16
|
+
basis: WorkClusterBasis;
|
|
17
|
+
title: string;
|
|
18
|
+
items: NonEmptyWorkItems;
|
|
19
|
+
executionCount: number;
|
|
20
|
+
stepCount: number;
|
|
21
|
+
retryCount: number;
|
|
22
|
+
iterationCount: number;
|
|
23
|
+
latestStatus: WorkStatus;
|
|
24
|
+
statusCounts: Readonly<WorkStatusCounts>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Group one phase for analysis without changing evidence identity or order.
|
|
28
|
+
*
|
|
29
|
+
* - Mutable calls may group by operation + target so changed inputs remain
|
|
30
|
+
* comparable as iterations.
|
|
31
|
+
* - Reads may group by one exact file target so different line windows stay
|
|
32
|
+
* comparable.
|
|
33
|
+
* - Search, Glob, Grep, Bash, and every other tool require exact normalized
|
|
34
|
+
* arguments. Sharing a cwd, broad path, tool name, or translated title is
|
|
35
|
+
* never enough.
|
|
36
|
+
* - Messages and otherwise unsigned records remain singletons.
|
|
37
|
+
*/
|
|
38
|
+
export declare function clusterWorkItems(items: readonly WorkItem[]): readonly WorkCluster[];
|
|
39
|
+
export declare function clusterOutcomeSummary(cluster: WorkCluster): string;
|
|
40
|
+
//# sourceMappingURL=aggregation.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { WorkPicture } from '../observation/fold.ts';
|
|
2
|
+
export interface FollowSnapshot {
|
|
3
|
+
follow: boolean;
|
|
4
|
+
unread: number;
|
|
5
|
+
selectedId: string | null;
|
|
6
|
+
}
|
|
7
|
+
export interface RailScrollState {
|
|
8
|
+
atBottom: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Follow versus pin state for the work rail.
|
|
12
|
+
*
|
|
13
|
+
* The rail follows the newest recorded occurrence by default. Selecting
|
|
14
|
+
* history or scrolling away pins the viewport; later occurrences and result
|
|
15
|
+
* updates increment `unread` without yanking the reader away from evidence.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createFollow(): {
|
|
18
|
+
snapshot: () => FollowSnapshot;
|
|
19
|
+
/** Counts appended occurrences or a settled live result while pinned. */
|
|
20
|
+
onPicture(picture: Pick<WorkPicture, "nodes">): FollowSnapshot;
|
|
21
|
+
onSelect(id: string): FollowSnapshot;
|
|
22
|
+
onScroll({ atBottom }: RailScrollState): FollowSnapshot;
|
|
23
|
+
setFollow(next: boolean): FollowSnapshot;
|
|
24
|
+
backToLatest(): FollowSnapshot;
|
|
25
|
+
/** Drop a pinned selection without re-arming follow: closing the inspector keeps the rail where the user left it. */
|
|
26
|
+
clearSelection(): FollowSnapshot;
|
|
27
|
+
reset(): FollowSnapshot;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=follow.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Minimal public facts needed to page one shared RC8 Session window. */
|
|
2
|
+
export interface HistoryWindowState {
|
|
3
|
+
hasMore: boolean;
|
|
4
|
+
loadingOlder: boolean;
|
|
5
|
+
headKey: string;
|
|
6
|
+
}
|
|
7
|
+
export type CompleteHistoryResult = {
|
|
8
|
+
kind: 'complete';
|
|
9
|
+
pages: number;
|
|
10
|
+
} | {
|
|
11
|
+
kind: 'cancelled';
|
|
12
|
+
pages: number;
|
|
13
|
+
} | {
|
|
14
|
+
kind: 'blocked';
|
|
15
|
+
pages: number;
|
|
16
|
+
reason: 'busy' | 'no-progress' | 'page-limit';
|
|
17
|
+
};
|
|
18
|
+
export interface CompleteHistoryOptions {
|
|
19
|
+
read: () => HistoryWindowState;
|
|
20
|
+
loadOlder: () => Promise<void>;
|
|
21
|
+
signal: AbortSignal;
|
|
22
|
+
maxPages?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Pull every older RC8 page in order. The Session remains the sole owner of
|
|
26
|
+
* history continuity; this helper only repeats its public, read-only paging
|
|
27
|
+
* verb and fails closed if one request does not advance the visible head.
|
|
28
|
+
*/
|
|
29
|
+
export declare function loadCompleteHistory({ read, loadOlder, signal, maxPages, }: CompleteHistoryOptions): Promise<CompleteHistoryResult>;
|
|
30
|
+
//# sourceMappingURL=history.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WorkGroup, WorkStatus, WorkTurn } from '../observation/fold.ts';
|
|
2
|
+
/** Overview progress is deliberately separate from execution evidence status. */
|
|
3
|
+
export type OverviewState = 'active' | 'current' | 'waiting' | 'failure' | 'interrupted' | 'settled' | 'partial';
|
|
4
|
+
export declare const OVERVIEW_STATE_LABEL: Readonly<Record<OverviewState, string>>;
|
|
5
|
+
/** Project evidence status into the one question overview markers answer: where should the user look? */
|
|
6
|
+
export declare function overviewStateOf(status: WorkStatus, isLatest: boolean): OverviewState;
|
|
7
|
+
export declare function groupOverviewSummary(group: WorkGroup): string;
|
|
8
|
+
export declare function turnOverviewSummary(turn: WorkTurn): string;
|
|
9
|
+
export declare function turnNeedsDefaultDisclosure(state: OverviewState, isLatest: boolean): boolean;
|
|
10
|
+
//# sourceMappingURL=overview.d.ts.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Stable model entry for consumers that need Watcher's truthful work picture. */
|
|
2
|
+
export { EMPTY_PICTURE, foldEvents, foldSnapshot, normalizedSignature, pairTools, parseJsonl, } from '../observation/fold.ts';
|
|
3
|
+
export type { WorkGroup, WorkItem, WorkPhase, WorkPicture, WorkPresentation, WorkStatus, WorkStep, WorkTurn, } from '../observation/fold.ts';
|
|
4
|
+
//# sourceMappingURL=watcher.d.ts.map
|