@deepseek-ai/dsh-client-ui-commands 0.1.5-alpha.1 → 0.1.5-alpha.2

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 CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/client/ui-commands/README.md
5
- README.md: e1264d10bd8ff807d8f348339e0c055607579407
6
- README.zh.md: c5323149aea1e38ff09262db9bd2aacad7b284ea
5
+ README.md: c5f3c55c08a6df8e6c3f122d0c5e341721c2b41a
6
+ README.zh.md: f728c03e067f74ba5142464adc17531225034aad
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "Client command API for the Web GUI: the / command source, three dispatch kinds, the per-session command directory, and popupSelect registration for business packages; for users and maintainers of slash commands."
2
+ description: "Client command API for the Web GUI: the / command source, three dispatch kinds, the per-session command directory, and popupSelect and action registration for business packages; for users and maintainers of slash commands."
3
3
  kind: "package-reference"
4
4
  ---
5
5
 
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
9
9
 
10
10
  ## Summary
11
11
 
12
- Typing a `/` command in the composer opens the matching surface — a registered popup, a host command's input, or a direct execution — and a command line is never silently downgraded to a plain prompt. Business packages contribute command surfaces through `ctx.commandUi`, registering a popupSelect spec (`/model`, `/permission`) or decorating an existing host command with a picker while the host keeps its catalog row and argument claim. Space and Enter resolve the line against the session's directory: a host descriptor with `input` is `leadingInput`, a registered `CommandUiSpec` is `popupSelect`, and everything else is `execute`.
12
+ Typing a `/` command in the composer opens the matching surface — a registered popup, a host command's input, or a direct execution — and a command line is never silently downgraded to a plain prompt. Business packages contribute command surfaces through `ctx.commandUi`: a popupSelect spec (`/model`, `/permission`) or an action (`/feedback`), registered as a command or decorating an existing host command while the host keeps its catalog row and argument claim. Space and Enter resolve the line against the session's directory: a host descriptor with `input` is `leadingInput`, a registered `CommandUiSpec` is its kind, and everything else is `execute`.
13
13
 
14
14
  ## Table of Contents
15
15
 
package/README.zh.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "Web GUI 的客户端命令 API:/ 命令 source、三类派发、会话级命令目录,以及面向业务包的 popupSelect 注册;供斜杠命令的用户与维护者阅读。"
2
+ description: "Web GUI 的客户端命令 API:/ 命令 source、三类派发、会话级命令目录,以及面向业务包的 popupSelect 与 action 注册;供斜杠命令的用户与维护者阅读。"
3
3
  kind: "package-reference"
4
4
  ---
5
5
 
@@ -9,7 +9,7 @@ kind: "package-reference"
9
9
 
10
10
  ## 概述
11
11
 
12
- 在 composer 中键入 `/` 命令会打开匹配的表面——已注册的弹窗、宿主命令的输入或直接执行——命令行绝不会被静默降级为普通提示词。业务包经 `ctx.commandUi` 贡献命令表面:注册 popupSelect 贡献项(`/model`、`/permission`),或用选择器装饰既有宿主命令,宿主保留其目录行与参数声明。空格与回车对照会话目录解析命令行:带 `input` 的宿主描述符是 `leadingInput`,注册了 `CommandUiSpec` 的是 `popupSelect`,其余全部是 `execute`。
12
+ 在 composer 中键入 `/` 命令会打开匹配的表面——已注册的弹窗、宿主命令的输入或直接执行——命令行绝不会被静默降级为普通提示词。业务包经 `ctx.commandUi` 贡献命令表面:popupSelect 贡献项(`/model`、`/permission`)或 action(`/feedback`),既可注册为命令,也可装饰既有宿主命令,宿主保留其目录行与参数声明。空格与回车对照会话目录解析命令行:带 `input` 的宿主描述符是 `leadingInput`,注册了 `CommandUiSpec` 的按其种类派发,其余全部是 `execute`。
13
13
 
14
14
  ## 目录
15
15
 
package/lib/client.js CHANGED
@@ -658,12 +658,12 @@ window.__ModuleLoader__.load({
658
658
  const key = HOST_DESCRIPTION_KEYS.get(command.name);
659
659
  return key !== void 0 && command.description === en[key] ? this.t(key) : command.description;
660
660
  }
661
- /** Decision table, menu column: contribution/decorated-host → popup; host input → claim; host bare → detached execute. */
661
+ /** Decision table, menu column: contribution/decorated-host → popup or action; host input → claim; host bare → detached execute. */
662
662
  dispatch(pick) {
663
663
  const name = pick.candidate.name;
664
664
  const contribution = this.live.contributions.get(name);
665
665
  if (contribution !== void 0 && contribution.available(pick.session)) {
666
- this.openPopup(name, contribution.ui, pick.session, {
666
+ this.invoke(name, contribution.ui, pick.session, {
667
667
  via: "menu",
668
668
  span: pick.span
669
669
  });
@@ -673,7 +673,7 @@ window.__ModuleLoader__.load({
673
673
  if (desc === void 0) return void 0;
674
674
  const decoration = this.live.decorations.get(name);
675
675
  if (decoration !== void 0 && decoration.available(pick.session)) {
676
- this.openPopup(name, decoration.ui, pick.session, {
676
+ this.invoke(name, decoration.ui, pick.session, {
677
677
  via: "menu",
678
678
  span: pick.span
679
679
  });
@@ -703,10 +703,11 @@ window.__ModuleLoader__.load({
703
703
  * args-tolerant.
704
704
  *
705
705
  * Envelope policy: an enter submission carrying attachments resolves only
706
- * through a command declaring attachment acceptance. Every other command route —
707
- * popup, non-accepting claim, bare detached execute — throws the refusal
708
- * so the machine surfaces one composer notice and the draft and attachments
709
- * stay in place; nothing executes and nothing is dropped.
706
+ * through a command declaring attachment acceptance. Every other submitting
707
+ * route — popup, non-accepting claim, bare detached execute — throws the
708
+ * refusal so the machine surfaces one composer notice and the draft and
709
+ * attachments stay in place; nothing executes and nothing is dropped. An
710
+ * action submits nothing and runs regardless.
710
711
  */
711
712
  async matchEnter(session, line, signal, envelope) {
712
713
  const trimmed = line.trim();
@@ -722,8 +723,8 @@ window.__ModuleLoader__.load({
722
723
  const contribution = this.live.contributions.get(name);
723
724
  if (contribution !== void 0 && contribution.available(session)) {
724
725
  if (!bare) return void 0;
725
- if (envelope.attachments > 0) refuseAttachments();
726
- this.openPopup(name, contribution.ui, session, {
726
+ if (envelope.attachments > 0 && contribution.ui.kind !== "action") refuseAttachments();
727
+ this.invoke(name, contribution.ui, session, {
727
728
  via: "enter",
728
729
  token
729
730
  });
@@ -735,8 +736,8 @@ window.__ModuleLoader__.load({
735
736
  if (bare) {
736
737
  const decoration = this.live.decorations.get(name);
737
738
  if (decoration !== void 0 && decoration.available(session)) {
738
- if (envelope.attachments > 0) refuseAttachments();
739
- this.openPopup(name, decoration.ui, session, {
739
+ if (envelope.attachments > 0 && decoration.ui.kind !== "action") refuseAttachments();
740
+ this.invoke(name, decoration.ui, session, {
740
741
  via: "enter",
741
742
  token
742
743
  });
@@ -756,8 +757,16 @@ window.__ModuleLoader__.load({
756
757
  this.runDetached(desc, session, trimmed);
757
758
  return "handled";
758
759
  }
759
- /** Open the session's popup for one contribution or decoration (menu pick / bare enter). */
760
- openPopup(name, ui, session, segment) {
760
+ /**
761
+ * Invoke one contribution or decoration (menu pick / bare enter): open the
762
+ * session's popup, or consume the token and run the action.
763
+ */
764
+ invoke(name, ui, session, segment) {
765
+ if (ui.kind === "action") {
766
+ this.consumeVia(session.sessionId, segment);
767
+ ui.run(session);
768
+ return;
769
+ }
761
770
  const actx = this.scopeFor(session.sessionId);
762
771
  if (actx === void 0) return;
763
772
  this.popupFor(actx).open(name, ui, session, segment);
@@ -28,11 +28,27 @@ export interface SelectOption {
28
28
  * The shell component is owned by ui-commands; business never sees it. Both
29
29
  * callbacks receive the ClientSessionContext captured at popup open.
30
30
  */
31
- export type CommandUiSpec = {
31
+ export interface PopupSelectSpec {
32
32
  readonly kind: 'popupSelect';
33
33
  options(session: ClientSessionContext, signal: AbortSignal): Promise<readonly SelectOption[]>;
34
34
  onSelect(option: SelectOption, session: ClientSessionContext): void | Promise<void>;
35
- };
35
+ }
36
+ /**
37
+ * Business registration for the action command kind: a bare invocation
38
+ * consumes the trigger token and runs one client-side callback (the Feedback
39
+ * row opens the feedback dialog). It submits nothing, so an
40
+ * attachment-carrying draft never refuses it.
41
+ */
42
+ export interface ActionSpec {
43
+ readonly kind: 'action';
44
+ /**
45
+ * Run the action for one session.
46
+ * @param session - the ClientSessionContext captured at invocation.
47
+ */
48
+ run(session: ClientSessionContext): void;
49
+ }
50
+ /** The UI behavior of a contribution or decoration. */
51
+ export type CommandUiSpec = PopupSelectSpec | ActionSpec;
36
52
  /**
37
53
  * One client-owned command contribution: a slash-menu entry whose behavior
38
54
  * lives entirely on the client (no host descriptor). Merged with the host
@@ -46,7 +62,7 @@ export interface CommandContribution {
46
62
  readonly description: () => string;
47
63
  /** Capability filter, called with a fresh projection per candidate pass. */
48
64
  available(session: ClientSessionContext): boolean;
49
- /** The command's UI behavior (this phase: popupSelect only). */
65
+ /** The command's UI behavior. */
50
66
  readonly ui: CommandUiSpec;
51
67
  }
52
68
  /**
@@ -63,7 +79,7 @@ export interface CommandDecoration {
63
79
  readonly name: string;
64
80
  /** Capability filter, called with a fresh projection per bare invocation. */
65
81
  available(session: ClientSessionContext): boolean;
66
- /** The bare-invocation UI (this phase: popupSelect only). */
82
+ /** The bare-invocation UI. */
67
83
  readonly ui: CommandUiSpec;
68
84
  }
69
85
  /** The `ctx.commandUi` service face visible to business packages. */
@@ -14,7 +14,7 @@ export type { CommandDescriptor, DirectoryStatus } from './directory.ts';
14
14
  export { filterOptions, PopupSelectController } from './popup.ts';
15
15
  export type { PopupSelectDeps, PopupSpec, PopupState, TokenSegment } from './popup.ts';
16
16
  export type { PopupSelectInjected, PopupSelectViewProps } from './PopupSelectView.tsx';
17
- export type { CommandContribution, CommandDecoration, CommandUiContract, CommandUiSpec, SelectConfirmation, SelectOption, } from './contract.ts';
17
+ export type { ActionSpec, CommandContribution, CommandDecoration, CommandUiContract, CommandUiSpec, PopupSelectSpec, SelectConfirmation, SelectOption, } from './contract.ts';
18
18
  export type { CommandKey } from './locales.ts';
19
19
  declare module '@deepseek-ai/cordis' {
20
20
  interface Context {
@@ -78,7 +78,7 @@ export declare class CommandUiRuntime extends Service implements CommandUiContra
78
78
  private candidates;
79
79
  /** Translate exact built-in Host copy while preserving scoped or third-party descriptors verbatim. */
80
80
  private hostDescription;
81
- /** Decision table, menu column: contribution/decorated-host → popup; host input → claim; host bare → detached execute. */
81
+ /** Decision table, menu column: contribution/decorated-host → popup or action; host input → claim; host bare → detached execute. */
82
82
  private dispatch;
83
83
  /** Decision table, space column: hot-key sync check; only host leadingInput claims. */
84
84
  private matchSpace;
@@ -89,14 +89,18 @@ export declare class CommandUiRuntime extends Service implements CommandUiContra
89
89
  * args-tolerant.
90
90
  *
91
91
  * Envelope policy: an enter submission carrying attachments resolves only
92
- * through a command declaring attachment acceptance. Every other command route —
93
- * popup, non-accepting claim, bare detached execute — throws the refusal
94
- * so the machine surfaces one composer notice and the draft and attachments
95
- * stay in place; nothing executes and nothing is dropped.
92
+ * through a command declaring attachment acceptance. Every other submitting
93
+ * route — popup, non-accepting claim, bare detached execute — throws the
94
+ * refusal so the machine surfaces one composer notice and the draft and
95
+ * attachments stay in place; nothing executes and nothing is dropped. An
96
+ * action submits nothing and runs regardless.
96
97
  */
97
98
  private matchEnter;
98
- /** Open the session's popup for one contribution or decoration (menu pick / bare enter). */
99
- private openPopup;
99
+ /**
100
+ * Invoke one contribution or decoration (menu pick / bare enter): open the
101
+ * session's popup, or consume the token and run the action.
102
+ */
103
+ private invoke;
100
104
  /** Build the leadingInput claim: token `/name ` + the command.execute submit transaction. */
101
105
  private leadingClaim;
102
106
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-commands",
3
3
  "description": "Client command surface: global directory cache, '/' source, three command UI kinds, popupSelect registry",
4
- "version": "0.1.5-alpha.1",
4
+ "version": "0.1.5-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -37,30 +37,28 @@
37
37
  }
38
38
  },
39
39
  "license": "MIT",
40
- "dependencies": {
41
- "clsx": "^2.0.0"
42
- },
43
40
  "peerDependencies": {
44
41
  "@deepseek-ai/cordis": "^4.0.2"
45
42
  },
46
43
  "devDependencies": {
47
44
  "@types/react": "~18.3.1",
48
45
  "react": "^18.2.0",
49
- "@deepseek-ai/dsh-api-remotes": "^0.1.5-alpha.1",
50
- "@deepseek-ai/dsh-client-connection": "^0.1.5-alpha.1",
51
- "@deepseek-ai/dsh-client-locale": "^0.1.5-alpha.1",
52
- "@deepseek-ai/dsh-client-test-runtime": "^0.1.5-alpha.1",
53
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.5-alpha.1",
54
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-alpha.1",
55
- "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.5-alpha.1",
56
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.5-alpha.1",
57
- "@deepseek-ai/dsh-commands": "^0.1.5-alpha.1",
46
+ "clsx": "^2.0.0",
47
+ "@deepseek-ai/dsh-client-connection": "^0.1.5-alpha.2",
48
+ "@deepseek-ai/dsh-client-locale": "^0.1.5-alpha.2",
49
+ "@deepseek-ai/dsh-client-test-runtime": "^0.1.5-alpha.2",
50
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-alpha.2",
51
+ "@deepseek-ai/dsh-commands": "^0.1.5-alpha.2",
52
+ "@deepseek-ai/dsh-client-ui-conversation": "^0.1.5-alpha.2",
53
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.5-alpha.2",
58
54
  "@deepseek-ai/cordis": "^4.0.2",
59
- "@deepseek-ai/dsh-api-session-controller": "^0.1.5-alpha.1",
60
- "@deepseek-ai/dsh-client-store": "^0.1.5-alpha.1",
61
- "@deepseek-ai/dsh-session": "^0.1.5-alpha.1",
62
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-alpha.1",
63
- "@deepseek-ai/dsh-client-ui-session": "^0.1.5-alpha.1"
55
+ "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.5-alpha.2",
56
+ "@deepseek-ai/dsh-api-session-controller": "^0.1.5-alpha.2",
57
+ "@deepseek-ai/dsh-client-store": "^0.1.5-alpha.2",
58
+ "@deepseek-ai/dsh-session": "^0.1.5-alpha.2",
59
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-alpha.2",
60
+ "@deepseek-ai/dsh-client-ui-session": "^0.1.5-alpha.2",
61
+ "@deepseek-ai/dsh-api-remotes": "^0.1.5-alpha.2"
64
62
  },
65
63
  "files": [
66
64
  "lib/index.js",