@ted-galago/wave-cli 0.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/dist/index.cjs ADDED
@@ -0,0 +1,1079 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ // src/index.ts
5
+ var import_commander2 = require("commander");
6
+ var import_zod9 = require("zod");
7
+
8
+ // src/cli.ts
9
+ var import_commander = require("commander");
10
+
11
+ // src/commands/tasks.ts
12
+ var import_zod2 = require("zod");
13
+
14
+ // src/config.ts
15
+ var import_zod = require("zod");
16
+
17
+ // src/errors.ts
18
+ var EXIT_CODES = {
19
+ success: 0,
20
+ generic: 1,
21
+ invalidArgs: 2,
22
+ missingOrInvalidAuth: 3,
23
+ forbidden: 4,
24
+ notFound: 5,
25
+ validationFailure: 6,
26
+ networkOrUpstream: 7
27
+ };
28
+ var CliError = class extends Error {
29
+ kind;
30
+ status;
31
+ details;
32
+ exitCode;
33
+ constructor(params) {
34
+ super(params.message);
35
+ this.name = "CliError";
36
+ this.kind = params.kind;
37
+ this.status = params.status;
38
+ this.exitCode = params.exitCode;
39
+ this.details = params.details ?? {};
40
+ }
41
+ };
42
+ function mapStatusToExitCode(status) {
43
+ if (status === 401) {
44
+ return EXIT_CODES.missingOrInvalidAuth;
45
+ }
46
+ if (status === 403) {
47
+ return EXIT_CODES.forbidden;
48
+ }
49
+ if (status === 404) {
50
+ return EXIT_CODES.notFound;
51
+ }
52
+ if (status === 400 || status === 422) {
53
+ return EXIT_CODES.validationFailure;
54
+ }
55
+ if (status >= 500) {
56
+ return EXIT_CODES.networkOrUpstream;
57
+ }
58
+ return EXIT_CODES.generic;
59
+ }
60
+
61
+ // src/config.ts
62
+ var DEFAULT_TIMEOUT_MS = 1e4;
63
+ var configSchema = import_zod.z.object({
64
+ baseUrl: import_zod.z.url(),
65
+ token: import_zod.z.string().min(1),
66
+ timeoutMs: import_zod.z.number().int().positive(),
67
+ debug: import_zod.z.boolean(),
68
+ agentName: import_zod.z.string().min(1).optional(),
69
+ agentRunId: import_zod.z.string().min(1).optional(),
70
+ requestId: import_zod.z.string().min(1).optional(),
71
+ openapiPath: import_zod.z.string().min(1).optional(),
72
+ openapiUrl: import_zod.z.url().optional(),
73
+ openapiVersion: import_zod.z.string().min(1).optional()
74
+ });
75
+ function parseTimeoutMs(raw) {
76
+ if (typeof raw === "number" && Number.isFinite(raw) && raw > 0) {
77
+ return raw;
78
+ }
79
+ if (typeof raw === "string" && raw.trim() !== "") {
80
+ const parsed = Number(raw);
81
+ if (Number.isFinite(parsed) && parsed > 0) {
82
+ return parsed;
83
+ }
84
+ }
85
+ return DEFAULT_TIMEOUT_MS;
86
+ }
87
+ function toOptionalNonEmpty(raw) {
88
+ if (typeof raw !== "string") {
89
+ return void 0;
90
+ }
91
+ const trimmed = raw.trim();
92
+ return trimmed.length > 0 ? trimmed : void 0;
93
+ }
94
+ function parseDebug(rawDebugOption, rawDebugEnv) {
95
+ if (typeof rawDebugOption === "boolean") {
96
+ return rawDebugOption;
97
+ }
98
+ if (!rawDebugEnv) {
99
+ return false;
100
+ }
101
+ const lowered = rawDebugEnv.toLowerCase();
102
+ return lowered === "1" || lowered === "true" || lowered === "yes";
103
+ }
104
+ function getConfig(options) {
105
+ const token = process.env.WAVE_API_TOKEN ?? process.env.WAVE_JWT ?? options.token ?? options.jwt;
106
+ if (!token) {
107
+ throw new CliError({
108
+ message: "Missing API token. Set WAVE_API_TOKEN (or WAVE_JWT) or pass --token/--jwt.",
109
+ kind: "missing_auth",
110
+ status: 401,
111
+ exitCode: EXIT_CODES.missingOrInvalidAuth
112
+ });
113
+ }
114
+ const baseUrl = options.baseUrl ?? process.env.WAVE_API_BASE_URL ?? process.env.WAVE_API_URL;
115
+ if (!baseUrl) {
116
+ throw new CliError({
117
+ message: "Missing API base URL. Set WAVE_API_BASE_URL (or WAVE_API_URL) or pass --base-url.",
118
+ kind: "invalid_args",
119
+ status: 400,
120
+ exitCode: EXIT_CODES.invalidArgs
121
+ });
122
+ }
123
+ const parsed = configSchema.safeParse({
124
+ baseUrl,
125
+ token,
126
+ timeoutMs: parseTimeoutMs(options.timeoutMs ?? process.env.WAVE_TIMEOUT_MS),
127
+ debug: parseDebug(options.debug, process.env.WAVE_DEBUG),
128
+ agentName: toOptionalNonEmpty(options.agentName ?? process.env.WAVE_AGENT_NAME),
129
+ agentRunId: toOptionalNonEmpty(options.agentRunId ?? process.env.WAVE_AGENT_RUN_ID),
130
+ requestId: toOptionalNonEmpty(options.requestId ?? process.env.WAVE_REQUEST_ID),
131
+ openapiPath: toOptionalNonEmpty(options.openapiPath ?? process.env.WAVE_OPENAPI_PATH),
132
+ openapiUrl: toOptionalNonEmpty(options.openapiUrl ?? process.env.WAVE_OPENAPI_URL),
133
+ openapiVersion: toOptionalNonEmpty(
134
+ options.openapiVersion ?? process.env.WAVE_OPENAPI_VERSION
135
+ )
136
+ });
137
+ if (!parsed.success) {
138
+ throw new CliError({
139
+ message: "Invalid CLI configuration.",
140
+ kind: "invalid_args",
141
+ status: 400,
142
+ exitCode: EXIT_CODES.invalidArgs,
143
+ details: { issues: parsed.error.issues }
144
+ });
145
+ }
146
+ return parsed.data;
147
+ }
148
+
149
+ // src/client/httpClient.ts
150
+ var import_node_crypto = require("crypto");
151
+ function buildEnvelope(params) {
152
+ return {
153
+ ok: params.ok,
154
+ command: params.command,
155
+ status: params.status,
156
+ data: params.data,
157
+ error: params.error,
158
+ meta: { requestId: params.requestId }
159
+ };
160
+ }
161
+ function parseJsonSafely(input) {
162
+ try {
163
+ return JSON.parse(input);
164
+ } catch {
165
+ return null;
166
+ }
167
+ }
168
+ function redactForLogs(value) {
169
+ if (value.length <= 8) {
170
+ return "[redacted]";
171
+ }
172
+ return `${value.slice(0, 4)}...[redacted]...${value.slice(-4)}`;
173
+ }
174
+ function debugLog(config, message) {
175
+ if (!config.debug) {
176
+ return;
177
+ }
178
+ process.stderr.write(`[wave:debug] ${message}
179
+ `);
180
+ }
181
+ async function executeFetch(params) {
182
+ const controller = new AbortController();
183
+ const timeoutId = setTimeout(() => controller.abort(), params.input.config.timeoutMs);
184
+ try {
185
+ return await fetch(params.url, {
186
+ method: params.input.method,
187
+ headers: {
188
+ Authorization: `Bearer ${params.input.config.token}`,
189
+ Accept: "application/json",
190
+ "Content-Type": "application/json",
191
+ "X-Origin": "langgraph-cli",
192
+ "X-Request-Id": params.requestId,
193
+ ...params.input.config.agentName ? { "X-Agent-Name": params.input.config.agentName } : {},
194
+ ...params.input.config.agentRunId ? { "X-Agent-Run-Id": params.input.config.agentRunId } : {}
195
+ },
196
+ body: params.input.body && params.input.method !== "GET" ? JSON.stringify(params.input.body) : void 0,
197
+ signal: controller.signal
198
+ });
199
+ } finally {
200
+ clearTimeout(timeoutId);
201
+ }
202
+ }
203
+ function errorFromPayload(payload, status) {
204
+ if (typeof payload === "object" && payload !== null) {
205
+ const asRecord = payload;
206
+ if ("error" in asRecord && typeof asRecord.error === "object" && asRecord.error !== null) {
207
+ const inner = asRecord.error;
208
+ return {
209
+ code: String(inner.code ?? `http_${status}`),
210
+ message: String(inner.message ?? "Request failed."),
211
+ details: typeof inner.details === "object" && inner.details !== null ? inner.details : {}
212
+ };
213
+ }
214
+ }
215
+ return {
216
+ code: `http_${status}`,
217
+ message: `HTTP ${status}`,
218
+ details: {}
219
+ };
220
+ }
221
+ async function httpRequest(input) {
222
+ const base = new URL(input.config.baseUrl);
223
+ const url = new URL(input.path, base);
224
+ const requestId = input.config.requestId ?? (0, import_node_crypto.randomUUID)();
225
+ const maxAttempts = input.method === "GET" ? 2 : 1;
226
+ debugLog(
227
+ input.config,
228
+ `request command=${input.command} method=${input.method} url=${url.toString()} token=${redactForLogs(
229
+ input.config.token
230
+ )}`
231
+ );
232
+ let attempt = 0;
233
+ while (attempt < maxAttempts) {
234
+ attempt += 1;
235
+ try {
236
+ const response = await executeFetch({ requestId, url, input });
237
+ const responseRequestId = response.headers.get("x-request-id") ?? requestId;
238
+ const text = await response.text();
239
+ const payload = text ? parseJsonSafely(text) : null;
240
+ if (response.ok) {
241
+ return {
242
+ envelope: buildEnvelope({
243
+ ok: true,
244
+ command: input.command,
245
+ status: response.status,
246
+ data: payload && typeof payload === "object" ? payload : { value: payload },
247
+ error: null,
248
+ requestId: responseRequestId
249
+ }),
250
+ exitCode: EXIT_CODES.success
251
+ };
252
+ }
253
+ return {
254
+ envelope: buildEnvelope({
255
+ ok: false,
256
+ command: input.command,
257
+ status: response.status,
258
+ data: null,
259
+ error: errorFromPayload(payload, response.status),
260
+ requestId: responseRequestId
261
+ }),
262
+ exitCode: mapStatusToExitCode(response.status)
263
+ };
264
+ } catch (error) {
265
+ const isRetryable = input.method === "GET" && attempt < maxAttempts;
266
+ if (isRetryable) {
267
+ debugLog(input.config, `retry command=${input.command} attempt=${attempt + 1}`);
268
+ continue;
269
+ }
270
+ const message = error instanceof Error ? error.message : "Network error.";
271
+ const status = 503;
272
+ return {
273
+ envelope: buildEnvelope({
274
+ ok: false,
275
+ command: input.command,
276
+ status,
277
+ data: null,
278
+ error: {
279
+ code: "network_error",
280
+ message,
281
+ details: {}
282
+ },
283
+ requestId
284
+ }),
285
+ exitCode: EXIT_CODES.networkOrUpstream
286
+ };
287
+ }
288
+ }
289
+ return {
290
+ envelope: buildEnvelope({
291
+ ok: false,
292
+ command: input.command,
293
+ status: 503,
294
+ data: null,
295
+ error: {
296
+ code: "network_error",
297
+ message: "Network request failed.",
298
+ details: {}
299
+ },
300
+ requestId
301
+ }),
302
+ exitCode: EXIT_CODES.networkOrUpstream
303
+ };
304
+ }
305
+
306
+ // src/output.ts
307
+ function printEnvelope(envelope) {
308
+ process.stdout.write(`${JSON.stringify(envelope)}
309
+ `);
310
+ }
311
+ function printEnvelopeAndExit(params) {
312
+ printEnvelope(params.envelope);
313
+ process.exit(params.exitCode ?? EXIT_CODES.success);
314
+ }
315
+
316
+ // src/commandRunner.ts
317
+ function buildCliErrorEnvelope(params) {
318
+ return {
319
+ ok: false,
320
+ command: params.command,
321
+ status: params.status,
322
+ data: null,
323
+ error: {
324
+ code: params.code,
325
+ message: params.message,
326
+ details: params.details ?? {}
327
+ },
328
+ meta: {
329
+ requestId: "local_error"
330
+ }
331
+ };
332
+ }
333
+ async function runApiCommand(input) {
334
+ try {
335
+ const config = getConfig(input.runtimeOptions);
336
+ const result = await httpRequest({
337
+ config,
338
+ command: input.command,
339
+ method: input.method,
340
+ path: input.path,
341
+ body: input.body
342
+ });
343
+ printEnvelopeAndExit(result);
344
+ } catch (error) {
345
+ if (error instanceof CliError) {
346
+ printEnvelopeAndExit({
347
+ envelope: buildCliErrorEnvelope({
348
+ command: input.command,
349
+ status: error.status,
350
+ code: error.kind,
351
+ message: error.message,
352
+ details: error.details
353
+ }),
354
+ exitCode: error.exitCode
355
+ });
356
+ }
357
+ const message = error instanceof Error ? error.message : "Unexpected error.";
358
+ printEnvelopeAndExit({
359
+ envelope: buildCliErrorEnvelope({
360
+ command: input.command,
361
+ status: 500,
362
+ code: "generic_error",
363
+ message
364
+ }),
365
+ exitCode: EXIT_CODES.generic
366
+ });
367
+ }
368
+ }
369
+
370
+ // src/commands/runtimeOptions.ts
371
+ function pickRuntimeOptions(options) {
372
+ return {
373
+ token: options.token,
374
+ jwt: options.jwt,
375
+ baseUrl: options.baseUrl,
376
+ timeoutMs: options.timeoutMs,
377
+ debug: options.debug,
378
+ agentName: options.agentName,
379
+ agentRunId: options.agentRunId,
380
+ requestId: options.requestId,
381
+ openapiPath: options.openapiPath,
382
+ openapiUrl: options.openapiUrl,
383
+ openapiVersion: options.openapiVersion
384
+ };
385
+ }
386
+
387
+ // src/commands/organization.ts
388
+ function normalize(input) {
389
+ if (!input) {
390
+ return void 0;
391
+ }
392
+ const trimmed = input.trim();
393
+ return trimmed.length > 0 ? trimmed : void 0;
394
+ }
395
+ function resolveOrganizationId(raw) {
396
+ const organizationId = normalize(process.env.WAVE_ORGANIZATION_ID) ?? normalize(process.env.WAVE_ORG_ID) ?? normalize(raw);
397
+ if (!organizationId) {
398
+ throw new CliError({
399
+ message: "Missing organization ID. Set WAVE_ORGANIZATION_ID (or WAVE_ORG_ID) or pass --organization-id.",
400
+ kind: "invalid_args",
401
+ status: 400,
402
+ exitCode: EXIT_CODES.invalidArgs
403
+ });
404
+ }
405
+ return organizationId;
406
+ }
407
+
408
+ // src/commands/tasks.ts
409
+ var projectIdSchema = import_zod2.z.string().min(1);
410
+ var idSchema = import_zod2.z.string().min(1);
411
+ var summarySchema = import_zod2.z.string().min(1);
412
+ function registerTaskCommands(program) {
413
+ const tasks = program.command("tasks").description("Task operations");
414
+ tasks.command("list").requiredOption("--project-id <projectId>").action(async (opts, cmd) => {
415
+ const projectId = projectIdSchema.parse(opts.projectId);
416
+ const globalOpts = cmd.optsWithGlobals();
417
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
418
+ await runApiCommand({
419
+ command: "tasks.list",
420
+ runtimeOptions: pickRuntimeOptions(globalOpts),
421
+ method: "GET",
422
+ path: `/organizations/${encodeURIComponent(organizationId)}/tasks?project_id=${encodeURIComponent(projectId)}`
423
+ });
424
+ });
425
+ tasks.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
426
+ const parsed = idSchema.parse(opts.id);
427
+ const globalOpts = cmd.optsWithGlobals();
428
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
429
+ await runApiCommand({
430
+ command: "tasks.show",
431
+ runtimeOptions: pickRuntimeOptions(globalOpts),
432
+ method: "GET",
433
+ path: `/organizations/${encodeURIComponent(organizationId)}/tasks/${encodeURIComponent(parsed)}`
434
+ });
435
+ });
436
+ tasks.command("create").requiredOption("--project-id <projectId>").option("--title <title>", "Legacy alias for --summary").option("--summary <summary>").action(async (opts, cmd) => {
437
+ const projectId = projectIdSchema.parse(opts.projectId);
438
+ const summary = summarySchema.parse(opts.summary ?? opts.title);
439
+ const globalOpts = cmd.optsWithGlobals();
440
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
441
+ await runApiCommand({
442
+ command: "tasks.create",
443
+ runtimeOptions: pickRuntimeOptions(globalOpts),
444
+ method: "POST",
445
+ path: `/organizations/${encodeURIComponent(organizationId)}/tasks`,
446
+ body: {
447
+ task: {
448
+ project_id: projectId,
449
+ summary
450
+ }
451
+ }
452
+ });
453
+ });
454
+ tasks.command("update").requiredOption("--id <id>").option("--summary <summary>").option("--description <description>").option("--status <status>").option("--priority <priority>").option("--due-date <dueDate>").option("--member-id <memberId>").action(async (opts, cmd) => {
455
+ const id = idSchema.parse(opts.id);
456
+ const globalOpts = cmd.optsWithGlobals();
457
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
458
+ const taskPayload = {
459
+ ...opts.summary ? { summary: String(opts.summary) } : {},
460
+ ...opts.description ? { description: String(opts.description) } : {},
461
+ ...opts.status ? { status: String(opts.status) } : {},
462
+ ...opts.priority ? { priority: String(opts.priority) } : {},
463
+ ...opts.dueDate ? { due_date: String(opts.dueDate) } : {},
464
+ ...opts.memberId ? { member_id: String(opts.memberId) } : {}
465
+ };
466
+ if (Object.keys(taskPayload).length === 0) {
467
+ throw new CliError({
468
+ message: "tasks update requires at least one patch field (summary, description, status, priority, due-date, member-id).",
469
+ kind: "invalid_args",
470
+ status: 400,
471
+ exitCode: EXIT_CODES.invalidArgs
472
+ });
473
+ }
474
+ await runApiCommand({
475
+ command: "tasks.update",
476
+ runtimeOptions: pickRuntimeOptions(globalOpts),
477
+ method: "PATCH",
478
+ path: `/organizations/${encodeURIComponent(organizationId)}/tasks/${encodeURIComponent(id)}`,
479
+ body: {
480
+ task: taskPayload
481
+ }
482
+ });
483
+ });
484
+ }
485
+
486
+ // src/commands/projects.ts
487
+ var import_zod4 = require("zod");
488
+
489
+ // src/commands/entityCrud.ts
490
+ var import_zod3 = require("zod");
491
+ var idSchema2 = import_zod3.z.string().min(1);
492
+ function parseJsonObject(raw) {
493
+ try {
494
+ const parsed = JSON.parse(raw);
495
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
496
+ throw new Error("JSON payload must be an object.");
497
+ }
498
+ return parsed;
499
+ } catch (error) {
500
+ throw new CliError({
501
+ message: error instanceof Error ? `Invalid --data-json: ${error.message}` : "Invalid --data-json.",
502
+ kind: "invalid_args",
503
+ status: 400,
504
+ exitCode: EXIT_CODES.invalidArgs
505
+ });
506
+ }
507
+ }
508
+ function normalizeBody(raw, rootKey) {
509
+ const payload = parseJsonObject(raw);
510
+ const rooted = payload[rootKey];
511
+ if (rooted && typeof rooted === "object" && !Array.isArray(rooted)) {
512
+ return payload;
513
+ }
514
+ return { [rootKey]: payload };
515
+ }
516
+ function assertRequiredCreateFields(body, rootKey, requiredFields) {
517
+ if (!requiredFields || requiredFields.length === 0) {
518
+ return;
519
+ }
520
+ const entity = body[rootKey];
521
+ if (!entity || typeof entity !== "object" || Array.isArray(entity)) {
522
+ throw new CliError({
523
+ message: `Invalid payload. Expected object at "${rootKey}".`,
524
+ kind: "invalid_args",
525
+ status: 400,
526
+ exitCode: EXIT_CODES.invalidArgs
527
+ });
528
+ }
529
+ const entityRecord = entity;
530
+ const missing = requiredFields.filter((field) => {
531
+ const value = entityRecord[field];
532
+ return !(typeof value === "string" && value.trim().length > 0);
533
+ });
534
+ if (missing.length > 0) {
535
+ throw new CliError({
536
+ message: `Missing required create fields for ${rootKey}: ${missing.join(", ")}.`,
537
+ kind: "invalid_args",
538
+ status: 400,
539
+ exitCode: EXIT_CODES.invalidArgs,
540
+ details: { requiredFields, rootKey }
541
+ });
542
+ }
543
+ }
544
+ function registerEntityCrudCommands(program, config) {
545
+ const entityCommand = program.command(config.command).description(config.description);
546
+ entityCommand.command("create").requiredOption("--data-json <dataJson>", "JSON object, optionally wrapped with root key").action(async (opts, cmd) => {
547
+ const globalOpts = cmd.optsWithGlobals();
548
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
549
+ const body = normalizeBody(String(opts.dataJson), config.rootKey);
550
+ assertRequiredCreateFields(body, config.rootKey, config.requiredCreateFields);
551
+ await runApiCommand({
552
+ command: `${config.command}.create`,
553
+ runtimeOptions: pickRuntimeOptions(globalOpts),
554
+ method: "POST",
555
+ path: `/organizations/${encodeURIComponent(organizationId)}/${config.resourcePath}`,
556
+ body
557
+ });
558
+ });
559
+ entityCommand.command("update").requiredOption("--id <id>").requiredOption("--data-json <dataJson>", "JSON object, optionally wrapped with root key").action(async (opts, cmd) => {
560
+ const id = idSchema2.parse(opts.id);
561
+ const globalOpts = cmd.optsWithGlobals();
562
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
563
+ const body = normalizeBody(String(opts.dataJson), config.rootKey);
564
+ await runApiCommand({
565
+ command: `${config.command}.update`,
566
+ runtimeOptions: pickRuntimeOptions(globalOpts),
567
+ method: "PATCH",
568
+ path: `/organizations/${encodeURIComponent(organizationId)}/${config.resourcePath}/${encodeURIComponent(id)}`,
569
+ body
570
+ });
571
+ });
572
+ }
573
+ var __testables = {
574
+ parseJsonObject,
575
+ normalizeBody,
576
+ assertRequiredCreateFields
577
+ };
578
+
579
+ // src/commands/projects.ts
580
+ var idSchema3 = import_zod4.z.string().min(1);
581
+ function registerProjectCommands(program) {
582
+ const projects = program.command("projects").description("Project operations");
583
+ projects.command("list").action(async (_opts, cmd) => {
584
+ const globalOpts = cmd.optsWithGlobals();
585
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
586
+ await runApiCommand({
587
+ command: "projects.list",
588
+ runtimeOptions: pickRuntimeOptions(globalOpts),
589
+ method: "GET",
590
+ path: `/organizations/${encodeURIComponent(organizationId)}/projects`
591
+ });
592
+ });
593
+ projects.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
594
+ const id = idSchema3.parse(opts.id);
595
+ const globalOpts = cmd.optsWithGlobals();
596
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
597
+ await runApiCommand({
598
+ command: "projects.show",
599
+ runtimeOptions: pickRuntimeOptions(globalOpts),
600
+ method: "GET",
601
+ path: `/organizations/${encodeURIComponent(organizationId)}/projects/${encodeURIComponent(id)}`
602
+ });
603
+ });
604
+ projects.command("create").requiredOption("--data-json <dataJson>", 'JSON object for project or {"project": {...}}').action(async (opts, cmd) => {
605
+ const globalOpts = cmd.optsWithGlobals();
606
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
607
+ const body = __testables.normalizeBody(String(opts.dataJson), "project");
608
+ await runApiCommand({
609
+ command: "projects.create",
610
+ runtimeOptions: pickRuntimeOptions(globalOpts),
611
+ method: "POST",
612
+ path: `/organizations/${encodeURIComponent(organizationId)}/projects`,
613
+ body
614
+ });
615
+ });
616
+ projects.command("update").requiredOption("--id <id>").requiredOption("--data-json <dataJson>", 'JSON object for project or {"project": {...}}').action(async (opts, cmd) => {
617
+ const id = idSchema3.parse(opts.id);
618
+ const globalOpts = cmd.optsWithGlobals();
619
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
620
+ const body = __testables.normalizeBody(String(opts.dataJson), "project");
621
+ await runApiCommand({
622
+ command: "projects.update",
623
+ runtimeOptions: pickRuntimeOptions(globalOpts),
624
+ method: "PATCH",
625
+ path: `/organizations/${encodeURIComponent(organizationId)}/projects/${encodeURIComponent(id)}`,
626
+ body
627
+ });
628
+ });
629
+ }
630
+
631
+ // src/commands/rocks.ts
632
+ var import_zod5 = require("zod");
633
+ var idSchema4 = import_zod5.z.string().min(1);
634
+ var rockCollectionIdSchema = import_zod5.z.string().min(1);
635
+ var statusSchema = import_zod5.z.enum(["on_track", "at_risk", "off_track"]);
636
+ function registerRockCommands(program) {
637
+ const rocks = program.command("rocks").description("Rock operations");
638
+ rocks.command("list").option("--rock-collection-id <rockCollectionId>").action(async (opts, cmd) => {
639
+ const globalOpts = cmd.optsWithGlobals();
640
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
641
+ const rockCollectionId = opts.rockCollectionId ? rockCollectionIdSchema.parse(opts.rockCollectionId) : void 0;
642
+ await runApiCommand({
643
+ command: "rocks.list",
644
+ runtimeOptions: pickRuntimeOptions(globalOpts),
645
+ method: "GET",
646
+ path: rockCollectionId ? `/organizations/${encodeURIComponent(organizationId)}/rocks?rock_collection_id=${encodeURIComponent(rockCollectionId)}` : `/organizations/${encodeURIComponent(organizationId)}/rocks`
647
+ });
648
+ });
649
+ rocks.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
650
+ const id = idSchema4.parse(opts.id);
651
+ const globalOpts = cmd.optsWithGlobals();
652
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
653
+ await runApiCommand({
654
+ command: "rocks.show",
655
+ runtimeOptions: pickRuntimeOptions(globalOpts),
656
+ method: "GET",
657
+ path: `/organizations/${encodeURIComponent(organizationId)}/rocks/${encodeURIComponent(id)}`
658
+ });
659
+ });
660
+ rocks.command("update-status").requiredOption("--id <id>").requiredOption("--status <status>").action(async (opts, cmd) => {
661
+ const id = idSchema4.parse(opts.id);
662
+ const status = statusSchema.parse(opts.status);
663
+ const globalOpts = cmd.optsWithGlobals();
664
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
665
+ await runApiCommand({
666
+ command: "rocks.update-status",
667
+ runtimeOptions: pickRuntimeOptions(globalOpts),
668
+ method: "PATCH",
669
+ path: `/organizations/${encodeURIComponent(organizationId)}/rocks/${encodeURIComponent(id)}`,
670
+ body: { rock: { status } }
671
+ });
672
+ });
673
+ rocks.command("create").requiredOption("--data-json <dataJson>", 'JSON object for rock or {"rock": {...}}').action(async (opts, cmd) => {
674
+ const globalOpts = cmd.optsWithGlobals();
675
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
676
+ const body = __testables.normalizeBody(String(opts.dataJson), "rock");
677
+ __testables.assertRequiredCreateFields(body, "rock", ["rock_collection_id"]);
678
+ await runApiCommand({
679
+ command: "rocks.create",
680
+ runtimeOptions: pickRuntimeOptions(globalOpts),
681
+ method: "POST",
682
+ path: `/organizations/${encodeURIComponent(organizationId)}/rocks`,
683
+ body
684
+ });
685
+ });
686
+ rocks.command("update").requiredOption("--id <id>").requiredOption("--data-json <dataJson>", 'JSON object for rock or {"rock": {...}}').action(async (opts, cmd) => {
687
+ const id = idSchema4.parse(opts.id);
688
+ const globalOpts = cmd.optsWithGlobals();
689
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
690
+ const body = __testables.normalizeBody(String(opts.dataJson), "rock");
691
+ await runApiCommand({
692
+ command: "rocks.update",
693
+ runtimeOptions: pickRuntimeOptions(globalOpts),
694
+ method: "PATCH",
695
+ path: `/organizations/${encodeURIComponent(organizationId)}/rocks/${encodeURIComponent(id)}`,
696
+ body
697
+ });
698
+ });
699
+ }
700
+
701
+ // src/commands/meetings.ts
702
+ var import_zod6 = require("zod");
703
+ var idSchema5 = import_zod6.z.string().min(1);
704
+ var notesSchema = import_zod6.z.string().min(1);
705
+ function registerMeetingCommands(program) {
706
+ const meetings = program.command("meetings").description("Meeting operations");
707
+ meetings.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
708
+ const id = idSchema5.parse(opts.id);
709
+ const globalOpts = cmd.optsWithGlobals();
710
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
711
+ await runApiCommand({
712
+ command: "meetings.show",
713
+ runtimeOptions: pickRuntimeOptions(globalOpts),
714
+ method: "GET",
715
+ path: `/organizations/${encodeURIComponent(organizationId)}/meetings/${encodeURIComponent(id)}`
716
+ });
717
+ });
718
+ meetings.command("notes").requiredOption("--id <id>").requiredOption("--content <content>").action(async (opts, cmd) => {
719
+ const id = idSchema5.parse(opts.id);
720
+ const notes = notesSchema.parse(opts.content);
721
+ const globalOpts = cmd.optsWithGlobals();
722
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
723
+ await runApiCommand({
724
+ command: "meeting-notes.create",
725
+ runtimeOptions: pickRuntimeOptions(globalOpts),
726
+ method: "PATCH",
727
+ path: `/organizations/${encodeURIComponent(organizationId)}/meetings/${encodeURIComponent(id)}`,
728
+ body: {
729
+ meeting: {
730
+ notes
731
+ }
732
+ }
733
+ });
734
+ });
735
+ meetings.command("create").requiredOption("--data-json <dataJson>", 'JSON object for meeting or {"meeting": {...}}').action(async (opts, cmd) => {
736
+ const globalOpts = cmd.optsWithGlobals();
737
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
738
+ const body = __testables.normalizeBody(String(opts.dataJson), "meeting");
739
+ await runApiCommand({
740
+ command: "meetings.create",
741
+ runtimeOptions: pickRuntimeOptions(globalOpts),
742
+ method: "POST",
743
+ path: `/organizations/${encodeURIComponent(organizationId)}/meetings`,
744
+ body
745
+ });
746
+ });
747
+ meetings.command("update").requiredOption("--id <id>").requiredOption("--data-json <dataJson>", 'JSON object for meeting or {"meeting": {...}}').action(async (opts, cmd) => {
748
+ const id = idSchema5.parse(opts.id);
749
+ const globalOpts = cmd.optsWithGlobals();
750
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
751
+ const body = __testables.normalizeBody(String(opts.dataJson), "meeting");
752
+ await runApiCommand({
753
+ command: "meetings.update",
754
+ runtimeOptions: pickRuntimeOptions(globalOpts),
755
+ method: "PATCH",
756
+ path: `/organizations/${encodeURIComponent(organizationId)}/meetings/${encodeURIComponent(id)}`,
757
+ body
758
+ });
759
+ });
760
+ }
761
+
762
+ // src/commands/members.ts
763
+ var import_zod7 = require("zod");
764
+ var idSchema6 = import_zod7.z.string().min(1);
765
+ function registerMemberCommands(program) {
766
+ const members = program.command("members").description("Member operations");
767
+ members.command("list").action(async (_opts, cmd) => {
768
+ const globalOpts = cmd.optsWithGlobals();
769
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
770
+ await runApiCommand({
771
+ command: "members.list",
772
+ runtimeOptions: pickRuntimeOptions(globalOpts),
773
+ method: "GET",
774
+ path: `/organizations/${encodeURIComponent(organizationId)}/members`
775
+ });
776
+ });
777
+ members.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
778
+ const id = idSchema6.parse(opts.id);
779
+ const globalOpts = cmd.optsWithGlobals();
780
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
781
+ await runApiCommand({
782
+ command: "members.show",
783
+ runtimeOptions: pickRuntimeOptions(globalOpts),
784
+ method: "GET",
785
+ path: `/organizations/${encodeURIComponent(organizationId)}/members/${encodeURIComponent(id)}`
786
+ });
787
+ });
788
+ members.command("create").requiredOption("--data-json <dataJson>", 'JSON object for member or {"member": {...}}').action(async (opts, cmd) => {
789
+ const globalOpts = cmd.optsWithGlobals();
790
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
791
+ const body = __testables.normalizeBody(String(opts.dataJson), "member");
792
+ await runApiCommand({
793
+ command: "members.create",
794
+ runtimeOptions: pickRuntimeOptions(globalOpts),
795
+ method: "POST",
796
+ path: `/organizations/${encodeURIComponent(organizationId)}/members`,
797
+ body
798
+ });
799
+ });
800
+ members.command("update").requiredOption("--id <id>").requiredOption("--data-json <dataJson>", 'JSON object for member or {"member": {...}}').action(async (opts, cmd) => {
801
+ const id = idSchema6.parse(opts.id);
802
+ const globalOpts = cmd.optsWithGlobals();
803
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
804
+ const body = __testables.normalizeBody(String(opts.dataJson), "member");
805
+ await runApiCommand({
806
+ command: "members.update",
807
+ runtimeOptions: pickRuntimeOptions(globalOpts),
808
+ method: "PATCH",
809
+ path: `/organizations/${encodeURIComponent(organizationId)}/members/${encodeURIComponent(id)}`,
810
+ body
811
+ });
812
+ });
813
+ }
814
+
815
+ // src/commands/issues.ts
816
+ var import_zod8 = require("zod");
817
+ var issueGroupIdSchema = import_zod8.z.string().min(1);
818
+ var idSchema7 = import_zod8.z.string().min(1);
819
+ var nameSchema = import_zod8.z.string().min(1);
820
+ var issueTypeSchema = import_zod8.z.string().min(1);
821
+ function registerIssueCommands(program) {
822
+ const issues = program.command("issues").description("Issue operations");
823
+ issues.command("create").requiredOption("--issue-group-id <issueGroupId>").requiredOption("--name <name>").requiredOption("--issue-type <issueType>").option("--status <status>").option("--priority <priority>").option("--description <description>").option("--due-by <dueBy>").option("--member-id <memberId>").action(async (opts, cmd) => {
824
+ const issueGroupId = issueGroupIdSchema.parse(opts.issueGroupId);
825
+ const name = nameSchema.parse(opts.name);
826
+ const issueType = issueTypeSchema.parse(opts.issueType);
827
+ const globalOpts = cmd.optsWithGlobals();
828
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
829
+ await runApiCommand({
830
+ command: "issues.create",
831
+ runtimeOptions: pickRuntimeOptions(globalOpts),
832
+ method: "POST",
833
+ path: `/organizations/${encodeURIComponent(organizationId)}/issues`,
834
+ body: {
835
+ issue: {
836
+ issue_group_id: issueGroupId,
837
+ name,
838
+ issue_type: issueType,
839
+ ...opts.status ? { status: String(opts.status) } : {},
840
+ ...opts.priority ? { priority: String(opts.priority) } : {},
841
+ ...opts.description ? { description: String(opts.description) } : {},
842
+ ...opts.dueBy ? { due_by: String(opts.dueBy) } : {},
843
+ ...opts.memberId ? { member_id: String(opts.memberId) } : {}
844
+ }
845
+ }
846
+ });
847
+ });
848
+ issues.command("update").requiredOption("--id <id>").requiredOption("--data-json <dataJson>", 'JSON object for issue or {"issue": {...}}').action(async (opts, cmd) => {
849
+ const id = idSchema7.parse(opts.id);
850
+ const globalOpts = cmd.optsWithGlobals();
851
+ const organizationId = resolveOrganizationId(globalOpts.organizationId);
852
+ const body = __testables.normalizeBody(String(opts.dataJson), "issue");
853
+ await runApiCommand({
854
+ command: "issues.update",
855
+ runtimeOptions: pickRuntimeOptions(globalOpts),
856
+ method: "PATCH",
857
+ path: `/organizations/${encodeURIComponent(organizationId)}/issues/${encodeURIComponent(id)}`,
858
+ body
859
+ });
860
+ });
861
+ }
862
+
863
+ // src/commands/systemTools.ts
864
+ function registerSystemToolCommands(program) {
865
+ registerEntityCrudCommands(program, {
866
+ command: "lists",
867
+ description: "List operations",
868
+ resourcePath: "lists",
869
+ rootKey: "list"
870
+ });
871
+ registerEntityCrudCommands(program, {
872
+ command: "list-items",
873
+ description: "List item operations",
874
+ resourcePath: "list_items",
875
+ rootKey: "list_item",
876
+ requiredCreateFields: ["list_id"]
877
+ });
878
+ registerEntityCrudCommands(program, {
879
+ command: "issue-groups",
880
+ description: "Issue group operations",
881
+ resourcePath: "issue_groups",
882
+ rootKey: "issue_group"
883
+ });
884
+ registerEntityCrudCommands(program, {
885
+ command: "todo-groups",
886
+ description: "To-do group operations",
887
+ resourcePath: "todo_groups",
888
+ rootKey: "todo_group"
889
+ });
890
+ registerEntityCrudCommands(program, {
891
+ command: "todos",
892
+ description: "To-do operations",
893
+ resourcePath: "todos",
894
+ rootKey: "todo",
895
+ requiredCreateFields: ["todo_group_id"]
896
+ });
897
+ registerEntityCrudCommands(program, {
898
+ command: "rock-collections",
899
+ description: "Rock collection operations",
900
+ resourcePath: "rock_collections",
901
+ rootKey: "rock_collection"
902
+ });
903
+ registerEntityCrudCommands(program, {
904
+ command: "knowledge",
905
+ description: "Knowledge content operations",
906
+ resourcePath: "contents",
907
+ rootKey: "content"
908
+ });
909
+ registerEntityCrudCommands(program, {
910
+ command: "stand-ups",
911
+ description: "Stand-up operations",
912
+ resourcePath: "stand_ups",
913
+ rootKey: "stand_up"
914
+ });
915
+ registerEntityCrudCommands(program, {
916
+ command: "news",
917
+ description: "News operations",
918
+ resourcePath: "headlines",
919
+ rootKey: "headline"
920
+ });
921
+ registerEntityCrudCommands(program, {
922
+ command: "questions",
923
+ description: "Q&A forum operations",
924
+ resourcePath: "questions",
925
+ rootKey: "question"
926
+ });
927
+ registerEntityCrudCommands(program, {
928
+ command: "pulse",
929
+ description: "Pulse operations",
930
+ resourcePath: "health_updates",
931
+ rootKey: "health_update"
932
+ });
933
+ registerEntityCrudCommands(program, {
934
+ command: "surveys",
935
+ description: "Survey operations",
936
+ resourcePath: "surveys",
937
+ rootKey: "survey"
938
+ });
939
+ registerEntityCrudCommands(program, {
940
+ command: "accountability",
941
+ description: "Accountability operations",
942
+ resourcePath: "responsibilities",
943
+ rootKey: "responsibility"
944
+ });
945
+ registerEntityCrudCommands(program, {
946
+ command: "kpis",
947
+ description: "KPI operations",
948
+ resourcePath: "smart_kpis",
949
+ rootKey: "smart_kpi"
950
+ });
951
+ registerEntityCrudCommands(program, {
952
+ command: "scorecard-groups",
953
+ description: "Scorecard group operations",
954
+ resourcePath: "measurable_groups",
955
+ rootKey: "measurable_group"
956
+ });
957
+ registerEntityCrudCommands(program, {
958
+ command: "scorecards",
959
+ description: "Scorecard item operations",
960
+ resourcePath: "measurables",
961
+ rootKey: "measurable",
962
+ requiredCreateFields: ["measurable_group_id"]
963
+ });
964
+ registerEntityCrudCommands(program, {
965
+ command: "customers",
966
+ description: "CRM customer operations",
967
+ resourcePath: "customers",
968
+ rootKey: "customer"
969
+ });
970
+ registerEntityCrudCommands(program, {
971
+ command: "contacts",
972
+ description: "CRM contact operations",
973
+ resourcePath: "contacts",
974
+ rootKey: "contact"
975
+ });
976
+ registerEntityCrudCommands(program, {
977
+ command: "annual-objectives",
978
+ description: "Foundation annual objective operations",
979
+ resourcePath: "annual_objectives",
980
+ rootKey: "annual_objective"
981
+ });
982
+ registerEntityCrudCommands(program, {
983
+ command: "quarterly-objectives",
984
+ description: "Foundation quarterly objective operations",
985
+ resourcePath: "quarterly_objectives",
986
+ rootKey: "quarterly_objective"
987
+ });
988
+ }
989
+
990
+ // src/cli.ts
991
+ function buildCli() {
992
+ const program = new import_commander.Command();
993
+ program.name("wave").description("Wave agent CLI").showHelpAfterError(false).allowExcessArguments(false).option("--token <token>", "API token (prefer WAVE_API_TOKEN env var)").option("--jwt <jwt>", "Legacy alias for --token (prefer WAVE_API_TOKEN env var)").option(
994
+ "--base-url <baseUrl>",
995
+ "API base URL (prefer WAVE_API_BASE_URL env var)"
996
+ ).option(
997
+ "--organization-id <organizationId>",
998
+ "Organization ID (prefer WAVE_ORGANIZATION_ID env var)"
999
+ ).option("--timeout-ms <timeoutMs>", "HTTP timeout in milliseconds").option("--debug", "Enable debug logs to stderr").option("--agent-name <agentName>", "Agent name for tracing").option("--agent-run-id <agentRunId>", "Agent run identifier for tracing").option("--request-id <requestId>", "Request identifier").option(
1000
+ "--openapi-path <openapiPath>",
1001
+ "Optional local OpenAPI file path for contract-aware tooling"
1002
+ ).option(
1003
+ "--openapi-url <openapiUrl>",
1004
+ "Optional OpenAPI URL for contract-aware tooling"
1005
+ ).option(
1006
+ "--openapi-version <openapiVersion>",
1007
+ "Optional pinned OpenAPI version/hash"
1008
+ ).exitOverride();
1009
+ registerTaskCommands(program);
1010
+ registerProjectCommands(program);
1011
+ registerRockCommands(program);
1012
+ registerMeetingCommands(program);
1013
+ registerMemberCommands(program);
1014
+ registerIssueCommands(program);
1015
+ registerSystemToolCommands(program);
1016
+ return program;
1017
+ }
1018
+
1019
+ // src/index.ts
1020
+ function printCliFailure(params) {
1021
+ printEnvelopeAndExit({
1022
+ envelope: {
1023
+ ok: false,
1024
+ command: "cli",
1025
+ status: params.status,
1026
+ data: null,
1027
+ error: {
1028
+ code: params.code,
1029
+ message: params.message,
1030
+ details: params.details ?? {}
1031
+ },
1032
+ meta: {
1033
+ requestId: "local_error"
1034
+ }
1035
+ },
1036
+ exitCode: params.exitCode
1037
+ });
1038
+ }
1039
+ async function main() {
1040
+ const program = buildCli();
1041
+ await program.parseAsync(process.argv);
1042
+ }
1043
+ main().catch((error) => {
1044
+ if (error instanceof CliError) {
1045
+ printCliFailure({
1046
+ status: error.status,
1047
+ code: error.kind,
1048
+ message: error.message,
1049
+ details: error.details,
1050
+ exitCode: error.exitCode
1051
+ });
1052
+ }
1053
+ if (error instanceof import_commander2.CommanderError) {
1054
+ printCliFailure({
1055
+ status: 400,
1056
+ code: "invalid_args",
1057
+ message: error.message,
1058
+ exitCode: EXIT_CODES.invalidArgs
1059
+ });
1060
+ }
1061
+ if (error instanceof import_zod9.ZodError || error instanceof import_commander2.InvalidArgumentError) {
1062
+ printCliFailure({
1063
+ status: 400,
1064
+ code: "invalid_args",
1065
+ message: "Invalid command arguments.",
1066
+ details: {
1067
+ issues: error instanceof import_zod9.ZodError ? error.issues : [{ message: error.message, code: "invalid_argument" }]
1068
+ },
1069
+ exitCode: EXIT_CODES.invalidArgs
1070
+ });
1071
+ }
1072
+ const message = error instanceof Error ? error.message : "Unexpected error.";
1073
+ printCliFailure({
1074
+ status: 500,
1075
+ code: "generic_error",
1076
+ message,
1077
+ exitCode: EXIT_CODES.generic
1078
+ });
1079
+ });