@mstar-harness/dsh 3.7.3 → 3.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.i18n.yaml +2 -2
- package/README.md +2 -2
- package/README.zh.md +2 -2
- package/bundle/README.md +8 -1
- package/dist/client/index.d.ts +12 -6
- package/dist/client/panel/PanelView.d.ts +38 -16
- package/dist/client/panel/engine-status-client.d.ts +187 -0
- package/dist/client/panel/graph/project-graph.d.ts +4 -4
- package/dist/client/panel/guards.d.ts +52 -3
- package/dist/client/panel/locale.d.ts +1 -1
- package/dist/client/panel/panel-meta.d.ts +2 -2
- package/dist/client/panel/sidebar.d.ts +2 -2
- package/dist/client/panel/state-section.d.ts +2 -2
- package/dist/client/panel/use-mstar-engine-status.d.ts +104 -32
- package/dist/client.js +333 -50
- 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 +7 -7
- 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 +33 -19
- package/harness-skills/mstar-artifacts/references/status-and-residuals.md +1 -1
- package/harness-skills/mstar-host/references/dsh.md +13 -4
- package/package.json +4 -2
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host half of the panel's engine-status channel: the `mstar/engineStatus`
|
|
3
|
+
* endpoint on the host's SHARED `/api` typert gateway.
|
|
4
|
+
*
|
|
5
|
+
* WHY this shape: a plugin cannot own a route. The host's typertGateway owns
|
|
6
|
+
* the single `/api` interceptor (`connection.rpc.intercept('/api')` would
|
|
7
|
+
* throw), and a third-party `connection.rpc.handle(...)` channel mounts through
|
|
8
|
+
* `webServer` on the CALLING fiber — which would force `webServer` into this
|
|
9
|
+
* plugin's static inject and pend the row on a base-only profile. The working
|
|
10
|
+
* third-party pattern is therefore a cordis service extending
|
|
11
|
+
* `TypertRemoteService` (the namespace IS the service key) whose endpoint
|
|
12
|
+
* descriptors are contributed with `ctx.typert.register(...)` from an OPTIONAL
|
|
13
|
+
* child (`ctx.inject(['typert'], …)`): a composition without a typert registry
|
|
14
|
+
* simply has no `/api` endpoints, and the plugin's runtime keeps working.
|
|
15
|
+
*
|
|
16
|
+
* The browser half calls `connection.rpc.call('/api', 'mstar/engineStatus',
|
|
17
|
+
* { args: { sessionId, cwd } })` — the payload contract is exactly one
|
|
18
|
+
* plain-object `args` field keyed by the declared parameter names.
|
|
19
|
+
*
|
|
20
|
+
* HARD constraint — headless boot safety: this module is reachable from
|
|
21
|
+
* `apply`, and it must never make the host row statically inject `connection`
|
|
22
|
+
* or `webServer`. Everything web-only is inside the optional inject child; the
|
|
23
|
+
* endpoint's own reads (`ctx.get('sessions')`, `ctx.get('sessionController')`)
|
|
24
|
+
* are structural and degrade when the service is absent.
|
|
25
|
+
*
|
|
26
|
+
* VALIDATION CHAIN — the endpoint serves ONE session's snapshot and answers
|
|
27
|
+
* otherwise. In order:
|
|
28
|
+
* 1. argument shape (non-empty ids, an absolute traversal-free `cwd`);
|
|
29
|
+
* 2. the session is resolved SERVER-side — the live `ctx.sessions.get(id)`
|
|
30
|
+
* first, then the session controller's persisted `inspect(id)` fallback;
|
|
31
|
+
* 3. the `{HARNESS_DIR}` comes from the SERVER-side session cwd (or the
|
|
32
|
+
* boot-resolved config root) — never from client-asserted input;
|
|
33
|
+
* 4. the store entry for that session must exist;
|
|
34
|
+
* 5. the client-asserted `cwd` must EQUAL the record's `cwd`, and the record's
|
|
35
|
+
* `cwd` must equal the resolved session's cwd.
|
|
36
|
+
* Every failure returns the explicit unavailable state WITH a reason: never
|
|
37
|
+
* another session's data, never a silently-close match, never a path built from
|
|
38
|
+
* unvalidated input.
|
|
39
|
+
*
|
|
40
|
+
* @module @mstar-harness/dsh/engine-status-endpoint
|
|
41
|
+
*/
|
|
42
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
43
|
+
import type { TypertContribution } from '@deepseek-ai/dsh-typert-registry';
|
|
44
|
+
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
45
|
+
import type { HarnessResolver } from './gates/_shared.ts';
|
|
46
|
+
import { MSTAR_ENGINE_STATUS_METHOD, MSTAR_ENGINE_STATUS_NAMESPACE } from './engine-status-wire.ts';
|
|
47
|
+
export { MSTAR_ENGINE_STATUS_METHOD, MSTAR_ENGINE_STATUS_NAMESPACE };
|
|
48
|
+
/** The served snapshot (the stored emission, echoed back with its identity). */
|
|
49
|
+
export interface MstarEngineStatusOk {
|
|
50
|
+
readonly status: 'ok';
|
|
51
|
+
readonly sessionId: string;
|
|
52
|
+
readonly cwd: string;
|
|
53
|
+
/** ISO timestamp of the emission the entry records. */
|
|
54
|
+
readonly at: string;
|
|
55
|
+
/** The agent turn the row was emitted for. */
|
|
56
|
+
readonly turn: number;
|
|
57
|
+
/** The exact catalog payload emitted to that session's model. */
|
|
58
|
+
readonly payload: Record<string, unknown>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The explicit "no answer" result. `reason` is machine-readable and always
|
|
62
|
+
* present — a degraded path is never silent.
|
|
63
|
+
*/
|
|
64
|
+
export interface MstarEngineStatusUnavailableResult {
|
|
65
|
+
readonly status: 'unavailable';
|
|
66
|
+
readonly reason: string;
|
|
67
|
+
}
|
|
68
|
+
/** The endpoint's wire result. */
|
|
69
|
+
export type MstarEngineStatusResult = MstarEngineStatusOk | MstarEngineStatusUnavailableResult;
|
|
70
|
+
/** Options the endpoint needs from the plugin's apply scope. */
|
|
71
|
+
export interface MstarEngineStatusEndpointOptions {
|
|
72
|
+
/** The per-workspace `{HARNESS_DIR}` resolver (the same one the gates use). */
|
|
73
|
+
readonly resolver: HarnessResolver;
|
|
74
|
+
/** The boot-resolved config root when an explicit `harnessDir` is configured. */
|
|
75
|
+
readonly bootHarnessDir: string | null;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Host-side `mstar/engineStatus` service: `/api/mstar/engineStatus` serves the
|
|
79
|
+
* stored snapshot of the session the caller asserts.
|
|
80
|
+
*/
|
|
81
|
+
export declare class MstarEngineStatusGateway extends TypertRemoteService {
|
|
82
|
+
private readonly resolver;
|
|
83
|
+
private readonly bootHarnessDir;
|
|
84
|
+
/**
|
|
85
|
+
* @param ctx - owning Cordis context.
|
|
86
|
+
* @param options - the apply-scoped resolver + boot root.
|
|
87
|
+
*/
|
|
88
|
+
constructor(ctx: Context, options: MstarEngineStatusEndpointOptions);
|
|
89
|
+
/**
|
|
90
|
+
* Serve one session's stored engine-status snapshot after the validation
|
|
91
|
+
* chain documented in the module header.
|
|
92
|
+
* @param sessionId - the session whose snapshot is requested (client-asserted).
|
|
93
|
+
* @param cwd - the session workspace the client believes it is reading (client-asserted).
|
|
94
|
+
* @returns the stored emission, or the explicit unavailable state with a reason.
|
|
95
|
+
*/
|
|
96
|
+
engineStatus(sessionId: string, cwd: string): Promise<MstarEngineStatusResult>;
|
|
97
|
+
/** The validation chain itself (contained by {@link engineStatus}). */
|
|
98
|
+
private serve;
|
|
99
|
+
/**
|
|
100
|
+
* Resolve the authoritative cwd of one session: the LIVE session first
|
|
101
|
+
* (`ctx.sessions.get(id)`), then the session controller's persisted
|
|
102
|
+
* `inspect(id)` fallback for a session that is not currently attached.
|
|
103
|
+
* A missing service, a missing session or a cwd-less header is an explicit
|
|
104
|
+
* unavailable reason, never a guess.
|
|
105
|
+
*/
|
|
106
|
+
private resolveSessionCwd;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The generated-style invocation descriptor for `/api/mstar/engineStatus`.
|
|
110
|
+
*
|
|
111
|
+
* Registered EXPLICITLY (not through `@Remote` SRC markers): the host gateway
|
|
112
|
+
* checks its own `ctx.typert.local` table FIRST, while SRC discovery reads a
|
|
113
|
+
* module-private marker table that a locally-resolved plugin copy can never
|
|
114
|
+
* share with the host installation.
|
|
115
|
+
*/
|
|
116
|
+
export declare function mstarEngineStatusContribution(): TypertContribution;
|
|
117
|
+
/**
|
|
118
|
+
* Install the host half of the channel on one apply scope.
|
|
119
|
+
*
|
|
120
|
+
* Two optional units, never a static inject on the plugin row:
|
|
121
|
+
* - the `mstar` service — `engineStatusServicePresent` above is the admission
|
|
122
|
+
* test, so a second apply on the same context (a sibling fiber, an HMR
|
|
123
|
+
* re-apply) does not construct a second gateway and keeps the FIRST instance
|
|
124
|
+
* with its own resolver/boot root. Constructing a second one would make the
|
|
125
|
+
* service's `provide` find the name taken and throw out of the child effect,
|
|
126
|
+
* so the present-check is the primary dedupe and the `has been registered`
|
|
127
|
+
* catch arm below covers what it cannot see: the concurrent-apply window, and
|
|
128
|
+
* an unreadable registry (the helper falls through in both cases);
|
|
129
|
+
* - the endpoint contribution, registered inside `ctx.inject(['typert'], …)`
|
|
130
|
+
* and returning that registration's own disposer — so the endpoints withdraw
|
|
131
|
+
* with the child fiber (or when the typert service goes away).
|
|
132
|
+
*
|
|
133
|
+
* DESCRIPTOR DEDUPE RESTS ON THE CATCH ARM. The registry does serve a presence
|
|
134
|
+
* probe — `local.get(endpoint)` answers the LIVE descriptor, or `undefined` when
|
|
135
|
+
* absent — but a pre-flight check cannot close the concurrent-apply window (two
|
|
136
|
+
* applies can both read it absent before either registers), so the registration
|
|
137
|
+
* itself stays the authoritative test. `local.hasSeen(endpoint)` is no
|
|
138
|
+
* substitute: it is a HISTORY probe, `true` for an endpoint registered at least
|
|
139
|
+
* once and staying `true` after it is withdrawn, so as a presence test it would
|
|
140
|
+
* skip re-registration for the endpoint a reload withdrew. A duplicate makes
|
|
141
|
+
* `register` throw, the arm swallows exactly that error and returns a no-op
|
|
142
|
+
* disposer, so a deduped apply can never withdraw another fiber's endpoint. The
|
|
143
|
+
* cost of that is the dependency on typert's error text (`already registered`);
|
|
144
|
+
* a `get`-based pre-check is the way to drop the dependency — it precedes the
|
|
145
|
+
* arm, but cannot replace it.
|
|
146
|
+
*
|
|
147
|
+
* Withdrawal follows ownership: the endpoint lives exactly as long as its OWNER
|
|
148
|
+
* fiber does. A deduped sibling that disposes withdraws nothing (it registered
|
|
149
|
+
* nothing); the owner disposing withdraws the service and the endpoints, and a
|
|
150
|
+
* later apply on a live context registers them afresh.
|
|
151
|
+
* @param ctx - the plugin's apply context.
|
|
152
|
+
* @param options - the apply-scoped resolver + boot root.
|
|
153
|
+
*/
|
|
154
|
+
export declare function installEngineStatusEndpoint(ctx: Context, options: MstarEngineStatusEndpointOptions): void;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable engine-status snapshot store — the edge-safe catalog source that a
|
|
3
|
+
* web-only reader (panel/endpoint) can serve WITHOUT re-running the in-process
|
|
4
|
+
* resolution that produces the step catalog.
|
|
5
|
+
*
|
|
6
|
+
* WHY a snapshot: the composed catalog payload is only available at the
|
|
7
|
+
* digest-gated `agent/pre-step` emission; a later reader (a different fiber,
|
|
8
|
+
* or the host endpoint answering a browser request) cannot rebuild it — it
|
|
9
|
+
* would re-resolve `{HARNESS_DIR}`, re-scan status/compass/residual, and could
|
|
10
|
+
* answer with state that never reached the model. Persisting the EXACT emitted
|
|
11
|
+
* payload at the emission site makes the served value a record of what the
|
|
12
|
+
* model actually saw, keyed by the session that saw it.
|
|
13
|
+
*
|
|
14
|
+
* File: `{HARNESS_DIR}/snapshots/engine-status.json`
|
|
15
|
+
*
|
|
16
|
+
* ```json
|
|
17
|
+
* {
|
|
18
|
+
* "sv": 1,
|
|
19
|
+
* "entries": { "<session id>": [ { "rv": 1, "cwd": "/proj", "at": "…", "turn": 3, "payload": { … } } ] }
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* `sv` is the envelope schema version and `rv` the per-entry record version:
|
|
24
|
+
* a reader that does not recognize EITHER must answer "unavailable" rather
|
|
25
|
+
* than parse a shape it does not understand — and (write rule below) a writer
|
|
26
|
+
* must refuse rather than replace one.
|
|
27
|
+
*
|
|
28
|
+
* Durability discipline (same as the agent-flow ledger):
|
|
29
|
+
* - every write runs under the per-directory inter-process write lock
|
|
30
|
+
* ({@link withWorkflowDirLock} — atomic `mkdir` lockdir, the package's
|
|
31
|
+
* single lock primitive);
|
|
32
|
+
* - the file itself is replaced by `writeFileSync(<writer-unique>.tmp)` +
|
|
33
|
+
* `renameSync` (atomic replace — concurrent readers never observe a torn
|
|
34
|
+
* file, and the failure cleanup can only ever remove its own temp file);
|
|
35
|
+
* - retention is enforced on EVERY write: newest
|
|
36
|
+
* {@link ENGINE_STATUS_SNAPSHOT_MAX_PER_SESSION} entries per session,
|
|
37
|
+
* nothing older than {@link ENGINE_STATUS_SNAPSHOT_MAX_AGE_MS}, and the whole
|
|
38
|
+
* envelope under {@link ENGINE_STATUS_SNAPSHOT_MAX_BYTES}.
|
|
39
|
+
*
|
|
40
|
+
* READ RULE (HARD): `sv !== 1`, an unknown shape, an unreadable file, or an
|
|
41
|
+
* absent file all yield the explicit {@link EngineStatusUnavailable} result.
|
|
42
|
+
* A best-effort parse is never returned — a reader must not present guessed
|
|
43
|
+
* state as the model's state.
|
|
44
|
+
*
|
|
45
|
+
* WRITE RULE (HARD): the same rule governs the writer. An existing envelope
|
|
46
|
+
* whose `sv` is unknown, whose JSON is torn, or that cannot be read is NOT
|
|
47
|
+
* replaceable: the write refuses with the explicit `degraded` reason and
|
|
48
|
+
* leaves the bytes untouched. Every session's snapshots live in that one file,
|
|
49
|
+
* so "start from an empty envelope" would silently destroy the snapshots of
|
|
50
|
+
* every other session sharing this `{HARNESS_DIR}` — a store the writer does
|
|
51
|
+
* not understand is never the writer's to overwrite (a version flap between
|
|
52
|
+
* two plugin builds, or a hand-truncated file, must not become data loss).
|
|
53
|
+
*
|
|
54
|
+
* BOUNDS: retention is per-session ({@link ENGINE_STATUS_SNAPSHOT_MAX_PER_SESSION}
|
|
55
|
+
* + {@link ENGINE_STATUS_SNAPSHOT_MAX_AGE_MS}) AND global
|
|
56
|
+
* ({@link ENGINE_STATUS_SNAPSHOT_MAX_BYTES}): a store above the byte ceiling
|
|
57
|
+
* sheds its least-recently-written session buckets — oldest first, never the
|
|
58
|
+
* writing session — and the write path reports the oversize condition ONCE per
|
|
59
|
+
* store so the host can log the one warning the containment contract promises
|
|
60
|
+
* instead of a warning per turn.
|
|
61
|
+
*
|
|
62
|
+
* KEYING (HARD): both session maps are prototype-less (`Object.create(null)`),
|
|
63
|
+
* and the read path gates on `Object.hasOwn`. The session id is caller-chosen
|
|
64
|
+
* on the host's `session.create` (a branded string with no shape validation),
|
|
65
|
+
* so an id equal to an `Object.prototype` member (`__proto__`, `constructor`,
|
|
66
|
+
* `toString`, …) must be an ordinary key: on a plain object literal it would
|
|
67
|
+
* instead read an inherited member (a non-array → `TypeError`) or hit the
|
|
68
|
+
* `__proto__` setter (reported `written` while persisting nothing).
|
|
69
|
+
*
|
|
70
|
+
* @module @mstar-harness/dsh/engine-status-store
|
|
71
|
+
*/
|
|
72
|
+
/** Envelope schema version carried by the snapshot file (`sv`). */
|
|
73
|
+
export declare const ENGINE_STATUS_SNAPSHOT_VERSION = 1;
|
|
74
|
+
/** Per-entry record version carried by every stored entry (`rv`). */
|
|
75
|
+
export declare const ENGINE_STATUS_SNAPSHOT_ENTRY_VERSION = 1;
|
|
76
|
+
/** Retention: newest entries kept per session (older ones are pruned on write). */
|
|
77
|
+
export declare const ENGINE_STATUS_SNAPSHOT_MAX_PER_SESSION = 50;
|
|
78
|
+
/** Retention: maximum entry age (30 days) — older entries are pruned on write. */
|
|
79
|
+
export declare const ENGINE_STATUS_SNAPSHOT_MAX_AGE_MS: number;
|
|
80
|
+
/**
|
|
81
|
+
* Retention: global byte ceiling for one store — the bound the per-session
|
|
82
|
+
* numbers above cannot express, since every session in a workspace shares this
|
|
83
|
+
* one file. Calibrated on the measured emission payload (≈19 KB per entry,
|
|
84
|
+
* ≈0.9 MB per session at the 50-entry cap) to ≈16 MB, i.e. ≈17 sessions before
|
|
85
|
+
* the oldest buckets are evicted; the writing session is never the one evicted.
|
|
86
|
+
*/
|
|
87
|
+
export declare const ENGINE_STATUS_SNAPSHOT_MAX_BYTES: number;
|
|
88
|
+
/**
|
|
89
|
+
* Lock-acquisition budget (ms) for the advisory snapshot write. The write runs
|
|
90
|
+
* synchronously on the per-turn `agent/pre-step` emission path, so it may never
|
|
91
|
+
* inherit the ledger's 30 s deadline: contention (or a stale lockdir left by a
|
|
92
|
+
* killed host) must degrade the advisory write quickly instead of stalling the
|
|
93
|
+
* agent step — and, in the same process, the `/api` gateway that serves the
|
|
94
|
+
* panel.
|
|
95
|
+
*/
|
|
96
|
+
export declare const ENGINE_STATUS_SNAPSHOT_LOCK_TIMEOUT_MS = 250;
|
|
97
|
+
/** Snapshot file location relative to `{HARNESS_DIR}`. */
|
|
98
|
+
export declare const ENGINE_STATUS_SNAPSHOT_RELATIVE_PATH = "snapshots/engine-status.json";
|
|
99
|
+
/**
|
|
100
|
+
* One stored emission: the payload the model saw, plus the identity needed to
|
|
101
|
+
* validate a later reader's claim (`cwd` is the session workspace the payload
|
|
102
|
+
* was resolved for).
|
|
103
|
+
*/
|
|
104
|
+
export interface EngineStatusSnapshotEntry {
|
|
105
|
+
/** Record version — a reader must see {@link ENGINE_STATUS_SNAPSHOT_ENTRY_VERSION}. */
|
|
106
|
+
readonly rv: number;
|
|
107
|
+
/** The session workspace the payload was resolved for (validation anchor). */
|
|
108
|
+
readonly cwd: string;
|
|
109
|
+
/** ISO timestamp of the emission. */
|
|
110
|
+
readonly at: string;
|
|
111
|
+
/** The agent turn the payload was emitted for. */
|
|
112
|
+
readonly turn: number;
|
|
113
|
+
/** The exact catalog payload object handed to the step messages. */
|
|
114
|
+
readonly payload: Record<string, unknown>;
|
|
115
|
+
}
|
|
116
|
+
/** Why a snapshot read could not produce the stored entry (every path explicit). */
|
|
117
|
+
export type EngineStatusSnapshotUnavailableReason = 'no-harness-dir' | 'absent' | 'unreadable' | 'invalid-json' | 'envelope-schema' | 'no-session-entry' | 'entry-schema';
|
|
118
|
+
/** The explicit "no answer" result — never a best-effort parse. */
|
|
119
|
+
export interface EngineStatusUnavailable {
|
|
120
|
+
readonly kind: 'unavailable';
|
|
121
|
+
readonly reason: EngineStatusSnapshotUnavailableReason;
|
|
122
|
+
}
|
|
123
|
+
/** Read outcome: the stored entry, or the explicit unavailable state. */
|
|
124
|
+
export type EngineStatusSnapshotRead = {
|
|
125
|
+
readonly kind: 'ok';
|
|
126
|
+
readonly entry: EngineStatusSnapshotEntry;
|
|
127
|
+
} | EngineStatusUnavailable;
|
|
128
|
+
/** Write outcome: written, or the degraded reason (never throws for I/O faults). */
|
|
129
|
+
export type EngineStatusSnapshotWrite = {
|
|
130
|
+
readonly kind: 'written';
|
|
131
|
+
readonly path: string;
|
|
132
|
+
readonly entries: number;
|
|
133
|
+
/** Session buckets shed to stay under the global byte ceiling (0 when none). */
|
|
134
|
+
readonly evicted: number;
|
|
135
|
+
/**
|
|
136
|
+
* Present ONLY on the first oversize write for this store in this process —
|
|
137
|
+
* the caller logs it. One warning per store, never one per turn.
|
|
138
|
+
*/
|
|
139
|
+
readonly warn?: string;
|
|
140
|
+
} | {
|
|
141
|
+
readonly kind: 'degraded';
|
|
142
|
+
readonly reason: string;
|
|
143
|
+
};
|
|
144
|
+
/** One write request — the emission site's payload plus its session identity. */
|
|
145
|
+
export interface EngineStatusSnapshotWriteInput {
|
|
146
|
+
/** The session whose catalog row this payload is (`session.header.id`). */
|
|
147
|
+
readonly sessionId: string;
|
|
148
|
+
/** The session workspace the payload was resolved for (`session.header.cwd`). */
|
|
149
|
+
readonly cwd: string;
|
|
150
|
+
/** The agent turn the row was emitted for. */
|
|
151
|
+
readonly turn: number;
|
|
152
|
+
/** The exact payload object handed to the step messages. */
|
|
153
|
+
readonly payload: object;
|
|
154
|
+
/** Emission timestamp (test seam; production uses `new Date()`). */
|
|
155
|
+
readonly now?: Date;
|
|
156
|
+
/** Global byte ceiling override (test seam; production uses the constant). */
|
|
157
|
+
readonly maxBytes?: number;
|
|
158
|
+
}
|
|
159
|
+
/** Absolute snapshot file path for one `{HARNESS_DIR}`. */
|
|
160
|
+
export declare function engineStatusSnapshotPath(harnessDir: string): string;
|
|
161
|
+
/** The explicit unavailable result (single constructor — one shape everywhere). */
|
|
162
|
+
export declare function engineStatusUnavailable(reason: EngineStatusSnapshotUnavailableReason): EngineStatusUnavailable;
|
|
163
|
+
/**
|
|
164
|
+
* Read the newest stored snapshot entry for one session.
|
|
165
|
+
*
|
|
166
|
+
* Every failure path is explicit: `{HARNESS_DIR}` unresolved (`no-harness-dir`),
|
|
167
|
+
* file absent (`absent`), unreadable (`unreadable`), not JSON (`invalid-json`),
|
|
168
|
+
* wrong envelope shape/`sv` (`envelope-schema`), no entries for the session
|
|
169
|
+
* (`no-session-entry`), or an unreadable entry record (`entry-schema`).
|
|
170
|
+
* @param harnessDir - the resolved `{HARNESS_DIR}` (null when none resolved).
|
|
171
|
+
* @param sessionId - the session whose snapshot is requested.
|
|
172
|
+
* @returns the newest stored entry, or the explicit unavailable state.
|
|
173
|
+
*/
|
|
174
|
+
export declare function readEngineStatusSnapshot(harnessDir: string | null, sessionId: string): EngineStatusSnapshotRead;
|
|
175
|
+
/**
|
|
176
|
+
* Persist one emission: append the entry for `sessionId`, prune (age + per
|
|
177
|
+
* session cap + the global byte ceiling), and atomically replace the file — the
|
|
178
|
+
* whole read-modify-write under the directory write lock.
|
|
179
|
+
*
|
|
180
|
+
* Contained by design: a lock timeout, a missing/unwritable directory, a failed
|
|
181
|
+
* replace, or an existing store this build does not understand returns
|
|
182
|
+
* `{kind:'degraded', reason}` (the advisory emission path must never abort the
|
|
183
|
+
* step it observes, and must never destroy what it cannot read). The in-memory
|
|
184
|
+
* payload is unaffected either way.
|
|
185
|
+
* @param harnessDir - the resolved `{HARNESS_DIR}` (null when none resolved).
|
|
186
|
+
* @param input - the emission's session identity + payload.
|
|
187
|
+
* @returns written (with the entry count, the evicted-bucket count and — once
|
|
188
|
+
* per store — the oversize warning) or the degraded reason.
|
|
189
|
+
*/
|
|
190
|
+
export declare function writeEngineStatusSnapshot(harnessDir: string | null, input: EngineStatusSnapshotWriteInput): EngineStatusSnapshotWrite;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE declaration of the engine-status wire address, shared by both halves
|
|
3
|
+
* of the channel: the host half composes the `/api` typert endpoint descriptor
|
|
4
|
+
* from these literals, and the browser half calls the same address through
|
|
5
|
+
* `connection.rpc.call(...)`.
|
|
6
|
+
*
|
|
7
|
+
* WHY a separate module: the two halves live in two bundle graphs (the host
|
|
8
|
+
* runs from `dist/index.js`, the panel from the closure-factory
|
|
9
|
+
* `dist/client.js`), and a rename on either side used to leave both suites
|
|
10
|
+
* green while the panel silently degraded to `transport-error` — each half's
|
|
11
|
+
* spec pinned only its own copy of the literals. Importing one module makes the
|
|
12
|
+
* rename impossible to land half-done, and `engine-status-wire.spec.ts` pins the
|
|
13
|
+
* descriptor the host registers against the address the client calls.
|
|
14
|
+
*
|
|
15
|
+
* CLIENT-SAFE BY CONSTRUCTION: no imports, no `node:` builtins, no side effects
|
|
16
|
+
* — only string literals and types. The client bundle's purity gate rejects
|
|
17
|
+
* non-inline-safe `@deepseek-ai/*` value imports; this module has nothing to
|
|
18
|
+
* inline but the two constants.
|
|
19
|
+
*
|
|
20
|
+
* @module @mstar-harness/dsh/engine-status-wire
|
|
21
|
+
*/
|
|
22
|
+
/** The gateway channel the endpoint is served on (the host's shared `/api`). */
|
|
23
|
+
export declare const ENGINE_STATUS_CHANNEL = "/api";
|
|
24
|
+
/** The endpoint path on that channel (namespace + method of the descriptor). */
|
|
25
|
+
export declare const ENGINE_STATUS_ENDPOINT = "mstar/engineStatus";
|
|
26
|
+
/** Wire namespace of the invocation (the cordis service key mirrors it). */
|
|
27
|
+
export declare const MSTAR_ENGINE_STATUS_NAMESPACE = "mstar";
|
|
28
|
+
/** Wire method of the invocation → `/api/mstar/engineStatus`. */
|
|
29
|
+
export declare const MSTAR_ENGINE_STATUS_METHOD = "engineStatus";
|
package/dist/gates/_shared.d.ts
CHANGED
|
@@ -305,6 +305,15 @@ export declare class HarnessResolver {
|
|
|
305
305
|
}
|
|
306
306
|
/** The workspace root of one agent — the session cwd (structural read; never trusts the runtime shape). */
|
|
307
307
|
export declare function sessionCwdOf(agent: unknown): string | undefined;
|
|
308
|
+
/**
|
|
309
|
+
* The stable session id of one agent — `session.header.id` (structural read).
|
|
310
|
+
*
|
|
311
|
+
* The SAME identity a later reader asserts when it asks the host endpoint for
|
|
312
|
+
* a session's engine-status snapshot: without a real id there is nothing to key
|
|
313
|
+
* a stored snapshot by, so an agent stub answers undefined and the write site
|
|
314
|
+
* skips the persist instead of inventing a key.
|
|
315
|
+
*/
|
|
316
|
+
export declare function sessionHeaderIdOf(agent: unknown): string | undefined;
|
|
308
317
|
/** The tool-execution actor of one fs-intent event, when it carries an agent. */
|
|
309
318
|
export declare function actorAgentOf(actor: object | undefined): unknown;
|
|
310
319
|
/**
|
package/dist/gates/catalog.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { type Context } from '@deepseek-ai/cordis';
|
|
2
2
|
import { type UserMessage } from '@deepseek-ai/dsh-llm';
|
|
3
3
|
import type { PreStepDecision } from '@deepseek-ai/dsh-agent';
|
|
4
|
-
import type {
|
|
4
|
+
import type { MstarEngineStatusPayload } from '../types.ts';
|
|
5
5
|
import { HarnessResolver } from './_shared.ts';
|
|
6
6
|
/** Default catalog cache refresh interval (ms) — see Config `catalogTtlMs`. */
|
|
7
7
|
export declare const DEFAULT_CATALOG_TTL_MS = 60000;
|
|
8
8
|
/** Catalog cache key for the explicit-`harnessDir` app-wide entry (one entry for every session). */
|
|
9
9
|
export declare const EXPLICIT_CACHE_KEY = "\0explicit";
|
|
10
|
-
/** One TTL cache entry: the unified
|
|
10
|
+
/** One TTL cache entry: the unified payload plus the build timestamp. */
|
|
11
11
|
export interface CatalogCacheEntry {
|
|
12
|
-
|
|
12
|
+
payload: MstarEngineStatusPayload;
|
|
13
13
|
builtAt: number;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
@@ -27,7 +27,7 @@ export interface CatalogCacheEntry {
|
|
|
27
27
|
export interface CatalogInvalidation {
|
|
28
28
|
/**
|
|
29
29
|
* Register `key` as the cache key of `harnessDir` — called by
|
|
30
|
-
* `
|
|
30
|
+
* `catalogPayloadFor` on cache hit AND build, and pre-registered by the
|
|
31
31
|
* entry at apply for the explicit-config boot entry (a ledger record
|
|
32
32
|
* between apply and the first pre-step must still invalidate the
|
|
33
33
|
* pre-seeded entry). A null harness dir (no `{HARNESS_DIR}` resolved) has
|
|
@@ -47,15 +47,15 @@ export interface CatalogInvalidation {
|
|
|
47
47
|
/** Create the apply-scoped invalidation bound to ONE catalog cache (entry-internal wiring — see {@link CatalogInvalidation}). */
|
|
48
48
|
export declare function createCatalogInvalidation(cache: Map<string, CatalogCacheEntry>): CatalogInvalidation;
|
|
49
49
|
/**
|
|
50
|
-
* Build the unified catalog
|
|
50
|
+
* Build the unified catalog payload for one harness dir (boot for the
|
|
51
51
|
* explicit config, first-use per workspace otherwise, then TTL-refreshed —
|
|
52
|
-
* see `
|
|
52
|
+
* see `catalogPayloadFor`). Logs the manifest fallback once per build — a
|
|
53
53
|
* '0.0.0' version would watermark every catalog row wrongly, so the
|
|
54
54
|
* fallback is never silent.
|
|
55
55
|
* @param ctx - registrant context (logger for the manifest fallback).
|
|
56
56
|
* @param harnessDir - the resolved `{HARNESS_DIR}` (null when none found).
|
|
57
57
|
*/
|
|
58
|
-
export declare function
|
|
58
|
+
export declare function buildCatalogPayload(ctx: Context, harnessDir: string | null): MstarEngineStatusPayload;
|
|
59
59
|
/**
|
|
60
60
|
* Advisory `agent/pre-step` waterfall listener (agent
|
|
61
61
|
* catalog): delegates through `next()` (never `reject` — that would block the
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
* compass soft/hard flip lands on the next assembly without
|
|
36
36
|
* re-registration, in zero-config and explicit-config deployments alike.
|
|
37
37
|
* - The context provider reuses the catalog's unified machine-summary
|
|
38
|
-
*
|
|
38
|
+
* payload (`buildCatalogPayload` — the SAME builder the engine-status
|
|
39
39
|
* pre-step catalog row uses) and projects the SLIM digest: the version watermark
|
|
40
40
|
* ALWAYS, plus ONE `workflow … | plans: …` line only when the active set
|
|
41
41
|
* selects a lifecycle (`state.selection.kind === 'active'`). Harness dir
|
package/dist/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { DshHostAdapter } from './gates/adapter.ts';
|
|
|
16
16
|
import type { DispatchGateAdvisory } from './gates/dispatch.ts';
|
|
17
17
|
export { DshMstar } from './service.ts';
|
|
18
18
|
export type { DshMstarOptions } from './service.ts';
|
|
19
|
-
export type { MstarEngineStatusSource, MstarHarnessState, MstarIterationGateView, AgentFlowEventView, AgentFlowSummaryRow, AgentFlowView, WorkflowSelectionView, } from './types.ts';
|
|
19
|
+
export type { MstarEngineStatusSource, MstarEngineStatusPayload, MstarHarnessState, MstarIterationGateView, AgentFlowEventView, AgentFlowSummaryRow, AgentFlowView, WorkflowSelectionView, } from './types.ts';
|
|
20
20
|
export { AGENT_FLOW_FILE, AGENT_FLOW_MAX_EVENTS, SETTLE_SEAM, readAgentFlow, recordDispatch, recordSettle, recordWorkflowVerdict, } from './gates/agent-flow.ts';
|
|
21
21
|
export type { AgentFlowEvent, DispatchVerdict, SettleOutcome, WorkflowGateMode, WorkflowVerdict, WorkflowVerdictInput, } from './gates/agent-flow.ts';
|
|
22
22
|
export { Config, HarnessResolver, skillLocalConfig } from './gates/_shared.ts';
|