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