@trydreamstate/cli 1.0.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 ADDED
@@ -0,0 +1,62 @@
1
+ # Dreamstate CLI
2
+
3
+ Live terminal client for Dreamstate capability catalog. No pack list, capability list, or schema lives in package.
4
+
5
+ ```sh
6
+ npm install -g @trydreamstate/cli
7
+
8
+ # Opens browser approval. No API key or prior CLI state needed.
9
+ dreamstate login
10
+
11
+ # SSH or remote box with no browser: paste the token minted by "Create session" in the web app.
12
+ dreamstate login --token <ds_live_...>
13
+
14
+ # Install hosted skills for your agents (space-separated, comma-separated or repeated --agents).
15
+ dreamstate skills install --agents claude-code codex cursor --skill '*' --json
16
+
17
+ # Delete the stored credentials.
18
+ dreamstate logout
19
+
20
+ # Optional: point CLI at local or test API.
21
+ export DREAMSTATE_API_URL=http://localhost:3001/api/v1
22
+
23
+ dreamstate auth whoami
24
+ dreamstate whoami --json
25
+ dreamstate packs list
26
+ dreamstate packs get <pack_id>
27
+ dreamstate commands search "create a workbook and add rows"
28
+ dreamstate tools get <capability_id>
29
+ dreamstate tools search --goal "create a workbook" --limit 50 --toolset tables
30
+ dreamstate tools run tables.workbooks.create --params '{"name":"Pipeline"}' --mode live --approved
31
+ ```
32
+
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.
34
+
35
+ `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
+
37
+ `--json` is output alias for `--json-output` when used without a value. `tools run --json <body>`, `runs list --json <query>`, and `runs cancel --json <body>` keep JSON input meaning. `tools run --mode smoke_test|dry_run|live` sends canonical execution mode; `--dry-run` aliases `--mode dry_run`. `--approved` authorizes request only, never enters request body. `tools search --limit <n>` and `--toolset <pack_id>` send canonical discovery query fields.
38
+
39
+ ## Stream contract and exit codes
40
+
41
+ Every invocation writes one JSON envelope to stdout. Pipe stdout to `jq`; progress, warnings, confirmation codes, and version-skew notices use stderr. Error envelopes have `ok: false`, `executed: false`, `error`, and `meta.exit_code`; usage errors use same envelope.
42
+
43
+ | Exit code | Meaning |
44
+ | --- | --- |
45
+ | 0 | Success |
46
+ | 2 | Usage error |
47
+ | 3 | Authentication failure |
48
+ | 4 | Not found |
49
+ | 5 | Server failure |
50
+ | 6 | Rate limited |
51
+ | 7 | Approval required |
52
+ | 8 | Request timeout |
53
+ | 9 | Server refusal (HTTP 4xx) |
54
+ | 10 | Transport failure |
55
+
56
+ Build and test:
57
+
58
+ ```sh
59
+ npm run build --workspace=packages/cli
60
+ npm test --workspace=packages/cli
61
+ npm run pack:smoke --workspace=packages/cli
62
+ ```
@@ -0,0 +1,106 @@
1
+ export declare const CLI_VERSION: string;
2
+ export interface DreamstateClientOptions {
3
+ apiKey: string;
4
+ baseUrl: string;
5
+ requestTimeoutMs?: number;
6
+ onVersionWarning?: (message: string) => void;
7
+ }
8
+ export declare const DEFAULT_REQUEST_TIMEOUT_MS = 15000;
9
+ export declare const TOOL_AND_RUN_REQUEST_TIMEOUT_MS = 60000;
10
+ export interface WhoamiResponse {
11
+ registry_hash: string;
12
+ workspace_id: string;
13
+ actor: {
14
+ type: string;
15
+ user_id?: string;
16
+ key_id?: string;
17
+ };
18
+ key_id: string | null;
19
+ actor_user_id: string | null;
20
+ scopes: string[];
21
+ plan_tier: string | null;
22
+ subscription_status: string | null;
23
+ api_base_url: string;
24
+ mcp_endpoint_url: string;
25
+ }
26
+ export interface CapabilityRunBody {
27
+ params: Record<string, unknown>;
28
+ mode?: 'smoke_test' | 'dry_run' | 'live';
29
+ agent_session_id?: string;
30
+ approved?: boolean;
31
+ max_credits?: number;
32
+ [key: string]: unknown;
33
+ }
34
+ export interface DeviceAuthorization {
35
+ device_code: string;
36
+ user_code: string;
37
+ verification_uri: string;
38
+ verification_uri_complete: string;
39
+ interval_seconds: number;
40
+ expires_at: string;
41
+ confirmation_code: string;
42
+ }
43
+ export type DeviceAuthorizationClaim = {
44
+ status: 'pending';
45
+ } | {
46
+ status: 'ready';
47
+ token: string;
48
+ workspace: {
49
+ id: string;
50
+ name: string;
51
+ };
52
+ };
53
+ export declare class CliError extends Error {
54
+ readonly code: string;
55
+ readonly status: number;
56
+ readonly details?: unknown;
57
+ readonly retryAfter?: string;
58
+ readonly traceId?: string;
59
+ readonly idempotencyKey?: string;
60
+ /** The server's retry decision and repair, forwarded unchanged so the CLI never re-derives them. */
61
+ readonly retryable?: boolean;
62
+ readonly repair?: unknown;
63
+ constructor(message: string, code: string, status: number, options?: {
64
+ details?: unknown;
65
+ retryAfter?: string;
66
+ traceId?: string;
67
+ idempotencyKey?: string;
68
+ retryable?: boolean;
69
+ repair?: unknown;
70
+ });
71
+ }
72
+ export declare function readToolEnvelopeTraceId(value: unknown): string | undefined;
73
+ export declare function requestDeviceAuthorization(baseUrl: string, body: {
74
+ state: string;
75
+ client: {
76
+ os: string;
77
+ hostname: string;
78
+ cli_version: string;
79
+ };
80
+ }): Promise<DeviceAuthorization>;
81
+ export declare function claimDeviceAuthorization(baseUrl: string, state: string): Promise<DeviceAuthorizationClaim>;
82
+ export declare class DreamstateClient {
83
+ private readonly apiKey;
84
+ private readonly baseUrl;
85
+ private readonly requestTimeoutMs?;
86
+ private readonly onVersionWarning?;
87
+ constructor(options: DreamstateClientOptions);
88
+ getWhoami(): Promise<unknown>;
89
+ listPacks(query?: Record<string, unknown>): Promise<unknown>;
90
+ getPack(packId: string, query?: Record<string, unknown>): Promise<unknown>;
91
+ routePack(goal: string): Promise<unknown>;
92
+ listSkills(query?: Record<string, unknown>): Promise<unknown>;
93
+ searchSkillDocuments(query: Record<string, unknown>): Promise<unknown>;
94
+ listAllSkills(): Promise<unknown>;
95
+ getSkill(skillId: string, query?: Record<string, unknown>): Promise<unknown>;
96
+ listTools(query?: Record<string, unknown>): Promise<unknown>;
97
+ getTool(capabilityId: string, query?: Record<string, unknown>): Promise<unknown>;
98
+ runCapability(capabilityId: string, body: CapabilityRunBody, idempotencyKey?: string | null): Promise<unknown>;
99
+ getRun(id: string): Promise<unknown>;
100
+ listRuns(query?: Record<string, unknown>): Promise<unknown>;
101
+ resumeRun(id: string, body: Record<string, unknown>, idempotencyKey?: string): Promise<unknown>;
102
+ getRunEvents(id: string, query?: Record<string, unknown>): Promise<unknown>;
103
+ cancelRun(id: string, body: Record<string, unknown>, idempotencyKey?: string): Promise<unknown>;
104
+ private request;
105
+ }
106
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js ADDED
@@ -0,0 +1,265 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DreamstateClient = exports.CliError = exports.TOOL_AND_RUN_REQUEST_TIMEOUT_MS = exports.DEFAULT_REQUEST_TIMEOUT_MS = exports.CLI_VERSION = void 0;
4
+ exports.readToolEnvelopeTraceId = readToolEnvelopeTraceId;
5
+ exports.requestDeviceAuthorization = requestDeviceAuthorization;
6
+ exports.claimDeviceAuthorization = claimDeviceAuthorization;
7
+ const node_crypto_1 = require("node:crypto");
8
+ exports.CLI_VERSION = require('../package.json').version;
9
+ exports.DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
10
+ exports.TOOL_AND_RUN_REQUEST_TIMEOUT_MS = 60_000;
11
+ class CliError extends Error {
12
+ code;
13
+ status;
14
+ details;
15
+ retryAfter;
16
+ traceId;
17
+ idempotencyKey;
18
+ /** The server's retry decision and repair, forwarded unchanged so the CLI never re-derives them. */
19
+ retryable;
20
+ repair;
21
+ constructor(message, code, status, options = {}) {
22
+ super(message);
23
+ this.name = 'CliError';
24
+ this.code = code;
25
+ this.status = status;
26
+ if (options.details !== undefined)
27
+ this.details = options.details;
28
+ if (options.retryAfter !== undefined)
29
+ this.retryAfter = options.retryAfter;
30
+ if (options.traceId !== undefined)
31
+ this.traceId = options.traceId;
32
+ if (options.idempotencyKey !== undefined)
33
+ this.idempotencyKey = options.idempotencyKey;
34
+ if (options.retryable !== undefined)
35
+ this.retryable = options.retryable;
36
+ if (options.repair !== undefined)
37
+ this.repair = options.repair;
38
+ }
39
+ }
40
+ exports.CliError = CliError;
41
+ function isApiErrorBody(value) {
42
+ const error = value && typeof value === 'object' ? value.error : null;
43
+ if (!error || typeof error !== 'object')
44
+ return false;
45
+ const candidate = error;
46
+ return typeof candidate.code === 'string' && typeof candidate.message === 'string';
47
+ }
48
+ function readToolEnvelopeTraceId(value) {
49
+ const envelope = value !== null && typeof value === 'object' ? value : null;
50
+ const meta = envelope?.meta;
51
+ const traceId = meta !== null && typeof meta === 'object' ? meta.trace_id : undefined;
52
+ if (typeof traceId === 'string' && traceId.trim())
53
+ return traceId;
54
+ const details = envelope?.error && typeof envelope.error === 'object' ? envelope.error.details : undefined;
55
+ const detailTraceId = details !== null && typeof details === 'object' ? details.trace_id : undefined;
56
+ return typeof detailTraceId === 'string' && detailTraceId.trim() ? detailTraceId : undefined;
57
+ }
58
+ function queryString(query) {
59
+ const params = new URLSearchParams();
60
+ for (const [key, value] of Object.entries(query)) {
61
+ if (value === undefined || value === null)
62
+ continue;
63
+ for (const item of Array.isArray(value) ? value : [value]) {
64
+ params.append(key, typeof item === 'string' ? item : JSON.stringify(item));
65
+ }
66
+ }
67
+ const serialized = params.toString();
68
+ return serialized ? `?${serialized}` : '';
69
+ }
70
+ function retryAfter(response, body) {
71
+ const value = body.error.details && typeof body.error.details === 'object'
72
+ ? body.error.details.retry_after
73
+ : undefined;
74
+ if (typeof value === 'string' && value.trim())
75
+ return value.trim();
76
+ if (typeof value === 'number' && Number.isFinite(value))
77
+ return String(value);
78
+ return response.headers.get('Retry-After')?.trim() || undefined;
79
+ }
80
+ function versionAtMost(current, target) {
81
+ return !isVersionGreater(current, target);
82
+ }
83
+ function responseError(payload, status) {
84
+ if (isApiErrorBody(payload)) {
85
+ return new CliError(payload.error.message, payload.error.code, status, {
86
+ details: payload.error.details,
87
+ ...(typeof payload.error.retryable === 'boolean' ? { retryable: payload.error.retryable } : {}),
88
+ ...(payload.error.repair && typeof payload.error.repair === 'object' ? { repair: payload.error.repair } : {}),
89
+ });
90
+ }
91
+ const error = payload && typeof payload === 'object' ? payload.error : null;
92
+ if (error && typeof error === 'object' && typeof error.code === 'string') {
93
+ const code = error.code;
94
+ return new CliError(code, code, status);
95
+ }
96
+ return null;
97
+ }
98
+ async function requestDeviceAuthorization(baseUrl, body) {
99
+ return requestPublic(baseUrl, '/cli/login-requests', { method: 'POST', body: JSON.stringify(body) });
100
+ }
101
+ async function claimDeviceAuthorization(baseUrl, state) {
102
+ return requestPublic(baseUrl, '/cli/login-requests/claim', { method: 'POST', body: JSON.stringify({ state }) });
103
+ }
104
+ async function requestPublic(baseUrl, path, init) {
105
+ let response;
106
+ try {
107
+ response = await fetch(`${baseUrl.replace(/\/+$/, '')}${path}`, {
108
+ ...init,
109
+ headers: { Accept: 'application/json', 'Content-Type': 'application/json', 'X-Dreamstate-Client-Version': exports.CLI_VERSION, ...init.headers },
110
+ });
111
+ }
112
+ catch (error) {
113
+ throw new CliError(`Request failed: ${error instanceof Error ? error.message : String(error)}`, 'network_error', 0);
114
+ }
115
+ let payload;
116
+ try {
117
+ payload = await response.json();
118
+ }
119
+ catch {
120
+ throw new CliError(`Dreamstate API returned invalid JSON (HTTP ${response.status})`, 'invalid_response', response.status);
121
+ }
122
+ const apiError = responseError(payload, response.status);
123
+ if (apiError)
124
+ throw apiError;
125
+ if (!response.ok)
126
+ throw new CliError(`Dreamstate API request failed (HTTP ${response.status})`, 'request_failed', response.status);
127
+ const data = payload && typeof payload === 'object' ? payload.data : undefined;
128
+ if (!data || typeof data !== 'object')
129
+ throw new CliError('Dreamstate API returned invalid device authorization data.', 'invalid_response', response.status);
130
+ return data;
131
+ }
132
+ class DreamstateClient {
133
+ apiKey;
134
+ baseUrl;
135
+ requestTimeoutMs;
136
+ onVersionWarning;
137
+ constructor(options) {
138
+ this.apiKey = options.apiKey;
139
+ this.baseUrl = options.baseUrl.replace(/\/+$/, '');
140
+ this.requestTimeoutMs = options.requestTimeoutMs;
141
+ this.onVersionWarning = options.onVersionWarning;
142
+ }
143
+ getWhoami() { return this.request('/whoami'); }
144
+ listPacks(query = {}) { return this.request(`/packs${queryString(query)}`); }
145
+ getPack(packId, query = {}) {
146
+ return this.request(`/packs/${encodeURIComponent(packId)}${queryString(query)}`);
147
+ }
148
+ routePack(goal) {
149
+ return this.request(`/packs/route${queryString({ goal })}`);
150
+ }
151
+ listSkills(query = {}) {
152
+ return this.request(`/skills${queryString(query)}`);
153
+ }
154
+ searchSkillDocuments(query) {
155
+ return this.request(`/skills/search${queryString(query)}`);
156
+ }
157
+ listAllSkills() {
158
+ return this.listSkills();
159
+ }
160
+ getSkill(skillId, query = {}) {
161
+ return this.request(`/skills/${encodeURIComponent(skillId)}${queryString(query)}`);
162
+ }
163
+ listTools(query = {}) {
164
+ return this.request(`/tools${queryString(query)}`, {}, exports.TOOL_AND_RUN_REQUEST_TIMEOUT_MS);
165
+ }
166
+ getTool(capabilityId, query = {}) {
167
+ return this.request(`/tools/${encodeURIComponent(capabilityId)}${queryString(query)}`, {}, exports.TOOL_AND_RUN_REQUEST_TIMEOUT_MS);
168
+ }
169
+ runCapability(capabilityId, body, idempotencyKey) {
170
+ const key = idempotencyKey === null ? undefined : idempotencyKey ?? (0, node_crypto_1.randomUUID)();
171
+ return this.request(`/tools/${encodeURIComponent(capabilityId)}/run`, {
172
+ method: 'POST', body: JSON.stringify(body),
173
+ ...(key ? { headers: { 'Idempotency-Key': key } } : {}),
174
+ }, exports.TOOL_AND_RUN_REQUEST_TIMEOUT_MS);
175
+ }
176
+ getRun(id) {
177
+ return this.request(`/runs/${encodeURIComponent(id)}`, {}, exports.TOOL_AND_RUN_REQUEST_TIMEOUT_MS);
178
+ }
179
+ listRuns(query = {}) {
180
+ return this.request(`/runs${queryString(query)}`, {}, exports.TOOL_AND_RUN_REQUEST_TIMEOUT_MS);
181
+ }
182
+ resumeRun(id, body, idempotencyKey) {
183
+ const key = idempotencyKey ?? (0, node_crypto_1.randomUUID)();
184
+ return this.request(`/runs/${encodeURIComponent(id)}/resume`, {
185
+ method: 'POST', body: JSON.stringify(body),
186
+ headers: { 'Idempotency-Key': key },
187
+ }, exports.TOOL_AND_RUN_REQUEST_TIMEOUT_MS);
188
+ }
189
+ getRunEvents(id, query = {}) {
190
+ return this.request(`/runs/${encodeURIComponent(id)}/events${queryString(query)}`);
191
+ }
192
+ cancelRun(id, body, idempotencyKey) {
193
+ const key = idempotencyKey ?? (0, node_crypto_1.randomUUID)();
194
+ return this.request(`/runs/${encodeURIComponent(id)}/cancel`, {
195
+ method: 'POST', body: JSON.stringify(body),
196
+ ...(key ? { headers: { 'Idempotency-Key': key } } : {}),
197
+ });
198
+ }
199
+ async request(path, init = {}, defaultTimeoutMs = exports.DEFAULT_REQUEST_TIMEOUT_MS) {
200
+ const requestTimeoutMs = this.requestTimeoutMs ?? defaultTimeoutMs;
201
+ const controller = new AbortController();
202
+ const timeout = setTimeout(() => controller.abort(), requestTimeoutMs);
203
+ let response;
204
+ try {
205
+ const idempotencyKey = new Headers(init.headers).get('Idempotency-Key') ?? undefined;
206
+ try {
207
+ response = await fetch(`${this.baseUrl}${path}`, {
208
+ ...init,
209
+ signal: controller.signal,
210
+ headers: {
211
+ Accept: 'application/json', Authorization: `Bearer ${this.apiKey}`,
212
+ 'X-Dreamstate-Client-Version': exports.CLI_VERSION,
213
+ ...(init.body ? { 'Content-Type': 'application/json' } : {}), ...init.headers,
214
+ },
215
+ });
216
+ }
217
+ catch (error) {
218
+ if (controller.signal.aborted) {
219
+ throw new CliError(`Request timed out after ${requestTimeoutMs}ms`, 'request_timeout', 0, { idempotencyKey });
220
+ }
221
+ throw new CliError(`Request failed: ${error instanceof Error ? error.message : String(error)}`, 'network_error', 0);
222
+ }
223
+ let payload;
224
+ try {
225
+ payload = await response.json();
226
+ }
227
+ catch {
228
+ if (controller.signal.aborted) {
229
+ throw new CliError(`Request timed out after ${requestTimeoutMs}ms`, 'request_timeout', response.status, { idempotencyKey });
230
+ }
231
+ throw new CliError(`Dreamstate API returned invalid JSON (HTTP ${response.status})`, 'invalid_response', response.status);
232
+ }
233
+ if (isApiErrorBody(payload)) {
234
+ throw new CliError(payload.error.message, payload.error.code, response.status, {
235
+ details: payload.error.details, retryAfter: retryAfter(response, payload),
236
+ traceId: readToolEnvelopeTraceId(payload), idempotencyKey,
237
+ ...(typeof payload.error.retryable === 'boolean' ? { retryable: payload.error.retryable } : {}),
238
+ ...(payload.error.repair && typeof payload.error.repair === 'object' ? { repair: payload.error.repair } : {}),
239
+ });
240
+ }
241
+ if (!response.ok)
242
+ throw new CliError(`Dreamstate API request failed (HTTP ${response.status})`, 'request_failed', response.status);
243
+ const minimum = payload && typeof payload === 'object' ? payload.meta?.minimum_cli_version : undefined;
244
+ if (typeof minimum === 'string' && isVersionGreater(minimum, exports.CLI_VERSION)) {
245
+ throw new CliError(`CLI ${minimum} or newer is required. Run: npm install -g @trydreamstate/cli@latest`, 'cli_update_required', 0);
246
+ }
247
+ const server = payload && typeof payload === 'object' ? payload.meta?.server_version : undefined;
248
+ if (typeof server === 'string' && isVersionGreater(server, exports.CLI_VERSION) && (typeof minimum !== 'string' || versionAtMost(minimum, exports.CLI_VERSION))) {
249
+ this.onVersionWarning?.(`Warning: CLI ${exports.CLI_VERSION} is behind server ${server}. Proceeding; server minimum is ${minimum ?? 'not declared'}.`);
250
+ }
251
+ return payload;
252
+ }
253
+ finally {
254
+ clearTimeout(timeout);
255
+ }
256
+ }
257
+ }
258
+ exports.DreamstateClient = DreamstateClient;
259
+ function isVersionGreater(required, current) {
260
+ const parse = (version) => version.replace(/^v/, '').split('-')[0].split('.').map((part) => Number(part));
261
+ const [requiredMajor = 0, requiredMinor = 0, requiredPatch = 0] = parse(required);
262
+ const [currentMajor = 0, currentMinor = 0, currentPatch = 0] = parse(current);
263
+ return requiredMajor > currentMajor || (requiredMajor === currentMajor && requiredMinor > currentMinor)
264
+ || (requiredMajor === currentMajor && requiredMinor === currentMinor && requiredPatch > currentPatch);
265
+ }
@@ -0,0 +1,7 @@
1
+ import { runPackCommand, type PackVerbSpec } from './shared';
2
+ import type { CliCommand } from '../index';
3
+ export declare const SEQUENCE_VERBS: PackVerbSpec[];
4
+ export declare const SEQUENCES_USAGE: string;
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>;
7
+ //# sourceMappingURL=sequences.d.ts.map
@@ -0,0 +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,EA6BxC,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"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseSequencesCommand = exports.SEQUENCES_USAGE = exports.SEQUENCE_VERBS = void 0;
4
+ exports.runSequencesCommand = runSequencesCommand;
5
+ const shared_1 = require("./shared");
6
+ exports.SEQUENCE_VERBS = [
7
+ { verb: 'list', capabilityId: 'workflow.automations.list', summary: 'List sequences in workspace.', flags: { limit: { type: 'string', into: 'limit' }, cursor: { type: 'string', into: 'cursor' }, lifecycle: { type: 'string', into: 'lifecycle' }, 'include-archived': { type: 'boolean', into: 'include_archived' }, search: { type: 'string', into: 'search' } }, mutating: false },
8
+ // Local only: writes a starter document to disk and calls no API, so authoring can
9
+ // begin from a file. capabilityId names the verb this scaffold is meant to feed.
10
+ { verb: 'init', capabilityId: 'workflow.automations.lint', summary: 'Write a starter sequence document to a local file. Calls no API and changes nothing.', flags: { name: { type: 'string', into: 'name' }, file: { type: 'string', into: 'file' } }, mutating: false },
11
+ { verb: 'get', capabilityId: 'workflow.automations.get', summary: 'Get one sequence.', positional: [{ name: 'id', into: 'automation_id' }], mutating: false },
12
+ { verb: 'create', capabilityId: 'workflow.automations.compose', summary: 'Create draft sequence. Does not publish or send.', flags: { name: { type: 'string', into: 'name' }, description: { type: 'string', into: 'description' }, timezone: { type: 'string', into: 'timezone' }, enrollment: { type: 'string', into: 'enrollment', json: true }, 'daily-cap': { type: 'string', into: 'daily_cap' }, 'max-new-enrollments-per-day': { type: 'string', into: 'max_new_enrollments_per_day' }, senders: { type: 'string', into: 'senders', json: true }, steps: { type: 'string', into: 'steps', json: true }, 'on-duplicate-name': { type: 'string', into: 'on_duplicate_name' } }, mutating: true },
13
+ { verb: 'update', capabilityId: 'workflow.automations.update', summary: 'Update sequence draft settings. Does not publish or send.', positional: [{ name: 'id', into: 'automation_id' }], flags: { patch: { type: 'string', into: 'patch', json: true }, 'expected-version': { type: 'string', into: 'expected_version', number: true } }, mutating: true },
14
+ { verb: 'lint', capabilityId: 'workflow.automations.lint', summary: 'Lint sequence draft. Makes no changes.', positional: [{ name: 'id', into: 'automation_id' }], flags: { document: { type: 'string', into: 'document', json: true, document: true } }, mutating: false },
15
+ { verb: 'preview', capabilityId: 'workflow.automations.preview', summary: 'Preview saved sequence. Creates no run and sends nothing.', positional: [{ name: 'id', into: 'automation_id' }], mutating: false },
16
+ { verb: 'variables', capabilityId: 'workflow.automations.variables_list', summary: 'List template variables available in sequence.', positional: [{ name: 'id', into: 'automation_id' }], flags: { document: { type: 'string', into: 'document', json: true, document: true }, node: { type: 'string', into: 'node_id' }, query: { type: 'string', into: 'query' }, limit: { type: 'string', into: 'limit' } }, mutating: false },
17
+ { verb: 'node-catalog', capabilityId: 'workflow.automations.node_catalog', summary: 'List available sequence node types.', flags: { query: { type: 'string', into: 'query' }, family: { type: 'string', into: 'family' }, 'include-blocked': { type: 'boolean', into: 'include_blocked' } }, mutating: false },
18
+ { verb: 'node-inspect', capabilityId: 'workflow.automations.node_inspect', summary: 'Inspect sequence node type or saved node.', positional: [{ name: 'id', into: 'automation_id', optional: true }], flags: { node: { type: 'string', into: 'node_id' }, 'node-kind': { type: 'string', into: 'node_kind' }, subtype: { type: 'string', into: 'subtype' }, config: { type: 'string', into: 'config', json: true } }, mutating: false },
19
+ { verb: 'node-add', capabilityId: 'workflow.automations.node_add', summary: 'Add node to sequence draft. Does not publish or send.', positional: [{ name: 'id', into: 'automation_id' }], flags: { node: { type: 'string', into: 'node', json: true }, 'after-node': { type: 'string', into: 'after_node_id' }, branch: { type: 'string', into: 'branch' }, 'expected-version': { type: 'string', into: 'expected_version', number: true } }, mutating: true },
20
+ { verb: 'node-patch', capabilityId: 'workflow.automations.node_patch', summary: 'Patch sequence node. Does not publish or send.', positional: [{ name: 'id', into: 'automation_id' }], flags: { node: { type: 'string', into: 'node_id' }, fields: { type: 'string', into: 'fields', json: true }, 'expected-version': { type: 'string', into: 'expected_version', number: true } }, mutating: true },
21
+ { verb: 'node-remove', capabilityId: 'workflow.automations.node_remove', summary: 'Remove node from sequence draft. Does not publish or send.', positional: [{ name: 'id', into: 'automation_id' }], flags: { node: { type: 'string', into: 'node_id' }, 'expected-version': { type: 'string', into: 'expected_version', number: true } }, mutating: true },
22
+ { verb: 'node-move', capabilityId: 'workflow.automations.node_move', summary: 'Move sequence node. Does not publish or send.', positional: [{ name: 'id', into: 'automation_id' }], flags: { node: { type: 'string', into: 'node_id' }, 'after-node': { type: 'string', into: 'after_node_id' }, branch: { type: 'string', into: 'branch' }, 'expected-version': { type: 'string', into: 'expected_version', number: true } }, mutating: true },
23
+ { verb: 'field-options', capabilityId: 'workflow.automations.field_options', summary: 'List options for sequence node fields.', positional: [{ name: 'id', into: 'automation_id', optional: true }], flags: { node: { type: 'string', into: 'node_id' }, 'node-kind': { type: 'string', into: 'node_kind' }, subtype: { type: 'string', into: 'subtype' }, '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 },
24
+ { verb: 'publish', capabilityId: 'sequence.sequences.publish', summary: 'Publish sequence draft. Does not enroll or send.', positional: [{ name: 'id', into: 'sequence_id' }], flags: { 'sequence-version-id': { type: 'string', into: 'sequence_version_id' }, 'latest-draft-version-id': { type: 'string', into: 'latest_draft_version_id' } }, mutating: true },
25
+ { verb: 'enroll', capabilityId: 'sequence.sequences.enroll_selection', summary: 'Enroll rows into sequence. Spends no credits and sends nothing; dispatch only happens at launch.', positional: [{ name: 'id', into: 'sequence_id' }], flags: { worksheet: { type: 'string', into: 'worksheet_id' }, view: { type: 'string', into: 'view_id' }, 'enrollment-filter': { type: 'string', into: 'enrollment_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' }, 'max-new-enrollments-per-day': { type: 'string', into: 'max_new_enrollments_per_day' } }, mutating: true },
26
+ { verb: 'launch', capabilityId: 'sequence.sequences.launch', summary: 'Launch published sequence dispatch.', positional: [{ name: 'id', into: 'sequence_id' }], flags: { 'max-live-sends': { type: 'string', into: 'max_live_sends' } }, mutating: true },
27
+ { verb: 'pause', capabilityId: 'sequence.sequences.pause', summary: 'Pause sequence dispatch. Sends no new messages.', positional: [{ name: 'id', into: 'sequence_id' }], mutating: true },
28
+ { 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 },
29
+ { verb: 'stats', capabilityId: 'sequence.sequences.step_counts_get', summary: 'Get sequence step counts.', positional: [{ name: 'id', into: 'sequence_id' }], mutating: false },
30
+ { 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 },
31
+ { 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 },
32
+ { 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 },
33
+ { verb: 'export', capabilityId: 'workflow.automations.export', summary: 'Export sequence definition. Makes no changes.', positional: [{ name: 'id', into: 'automation_id' }], mutating: false },
34
+ { verb: 'import', capabilityId: 'workflow.automations.import', summary: 'Import sequence as draft. Does not publish or send.', flags: { name: { type: 'string', into: 'name' }, document: { type: 'string', into: 'document', json: true, document: true } }, mutating: true },
35
+ ];
36
+ exports.SEQUENCES_USAGE = (0, shared_1.renderPackUsage)('sequences', exports.SEQUENCE_VERBS);
37
+ exports.parseSequencesCommand = (0, shared_1.buildPackParser)('sequences', 'sequence', exports.SEQUENCE_VERBS, exports.SEQUENCES_USAGE);
38
+ async function runSequencesCommand(client, command, stdout) {
39
+ if (command.command === 'pack' && command.verb === 'init') {
40
+ (0, shared_1.runPackInit)('sequence', command, stdout);
41
+ return;
42
+ }
43
+ await (0, shared_1.runPackCommand)(client, command, stdout);
44
+ }
@@ -0,0 +1,53 @@
1
+ import type { DreamstateClient } from '../client';
2
+ import { type CliCommand } from '../index';
3
+ export interface PackVerbSpec {
4
+ verb: string;
5
+ capabilityId: string;
6
+ summary: string;
7
+ /**
8
+ * `optional: true` marks a positional the verb can do without. node-inspect and
9
+ * field-options answer two different questions: the contract for a node TYPE, which
10
+ * needs no automation at all, and the state of one saved node, which needs an id.
11
+ * Requiring the id for both meant reading a type's schema was impossible without
12
+ * first creating something to read it from.
13
+ */
14
+ positional?: {
15
+ name: string;
16
+ into: string;
17
+ optional?: boolean;
18
+ }[];
19
+ /**
20
+ * `document: true` marks the ONE flag that carries a whole authored document, so
21
+ * --file knows where to put a file's contents. Without it --file bound to whichever
22
+ * json flag happened to be declared first, which on `sequences create` was
23
+ * `enrollment`: a whole sequence document arrived as the enrollment binding and the
24
+ * server refused it field by field. Flag order is not a contract, so the document
25
+ * flag has to say so itself.
26
+ */
27
+ /**
28
+ * `number: true` marks a flag whose capability param is numeric. Every flag arrives
29
+ * from the shell as a string, so `--expected-version 1` was sent as "1" and refused
30
+ * with `params.expected_version: expected number; received string`: the optimistic
31
+ * concurrency check could not be satisfied from the CLI at all.
32
+ */
33
+ flags?: Record<string, {
34
+ type: 'string' | 'boolean';
35
+ into: string;
36
+ json?: boolean;
37
+ document?: boolean;
38
+ number?: boolean;
39
+ }>;
40
+ mutating: boolean;
41
+ }
42
+ export declare function buildPackParser(pack: 'sequences' | 'workflows', kind: 'sequence' | 'workflow', specs: PackVerbSpec[], usage: string): (argv: string[]) => CliCommand;
43
+ /**
44
+ * A starter document written to disk, so authoring can begin from a file the way the
45
+ * rest of this pack now accepts one. It writes nothing to the workspace and calls no
46
+ * API: the point is to hand back something `lint --file` will accept and refuse
47
+ * usefully, rather than to guess a valid sequence on the caller's behalf.
48
+ */
49
+ export declare function packScaffold(kind: 'sequence' | 'workflow', name: string): Record<string, unknown>;
50
+ 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 renderPackUsage(pack: string, specs: PackVerbSpec[]): string;
53
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +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,CAmBhI;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,MAAM,CAE3E"}