@trydreamstate/cli 1.2.0 → 1.2.1

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
@@ -8,6 +8,10 @@ npm install -g @trydreamstate/cli
8
8
  # Opens browser approval. No API key or prior CLI state needed.
9
9
  dreamstate login
10
10
 
11
+ # Login installs every hosted Dreamstate skill plus router skill for detected Claude Code, Codex, and Cursor installations.
12
+ # Skip automatic installation when needed.
13
+ dreamstate login --no-skills
14
+
11
15
  # SSH or remote box with no browser: paste the token minted by "Create session" in the web app.
12
16
  dreamstate login --token <ds_live_...>
13
17
 
@@ -33,7 +37,7 @@ dreamstate tools search --goal "create a workbook" --limit 50 --toolset tables
33
37
  dreamstate tools run tables.workbooks.create --params '{"name":"Pipeline"}' --mode live --approved
34
38
  ```
35
39
 
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.
40
+ `login` installs every hosted Dreamstate skill and router skill at user level for detected Claude Code, Codex, and Cursor installations. `login --no-skills` skips this step. If no supported agent is detected or installation fails, login still succeeds and prints `Run dreamstate skills install to install Dreamstate skills.` to stderr. With `--json`, login adds `data.skills` with either installed agents and file count or a skip reason. `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
41
 
38
42
  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.
39
43
 
package/dist/client.d.ts CHANGED
@@ -25,7 +25,6 @@ export interface WhoamiResponse {
25
25
  api_base_url: string;
26
26
  mcp_endpoint_url: string;
27
27
  auth_kind?: 'user_session' | 'workspace_key';
28
- active_workspace_id?: string | null;
29
28
  workspaces?: WhoamiWorkspace[];
30
29
  }
31
30
  export interface WhoamiWorkspace {
@@ -99,6 +98,9 @@ export declare class DreamstateClient {
99
98
  private readonly onVersionWarning?;
100
99
  constructor(options: DreamstateClientOptions);
101
100
  getWhoami(): Promise<unknown>;
101
+ /** Status reports server compatibility, including a requirement this CLI cannot satisfy. */
102
+ getStatusWhoami(): Promise<unknown>;
103
+ getHealth(): Promise<unknown>;
102
104
  listPacks(query?: Record<string, unknown>): Promise<unknown>;
103
105
  getPack(packId: string, query?: Record<string, unknown>): Promise<unknown>;
104
106
  routePack(goal: string): Promise<unknown>;
@@ -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
@@ -149,6 +149,9 @@ class DreamstateClient {
149
149
  this.onVersionWarning = options.onVersionWarning;
150
150
  }
151
151
  getWhoami() { return this.request('/whoami'); }
152
+ /** Status reports server compatibility, including a requirement this CLI cannot satisfy. */
153
+ getStatusWhoami() { return this.request('/whoami', {}, exports.DEFAULT_REQUEST_TIMEOUT_MS, true); }
154
+ getHealth() { return this.request(new URL('/health', this.baseUrl).toString()); }
152
155
  listPacks(query = {}) { return this.request(`/packs${queryString(query)}`); }
153
156
  getPack(packId, query = {}) {
154
157
  return this.request(`/packs/${encodeURIComponent(packId)}${queryString(query)}`);
@@ -204,7 +207,7 @@ class DreamstateClient {
204
207
  ...(key ? { headers: { 'Idempotency-Key': key } } : {}),
205
208
  });
206
209
  }
207
- async request(path, init = {}, defaultTimeoutMs = exports.DEFAULT_REQUEST_TIMEOUT_MS) {
210
+ async request(path, init = {}, defaultTimeoutMs = exports.DEFAULT_REQUEST_TIMEOUT_MS, allowIncompatibleCli = false) {
208
211
  const requestTimeoutMs = this.requestTimeoutMs ?? defaultTimeoutMs;
209
212
  const controller = new AbortController();
210
213
  const timeout = setTimeout(() => controller.abort(), requestTimeoutMs);
@@ -212,7 +215,7 @@ class DreamstateClient {
212
215
  try {
213
216
  const idempotencyKey = new Headers(init.headers).get('Idempotency-Key') ?? undefined;
214
217
  try {
215
- response = await fetch(`${this.baseUrl}${path}`, {
218
+ response = await fetch(path.startsWith('http') ? path : `${this.baseUrl}${path}`, {
216
219
  ...init,
217
220
  signal: controller.signal,
218
221
  headers: {
@@ -250,7 +253,7 @@ class DreamstateClient {
250
253
  if (!response.ok)
251
254
  throw new CliError(`Dreamstate API request failed (HTTP ${response.status})`, 'request_failed', response.status);
252
255
  const minimum = payload && typeof payload === 'object' ? payload.meta?.minimum_cli_version : undefined;
253
- if (typeof minimum === 'string' && isVersionGreater(minimum, exports.CLI_VERSION)) {
256
+ if (!allowIncompatibleCli && typeof minimum === 'string' && isVersionGreater(minimum, exports.CLI_VERSION)) {
254
257
  throw new CliError(`CLI ${minimum} or newer is required. Run: npm install -g @trydreamstate/cli@latest`, 'cli_update_required', 0);
255
258
  }
256
259
  const server = payload && typeof payload === 'object' ? payload.meta?.server_version : undefined;
@@ -3,5 +3,5 @@ import type { CliCommand } from '../index';
3
3
  export declare const SEQUENCE_VERBS: PackVerbSpec[];
4
4
  export declare const SEQUENCES_USAGE: string;
5
5
  export declare const parseSequencesCommand: (argv: string[]) => CliCommand;
6
- export declare function runSequencesCommand(client: Parameters<typeof runPackCommand>[0], command: CliCommand, stdout: NodeJS.WritableStream): Promise<void>;
6
+ export declare function runSequencesCommand(client: Parameters<typeof runPackCommand>[0], command: CliCommand, stdout: NodeJS.WritableStream, sleep?: Parameters<typeof runPackCommand>[3]): Promise<void>;
7
7
  //# sourceMappingURL=sequences.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sequences.d.ts","sourceRoot":"","sources":["../../src/commands/sequences.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,cAAc,EAAe,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAC5G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,eAAO,MAAM,cAAc,EAAE,YAAY,EA+BxC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAqD,CAAC;AACpF,eAAO,MAAM,qBAAqB,gCAA4E,CAAC;AAC/G,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,EAC5C,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,CAAC,cAAc,GAC5B,OAAO,CAAC,IAAI,CAAC,CAMf"}
1
+ {"version":3,"file":"sequences.d.ts","sourceRoot":"","sources":["../../src/commands/sequences.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,cAAc,EAAe,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAC5G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,eAAO,MAAM,cAAc,EAAE,YAAY,EA+BxC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAqD,CAAC;AACpF,eAAO,MAAM,qBAAqB,gCAA4E,CAAC;AAC/G,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,EAC5C,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,CAAC,cAAc,EAC7B,KAAK,CAAC,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,GAC3C,OAAO,CAAC,IAAI,CAAC,CAMf"}
@@ -29,7 +29,7 @@ exports.SEQUENCE_VERBS = [
29
29
  { verb: 'pause', capabilityId: 'sequence.sequences.pause', summary: 'Pause sequence dispatch. Sends no new messages.', positional: [{ name: 'id', into: 'sequence_id' }], mutating: true },
30
30
  { verb: 'resume', capabilityId: 'sequence.sequences.resume', summary: 'Resume sequence dispatch.', positional: [{ name: 'id', into: 'sequence_id' }], flags: { 'max-live-sends': { type: 'string', into: 'max_live_sends' } }, mutating: true },
31
31
  { verb: 'stats', capabilityId: 'sequence.sequences.step_counts_get', summary: 'Get sequence step counts.', positional: [{ name: 'id', into: 'sequence_id' }], mutating: false },
32
- { verb: 'analytics', capabilityId: 'sequence.sequences.analytics_get', summary: 'Get sequence analytics.', positional: [{ name: 'id', into: 'sequence_id' }], flags: { period: { type: 'string', into: 'period' } }, mutating: false },
32
+ { verb: 'analytics', capabilityId: 'sequence.sequences.analytics_get', summary: 'Get sequence analytics.', positional: [{ name: 'id', into: 'sequence_id' }], flags: { 'window-days': { type: 'string', into: 'window_days', number: true } }, mutating: false },
33
33
  { verb: 'duplicate', capabilityId: 'workflow.automations.duplicate', summary: 'Duplicate sequence as draft. Does not publish or send.', positional: [{ name: 'id', into: 'automation_id' }], flags: { name: { type: 'string', into: 'name' }, 'expected-version': { type: 'string', into: 'expected_version', number: true } }, mutating: true },
34
34
  { verb: 'archive', capabilityId: 'workflow.automations.archive', summary: 'Archive sequence. Does not delete records or send.', positional: [{ name: 'id', into: 'automation_id' }], flags: { reason: { type: 'string', into: 'reason' }, 'expected-version': { type: 'string', into: 'expected_version', number: true } }, mutating: true },
35
35
  { verb: 'export', capabilityId: 'workflow.automations.export', summary: 'Export sequence definition. Makes no changes.', positional: [{ name: 'id', into: 'automation_id' }], mutating: false },
@@ -37,10 +37,10 @@ exports.SEQUENCE_VERBS = [
37
37
  ];
38
38
  exports.SEQUENCES_USAGE = (0, shared_1.renderPackUsage)('sequences', exports.SEQUENCE_VERBS);
39
39
  exports.parseSequencesCommand = (0, shared_1.buildPackParser)('sequences', 'sequence', exports.SEQUENCE_VERBS, exports.SEQUENCES_USAGE);
40
- async function runSequencesCommand(client, command, stdout) {
40
+ async function runSequencesCommand(client, command, stdout, sleep) {
41
41
  if (command.command === 'pack' && command.verb === 'init') {
42
42
  (0, shared_1.runPackInit)('sequence', command, stdout);
43
43
  return;
44
44
  }
45
- await (0, shared_1.runPackCommand)(client, command, stdout);
45
+ await (0, shared_1.runPackCommand)(client, command, stdout, sleep);
46
46
  }
@@ -36,6 +36,7 @@ export interface PackVerbSpec {
36
36
  json?: boolean;
37
37
  document?: boolean;
38
38
  number?: boolean;
39
+ required?: boolean;
39
40
  }>;
40
41
  mutating: boolean;
41
42
  }
@@ -48,6 +49,6 @@ export declare function buildPackParser(pack: 'sequences' | 'workflows', kind: '
48
49
  */
49
50
  export declare function packScaffold(kind: 'sequence' | 'workflow', name: string): Record<string, unknown>;
50
51
  export declare function runPackInit(kind: 'sequence' | 'workflow', command: CliCommand, stdout: NodeJS.WritableStream): void;
51
- export declare function runPackCommand(client: DreamstateClient, command: CliCommand, stdout: NodeJS.WritableStream): Promise<void>;
52
+ export declare function runPackCommand(client: DreamstateClient, command: CliCommand, stdout: NodeJS.WritableStream, sleep?: (milliseconds: number) => Promise<void>): Promise<void>;
52
53
  export declare function renderPackUsage(pack: string, specs: PackVerbSpec[]): string;
53
54
  //# sourceMappingURL=shared.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/commands/shared.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAKlD,OAAO,EAA6B,KAAK,UAAU,EAAiC,MAAM,UAAU,CAAC;AAMrG,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IACpD;;;;;;OAMG;IACH,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IAClE;;;;;;;OAOG;IACH;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,QAAQ,GAAC,SAAS,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACzH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAsBD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,WAAW,GAAC,WAAW,EAAE,IAAI,EAAE,UAAU,GAAC,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,GAC/F,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,UAAU,CAsGhC;AAGD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA2BjG;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,UAAU,GAAG,UAAU,EAC7B,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,CAAC,cAAc,GAC5B,IAAI,CAuBN;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBhI;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,MAAM,CAE3E"}
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/commands/shared.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAKlD,OAAO,EAA6B,KAAK,UAAU,EAAiC,MAAM,UAAU,CAAC;AAOrG,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IACpD;;;;;;OAMG;IACH,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IAClE;;;;;;;OAOG;IACH;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,QAAQ,GAAC,SAAS,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC7I,QAAQ,EAAE,OAAO,CAAC;CACnB;AAsBD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,WAAW,GAAC,WAAW,EAAE,IAAI,EAAE,UAAU,GAAC,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,GAC/F,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,UAAU,CAmHhC;AAGD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA+BjG;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,UAAU,GAAG,UAAU,EAC7B,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,CAAC,cAAc,GAC5B,IAAI,CAuBN;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,cAAc,EAAE,KAAK,GAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAiF,GAAG,OAAO,CAAC,IAAI,CAAC,CAuDhQ;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,MAAM,CAM3E"}
@@ -12,6 +12,7 @@ const node_util_1 = require("node:util");
12
12
  // audit:canonical-cutover:clean treats importing them as a release blocker.
13
13
  const index_1 = require("../index");
14
14
  const node_fs_1 = require("node:fs");
15
+ const runWait_1 = require("../runWait");
15
16
  const MODES = ['dry_run', 'live', 'smoke_test'];
16
17
  function parseObject(raw, flag) {
17
18
  try {
@@ -47,7 +48,7 @@ function buildPackParser(pack, kind, specs, usage) {
47
48
  const options = {
48
49
  mode: { type: 'string' }, 'dry-run': { type: 'boolean' }, live: { type: 'boolean' }, 'agent-session-id': { type: 'string' },
49
50
  'idempotency-key': { type: 'string' }, 'max-credits': { type: 'string' }, params: { type: 'string' },
50
- 'json-output': { type: 'boolean' }, open: { type: 'boolean' }, help: { type: 'boolean', short: 'h' },
51
+ 'wait-timeout': { type: 'string' }, 'no-wait': { type: 'boolean' }, 'json-output': { type: 'boolean' }, open: { type: 'boolean' }, help: { type: 'boolean', short: 'h' },
51
52
  };
52
53
  // A verb that takes a JSON document on a flag also takes it from a file, so a
53
54
  // whole authored document can be linted or imported straight off disk instead of
@@ -63,7 +64,14 @@ function buildPackParser(pack, kind, specs, usage) {
63
64
  options.file = { type: 'string' };
64
65
  for (const [flag, definition] of Object.entries(spec.flags ?? {}))
65
66
  options[flag] = { type: definition.type };
66
- const { values, positionals } = (0, node_util_1.parseArgs)({ args: argv.slice(1), options, allowPositionals: true, strict: true });
67
+ let values;
68
+ let positionals;
69
+ try {
70
+ ({ values, positionals } = (0, node_util_1.parseArgs)({ args: argv.slice(1), options, allowPositionals: true, strict: true }));
71
+ }
72
+ catch (error) {
73
+ throw new index_1.CliUsageError(`${error instanceof Error ? error.message : 'Invalid arguments.'}\n${usage}`);
74
+ }
67
75
  const mode = values.mode;
68
76
  const dryRun = values['dry-run'];
69
77
  const live = values.live;
@@ -71,8 +79,13 @@ function buildPackParser(pack, kind, specs, usage) {
71
79
  const idempotencyKey = values['idempotency-key'];
72
80
  const rawParams = values.params;
73
81
  const rawMaxCredits = values['max-credits'];
82
+ const rawWaitTimeout = values['wait-timeout'];
74
83
  if (values.help)
75
- throw new index_1.CliUsageError(usage);
84
+ return { command: 'pack_help', usage, ...(values['json-output'] ? { jsonOutput: true } : {}) };
85
+ for (const [flag, definition] of Object.entries(spec.flags ?? {})) {
86
+ if (definition.required && values[flag] === undefined)
87
+ throw new index_1.CliUsageError(`--${flag} is required for ${pack} ${spec.verb}.\n${usage}`);
88
+ }
76
89
  const positional = spec.positional ?? [];
77
90
  // A document supplied inline or from a file is authored, not saved, so there is no
78
91
  // id to name yet. lint and its kin accept a hypothetical document, which is the
@@ -147,12 +160,16 @@ function buildPackParser(pack, kind, specs, usage) {
147
160
  const maxCredits = rawMaxCredits === undefined ? undefined : Number(rawMaxCredits);
148
161
  if (maxCredits !== undefined && (!Number.isFinite(maxCredits) || maxCredits < 0))
149
162
  throw new index_1.CliUsageError('--max-credits must be a non-negative number');
163
+ const waitTimeout = rawWaitTimeout === undefined ? 120 : Number(rawWaitTimeout);
164
+ if (!Number.isFinite(waitTimeout) || waitTimeout < 0)
165
+ throw new index_1.CliUsageError('--wait-timeout must be a non-negative number');
150
166
  return {
151
167
  command: 'pack', pack, verb: spec.verb, capabilityId: spec.capabilityId, input,
152
168
  ...(explicitMode ? { mode: explicitMode } : spec.mutating ? { mode: 'dry_run' } : {}),
153
169
  ...(agentSessionId ? { agentSessionId } : {}),
154
170
  ...(idempotencyKey ? { idempotencyKey } : {}),
155
171
  ...(maxCredits === undefined ? {} : { maxCredits }), ...(values['json-output'] ? { jsonOutput: true } : {}),
172
+ waitTimeout, ...(values['no-wait'] ? { noWait: true } : {}),
156
173
  ...(values.open ? { open: true } : {}),
157
174
  };
158
175
  };
@@ -177,19 +194,23 @@ function packScaffold(kind, name) {
177
194
  steps: [
178
195
  {
179
196
  id: 'step_1',
180
- kind: 'linkedin',
181
- channel: 'linkedin',
182
- // send_dm, not send_connection_request. compose refuses the latter on purpose:
183
- // a send_dm carrying note_template sends the invitation and then body_template
184
- // once it is accepted, so one step covers both. A scaffold naming the refused
185
- // step lints clean and then fails at create, which is the same trap as before.
186
- action: 'send_dm',
187
- note_template: 'Hi {{first_name}}, would love to connect.',
188
- body_template: 'Thanks for connecting, {{first_name}}.',
197
+ kind: 'email',
198
+ channel: 'email',
199
+ action: 'send_email',
200
+ subject_template: 'Quick question, {{first_name}}',
201
+ body_template: 'Hi {{first_name}},\n\nWould this be useful to you?',
189
202
  },
190
203
  ],
191
204
  }
192
- : { kind: 'workflow', name, nodes: [], edges: [] };
205
+ : {
206
+ kind: 'workflow',
207
+ name,
208
+ nodes: [
209
+ { id: 'trigger-root', type: 'trigger', position: { x: 0, y: 0 }, data: { kind: 'trigger', subtype: 'table', config: {} } },
210
+ { id: 'action-example', type: 'action', position: { x: 0, y: 160 }, data: { kind: 'action', subtype: 'send_connection_request_to_contact', config: {} } },
211
+ ],
212
+ edges: [{ id: 'edge-trigger-action', source: 'trigger-root', target: 'action-example' }],
213
+ };
193
214
  }
194
215
  function runPackInit(kind, command, stdout) {
195
216
  if (command.command !== 'pack')
@@ -216,20 +237,51 @@ function runPackInit(kind, command, stdout) {
216
237
  },
217
238
  }, null, command.jsonOutput ? 0 : 2)}\n`);
218
239
  }
219
- async function runPackCommand(client, command, stdout) {
240
+ async function runPackCommand(client, command, stdout, sleep = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds))) {
220
241
  if (command.command !== 'pack')
221
242
  throw new index_1.CliUsageError('Pack command required.');
222
243
  // Every run needs a tool_turn_token from tools_get, exactly as the generic
223
244
  // tools run path does. Without it the server refuses capability_not_fetched,
224
245
  // which made every pack verb unusable even though its capability id was right.
225
- const { toolTurnToken } = require('../index');
226
- const turnToken = toolTurnToken(await client.getTool(command.capabilityId));
227
- const result = await client.runCapability(command.capabilityId, {
246
+ const { toolTurnToken, capabilityIdempotencyKey } = require('../index');
247
+ if (command.verb === 'activate' && command.input.max_credits === undefined) {
248
+ throw new index_1.CliUsageError('workflows activate requires --max-credits <n>.');
249
+ }
250
+ if (command.verb === 'publish' || command.verb === 'activate') {
251
+ const workflowId = command.input.workflow_id;
252
+ if (typeof workflowId !== 'string')
253
+ throw new index_1.CliUsageError(`workflows ${command.verb} requires <id>.`);
254
+ const readFetched = await client.getTool('workflow.automations.get');
255
+ const current = await client.runCapability('workflow.automations.get', {
256
+ params: { kind: 'workflow', automation_id: workflowId },
257
+ tool_turn_token: toolTurnToken(readFetched),
258
+ }, capabilityIdempotencyKey(readFetched));
259
+ const workflow = workflowFromGet(current);
260
+ if (command.verb === 'publish') {
261
+ command.input.expected_draft_version_id ??= nullableString(workflow.latest_draft_version_id, 'latest_draft_version_id');
262
+ command.input.expected_active_version_id ??= nullableString(workflow.active_version_id, 'active_version_id');
263
+ }
264
+ else {
265
+ command.input.expected_version_id ??= requiredString(workflow.active_version_id, 'active_version_id');
266
+ }
267
+ }
268
+ const fetched = await client.getTool(command.capabilityId);
269
+ const turnToken = toolTurnToken(fetched);
270
+ let result = await client.runCapability(command.capabilityId, {
228
271
  params: command.input, tool_turn_token: turnToken, ...(command.mode ? { mode: command.mode } : {}),
229
272
  ...(command.agentSessionId ? { agent_session_id: command.agentSessionId } : {}),
230
273
  ...(command.maxCredits === undefined ? {} : { max_credits: command.maxCredits }),
231
- }, command.idempotencyKey);
232
- stdout.write(`${JSON.stringify(result, null, command.jsonOutput ? 0 : 2)}\n`);
274
+ }, command.idempotencyKey ?? capabilityIdempotencyKey(fetched));
275
+ if (!command.noWait && !(0, runWait_1.columnRunReturnsRunId)(command.capabilityId)) {
276
+ const waited = await (0, runWait_1.waitForRun)(client, result, command.waitTimeout, sleep);
277
+ result = waited.value;
278
+ if (waited.timedOut)
279
+ process.exitCode = runWait_1.RUN_WAIT_TIMEOUT_EXIT_CODE;
280
+ }
281
+ const output = command.mode === 'dry_run' && result && typeof result === 'object' && !Array.isArray(result)
282
+ ? { ...result, meta: { ...(result.meta ?? {}), dry_run: true, note: 'dry_run: true, rerun with --live to apply' } }
283
+ : result;
284
+ stdout.write(`${JSON.stringify(output, null, command.jsonOutput ? 0 : 2)}\n`);
233
285
  if (!command.jsonOutput) {
234
286
  const root = result && typeof result === 'object' ? result : {};
235
287
  const webUrl = root.web_url ?? root.data?.web_url;
@@ -245,5 +297,31 @@ async function runPackCommand(client, command, stdout) {
245
297
  }
246
298
  }
247
299
  function renderPackUsage(pack, specs) {
248
- return `Usage: dreamstate ${pack} <verb> [args] [flags]\n\nVerbs:\n${specs.map((spec) => ` ${spec.verb.padEnd(18)} ${spec.summary}`).join('\n')}`;
300
+ return `Usage: dreamstate ${pack} <verb> [args] [flags]\nRequired positionals use <name:field>. Optional positionals use [name:field]. Flags list target input fields. Run responses wait by default, use --wait-timeout <seconds> (default 120) or --no-wait.\n\nVerbs:\n${specs.map((spec) => {
301
+ const positionals = (spec.positional ?? []).map(({ name, into, optional }) => `${optional ? '[' : '<'}${name}:${into}${optional ? ']' : '>'}`).join(' ');
302
+ const flags = Object.entries(spec.flags ?? {}).map(([flag, definition]) => `--${flag} <${definition.into}>${definition.required ? ' (required)' : ''}`).join(' ');
303
+ return ` ${spec.verb.padEnd(18)} ${[positionals, flags].filter(Boolean).join(' ')}\n${' '.repeat(20)}${spec.summary} Capability: ${spec.capabilityId}`;
304
+ }).join('\n')}`;
305
+ }
306
+ function workflowFromGet(value) {
307
+ const root = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
308
+ const data = root.data && typeof root.data === 'object' && !Array.isArray(root.data) ? root.data : {};
309
+ // The canonical door returns { data: { run: { steps: [{ outputs }] } } };
310
+ // outputs holds latest_draft_version_id and active_version_id.
311
+ const run = data.run && typeof data.run === 'object' ? data.run : null;
312
+ const outputs = run?.steps?.[0]?.outputs;
313
+ const workflow = outputs ?? data;
314
+ if (!workflow || typeof workflow !== 'object' || Array.isArray(workflow))
315
+ throw new index_1.CliUsageError('workflow get returned no workflow version data.');
316
+ return workflow;
317
+ }
318
+ function nullableString(value, name) {
319
+ if (value === null || typeof value === 'string')
320
+ return value;
321
+ throw new index_1.CliUsageError(`workflow get returned no ${name}.`);
322
+ }
323
+ function requiredString(value, name) {
324
+ if (typeof value === 'string' && value)
325
+ return value;
326
+ throw new index_1.CliUsageError(`workflow get returned no ${name}; publish workflow before activation.`);
249
327
  }
@@ -3,5 +3,5 @@ import type { CliCommand } from '../index';
3
3
  export declare const WORKFLOW_VERBS: PackVerbSpec[];
4
4
  export declare const WORKFLOWS_USAGE: string;
5
5
  export declare const parseWorkflowsCommand: (argv: string[]) => CliCommand;
6
- export declare function runWorkflowsCommand(client: Parameters<typeof runPackCommand>[0], command: CliCommand, stdout: NodeJS.WritableStream): Promise<void>;
6
+ export declare function runWorkflowsCommand(client: Parameters<typeof runPackCommand>[0], command: CliCommand, stdout: NodeJS.WritableStream, sleep?: Parameters<typeof runPackCommand>[3]): Promise<void>;
7
7
  //# sourceMappingURL=workflows.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../../src/commands/workflows.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,cAAc,EAEd,KAAK,YAAY,EAClB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAS3C,eAAO,MAAM,cAAc,EAAE,YAAY,EA8BxC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAqD,CAAC;AACpF,eAAO,MAAM,qBAAqB,gCAA4E,CAAC;AAC/G,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,EAC5C,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,CAAC,cAAc,GAC5B,OAAO,CAAC,IAAI,CAAC,CAMf"}
1
+ {"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../../src/commands/workflows.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,cAAc,EAEd,KAAK,YAAY,EAClB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAS3C,eAAO,MAAM,cAAc,EAAE,YAAY,EA8BxC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAqD,CAAC;AACpF,eAAO,MAAM,qBAAqB,gCAA4E,CAAC;AAC/G,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,EAC5C,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,CAAC,cAAc,EAC7B,KAAK,CAAC,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,GAC3C,OAAO,CAAC,IAAI,CAAC,CAMf"}
@@ -27,14 +27,14 @@ exports.WORKFLOW_VERBS = [
27
27
  { verb: 'node-remove', capabilityId: 'workflow.automations.node_remove', summary: 'Remove workflow node.', positional: id, flags: { ...workflowVersion, 'node-id': { type: 'string', into: 'node_id' } }, mutating: true },
28
28
  { verb: 'node-move', capabilityId: 'workflow.automations.node_move', summary: 'Move workflow node.', positional: id, flags: { ...workflowVersion, 'node-id': { type: 'string', into: 'node_id' }, 'after-node-id': { type: 'string', into: 'after_node_id' }, branch: { type: 'string', into: 'branch' } }, mutating: true },
29
29
  { verb: 'field-options', capabilityId: 'workflow.automations.field_options', summary: 'Resolve workflow node field options.', flags: { 'node-kind': { type: 'string', into: 'node_kind' }, subtype: { type: 'string', into: 'subtype' }, 'automation-id': { type: 'string', into: 'automation_id' }, 'node-id': { type: 'string', into: 'node_id' }, 'field-key': { type: 'string', into: 'field_key' }, 'field-keys': { type: 'string', into: 'field_keys', json: true }, query: { type: 'string', into: 'query' }, limit: { type: 'string', into: 'limit' }, cursor: { type: 'string', into: 'cursor' }, 'field-context': { type: 'string', into: 'field_context', json: true } }, mutating: false },
30
- { verb: 'draft-save', capabilityId: 'workflow.workflows.draft_save', summary: 'Save workflow draft.', positional: id, flags: { graph: { type: 'string', into: 'graph', json: true, document: true }, 'expected-latest-draft-version-id': { type: 'string', into: 'expected_latest_draft_version_id' } }, mutating: true },
31
- { verb: 'publish', capabilityId: 'workflow.workflows.draft_publish', summary: 'Publish workflow draft.', positional: id, flags: { 'expected-draft-version-id': { type: 'string', into: 'expected_draft_version_id' }, 'expected-active-version-id': { type: 'string', into: 'expected_active_version_id' } }, mutating: true },
32
- { verb: 'activate', capabilityId: 'workflow.workflows.activate', summary: 'Activate workflow.', positional: id, flags: { 'expected-version-id': { type: 'string', into: 'expected_version_id' }, 'delivery-binding': { type: 'string', into: 'delivery_binding', json: true } }, mutating: true },
33
- { verb: 'deactivate', capabilityId: 'workflow.workflows.deactivate', summary: 'Deactivate workflow.', positional: id, mutating: true },
34
- { verb: 'enroll', capabilityId: 'workflow.workflows.enroll_selection', summary: 'Enroll selection in workflow.', positional: id, flags: { selection: { type: 'string', into: 'selection', json: true } }, mutating: true },
30
+ { verb: 'draft-save', capabilityId: 'workflow.workflows.draft_save', summary: 'Save workflow draft.', positional: workflowId, flags: { graph: { type: 'string', into: 'graph', json: true, document: true }, 'expected-latest-draft-version-id': { type: 'string', into: 'expected_latest_draft_version_id' } }, mutating: true },
31
+ { verb: 'publish', capabilityId: 'workflow.workflows.draft_publish', summary: 'Publish workflow draft.', positional: workflowId, flags: { 'expected-draft-version-id': { type: 'string', into: 'expected_draft_version_id' }, 'expected-active-version-id': { type: 'string', into: 'expected_active_version_id' } }, mutating: true },
32
+ { verb: 'activate', capabilityId: 'workflow.workflows.activate', summary: 'Activate workflow.', positional: workflowId, flags: { 'expected-version-id': { type: 'string', into: 'expected_version_id' }, 'max-credits': { type: 'string', into: 'max_credits', number: true, required: true }, 'delivery-binding': { type: 'string', into: 'delivery_binding', json: true } }, mutating: true },
33
+ { verb: 'deactivate', capabilityId: 'workflow.workflows.deactivate', summary: 'Deactivate workflow.', positional: workflowId, mutating: true },
34
+ { verb: 'enroll', capabilityId: 'workflow.workflows.enroll_selection', summary: 'Enroll saved worksheet selection in workflow.', positional: workflowId, flags: { 'workbook-id': { type: 'string', into: 'workbook_id' }, 'worksheet-id': { type: 'string', into: 'worksheet_id' }, 'saved-view-id': { type: 'string', into: 'saved_view_id' }, 'selection-snapshot-id': { type: 'string', into: 'selection_snapshot_id' }, 'trigger-node-id': { type: 'string', into: 'trigger_node_id' }, 'audience-filter': { type: 'string', into: 'audience_filter', json: true }, 'enrollment-priority': { type: 'string', into: 'enrollment_priority', json: true }, 'enrollment-sort': { type: 'string', into: 'enrollment_sort', json: true }, 'max-live-sends': { type: 'string', into: 'max_live_sends', number: true } }, mutating: true },
35
35
  { verb: 'runs', capabilityId: 'workflow.workflows.runs_list', summary: 'List workflow runs.', positional: workflowId, flags: { workflow: { type: 'string', into: 'workflow_id' }, limit: { type: 'string', into: 'limit' } }, mutating: false },
36
- { verb: 'run', capabilityId: 'workflow.workflows.run_trace_get', summary: 'Get workflow run trace.', positional: id, flags: { 'subject-id': { type: 'string', into: 'subject_id' } }, mutating: false },
37
- { verb: 'retry', capabilityId: 'workflow.workflows.run_retry', summary: 'Retry failed workflow run event.', positional: id, flags: { 'subject-id': { type: 'string', into: 'subject_id' }, 'failed-event-id': { type: 'string', into: 'failed_event_id' }, 'failed-node-id': { type: 'string', into: 'failed_node_id' } }, mutating: true },
36
+ { verb: 'run', capabilityId: 'workflow.workflows.run_trace_get', summary: 'Get workflow run trace.', positional: workflowId, flags: { 'subject-id': { type: 'string', into: 'subject_id' } }, mutating: false },
37
+ { verb: 'retry', capabilityId: 'workflow.workflows.run_retry', summary: 'Retry failed workflow run event.', positional: workflowId, flags: { 'subject-id': { type: 'string', into: 'subject_id' }, 'failed-event-id': { type: 'string', into: 'failed_event_id' }, 'failed-node-id': { type: 'string', into: 'failed_node_id' } }, mutating: true },
38
38
  { verb: 'duplicate', capabilityId: 'workflow.automations.duplicate', summary: 'Duplicate workflow.', positional: id, flags: { ...workflowVersion, name: { type: 'string', into: 'name' } }, mutating: true },
39
39
  { verb: 'archive', capabilityId: 'workflow.automations.archive', summary: 'Archive workflow.', positional: id, flags: { ...workflowVersion, reason: { type: 'string', into: 'reason' } }, mutating: true },
40
40
  { verb: 'export', capabilityId: 'workflow.automations.export', summary: 'Export workflow.', positional: id, mutating: false },
@@ -42,10 +42,10 @@ exports.WORKFLOW_VERBS = [
42
42
  ];
43
43
  exports.WORKFLOWS_USAGE = (0, shared_1.renderPackUsage)('workflows', exports.WORKFLOW_VERBS);
44
44
  exports.parseWorkflowsCommand = (0, shared_1.buildPackParser)('workflows', 'workflow', exports.WORKFLOW_VERBS, exports.WORKFLOWS_USAGE);
45
- async function runWorkflowsCommand(client, command, stdout) {
45
+ async function runWorkflowsCommand(client, command, stdout, sleep) {
46
46
  if (command.command === 'pack' && command.verb === 'init') {
47
47
  (0, shared_1.runPackInit)('workflow', command, stdout);
48
48
  return;
49
49
  }
50
- await (0, shared_1.runPackCommand)(client, command, stdout);
50
+ await (0, shared_1.runPackCommand)(client, command, stdout, sleep);
51
51
  }
package/dist/config.d.ts CHANGED
@@ -25,6 +25,15 @@ export interface StoredCredentials {
25
25
  token: string;
26
26
  workspace: string | null;
27
27
  }
28
+ export interface CredentialProfile extends StoredCredentials {
29
+ name: string;
30
+ }
31
+ export declare function validateProfileName(name: string): string;
32
+ export declare function currentCredentialProfile(path?: string, environment?: NodeJS.ProcessEnv): Promise<string | null>;
33
+ export declare function useCredentialProfile(name: string, path?: string): Promise<void>;
34
+ export declare function selectedCredentialsPath(path: string, environment?: NodeJS.ProcessEnv): Promise<string>;
35
+ export declare function listCredentialProfiles(path?: string): Promise<CredentialProfile[]>;
36
+ export declare function removeCredentialProfile(name: string, path?: string): Promise<boolean>;
28
37
  /**
29
38
  * The file is JSON `{token, workspace}`. Files written by 1.0.x hold one bare
30
39
  * token line; they keep working so an upgrade never logs anyone out.
@@ -35,4 +44,5 @@ export declare function resolveApiKey(environment?: NodeJS.ProcessEnv, path?: st
35
44
  export declare function resolveWorkspace(flag: string | undefined, environment?: NodeJS.ProcessEnv, path?: string): Promise<string | undefined>;
36
45
  export declare function readApiKeyFile(path: string): Promise<string>;
37
46
  export declare function storeApiKey(apiKey: string, path?: string, workspace?: string | null): Promise<string>;
47
+ export declare function storeCredentialProfile(name: string, apiKey: string, path?: string, workspace?: string | null): Promise<string>;
38
48
  //# 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,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"}
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,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D,IAAI,EAAE,MAAM,CAAC;CACd;AAID,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIxD;AAcD,wBAAsB,wBAAwB,CAAC,IAAI,SAAoB,EAAE,WAAW,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAU7I;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,SAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAShG;AAED,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAGzH;AAED,wBAAsB,sBAAsB,CAAC,IAAI,SAAoB,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAanG;AAED,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,SAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,CAUtG;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,CAOjB;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,CAO7B;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;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,SAAoB,EAAE,SAAS,GAAE,MAAM,GAAG,IAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAIrJ"}
package/dist/config.js CHANGED
@@ -4,11 +4,18 @@ exports.API_KEY_PREFIXES = exports.ApiKeyFileError = exports.MissingApiKeyError
4
4
  exports.credentialsPath = credentialsPath;
5
5
  exports.resolveApiBaseUrl = resolveApiBaseUrl;
6
6
  exports.isDreamstateToken = isDreamstateToken;
7
+ exports.validateProfileName = validateProfileName;
8
+ exports.currentCredentialProfile = currentCredentialProfile;
9
+ exports.useCredentialProfile = useCredentialProfile;
10
+ exports.selectedCredentialsPath = selectedCredentialsPath;
11
+ exports.listCredentialProfiles = listCredentialProfiles;
12
+ exports.removeCredentialProfile = removeCredentialProfile;
7
13
  exports.readStoredCredentials = readStoredCredentials;
8
14
  exports.resolveApiKey = resolveApiKey;
9
15
  exports.resolveWorkspace = resolveWorkspace;
10
16
  exports.readApiKeyFile = readApiKeyFile;
11
17
  exports.storeApiKey = storeApiKey;
18
+ exports.storeCredentialProfile = storeCredentialProfile;
12
19
  const promises_1 = require("node:fs/promises");
13
20
  const node_os_1 = require("node:os");
14
21
  const node_path_1 = require("node:path");
@@ -103,6 +110,85 @@ exports.API_KEY_PREFIXES = ['ds_user_', 'ds_live_'];
103
110
  function isDreamstateToken(value) {
104
111
  return exports.API_KEY_PREFIXES.some((prefix) => value.startsWith(prefix) && value.length > prefix.length);
105
112
  }
113
+ const PROFILE_NAME = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;
114
+ function validateProfileName(name) {
115
+ const normalized = name.trim();
116
+ if (!PROFILE_NAME.test(normalized))
117
+ throw new ApiKeyFileError('Profile names must use letters, numbers, hyphens, or underscores.');
118
+ return normalized;
119
+ }
120
+ function profileDirectory(path) {
121
+ return (0, node_path_1.join)(path, '..', 'profiles');
122
+ }
123
+ function profilePath(path, name) {
124
+ return (0, node_path_1.join)(profileDirectory(path), validateProfileName(name));
125
+ }
126
+ function currentProfilePath(path) {
127
+ return (0, node_path_1.join)(path, '..', 'current-profile');
128
+ }
129
+ async function currentCredentialProfile(path = credentialsPath(), environment = process.env) {
130
+ const fromEnvironment = environment.DREAMSTATE_PROFILE?.trim();
131
+ if (fromEnvironment)
132
+ return validateProfileName(fromEnvironment);
133
+ try {
134
+ const name = (await (0, promises_1.readFile)(currentProfilePath(path), 'utf8')).trim();
135
+ return name ? validateProfileName(name) : null;
136
+ }
137
+ catch (error) {
138
+ if (['ENOENT', 'ENOTDIR'].includes(error.code ?? ''))
139
+ return null;
140
+ throw error;
141
+ }
142
+ }
143
+ async function useCredentialProfile(name, path = credentialsPath()) {
144
+ const normalized = validateProfileName(name);
145
+ if (!await readStoredCredentials(profilePath(path, normalized))) {
146
+ throw new ApiKeyFileError(`Profile not found: ${normalized}. Run dreamstate login --profile ${normalized} --token <key> first.`);
147
+ }
148
+ const directory = (0, node_path_1.join)(path, '..');
149
+ await (0, promises_1.mkdir)(directory, { recursive: true, mode: 0o700 });
150
+ await (0, promises_1.writeFile)(currentProfilePath(path), `${normalized}\n`, { encoding: 'utf8', mode: 0o600 });
151
+ await (0, promises_1.chmod)(currentProfilePath(path), 0o600);
152
+ }
153
+ async function selectedCredentialsPath(path, environment = process.env) {
154
+ const profile = await currentCredentialProfile(path, environment);
155
+ return profile ? profilePath(path, profile) : path;
156
+ }
157
+ async function listCredentialProfiles(path = credentialsPath()) {
158
+ let names;
159
+ try {
160
+ names = await (0, promises_1.readdir)(profileDirectory(path));
161
+ }
162
+ catch (error) {
163
+ if (['ENOENT', 'ENOTDIR'].includes(error.code ?? ''))
164
+ return [];
165
+ throw error;
166
+ }
167
+ const profiles = await Promise.all(names.sort().map(async (name) => {
168
+ try {
169
+ const stored = await readStoredCredentials(profilePath(path, name));
170
+ return stored ? { name, ...stored } : null;
171
+ }
172
+ catch {
173
+ return null;
174
+ }
175
+ }));
176
+ return profiles.filter((profile) => profile !== null);
177
+ }
178
+ async function removeCredentialProfile(name, path = credentialsPath()) {
179
+ const normalized = validateProfileName(name);
180
+ try {
181
+ await (0, promises_1.unlink)(profilePath(path, normalized));
182
+ if (await currentCredentialProfile(path) === normalized)
183
+ await (0, promises_1.unlink)(currentProfilePath(path)).catch(() => undefined);
184
+ return true;
185
+ }
186
+ catch (error) {
187
+ if (error.code === 'ENOENT')
188
+ return false;
189
+ throw error;
190
+ }
191
+ }
106
192
  /**
107
193
  * The file is JSON `{token, workspace}`. Files written by 1.0.x hold one bare
108
194
  * token line; they keep working so an upgrade never logs anyone out.
@@ -138,7 +224,8 @@ async function resolveApiKey(environment = process.env, path) {
138
224
  const environmentKey = environment.DREAMSTATE_API_KEY?.trim();
139
225
  if (environmentKey)
140
226
  return environmentKey;
141
- const stored = await readStoredCredentials(path ?? credentialsPath(undefined, environment));
227
+ const credentials = await selectedCredentialsPath(path ?? credentialsPath(undefined, environment), environment);
228
+ const stored = await readStoredCredentials(credentials);
142
229
  if (stored)
143
230
  return stored.token;
144
231
  throw new MissingApiKeyError();
@@ -151,7 +238,8 @@ async function resolveWorkspace(flag, environment = process.env, path) {
151
238
  const fromEnvironment = environment.DREAMSTATE_WORKSPACE?.trim();
152
239
  if (fromEnvironment)
153
240
  return fromEnvironment;
154
- return (await readStoredCredentials(path ?? credentialsPath(undefined, environment)))?.workspace ?? undefined;
241
+ const credentials = await selectedCredentialsPath(path ?? credentialsPath(undefined, environment), environment);
242
+ return (await readStoredCredentials(credentials))?.workspace ?? undefined;
155
243
  }
156
244
  async function readApiKeyFile(path) {
157
245
  let file;
@@ -183,3 +271,8 @@ async function storeApiKey(apiKey, path = credentialsPath(), workspace = null) {
183
271
  await (0, promises_1.chmod)(path, 0o600);
184
272
  return path;
185
273
  }
274
+ async function storeCredentialProfile(name, apiKey, path = credentialsPath(), workspace = null) {
275
+ const target = profilePath(path, name);
276
+ await storeApiKey(apiKey, target, workspace);
277
+ return target;
278
+ }