@sqlrooms/room-store 0.28.0-rc.0 → 0.28.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.md CHANGED
@@ -1,164 +1,124 @@
1
- This package provides the core state management for SQLRooms using [Zustand](https://github.com/pmndrs/zustand). It is designed to be extensible, allowing you to build custom room experiences by creating and composing state "slices".
1
+ Low-level state management primitives for SQLRooms, built on Zustand.
2
+
3
+ Use this package when you want to build custom room state from scratch.
4
+ If you want DuckDB + layout + room shell out of the box, use `@sqlrooms/room-shell`.
2
5
 
3
6
  ## Installation
4
7
 
5
8
  ```bash
6
- npm install @sqlrooms/room-store @sqlrooms/room-config zod zustand
9
+ npm install @sqlrooms/room-store
7
10
  ```
8
11
 
9
- ## Core Concepts
10
-
11
- ### RoomStore
12
-
13
- The `RoomStore` is a Zustand store that holds the entire state of a room. It is created by calling `createRoomStore` with a function that composes one or more slice creators.
14
-
15
- ### RoomState
16
-
17
- The `RoomState` is the object that defines the shape of the store. It includes state from the base room shell slice and any additional slices you add:
12
+ ## What this package provides
18
13
 
19
- - `room.config`: This holds the configuration of the room that is persisted. This is defined by a `zod` schema, often extending the `BaseRoomConfig` from `@sqlrooms/room-config`.
20
- - `room`: This holds the client-side state of the room, such as task progress, and provides actions for interacting with the room.
21
- - `db`: DuckDB database state and methods
22
- - `layout`: Layout configuration and panel definitions
14
+ - `createRoomStore()` and `createRoomStoreCreator()`
15
+ - base lifecycle slice: `createBaseRoomSlice()`
16
+ - generic slice helper: `createSlice()`
17
+ - React context/hooks: `RoomStateProvider`, `useBaseRoomStore`, `useRoomStoreApi`
18
+ - persistence helpers: `persistSliceConfigs()`, `createPersistHelpers()`
23
19
 
24
- ### Slices
20
+ ## Quick start
25
21
 
26
- A slice is a piece of the room's state and its associated actions. You can create your own slices to add custom functionality to your room. The framework provides `createRoomShellSlice` to create the base slice with core room functionality. You combine this with your own slices inside the `createRoomStore` composer function.
27
-
28
- ## Basic Usage
29
-
30
- Here's an example of how to create a room store with a custom feature slice.
31
-
32
- ```typescript
22
+ ```tsx
33
23
  import {
24
+ BaseRoomStoreState,
25
+ createBaseRoomSlice,
34
26
  createRoomStore,
35
- createRoomShellSlice,
36
- RoomShellSliceState,
27
+ createSlice,
28
+ type StateCreator,
37
29
  } from '@sqlrooms/room-store';
38
- import {StateCreator} from 'zustand';
39
30
 
40
- // 1. Define the state and actions for your custom feature slice.
41
- export interface MyFeatureSlice {
42
- activeChartId: string | null;
43
- setActiveChartId: (id: string | null) => void;
31
+ type CounterSliceState = {
32
+ counter: {
33
+ value: number;
34
+ increment: () => void;
35
+ };
36
+ };
37
+
38
+ function createCounterSlice(): StateCreator<CounterSliceState> {
39
+ return createSlice<CounterSliceState>((set, get) => ({
40
+ counter: {
41
+ value: 0,
42
+ increment: () =>
43
+ set((state) => ({
44
+ counter: {
45
+ ...state.counter,
46
+ value: get().counter.value + 1,
47
+ },
48
+ })),
49
+ },
50
+ }));
44
51
  }
45
52
 
46
- // 2. Create your custom slice.
47
- export const createMyFeatureSlice: StateCreator<MyFeatureSlice> = (set) => ({
48
- activeChartId: null,
49
- setActiveChartId: (id) => set({activeChartId: id}),
50
- });
51
-
52
- // 3. Define the full state of your room, combining the base RoomShellSliceState
53
- // with your custom slice's state.
54
- export type MyRoomState = RoomShellSliceState & MyFeatureSlice;
53
+ type RoomState = BaseRoomStoreState & CounterSliceState;
55
54
 
56
- // 4. Create the room store by composing the base slice and your custom slice.
57
- export const {roomStore, useRoomStore} = createRoomStore<MyRoomState>(
55
+ export const {roomStore, useRoomStore} = createRoomStore<RoomState>(
58
56
  (set, get, store) => ({
59
- ...createRoomShellSlice({
60
- config: {
61
- // You can provide initial values for your config here
62
- title: 'My First Room',
63
- dataSources: [],
64
- },
65
- layout: {
66
- config: {
67
- // Layout configuration
68
- },
69
- panels: {
70
- // Panel definitions
71
- },
72
- },
73
- })(set, get, store),
74
-
75
- // Add your custom slice to the store
76
- ...createMyFeatureSlice(set, get, store),
57
+ ...createBaseRoomSlice()(set, get, store),
58
+ ...createCounterSlice()(set, get, store),
77
59
  }),
78
60
  );
79
-
80
- export {roomStore, useRoomStore};
81
61
  ```
82
62
 
83
- ## Providing the Store
84
-
85
- To make the store available to your React components, you need to use the `RoomStateProvider` component at the root of your application.
63
+ ## React integration
86
64
 
87
65
  ```tsx
88
66
  import {RoomStateProvider} from '@sqlrooms/room-store';
89
- import {roomStore} from './my-room-store';
67
+ import {roomStore} from './store';
90
68
 
91
- function App() {
69
+ export function App() {
92
70
  return (
93
71
  <RoomStateProvider roomStore={roomStore}>
94
- {/* Your room components go here */}
72
+ <Dashboard />
95
73
  </RoomStateProvider>
96
74
  );
97
75
  }
98
76
  ```
99
77
 
100
- ## Accessing the Store in Components
101
-
102
- You can use the `useRoomStore` hook returned by `createRoomStore` to access the room's state and actions from any component.
103
-
104
78
  ```tsx
105
- import {useRoomStore} from './my-room-store';
79
+ import {useRoomStore} from './store';
80
+ import {Button} from '@sqlrooms/ui';
106
81
 
107
- function RoomTitle() {
108
- const title = useRoomStore((state) => state.room.config.title);
109
- const activeChartId = useRoomStore((state) => state.activeChartId);
110
- const setActiveChartId = useRoomStore((state) => state.setActiveChartId);
82
+ function Dashboard() {
83
+ const value = useRoomStore((state) => state.counter.value);
84
+ const increment = useRoomStore((state) => state.counter.increment);
111
85
 
112
- return (
113
- <div>
114
- <h1>{title}</h1>
115
- <p>Active Chart: {activeChartId || 'None'}</p>
116
- <button onClick={() => setActiveChartId('chart-123')}>
117
- Activate Chart
118
- </button>
119
- </div>
120
- );
86
+ return <Button onClick={increment}>Count: {value}</Button>;
121
87
  }
122
88
  ```
123
89
 
124
- ## Imperative Access
125
-
126
- Use selectors in render paths, and use store API methods for event handlers, timers, and other imperative code.
90
+ ## Imperative access
127
91
 
128
- `useRoomStoreApi()` is non-reactive. It returns the raw `StoreApi` from context and does not subscribe to state changes, so components using it will not rerender on every store update. For reactive reads that should drive rerenders, use `useRoomStore((state) => ...)` selectors.
92
+ Use `roomStore.getState()` for non-reactive code (events, timers, async jobs).
129
93
 
130
- ### Module-level imperative access
94
+ ```ts
95
+ import {roomStore} from './store';
131
96
 
132
- ```tsx
133
- import {roomStore, useRoomStore} from './my-room-store';
134
-
135
- async function runAnalysis() {
136
- const sessionId = roomStore.getState().ai.config.currentSessionId;
137
- if (sessionId) {
138
- await useRoomStore.getState().ai.startAnalysis(sessionId);
139
- }
97
+ export function incrementLater() {
98
+ setTimeout(() => {
99
+ roomStore.getState().counter.increment();
100
+ }, 500);
140
101
  }
141
102
  ```
142
103
 
143
- ### Context-based imperative access inside components
104
+ Inside components, `useRoomStoreApi()` gives you the raw store API:
144
105
 
145
106
  ```tsx
146
107
  import {useRoomStoreApi} from '@sqlrooms/room-store';
108
+ import {Button} from '@sqlrooms/ui';
147
109
 
148
- function StartButton() {
110
+ function ResetButton() {
149
111
  const store = useRoomStoreApi();
150
-
151
112
  return (
152
- <button
153
- onClick={async () => {
154
- const sessionId = store.getState().ai.config.currentSessionId;
155
- if (sessionId) {
156
- await store.getState().ai.startAnalysis(sessionId);
157
- }
113
+ <Button
114
+ onClick={() => {
115
+ // Example: imperative read from store
116
+ const current = store.getState().room.initialized;
117
+ console.log('initialized', current);
158
118
  }}
159
119
  >
160
- Start
161
- </button>
120
+ Inspect store
121
+ </Button>
162
122
  );
163
123
  }
164
124
  ```
@@ -0,0 +1,43 @@
1
+ import { StoreApi } from 'zustand';
2
+ import { BaseRoomStoreState } from './BaseRoomStore';
3
+ import { RoomCommandDescriptor, RoomCommandInvocationOptions, RoomCommandListOptions, RoomCommandPortableSchema, RoomCommandResult } from './CommandSlice';
4
+ export type CommandCliAdapterOptions = {
5
+ defaultActor?: string;
6
+ defaultTraceId?: string;
7
+ defaultMetadata?: Record<string, unknown>;
8
+ };
9
+ export type CommandCliAdapter = {
10
+ listCommands: (options?: Omit<RoomCommandListOptions, 'surface'>) => RoomCommandDescriptor[];
11
+ executeCommand: (commandId: string, input?: unknown, invocation?: Omit<RoomCommandInvocationOptions, 'surface'>) => Promise<RoomCommandResult>;
12
+ };
13
+ export type CommandMcpToolDescriptor = {
14
+ name: string;
15
+ commandId: string;
16
+ title: string;
17
+ description?: string;
18
+ inputSchema?: RoomCommandPortableSchema;
19
+ annotations?: {
20
+ readOnlyHint?: boolean;
21
+ idempotentHint?: boolean;
22
+ destructiveHint?: boolean;
23
+ requiresConfirmation?: boolean;
24
+ };
25
+ };
26
+ export type CommandMcpAdapterOptions = {
27
+ toolNamePrefix?: string;
28
+ includeInvisible?: boolean;
29
+ includeDisabled?: boolean;
30
+ includeInputSchema?: boolean;
31
+ mapToolName?: (commandId: string) => string;
32
+ defaultActor?: string;
33
+ defaultTraceId?: string;
34
+ defaultMetadata?: Record<string, unknown>;
35
+ };
36
+ export type CommandMcpAdapter = {
37
+ listTools: () => CommandMcpToolDescriptor[];
38
+ resolveCommandId: (toolName: string) => string | undefined;
39
+ callTool: (toolName: string, input?: unknown, invocation?: Omit<RoomCommandInvocationOptions, 'surface'>) => Promise<RoomCommandResult>;
40
+ };
41
+ export declare function createCommandCliAdapter<RS extends BaseRoomStoreState>(store: StoreApi<RS>, options?: CommandCliAdapterOptions): CommandCliAdapter;
42
+ export declare function createCommandMcpAdapter<RS extends BaseRoomStoreState>(store: StoreApi<RS>, options?: CommandMcpAdapterOptions): CommandMcpAdapter;
43
+ //# sourceMappingURL=CommandAdapters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommandAdapters.d.ts","sourceRoot":"","sources":["../src/CommandAdapters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,SAAS,CAAC;AACjC,OAAO,EAAC,kBAAkB,EAAC,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAEL,qBAAqB,EACrB,4BAA4B,EAC5B,sBAAsB,EACtB,yBAAyB,EACzB,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,wBAAwB,GAAG;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,YAAY,EAAE,CACZ,OAAO,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,SAAS,CAAC,KAC9C,qBAAqB,EAAE,CAAC;IAC7B,cAAc,EAAE,CACd,SAAS,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,OAAO,EACf,UAAU,CAAC,EAAE,IAAI,CAAC,4BAA4B,EAAE,SAAS,CAAC,KACvD,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,yBAAyB,CAAC;IACxC,WAAW,CAAC,EAAE;QACZ,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,oBAAoB,CAAC,EAAE,OAAO,CAAC;KAChC,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,EAAE,MAAM,wBAAwB,EAAE,CAAC;IAC5C,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAC3D,QAAQ,EAAE,CACR,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,OAAO,EACf,UAAU,CAAC,EAAE,IAAI,CAAC,4BAA4B,EAAE,SAAS,CAAC,KACvD,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACjC,CAAC;AAIF,wBAAgB,uBAAuB,CAAC,EAAE,SAAS,kBAAkB,EACnE,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC,EACnB,OAAO,CAAC,EAAE,wBAAwB,GACjC,iBAAiB,CAiCnB;AAED,wBAAgB,uBAAuB,CAAC,EAAE,SAAS,kBAAkB,EACnE,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC,EACnB,OAAO,CAAC,EAAE,wBAAwB,GACjC,iBAAiB,CA2EnB"}
@@ -0,0 +1,107 @@
1
+ import { hasCommandSliceState, } from './CommandSlice';
2
+ const DEFAULT_MCP_TOOL_PREFIX = 'command.';
3
+ export function createCommandCliAdapter(store, options) {
4
+ return {
5
+ listCommands: (listOptions) => {
6
+ const state = store.getState();
7
+ if (!hasCommandSliceState(state)) {
8
+ return [];
9
+ }
10
+ return state.commands.listCommands({
11
+ ...listOptions,
12
+ surface: 'cli',
13
+ actor: listOptions?.actor ?? options?.defaultActor,
14
+ traceId: listOptions?.traceId ?? options?.defaultTraceId,
15
+ metadata: listOptions?.metadata ?? options?.defaultMetadata,
16
+ });
17
+ },
18
+ executeCommand: async (commandId, input, invocation) => {
19
+ const state = store.getState();
20
+ if (!hasCommandSliceState(state)) {
21
+ return {
22
+ success: false,
23
+ commandId,
24
+ code: 'command-registry-unavailable',
25
+ error: 'Command registry is not available.',
26
+ };
27
+ }
28
+ return await state.commands.invokeCommand(commandId, input, {
29
+ surface: 'cli',
30
+ actor: invocation?.actor ?? options?.defaultActor,
31
+ traceId: invocation?.traceId ?? options?.defaultTraceId,
32
+ metadata: invocation?.metadata ?? options?.defaultMetadata,
33
+ });
34
+ },
35
+ };
36
+ }
37
+ export function createCommandMcpAdapter(store, options) {
38
+ const toolNamePrefix = options?.toolNamePrefix ?? DEFAULT_MCP_TOOL_PREFIX;
39
+ const toolNameFromCommandId = options?.mapToolName ??
40
+ ((commandId) => `${toolNamePrefix}${sanitizeToolName(commandId)}`);
41
+ const listDescriptors = () => {
42
+ const state = store.getState();
43
+ if (!hasCommandSliceState(state)) {
44
+ return [];
45
+ }
46
+ return state.commands.listCommands({
47
+ surface: 'mcp',
48
+ includeInvisible: options?.includeInvisible ?? false,
49
+ includeDisabled: options?.includeDisabled ?? false,
50
+ includeInputSchema: options?.includeInputSchema ?? true,
51
+ actor: options?.defaultActor,
52
+ traceId: options?.defaultTraceId,
53
+ metadata: options?.defaultMetadata,
54
+ });
55
+ };
56
+ const listTools = () => listDescriptors().map((descriptor) => ({
57
+ name: toolNameFromCommandId(descriptor.id),
58
+ commandId: descriptor.id,
59
+ title: descriptor.name,
60
+ description: descriptor.description,
61
+ inputSchema: descriptor.inputSchema,
62
+ annotations: {
63
+ readOnlyHint: descriptor.readOnly,
64
+ idempotentHint: descriptor.idempotent,
65
+ destructiveHint: descriptor.riskLevel === 'high',
66
+ requiresConfirmation: descriptor.requiresConfirmation,
67
+ },
68
+ }));
69
+ const resolveCommandId = (toolName) => {
70
+ const tools = listTools();
71
+ return tools.find((tool) => tool.name === toolName)?.commandId;
72
+ };
73
+ return {
74
+ listTools,
75
+ resolveCommandId,
76
+ callTool: async (toolName, input, invocation) => {
77
+ const commandId = resolveCommandId(toolName);
78
+ if (!commandId) {
79
+ return {
80
+ success: false,
81
+ commandId: toolName,
82
+ code: 'command-tool-not-found',
83
+ error: `Unknown command tool "${toolName}".`,
84
+ };
85
+ }
86
+ const state = store.getState();
87
+ if (!hasCommandSliceState(state)) {
88
+ return {
89
+ success: false,
90
+ commandId,
91
+ code: 'command-registry-unavailable',
92
+ error: 'Command registry is not available.',
93
+ };
94
+ }
95
+ return await state.commands.invokeCommand(commandId, input, {
96
+ surface: 'mcp',
97
+ actor: invocation?.actor ?? options?.defaultActor,
98
+ traceId: invocation?.traceId ?? options?.defaultTraceId,
99
+ metadata: invocation?.metadata ?? options?.defaultMetadata,
100
+ });
101
+ },
102
+ };
103
+ }
104
+ function sanitizeToolName(commandId) {
105
+ return commandId.replace(/[^a-zA-Z0-9._-]/g, '_');
106
+ }
107
+ //# sourceMappingURL=CommandAdapters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommandAdapters.js","sourceRoot":"","sources":["../src/CommandAdapters.ts"],"names":[],"mappings":"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","sourcesContent":["import {StoreApi} from 'zustand';\nimport {BaseRoomStoreState} from './BaseRoomStore';\nimport {\n hasCommandSliceState,\n RoomCommandDescriptor,\n RoomCommandInvocationOptions,\n RoomCommandListOptions,\n RoomCommandPortableSchema,\n RoomCommandResult,\n} from './CommandSlice';\n\nexport type CommandCliAdapterOptions = {\n defaultActor?: string;\n defaultTraceId?: string;\n defaultMetadata?: Record<string, unknown>;\n};\n\nexport type CommandCliAdapter = {\n listCommands: (\n options?: Omit<RoomCommandListOptions, 'surface'>,\n ) => RoomCommandDescriptor[];\n executeCommand: (\n commandId: string,\n input?: unknown,\n invocation?: Omit<RoomCommandInvocationOptions, 'surface'>,\n ) => Promise<RoomCommandResult>;\n};\n\nexport type CommandMcpToolDescriptor = {\n name: string;\n commandId: string;\n title: string;\n description?: string;\n inputSchema?: RoomCommandPortableSchema;\n annotations?: {\n readOnlyHint?: boolean;\n idempotentHint?: boolean;\n destructiveHint?: boolean;\n requiresConfirmation?: boolean;\n };\n};\n\nexport type CommandMcpAdapterOptions = {\n toolNamePrefix?: string;\n includeInvisible?: boolean;\n includeDisabled?: boolean;\n includeInputSchema?: boolean;\n mapToolName?: (commandId: string) => string;\n defaultActor?: string;\n defaultTraceId?: string;\n defaultMetadata?: Record<string, unknown>;\n};\n\nexport type CommandMcpAdapter = {\n listTools: () => CommandMcpToolDescriptor[];\n resolveCommandId: (toolName: string) => string | undefined;\n callTool: (\n toolName: string,\n input?: unknown,\n invocation?: Omit<RoomCommandInvocationOptions, 'surface'>,\n ) => Promise<RoomCommandResult>;\n};\n\nconst DEFAULT_MCP_TOOL_PREFIX = 'command.';\n\nexport function createCommandCliAdapter<RS extends BaseRoomStoreState>(\n store: StoreApi<RS>,\n options?: CommandCliAdapterOptions,\n): CommandCliAdapter {\n return {\n listCommands: (listOptions) => {\n const state = store.getState();\n if (!hasCommandSliceState(state)) {\n return [];\n }\n return state.commands.listCommands({\n ...listOptions,\n surface: 'cli',\n actor: listOptions?.actor ?? options?.defaultActor,\n traceId: listOptions?.traceId ?? options?.defaultTraceId,\n metadata: listOptions?.metadata ?? options?.defaultMetadata,\n });\n },\n executeCommand: async (commandId, input, invocation) => {\n const state = store.getState();\n if (!hasCommandSliceState(state)) {\n return {\n success: false,\n commandId,\n code: 'command-registry-unavailable',\n error: 'Command registry is not available.',\n };\n }\n return await state.commands.invokeCommand(commandId, input, {\n surface: 'cli',\n actor: invocation?.actor ?? options?.defaultActor,\n traceId: invocation?.traceId ?? options?.defaultTraceId,\n metadata: invocation?.metadata ?? options?.defaultMetadata,\n });\n },\n };\n}\n\nexport function createCommandMcpAdapter<RS extends BaseRoomStoreState>(\n store: StoreApi<RS>,\n options?: CommandMcpAdapterOptions,\n): CommandMcpAdapter {\n const toolNamePrefix = options?.toolNamePrefix ?? DEFAULT_MCP_TOOL_PREFIX;\n\n const toolNameFromCommandId =\n options?.mapToolName ??\n ((commandId: string) => `${toolNamePrefix}${sanitizeToolName(commandId)}`);\n\n const listDescriptors = () => {\n const state = store.getState();\n if (!hasCommandSliceState(state)) {\n return [] as RoomCommandDescriptor[];\n }\n return state.commands.listCommands({\n surface: 'mcp',\n includeInvisible: options?.includeInvisible ?? false,\n includeDisabled: options?.includeDisabled ?? false,\n includeInputSchema: options?.includeInputSchema ?? true,\n actor: options?.defaultActor,\n traceId: options?.defaultTraceId,\n metadata: options?.defaultMetadata,\n });\n };\n\n const listTools = (): CommandMcpToolDescriptor[] =>\n listDescriptors().map((descriptor) => ({\n name: toolNameFromCommandId(descriptor.id),\n commandId: descriptor.id,\n title: descriptor.name,\n description: descriptor.description,\n inputSchema: descriptor.inputSchema,\n annotations: {\n readOnlyHint: descriptor.readOnly,\n idempotentHint: descriptor.idempotent,\n destructiveHint: descriptor.riskLevel === 'high',\n requiresConfirmation: descriptor.requiresConfirmation,\n },\n }));\n\n const resolveCommandId = (toolName: string): string | undefined => {\n const tools = listTools();\n return tools.find((tool) => tool.name === toolName)?.commandId;\n };\n\n return {\n listTools,\n resolveCommandId,\n callTool: async (toolName, input, invocation) => {\n const commandId = resolveCommandId(toolName);\n if (!commandId) {\n return {\n success: false,\n commandId: toolName,\n code: 'command-tool-not-found',\n error: `Unknown command tool \"${toolName}\".`,\n };\n }\n\n const state = store.getState();\n if (!hasCommandSliceState(state)) {\n return {\n success: false,\n commandId,\n code: 'command-registry-unavailable',\n error: 'Command registry is not available.',\n };\n }\n\n return await state.commands.invokeCommand(commandId, input, {\n surface: 'mcp',\n actor: invocation?.actor ?? options?.defaultActor,\n traceId: invocation?.traceId ?? options?.defaultTraceId,\n metadata: invocation?.metadata ?? options?.defaultMetadata,\n });\n },\n };\n}\n\nfunction sanitizeToolName(commandId: string): string {\n return commandId.replace(/[^a-zA-Z0-9._-]/g, '_');\n}\n"]}
@@ -0,0 +1,131 @@
1
+ import type { ComponentType } from 'react';
2
+ import { ZodType } from 'zod';
3
+ import { StoreApi } from 'zustand';
4
+ import { BaseRoomStoreState, StateCreator } from './BaseRoomStore';
5
+ import type { RoomCommandPortableSchema } from './RoomCommandPortableSchema';
6
+ export type { RoomCommandPortableSchema } from './RoomCommandPortableSchema';
7
+ export type RoomCommandSurface = 'palette' | 'ai' | 'cli' | 'mcp' | 'api' | 'unknown';
8
+ export type RoomCommandInvocation = {
9
+ surface: RoomCommandSurface;
10
+ actor?: string;
11
+ traceId?: string;
12
+ metadata?: Record<string, unknown>;
13
+ };
14
+ export type RoomCommandInvocationOptions = Partial<RoomCommandInvocation>;
15
+ export type RoomCommandExecutionContext<RS extends BaseRoomStoreState = BaseRoomStoreState> = {
16
+ store: StoreApi<RS>;
17
+ getState: () => RS;
18
+ invocation: RoomCommandInvocation;
19
+ };
20
+ export type RoomCommandPredicate<RS extends BaseRoomStoreState = BaseRoomStoreState> = (context: RoomCommandExecutionContext<RS>) => boolean;
21
+ export type RoomCommandInputComponentProps = {
22
+ commandId: string;
23
+ commandName: string;
24
+ isSubmitting: boolean;
25
+ error?: string;
26
+ onSubmit: (input: unknown) => void | Promise<void>;
27
+ onCancel: () => void;
28
+ };
29
+ export type RoomCommandInputComponent = ComponentType<RoomCommandInputComponentProps>;
30
+ export type RoomCommandRiskLevel = 'low' | 'medium' | 'high';
31
+ export type RoomCommandPolicyMetadata = {
32
+ readOnly?: boolean;
33
+ idempotent?: boolean;
34
+ riskLevel?: RoomCommandRiskLevel;
35
+ requiresConfirmation?: boolean;
36
+ };
37
+ export type RoomCommandUiMetadata = {
38
+ shortcut?: string;
39
+ inputComponent?: RoomCommandInputComponent;
40
+ hidden?: boolean;
41
+ };
42
+ export type RoomCommandResult<TData = unknown> = {
43
+ success: boolean;
44
+ commandId: string;
45
+ message?: string;
46
+ code?: string;
47
+ data?: TData;
48
+ error?: string;
49
+ };
50
+ export type RoomCommandExecuteOutput<TData = unknown> = RoomCommandResult<TData> | TData | void;
51
+ export type RoomCommand<RS extends BaseRoomStoreState = BaseRoomStoreState> = {
52
+ id: string;
53
+ name: string;
54
+ description?: string;
55
+ group?: string;
56
+ keywords?: string[];
57
+ inputSchema?: ZodType<unknown>;
58
+ inputDescription?: string;
59
+ validateInput?: (input: unknown, context: RoomCommandExecutionContext<RS>) => void | Promise<void>;
60
+ execute: (context: RoomCommandExecutionContext<RS>, input?: unknown) => RoomCommandExecuteOutput | Promise<RoomCommandExecuteOutput>;
61
+ isVisible?: RoomCommandPredicate<RS>;
62
+ isEnabled?: RoomCommandPredicate<RS>;
63
+ metadata?: RoomCommandPolicyMetadata;
64
+ ui?: RoomCommandUiMetadata;
65
+ /** @deprecated Use ui?.shortcut */
66
+ shortcut?: string;
67
+ /** @deprecated Use ui?.inputComponent */
68
+ inputComponent?: RoomCommandInputComponent;
69
+ /** @deprecated Use metadata?.readOnly */
70
+ readOnly?: boolean;
71
+ /** @deprecated Use metadata?.idempotent */
72
+ idempotent?: boolean;
73
+ /** @deprecated Use metadata?.riskLevel */
74
+ riskLevel?: RoomCommandRiskLevel;
75
+ /** @deprecated Use metadata?.requiresConfirmation */
76
+ requiresConfirmation?: boolean;
77
+ };
78
+ export type RegisteredRoomCommand<RS extends BaseRoomStoreState = BaseRoomStoreState> = RoomCommand<RS> & {
79
+ owner: string;
80
+ };
81
+ export type RoomCommandDescriptor = {
82
+ id: string;
83
+ owner: string;
84
+ name: string;
85
+ description?: string;
86
+ group?: string;
87
+ keywords?: string[];
88
+ enabled: boolean;
89
+ visible: boolean;
90
+ requiresInput: boolean;
91
+ inputDescription?: string;
92
+ inputSchema?: RoomCommandPortableSchema;
93
+ shortcut?: string;
94
+ readOnly: boolean;
95
+ idempotent: boolean;
96
+ riskLevel: RoomCommandRiskLevel;
97
+ requiresConfirmation: boolean;
98
+ };
99
+ export type RoomCommandListOptions = RoomCommandInvocationOptions & {
100
+ includeInvisible?: boolean;
101
+ includeDisabled?: boolean;
102
+ includeInputSchema?: boolean;
103
+ };
104
+ export type CommandSliceState<RS extends BaseRoomStoreState = BaseRoomStoreState> = {
105
+ commands: {
106
+ registry: Record<string, RegisteredRoomCommand<RS>>;
107
+ ownerToCommandIds: Record<string, string[]>;
108
+ registerCommand: (owner: string, command: RoomCommand<RS>) => void;
109
+ registerCommands: (owner: string, commands: RoomCommand<RS>[]) => void;
110
+ unregisterCommand: (commandId: string) => void;
111
+ unregisterCommands: (owner: string) => void;
112
+ getCommand: (commandId: string) => RegisteredRoomCommand<RS> | undefined;
113
+ listCommands: (options?: RoomCommandListOptions) => RoomCommandDescriptor[];
114
+ invokeCommand: (commandId: string, input?: unknown, invocation?: RoomCommandInvocationOptions) => Promise<RoomCommandResult>;
115
+ executeCommand: (commandId: string, input?: unknown, invocation?: RoomCommandInvocationOptions) => Promise<void>;
116
+ };
117
+ };
118
+ export declare function createCommandSlice<RS extends BaseRoomStoreState = BaseRoomStoreState>(): StateCreator<CommandSliceState<RS>>;
119
+ export declare function createRoomCommandExecutionContext<RS extends BaseRoomStoreState>(store: StoreApi<RS>, invocation?: RoomCommandInvocationOptions): RoomCommandExecutionContext<RS>;
120
+ export declare function hasCommandSliceState(state: unknown): state is BaseRoomStoreState & CommandSliceState;
121
+ export declare function registerCommandsForOwner<RS extends BaseRoomStoreState>(store: StoreApi<RS>, owner: string, commands: RoomCommand<RS>[]): void;
122
+ export declare function unregisterCommandsForOwner<RS extends BaseRoomStoreState>(store: StoreApi<RS>, owner: string): void;
123
+ export declare function listCommandsFromStore<RS extends BaseRoomStoreState>(store: StoreApi<RS>, options?: RoomCommandListOptions): RoomCommandDescriptor[];
124
+ export declare function invokeCommandFromStore<RS extends BaseRoomStoreState>(store: StoreApi<RS>, commandId: string, input?: unknown, invocation?: RoomCommandInvocationOptions): Promise<RoomCommandResult>;
125
+ export declare function validateCommandInput<RS extends BaseRoomStoreState>(command: RoomCommand<RS>, input: unknown, context: RoomCommandExecutionContext<RS>): Promise<unknown>;
126
+ export declare function doesCommandRequireInput(command: Pick<RoomCommand, 'inputSchema'>): boolean;
127
+ export declare function getCommandShortcut(command: Pick<RoomCommand, 'ui' | 'shortcut'>): string | undefined;
128
+ export declare function getCommandInputComponent(command: Pick<RoomCommand, 'ui' | 'inputComponent'>): RoomCommandInputComponent | undefined;
129
+ export declare function resolveCommandPolicyMetadata(command: Pick<RoomCommand, 'metadata' | 'readOnly' | 'idempotent' | 'riskLevel' | 'requiresConfirmation'>): Required<RoomCommandPolicyMetadata>;
130
+ export declare function exportCommandInputSchema(schema: ZodType<unknown> | undefined): RoomCommandPortableSchema | undefined;
131
+ //# sourceMappingURL=CommandSlice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommandSlice.d.ts","sourceRoot":"","sources":["../src/CommandSlice.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,344 @@
1
+ import { produce } from 'immer';
2
+ import { createSlice } from './BaseRoomStore';
3
+ import { toPortableSchema } from './toPortableSchema';
4
+ const DEFAULT_COMMAND_OWNER = 'global';
5
+ const DEFAULT_COMMAND_SURFACE = 'unknown';
6
+ export function createCommandSlice() {
7
+ return createSlice((set, get, store) => ({
8
+ commands: {
9
+ registry: {},
10
+ ownerToCommandIds: {},
11
+ registerCommand: (owner, command) => get().commands.registerCommands(owner, [command]),
12
+ registerCommands: (owner, commands) => {
13
+ const normalizedOwner = normalizeOwner(owner);
14
+ set((state) => produce(state, (draft) => {
15
+ const previousIds = draft.commands.ownerToCommandIds[normalizedOwner] ?? [];
16
+ for (const previousId of previousIds) {
17
+ delete draft.commands.registry[previousId];
18
+ }
19
+ const nextIds = new Set();
20
+ for (const command of commands) {
21
+ if (!command.id) {
22
+ continue;
23
+ }
24
+ const existingCommand = draft.commands.registry[command.id];
25
+ if (existingCommand &&
26
+ existingCommand.owner !== normalizedOwner) {
27
+ removeCommandIdFromOwner(draft.commands.ownerToCommandIds, existingCommand.owner, command.id);
28
+ }
29
+ draft.commands.registry[command.id] = {
30
+ ...command,
31
+ owner: normalizedOwner,
32
+ };
33
+ nextIds.add(command.id);
34
+ }
35
+ if (nextIds.size === 0) {
36
+ delete draft.commands.ownerToCommandIds[normalizedOwner];
37
+ return;
38
+ }
39
+ draft.commands.ownerToCommandIds[normalizedOwner] =
40
+ Array.from(nextIds);
41
+ }));
42
+ },
43
+ unregisterCommand: (commandId) => {
44
+ const existingCommand = get().commands.registry[commandId];
45
+ if (!existingCommand) {
46
+ return;
47
+ }
48
+ set((state) => produce(state, (draft) => {
49
+ delete draft.commands.registry[commandId];
50
+ removeCommandIdFromOwner(draft.commands.ownerToCommandIds, existingCommand.owner, commandId);
51
+ }));
52
+ },
53
+ unregisterCommands: (owner) => {
54
+ const normalizedOwner = normalizeOwner(owner);
55
+ set((state) => produce(state, (draft) => {
56
+ const commandIds = draft.commands.ownerToCommandIds[normalizedOwner] ?? [];
57
+ for (const commandId of commandIds) {
58
+ delete draft.commands.registry[commandId];
59
+ }
60
+ delete draft.commands.ownerToCommandIds[normalizedOwner];
61
+ }));
62
+ },
63
+ getCommand: (commandId) => get().commands.registry[commandId],
64
+ listCommands: (options) => {
65
+ const invocation = normalizeInvocation(options);
66
+ const context = createRoomCommandExecutionContext(store, invocation);
67
+ const includeInvisible = options?.includeInvisible ?? false;
68
+ const includeDisabled = options?.includeDisabled ?? true;
69
+ const includeInputSchema = options?.includeInputSchema ?? true;
70
+ const descriptors = Object.values(get().commands.registry)
71
+ .map((command) => createCommandDescriptor(command, context, includeInputSchema))
72
+ .filter((descriptor) => includeInvisible ? true : descriptor.visible)
73
+ .filter((descriptor) => includeDisabled ? true : descriptor.enabled);
74
+ descriptors.sort((first, second) => {
75
+ const firstGroup = first.group ?? '';
76
+ const secondGroup = second.group ?? '';
77
+ if (firstGroup !== secondGroup) {
78
+ return firstGroup.localeCompare(secondGroup);
79
+ }
80
+ return first.name.localeCompare(second.name);
81
+ });
82
+ return descriptors;
83
+ },
84
+ invokeCommand: async (commandId, input, invocationOptions) => {
85
+ const command = get().commands.registry[commandId];
86
+ if (!command) {
87
+ return {
88
+ success: false,
89
+ commandId,
90
+ code: 'command-not-found',
91
+ error: `Unknown command "${commandId}".`,
92
+ };
93
+ }
94
+ const invocation = normalizeInvocation(invocationOptions);
95
+ const executionContext = createRoomCommandExecutionContext(store, invocation);
96
+ if (!resolveCommandEnabled(command, executionContext)) {
97
+ return {
98
+ success: false,
99
+ commandId: command.id,
100
+ code: 'command-disabled',
101
+ error: `Command "${command.name}" is currently disabled.`,
102
+ };
103
+ }
104
+ try {
105
+ const validatedInput = await validateCommandInput(command, input, executionContext);
106
+ const rawResult = await command.execute(executionContext, validatedInput);
107
+ return normalizeCommandExecuteResult(command.id, rawResult);
108
+ }
109
+ catch (error) {
110
+ get().room.captureException(error);
111
+ return {
112
+ success: false,
113
+ commandId: command.id,
114
+ code: 'command-execution-error',
115
+ error: toErrorMessage(error),
116
+ };
117
+ }
118
+ },
119
+ executeCommand: async (commandId, input, invocation) => {
120
+ const result = await get().commands.invokeCommand(commandId, input, invocation);
121
+ if (!result.success) {
122
+ throw new Error(result.error ??
123
+ result.message ??
124
+ `Failed to execute ${commandId}`);
125
+ }
126
+ },
127
+ },
128
+ }));
129
+ }
130
+ export function createRoomCommandExecutionContext(store, invocation) {
131
+ return {
132
+ store,
133
+ getState: () => store.getState(),
134
+ invocation: normalizeInvocation(invocation),
135
+ };
136
+ }
137
+ export function hasCommandSliceState(state) {
138
+ if (typeof state !== 'object' || state === null || !('commands' in state)) {
139
+ return false;
140
+ }
141
+ const commands = state.commands;
142
+ if (typeof commands !== 'object' || commands === null) {
143
+ return false;
144
+ }
145
+ return ('registerCommands' in commands &&
146
+ typeof commands.registerCommands === 'function' &&
147
+ 'unregisterCommands' in commands &&
148
+ typeof commands.unregisterCommands === 'function' &&
149
+ 'listCommands' in commands &&
150
+ typeof commands.listCommands === 'function' &&
151
+ 'invokeCommand' in commands &&
152
+ typeof commands.invokeCommand === 'function' &&
153
+ 'executeCommand' in commands &&
154
+ typeof commands.executeCommand === 'function');
155
+ }
156
+ export function registerCommandsForOwner(store, owner, commands) {
157
+ const state = store.getState();
158
+ if (!hasCommandSliceState(state)) {
159
+ return;
160
+ }
161
+ state.commands.registerCommands(owner, commands);
162
+ }
163
+ export function unregisterCommandsForOwner(store, owner) {
164
+ const state = store.getState();
165
+ if (!hasCommandSliceState(state)) {
166
+ return;
167
+ }
168
+ state.commands.unregisterCommands(owner);
169
+ }
170
+ export function listCommandsFromStore(store, options) {
171
+ const state = store.getState();
172
+ if (!hasCommandSliceState(state)) {
173
+ return [];
174
+ }
175
+ return state.commands.listCommands(options);
176
+ }
177
+ export async function invokeCommandFromStore(store, commandId, input, invocation) {
178
+ const state = store.getState();
179
+ if (!hasCommandSliceState(state)) {
180
+ return {
181
+ success: false,
182
+ commandId,
183
+ code: 'command-registry-unavailable',
184
+ error: 'Command registry is not available.',
185
+ };
186
+ }
187
+ return await state.commands.invokeCommand(commandId, input, invocation);
188
+ }
189
+ export async function validateCommandInput(command, input, context) {
190
+ const parsedInput = command.inputSchema
191
+ ? parseCommandInput(command.inputSchema, input)
192
+ : input;
193
+ if (command.validateInput) {
194
+ await command.validateInput(parsedInput, context);
195
+ }
196
+ return parsedInput;
197
+ }
198
+ export function doesCommandRequireInput(command) {
199
+ if (!command.inputSchema) {
200
+ return false;
201
+ }
202
+ return !command.inputSchema.safeParse(undefined).success;
203
+ }
204
+ export function getCommandShortcut(command) {
205
+ return command.ui?.shortcut ?? command.shortcut;
206
+ }
207
+ export function getCommandInputComponent(command) {
208
+ return command.ui?.inputComponent ?? command.inputComponent;
209
+ }
210
+ export function resolveCommandPolicyMetadata(command) {
211
+ return {
212
+ readOnly: command.metadata?.readOnly ?? command.readOnly ?? false,
213
+ idempotent: command.metadata?.idempotent ?? command.idempotent ?? false,
214
+ riskLevel: command.metadata?.riskLevel ?? command.riskLevel ?? 'medium',
215
+ requiresConfirmation: command.metadata?.requiresConfirmation ??
216
+ command.requiresConfirmation ??
217
+ false,
218
+ };
219
+ }
220
+ export function exportCommandInputSchema(schema) {
221
+ if (!schema) {
222
+ return undefined;
223
+ }
224
+ return toPortableSchema(schema);
225
+ }
226
+ function createCommandDescriptor(command, context, includeInputSchema) {
227
+ const metadata = resolveCommandPolicyMetadata(command);
228
+ return {
229
+ id: command.id,
230
+ owner: command.owner,
231
+ name: command.name,
232
+ description: command.description,
233
+ group: command.group,
234
+ keywords: command.keywords,
235
+ visible: resolveCommandVisibility(command, context),
236
+ enabled: resolveCommandEnabled(command, context),
237
+ requiresInput: doesCommandRequireInput(command),
238
+ inputDescription: command.inputDescription,
239
+ inputSchema: includeInputSchema
240
+ ? exportCommandInputSchema(command.inputSchema)
241
+ : undefined,
242
+ shortcut: getCommandShortcut(command),
243
+ ...metadata,
244
+ };
245
+ }
246
+ function normalizeCommandExecuteResult(commandId, rawResult) {
247
+ if (isRoomCommandResult(rawResult)) {
248
+ return {
249
+ ...rawResult,
250
+ commandId: rawResult.commandId || commandId,
251
+ };
252
+ }
253
+ return {
254
+ success: true,
255
+ commandId,
256
+ ...(rawResult !== undefined ? { data: rawResult } : {}),
257
+ };
258
+ }
259
+ function isRoomCommandResult(value) {
260
+ return (typeof value === 'object' &&
261
+ value !== null &&
262
+ 'success' in value &&
263
+ typeof value.success === 'boolean' &&
264
+ 'commandId' in value);
265
+ }
266
+ function removeCommandIdFromOwner(ownerToCommandIds, owner, commandId) {
267
+ const ownerCommandIds = ownerToCommandIds[owner];
268
+ if (!ownerCommandIds) {
269
+ return;
270
+ }
271
+ const filteredIds = ownerCommandIds.filter((id) => id !== commandId);
272
+ if (filteredIds.length === 0) {
273
+ delete ownerToCommandIds[owner];
274
+ return;
275
+ }
276
+ ownerToCommandIds[owner] = filteredIds;
277
+ }
278
+ function normalizeOwner(owner) {
279
+ const trimmed = owner.trim();
280
+ if (trimmed.length > 0) {
281
+ return trimmed;
282
+ }
283
+ return DEFAULT_COMMAND_OWNER;
284
+ }
285
+ function normalizeInvocation(invocation) {
286
+ return {
287
+ surface: invocation?.surface ?? DEFAULT_COMMAND_SURFACE,
288
+ actor: invocation?.actor,
289
+ traceId: invocation?.traceId,
290
+ metadata: invocation?.metadata,
291
+ };
292
+ }
293
+ function resolveCommandVisibility(command, context) {
294
+ if (command.ui?.hidden) {
295
+ return false;
296
+ }
297
+ if (!command.isVisible) {
298
+ return true;
299
+ }
300
+ try {
301
+ return command.isVisible(context);
302
+ }
303
+ catch (error) {
304
+ context.getState().room.captureException(error);
305
+ return false;
306
+ }
307
+ }
308
+ function resolveCommandEnabled(command, context) {
309
+ if (!command.isEnabled) {
310
+ return true;
311
+ }
312
+ try {
313
+ return command.isEnabled(context);
314
+ }
315
+ catch (error) {
316
+ context.getState().room.captureException(error);
317
+ return false;
318
+ }
319
+ }
320
+ function parseCommandInput(schema, input) {
321
+ const parsedResult = schema.safeParse(input);
322
+ if (parsedResult.success) {
323
+ return parsedResult.data;
324
+ }
325
+ throw new Error(formatCommandInputValidationError(parsedResult.error));
326
+ }
327
+ function formatCommandInputValidationError(error) {
328
+ const message = error.issues
329
+ .map((issue) => {
330
+ const path = issue.path.length > 0 ? issue.path.join('.') : 'input';
331
+ return `${path}: ${issue.message}`;
332
+ })
333
+ .join('; ');
334
+ return message.length > 0
335
+ ? `Invalid command input: ${message}`
336
+ : 'Invalid command input.';
337
+ }
338
+ function toErrorMessage(error) {
339
+ if (error instanceof Error) {
340
+ return error.message;
341
+ }
342
+ return String(error);
343
+ }
344
+ //# sourceMappingURL=CommandSlice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommandSlice.js","sourceRoot":"","sources":["../src/CommandSlice.ts"],"names":[],"mappings":"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","sourcesContent":["import {produce} from 'immer';\nimport type {ComponentType} from 'react';\nimport {z, ZodType} from 'zod';\nimport {StoreApi} from 'zustand';\nimport {BaseRoomStoreState, createSlice, StateCreator} from './BaseRoomStore';\nimport type {RoomCommandPortableSchema} from './RoomCommandPortableSchema';\nimport {toPortableSchema} from './toPortableSchema';\n\nexport type {RoomCommandPortableSchema} from './RoomCommandPortableSchema';\n\nconst DEFAULT_COMMAND_OWNER = 'global';\nconst DEFAULT_COMMAND_SURFACE: RoomCommandSurface = 'unknown';\n\nexport type RoomCommandSurface =\n | 'palette'\n | 'ai'\n | 'cli'\n | 'mcp'\n | 'api'\n | 'unknown';\n\nexport type RoomCommandInvocation = {\n surface: RoomCommandSurface;\n actor?: string;\n traceId?: string;\n metadata?: Record<string, unknown>;\n};\n\nexport type RoomCommandInvocationOptions = Partial<RoomCommandInvocation>;\n\nexport type RoomCommandExecutionContext<\n RS extends BaseRoomStoreState = BaseRoomStoreState,\n> = {\n store: StoreApi<RS>;\n getState: () => RS;\n invocation: RoomCommandInvocation;\n};\n\nexport type RoomCommandPredicate<\n RS extends BaseRoomStoreState = BaseRoomStoreState,\n> = (context: RoomCommandExecutionContext<RS>) => boolean;\n\nexport type RoomCommandInputComponentProps = {\n commandId: string;\n commandName: string;\n isSubmitting: boolean;\n error?: string;\n onSubmit: (input: unknown) => void | Promise<void>;\n onCancel: () => void;\n};\n\nexport type RoomCommandInputComponent =\n ComponentType<RoomCommandInputComponentProps>;\n\nexport type RoomCommandRiskLevel = 'low' | 'medium' | 'high';\n\nexport type RoomCommandPolicyMetadata = {\n readOnly?: boolean;\n idempotent?: boolean;\n riskLevel?: RoomCommandRiskLevel;\n requiresConfirmation?: boolean;\n};\n\nexport type RoomCommandUiMetadata = {\n shortcut?: string;\n inputComponent?: RoomCommandInputComponent;\n hidden?: boolean;\n};\n\nexport type RoomCommandResult<TData = unknown> = {\n success: boolean;\n commandId: string;\n message?: string;\n code?: string;\n data?: TData;\n error?: string;\n};\n\nexport type RoomCommandExecuteOutput<TData = unknown> =\n | RoomCommandResult<TData>\n | TData\n | void;\n\nexport type RoomCommand<RS extends BaseRoomStoreState = BaseRoomStoreState> = {\n id: string;\n name: string;\n description?: string;\n group?: string;\n keywords?: string[];\n inputSchema?: ZodType<unknown>;\n inputDescription?: string;\n validateInput?: (\n input: unknown,\n context: RoomCommandExecutionContext<RS>,\n ) => void | Promise<void>;\n execute: (\n context: RoomCommandExecutionContext<RS>,\n input?: unknown,\n ) => RoomCommandExecuteOutput | Promise<RoomCommandExecuteOutput>;\n isVisible?: RoomCommandPredicate<RS>;\n isEnabled?: RoomCommandPredicate<RS>;\n metadata?: RoomCommandPolicyMetadata;\n ui?: RoomCommandUiMetadata;\n /** @deprecated Use ui?.shortcut */\n shortcut?: string;\n /** @deprecated Use ui?.inputComponent */\n inputComponent?: RoomCommandInputComponent;\n /** @deprecated Use metadata?.readOnly */\n readOnly?: boolean;\n /** @deprecated Use metadata?.idempotent */\n idempotent?: boolean;\n /** @deprecated Use metadata?.riskLevel */\n riskLevel?: RoomCommandRiskLevel;\n /** @deprecated Use metadata?.requiresConfirmation */\n requiresConfirmation?: boolean;\n};\n\nexport type RegisteredRoomCommand<\n RS extends BaseRoomStoreState = BaseRoomStoreState,\n> = RoomCommand<RS> & {\n owner: string;\n};\n\nexport type RoomCommandDescriptor = {\n id: string;\n owner: string;\n name: string;\n description?: string;\n group?: string;\n keywords?: string[];\n enabled: boolean;\n visible: boolean;\n requiresInput: boolean;\n inputDescription?: string;\n inputSchema?: RoomCommandPortableSchema;\n shortcut?: string;\n readOnly: boolean;\n idempotent: boolean;\n riskLevel: RoomCommandRiskLevel;\n requiresConfirmation: boolean;\n};\n\nexport type RoomCommandListOptions = RoomCommandInvocationOptions & {\n includeInvisible?: boolean;\n includeDisabled?: boolean;\n includeInputSchema?: boolean;\n};\n\nexport type CommandSliceState<\n RS extends BaseRoomStoreState = BaseRoomStoreState,\n> = {\n commands: {\n registry: Record<string, RegisteredRoomCommand<RS>>;\n ownerToCommandIds: Record<string, string[]>;\n registerCommand: (owner: string, command: RoomCommand<RS>) => void;\n registerCommands: (owner: string, commands: RoomCommand<RS>[]) => void;\n unregisterCommand: (commandId: string) => void;\n unregisterCommands: (owner: string) => void;\n getCommand: (commandId: string) => RegisteredRoomCommand<RS> | undefined;\n listCommands: (options?: RoomCommandListOptions) => RoomCommandDescriptor[];\n invokeCommand: (\n commandId: string,\n input?: unknown,\n invocation?: RoomCommandInvocationOptions,\n ) => Promise<RoomCommandResult>;\n executeCommand: (\n commandId: string,\n input?: unknown,\n invocation?: RoomCommandInvocationOptions,\n ) => Promise<void>;\n };\n};\n\nexport function createCommandSlice<\n RS extends BaseRoomStoreState = BaseRoomStoreState,\n>(): StateCreator<CommandSliceState<RS>> {\n return createSlice<CommandSliceState<RS>, RS & CommandSliceState<RS>>(\n (set, get, store) => ({\n commands: {\n registry: {},\n ownerToCommandIds: {},\n registerCommand: (owner, command) =>\n get().commands.registerCommands(owner, [command]),\n registerCommands: (owner, commands) => {\n const normalizedOwner = normalizeOwner(owner);\n set((state) =>\n produce(state, (draft) => {\n const previousIds =\n draft.commands.ownerToCommandIds[normalizedOwner] ?? [];\n for (const previousId of previousIds) {\n delete draft.commands.registry[previousId];\n }\n\n const nextIds = new Set<string>();\n for (const command of commands) {\n if (!command.id) {\n continue;\n }\n\n const existingCommand = draft.commands.registry[command.id];\n if (\n existingCommand &&\n existingCommand.owner !== normalizedOwner\n ) {\n removeCommandIdFromOwner(\n draft.commands.ownerToCommandIds,\n existingCommand.owner,\n command.id,\n );\n }\n\n draft.commands.registry[command.id] = {\n ...command,\n owner: normalizedOwner,\n };\n nextIds.add(command.id);\n }\n\n if (nextIds.size === 0) {\n delete draft.commands.ownerToCommandIds[normalizedOwner];\n return;\n }\n\n draft.commands.ownerToCommandIds[normalizedOwner] =\n Array.from(nextIds);\n }),\n );\n },\n unregisterCommand: (commandId) => {\n const existingCommand = get().commands.registry[commandId];\n if (!existingCommand) {\n return;\n }\n set((state) =>\n produce(state, (draft) => {\n delete draft.commands.registry[commandId];\n removeCommandIdFromOwner(\n draft.commands.ownerToCommandIds,\n existingCommand.owner,\n commandId,\n );\n }),\n );\n },\n unregisterCommands: (owner) => {\n const normalizedOwner = normalizeOwner(owner);\n set((state) =>\n produce(state, (draft) => {\n const commandIds =\n draft.commands.ownerToCommandIds[normalizedOwner] ?? [];\n for (const commandId of commandIds) {\n delete draft.commands.registry[commandId];\n }\n delete draft.commands.ownerToCommandIds[normalizedOwner];\n }),\n );\n },\n getCommand: (commandId) => get().commands.registry[commandId],\n listCommands: (options) => {\n const invocation = normalizeInvocation(options);\n const context = createRoomCommandExecutionContext(\n store as StoreApi<RS>,\n invocation,\n );\n const includeInvisible = options?.includeInvisible ?? false;\n const includeDisabled = options?.includeDisabled ?? true;\n const includeInputSchema = options?.includeInputSchema ?? true;\n\n const descriptors = Object.values(get().commands.registry)\n .map((command) =>\n createCommandDescriptor(command, context, includeInputSchema),\n )\n .filter((descriptor) =>\n includeInvisible ? true : descriptor.visible,\n )\n .filter((descriptor) =>\n includeDisabled ? true : descriptor.enabled,\n );\n\n descriptors.sort((first, second) => {\n const firstGroup = first.group ?? '';\n const secondGroup = second.group ?? '';\n if (firstGroup !== secondGroup) {\n return firstGroup.localeCompare(secondGroup);\n }\n return first.name.localeCompare(second.name);\n });\n return descriptors;\n },\n invokeCommand: async (commandId, input, invocationOptions) => {\n const command = get().commands.registry[commandId];\n if (!command) {\n return {\n success: false,\n commandId,\n code: 'command-not-found',\n error: `Unknown command \"${commandId}\".`,\n };\n }\n\n const invocation = normalizeInvocation(invocationOptions);\n const executionContext = createRoomCommandExecutionContext(\n store as StoreApi<RS>,\n invocation,\n );\n\n if (!resolveCommandEnabled(command, executionContext)) {\n return {\n success: false,\n commandId: command.id,\n code: 'command-disabled',\n error: `Command \"${command.name}\" is currently disabled.`,\n };\n }\n\n try {\n const validatedInput = await validateCommandInput(\n command,\n input,\n executionContext,\n );\n const rawResult = await command.execute(\n executionContext,\n validatedInput,\n );\n return normalizeCommandExecuteResult(command.id, rawResult);\n } catch (error) {\n get().room.captureException(error);\n return {\n success: false,\n commandId: command.id,\n code: 'command-execution-error',\n error: toErrorMessage(error),\n };\n }\n },\n executeCommand: async (commandId, input, invocation) => {\n const result = await get().commands.invokeCommand(\n commandId,\n input,\n invocation,\n );\n if (!result.success) {\n throw new Error(\n result.error ??\n result.message ??\n `Failed to execute ${commandId}`,\n );\n }\n },\n },\n }),\n );\n}\n\nexport function createRoomCommandExecutionContext<\n RS extends BaseRoomStoreState,\n>(\n store: StoreApi<RS>,\n invocation?: RoomCommandInvocationOptions,\n): RoomCommandExecutionContext<RS> {\n return {\n store,\n getState: () => store.getState(),\n invocation: normalizeInvocation(invocation),\n };\n}\n\nexport function hasCommandSliceState(\n state: unknown,\n): state is BaseRoomStoreState & CommandSliceState {\n if (typeof state !== 'object' || state === null || !('commands' in state)) {\n return false;\n }\n\n const commands = state.commands;\n if (typeof commands !== 'object' || commands === null) {\n return false;\n }\n\n return (\n 'registerCommands' in commands &&\n typeof commands.registerCommands === 'function' &&\n 'unregisterCommands' in commands &&\n typeof commands.unregisterCommands === 'function' &&\n 'listCommands' in commands &&\n typeof commands.listCommands === 'function' &&\n 'invokeCommand' in commands &&\n typeof commands.invokeCommand === 'function' &&\n 'executeCommand' in commands &&\n typeof commands.executeCommand === 'function'\n );\n}\n\nexport function registerCommandsForOwner<RS extends BaseRoomStoreState>(\n store: StoreApi<RS>,\n owner: string,\n commands: RoomCommand<RS>[],\n): void {\n const state = store.getState();\n if (!hasCommandSliceState(state)) {\n return;\n }\n state.commands.registerCommands(\n owner,\n commands as unknown as RoomCommand<BaseRoomStoreState>[],\n );\n}\n\nexport function unregisterCommandsForOwner<RS extends BaseRoomStoreState>(\n store: StoreApi<RS>,\n owner: string,\n): void {\n const state = store.getState();\n if (!hasCommandSliceState(state)) {\n return;\n }\n state.commands.unregisterCommands(owner);\n}\n\nexport function listCommandsFromStore<RS extends BaseRoomStoreState>(\n store: StoreApi<RS>,\n options?: RoomCommandListOptions,\n): RoomCommandDescriptor[] {\n const state = store.getState();\n if (!hasCommandSliceState(state)) {\n return [];\n }\n return state.commands.listCommands(options);\n}\n\nexport async function invokeCommandFromStore<RS extends BaseRoomStoreState>(\n store: StoreApi<RS>,\n commandId: string,\n input?: unknown,\n invocation?: RoomCommandInvocationOptions,\n): Promise<RoomCommandResult> {\n const state = store.getState();\n if (!hasCommandSliceState(state)) {\n return {\n success: false,\n commandId,\n code: 'command-registry-unavailable',\n error: 'Command registry is not available.',\n };\n }\n return await state.commands.invokeCommand(commandId, input, invocation);\n}\n\nexport async function validateCommandInput<RS extends BaseRoomStoreState>(\n command: RoomCommand<RS>,\n input: unknown,\n context: RoomCommandExecutionContext<RS>,\n): Promise<unknown> {\n const parsedInput = command.inputSchema\n ? parseCommandInput(command.inputSchema, input)\n : input;\n\n if (command.validateInput) {\n await command.validateInput(parsedInput, context);\n }\n return parsedInput;\n}\n\nexport function doesCommandRequireInput(\n command: Pick<RoomCommand, 'inputSchema'>,\n): boolean {\n if (!command.inputSchema) {\n return false;\n }\n return !command.inputSchema.safeParse(undefined).success;\n}\n\nexport function getCommandShortcut(\n command: Pick<RoomCommand, 'ui' | 'shortcut'>,\n): string | undefined {\n return command.ui?.shortcut ?? command.shortcut;\n}\n\nexport function getCommandInputComponent(\n command: Pick<RoomCommand, 'ui' | 'inputComponent'>,\n): RoomCommandInputComponent | undefined {\n return command.ui?.inputComponent ?? command.inputComponent;\n}\n\nexport function resolveCommandPolicyMetadata(\n command: Pick<\n RoomCommand,\n | 'metadata'\n | 'readOnly'\n | 'idempotent'\n | 'riskLevel'\n | 'requiresConfirmation'\n >,\n): Required<RoomCommandPolicyMetadata> {\n return {\n readOnly: command.metadata?.readOnly ?? command.readOnly ?? false,\n idempotent: command.metadata?.idempotent ?? command.idempotent ?? false,\n riskLevel: command.metadata?.riskLevel ?? command.riskLevel ?? 'medium',\n requiresConfirmation:\n command.metadata?.requiresConfirmation ??\n command.requiresConfirmation ??\n false,\n };\n}\n\nexport function exportCommandInputSchema(\n schema: ZodType<unknown> | undefined,\n): RoomCommandPortableSchema | undefined {\n if (!schema) {\n return undefined;\n }\n return toPortableSchema(schema);\n}\n\nfunction createCommandDescriptor<RS extends BaseRoomStoreState>(\n command: RegisteredRoomCommand<RS>,\n context: RoomCommandExecutionContext<RS>,\n includeInputSchema: boolean,\n): RoomCommandDescriptor {\n const metadata = resolveCommandPolicyMetadata(command);\n return {\n id: command.id,\n owner: command.owner,\n name: command.name,\n description: command.description,\n group: command.group,\n keywords: command.keywords,\n visible: resolveCommandVisibility(command, context),\n enabled: resolveCommandEnabled(command, context),\n requiresInput: doesCommandRequireInput(command),\n inputDescription: command.inputDescription,\n inputSchema: includeInputSchema\n ? exportCommandInputSchema(command.inputSchema)\n : undefined,\n shortcut: getCommandShortcut(command),\n ...metadata,\n };\n}\n\nfunction normalizeCommandExecuteResult(\n commandId: string,\n rawResult: RoomCommandExecuteOutput,\n): RoomCommandResult {\n if (isRoomCommandResult(rawResult)) {\n return {\n ...rawResult,\n commandId: rawResult.commandId || commandId,\n };\n }\n\n return {\n success: true,\n commandId,\n ...(rawResult !== undefined ? {data: rawResult} : {}),\n };\n}\n\nfunction isRoomCommandResult(value: unknown): value is RoomCommandResult {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'success' in value &&\n typeof value.success === 'boolean' &&\n 'commandId' in value\n );\n}\n\nfunction removeCommandIdFromOwner(\n ownerToCommandIds: Record<string, string[]>,\n owner: string,\n commandId: string,\n): void {\n const ownerCommandIds = ownerToCommandIds[owner];\n if (!ownerCommandIds) {\n return;\n }\n\n const filteredIds = ownerCommandIds.filter((id) => id !== commandId);\n if (filteredIds.length === 0) {\n delete ownerToCommandIds[owner];\n return;\n }\n ownerToCommandIds[owner] = filteredIds;\n}\n\nfunction normalizeOwner(owner: string): string {\n const trimmed = owner.trim();\n if (trimmed.length > 0) {\n return trimmed;\n }\n return DEFAULT_COMMAND_OWNER;\n}\n\nfunction normalizeInvocation(\n invocation?: RoomCommandInvocationOptions,\n): RoomCommandInvocation {\n return {\n surface: invocation?.surface ?? DEFAULT_COMMAND_SURFACE,\n actor: invocation?.actor,\n traceId: invocation?.traceId,\n metadata: invocation?.metadata,\n };\n}\n\nfunction resolveCommandVisibility<RS extends BaseRoomStoreState>(\n command: RoomCommand<RS>,\n context: RoomCommandExecutionContext<RS>,\n): boolean {\n if (command.ui?.hidden) {\n return false;\n }\n if (!command.isVisible) {\n return true;\n }\n try {\n return command.isVisible(context);\n } catch (error) {\n context.getState().room.captureException(error);\n return false;\n }\n}\n\nfunction resolveCommandEnabled<RS extends BaseRoomStoreState>(\n command: RoomCommand<RS>,\n context: RoomCommandExecutionContext<RS>,\n): boolean {\n if (!command.isEnabled) {\n return true;\n }\n try {\n return command.isEnabled(context);\n } catch (error) {\n context.getState().room.captureException(error);\n return false;\n }\n}\n\nfunction parseCommandInput(schema: ZodType<unknown>, input: unknown): unknown {\n const parsedResult = schema.safeParse(input);\n if (parsedResult.success) {\n return parsedResult.data;\n }\n throw new Error(formatCommandInputValidationError(parsedResult.error));\n}\n\nfunction formatCommandInputValidationError(error: z.ZodError): string {\n const message = error.issues\n .map((issue) => {\n const path = issue.path.length > 0 ? issue.path.join('.') : 'input';\n return `${path}: ${issue.message}`;\n })\n .join('; ');\n return message.length > 0\n ? `Invalid command input: ${message}`\n : 'Invalid command input.';\n}\n\nfunction toErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n return String(error);\n}\n"]}
@@ -0,0 +1,17 @@
1
+ export type RoomCommandPortableSchema = {
2
+ type?: string;
3
+ $schema?: string;
4
+ title?: string;
5
+ description?: string;
6
+ enum?: unknown[];
7
+ const?: unknown;
8
+ default?: unknown;
9
+ format?: string;
10
+ properties?: Record<string, RoomCommandPortableSchema>;
11
+ required?: string[];
12
+ items?: RoomCommandPortableSchema;
13
+ anyOf?: RoomCommandPortableSchema[];
14
+ additionalProperties?: boolean | RoomCommandPortableSchema;
15
+ [key: string]: unknown;
16
+ };
17
+ //# sourceMappingURL=RoomCommandPortableSchema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoomCommandPortableSchema.d.ts","sourceRoot":"","sources":["../src/RoomCommandPortableSchema.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;IACvD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,yBAAyB,CAAC;IAClC,KAAK,CAAC,EAAE,yBAAyB,EAAE,CAAC;IACpC,oBAAoB,CAAC,EAAE,OAAO,GAAG,yBAAyB,CAAC;IAC3D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=RoomCommandPortableSchema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoomCommandPortableSchema.js","sourceRoot":"","sources":["../src/RoomCommandPortableSchema.ts"],"names":[],"mappings":"","sourcesContent":["export type RoomCommandPortableSchema = {\n type?: string;\n $schema?: string;\n title?: string;\n description?: string;\n enum?: unknown[];\n const?: unknown;\n default?: unknown;\n format?: string;\n properties?: Record<string, RoomCommandPortableSchema>;\n required?: string[];\n items?: RoomCommandPortableSchema;\n anyOf?: RoomCommandPortableSchema[];\n additionalProperties?: boolean | RoomCommandPortableSchema;\n [key: string]: unknown;\n};\n"]}
package/dist/index.d.ts CHANGED
@@ -8,5 +8,9 @@ export { createBaseRoomSlice, createBaseSlice, createSlice, createRoomSlice, cre
8
8
  export type { BaseRoomStoreState, CreateBaseRoomSliceProps, BaseRoomStore, UseRoomStore, } from './BaseRoomStore';
9
9
  export { createPersistHelpers, persistSliceConfigs, } from './createPersistHelpers';
10
10
  export type { StateCreator, StoreApi } from 'zustand';
11
+ export { createCommandSlice, createRoomCommandExecutionContext, doesCommandRequireInput, exportCommandInputSchema, getCommandInputComponent, getCommandShortcut, hasCommandSliceState, invokeCommandFromStore, listCommandsFromStore, registerCommandsForOwner, resolveCommandPolicyMetadata, unregisterCommandsForOwner, validateCommandInput, } from './CommandSlice';
12
+ export type { CommandSliceState, RoomCommandDescriptor, RoomCommandExecuteOutput, RoomCommandInvocation, RoomCommandInvocationOptions, RegisteredRoomCommand, RoomCommand, RoomCommandInputComponent, RoomCommandInputComponentProps, RoomCommandListOptions, RoomCommandPolicyMetadata, RoomCommandPortableSchema, RoomCommandResult, RoomCommandRiskLevel, RoomCommandSurface, RoomCommandUiMetadata, RoomCommandExecutionContext, RoomCommandPredicate, } from './CommandSlice';
13
+ export { createCommandCliAdapter, createCommandMcpAdapter, } from './CommandAdapters';
14
+ export type { CommandCliAdapter, CommandCliAdapterOptions, CommandMcpAdapter, CommandMcpAdapterOptions, CommandMcpToolDescriptor, } from './CommandAdapters';
11
15
  export { BaseRoomConfig, DEFAULT_ROOM_TITLE, createDefaultBaseRoomConfig, DataSourceTypes, BaseDataSource, FileDataSource, UrlDataSource, SqlQueryDataSource, DataSource, isFileDataSource, isUrlDataSource, isSqlQueryDataSource, LoadFile, StandardLoadOptions, SpatialLoadOptions, SpatialLoadFileOptions, isSpatialLoadFileOptions, StandardLoadFileOptions, LoadFileOptions, MAIN_VIEW, LayoutTypes, DEFAULT_MOSAIC_LAYOUT, createDefaultMosaicLayout, MosaicLayoutDirection, MosaicLayoutParent, isMosaicLayoutParent, MosaicLayoutNodeKey, MosaicLayoutNode, MosaicLayoutConfig, LayoutConfig, } from '@sqlrooms/room-config';
12
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAC,sBAAsB,EAAC,MAAM,qBAAqB,CAAC;AAEhE,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,WAAW,EACX,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,kBAAkB,EAClB,wBAAwB,EACxB,aAAa,EACb,YAAY,GACb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAC,YAAY,EAAE,QAAQ,EAAC,MAAM,SAAS,CAAC;AAIpD,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,2BAA2B,EAC3B,eAAe,EACf,cAAc,EACd,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,QAAQ,EACR,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,EACvB,eAAe,EACf,SAAS,EACT,WAAW,EACX,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,GACb,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAC,sBAAsB,EAAC,MAAM,qBAAqB,CAAC;AAEhE,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,WAAW,EACX,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,kBAAkB,EAClB,wBAAwB,EACxB,aAAa,EACb,YAAY,GACb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAC,YAAY,EAAE,QAAQ,EAAC,MAAM,SAAS,CAAC;AAEpD,OAAO,EACL,kBAAkB,EAClB,iCAAiC,EACjC,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,4BAA4B,EAC5B,0BAA0B,EAC1B,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,4BAA4B,EAC5B,qBAAqB,EACrB,WAAW,EACX,yBAAyB,EACzB,8BAA8B,EAC9B,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,2BAA2B,EAC3B,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,iBAAiB,EACjB,wBAAwB,EACxB,iBAAiB,EACjB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,2BAA2B,EAC3B,eAAe,EACf,cAAc,EACd,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,QAAQ,EACR,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,EACvB,eAAe,EACf,SAAS,EACT,WAAW,EACX,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,GACb,MAAM,uBAAuB,CAAC"}
package/dist/index.js CHANGED
@@ -5,6 +5,8 @@
5
5
  export { RoomStateContext, RoomStateProvider, useBaseRoomStore, useRoomStoreApi, } from './RoomStateProvider';
6
6
  export { createBaseRoomSlice, createBaseSlice, createSlice, createRoomSlice, createRoomStore, createRoomStoreCreator, isRoomSliceWithDestroy, isRoomSliceWithInitialize, } from './BaseRoomStore';
7
7
  export { createPersistHelpers, persistSliceConfigs, } from './createPersistHelpers';
8
+ export { createCommandSlice, createRoomCommandExecutionContext, doesCommandRequireInput, exportCommandInputSchema, getCommandInputComponent, getCommandShortcut, hasCommandSliceState, invokeCommandFromStore, listCommandsFromStore, registerCommandsForOwner, resolveCommandPolicyMetadata, unregisterCommandsForOwner, validateCommandInput, } from './CommandSlice';
9
+ export { createCommandCliAdapter, createCommandMcpAdapter, } from './CommandAdapters';
8
10
  // Re-export from @sqlrooms/room-config
9
11
  // Values also export their corresponding types automatically (Zod pattern)
10
12
  export { BaseRoomConfig, DEFAULT_ROOM_TITLE, createDefaultBaseRoomConfig, DataSourceTypes, BaseDataSource, FileDataSource, UrlDataSource, SqlQueryDataSource, DataSource, isFileDataSource, isUrlDataSource, isSqlQueryDataSource, LoadFile, StandardLoadOptions, SpatialLoadOptions, SpatialLoadFileOptions, isSpatialLoadFileOptions, StandardLoadFileOptions, LoadFileOptions, MAIN_VIEW, LayoutTypes, DEFAULT_MOSAIC_LAYOUT, createDefaultMosaicLayout, MosaicLayoutDirection, MosaicLayoutParent, isMosaicLayoutParent, MosaicLayoutNodeKey, MosaicLayoutNode, MosaicLayoutConfig, LayoutConfig, } from '@sqlrooms/room-config';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,WAAW,EACX,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AAQzB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAGhC,uCAAuC;AACvC,2EAA2E;AAC3E,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,2BAA2B,EAC3B,eAAe,EACf,cAAc,EACd,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,QAAQ,EACR,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,EACvB,eAAe,EACf,SAAS,EACT,WAAW,EACX,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,GACb,MAAM,uBAAuB,CAAC","sourcesContent":["/**\n * {@include ../README.md}\n * @packageDocumentation\n */\n\nexport {\n RoomStateContext,\n RoomStateProvider,\n useBaseRoomStore,\n useRoomStoreApi,\n} from './RoomStateProvider';\nexport type {RoomStateProviderProps} from './RoomStateProvider';\n\nexport {\n createBaseRoomSlice,\n createBaseSlice,\n createSlice,\n createRoomSlice,\n createRoomStore,\n createRoomStoreCreator,\n isRoomSliceWithDestroy,\n isRoomSliceWithInitialize,\n} from './BaseRoomStore';\nexport type {\n BaseRoomStoreState,\n CreateBaseRoomSliceProps,\n BaseRoomStore,\n UseRoomStore,\n} from './BaseRoomStore';\n\nexport {\n createPersistHelpers,\n persistSliceConfigs,\n} from './createPersistHelpers';\nexport type {StateCreator, StoreApi} from 'zustand';\n\n// Re-export from @sqlrooms/room-config\n// Values also export their corresponding types automatically (Zod pattern)\nexport {\n BaseRoomConfig,\n DEFAULT_ROOM_TITLE,\n createDefaultBaseRoomConfig,\n DataSourceTypes,\n BaseDataSource,\n FileDataSource,\n UrlDataSource,\n SqlQueryDataSource,\n DataSource,\n isFileDataSource,\n isUrlDataSource,\n isSqlQueryDataSource,\n LoadFile,\n StandardLoadOptions,\n SpatialLoadOptions,\n SpatialLoadFileOptions,\n isSpatialLoadFileOptions,\n StandardLoadFileOptions,\n LoadFileOptions,\n MAIN_VIEW,\n LayoutTypes,\n DEFAULT_MOSAIC_LAYOUT,\n createDefaultMosaicLayout,\n MosaicLayoutDirection,\n MosaicLayoutParent,\n isMosaicLayoutParent,\n MosaicLayoutNodeKey,\n MosaicLayoutNode,\n MosaicLayoutConfig,\n LayoutConfig,\n} from '@sqlrooms/room-config';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,WAAW,EACX,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AAQzB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,kBAAkB,EAClB,iCAAiC,EACjC,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,4BAA4B,EAC5B,0BAA0B,EAC1B,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AAqBxB,OAAO,EACL,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAS3B,uCAAuC;AACvC,2EAA2E;AAC3E,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,2BAA2B,EAC3B,eAAe,EACf,cAAc,EACd,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,QAAQ,EACR,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,EACvB,eAAe,EACf,SAAS,EACT,WAAW,EACX,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,GACb,MAAM,uBAAuB,CAAC","sourcesContent":["/**\n * {@include ../README.md}\n * @packageDocumentation\n */\n\nexport {\n RoomStateContext,\n RoomStateProvider,\n useBaseRoomStore,\n useRoomStoreApi,\n} from './RoomStateProvider';\nexport type {RoomStateProviderProps} from './RoomStateProvider';\n\nexport {\n createBaseRoomSlice,\n createBaseSlice,\n createSlice,\n createRoomSlice,\n createRoomStore,\n createRoomStoreCreator,\n isRoomSliceWithDestroy,\n isRoomSliceWithInitialize,\n} from './BaseRoomStore';\nexport type {\n BaseRoomStoreState,\n CreateBaseRoomSliceProps,\n BaseRoomStore,\n UseRoomStore,\n} from './BaseRoomStore';\n\nexport {\n createPersistHelpers,\n persistSliceConfigs,\n} from './createPersistHelpers';\nexport type {StateCreator, StoreApi} from 'zustand';\n\nexport {\n createCommandSlice,\n createRoomCommandExecutionContext,\n doesCommandRequireInput,\n exportCommandInputSchema,\n getCommandInputComponent,\n getCommandShortcut,\n hasCommandSliceState,\n invokeCommandFromStore,\n listCommandsFromStore,\n registerCommandsForOwner,\n resolveCommandPolicyMetadata,\n unregisterCommandsForOwner,\n validateCommandInput,\n} from './CommandSlice';\nexport type {\n CommandSliceState,\n RoomCommandDescriptor,\n RoomCommandExecuteOutput,\n RoomCommandInvocation,\n RoomCommandInvocationOptions,\n RegisteredRoomCommand,\n RoomCommand,\n RoomCommandInputComponent,\n RoomCommandInputComponentProps,\n RoomCommandListOptions,\n RoomCommandPolicyMetadata,\n RoomCommandPortableSchema,\n RoomCommandResult,\n RoomCommandRiskLevel,\n RoomCommandSurface,\n RoomCommandUiMetadata,\n RoomCommandExecutionContext,\n RoomCommandPredicate,\n} from './CommandSlice';\nexport {\n createCommandCliAdapter,\n createCommandMcpAdapter,\n} from './CommandAdapters';\nexport type {\n CommandCliAdapter,\n CommandCliAdapterOptions,\n CommandMcpAdapter,\n CommandMcpAdapterOptions,\n CommandMcpToolDescriptor,\n} from './CommandAdapters';\n\n// Re-export from @sqlrooms/room-config\n// Values also export their corresponding types automatically (Zod pattern)\nexport {\n BaseRoomConfig,\n DEFAULT_ROOM_TITLE,\n createDefaultBaseRoomConfig,\n DataSourceTypes,\n BaseDataSource,\n FileDataSource,\n UrlDataSource,\n SqlQueryDataSource,\n DataSource,\n isFileDataSource,\n isUrlDataSource,\n isSqlQueryDataSource,\n LoadFile,\n StandardLoadOptions,\n SpatialLoadOptions,\n SpatialLoadFileOptions,\n isSpatialLoadFileOptions,\n StandardLoadFileOptions,\n LoadFileOptions,\n MAIN_VIEW,\n LayoutTypes,\n DEFAULT_MOSAIC_LAYOUT,\n createDefaultMosaicLayout,\n MosaicLayoutDirection,\n MosaicLayoutParent,\n isMosaicLayoutParent,\n MosaicLayoutNodeKey,\n MosaicLayoutNode,\n MosaicLayoutConfig,\n LayoutConfig,\n} from '@sqlrooms/room-config';\n"]}
@@ -0,0 +1,17 @@
1
+ import { ZodType } from 'zod';
2
+ import type { RoomCommandPortableSchema } from './RoomCommandPortableSchema';
3
+ /**
4
+ * Converts a Zod schema into a JSON Schema-compatible structure used by command
5
+ * descriptors and adapters.
6
+ *
7
+ * The conversion is based on `z.toJSONSchema()` so that we rely on Zod's
8
+ * maintained conversion logic instead of traversing Zod internals directly.
9
+ *
10
+ * Zod marks some types as unrepresentable in JSON Schema (for example date and
11
+ * bigint). We opt into `unrepresentable: 'any'` and then restore useful type
12
+ * hints in `override`:
13
+ * - `z.date()` -> `{type: 'string', format: 'date-time'}`
14
+ * - `z.bigint()` -> `{type: 'string', format: 'bigint'}`
15
+ */
16
+ export declare function toPortableSchema(schema: ZodType<unknown>): RoomCommandPortableSchema;
17
+ //# sourceMappingURL=toPortableSchema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toPortableSchema.d.ts","sourceRoot":"","sources":["../src/toPortableSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAI,OAAO,EAAC,MAAM,KAAK,CAAC;AAC/B,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,6BAA6B,CAAC;AAE3E;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GACvB,yBAAyB,CAe3B"}
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Converts a Zod schema into a JSON Schema-compatible structure used by command
4
+ * descriptors and adapters.
5
+ *
6
+ * The conversion is based on `z.toJSONSchema()` so that we rely on Zod's
7
+ * maintained conversion logic instead of traversing Zod internals directly.
8
+ *
9
+ * Zod marks some types as unrepresentable in JSON Schema (for example date and
10
+ * bigint). We opt into `unrepresentable: 'any'` and then restore useful type
11
+ * hints in `override`:
12
+ * - `z.date()` -> `{type: 'string', format: 'date-time'}`
13
+ * - `z.bigint()` -> `{type: 'string', format: 'bigint'}`
14
+ */
15
+ export function toPortableSchema(schema) {
16
+ return z.toJSONSchema(schema, {
17
+ unrepresentable: 'any',
18
+ override: (ctx) => {
19
+ const schemaType = ctx.zodSchema
20
+ .def?.type;
21
+ if (schemaType === 'date') {
22
+ ctx.jsonSchema.type = 'string';
23
+ ctx.jsonSchema.format = 'date-time';
24
+ }
25
+ else if (schemaType === 'bigint') {
26
+ ctx.jsonSchema.type = 'string';
27
+ ctx.jsonSchema.format = 'bigint';
28
+ }
29
+ },
30
+ });
31
+ }
32
+ //# sourceMappingURL=toPortableSchema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toPortableSchema.js","sourceRoot":"","sources":["../src/toPortableSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAU,MAAM,KAAK,CAAC;AAG/B;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAwB;IAExB,OAAO,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE;QAC5B,eAAe,EAAE,KAAK;QACtB,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE;YAChB,MAAM,UAAU,GAAI,GAAG,CAAC,SAAgD;iBACrE,GAAG,EAAE,IAAI,CAAC;YACb,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;gBAC1B,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,QAAQ,CAAC;gBAC/B,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,WAAW,CAAC;YACtC,CAAC;iBAAM,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;gBACnC,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,QAAQ,CAAC;gBAC/B,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,QAAQ,CAAC;YACnC,CAAC;QACH,CAAC;KACF,CAA8B,CAAC;AAClC,CAAC","sourcesContent":["import {z, ZodType} from 'zod';\nimport type {RoomCommandPortableSchema} from './RoomCommandPortableSchema';\n\n/**\n * Converts a Zod schema into a JSON Schema-compatible structure used by command\n * descriptors and adapters.\n *\n * The conversion is based on `z.toJSONSchema()` so that we rely on Zod's\n * maintained conversion logic instead of traversing Zod internals directly.\n *\n * Zod marks some types as unrepresentable in JSON Schema (for example date and\n * bigint). We opt into `unrepresentable: 'any'` and then restore useful type\n * hints in `override`:\n * - `z.date()` -> `{type: 'string', format: 'date-time'}`\n * - `z.bigint()` -> `{type: 'string', format: 'bigint'}`\n */\nexport function toPortableSchema(\n schema: ZodType<unknown>,\n): RoomCommandPortableSchema {\n return z.toJSONSchema(schema, {\n unrepresentable: 'any',\n override: (ctx) => {\n const schemaType = (ctx.zodSchema as unknown as {def?: {type?: string}})\n .def?.type;\n if (schemaType === 'date') {\n ctx.jsonSchema.type = 'string';\n ctx.jsonSchema.format = 'date-time';\n } else if (schemaType === 'bigint') {\n ctx.jsonSchema.type = 'string';\n ctx.jsonSchema.format = 'bigint';\n }\n },\n }) as RoomCommandPortableSchema;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sqlrooms/room-store",
3
- "version": "0.28.0-rc.0",
3
+ "version": "0.28.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/index.js",
@@ -19,7 +19,7 @@
19
19
  "access": "public"
20
20
  },
21
21
  "dependencies": {
22
- "@sqlrooms/room-config": "0.28.0-rc.0",
22
+ "@sqlrooms/room-config": "0.28.0",
23
23
  "immer": "^11.0.1",
24
24
  "zod": "^4.1.8",
25
25
  "zustand": "^5.0.8"
@@ -30,9 +30,15 @@
30
30
  "scripts": {
31
31
  "dev": "tsc -w",
32
32
  "build": "tsc",
33
+ "test": "jest",
34
+ "test:watch": "jest --watch",
33
35
  "lint": "eslint .",
34
36
  "typecheck": "tsc --noEmit",
35
37
  "typedoc": "typedoc"
36
38
  },
37
- "gitHead": "87a478edbff690e04c38cc717db8e11e844565c8"
39
+ "devDependencies": {
40
+ "@sqlrooms/preset-jest": "0.28.0",
41
+ "ts-jest": "^29.4.4"
42
+ },
43
+ "gitHead": "dcac54f8adf77240e293c93d224a0ce9fd8142a9"
38
44
  }