@trydreamstate/cli 1.0.1 → 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
@@ -29,6 +29,13 @@ export type CliCommand = {
29
29
  } | {
30
30
  command: 'whoami';
31
31
  jsonOutput?: boolean;
32
+ } | {
33
+ command: 'workspaces_list';
34
+ jsonOutput?: boolean;
35
+ } | {
36
+ command: 'workspaces_use';
37
+ workspace: string;
38
+ jsonOutput?: boolean;
32
39
  } | {
33
40
  command: 'packs_list';
34
41
  jsonOutput?: boolean;
@@ -164,6 +171,14 @@ type SpawnLike = (command: string, args: readonly string[], options: {
164
171
  };
165
172
  export declare function openWebUrl(rawUrl: string, launch?: SpawnLike): void;
166
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
+ };
167
182
  export declare function runCli(argv?: string[], runtime?: CliRuntime): Promise<void>;
168
183
  export {};
169
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')
@@ -567,6 +581,41 @@ function deviceState() {
567
581
  function runtimeCredentialsPath(runtime) {
568
582
  return runtime.credentialsPath ?? (0, config_1.credentialsPath)(undefined, runtime.env ?? process.env);
569
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
+ }
570
619
  function wait(milliseconds) {
571
620
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
572
621
  }
@@ -583,7 +632,7 @@ async function loginWithDeviceAuthorization(runtime, stdout, stderr) {
583
632
  for (;;) {
584
633
  const claim = await (0, client_1.claimDeviceAuthorization)(baseUrl, authorization.device_code);
585
634
  if (claim.status === 'ready') {
586
- await (0, config_1.storeApiKey)(claim.token, runtimeCredentialsPath(runtime));
635
+ await (0, config_1.storeApiKey)(claim.token, runtimeCredentialsPath(runtime), claim.workspace.id);
587
636
  const client = new client_1.DreamstateClient({
588
637
  baseUrl,
589
638
  apiKey: claim.token,
@@ -614,7 +663,8 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
614
663
  ignoreBrokenPipe(stdout);
615
664
  ignoreBrokenPipe(stderr);
616
665
  try {
617
- const command = parseCliArgs(argv);
666
+ const extracted = extractWorkspaceFlag(argv);
667
+ const command = parseCliArgs(extracted.argv);
618
668
  if (command.command === 'help') {
619
669
  print({ ok: true, data: { usage: USAGE }, meta: {} }, stdout, false);
620
670
  process.exitCode = exports.CLI_EXIT.SUCCESS;
@@ -646,12 +696,16 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
646
696
  }
647
697
  if (command.command === 'login' && command.token !== undefined) {
648
698
  const token = command.token.trim();
649
- if (!token.startsWith('ds_live_') || token.length <= 'ds_live_'.length)
650
- throw new CliUsageError('--token must be a Dreamstate API key starting with ds_live_.');
651
- 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();
652
705
  const client = new client_1.DreamstateClient({
653
706
  baseUrl,
654
707
  apiKey: token,
708
+ ...(requested ? { workspace: requested } : {}),
655
709
  requestTimeoutMs: runtime.requestTimeoutMs,
656
710
  onVersionWarning: (message) => stderr.write(`${message}\n`),
657
711
  });
@@ -664,8 +718,8 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
664
718
  if (command.command === 'login') {
665
719
  if (command.apiKeyFile || (runtime.env ?? process.env).DREAMSTATE_API_KEY || runtime.promptHidden) {
666
720
  const key = await readLoginKey(command, runtime);
667
- if (!key.startsWith('ds_live_'))
668
- 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_.');
669
723
  const path = await (0, config_1.storeApiKey)(key, runtimeCredentialsPath(runtime));
670
724
  print({ ok: true, data: { credentials_path: path }, meta: {} }, stdout, Boolean(command.jsonOutput));
671
725
  stderr.write('Run dreamstate skills install to install Dreamstate skills.\n');
@@ -682,7 +736,8 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
682
736
  const baseUrl = (0, config_1.resolveApiBaseUrl)(environment);
683
737
  const credentialFilePath = runtimeCredentialsPath(runtime);
684
738
  const apiKey = await (0, config_1.resolveApiKey)(environment, credentialFilePath);
685
- 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 });
686
741
  await client.listSkills({ limit: 1 });
687
742
  const installers = await (0, skillInstaller_1.inspectSkillInstallers)(command.agents, runtime.homeDirectory, Boolean(command.project));
688
743
  print({ ok: true, data: { index_reachable: true, installers }, meta: {} }, stdout, Boolean(command.jsonOutput));
@@ -735,17 +790,60 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
735
790
  }
736
791
  throw error;
737
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);
738
800
  const client = new client_1.DreamstateClient({
739
801
  baseUrl,
740
802
  apiKey,
803
+ ...(workspace ? { workspace } : {}),
741
804
  requestTimeoutMs: runtime.requestTimeoutMs,
742
805
  onVersionWarning: (message) => (runtime.stderr ?? process.stderr).write(`${message}\n`),
743
806
  });
744
807
  let result;
745
808
  switch (command.command) {
746
- case 'whoami':
809
+ case 'whoami': {
747
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
+ }
748
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
+ }
749
847
  case 'packs_list':
750
848
  result = await client.listPacks();
751
849
  break;
@@ -819,6 +917,8 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
819
917
  // forget it once the paid run is admitted, so every other call keeps
820
918
  // fetching a fresh turn exactly as before.
821
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;
822
922
  let warnedAboutTurnCache = false;
823
923
  const warnTurnCache = () => {
824
924
  if (warnedAboutTurnCache)
@@ -828,22 +928,22 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
828
928
  };
829
929
  const pending = command.turnToken
830
930
  ? null
831
- : 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);
832
932
  const turnToken = command.turnToken ?? pending ?? toolTurnToken(await client.getTool(command.capabilityId));
833
933
  try {
834
934
  result = await client.runCapability(command.capabilityId, { ...command.body, tool_turn_token: turnToken }, command.idempotencyKey);
835
935
  }
836
936
  catch (error) {
837
937
  if (!command.turnToken && code(error) === 'quote_required') {
838
- 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);
839
939
  }
840
940
  throw error;
841
941
  }
842
942
  if (!command.turnToken) {
843
943
  if (command.body.mode === 'dry_run')
844
- 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);
845
945
  else if (pending)
846
- await (0, turnCache_1.forgetTurnToken)(turns, baseUrl, apiKey, command.capabilityId, warnTurnCache);
946
+ await (0, turnCache_1.forgetTurnToken)(turns, baseUrl, turnKey, command.capabilityId, warnTurnCache);
847
947
  }
848
948
  break;
849
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,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,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) {
@@ -123,7 +149,9 @@ async function installSkills(skills, options) {
123
149
  const provenance = { workspaceId: options.workspaceId ?? 'unknown', indexVersion: options.indexVersion ?? 'unknown' };
124
150
  const entries = await Promise.all(skills.map((skill) => writeHostedSkill(canonical, skill, provenance)));
125
151
  const files = entries.map((entry) => entry.file);
126
- 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;
127
155
  const root = skillInstallDirectory(agent, home, Boolean(options.project), cwd);
128
156
  for (const entry of entries)
129
157
  files.push(await linkAgentSkill(root, canonical, entry.name, Boolean(options.copy)));
@@ -162,7 +190,7 @@ async function inspectSkillInstallers(agents, homeDirectory = (0, node_os_1.home
162
190
  catch { /* unavailable */ }
163
191
  }
164
192
  const symlinks = [];
165
- if (agent === 'claude-code') {
193
+ if (linksIntoCanonical(agent)) {
166
194
  try {
167
195
  for (const name of await (await Promise.resolve().then(() => __importStar(require('node:fs/promises')))).readdir(directory)) {
168
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.1",
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",