@xmoon76/dsh-pi-tui 0.4.3-alpha.2 → 0.4.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.
@@ -67,8 +67,16 @@ interface TuiAutocompleteQuery {
67
67
  interface TuiAutocompleteProvider {
68
68
  getSuggestions(query: TuiAutocompleteQuery): Promise<TuiAutocompleteSuggestions | null>;
69
69
  }
70
- /** API version of the extension surface (bumped only on breaking changes). */
71
- declare const API_VERSION: 1;
70
+ /**
71
+ * API version of the extension surface (bumped only on breaking changes).
72
+ * `2` is the client-command contribution contract: `execution` and the
73
+ * never-wired `argumentProvider` are REMOVED, `handler` is required, and a
74
+ * stale plugin still declaring the removed ownership shape is rejected at
75
+ * registration. `1` was the M0–M3 foundation. A plugin branching on
76
+ * `api().apiVersion` can tell the two schemas apart — the host never reports
77
+ * a version it does not implement.
78
+ */
79
+ declare const API_VERSION: 2;
72
80
  /** Capability identifiers, feature-detected via {@link PiTuiApiInfo}. */
73
81
  type PiTuiCapability = 'slot.chrome.header.badge' | 'slot.input.dock.item' | 'slot.chrome.footer.status' | 'slot.chrome.footer.item' | 'slot.input.widget' | 'surface.snapshot' | 'advanced.input.capture' | 'advanced.ui.interactive' | 'advanced.editor.control' | 'unstable.input.raw' | 'unstable.surface.handle';
74
82
  /** Slot identities this bundle knows; unknown names are rejected at registration. */
@@ -79,7 +87,8 @@ type PiTuiSlotSemantic = 'list' | 'single';
79
87
  type ExtensionTier = 'stable' | 'advanced' | 'unstable';
80
88
  /** What a plugin may know about the host (M1: version + capabilities only). */
81
89
  interface PiTuiApiInfo {
82
- /** The extension API version; 1 for the M0–M3 foundation. */
90
+ /** The extension API version: 2 for the client-command contribution
91
+ * contract, 1 for the M0–M3 foundation (see {@link API_VERSION}). */
83
92
  readonly apiVersion: typeof API_VERSION;
84
93
  /** The `@xmoon76/dsh-pi-tui` bundle version (semver string). */
85
94
  readonly hostVersion: string;
@@ -335,29 +344,40 @@ interface InputWidget {
335
344
  /** Preferred max rows (budget); the host may grant fewer. */
336
345
  readonly maxHeight?: number;
337
346
  }
338
- /** One command contribution (plan §10): ownership metadata over an
339
- * existing command. The bridge does NOT execute — the commands service
340
- * does. `/name args...` ALWAYS keeps `invocation.rawInput` verbatim. */
347
+ /** One CLIENT-OWNED command contribution (plan §10) — the DSH client
348
+ * command contribution shape: a slash name whose behavior lives entirely on
349
+ * the client (no host descriptor). It appears in the `/` menu merged with
350
+ * the host catalog and executes through its own `handler`, never steered.
351
+ * A contribution whose name is a host command FAILS LOUD at candidate
352
+ * synthesis and never shadows it (the host command keeps its claim).
353
+ * A contribution is a slash-MENU entry, so it claims the BARE `/name` token
354
+ * only (DSH `matchEnter`): `/name args...` is NOT an invocation — it is an
355
+ * ordinary submission that reaches the model, and `handler` never runs for
356
+ * it. */
341
357
  interface TuiCommandContribution {
342
358
  readonly id: string;
343
359
  /** The slash-command name WITHOUT the leading slash. */
344
360
  readonly name: string;
345
361
  readonly description: string;
346
- /** Execution ownership: local (never steered) vs submission (session
347
- * policy). Busy Enter classifies by the EFFECTIVE ownership. */
348
- readonly execution: 'local' | 'submission';
349
- /** Whether the command may run without a live session. */
362
+ /** Whether the command may run BEFORE a live session exists (default
363
+ * false). A sessionless contribution executes immediately; every other
364
+ * contribution resolves/creates the session first, then executes — the
365
+ * host command surface is session-keyed upstream, so this is an explicit
366
+ * TUI extension for pure client commands (an overlay toggle, a picker). */
350
367
  readonly sessionless?: boolean;
351
- /** Optional autocomplete provider for this command's arguments
352
- * (the structural {@link TuiAutocompleteProvider}). */
353
- readonly argumentProvider?: TuiAutocompleteProvider;
354
- /** Optional local handler; absent = metadata-only ownership (the
355
- * commands service handler runs). */
356
- readonly handler?: TuiLocalCommandHandler;
368
+ /** The command's client behavior (required): the TUI runs it locally for the
369
+ * BARE `/name` line, passing `invocation.rawInput` verbatim (it carries no
370
+ * non-whitespace input, since an argued line is never an invocation, though
371
+ * trailing whitespace may be preserved), with or without a live session
372
+ * according to {@link sessionless}. */
373
+ readonly handler: TuiLocalCommandHandler;
357
374
  }
358
375
  /** The local command handler signature (invocation carries the VERBATIM
359
- * raw input — never re-parsed or rewritten). Returns the commands
360
- * service's result shape (`{ kind: 'success' }` / `{ kind: 'error',
376
+ * raw input — never re-parsed or rewritten). A client command CONTRIBUTION is
377
+ * invoked by its bare token alone, so its `rawInput` never carries
378
+ * non-whitespace input (trailing whitespace is preserved verbatim); TUI-owned
379
+ * local commands (`/export json`) still receive their arguments here. Returns the
380
+ * commands service's result shape (`{ kind: 'success' }` / `{ kind: 'error',
361
381
  * text }`) so the runner's notify path is shared. */
362
382
  interface TuiLocalCommandHandler {
363
383
  (invocation: {
@@ -380,9 +400,13 @@ interface TuiLocalCommandHandler {
380
400
  readonly text: string;
381
401
  }>;
382
402
  }
383
- /** A live handle on one command contribution. */
403
+ /** A live handle on ONE command contribution REGISTRATION. */
384
404
  interface TuiCommandHandle {
385
405
  readonly id: string;
406
+ /** Dispose THIS registration (idempotent). A repeated or late call — e.g.
407
+ * a fiber disposer running after an HMR reload re-registered the same id —
408
+ * never removes a NEWER registration: the handle names one generation, not
409
+ * the id. */
386
410
  dispose(): void;
387
411
  }
388
412
  /** The command bridge's observable snapshot. */
@@ -391,9 +415,12 @@ interface TuiCommandBridgeSnapshot {
391
415
  readonly id: string;
392
416
  readonly name: string;
393
417
  readonly description: string;
394
- readonly execution: 'local' | 'submission';
395
418
  readonly sessionless: boolean;
396
419
  readonly owner: string;
420
+ /** Monotonic per-registration generation (diagnostics + the notice
421
+ * identity): a dispose + re-register under the same id/owner is a NEW
422
+ * generation, even when both happen inside one coalesced flush. */
423
+ readonly generation: number;
397
424
  }[];
398
425
  readonly revision: number;
399
426
  }