@trydreamstate/cli 1.0.0 → 1.1.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
@@ -22,6 +22,9 @@ export DREAMSTATE_API_URL=http://localhost:3001/api/v1
22
22
 
23
23
  dreamstate auth whoami
24
24
  dreamstate whoami --json
25
+ dreamstate workspaces list
26
+ dreamstate workspaces use <id|slug>
27
+ dreamstate packs list --workspace <id|slug>
25
28
  dreamstate packs list
26
29
  dreamstate packs get <pack_id>
27
30
  dreamstate commands search "create a workbook and add rows"
@@ -30,7 +33,9 @@ dreamstate tools search --goal "create a workbook" --limit 50 --toolset tables
30
33
  dreamstate tools run tables.workbooks.create --params '{"name":"Pipeline"}' --mode live --approved
31
34
  ```
32
35
 
33
- `login --token <ds_live_...>` checks the token looks like a `ds_live_` key, verifies it with `whoami` against the API, and only then stores it (mode `0600`) and prints the same `whoami` output. The token is never echoed, and a rejected token is not stored. `auth login` keeps `--api-key-file`, stdin and `DREAMSTATE_API_KEY`. `logout` deletes `~/.dreamstate/credentials` (or `$DREAMSTATE_CONFIG_DIR/credentials`), prints what it removed, and exits 0 even when already logged out. `--agents` accepts `codex`, `claude-code` and `cursor`, as `--agents claude-code codex cursor`, `--agents claude-code,codex` or repeated flags, for `skills install` and `skills doctor`. Node 22 or newer is required.
36
+ `login --token <ds_user_...|ds_live_...>` checks the token looks like a `ds_user_` session or `ds_live_` key, verifies it with `whoami` against the API, and only then stores it (mode `0600`) and prints the same `whoami` output. The token is never echoed, and a rejected token is not stored. `auth login` keeps `--api-key-file`, stdin and `DREAMSTATE_API_KEY`. `logout` deletes `~/.dreamstate/credentials` (or `$DREAMSTATE_CONFIG_DIR/credentials`), prints what it removed, and exits 0 even when already logged out. `--agents` accepts `codex`, `claude-code` and `cursor`, as `--agents claude-code codex cursor`, `--agents claude-code,codex` or repeated flags, for `skills install` and `skills doctor`. Node 22 or newer is required.
37
+
38
+ Credentials are stored as JSON `{"token", "workspace"}` (mode `0600`); the single-line file written by 1.0.x is still read. A `ds_user_` session belongs to you and works in every workspace you are a member of. Pick the workspace with `--workspace <id|slug>` (accepted by every command), then `DREAMSTATE_WORKSPACE`, then the stored default, in that order; the choice is sent as the `X-Dreamstate-Workspace` header. `login` stores the workspace you approved as the default. `workspaces list` shows your workspaces and marks the active one (`--json` returns the raw `whoami` envelope), and `workspaces use <id|slug>` verifies membership with `whoami` and stores the default. A `ds_live_` machine key is bound to one workspace: `workspaces use` refuses it, so run `dreamstate login` for a user session that can switch. `whoami` prints the active workspace on stderr.
34
39
 
35
40
  `login` prints approval URL plus confirmation code. Approval page shows same code, then CLI stores granted credential with mode `0600` and prints `whoami`. Default API is `https://api.trydreamstate.com/api/v1`; `DREAMSTATE_API_URL` overrides it. `whoami` and `auth whoami` are aliases. `auth whoami` prints API `registry_hash` unchanged. `packs list`, `packs get`, and `commands search` read authenticated API catalog at request time.
36
41
 
package/dist/client.d.ts CHANGED
@@ -2,6 +2,8 @@ export declare const CLI_VERSION: string;
2
2
  export interface DreamstateClientOptions {
3
3
  apiKey: string;
4
4
  baseUrl: string;
5
+ /** Sent as X-Dreamstate-Workspace so a user session can act in any workspace it belongs to. */
6
+ workspace?: string;
5
7
  requestTimeoutMs?: number;
6
8
  onVersionWarning?: (message: string) => void;
7
9
  }
@@ -22,6 +24,15 @@ export interface WhoamiResponse {
22
24
  subscription_status: string | null;
23
25
  api_base_url: string;
24
26
  mcp_endpoint_url: string;
27
+ auth_kind?: 'user_session' | 'workspace_key';
28
+ active_workspace_id?: string | null;
29
+ workspaces?: WhoamiWorkspace[];
30
+ }
31
+ export interface WhoamiWorkspace {
32
+ id: string;
33
+ name: string;
34
+ slug: string;
35
+ role: string;
25
36
  }
26
37
  export interface CapabilityRunBody {
27
38
  params: Record<string, unknown>;
@@ -82,6 +93,7 @@ export declare function claimDeviceAuthorization(baseUrl: string, state: string)
82
93
  export declare class DreamstateClient {
83
94
  private readonly apiKey;
84
95
  private readonly baseUrl;
96
+ private readonly workspace?;
85
97
  private readonly requestTimeoutMs?;
86
98
  private readonly onVersionWarning?;
87
99
  constructor(options: DreamstateClientOptions);
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -8,6 +8,12 @@ const node_crypto_1 = require("node:crypto");
8
8
  exports.CLI_VERSION = require('../package.json').version;
9
9
  exports.DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
10
10
  exports.TOOL_AND_RUN_REQUEST_TIMEOUT_MS = 60_000;
11
+ /** Server workspace refusals rewritten so the message says what to run next. */
12
+ const WORKSPACE_ERROR_MESSAGES = {
13
+ workspace_required: 'No workspace is selected. Run dreamstate workspaces list, then dreamstate workspaces use <workspace> (or pass --workspace <id|slug>).',
14
+ workspace_forbidden: 'You are not a member of that workspace. Run dreamstate workspaces list to see the workspaces you can use, then dreamstate workspaces use <workspace>.',
15
+ workspace_scoped_credential: 'This key is bound to one workspace. Run dreamstate login for a user session that can switch, or remove --workspace and DREAMSTATE_WORKSPACE.',
16
+ };
11
17
  class CliError extends Error {
12
18
  code;
13
19
  status;
@@ -132,11 +138,13 @@ async function requestPublic(baseUrl, path, init) {
132
138
  class DreamstateClient {
133
139
  apiKey;
134
140
  baseUrl;
141
+ workspace;
135
142
  requestTimeoutMs;
136
143
  onVersionWarning;
137
144
  constructor(options) {
138
145
  this.apiKey = options.apiKey;
139
146
  this.baseUrl = options.baseUrl.replace(/\/+$/, '');
147
+ this.workspace = options.workspace;
140
148
  this.requestTimeoutMs = options.requestTimeoutMs;
141
149
  this.onVersionWarning = options.onVersionWarning;
142
150
  }
@@ -210,6 +218,7 @@ class DreamstateClient {
210
218
  headers: {
211
219
  Accept: 'application/json', Authorization: `Bearer ${this.apiKey}`,
212
220
  'X-Dreamstate-Client-Version': exports.CLI_VERSION,
221
+ ...(this.workspace ? { 'X-Dreamstate-Workspace': this.workspace } : {}),
213
222
  ...(init.body ? { 'Content-Type': 'application/json' } : {}), ...init.headers,
214
223
  },
215
224
  });
@@ -231,7 +240,7 @@ class DreamstateClient {
231
240
  throw new CliError(`Dreamstate API returned invalid JSON (HTTP ${response.status})`, 'invalid_response', response.status);
232
241
  }
233
242
  if (isApiErrorBody(payload)) {
234
- throw new CliError(payload.error.message, payload.error.code, response.status, {
243
+ throw new CliError(WORKSPACE_ERROR_MESSAGES[payload.error.code] ?? payload.error.message, payload.error.code, response.status, {
235
244
  details: payload.error.details, retryAfter: retryAfter(response, payload),
236
245
  traceId: readToolEnvelopeTraceId(payload), idempotencyKey,
237
246
  ...(typeof payload.error.retryable === 'boolean' ? { retryable: payload.error.retryable } : {}),
package/dist/config.d.ts CHANGED
@@ -19,7 +19,20 @@ export declare class ApiKeyFileError extends Error {
19
19
  }
20
20
  export declare function credentialsPath(homeDirectory?: string, environment?: NodeJS.ProcessEnv): string;
21
21
  export declare function resolveApiBaseUrl(environment?: NodeJS.ProcessEnv): string;
22
+ export declare const API_KEY_PREFIXES: readonly ["ds_user_", "ds_live_"];
23
+ export declare function isDreamstateToken(value: string): boolean;
24
+ export interface StoredCredentials {
25
+ token: string;
26
+ workspace: string | null;
27
+ }
28
+ /**
29
+ * The file is JSON `{token, workspace}`. Files written by 1.0.x hold one bare
30
+ * token line; they keep working so an upgrade never logs anyone out.
31
+ */
32
+ export declare function readStoredCredentials(path: string): Promise<StoredCredentials | null>;
22
33
  export declare function resolveApiKey(environment?: NodeJS.ProcessEnv, path?: string): Promise<string>;
34
+ /** Workspace precedence: --workspace flag, then DREAMSTATE_WORKSPACE, then the stored default. */
35
+ export declare function resolveWorkspace(flag: string | undefined, environment?: NodeJS.ProcessEnv, path?: string): Promise<string | undefined>;
23
36
  export declare function readApiKeyFile(path: string): Promise<string>;
24
- export declare function storeApiKey(apiKey: string, path?: string): Promise<string>;
37
+ export declare function storeApiKey(apiKey: string, path?: string, workspace?: string | null): Promise<string>;
25
38
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,qBAAqB;gBAEtB,OAAO,SAA8C;CAIlE;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,qBAAqB;gBAEtB,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,uBAAuB;gBACxB,OAAO,EAAE,MAAM;CAC5B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,uBAAuB;gBAGlC,OAAO,SAA6E;CAKvF;AAED,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAgB,eAAe,CAC7B,aAAa,SAAY,EACzB,WAAW,GAAE,MAAM,CAAC,UAAwB,GAC3C,MAAM,CAGR;AAED,wBAAgB,iBAAiB,CAAC,WAAW,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CA+BtF;AAWD,wBAAsB,aAAa,CACjC,WAAW,GAAE,MAAM,CAAC,UAAwB,EAC5C,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAajB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBlE;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,SAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAW3F"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,qBAAqB;gBAEtB,OAAO,SAA8C;CAIlE;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,qBAAqB;gBAEtB,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,uBAAuB;gBACxB,OAAO,EAAE,MAAM;CAC5B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,uBAAuB;gBAGlC,OAAO,SAA6E;CAKvF;AAED,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAgB,eAAe,CAC7B,aAAa,SAAY,EACzB,WAAW,GAAE,MAAM,CAAC,UAAwB,GAC3C,MAAM,CAGR;AAED,wBAAgB,iBAAiB,CAAC,WAAW,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CA+BtF;AAWD,eAAO,MAAM,gBAAgB,mCAAoC,CAAC;AAElE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAoB3F;AAED,wBAAsB,aAAa,CACjC,WAAW,GAAE,MAAM,CAAC,UAAwB,EAC5C,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED,kGAAkG;AAClG,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,WAAW,GAAE,MAAM,CAAC,UAAwB,EAC5C,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAM7B;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBlE;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,SAAoB,EAAE,SAAS,GAAE,MAAM,GAAG,IAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAW5H"}
package/dist/config.js CHANGED
@@ -1,9 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ApiKeyFileError = exports.MissingApiKeyError = exports.HostPinMismatchError = exports.ApiBaseUrlError = exports.MissingApiUrlError = void 0;
3
+ exports.API_KEY_PREFIXES = exports.ApiKeyFileError = exports.MissingApiKeyError = exports.HostPinMismatchError = exports.ApiBaseUrlError = exports.MissingApiUrlError = void 0;
4
4
  exports.credentialsPath = credentialsPath;
5
5
  exports.resolveApiBaseUrl = resolveApiBaseUrl;
6
+ exports.isDreamstateToken = isDreamstateToken;
7
+ exports.readStoredCredentials = readStoredCredentials;
6
8
  exports.resolveApiKey = resolveApiKey;
9
+ exports.resolveWorkspace = resolveWorkspace;
7
10
  exports.readApiKeyFile = readApiKeyFile;
8
11
  exports.storeApiKey = storeApiKey;
9
12
  const promises_1 = require("node:fs/promises");
@@ -96,22 +99,60 @@ function isExplicitLoopbackHttpOrigin(candidate, url) {
96
99
  || /^127\.0\.0\.1:\d+$/.test(authority)
97
100
  || /^\[::1\]:\d+$/.test(authority);
98
101
  }
99
- async function resolveApiKey(environment = process.env, path) {
100
- const environmentKey = environment.DREAMSTATE_API_KEY?.trim();
101
- if (environmentKey)
102
- return environmentKey;
103
- const credentialFilePath = path ?? credentialsPath(undefined, environment);
102
+ exports.API_KEY_PREFIXES = ['ds_user_', 'ds_live_'];
103
+ function isDreamstateToken(value) {
104
+ return exports.API_KEY_PREFIXES.some((prefix) => value.startsWith(prefix) && value.length > prefix.length);
105
+ }
106
+ /**
107
+ * The file is JSON `{token, workspace}`. Files written by 1.0.x hold one bare
108
+ * token line; they keep working so an upgrade never logs anyone out.
109
+ */
110
+ async function readStoredCredentials(path) {
111
+ let raw;
104
112
  try {
105
- const storedKey = (await (0, promises_1.readFile)(credentialFilePath, 'utf8')).trim();
106
- if (storedKey)
107
- return storedKey;
113
+ raw = (await (0, promises_1.readFile)(path, 'utf8')).trim();
108
114
  }
109
115
  catch (error) {
110
- if (error.code !== 'ENOENT')
111
- throw error;
116
+ if (['ENOENT', 'ENOTDIR'].includes(error.code ?? ''))
117
+ return null;
118
+ throw error;
119
+ }
120
+ if (!raw)
121
+ return null;
122
+ if (!raw.startsWith('{'))
123
+ return { token: raw, workspace: null };
124
+ let parsed;
125
+ try {
126
+ parsed = JSON.parse(raw);
112
127
  }
128
+ catch {
129
+ throw new ApiKeyFileError(`Credentials file is not valid JSON: ${path}. Run dreamstate login again.`);
130
+ }
131
+ const record = parsed && typeof parsed === 'object' ? parsed : {};
132
+ if (typeof record.token !== 'string' || !record.token.trim())
133
+ return null;
134
+ const workspace = typeof record.workspace === 'string' && record.workspace.trim() ? record.workspace.trim() : null;
135
+ return { token: record.token.trim(), workspace };
136
+ }
137
+ async function resolveApiKey(environment = process.env, path) {
138
+ const environmentKey = environment.DREAMSTATE_API_KEY?.trim();
139
+ if (environmentKey)
140
+ return environmentKey;
141
+ const stored = await readStoredCredentials(path ?? credentialsPath(undefined, environment));
142
+ if (stored)
143
+ return stored.token;
113
144
  throw new MissingApiKeyError();
114
145
  }
146
+ /** Workspace precedence: --workspace flag, then DREAMSTATE_WORKSPACE, then the stored default. */
147
+ async function resolveWorkspace(flag, environment = process.env, path) {
148
+ const fromFlag = flag?.trim();
149
+ if (fromFlag)
150
+ return fromFlag;
151
+ const fromEnvironment = environment.DREAMSTATE_WORKSPACE?.trim();
152
+ if (fromEnvironment)
153
+ return fromEnvironment;
154
+ return (await readStoredCredentials(path ?? credentialsPath(undefined, environment)))?.workspace ?? undefined;
155
+ }
115
156
  async function readApiKeyFile(path) {
116
157
  let file;
117
158
  try {
@@ -131,14 +172,14 @@ async function readApiKeyFile(path) {
131
172
  }
132
173
  return (await (0, promises_1.readFile)(path, 'utf8')).trim();
133
174
  }
134
- async function storeApiKey(apiKey, path = credentialsPath()) {
175
+ async function storeApiKey(apiKey, path = credentialsPath(), workspace = null) {
135
176
  const normalized = apiKey.trim();
136
- if (!normalized.startsWith('ds_live_')) {
137
- throw new Error('Dreamstate API keys must start with ds_live_.');
177
+ if (!isDreamstateToken(normalized)) {
178
+ throw new Error('Dreamstate API keys must start with ds_user_ or ds_live_.');
138
179
  }
139
180
  const directory = (0, node_path_1.join)(path, '..');
140
181
  await (0, promises_1.mkdir)(directory, { recursive: true, mode: 0o700 });
141
- await (0, promises_1.writeFile)(path, `${normalized}\n`, { encoding: 'utf8', mode: 0o600 });
182
+ await (0, promises_1.writeFile)(path, `${JSON.stringify({ token: normalized, workspace })}\n`, { encoding: 'utf8', mode: 0o600 });
142
183
  await (0, promises_1.chmod)(path, 0o600);
143
184
  return path;
144
185
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { type ChildProcess } from 'node:child_process';
3
2
  import { type SkillInstallAgent } from './skillInstaller';
4
3
  export type CanonicalApiCapabilityId = string;
5
4
  export declare const CLI_EXIT: {
@@ -30,6 +29,13 @@ export type CliCommand = {
30
29
  } | {
31
30
  command: 'whoami';
32
31
  jsonOutput?: boolean;
32
+ } | {
33
+ command: 'workspaces_list';
34
+ jsonOutput?: boolean;
35
+ } | {
36
+ command: 'workspaces_use';
37
+ workspace: string;
38
+ jsonOutput?: boolean;
33
39
  } | {
34
40
  command: 'packs_list';
35
41
  jsonOutput?: boolean;
@@ -159,9 +165,20 @@ type SpawnLike = (command: string, args: readonly string[], options: {
159
165
  detached: boolean;
160
166
  stdio: 'ignore';
161
167
  shell: false;
162
- }) => Pick<ChildProcess, 'unref'>;
168
+ }) => {
169
+ unref(): void;
170
+ on?(event: 'error', listener: (error: Error) => void): unknown;
171
+ };
163
172
  export declare function openWebUrl(rawUrl: string, launch?: SpawnLike): void;
164
173
  export declare function exitCodeForError(error: unknown): number;
174
+ /**
175
+ * --workspace is global: it is lifted out of argv before any subcommand parser
176
+ * sees it, so every command accepts it without each parser declaring it.
177
+ */
178
+ export declare function extractWorkspaceFlag(argv: string[]): {
179
+ argv: string[];
180
+ workspace?: string;
181
+ };
165
182
  export declare function runCli(argv?: string[], runtime?: CliRuntime): Promise<void>;
166
183
  export {};
167
184
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ exports.toolTurnToken = toolTurnToken;
7
7
  exports.refusalEnvelope = refusalEnvelope;
8
8
  exports.openWebUrl = openWebUrl;
9
9
  exports.exitCodeForError = exitCodeForError;
10
+ exports.extractWorkspaceFlag = extractWorkspaceFlag;
10
11
  exports.runCli = runCli;
11
12
  const node_child_process_1 = require("node:child_process");
12
13
  const node_crypto_1 = require("node:crypto");
@@ -26,9 +27,11 @@ Usage:
26
27
  dreamstate --help
27
28
  dreamstate --version
28
29
  dreamstate login
29
- dreamstate login --token <ds_live_...>
30
+ dreamstate login --token <ds_user_...|ds_live_...>
30
31
  dreamstate logout
31
32
  dreamstate whoami [--json-output|--json]
33
+ dreamstate workspaces list [--json-output|--json]
34
+ dreamstate workspaces use <id|slug>
32
35
  dreamstate auth login [--api-key-file <path>]
33
36
  dreamstate auth whoami [--json-output|--json]
34
37
  dreamstate packs list [--json-output|--json]
@@ -53,7 +56,8 @@ Usage:
53
56
  dreamstate runs cancel <run_id> --json <body> [--idempotency-key <key>] [--json-output|--json]
54
57
 
55
58
  All catalog discovery reads live API records. Set DREAMSTATE_API_URL and DREAMSTATE_API_KEY.
56
- login opens browser approval; login --token stores a ds_live_ key (for SSH or remote machines) after verifying it with whoami.
59
+ login opens browser approval; login --token stores a ds_user_ session or ds_live_ key (for SSH or remote machines) after verifying it with whoami.
60
+ Global flag --workspace <id|slug> (any command) or DREAMSTATE_WORKSPACE picks the workspace for one call; workspaces use stores a default. Flag beats env beats stored. A ds_live_ key is bound to one workspace and cannot switch.
57
61
  logout deletes the stored credentials file. --agents takes space-separated, comma-separated or repeated values.
58
62
  `;
59
63
  class CliUsageError extends Error {
@@ -337,7 +341,7 @@ function parseCliArgs(argv) {
337
341
  if (values.help)
338
342
  return { command: 'help' };
339
343
  if (positionals.length)
340
- throw new CliUsageError('Usage: dreamstate login [--token <ds_live_...>]');
344
+ throw new CliUsageError('Usage: dreamstate login [--token <ds_user_...|ds_live_...>]');
341
345
  if (values.token !== undefined && values['api-key-file'])
342
346
  throw new CliUsageError('Use either --token or --api-key-file, not both.');
343
347
  return { command: 'login', ...(values.token !== undefined ? { token: values.token } : {}), ...(values['api-key-file'] ? { apiKeyFile: values['api-key-file'] } : {}), ...outputOption(values) };
@@ -356,6 +360,16 @@ function parseCliArgs(argv) {
356
360
  return { command: 'whoami', ...outputOption(values) };
357
361
  throw new CliUsageError('Usage: dreamstate whoami [--json-output]');
358
362
  }
363
+ if (group === 'workspaces') {
364
+ const { values, positionals } = (0, node_util_1.parseArgs)({ args: rest, options: { 'json-output': { type: 'boolean' }, help: { type: 'boolean', short: 'h' } }, allowPositionals: true, strict: true });
365
+ if (values.help)
366
+ return { command: 'help' };
367
+ if (positionals.length === 1 && positionals[0] === 'list')
368
+ return { command: 'workspaces_list', ...outputOption(values) };
369
+ if (positionals.length === 2 && positionals[0] === 'use' && positionals[1])
370
+ return { command: 'workspaces_use', workspace: positionals[1], ...outputOption(values) };
371
+ throw new CliUsageError('Usage: dreamstate workspaces <list|use <id|slug>>');
372
+ }
359
373
  if (group === 'auth') {
360
374
  const { values, positionals } = (0, node_util_1.parseArgs)({ args: rest, options: { 'api-key-file': { type: 'string' }, 'json-output': { type: 'boolean' } }, allowPositionals: true, strict: true });
361
375
  if (positionals.length === 1 && positionals[0] === 'login')
@@ -458,7 +472,16 @@ function openWebUrl(rawUrl, launch = node_child_process_1.spawn) {
458
472
  : process.platform === 'win32'
459
473
  ? ['rundll32', ['url.dll,FileProtocolHandler', target]]
460
474
  : ['xdg-open', [target]];
461
- launch(command, args, { detached: true, stdio: 'ignore', shell: false }).unref();
475
+ // The URL is always printed first, so a machine with no browser opener (an SSH
476
+ // box, a container) must keep going, not crash on an unhandled spawn error.
477
+ try {
478
+ const child = launch(command, args, { detached: true, stdio: 'ignore', shell: false });
479
+ child.on?.('error', () => undefined);
480
+ child.unref();
481
+ }
482
+ catch {
483
+ // Same: opening a browser is a convenience, never a requirement.
484
+ }
462
485
  }
463
486
  function resultWebUrl(value) {
464
487
  if (!value || typeof value !== 'object' || Array.isArray(value))
@@ -558,6 +581,41 @@ function deviceState() {
558
581
  function runtimeCredentialsPath(runtime) {
559
582
  return runtime.credentialsPath ?? (0, config_1.credentialsPath)(undefined, runtime.env ?? process.env);
560
583
  }
584
+ /**
585
+ * --workspace is global: it is lifted out of argv before any subcommand parser
586
+ * sees it, so every command accepts it without each parser declaring it.
587
+ */
588
+ function extractWorkspaceFlag(argv) {
589
+ const rest = [];
590
+ let workspace;
591
+ for (let index = 0; index < argv.length; index += 1) {
592
+ const argument = argv[index];
593
+ if (argument === '--workspace') {
594
+ const value = argv[index + 1];
595
+ if (value === undefined || value.startsWith('-') || !value.trim())
596
+ throw new CliUsageError('--workspace requires a workspace id or slug.');
597
+ workspace = value.trim();
598
+ index += 1;
599
+ }
600
+ else if (argument.startsWith('--workspace=')) {
601
+ workspace = argument.slice('--workspace='.length).trim();
602
+ if (!workspace)
603
+ throw new CliUsageError('--workspace requires a workspace id or slug.');
604
+ }
605
+ else {
606
+ rest.push(argument);
607
+ }
608
+ }
609
+ return { argv: rest, ...(workspace ? { workspace } : {}) };
610
+ }
611
+ function whoamiData(value) {
612
+ const data = value && typeof value === 'object' ? value.data : undefined;
613
+ return data && typeof data === 'object' ? data : {};
614
+ }
615
+ function activeWorkspace(data) {
616
+ const activeId = data.workspace_id ?? data.active_workspace_id ?? undefined;
617
+ return activeId ? data.workspaces?.find((workspace) => workspace.id === activeId) : undefined;
618
+ }
561
619
  function wait(milliseconds) {
562
620
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
563
621
  }
@@ -574,7 +632,7 @@ async function loginWithDeviceAuthorization(runtime, stdout, stderr) {
574
632
  for (;;) {
575
633
  const claim = await (0, client_1.claimDeviceAuthorization)(baseUrl, authorization.device_code);
576
634
  if (claim.status === 'ready') {
577
- await (0, config_1.storeApiKey)(claim.token, runtimeCredentialsPath(runtime));
635
+ await (0, config_1.storeApiKey)(claim.token, runtimeCredentialsPath(runtime), claim.workspace.id);
578
636
  const client = new client_1.DreamstateClient({
579
637
  baseUrl,
580
638
  apiKey: claim.token,
@@ -605,7 +663,8 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
605
663
  ignoreBrokenPipe(stdout);
606
664
  ignoreBrokenPipe(stderr);
607
665
  try {
608
- const command = parseCliArgs(argv);
666
+ const extracted = extractWorkspaceFlag(argv);
667
+ const command = parseCliArgs(extracted.argv);
609
668
  if (command.command === 'help') {
610
669
  print({ ok: true, data: { usage: USAGE }, meta: {} }, stdout, false);
611
670
  process.exitCode = exports.CLI_EXIT.SUCCESS;
@@ -637,12 +696,16 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
637
696
  }
638
697
  if (command.command === 'login' && command.token !== undefined) {
639
698
  const token = command.token.trim();
640
- if (!token.startsWith('ds_live_') || token.length <= 'ds_live_'.length)
641
- throw new CliUsageError('--token must be a Dreamstate API key starting with ds_live_.');
642
- const baseUrl = (0, config_1.resolveApiBaseUrl)(runtime.env ?? process.env);
699
+ if (!(0, config_1.isDreamstateToken)(token))
700
+ throw new CliUsageError('--token must be a Dreamstate session or API key starting with ds_user_ or ds_live_.');
701
+ const environment = runtime.env ?? process.env;
702
+ const baseUrl = (0, config_1.resolveApiBaseUrl)(environment);
703
+ // Only an explicit flag or env picks the workspace here: a stored default belongs to the previous login.
704
+ const requested = extracted.workspace ?? environment.DREAMSTATE_WORKSPACE?.trim();
643
705
  const client = new client_1.DreamstateClient({
644
706
  baseUrl,
645
707
  apiKey: token,
708
+ ...(requested ? { workspace: requested } : {}),
646
709
  requestTimeoutMs: runtime.requestTimeoutMs,
647
710
  onVersionWarning: (message) => stderr.write(`${message}\n`),
648
711
  });
@@ -655,8 +718,8 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
655
718
  if (command.command === 'login') {
656
719
  if (command.apiKeyFile || (runtime.env ?? process.env).DREAMSTATE_API_KEY || runtime.promptHidden) {
657
720
  const key = await readLoginKey(command, runtime);
658
- if (!key.startsWith('ds_live_'))
659
- throw new CliUsageError('Dreamstate API keys must start with ds_live_.');
721
+ if (!(0, config_1.isDreamstateToken)(key))
722
+ throw new CliUsageError('Dreamstate API keys must start with ds_user_ or ds_live_.');
660
723
  const path = await (0, config_1.storeApiKey)(key, runtimeCredentialsPath(runtime));
661
724
  print({ ok: true, data: { credentials_path: path }, meta: {} }, stdout, Boolean(command.jsonOutput));
662
725
  stderr.write('Run dreamstate skills install to install Dreamstate skills.\n');
@@ -673,7 +736,8 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
673
736
  const baseUrl = (0, config_1.resolveApiBaseUrl)(environment);
674
737
  const credentialFilePath = runtimeCredentialsPath(runtime);
675
738
  const apiKey = await (0, config_1.resolveApiKey)(environment, credentialFilePath);
676
- const client = new client_1.DreamstateClient({ baseUrl, apiKey, requestTimeoutMs: runtime.requestTimeoutMs });
739
+ const workspace = await (0, config_1.resolveWorkspace)(extracted.workspace, environment, credentialFilePath);
740
+ const client = new client_1.DreamstateClient({ baseUrl, apiKey, ...(workspace ? { workspace } : {}), requestTimeoutMs: runtime.requestTimeoutMs });
677
741
  await client.listSkills({ limit: 1 });
678
742
  const installers = await (0, skillInstaller_1.inspectSkillInstallers)(command.agents, runtime.homeDirectory, Boolean(command.project));
679
743
  print({ ok: true, data: { index_reachable: true, installers }, meta: {} }, stdout, Boolean(command.jsonOutput));
@@ -726,17 +790,60 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
726
790
  }
727
791
  throw error;
728
792
  }
793
+ if (command.command === 'workspaces_use' && apiKey.startsWith('ds_live_')) {
794
+ // Decided locally: a workspace key can never switch, so no request is worth making.
795
+ throw new CliUsageError('This key is bound to one workspace. Run dreamstate login for a user session that can switch.');
796
+ }
797
+ const workspace = command.command === 'workspaces_use'
798
+ ? command.workspace
799
+ : await (0, config_1.resolveWorkspace)(extracted.workspace, environment, credentialFilePath);
729
800
  const client = new client_1.DreamstateClient({
730
801
  baseUrl,
731
802
  apiKey,
803
+ ...(workspace ? { workspace } : {}),
732
804
  requestTimeoutMs: runtime.requestTimeoutMs,
733
805
  onVersionWarning: (message) => (runtime.stderr ?? process.stderr).write(`${message}\n`),
734
806
  });
735
807
  let result;
736
808
  switch (command.command) {
737
- case 'whoami':
809
+ case 'whoami': {
738
810
  result = await client.getWhoami();
811
+ if (!command.jsonOutput) {
812
+ const active = activeWorkspace(whoamiData(result));
813
+ if (active)
814
+ stderr.write(`Active workspace: ${active.name} (${active.slug})\n`);
815
+ }
739
816
  break;
817
+ }
818
+ case 'workspaces_list': {
819
+ result = await client.getWhoami();
820
+ if (!command.jsonOutput) {
821
+ const data = whoamiData(result);
822
+ const activeId = data.workspace_id ?? data.active_workspace_id ?? null;
823
+ const rows = data.workspaces ?? [];
824
+ stdout.write(rows.length
825
+ ? `${rows.map((row) => `${row.id === activeId ? '*' : ' '} ${row.slug} ${row.name} ${row.role} ${row.id}`).join('\n')}\n`
826
+ : 'No workspaces. Ask a workspace owner to invite you.\n');
827
+ process.exitCode = exports.CLI_EXIT.SUCCESS;
828
+ return;
829
+ }
830
+ break;
831
+ }
832
+ case 'workspaces_use': {
833
+ const whoami = await client.getWhoami();
834
+ const data = whoamiData(whoami);
835
+ const wanted = command.workspace.toLowerCase();
836
+ const match = data.workspaces?.find((row) => row.id.toLowerCase() === wanted || row.slug.toLowerCase() === wanted);
837
+ if (!match)
838
+ throw new CliUsageError(`You are not a member of workspace "${command.workspace}". Run dreamstate workspaces list to see the workspaces you can use.`);
839
+ const stored = await (0, config_1.readStoredCredentials)(credentialFilePath);
840
+ if (!stored)
841
+ throw new CliUsageError('workspaces use saves the default next to a stored login. Run dreamstate login or dreamstate login --token first.');
842
+ await (0, config_1.storeApiKey)(stored.token, credentialFilePath, match.id);
843
+ stderr.write(`Default workspace: ${match.name} (${match.slug})\n`);
844
+ result = { ok: true, data: { workspace: { id: match.id, name: match.name, slug: match.slug }, credentials_path: credentialFilePath }, meta: {} };
845
+ break;
846
+ }
740
847
  case 'packs_list':
741
848
  result = await client.listPacks();
742
849
  break;
@@ -766,20 +873,31 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
766
873
  // A remote id becomes a directory name; refuse traversal before any request or write.
767
874
  if (ids.some((id) => !/^[a-z0-9][a-z0-9_-]*$/i.test(id)))
768
875
  throw new CliUsageError('Dreamstate API returned an invalid skill id.');
769
- const skills = await Promise.all(ids.map(async (id) => {
876
+ // One at a time: each read comes from the workspace's private vault,
877
+ // which admits two reads at once, and fifteen in parallel failed on prod.
878
+ const skills = [];
879
+ for (const id of ids) {
770
880
  const skill = hostedSkill(await client.getSkill(id));
771
881
  if (!/^[a-z0-9][a-z0-9_-]*$/i.test(skill.id))
772
882
  throw new CliUsageError('Dreamstate API returned an invalid skill id.');
773
883
  if (skill.id !== id)
774
884
  throw new client_1.CliError('Dreamstate API returned a mismatched skill id.', 'invalid_response', 200);
775
- return skill;
776
- }));
885
+ skills.push(skill);
886
+ }
777
887
  const packs = await client.listPacks();
888
+ const whoami = await client.getWhoami();
889
+ const workspaceId = typeof whoami?.data?.workspace_id === 'string' ? whoami.data.workspace_id : 'unknown';
890
+ // Stamped into every file so a stale install is visible against the live skills.
891
+ const indexVersion = (0, node_crypto_1.createHash)('sha256')
892
+ .update(JSON.stringify(skills.map((skill) => [skill.id, skill.description, skill.body, skill.frontmatter ?? {}])))
893
+ .digest('hex').slice(0, 16);
778
894
  const installed = await (0, skillInstaller_1.installSkills)([...skills, (0, skillInstaller_1.routerSkill)(packs)], {
779
895
  agents: command.agents,
780
896
  homeDirectory: runtime.homeDirectory,
781
897
  project: Boolean(command.project),
782
898
  copy: Boolean(command.copy) || process.platform === 'win32',
899
+ workspaceId,
900
+ indexVersion,
783
901
  });
784
902
  result = { ok: true, data: { installed_files: installed.files, skill_ids: [...ids, 'router'], agents: command.agents, ...(command.project ? { lock_file: 'skills-lock.json' } : {}) }, meta: {} };
785
903
  break;
@@ -799,6 +917,8 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
799
917
  // forget it once the paid run is admitted, so every other call keeps
800
918
  // fetching a fresh turn exactly as before.
801
919
  const turns = (0, turnCache_1.turnCachePath)(credentialFilePath);
920
+ // A turn belongs to one workspace, so the workspace is part of the cache identity.
921
+ const turnKey = workspace ? `${apiKey}\n${workspace}` : apiKey;
802
922
  let warnedAboutTurnCache = false;
803
923
  const warnTurnCache = () => {
804
924
  if (warnedAboutTurnCache)
@@ -808,22 +928,22 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
808
928
  };
809
929
  const pending = command.turnToken
810
930
  ? null
811
- : await (0, turnCache_1.reusableTurnToken)(turns, baseUrl, apiKey, command.capabilityId, Date.now(), warnTurnCache);
931
+ : await (0, turnCache_1.reusableTurnToken)(turns, baseUrl, turnKey, command.capabilityId, Date.now(), warnTurnCache);
812
932
  const turnToken = command.turnToken ?? pending ?? toolTurnToken(await client.getTool(command.capabilityId));
813
933
  try {
814
934
  result = await client.runCapability(command.capabilityId, { ...command.body, tool_turn_token: turnToken }, command.idempotencyKey);
815
935
  }
816
936
  catch (error) {
817
937
  if (!command.turnToken && code(error) === 'quote_required') {
818
- await (0, turnCache_1.rememberTurnToken)(turns, baseUrl, apiKey, command.capabilityId, turnToken, Date.now(), warnTurnCache);
938
+ await (0, turnCache_1.rememberTurnToken)(turns, baseUrl, turnKey, command.capabilityId, turnToken, Date.now(), warnTurnCache);
819
939
  }
820
940
  throw error;
821
941
  }
822
942
  if (!command.turnToken) {
823
943
  if (command.body.mode === 'dry_run')
824
- await (0, turnCache_1.rememberTurnToken)(turns, baseUrl, apiKey, command.capabilityId, turnToken, Date.now(), warnTurnCache);
944
+ await (0, turnCache_1.rememberTurnToken)(turns, baseUrl, turnKey, command.capabilityId, turnToken, Date.now(), warnTurnCache);
825
945
  else if (pending)
826
- await (0, turnCache_1.forgetTurnToken)(turns, baseUrl, apiKey, command.capabilityId, warnTurnCache);
946
+ await (0, turnCache_1.forgetTurnToken)(turns, baseUrl, turnKey, command.capabilityId, warnTurnCache);
827
947
  }
828
948
  break;
829
949
  }
@@ -1,4 +1,4 @@
1
- export declare const SKILL_INSTALL_AGENTS: readonly ["codex", "claude-code", "cursor"];
1
+ export declare const SKILL_INSTALL_AGENTS: readonly ["codex", "claude-code", "cursor", "opencode", "hermes", "openclaw"];
2
2
  export type SkillInstallAgent = typeof SKILL_INSTALL_AGENTS[number];
3
3
  export interface HostedSkill {
4
4
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"skillInstaller.d.ts","sourceRoot":"","sources":["../src/skillInstaller.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,oBAAoB,6CAA8C,CAAC;AAChF,MAAM,MAAM,iBAAiB,GAAG,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAEpE,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAChD,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAKD,wBAAgB,wBAAwB,CAAC,aAAa,SAAY,EAAE,OAAO,UAAQ,EAAE,GAAG,SAAgB,GAAG,MAAM,CAEhH;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,iBAAiB,EAAE,aAAa,SAAY,EAAE,OAAO,UAAQ,EAAE,GAAG,SAAgB,GAAG,MAAM,CAKvI;AAiBD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAazH;AA8BD,wBAAsB,aAAa,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,QAAQ,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAe1N;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,OAAO,GAAG,WAAW,CAO3D;AAED,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,EAAE,aAAa,SAAY,EAAE,OAAO,UAAQ,EAAE,GAAG,SAAgB,GAAG,OAAO,CAAC,KAAK,CAAC;IAAE,KAAK,EAAE,iBAAiB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAAC,CAkC1W"}
1
+ {"version":3,"file":"skillInstaller.d.ts","sourceRoot":"","sources":["../src/skillInstaller.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,oBAAoB,+EAAgF,CAAC;AAClH,MAAM,MAAM,iBAAiB,GAAG,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAEpE,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAChD,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAKD,wBAAgB,wBAAwB,CAAC,aAAa,SAAY,EAAE,OAAO,UAAQ,EAAE,GAAG,SAAgB,GAAG,MAAM,CAEhH;AAiBD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,iBAAiB,EAAE,aAAa,SAAY,EAAE,OAAO,UAAQ,EAAE,GAAG,SAAgB,GAAG,MAAM,CAIvI;AA8BD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAczH;AA8BD,wBAAsB,aAAa,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,QAAQ,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAgB1N;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,OAAO,GAAG,WAAW,CAO3D;AAED,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,EAAE,aAAa,SAAY,EAAE,OAAO,UAAQ,EAAE,GAAG,SAAgB,GAAG,OAAO,CAAC,KAAK,CAAC;IAAE,KAAK,EAAE,iBAAiB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAAC,CAkC1W"}
@@ -46,18 +46,44 @@ const node_crypto_1 = require("node:crypto");
46
46
  const node_os_1 = require("node:os");
47
47
  const node_path_1 = require("node:path");
48
48
  const index_1 = require("./index");
49
- exports.SKILL_INSTALL_AGENTS = ['codex', 'claude-code', 'cursor'];
49
+ exports.SKILL_INSTALL_AGENTS = ['codex', 'claude-code', 'cursor', 'opencode', 'hermes', 'openclaw'];
50
50
  const allowedTools = 'Bash(dreamstate *), Bash(jq *)';
51
51
  const safeId = /^[a-z0-9][a-z0-9_-]*$/i;
52
52
  function canonicalSkillsDirectory(homeDirectory = (0, node_os_1.homedir)(), project = false, cwd = process.cwd()) {
53
53
  return project ? (0, node_path_1.join)(cwd, '.agents', 'skills') : (0, node_path_1.join)(homeDirectory, '.agents', 'skills');
54
54
  }
55
+ // One canonical copy in .agents/skills; every other agent's skills directory
56
+ // links back into it, so all agents on a machine see the same skills.
57
+ // Codex and OpenCode read .agents/skills themselves and need no link.
58
+ const AGENT_SKILL_DIRECTORIES = {
59
+ codex: null,
60
+ opencode: null,
61
+ 'claude-code': ['.claude', 'skills'],
62
+ cursor: ['.cursor', 'skills'],
63
+ hermes: ['.hermes', 'skills'],
64
+ openclaw: ['.openclaw', 'skills'],
65
+ };
66
+ // Only linked when the agent is already installed (its home folder exists), so
67
+ // installing skills never creates a folder for an agent the person does not use.
68
+ const LINK_ONLY_WHEN_INSTALLED = new Set(['hermes', 'openclaw']);
55
69
  function skillInstallDirectory(agent, homeDirectory = (0, node_os_1.homedir)(), project = false, cwd = process.cwd()) {
56
- // Codex and Cursor both read the shared .agents/skills directory; only Claude
57
- // Code needs its own directory, which links back into the shared one.
58
- if (agent !== 'claude-code')
70
+ const segments = AGENT_SKILL_DIRECTORIES[agent];
71
+ if (!segments)
59
72
  return canonicalSkillsDirectory(homeDirectory, project, cwd);
60
- return (0, node_path_1.join)(project ? cwd : homeDirectory, '.claude', 'skills');
73
+ return (0, node_path_1.join)(project ? cwd : homeDirectory, ...segments);
74
+ }
75
+ function linksIntoCanonical(agent) {
76
+ return AGENT_SKILL_DIRECTORIES[agent] !== null;
77
+ }
78
+ async function agentInstalled(agent, homeDirectory, project, cwd) {
79
+ if (!LINK_ONLY_WHEN_INSTALLED.has(agent))
80
+ return true;
81
+ try {
82
+ return (await (0, promises_1.stat)((0, node_path_1.dirname)(skillInstallDirectory(agent, homeDirectory, project, cwd)))).isDirectory();
83
+ }
84
+ catch {
85
+ return false;
86
+ }
61
87
  }
62
88
  function yamlValue(value) { return JSON.stringify(value); }
63
89
  function skillName(id) {
@@ -74,11 +100,12 @@ function packs(frontmatter) {
74
100
  }
75
101
  function renderSkillMarkdown(skill, provenance) {
76
102
  const name = skillName(skill.id);
77
- const source = skill.frontmatter ?? {};
103
+ const { name: _name, description: _description, 'allowed-tools': _tools, ...source } = skill.frontmatter ?? {};
104
+ // name and description lead, as agent hosts read them first.
78
105
  const frontmatter = {
79
- ...source,
80
106
  name,
81
107
  description: skill.description,
108
+ ...source,
82
109
  'allowed-tools': allowedTools,
83
110
  };
84
111
  const lines = Object.entries(frontmatter).flatMap(([key, value]) => Array.isArray(value)
@@ -122,7 +149,9 @@ async function installSkills(skills, options) {
122
149
  const provenance = { workspaceId: options.workspaceId ?? 'unknown', indexVersion: options.indexVersion ?? 'unknown' };
123
150
  const entries = await Promise.all(skills.map((skill) => writeHostedSkill(canonical, skill, provenance)));
124
151
  const files = entries.map((entry) => entry.file);
125
- for (const agent of options.agents.filter((agent) => agent === 'claude-code')) {
152
+ for (const agent of options.agents.filter(linksIntoCanonical)) {
153
+ if (!await agentInstalled(agent, home, Boolean(options.project), cwd))
154
+ continue;
126
155
  const root = skillInstallDirectory(agent, home, Boolean(options.project), cwd);
127
156
  for (const entry of entries)
128
157
  files.push(await linkAgentSkill(root, canonical, entry.name, Boolean(options.copy)));
@@ -161,7 +190,7 @@ async function inspectSkillInstallers(agents, homeDirectory = (0, node_os_1.home
161
190
  catch { /* unavailable */ }
162
191
  }
163
192
  const symlinks = [];
164
- if (agent === 'claude-code') {
193
+ if (linksIntoCanonical(agent)) {
165
194
  try {
166
195
  for (const name of await (await Promise.resolve().then(() => __importStar(require('node:fs/promises')))).readdir(directory)) {
167
196
  const path = (0, node_path_1.join)(directory, name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trydreamstate/cli",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Live command-line client for the Dreamstate v1 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",