@xmoon76/dsh-pi-tui 0.1.3 → 0.1.5

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.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A third-party TUI mode for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh`), built on a vendored fork of [pi-tui](https://github.com/MoonshotAI/kimi-code/tree/main/packages/pi-tui).
4
4
 
5
- This package is the `dsh.bundle` layer that makes `dsh --profile pi-tui` run a terminal UI instead of the browser GUI (`dsh --profile web`) or one-shot mode (`dsh --profile headless`). The vendored pi-tui fork (`@xmoon76/pi-tui`, with its five local rendering fixes) is bundled inside this package's build output — you only ever install this one package.
5
+ This package is the `dsh.bundle` layer that makes `dsh --profile pi-tui` run a terminal UI instead of the browser GUI (`dsh --profile web`) or one-shot mode (`dsh --profile headless`). The vendored pi-tui fork (`@xmoon76/pi-tui`, with its local rendering fixes — the divergence ledger lives in the repo at `packages/pi-tui/AGENTS.md`) is bundled inside this package's build output — you only ever install this one package.
6
6
 
7
7
  ## Install
8
8
 
package/dist/index.d.mts CHANGED
@@ -1,8 +1,97 @@
1
1
  import z from "@deepseek-ai/schemastery";
2
- import { ModelSelectionRef } from "@deepseek-ai/dsh-agent";
2
+ import { Agent, ModelSelectionRef } from "@deepseek-ai/dsh-agent";
3
3
  import { SessionEvent, SessionId } from "@deepseek-ai/dsh-session";
4
+ import { CommandDescriptor } from "@deepseek-ai/dsh-commands";
4
5
  import { EventEmitter } from "events";
5
6
  import { Context } from "@deepseek-ai/cordis";
7
+ //#region src/diag.d.ts
8
+ interface Diag {
9
+ debug(message: string, fields?: Record<string, unknown>): void;
10
+ info(message: string, fields?: Record<string, unknown>): void;
11
+ warn(message: string, fields?: Record<string, unknown>): void;
12
+ error(message: string, fields?: Record<string, unknown>): void;
13
+ /** Release the file handle, if one is open. */
14
+ dispose(): void;
15
+ }
16
+ //#endregion
17
+ //#region src/skill-catalog.d.ts
18
+ /**
19
+ * The standing-scope skill catalog adapter: the SINGLE narrow seam between
20
+ * the TUI and the dsh skill services (the non-public-API isolation
21
+ * contract, plan appendix B).
22
+ *
23
+ * Everything the TUI knows about dsh-skill and agent-presets lives here:
24
+ * - structural service types (never upstream classes) with OPTIONAL
25
+ * capability members — `snapshot` and `standingKeyFor` are detected at
26
+ * call time, so an upstream change degrades instead of breaking;
27
+ * - `readHumanSkillCatalog()`: snapshot-first collector (list() fallback),
28
+ * official `isUserInvocable` filter, field validation, stable sort,
29
+ * deep freeze, distinct abort propagation;
30
+ * - `resolveColdSkillTarget()`: capability-gated cold target selection
31
+ * (standing scope → rosterless global → degraded global with a notice);
32
+ * - `resolveLiveSkillTarget()`: the agent's own registry + agent scope.
33
+ *
34
+ * Failure contract: ordinary provider/composition failures surface as
35
+ * degraded targets or rethrown errors for the coordinator to classify;
36
+ * aborts ALWAYS propagate as aborts. No failure may hang or crash the TUI —
37
+ * the worst outcome is "the corresponding commands are missing".
38
+ * @module @xmoon76/dsh-pi-tui/skill-catalog
39
+ */
40
+ /** The human-facing slice of one skill: display fields only. */
41
+ interface HumanSkillSummary {
42
+ readonly name: string;
43
+ readonly description: string;
44
+ readonly whenToUse?: string;
45
+ }
46
+ /** The detached human skill catalog one observation produced. */
47
+ interface HumanSkillCatalog {
48
+ readonly skills: readonly HumanSkillSummary[];
49
+ /** Whether discovery completed within a stable revision (an incomplete
50
+ * observation must not replace a last-good catalog). */
51
+ readonly complete: boolean;
52
+ }
53
+ //#endregion
54
+ //#region src/surface-catalog.d.ts
55
+ /** One effective command's discovery metadata (the official descriptor's
56
+ * display fields; never a handler or a definition). */
57
+ interface SurfaceCommandSummary {
58
+ readonly name: string;
59
+ readonly description: string;
60
+ readonly input?: {
61
+ readonly hint: string;
62
+ };
63
+ }
64
+ /** One provider's detached failure text (never the thrown value itself). */
65
+ interface SurfaceCatalogIssue {
66
+ readonly provider: 'commands' | 'skills';
67
+ readonly message: string;
68
+ }
69
+ /**
70
+ * The complete frozen catalog view installed before the first input:
71
+ * - `commands` — the full effective view at read time (diagnostics/tests);
72
+ * - `scopedCommands` — effective entries absent from, or shadowing, the
73
+ * read-time global baseline (completion overrides while sessionless);
74
+ * - `skills` — human-invocable skill summaries (official policy applied);
75
+ * - `issues` — per-provider failures; an absent service is NOT an issue.
76
+ */
77
+ interface SurfaceCatalogSnapshot {
78
+ readonly commands: readonly SurfaceCommandSummary[];
79
+ readonly scopedCommands: readonly SurfaceCommandSummary[];
80
+ readonly skills: readonly HumanSkillSummary[];
81
+ readonly issues: readonly SurfaceCatalogIssue[];
82
+ }
83
+ /** The commands-service surface the collector reads. */
84
+ interface SurfaceCommandsService {
85
+ list(agent: Agent): readonly CommandDescriptor[];
86
+ }
87
+ /** The narrow context surface {@link readSurfaceCatalog} consumes. The
88
+ * SKILL services are NOT reached here: every dsh skill/agent-presets
89
+ * access goes through `src/skill-catalog.ts` (the single-point adapter,
90
+ * plan appendix B.1). */
91
+ interface SurfaceCatalogContext {
92
+ get(name: 'commands'): SurfaceCommandsService | undefined;
93
+ }
94
+ //#endregion
6
95
  //#region src/commands.d.ts
7
96
  /** A balanced completed-turn prefix for forking: the log up to (and including)
8
97
  * the last `turn/end`. Undefined when no turn has completed yet.
@@ -23,11 +112,103 @@ interface Config {
23
112
  }
24
113
  declare const Config: z<Config>;
25
114
  /**
26
- * Read an explicit child-session reference from a future/extended job record.
27
- * Current dsh JobSnapshot records do not expose one, so this normally returns
28
- * undefined. Crucially, label, registration order and timestamps are never
29
- * accepted as identity signals.
115
+ * Slash commands that need no session: before the first user message
116
+ * (deferred start) they run locally without creating one. Everything else
117
+ * dispatches through `commands.execute`, which creates the session lazily
118
+ * (the command line IS the first user input). Commands in this set must
119
+ * tolerate `liveAgent === undefined` in their handlers.
120
+ *
121
+ * Exported for the headless suite: the gate is exactly where a sessionless
122
+ * command silently starts creating sessions again.
123
+ */
124
+ declare const SESSIONLESS_COMMANDS: Set<string>;
125
+ /**
126
+ * The LOCAL-execute command set: TUI-owned UI/control commands AND core
127
+ * control commands the TUI does not itself register (e.g. /kill) that
128
+ * must ALWAYS run locally through the commands service, never steered,
129
+ * regardless of the busyEnter preference. Everything NOT in this set —
130
+ * plain prompts AND non-local commands (the per-skill slash commands like
131
+ * /grilling or /matrix-cli) — flows through the busy-Enter submission
132
+ * policy while the agent is running: web parity, where a skill invocation
133
+ * is a plain `session.prompt` whose leading `/name` line the host's
134
+ * pre-step listener (dsh-tool-skill) resolves into the injected skill
135
+ * body — there is no command-execution wire for skills.
136
+ */
137
+ declare const LOCAL_COMMANDS: Set<string>;
138
+ /**
139
+ * Whether one submission steers under the busy-Enter preference: NOT a
140
+ * force-queued chord, NOT a TUI-owned local command, and the agent is
141
+ * running with the preference set to 'steer'. Pure so the dispatch gate
142
+ * (inside the runner closure) is testable headless.
143
+ * @param parsed - the parsed slash command, undefined for a plain prompt.
144
+ * @param running - whether the live agent reports running.
145
+ * @param busyEnter - the persisted preference value (''/undefined = queue).
146
+ * @param forceQueue - the Ctrl+Enter chord: always queue, never steer.
30
147
  */
148
+ declare function shouldSteerOnEnter(parsed: {
149
+ name: string;
150
+ } | undefined, running: boolean, busyEnter: string | undefined, forceQueue: boolean): boolean;
151
+ /**
152
+ * The advertised-claim miss decision (pure, exported for the headless
153
+ * suite): a slash input whose name was advertised by the completion list at
154
+ * submit time but that the REAL session's catalog lacks is CONSUMED with an
155
+ * explicit error — never sent to the model as a plain user message. An
156
+ * unadvertised miss keeps the existing plain-input fallback (the user may
157
+ * deliberately send slash text to the model).
158
+ * @param execution - the settled `commands.execute` outcome.
159
+ * @param wasAdvertised - the claim captured BEFORE session creation.
160
+ * @returns whether the miss must be consumed as an advertised miss.
161
+ */
162
+ declare function shouldConsumeAdvertisedMiss(execution: {
163
+ readonly result: unknown;
164
+ } | undefined, wasAdvertised: boolean): boolean;
165
+ /**
166
+ * The pre-mount surface catalog resolution:
167
+ * - an explicit `--session` start PREFETCHES the resumed agent's effective
168
+ * catalog (a live read emits no session events);
169
+ * - the deferred start (no `--session`) reads the cold HUMAN SKILL catalog
170
+ * through the preset's STANDING SCOPE — no Agent, no session, no turn —
171
+ * so the first input sees human-invocable skills without any durable
172
+ * side effect (the mechanism that avoids the probe dead end: host
173
+ * `session/created` observers write durable knob events into every fresh
174
+ * session).
175
+ *
176
+ * The snapshot (resume) or the skill catalog (cold) installs synchronously
177
+ * after mount (the ready barrier).
178
+ *
179
+ * Failure taxonomy (plan appendix B):
180
+ * - lifecycle cancellation: nothing installed, no notice;
181
+ * - a prefetch/standing read failure degrades to a one-shot notice (the
182
+ * TUI mounts with the global view and built-in commands);
183
+ * - a missing/unknown preset or a broken standing mount degrades the cold
184
+ * target to the global layer with a one-shot notice — never a probe
185
+ * Agent, never a startup failure;
186
+ * - an ordinary provider read failure never rejects here: it becomes an
187
+ * empty field + detached issue inside the catalog.
188
+ * @param options - injected dependencies (see {@link ResolveInitialCatalogOptions}).
189
+ * @returns the snapshot / skill catalog to install and an optional notice.
190
+ */
191
+ interface InitialCatalogResolution {
192
+ /** The resume prefetch snapshot to install at mount. */
193
+ readonly snapshot?: SurfaceCatalogSnapshot;
194
+ /** The cold standing-scope human skill catalog (deferred start). */
195
+ readonly skills?: HumanSkillCatalog;
196
+ /** A user-facing notice when the prefetch/standing read degraded. */
197
+ readonly notice?: string;
198
+ }
199
+ /** Options for {@link resolveInitialCatalog}. */
200
+ interface ResolveInitialCatalogOptions {
201
+ /** The resumed live agent, if any (prefetch path). */
202
+ readonly liveAgent?: Agent;
203
+ /** The effective preset id for the cold standing read (undefined = the
204
+ * deployment default; only consulted for the deferred start). */
205
+ readonly presetId?: string;
206
+ readonly signal: AbortSignal;
207
+ /** The context surface the collectors read services from. */
208
+ readonly ctx: SurfaceCatalogContext;
209
+ readonly diag: Diag;
210
+ }
211
+ declare function resolveInitialCatalog(options: ResolveInitialCatalogOptions): Promise<InitialCatalogResolution>;
31
212
  declare function subagentJobTranscriptId(snapshot: unknown): string | undefined;
32
213
  /** Viewer body for a subagent job with no uniquely matched child. */
33
214
  declare function subagentJobViewHint(status: string, detail: string | undefined): string;
@@ -131,4 +312,4 @@ declare function recomposeBlank(ctx: Context, agent: {
131
312
  */
132
313
  declare function apply(ctx: Context, config: Config): void;
133
314
  //#endregion
134
- export { AgentComposition, Config, RecomposableSession, RecomposeOutcome, apply, composeAgent, dangerCommand, forkSeed, inject, name, recomposeBlank, recordedPreset, resumeCommand, runningProfile, subagentJobTranscriptId, subagentJobViewHint };
315
+ export { AgentComposition, Config, InitialCatalogResolution, LOCAL_COMMANDS, RecomposableSession, RecomposeOutcome, ResolveInitialCatalogOptions, SESSIONLESS_COMMANDS, apply, composeAgent, dangerCommand, forkSeed, inject, name, recomposeBlank, recordedPreset, resolveInitialCatalog, resumeCommand, runningProfile, shouldConsumeAdvertisedMiss, shouldSteerOnEnter, subagentJobTranscriptId, subagentJobViewHint };