@mstar-harness/dsh 3.7.3 → 3.8.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/README.i18n.yaml +2 -2
- package/README.md +127 -189
- package/README.zh.md +14 -12
- package/bundle/README.md +84 -165
- package/dist/client/index.d.ts +22 -7
- package/dist/client/panel/MstarPanelTitle.d.ts +13 -0
- package/dist/client/panel/PanelView.d.ts +75 -49
- package/dist/client/panel/TabNav.d.ts +17 -14
- package/dist/client/panel/definition.d.ts +23 -0
- package/dist/client/panel/engine-status-client.d.ts +187 -0
- package/dist/client/panel/graph/project-graph.d.ts +13 -55
- package/dist/client/panel/graph/schema.d.ts +1 -2
- package/dist/client/panel/guards.d.ts +52 -3
- package/dist/client/panel/locale.d.ts +1 -1
- package/dist/client/panel/mstar-glyph.d.ts +22 -0
- package/dist/client/panel/pages/AgentListPage.d.ts +71 -0
- package/dist/client/panel/pages/EventLogPage.d.ts +7 -4
- package/dist/client/panel/pages/IterationInfoSection.d.ts +16 -13
- package/dist/client/panel/pages/IterationTaskPage.d.ts +13 -14
- package/dist/client/panel/panel-meta.d.ts +2 -2
- package/dist/client/panel/panel-store.d.ts +28 -0
- package/dist/client/panel/sidebar.d.ts +12 -7
- package/dist/client/panel/state-section.d.ts +2 -2
- package/dist/client/panel/use-mstar-engine-status.d.ts +105 -32
- package/dist/client/panel/zones/Legend.d.ts +5 -3
- package/dist/client/panel/zones/TaskBoard.d.ts +13 -9
- package/dist/client.js +1017 -1236
- package/dist/engine-status-endpoint.d.ts +154 -0
- package/dist/engine-status-store.d.ts +190 -0
- package/dist/engine-status-wire.d.ts +29 -0
- package/dist/gates/_shared.d.ts +9 -0
- package/dist/gates/catalog.d.ts +8 -8
- package/dist/gates/system-prompt.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +528 -94
- package/dist/types.d.ts +40 -19
- package/harness-skills/mstar-artifacts/references/status-and-residuals.md +1 -1
- package/harness-skills/mstar-host/references/dsh.md +94 -219
- package/package.json +67 -63
- package/dist/client/panel/pages/AgentCanvasPage.d.ts +0 -345
|
@@ -1,64 +1,90 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Morning Star workflow panel page — the
|
|
3
|
-
*
|
|
2
|
+
* Morning Star workflow panel page — the right-Sidebar pane body (the keyed
|
|
3
|
+
* `sidebar.right.pane.tab` seat component, plan sidebar §L1.5): render of the
|
|
4
|
+
* session's engine-status snapshot.
|
|
4
5
|
*
|
|
5
|
-
* Inputs: the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Inputs: the sidebar seat's props (`MstarPanelBodyProps` — the seat's
|
|
7
|
+
* runtime share incl. the framework-injected `useTabInfo()` + the session
|
|
8
|
+
* standard kit + the entry store share (`useStore` + baked `select`, backed
|
|
9
|
+
* by the registration's `store` option) + the plugin's engine-status client
|
|
10
|
+
* bound by the plugin entry + the typed `t` seat (`locale: 'mstar-panel'`)).
|
|
11
|
+
* The `useMstarEngineStatus()` hook turns the anchor row + the served
|
|
12
|
+
* snapshot into ONE explicit render state (spec §5) — the render body is a
|
|
13
|
+
* pure function of (state, payload, snapshot `at`, t).
|
|
9
14
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* MenuTabs) + the content region (switches per tab) + the freshness footer.
|
|
15
|
-
* The `data-mstar-graph` anchor now marks the CONTENT container (spec §6.1 —
|
|
16
|
-
* previously the canvas container), so tests pin the layout contract, not the
|
|
17
|
-
* per-tab page internals.
|
|
15
|
+
* Visibility (plan sidebar §L2.6): a docked body is projected only while its
|
|
16
|
+
* sidebar column is expanded and the tab is active —
|
|
17
|
+
* `useTabInfo().tab.visible` — so a collapsed column renders NOTHING (no
|
|
18
|
+
* projection, no DOM). A floating pane is always visible.
|
|
18
19
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* the muted placeholder AND the AgentEventDock — 无双份日志).
|
|
20
|
+
* Layout (plan sidebar §L2.1): the narrow-column shell is a single flex
|
|
21
|
+
* column with exactly three zones — the section nav (`flex: none`), the
|
|
22
|
+
* panel-owned scroll body (`[data-mstar-scroll]`, flex: 1 1 auto ·
|
|
23
|
+
* min-height: 0 · the ONLY `overflow-y: auto` element in the panel; it also
|
|
24
|
+
* carries the `data-mstar-graph` content-container anchor), and the pinned
|
|
25
|
+
* meta dock (`flex: none`). The workspace-state digest renders IN FLOW at the
|
|
26
|
+
* end of the scroll body (the old 300px sibling column and its nested
|
|
27
|
+
* scroller are gone); the freshness footer follows it in the same flow.
|
|
28
28
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* no
|
|
36
|
-
*
|
|
29
|
+
* Section state (plan sidebar §L2.4): the entry store, keyed by
|
|
30
|
+
* `tabInfo.tab.id` (default `'tasks'`, D1) — it survives the body's unmount
|
|
31
|
+
* when another pane tab activates, which `useState` cannot. The render is
|
|
32
|
+
* SSR-stable: an untouched store reads `undefined` → the default tasks page.
|
|
33
|
+
*
|
|
34
|
+
* Empty branches (spec §2): waiting / loading / unavailable / no-harness
|
|
35
|
+
* render no tabs, no digest and no meta dock — each with its OWN anchor and
|
|
36
|
+
* copy, so a degraded read is never mistakable for an empty workspace.
|
|
37
|
+
* Degradation stays total: `projectGraph` never throws; no iteration → the
|
|
38
|
+
* IterationTaskPage's collapsed muted head (spec §8); `state` null / plans
|
|
39
|
+
* missing → muted kanban skeleton.
|
|
37
40
|
*/
|
|
38
41
|
import * as React from 'react';
|
|
39
|
-
import type {
|
|
40
|
-
import type {
|
|
41
|
-
import type {
|
|
42
|
-
import {
|
|
43
|
-
|
|
42
|
+
import type { PropsLocale, PropsRuntime, TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
|
|
43
|
+
import type { SessionId } from '@deepseek-ai/dsh-session';
|
|
44
|
+
import type { MstarEngineStatusPayload } from '../../types.ts';
|
|
45
|
+
import type { PropsStore } from '@deepseek-ai/dsh-client-store';
|
|
46
|
+
import type { MstarEngineStatusClient } from './engine-status-client.ts';
|
|
47
|
+
import { type UseSessions } from './use-mstar-engine-status.ts';
|
|
48
|
+
import { createPanelStore, type PanelSection } from './panel-store.ts';
|
|
49
|
+
/**
|
|
50
|
+
* The sidebar body seat's props (plan sidebar §L1.5): the seat's runtime
|
|
51
|
+
* share (owner + keyed + the seat's inject face — `useTabInfo()` — + the
|
|
52
|
+
* session standard kit, incl. the ui-chat-merged `useChat`) + the entry
|
|
53
|
+
* store share (plan §L2.4 — the registration's `store` option) + the typed
|
|
54
|
+
* `t` seat from the registration's `locale:` option.
|
|
55
|
+
*/
|
|
56
|
+
export interface MstarPanelBodyProps extends PropsRuntime<'sidebar.right.pane.tab'>, PropsStore<ReturnType<typeof createPanelStore>>, PropsLocale<'mstar-panel'> {
|
|
44
57
|
/** Namespace-bound translate seat (`locale: 'mstar-panel'`). */
|
|
45
58
|
t: TranslateNS<'mstar-panel'>;
|
|
59
|
+
/**
|
|
60
|
+
* Current session identity — the session standard kit's own prop. Declared
|
|
61
|
+
* here (rather than inherited) because this package does not depend on the
|
|
62
|
+
* ui-session adapter that merges the session-kit declarations into
|
|
63
|
+
* `SessionStandardProps`; the seat's session scope always supplies it at
|
|
64
|
+
* runtime.
|
|
65
|
+
*/
|
|
66
|
+
sessionId?: SessionId;
|
|
67
|
+
/** Host session-list selector hook (the global standard seat, same reason). */
|
|
68
|
+
useSessions?: UseSessions;
|
|
69
|
+
/**
|
|
70
|
+
* The plugin's engine-status client (bound to the client `connection`
|
|
71
|
+
* service by the plugin entry). Absent only in a composition that injects
|
|
72
|
+
* no transport — the panel then reports the explicit `unavailable` state.
|
|
73
|
+
*/
|
|
74
|
+
engineStatus?: MstarEngineStatusClient;
|
|
46
75
|
}
|
|
47
76
|
export interface PanelContentProps {
|
|
48
|
-
tab
|
|
49
|
-
|
|
77
|
+
/** The active panel section (plan sidebar §L1.5 vocabulary — not a sidebar tab record). */
|
|
78
|
+
section: PanelSection;
|
|
79
|
+
source: MstarEngineStatusPayload;
|
|
50
80
|
t: TranslateNS<'mstar-panel'>;
|
|
51
81
|
}
|
|
52
82
|
/**
|
|
53
|
-
*
|
|
54
|
-
* layout. tasks = the IterationTaskPage (spec §3 — Content Head + Steps
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* + idle states + AgentEdge collaboration edges; it replaced the muted placeholder and the AgentFlowZone); events =
|
|
59
|
-
* the real EventLogPage (spec §5 — non-canvas log page: Agent 流转事件 +
|
|
60
|
-
* 违规记录 partitions with per-row `<details>` expansion; it replaced the muted placeholder AND the
|
|
61
|
-
* AgentEventDock — 无双份日志, the dock is removed with this plan).
|
|
83
|
+
* Section → page mapping (spec §6.2): the only per-section-switching part of
|
|
84
|
+
* the layout. tasks = the IterationTaskPage (spec §3 — Content Head + Steps
|
|
85
|
+
* + the plan board); agents = the AgentListPage (spec §4 — the vertical
|
|
86
|
+
* grouped list, plan sidebar §L3); events = the EventLogPage (spec §5 — the
|
|
87
|
+
* log page with per-row `<details>` expansion).
|
|
62
88
|
*/
|
|
63
|
-
export declare function PanelContent({
|
|
64
|
-
export declare function PanelView({ t, useChat }:
|
|
89
|
+
export declare function PanelContent({ section, source, t }: PanelContentProps): React.JSX.Element;
|
|
90
|
+
export declare function PanelView({ t, useChat, useSessions, sessionId, engineStatus, useTabInfo, useStore, actions }: MstarPanelBodyProps): React.JSX.Element | null;
|
|
@@ -1,28 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TabNav (spec panel-tabs §2/§6.1) —
|
|
3
|
-
* the
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* `active` + `onChange` (spec §6.1 interface
|
|
3
|
+
* the section nav, the shell's first flex zone (`flex: none`): the three
|
|
4
|
+
* internal sections (任务迭代 / 代理执行 / 事件记录) of the one sidebar tab.
|
|
5
|
+
* Section state is owned by the panel entry store (plan sidebar §L2.4 —
|
|
6
|
+
* keyed by the sidebar tab record, default 'tasks', no routing); TabNav is a
|
|
7
|
+
* controlled component receiving `active` + `onChange` (spec §6.1 interface
|
|
8
|
+
* contract).
|
|
8
9
|
*
|
|
9
10
|
* Anchors: `data-mstar-tab-nav` (the nav frame), `data-mstar-tab="{id}"` on
|
|
10
11
|
* every tab and `data-mstar-tab-active="true|false"` (activation state). The
|
|
11
12
|
* active tab gets the business-token underline; inactive tabs stay secondary.
|
|
13
|
+
* Visual language (plan sidebar §L2.3): the strip ABOVE this nav is the dsh
|
|
14
|
+
* tab chrome (chips with borders — the host's, untouched); this nav is
|
|
15
|
+
* content — `role="tablist"`, `role="tab"` + `aria-selected`, the underline
|
|
16
|
+
* via `box-shadow`, no borders on the tabs.
|
|
12
17
|
*
|
|
13
|
-
* A11y:
|
|
14
|
-
* `
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* be scope creep without an explicit keyboard contract).
|
|
18
|
+
* A11y: WAI-ARIA tablist, each tab a `role="tab"` button with
|
|
19
|
+
* `aria-selected` (APG Tabs pattern). Deliberately minimal: every tab stays
|
|
20
|
+
* Tab-reachable (no roving tabindex / arrow-key handling — that behavior
|
|
21
|
+
* would be scope creep without an explicit keyboard contract).
|
|
18
22
|
*/
|
|
19
23
|
import * as React from 'react';
|
|
20
24
|
import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
|
|
21
|
-
|
|
22
|
-
export type PanelTab = 'tasks' | 'agents' | 'events';
|
|
25
|
+
import type { PanelSection } from './panel-store.ts';
|
|
23
26
|
export interface TabNavProps {
|
|
24
|
-
active:
|
|
25
|
-
onChange: (tab:
|
|
27
|
+
active: PanelSection;
|
|
28
|
+
onChange: (tab: PanelSection) => void;
|
|
26
29
|
t: TranslateNS<'mstar-panel'>;
|
|
27
30
|
}
|
|
28
31
|
export declare function TabNav({ active, onChange, t }: TabNavProps): React.JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The panel's right-Sidebar tab-type definition (plan sidebar §L1.2) — stage
|
|
3
|
+
* one of the two-stage seat registration: what the panel IS in the tab
|
|
4
|
+
* system. Stage two (the keyed `sidebar.right.pane.tab` body and
|
|
5
|
+
* `sidebar.right.pane.tab.title` chip under the same `id`) lives in the
|
|
6
|
+
* plugin entry (`src/client/index.ts`).
|
|
7
|
+
*
|
|
8
|
+
* A page type: `patterns`/`canOpen` omitted (it recognizes no resource
|
|
9
|
+
* address — it is opened by `kind`), `priority` omitted (defaults to the
|
|
10
|
+
* `extension` band, the right band for a type from outside the product), and
|
|
11
|
+
* exactly one guide entry so the start page carries the MStar capsule. The
|
|
12
|
+
* `title` thunk is re-read on every use, so the guide capsule follows the
|
|
13
|
+
* current locale; the chip's copy is captured at open time by the host.
|
|
14
|
+
*/
|
|
15
|
+
import type { SidebarRightTabDefinition } from '@deepseek-ai/dsh-client-ui-sidebar-right/client';
|
|
16
|
+
import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
|
|
17
|
+
/** This implementation's identity in the tab system — the key its body and title register under. */
|
|
18
|
+
export declare const MSTAR_PANEL_ID = "@mstar-harness/dsh";
|
|
19
|
+
/** The page kind the panel owns (U2: one sidebar tab). */
|
|
20
|
+
export declare const MSTAR_PANEL_KIND = "mstar-workflow";
|
|
21
|
+
/** The guide capsule's position among every registered type's entries (files ships order 10). */
|
|
22
|
+
export declare const MSTAR_GUIDE_ORDER = 20;
|
|
23
|
+
export declare function mstarPanelDefinition(t: TranslateNS<'mstar-panel'>): SidebarRightTabDefinition;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client half of the engine-status channel: the per-session snapshot cache the
|
|
3
|
+
* panel reads and the `/api/mstar/engineStatus` fetch that fills it.
|
|
4
|
+
*
|
|
5
|
+
* WHY a cache outside React: the panel is a browser bundle and the payload
|
|
6
|
+
* lives on the HOST filesystem (the persisted catalog row is only the anchor —
|
|
7
|
+
* its `source` is the frozen three-member first-party arm). The data therefore
|
|
8
|
+
* arrives over the host's shared typert `/api` gateway, asynchronously and
|
|
9
|
+
* repeatedly (every new anchor row asks again). Keeping that state in a small
|
|
10
|
+
* observable store — rather than component state — gives one request per
|
|
11
|
+
* (session, anchor) across re-renders, survives the panel unmounting, and lets
|
|
12
|
+
* the render path read it synchronously.
|
|
13
|
+
*
|
|
14
|
+
* KEYING, not adjacency: entries are keyed by session id, and a response is
|
|
15
|
+
* validated against the session that was REQUESTED
|
|
16
|
+
* ({@link parseEngineStatusResult}) — session A's panel can never render
|
|
17
|
+
* session B's snapshot.
|
|
18
|
+
*
|
|
19
|
+
* GENERATIONS: a new connection generation makes every wire-derived byte
|
|
20
|
+
* suspect, so `invalidate()` bumps a generation counter, drops the cache and
|
|
21
|
+
* clears the in-flight registry; a request answered after the bump is discarded
|
|
22
|
+
* on arrival ({@link MstarEngineStatusClient.write}) and the next render
|
|
23
|
+
* re-issues it. Without the fence an in-flight pre-reconnect answer would
|
|
24
|
+
* repopulate the cache and then suppress the repull the invalidation exists to
|
|
25
|
+
* force.
|
|
26
|
+
*
|
|
27
|
+
* DEADLINES: the gateway is a network hop, so one request is bounded
|
|
28
|
+
* ({@link MstarEngineStatusClientOptions.timeoutMs}) and a request that
|
|
29
|
+
* outlives its budget degrades to the explicit `unavailable('timeout:…')`
|
|
30
|
+
* reason instead of pinning `loading` for a whole turn. A served snapshot is
|
|
31
|
+
* likewise re-pulled on a modest interval
|
|
32
|
+
* ({@link MstarEngineStatusClientOptions.refreshIntervalMs}) — D3's "explicit
|
|
33
|
+
* refresh", never per agent-flow event. A refresh asks for the anchor it saw,
|
|
34
|
+
* so it never overwrites a newer anchor's answer ({@link
|
|
35
|
+
* MstarEngineStatusClient.write}).
|
|
36
|
+
*
|
|
37
|
+
* The store is written ONLY from a response continuation (never during a
|
|
38
|
+
* render), so reading it through `useSyncExternalStore` stays within React's
|
|
39
|
+
* snapshot contract.
|
|
40
|
+
*
|
|
41
|
+
* @module @mstar-harness/dsh/client/panel/engine-status-client
|
|
42
|
+
*/
|
|
43
|
+
import type { ConnectionRpcResult } from '@deepseek-ai/dsh-client-connection/client';
|
|
44
|
+
import { ENGINE_STATUS_CHANNEL, ENGINE_STATUS_ENDPOINT } from '../../engine-status-wire.ts';
|
|
45
|
+
import { type MstarEngineStatusFetch } from './guards.ts';
|
|
46
|
+
export { ENGINE_STATUS_CHANNEL, ENGINE_STATUS_ENDPOINT };
|
|
47
|
+
/** Deadline for one `/api/mstar/engineStatus` request (a hanging gateway must not pin `loading`). */
|
|
48
|
+
export declare const ENGINE_STATUS_REQUEST_TIMEOUT_MS = 5000;
|
|
49
|
+
/** How often a served snapshot is re-pulled (D3's "explicit refresh", modest interval). */
|
|
50
|
+
export declare const ENGINE_STATUS_REFRESH_INTERVAL_MS = 30000;
|
|
51
|
+
/**
|
|
52
|
+
* Structural face of the client `connection` service the panel needs — the
|
|
53
|
+
* generic RPC caller of the shared gateway. Declared structurally (not
|
|
54
|
+
* imported) so the bundle stays free of any runtime dependency on the
|
|
55
|
+
* transport package: the host injects `@deepseek-ai/dsh-client-connection`
|
|
56
|
+
* through the client manifest.
|
|
57
|
+
*/
|
|
58
|
+
export interface MstarEngineStatusConnection {
|
|
59
|
+
readonly rpc: {
|
|
60
|
+
call(channel: string, endpoint: string, payload: unknown, signal?: AbortSignal): Promise<ConnectionRpcResult<unknown>>;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Connection generations: a new generation means every wire-derived byte is
|
|
64
|
+
* suspect, so the cache is dropped and the panel repulls.
|
|
65
|
+
*/
|
|
66
|
+
readonly generation?: {
|
|
67
|
+
subscribe(listener: () => void): () => void;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** Optional timings (test seams; production uses the two constants above). */
|
|
71
|
+
export interface MstarEngineStatusClientOptions {
|
|
72
|
+
/** Per-request deadline in ms (`0` disables the bound). */
|
|
73
|
+
readonly timeoutMs?: number;
|
|
74
|
+
/** Refresh interval in ms (`0` disables the interval). */
|
|
75
|
+
readonly refreshIntervalMs?: number;
|
|
76
|
+
}
|
|
77
|
+
/** One session's cached answer, tagged with the anchor row it answers. */
|
|
78
|
+
export interface MstarEngineStatusEntry {
|
|
79
|
+
/** Message time of the anchor row this answer belongs to (staleness key). */
|
|
80
|
+
readonly anchorTime: number;
|
|
81
|
+
/** The workspace directory the answer was requested for (reused by a refresh). */
|
|
82
|
+
readonly cwd: string;
|
|
83
|
+
/** When the answer landed — the refresh clock (never the anchor row's time). */
|
|
84
|
+
readonly fetchedAt: number;
|
|
85
|
+
readonly fetch: MstarEngineStatusFetch;
|
|
86
|
+
}
|
|
87
|
+
/** The observable store value: at most one entry per session. */
|
|
88
|
+
export interface MstarEngineStatusSnapshot {
|
|
89
|
+
readonly entries: ReadonlyMap<string, MstarEngineStatusEntry>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The panel's engine-status client: one `/api/mstar/engineStatus` request per
|
|
93
|
+
* (session, anchor row), cached per session and observable by React.
|
|
94
|
+
*/
|
|
95
|
+
export declare class MstarEngineStatusClient {
|
|
96
|
+
private readonly connection;
|
|
97
|
+
private snapshot;
|
|
98
|
+
private readonly listeners;
|
|
99
|
+
private readonly inFlight;
|
|
100
|
+
private readonly abort;
|
|
101
|
+
/** Refreshes in flight, keyed by session (one per session, alongside the anchor requests). */
|
|
102
|
+
private readonly refreshing;
|
|
103
|
+
private readonly timeoutMs;
|
|
104
|
+
private readonly refreshIntervalMs;
|
|
105
|
+
private refreshTimer;
|
|
106
|
+
private generationDisposer;
|
|
107
|
+
/** Connection generation: bumped by {@link invalidate}; a mismatched answer is dropped. */
|
|
108
|
+
private generation;
|
|
109
|
+
private disposed;
|
|
110
|
+
/**
|
|
111
|
+
* @param connection - the client `connection` service, or undefined in a
|
|
112
|
+
* composition without one (the panel then reports `unavailable`).
|
|
113
|
+
* @param options - request deadline / refresh interval (test seams).
|
|
114
|
+
*/
|
|
115
|
+
constructor(connection: MstarEngineStatusConnection | null | undefined, options?: MstarEngineStatusClientOptions);
|
|
116
|
+
/** Current store value (stable reference until a response lands). */
|
|
117
|
+
getSnapshot: () => MstarEngineStatusSnapshot;
|
|
118
|
+
/** Subscribe to store writes (`useSyncExternalStore` face). */
|
|
119
|
+
subscribe: (listener: () => void) => (() => void);
|
|
120
|
+
/**
|
|
121
|
+
* Ensure the session's snapshot for ONE anchor row is being fetched. Safe to
|
|
122
|
+
* call on every render: an entry that already answers this anchor, and a
|
|
123
|
+
* request already in flight for it, are both no-ops.
|
|
124
|
+
* @param sessionId - the session the panel is showing.
|
|
125
|
+
* @param cwd - the session's workspace directory (the host cross-checks it
|
|
126
|
+
* against the session and the stored snapshot; an unknown cwd is not
|
|
127
|
+
* asserted, the panel degrades explicitly instead).
|
|
128
|
+
* @param anchorTime - message time of the anchor row this request answers.
|
|
129
|
+
*/
|
|
130
|
+
ensure(sessionId: string, cwd: string, anchorTime: number): void;
|
|
131
|
+
/**
|
|
132
|
+
* Drop every cached answer (a new connection generation invalidates the wire
|
|
133
|
+
* data) and fence off the requests already on the wire: their answers belong
|
|
134
|
+
* to the previous generation and must never repopulate the cache, or the
|
|
135
|
+
* repull this invalidation exists to force would be suppressed by them.
|
|
136
|
+
*/
|
|
137
|
+
invalidate(): void;
|
|
138
|
+
/** Stop accepting writes, abort in-flight requests and end the refresh interval (plugin teardown). */
|
|
139
|
+
dispose(): void;
|
|
140
|
+
/**
|
|
141
|
+
* Re-pull every served snapshot on a modest interval: the host keeps emitting
|
|
142
|
+
* on each digest-gated `agent/pre-step`, and a panel left open on an idle
|
|
143
|
+
* session would otherwise never see a newer snapshot. Deliberately NOT tied to
|
|
144
|
+
* agent-flow events, and never in flight twice for one session.
|
|
145
|
+
*/
|
|
146
|
+
private startRefreshTimer;
|
|
147
|
+
/**
|
|
148
|
+
* One refresh pass over the cache: every entry older than the refresh
|
|
149
|
+
* interval is re-pulled for the SAME anchor (the anchor only moves when the
|
|
150
|
+
* host appends a newer row, which already triggers its own request). Public
|
|
151
|
+
* as the interval's deterministic test seam; the interval calls it.
|
|
152
|
+
*/
|
|
153
|
+
refresh(): void;
|
|
154
|
+
/**
|
|
155
|
+
* One request → one validated entry. Never throws: a fault, a missing
|
|
156
|
+
* connection and an exceeded deadline are all explicit reasons.
|
|
157
|
+
* @returns the answer (also published through {@link write} when the
|
|
158
|
+
* generation it was issued under is still current).
|
|
159
|
+
*/
|
|
160
|
+
private fetch;
|
|
161
|
+
/**
|
|
162
|
+
* Bound one request: the request is aborted at the deadline and the caller
|
|
163
|
+
* gets the explicit timeout reason. A gateway that never answers must not pin
|
|
164
|
+
* `loading` (and with it the panel) for a whole turn.
|
|
165
|
+
*/
|
|
166
|
+
private withDeadline;
|
|
167
|
+
/**
|
|
168
|
+
* Publish one answer (the only writer — always outside a render).
|
|
169
|
+
*
|
|
170
|
+
* An answer issued under a superseded connection generation is DROPPED: it
|
|
171
|
+
* describes the connection that is gone, and publishing it would both render
|
|
172
|
+
* pre-reconnect data as `ok` and suppress the repull `invalidate()` forces
|
|
173
|
+
* (the stale answer would satisfy `ensure`'s anchor check).
|
|
174
|
+
*
|
|
175
|
+
* An answer for a SUPERSEDED anchor is dropped for the same class of reason:
|
|
176
|
+
* a refresh issues its request for the anchor it saw, and a newer anchor row
|
|
177
|
+
* can be answered in the meantime, so publishing on arrival would overwrite a
|
|
178
|
+
* newer snapshot with an older one under a refreshed cache clock and no
|
|
179
|
+
* staleness marker. `ensure` already refuses an older anchor, which is why
|
|
180
|
+
* this only ever happens through {@link refresh}.
|
|
181
|
+
*/
|
|
182
|
+
private write;
|
|
183
|
+
/** The store write itself (no generation test — see {@link write}). */
|
|
184
|
+
private writeEntry;
|
|
185
|
+
/** Notify subscribers, isolating a throwing listener. */
|
|
186
|
+
private notify;
|
|
187
|
+
}
|
|
@@ -35,8 +35,7 @@
|
|
|
35
35
|
* (the stage skeleton + entities/edges now live in the `agents` projection —
|
|
36
36
|
* spec §4);
|
|
37
37
|
* - added: `iteration.steps / currentStep / branches`, `tasks.columns / total
|
|
38
|
-
* / truncated`, `agents` (entities +
|
|
39
|
-
* pending counts — spec §4).
|
|
38
|
+
* / truncated`, `agents` (entities + executing/pending counts — spec §4).
|
|
40
39
|
*
|
|
41
40
|
* Agent-entity semantics (the per-role aggregation): entities aggregate by ROLE, not by session
|
|
42
41
|
* — a KNOWN_AGENTS roster role keys its own card (same role across sessions
|
|
@@ -48,8 +47,8 @@
|
|
|
48
47
|
* RENDER places `zone: 'general'` entities in an unknown sub-partition at
|
|
49
48
|
* the bottom of the LAST column (the standalone rightmost unknown column
|
|
50
49
|
* is superseded: 4 columns total). The SDD loop back-edge (sdd-implement →
|
|
51
|
-
* general)
|
|
52
|
-
*
|
|
50
|
+
* general) and the sub-bucket supervise line are both REMOVED from the
|
|
51
|
+
* projection — the agents zone projects entities only. The event-log `unexpected`
|
|
53
52
|
* badge is a SEPARATE, unchanged semantic (`expected` ⟺ role ∈
|
|
54
53
|
* EXPECTED_ROLE_FLOW union). The `sdd-implement` column is further split
|
|
55
54
|
* into implementor / reviewer SUB-BUCKETS: every entity carries a projected `bucket` field ('implementor' /
|
|
@@ -74,7 +73,7 @@
|
|
|
74
73
|
* with a transition past Phase 2 (an inconsistent harness state) degrades to the existing transition-driven current-step logic
|
|
75
74
|
* (Step 2→4) — backward compatible, `active` semantics unchanged.
|
|
76
75
|
*/
|
|
77
|
-
import type {
|
|
76
|
+
import type { MstarEngineStatusPayload } from '../../../types.ts';
|
|
78
77
|
import { type AgentZone, type PhaseId, type PlanStateId } from './schema.ts';
|
|
79
78
|
/** Current-step verdict from `gate.ok` (spec §3). */
|
|
80
79
|
export type PhaseVerdict = 'pass' | 'fail' | 'unknown';
|
|
@@ -215,7 +214,7 @@ export interface AgentEntityView {
|
|
|
215
214
|
* non-roster dispatch); the KNOWN_AGENTS role id for idle cards. INVARIANT
|
|
216
215
|
* (spec §6.2): keys are UNIQUE across the whole `entities` array —
|
|
217
216
|
* an evidence-derived `general` key suppresses the idle general twin in
|
|
218
|
-
* `idleEntities`, so the
|
|
217
|
+
* `idleEntities`, so the render layer's entity `key` space never sees
|
|
219
218
|
* duplicates.
|
|
220
219
|
*/
|
|
221
220
|
key: string;
|
|
@@ -291,44 +290,6 @@ export type AgentEmphasis = 'current' | 'next' | 'off' | null;
|
|
|
291
290
|
export type AgentEntityStatus = 'running' | 'settled' | 'error' | 'denied'
|
|
292
291
|
/** Retained for shape compat; the derivation (entityStatus) no longer emits it. */
|
|
293
292
|
| 'advisory' | 'idle';
|
|
294
|
-
/** Edge kinds (spec §4 — the finalized line semantics, design doc §2.2): handoff / sub-bucket
|
|
295
|
-
* supervision arrows. `expected` (stage skeleton) and `next` (running
|
|
296
|
-
* animation) are REMOVED — the column order implies the flow, the running
|
|
297
|
-
* card glow/status point carries the position. */
|
|
298
|
-
export type AgentEdgeKind = 'actual' | 'supervise';
|
|
299
|
-
/**
|
|
300
|
-
* One agents-zone arrow (spec §4):
|
|
301
|
-
* - `actual`: same-plan handoff between ts-adjacent dispatch ENTITY keys
|
|
302
|
-
* (source/target = entity key — role-based). The line set filters
|
|
303
|
-
* general-bucket endpoints
|
|
304
|
-
* (a general handoff is noise, not a meaningful transfer) and keeps at most
|
|
305
|
-
* ONE edge per entity-key pair (the latest direction) — design doc §2.2;
|
|
306
|
-
* - `supervise`: ONE static sub-bucket line inside the `sdd-implement`
|
|
307
|
-
* column — implementor ↔ reviewer mutual supervision (the mstar-sdd
|
|
308
|
-
* mutual-supervision contract; the render draws it as a bidirectional
|
|
309
|
-
* double arrow).
|
|
310
|
-
* source/target embed the column id as an anchor prefix:
|
|
311
|
-
* `<stage-id>:implementor` / `<stage-id>:reviewer`. NOT per-entity pairs —
|
|
312
|
-
* drawing per-role pairs would fabricate concrete supervision relations
|
|
313
|
-
* where no evidence exists (evidence-level handoffs are covered by
|
|
314
|
-
* `actualEdges`). STATIC presence (design knowledge) + evidence-driven
|
|
315
|
-
* lighting via `evidenced` (dim without implement/review dispatch
|
|
316
|
-
* evidence, lit with it — never a fabricated activation).
|
|
317
|
-
*/
|
|
318
|
-
export interface AgentEdge {
|
|
319
|
-
kind: AgentEdgeKind;
|
|
320
|
-
/** actual: entity key; supervise: `<stage-id>:implementor|reviewer`. */
|
|
321
|
-
source: string;
|
|
322
|
-
target: string;
|
|
323
|
-
/** Unused by the line edge set (the removed `next` arrow carried the
|
|
324
|
-
* running entity key); kept for shape stability — always null. */
|
|
325
|
-
entityKey: string | null;
|
|
326
|
-
/** Supervise edges only:
|
|
327
|
-
* evidence-driven lighting — true when any dispatch row's role belongs to
|
|
328
|
-
* an SDD sub-bucket (implementor ∪ reviewer), false otherwise (dim).
|
|
329
|
-
* Absent (undefined) for actual. */
|
|
330
|
-
evidenced?: boolean;
|
|
331
|
-
}
|
|
332
293
|
/**
|
|
333
294
|
* The canvas degradation-note classification (spec §8): the projection
|
|
334
295
|
* decides the note from the RAW ledger (never a UI-side heuristic on the
|
|
@@ -341,8 +302,8 @@ export interface AgentEdge {
|
|
|
341
302
|
export type AgentZoneNote = 'empty' | 'settle-only' | null;
|
|
342
303
|
/**
|
|
343
304
|
* The projected agents zone (spec §4 + §6.2): the EXPECTED_ROLE_FLOW stage
|
|
344
|
-
* skeleton plus the dispatch-derived entity cards
|
|
345
|
-
*
|
|
305
|
+
* skeleton plus the dispatch-derived entity cards. Total function — NEVER
|
|
306
|
+
* throws and NEVER fabricates: the KNOWN_AGENTS
|
|
346
307
|
* roster always projects as entities (idle cards when there is no evidence) —
|
|
347
308
|
* agentFlow missing/unreadable → `degraded` (full idle roster + no
|
|
348
309
|
* executing/pending claims); 0 events → `empty` (full idle roster + pending
|
|
@@ -360,8 +321,6 @@ export interface AgentZoneView {
|
|
|
360
321
|
note: AgentZoneNote;
|
|
361
322
|
/** Evidence-derived dispatch entities ∪ idle KNOWN_AGENTS cards — the full roster is NEVER hidden (spec §6.2). */
|
|
362
323
|
entities: readonly AgentEntityView[];
|
|
363
|
-
/** expected (stage skeleton) + actual (same-plan handoffs) + at most one next (latest running). */
|
|
364
|
-
edges: readonly AgentEdge[];
|
|
365
324
|
/** `running` entity count — the summary "N 执行中" (idle cards never count). */
|
|
366
325
|
executing: number;
|
|
367
326
|
/** Sum of expected roles of stages with no dispatch evidence — the summary "M 待执行". */
|
|
@@ -441,7 +400,7 @@ export interface ZoneView {
|
|
|
441
400
|
plans: boolean;
|
|
442
401
|
};
|
|
443
402
|
}
|
|
444
|
-
export declare function projectGraph(source:
|
|
403
|
+
export declare function projectGraph(source: MstarEngineStatusPayload | null): ZoneView;
|
|
445
404
|
/**
|
|
446
405
|
* `projectAgents(source, currentStep): AgentZoneView` — the agents zone (spec
|
|
447
406
|
* §4 + §6.2). `currentStep` is the ITERATION's current step (1-based into
|
|
@@ -458,8 +417,7 @@ export declare function projectGraph(source: MstarEngineStatusSource | null): Zo
|
|
|
458
417
|
* role is pending);
|
|
459
418
|
* - otherwise: entities aggregated from dispatch rows (with `idle: false`),
|
|
460
419
|
* statuses via the shared pairing walk, the un-evidenced KNOWN_AGENTS
|
|
461
|
-
* members appended as idle cards,
|
|
462
|
-
* the `expected` skeleton and `next` animation edges are REMOVED), and the
|
|
420
|
+
* members appended as idle cards, and the
|
|
463
421
|
* executing (running entities — idle never counts) / pending
|
|
464
422
|
* (un-evidenced stage roles) counts.
|
|
465
423
|
*
|
|
@@ -468,8 +426,8 @@ export declare function projectGraph(source: MstarEngineStatusSource | null): Zo
|
|
|
468
426
|
* suppresses a known role's idle card when its id already exists as an
|
|
469
427
|
* evidence-derived entity key (a NON-roster dispatch produces a lit `general`
|
|
470
428
|
* key while the roster `general` id stays un-evidenced — the twin is
|
|
471
|
-
* suppressed via `litKeys`), so the render layer's `key
|
|
472
|
-
*
|
|
429
|
+
* suppressed via `litKeys`), so the render layer's entity `key` space never
|
|
430
|
+
* collides.
|
|
473
431
|
*
|
|
474
432
|
* Canvas note: `note` classifies the readable ledger in
|
|
475
433
|
* the projection ('empty' / 'settle-only' / null — see `AgentZoneNote`); the
|
|
@@ -481,7 +439,7 @@ export declare function projectGraph(source: MstarEngineStatusSource | null): Zo
|
|
|
481
439
|
* annotates the current plan; degraded/empty branches include the note too
|
|
482
440
|
* (it is a state.plans annotation, independent of the ledger evidence).
|
|
483
441
|
*/
|
|
484
|
-
export declare function projectAgents(source:
|
|
442
|
+
export declare function projectAgents(source: MstarEngineStatusPayload | null, currentStep: number | null): AgentZoneView;
|
|
485
443
|
/** One row of the pairing walk — the identity a PAIRED settle carries (spec R1: exact identity pairing,
|
|
486
444
|
* never owner+time guessing). The kind is the FULL projected kind union:
|
|
487
445
|
* workflow/unknown rows are walk no-ops (they carry no paired marker) —
|
|
@@ -525,7 +483,7 @@ export declare function pairSettleIndexes(rows: readonly PairingRow[]): Readonly
|
|
|
525
483
|
* the server's empty view → present with 0 events → no events either (the
|
|
526
484
|
* `agents` skeleton carries `empty`).
|
|
527
485
|
*/
|
|
528
|
-
export declare function projectFlowEvents(source:
|
|
486
|
+
export declare function projectFlowEvents(source: MstarEngineStatusPayload | null): {
|
|
529
487
|
events: FlowEventView[];
|
|
530
488
|
unexpected: FlowEventView[];
|
|
531
489
|
};
|
|
@@ -82,8 +82,7 @@ export declare const TRANSITION_TO_PHASE: Readonly<Record<string, PhaseId>>;
|
|
|
82
82
|
* placement (BOTTOM INSIDE the `sdd-implement` column bucket) is
|
|
83
83
|
* superseded by the F5; the former SDD implement ↔ review
|
|
84
84
|
* skeleton EDGE (sdd-implement → general back-edge, the `loop: true` arrow)
|
|
85
|
-
*
|
|
86
|
-
* project-graph.ts `superviseEdges`).
|
|
85
|
+
* and the F5 sub-bucket supervise line are both REMOVED from the projection.
|
|
87
86
|
*
|
|
88
87
|
* Matching rules (spec §2.3 — implemented by `projectGraph`'s flow
|
|
89
88
|
* projection): `expected` ⟺ `event.role` ∈ the union of ALL `roles` below
|
|
@@ -1,12 +1,61 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Field-level degradation guards for the runtime `mstar-engine-status`
|
|
2
|
+
* Field-level degradation guards for the runtime `mstar-engine-status` payload
|
|
3
3
|
* (spec §2.4): the client does not exhaustively validate the union — it
|
|
4
|
-
* narrows
|
|
5
|
-
*
|
|
4
|
+
* narrows, then degrades per field. Unknown/missing values render as
|
|
5
|
+
* `unknown`, never as guessed values.
|
|
6
|
+
*
|
|
7
|
+
* This module ALSO carries the one place that validates untrusted input
|
|
8
|
+
* exhaustively: {@link parseEngineStatusResult}, which turns the
|
|
9
|
+
* `/api/mstar/engineStatus` wire envelope into the panel's explicit state. The
|
|
10
|
+
* payload is a remote answer the panel never authored, so a malformed
|
|
11
|
+
* envelope degrades to `unavailable` — never to a half-parsed view.
|
|
6
12
|
*/
|
|
13
|
+
import type { MstarEngineStatusPayload } from '../../types.ts';
|
|
7
14
|
/** String field: non-empty string, else null (missing → `unknown`). */
|
|
8
15
|
export declare function str(value: unknown): string | null;
|
|
9
16
|
/** Boolean field: real boolean, else null. */
|
|
10
17
|
export declare function bool(value: unknown): boolean | null;
|
|
11
18
|
/** Count field: finite number, else null. */
|
|
12
19
|
export declare function count(value: unknown): number | null;
|
|
20
|
+
/** Plain-object record (null and arrays are not records), else null. */
|
|
21
|
+
export declare function record(value: unknown): Record<string, unknown> | null;
|
|
22
|
+
/**
|
|
23
|
+
* The engine-status state the panel renders from: either the host's stored
|
|
24
|
+
* snapshot emission, or the explicit reason the snapshot is unavailable.
|
|
25
|
+
* There is deliberately no third "empty" shape — a degraded read is ALWAYS an
|
|
26
|
+
* `unavailable` carrying a reason, never a silently-empty payload.
|
|
27
|
+
*/
|
|
28
|
+
export type MstarEngineStatusFetch = {
|
|
29
|
+
readonly status: 'ok';
|
|
30
|
+
/** The exact catalog payload the host stored for this session. */
|
|
31
|
+
readonly payload: MstarEngineStatusPayload;
|
|
32
|
+
/** ISO timestamp of the served snapshot — the panel's freshness marker. */
|
|
33
|
+
readonly at: string;
|
|
34
|
+
/** The agent turn the row was emitted for. */
|
|
35
|
+
readonly turn: number;
|
|
36
|
+
} | {
|
|
37
|
+
readonly status: 'unavailable';
|
|
38
|
+
readonly reason: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Validate one `/api/mstar/engineStatus` response into the panel's state.
|
|
42
|
+
*
|
|
43
|
+
* The whole envelope is untrusted: the transport result (`{ok, value}` /
|
|
44
|
+
* `{ok: false, error}`), the endpoint result (`status` + its fields) and the
|
|
45
|
+
* payload object. Every branch that cannot be read in full answers the
|
|
46
|
+
* explicit `unavailable` state with a machine-readable reason; the host's own
|
|
47
|
+
* `unavailable` reason is surfaced verbatim.
|
|
48
|
+
*
|
|
49
|
+
* @param raw - the value returned by `connection.rpc.call` (untrusted).
|
|
50
|
+
* @param sessionId - the session this client ASKED for; a response naming any
|
|
51
|
+
* other session is refused (`session-mismatch`) — one session's request can
|
|
52
|
+
* never render another session's data.
|
|
53
|
+
* @param cwd - the workspace this client ASSERTED in the same request; the host
|
|
54
|
+
* echoes the record's `cwd`, so a response naming another workspace is refused
|
|
55
|
+
* (`cwd-mismatch`) rather than rendered as this session's snapshot. The
|
|
56
|
+
* comparison is exact byte equality: the host matched the asserted string
|
|
57
|
+
* against its own record verbatim, so a normalising comparison here would
|
|
58
|
+
* accept a workspace the host itself refused.
|
|
59
|
+
* @returns the validated snapshot state, or the explicit unavailable state.
|
|
60
|
+
*/
|
|
61
|
+
export declare function parseEngineStatusResult(raw: unknown, sessionId: string, cwd?: string): MstarEngineStatusFetch;
|