@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/README.md +135 -0
- package/dist/index.cjs +1079 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1078 -0
- package/package.json +30 -0
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
|
+
});
|