@gonovus-ai/spec-flow-cli 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -18
- package/dist/bin.js +0 -0
- package/dist/cli.js +309 -293
- package/dist/cli.js.map +1 -1
- package/dist/github-connection-commands.js +18 -14
- package/dist/github-connection-commands.js.map +1 -1
- package/dist/github-import-commands.js +13 -8
- package/dist/github-import-commands.js.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/product-map-commands.d.ts +17 -0
- package/dist/product-map-commands.js +48 -0
- package/dist/product-map-commands.js.map +1 -0
- package/dist/user-api-key-commands.d.ts +1 -2
- package/dist/user-api-key-commands.js +10 -9
- package/dist/user-api-key-commands.js.map +1 -1
- package/dist/work-item-asset-commands.js +17 -3
- package/dist/work-item-asset-commands.js.map +1 -1
- package/dist/work-item-resource-link-commands.js +19 -8
- package/dist/work-item-resource-link-commands.js.map +1 -1
- package/package.json +10 -10
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,7 @@ import { z } from "zod";
|
|
|
5
5
|
import { addAuthenticationCommandTopology } from "./authentication-command-topology.js";
|
|
6
6
|
import { registerGitHubAccountCommands } from "./github-account-commands.js";
|
|
7
7
|
import { parseHttpOrigin, unresolvedSpecFlowApiOrigin, } from "./http-origin.js";
|
|
8
|
+
import { registerProductMapCommands } from "./product-map-commands.js";
|
|
8
9
|
import { specFlowCliUserAgent } from "./user-agent.js";
|
|
9
10
|
import { registerUserApiKeyCommands } from "./user-api-key-commands.js";
|
|
10
11
|
import { registerWorkItemAssetCommands } from "./work-item-asset-commands.js";
|
|
@@ -56,7 +57,7 @@ const findingReferenceSchema = z
|
|
|
56
57
|
const findingTargetSchema = z
|
|
57
58
|
.object({
|
|
58
59
|
references: z.array(findingReferenceSchema).min(1).max(50),
|
|
59
|
-
specId: z.string().trim().toUpperCase().regex(/^[A-Z]{2,10}-[1-9]\d*$/u),
|
|
60
|
+
specId: z.string().trim().toUpperCase().regex(/^[A-Z]{2,10}-S[1-9]\d*$/u),
|
|
60
61
|
})
|
|
61
62
|
.strict();
|
|
62
63
|
const findingEvidenceSchema = z.discriminatedUnion("kind", [
|
|
@@ -169,21 +170,37 @@ export async function runCli(arguments_, dependencies) {
|
|
|
169
170
|
workspace
|
|
170
171
|
.command("list")
|
|
171
172
|
.action(async () => {
|
|
172
|
-
exitCode = await run((client) => client.GET("/v1/workspaces"), {
|
|
173
|
+
exitCode = await run((client) => client.GET("/v1/workspaces"), { rejectWorkspaceReadToken: true });
|
|
173
174
|
});
|
|
174
175
|
workspace
|
|
175
176
|
.command("create")
|
|
176
177
|
.requiredOption("--name <name>")
|
|
178
|
+
.requiredOption("--prefix <prefix>", "Immutable Workspace number prefix, 2 to 10 uppercase letters")
|
|
179
|
+
.option("--spec-language <language>", "Workspace keyword language: zh-CN or en", (value) => z.enum(["zh-CN", "en"]).parse(value), "zh-CN")
|
|
177
180
|
.action(async (options) => {
|
|
178
|
-
if (
|
|
181
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
179
182
|
exitCode = rejectTokenWrite(dependencies);
|
|
180
183
|
return;
|
|
181
184
|
}
|
|
182
185
|
const idempotencyKey = randomUUID();
|
|
183
186
|
exitCode = await run((client) => client.POST("/v1/workspaces", {
|
|
184
|
-
body: { name: options.name },
|
|
187
|
+
body: { name: options.name, prefix: options.prefix, specLanguage: options.specLanguage },
|
|
185
188
|
params: { header: { "idempotency-key": idempotencyKey } },
|
|
186
|
-
}), { retryTransportOnce: true });
|
|
189
|
+
}), { retryTransportOnce: true, ambiguousOutcomeMessage: "Workspace creation outcome is unknown; run workspace list before trying a new command identity" });
|
|
190
|
+
});
|
|
191
|
+
workspace.command("rename").requiredOption("--workspace-id <workspaceId>").requiredOption("--name <name>").requiredOption("--expected-version <version>", "Observed Workspace settings version", parseOpaqueVersion).requiredOption("--idempotency-key <key>").action(async (options) => {
|
|
192
|
+
exitCode = await run(client => client.PATCH("/v1/workspaces/{workspaceId}/settings", { params: { path: { workspaceId: options.workspaceId }, header: { "idempotency-key": options.idempotencyKey, "if-match": options.expectedVersion } }, body: { name: options.name } }), { retryTransportOnce: true });
|
|
193
|
+
});
|
|
194
|
+
const workspaceSettings = workspace.command("settings");
|
|
195
|
+
workspaceSettings.command("read").requiredOption("--workspace-id <workspaceId>").action(async (options) => {
|
|
196
|
+
exitCode = await run(client => client.GET("/v1/workspaces/{workspaceId}/settings", { params: { path: options } }));
|
|
197
|
+
});
|
|
198
|
+
workspaceSettings.command("update").requiredOption("--workspace-id <workspaceId>").requiredOption("--spec-language <language>", "Workspace keyword language", (value) => z.enum(["zh-CN", "en"]).parse(value)).requiredOption("--expected-version <version>", "Observed Workspace settings version", parseOpaqueVersion).requiredOption("--idempotency-key <key>").action(async (options) => {
|
|
199
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
200
|
+
exitCode = rejectTokenWrite(dependencies);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
exitCode = await run(client => client.PATCH("/v1/workspaces/{workspaceId}/settings", { params: { path: { workspaceId: options.workspaceId }, header: { "idempotency-key": options.idempotencyKey, "if-match": options.expectedVersion } }, body: { specLanguage: options.specLanguage } }), { retryTransportOnce: true });
|
|
187
204
|
});
|
|
188
205
|
const workspaceMember = workspace.command("member");
|
|
189
206
|
workspaceMember
|
|
@@ -192,7 +209,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
192
209
|
.action(async (options) => {
|
|
193
210
|
exitCode = await run((client) => client.GET("/v1/workspaces/{workspaceId}/members", {
|
|
194
211
|
params: { path: { workspaceId: options.workspaceId } },
|
|
195
|
-
}), {
|
|
212
|
+
}), { rejectWorkspaceReadToken: true });
|
|
196
213
|
});
|
|
197
214
|
workspaceMember
|
|
198
215
|
.command("search")
|
|
@@ -205,7 +222,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
205
222
|
path: { workspaceId: options.workspaceId },
|
|
206
223
|
query: { limit: options.limit, query: options.query },
|
|
207
224
|
},
|
|
208
|
-
}), {
|
|
225
|
+
}), { rejectWorkspaceReadToken: true });
|
|
209
226
|
});
|
|
210
227
|
workspaceMember
|
|
211
228
|
.command("add")
|
|
@@ -214,7 +231,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
214
231
|
.requiredOption("--subject <subject>", "Authentik subject from `workspace member search`")
|
|
215
232
|
.requiredOption("--role <role>", "Workspace Role name")
|
|
216
233
|
.action(async (options) => {
|
|
217
|
-
if (
|
|
234
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
218
235
|
exitCode = rejectTokenWrite(dependencies);
|
|
219
236
|
return;
|
|
220
237
|
}
|
|
@@ -238,7 +255,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
238
255
|
.requiredOption("--role <role>", "Workspace Role name")
|
|
239
256
|
.requiredOption("--expected-version <version>", "Opaque Member version from `workspace member list`", parseOpaqueVersion)
|
|
240
257
|
.action(async (options) => {
|
|
241
|
-
if (
|
|
258
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
242
259
|
exitCode = rejectTokenWrite(dependencies);
|
|
243
260
|
return;
|
|
244
261
|
}
|
|
@@ -266,7 +283,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
266
283
|
.requiredOption("--user-id <userId>", "Member User ID from `workspace member list`")
|
|
267
284
|
.requiredOption("--expected-version <version>", "Opaque Member version from `workspace member list`", parseOpaqueVersion)
|
|
268
285
|
.action(async (options) => {
|
|
269
|
-
if (
|
|
286
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
270
287
|
exitCode = rejectTokenWrite(dependencies);
|
|
271
288
|
return;
|
|
272
289
|
}
|
|
@@ -294,7 +311,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
294
311
|
.action(async (options) => {
|
|
295
312
|
exitCode = await run((client) => client.GET("/v1/workspaces/{workspaceId}/roles", {
|
|
296
313
|
params: { path: { workspaceId: options.workspaceId } },
|
|
297
|
-
}), {
|
|
314
|
+
}), { rejectWorkspaceReadToken: true });
|
|
298
315
|
});
|
|
299
316
|
workspaceRole
|
|
300
317
|
.command("create")
|
|
@@ -302,7 +319,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
302
319
|
.requiredOption("--name <name>", "Custom Workspace Role name")
|
|
303
320
|
.requiredOption("--statements <statements>", "JSON object mapping permission resources to granted actions", parseRoleStatements)
|
|
304
321
|
.action(async (options) => {
|
|
305
|
-
if (
|
|
322
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
306
323
|
exitCode = rejectTokenWrite(dependencies);
|
|
307
324
|
return;
|
|
308
325
|
}
|
|
@@ -322,7 +339,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
322
339
|
.requiredOption("--statements <statements>", "JSON object mapping permission resources to granted actions", parseRoleStatements)
|
|
323
340
|
.requiredOption("--expected-version <version>", "Opaque Role version from `workspace role list`", parseOpaqueVersion)
|
|
324
341
|
.action(async (options) => {
|
|
325
|
-
if (
|
|
342
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
326
343
|
exitCode = rejectTokenWrite(dependencies);
|
|
327
344
|
return;
|
|
328
345
|
}
|
|
@@ -350,7 +367,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
350
367
|
.requiredOption("--name <name>", "Custom Workspace Role name")
|
|
351
368
|
.requiredOption("--expected-version <version>", "Opaque Role version from `workspace role list`", parseOpaqueVersion)
|
|
352
369
|
.action(async (options) => {
|
|
353
|
-
if (
|
|
370
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
354
371
|
exitCode = rejectTokenWrite(dependencies);
|
|
355
372
|
return;
|
|
356
373
|
}
|
|
@@ -388,16 +405,14 @@ export async function runCli(arguments_, dependencies) {
|
|
|
388
405
|
: { workspaceId: options.workspaceId }),
|
|
389
406
|
},
|
|
390
407
|
},
|
|
391
|
-
}), {
|
|
408
|
+
}), { rejectWorkspaceReadToken: true });
|
|
392
409
|
});
|
|
393
410
|
project
|
|
394
411
|
.command("create")
|
|
395
412
|
.requiredOption("--name <name>")
|
|
396
|
-
.requiredOption("--project-id <projectId>", "Immutable Project ID (2-10 letters)", parseProjectId)
|
|
397
413
|
.requiredOption("--workspace-id <workspaceId>", "Workspace ID returned by `workspace list` or `workspace create`")
|
|
398
|
-
.option("--spec-language <language>", "Spec Language: en or zh-CN (default: en)")
|
|
399
414
|
.action(async (options) => {
|
|
400
|
-
if (
|
|
415
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
401
416
|
exitCode = rejectTokenWrite(dependencies);
|
|
402
417
|
return;
|
|
403
418
|
}
|
|
@@ -405,11 +420,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
405
420
|
exitCode = await run((client) => client.POST("/v1/projects", {
|
|
406
421
|
body: {
|
|
407
422
|
name: options.name,
|
|
408
|
-
projectId: options.projectId,
|
|
409
423
|
workspaceId: options.workspaceId,
|
|
410
|
-
...(options.specLanguage === undefined
|
|
411
|
-
? {}
|
|
412
|
-
: { specLanguage: options.specLanguage }),
|
|
413
424
|
},
|
|
414
425
|
params: { header: { "idempotency-key": idempotencyKey } },
|
|
415
426
|
}), { retryTransportOnce: true });
|
|
@@ -431,7 +442,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
431
442
|
},
|
|
432
443
|
}), {
|
|
433
444
|
ambiguousOutcomeMessage: `Project ${operation} outcome is unknown; read Project context before retrying`,
|
|
434
|
-
|
|
445
|
+
rejectWorkspaceReadToken: true,
|
|
435
446
|
retryTransportOnce: true,
|
|
436
447
|
});
|
|
437
448
|
});
|
|
@@ -444,21 +455,13 @@ export async function runCli(arguments_, dependencies) {
|
|
|
444
455
|
params: { path: { projectId: options.projectId } },
|
|
445
456
|
}));
|
|
446
457
|
});
|
|
447
|
-
project
|
|
448
|
-
.command("directory")
|
|
449
|
-
.requiredOption("--project-id <projectId>")
|
|
450
|
-
.action(async (options) => {
|
|
451
|
-
exitCode = await run((client) => client.GET("/v1/projects/{projectId}/spec-directory", {
|
|
452
|
-
params: { path: { projectId: options.projectId } },
|
|
453
|
-
}));
|
|
454
|
-
});
|
|
455
458
|
const sharing = project.command("sharing").description("Manage anonymous task-only Project sharing");
|
|
456
459
|
sharing.command("read")
|
|
457
460
|
.requiredOption("--project-id <projectId>")
|
|
458
461
|
.action(async (options) => {
|
|
459
462
|
exitCode = await run((client) => client.GET("/v1/projects/{projectId}/sharing", {
|
|
460
463
|
params: { path: { projectId: options.projectId } },
|
|
461
|
-
}), {
|
|
464
|
+
}), { rejectWorkspaceReadToken: true });
|
|
462
465
|
});
|
|
463
466
|
sharing.command("set")
|
|
464
467
|
.requiredOption("--project-id <projectId>")
|
|
@@ -474,42 +477,45 @@ export async function runCli(arguments_, dependencies) {
|
|
|
474
477
|
return value;
|
|
475
478
|
})
|
|
476
479
|
.action(async (options) => {
|
|
477
|
-
if (
|
|
480
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
478
481
|
exitCode = rejectTokenWrite(dependencies);
|
|
479
482
|
return;
|
|
480
483
|
}
|
|
481
484
|
exitCode = await run((client) => client.PUT("/v1/projects/{projectId}/sharing", {
|
|
482
485
|
body: { isPublic: options.public },
|
|
483
486
|
params: { path: { projectId: options.projectId }, header: { "if-match": options.expectedVersion, "idempotency-key": options.idempotencyKey } },
|
|
484
|
-
}), {
|
|
487
|
+
}), { rejectWorkspaceReadToken: true, retryTransportOnce: true, ambiguousOutcomeMessage: "Sharing outcome is unknown; reread project sharing and retry the same command key and intent" });
|
|
485
488
|
});
|
|
486
489
|
const spec = program.command("spec");
|
|
490
|
+
spec.command("list").requiredOption("--workspace-id <workspaceId>").option("--project-id <projectId>").option("--query <query>").option("--limit <limit>", "Maximum results", parseSearchLimit, 50).option("--cursor <cursor>").action(async (options) => {
|
|
491
|
+
exitCode = await run(client => client.GET("/v1/workspaces/{workspaceId}/spec-directory", { params: { path: { workspaceId: options.workspaceId }, query: { ...(options.projectId === undefined ? {} : { projectId: options.projectId }), ...(options.query === undefined ? {} : { query: options.query }), limit: options.limit, ...(options.cursor === undefined ? {} : { cursor: options.cursor }) } } }), { rejectWorkspaceReadToken: true });
|
|
492
|
+
});
|
|
487
493
|
spec
|
|
488
494
|
.command("read")
|
|
489
|
-
.requiredOption("--
|
|
495
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
490
496
|
.requiredOption("--spec-id <specId>")
|
|
491
497
|
.action(async (options) => {
|
|
492
|
-
exitCode = await run((client) => client.GET("/v1/
|
|
498
|
+
exitCode = await run((client) => client.GET("/v1/workspaces/{workspaceId}/specs/{specId}", {
|
|
493
499
|
params: { path: options },
|
|
494
|
-
}), {
|
|
500
|
+
}), { rejectWorkspaceReadToken: true });
|
|
495
501
|
});
|
|
496
502
|
spec
|
|
497
503
|
.command("changelog")
|
|
498
|
-
.requiredOption("--
|
|
504
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
499
505
|
.requiredOption("--spec-id <specId>")
|
|
500
506
|
.action(async (options) => {
|
|
501
|
-
exitCode = await run((client) => client.GET("/v1/
|
|
507
|
+
exitCode = await run((client) => client.GET("/v1/workspaces/{workspaceId}/specs/{specId}/changelog", { params: { path: options } }), { rejectWorkspaceReadToken: true });
|
|
502
508
|
});
|
|
503
509
|
spec
|
|
504
510
|
.command("search")
|
|
505
|
-
.requiredOption("--
|
|
511
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
506
512
|
.requiredOption("--query <query>")
|
|
507
513
|
.option("--limit <limit>", "Maximum results", parseSearchLimit, 20)
|
|
508
514
|
.option("--cursor <cursor>")
|
|
509
515
|
.action(async (options) => {
|
|
510
|
-
exitCode = await run((client) => client.GET("/v1/
|
|
516
|
+
exitCode = await run((client) => client.GET("/v1/workspaces/{workspaceId}/spec-search", {
|
|
511
517
|
params: {
|
|
512
|
-
path: {
|
|
518
|
+
path: { workspaceId: options.workspaceId },
|
|
513
519
|
query: {
|
|
514
520
|
...(options.cursor === undefined
|
|
515
521
|
? {}
|
|
@@ -522,33 +528,33 @@ export async function runCli(arguments_, dependencies) {
|
|
|
522
528
|
});
|
|
523
529
|
spec
|
|
524
530
|
.command("current")
|
|
525
|
-
.requiredOption("--
|
|
531
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
526
532
|
.requiredOption("--spec-id <specId>")
|
|
527
533
|
.action(async (options) => {
|
|
528
|
-
exitCode = await run((client) => client.GET("/v1/
|
|
534
|
+
exitCode = await run((client) => client.GET(hasWorkspaceReadToken(dependencies.environment) ? "/v1/workspaces/{workspaceId}/published/specs/{specId}/current-revision" : "/v1/workspaces/{workspaceId}/specs/{specId}/current-revision", { params: { path: options } }));
|
|
529
535
|
});
|
|
530
536
|
spec
|
|
531
537
|
.command("revision")
|
|
532
|
-
.requiredOption("--
|
|
538
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
533
539
|
.requiredOption("--spec-id <specId>")
|
|
534
540
|
.requiredOption("--revision-id <revisionId>")
|
|
535
541
|
.action(async (options) => {
|
|
536
|
-
exitCode = await run((client) => client.GET("/v1/
|
|
542
|
+
exitCode = await run((client) => client.GET(hasWorkspaceReadToken(dependencies.environment) ? "/v1/workspaces/{workspaceId}/published/specs/{specId}/revisions/{revisionId}" : "/v1/workspaces/{workspaceId}/specs/{specId}/revisions/{revisionId}", { params: { path: options } }));
|
|
537
543
|
});
|
|
538
544
|
spec
|
|
539
545
|
.command("edit")
|
|
540
|
-
.requiredOption("--
|
|
546
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
541
547
|
.requiredOption("--spec-id <specId>")
|
|
542
548
|
.requiredOption("--content <content>")
|
|
543
549
|
.option("--agent-revision <agentRevision>")
|
|
544
550
|
.option("--agent-model <agentModel>")
|
|
545
551
|
.option("--source-reference-ids <sourceReferenceIds>")
|
|
546
552
|
.action(async (options) => {
|
|
547
|
-
if (
|
|
553
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
548
554
|
exitCode = rejectTokenWrite(dependencies);
|
|
549
555
|
return;
|
|
550
556
|
}
|
|
551
|
-
exitCode = await run((client) => client.PUT("/v1/
|
|
557
|
+
exitCode = await run((client) => client.PUT("/v1/workspaces/{workspaceId}/specs/{specId}/draft", {
|
|
552
558
|
body: {
|
|
553
559
|
content: options.content,
|
|
554
560
|
provenance: toAgentProvenance(options),
|
|
@@ -558,17 +564,17 @@ export async function runCli(arguments_, dependencies) {
|
|
|
558
564
|
});
|
|
559
565
|
spec
|
|
560
566
|
.command("assign-scenario-ids")
|
|
561
|
-
.requiredOption("--
|
|
567
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
562
568
|
.requiredOption("--spec-id <specId>")
|
|
563
569
|
.option("--agent-revision <agentRevision>")
|
|
564
570
|
.option("--agent-model <agentModel>")
|
|
565
571
|
.action(async (options) => {
|
|
566
|
-
if (
|
|
572
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
567
573
|
exitCode = rejectTokenWrite(dependencies);
|
|
568
574
|
return;
|
|
569
575
|
}
|
|
570
576
|
const idempotencyKey = randomUUID();
|
|
571
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
577
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/specs/{specId}/draft/scenario-ids", {
|
|
572
578
|
body: { provenance: toAgentProvenance(options) },
|
|
573
579
|
params: {
|
|
574
580
|
header: { "idempotency-key": idempotencyKey },
|
|
@@ -581,15 +587,15 @@ export async function runCli(arguments_, dependencies) {
|
|
|
581
587
|
});
|
|
582
588
|
spec
|
|
583
589
|
.command("publish")
|
|
584
|
-
.requiredOption("--
|
|
590
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
585
591
|
.requiredOption("--spec-id <specId>")
|
|
586
592
|
.action(async (options) => {
|
|
587
|
-
if (
|
|
593
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
588
594
|
exitCode = rejectTokenWrite(dependencies);
|
|
589
595
|
return;
|
|
590
596
|
}
|
|
591
597
|
const idempotencyKey = randomUUID();
|
|
592
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
598
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/specs/{specId}/publish", {
|
|
593
599
|
params: {
|
|
594
600
|
header: { "idempotency-key": idempotencyKey },
|
|
595
601
|
path: options,
|
|
@@ -601,18 +607,18 @@ export async function runCli(arguments_, dependencies) {
|
|
|
601
607
|
});
|
|
602
608
|
spec
|
|
603
609
|
.command("create")
|
|
604
|
-
.requiredOption("--
|
|
610
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
605
611
|
.option("--capability-id <capabilityId>")
|
|
606
612
|
.requiredOption("--feature-name <featureName>")
|
|
607
613
|
.option("--source-references <sourceReferences>")
|
|
608
614
|
.action(async (options) => {
|
|
609
|
-
if (
|
|
615
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
610
616
|
exitCode = rejectTokenWrite(dependencies);
|
|
611
617
|
return;
|
|
612
618
|
}
|
|
613
619
|
const idempotencyKey = randomUUID();
|
|
614
620
|
const sourceReferences = parseSourceReferences(options.sourceReferences ?? "[]");
|
|
615
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
621
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/specs", {
|
|
616
622
|
body: {
|
|
617
623
|
capabilityId: options.capabilityId ?? null,
|
|
618
624
|
featureName: options.featureName,
|
|
@@ -620,7 +626,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
620
626
|
},
|
|
621
627
|
params: {
|
|
622
628
|
header: { "idempotency-key": idempotencyKey },
|
|
623
|
-
path: {
|
|
629
|
+
path: { workspaceId: options.workspaceId },
|
|
624
630
|
},
|
|
625
631
|
}), {
|
|
626
632
|
ambiguousOutcomeMessage: "Spec Creation outcome is unknown; inspect the Project directory before retrying",
|
|
@@ -629,13 +635,13 @@ export async function runCli(arguments_, dependencies) {
|
|
|
629
635
|
});
|
|
630
636
|
spec
|
|
631
637
|
.command("update")
|
|
632
|
-
.requiredOption("--
|
|
638
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
633
639
|
.requiredOption("--spec-id <specId>")
|
|
634
640
|
.requiredOption("--expected-version <expectedVersion>", "Opaque version returned by SpecFlow", parseOpaqueVersion)
|
|
635
641
|
.option("--capability-id <capabilityId>")
|
|
636
642
|
.option("--source-references <sourceReferences>")
|
|
637
643
|
.action(async (options) => {
|
|
638
|
-
if (
|
|
644
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
639
645
|
exitCode = rejectTokenWrite(dependencies);
|
|
640
646
|
return;
|
|
641
647
|
}
|
|
@@ -646,7 +652,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
646
652
|
const sourceReferences = options.sourceReferences === undefined
|
|
647
653
|
? undefined
|
|
648
654
|
: parseSourceReferences(options.sourceReferences);
|
|
649
|
-
exitCode = await run((client) => client.PATCH("/v1/
|
|
655
|
+
exitCode = await run((client) => client.PATCH("/v1/workspaces/{workspaceId}/specs/{specId}", {
|
|
650
656
|
body: {
|
|
651
657
|
...(options.capabilityId === undefined
|
|
652
658
|
? {}
|
|
@@ -663,16 +669,16 @@ export async function runCli(arguments_, dependencies) {
|
|
|
663
669
|
});
|
|
664
670
|
spec
|
|
665
671
|
.command("draft")
|
|
666
|
-
.requiredOption("--
|
|
672
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
667
673
|
.requiredOption("--spec-id <specId>")
|
|
668
674
|
.requiredOption("--expected-version <expectedVersion>", "Opaque version returned by SpecFlow", parseOpaqueVersion)
|
|
669
675
|
.action(async (options) => {
|
|
670
|
-
if (
|
|
676
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
671
677
|
exitCode = rejectTokenWrite(dependencies);
|
|
672
678
|
return;
|
|
673
679
|
}
|
|
674
680
|
const idempotencyKey = randomUUID();
|
|
675
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
681
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/specs/{specId}/draft-session", {
|
|
676
682
|
params: {
|
|
677
683
|
header: {
|
|
678
684
|
"idempotency-key": idempotencyKey,
|
|
@@ -687,13 +693,13 @@ export async function runCli(arguments_, dependencies) {
|
|
|
687
693
|
});
|
|
688
694
|
spec
|
|
689
695
|
.command("state")
|
|
690
|
-
.requiredOption("--
|
|
696
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
691
697
|
.requiredOption("--spec-id <specId>")
|
|
692
698
|
.requiredOption("--expected-version <expectedVersion>", "Opaque version returned by SpecFlow", parseOpaqueVersion)
|
|
693
699
|
.requiredOption("--state <state>", "Ready or Unavailable", parseSpecState)
|
|
694
700
|
.option("--unavailability-reason <unavailabilityReason>")
|
|
695
701
|
.action(async (options) => {
|
|
696
|
-
if (
|
|
702
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
697
703
|
exitCode = rejectTokenWrite(dependencies);
|
|
698
704
|
return;
|
|
699
705
|
}
|
|
@@ -705,7 +711,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
705
711
|
options.unavailabilityReason !== undefined) {
|
|
706
712
|
throw invalidArgument("Ready does not accept --unavailability-reason");
|
|
707
713
|
}
|
|
708
|
-
exitCode = await run((client) => client.PATCH("/v1/
|
|
714
|
+
exitCode = await run((client) => client.PATCH("/v1/workspaces/{workspaceId}/specs/{specId}/state", {
|
|
709
715
|
body: options.state === "Ready"
|
|
710
716
|
? { state: "Ready" }
|
|
711
717
|
: {
|
|
@@ -720,16 +726,16 @@ export async function runCli(arguments_, dependencies) {
|
|
|
720
726
|
});
|
|
721
727
|
spec
|
|
722
728
|
.command("rollback")
|
|
723
|
-
.requiredOption("--
|
|
729
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
724
730
|
.requiredOption("--spec-id <specId>")
|
|
725
731
|
.requiredOption("--revision-id <revisionId>")
|
|
726
732
|
.action(async (options) => {
|
|
727
|
-
if (
|
|
733
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
728
734
|
exitCode = rejectTokenWrite(dependencies);
|
|
729
735
|
return;
|
|
730
736
|
}
|
|
731
737
|
const idempotencyKey = randomUUID();
|
|
732
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
738
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/specs/{specId}/rollback", {
|
|
733
739
|
body: { revisionId: options.revisionId },
|
|
734
740
|
params: {
|
|
735
741
|
header: { "idempotency-key": idempotencyKey },
|
|
@@ -742,127 +748,131 @@ export async function runCli(arguments_, dependencies) {
|
|
|
742
748
|
});
|
|
743
749
|
spec
|
|
744
750
|
.command("delete")
|
|
745
|
-
.requiredOption("--
|
|
751
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
746
752
|
.requiredOption("--spec-id <specId>")
|
|
747
753
|
.requiredOption("--expected-version <expectedVersion>", "Opaque version returned by SpecFlow", parseOpaqueVersion)
|
|
748
754
|
.action(async (options) => {
|
|
749
|
-
if (
|
|
755
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
750
756
|
exitCode = rejectTokenWrite(dependencies);
|
|
751
757
|
return;
|
|
752
758
|
}
|
|
753
|
-
exitCode = await run(async (client) => withSuccessData(await client.DELETE("/v1/
|
|
759
|
+
exitCode = await run(async (client) => withSuccessData(await client.DELETE("/v1/workspaces/{workspaceId}/specs/{specId}", {
|
|
754
760
|
params: {
|
|
755
761
|
header: { "if-match": options.expectedVersion },
|
|
756
762
|
path: options,
|
|
757
763
|
},
|
|
758
764
|
}), { deleted: { specId: options.specId } }));
|
|
759
765
|
});
|
|
760
|
-
const
|
|
761
|
-
|
|
766
|
+
const workspaceGlossary = workspace.command("glossary");
|
|
767
|
+
workspaceGlossary
|
|
762
768
|
.command("revision")
|
|
763
|
-
.requiredOption("--
|
|
769
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
764
770
|
.requiredOption("--revision-id <revisionId>")
|
|
765
771
|
.action(async (options) => {
|
|
766
|
-
exitCode = await run((client) => client.GET("/v1/
|
|
772
|
+
exitCode = await run((client) => client.GET(hasWorkspaceReadToken(dependencies.environment) ? "/v1/workspaces/{workspaceId}/published/glossary/revisions/{revisionId}" : "/v1/workspaces/{workspaceId}/glossary/revisions/{revisionId}", { params: { path: options } }));
|
|
767
773
|
});
|
|
768
|
-
|
|
774
|
+
workspaceGlossary
|
|
769
775
|
.command("read")
|
|
770
|
-
.requiredOption("--
|
|
776
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
771
777
|
.action(async (options) => {
|
|
772
|
-
exitCode = await run((client) => client.GET("/v1/
|
|
773
|
-
params: { path: {
|
|
774
|
-
}), {
|
|
778
|
+
exitCode = await run((client) => client.GET("/v1/workspaces/{workspaceId}/glossary", {
|
|
779
|
+
params: { path: { workspaceId: options.workspaceId } },
|
|
780
|
+
}), { rejectWorkspaceReadToken: true });
|
|
775
781
|
});
|
|
776
|
-
|
|
782
|
+
workspaceGlossary
|
|
777
783
|
.command("changelog")
|
|
778
|
-
.requiredOption("--
|
|
784
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
779
785
|
.action(async (options) => {
|
|
780
|
-
exitCode = await run((client) => client.GET("/v1/
|
|
781
|
-
params: { path: {
|
|
782
|
-
}), {
|
|
786
|
+
exitCode = await run((client) => client.GET("/v1/workspaces/{workspaceId}/glossary/changelog", {
|
|
787
|
+
params: { path: { workspaceId: options.workspaceId } },
|
|
788
|
+
}), { rejectWorkspaceReadToken: true });
|
|
783
789
|
});
|
|
784
|
-
|
|
790
|
+
workspaceGlossary
|
|
785
791
|
.command("draft")
|
|
786
|
-
.requiredOption("--
|
|
792
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
787
793
|
.action(async (options) => {
|
|
788
|
-
if (
|
|
794
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
789
795
|
exitCode = rejectTokenWrite(dependencies);
|
|
790
796
|
return;
|
|
791
797
|
}
|
|
792
798
|
const idempotencyKey = randomUUID();
|
|
793
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
799
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/glossary/draft-session", {
|
|
794
800
|
params: {
|
|
795
801
|
header: { "idempotency-key": idempotencyKey },
|
|
796
|
-
path: {
|
|
802
|
+
path: { workspaceId: options.workspaceId },
|
|
797
803
|
},
|
|
798
804
|
}), {
|
|
799
805
|
ambiguousOutcomeMessage: "Glossary Draft Session outcome is unknown; read the Glossary before retrying",
|
|
800
806
|
retryTransportOnce: true,
|
|
801
807
|
});
|
|
802
808
|
});
|
|
803
|
-
|
|
809
|
+
workspaceGlossary
|
|
804
810
|
.command("edit")
|
|
805
|
-
.requiredOption("--
|
|
811
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
806
812
|
.requiredOption("--entries <entries>")
|
|
807
813
|
.option("--agent-revision <agentRevision>")
|
|
808
814
|
.option("--agent-model <agentModel>")
|
|
809
815
|
.option("--source-reference-ids <sourceReferenceIds>")
|
|
810
816
|
.action(async (options) => {
|
|
811
|
-
if (
|
|
817
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
812
818
|
exitCode = rejectTokenWrite(dependencies);
|
|
813
819
|
return;
|
|
814
820
|
}
|
|
815
821
|
const entries = parseGlossaryEntries(options.entries);
|
|
816
|
-
exitCode = await run((client) => client.PUT("/v1/
|
|
822
|
+
exitCode = await run((client) => client.PUT("/v1/workspaces/{workspaceId}/glossary/draft", {
|
|
817
823
|
body: { entries, provenance: toAgentProvenance(options) },
|
|
818
|
-
params: { path: {
|
|
824
|
+
params: { path: { workspaceId: options.workspaceId } },
|
|
819
825
|
}));
|
|
820
826
|
});
|
|
821
|
-
|
|
827
|
+
workspaceGlossary
|
|
822
828
|
.command("publish")
|
|
823
|
-
.requiredOption("--
|
|
829
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
830
|
+
.option("--entry-ids <entryIds...>", "Publish only the selected term changes")
|
|
824
831
|
.action(async (options) => {
|
|
825
|
-
if (
|
|
832
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
826
833
|
exitCode = rejectTokenWrite(dependencies);
|
|
827
834
|
return;
|
|
828
835
|
}
|
|
829
836
|
const idempotencyKey = randomUUID();
|
|
830
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
831
|
-
body: {},
|
|
837
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/glossary/publish", {
|
|
838
|
+
body: options.entryIds === undefined ? {} : { entryIds: options.entryIds },
|
|
832
839
|
params: {
|
|
833
840
|
header: { "idempotency-key": idempotencyKey },
|
|
834
|
-
path: {
|
|
841
|
+
path: { workspaceId: options.workspaceId },
|
|
835
842
|
},
|
|
836
843
|
}), {
|
|
837
844
|
ambiguousOutcomeMessage: "Glossary Publish outcome is unknown; inspect the Glossary Changelog before retrying",
|
|
838
845
|
retryTransportOnce: true,
|
|
839
846
|
});
|
|
840
847
|
});
|
|
841
|
-
|
|
848
|
+
workspaceGlossary
|
|
842
849
|
.command("rollback")
|
|
843
|
-
.requiredOption("--
|
|
850
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
844
851
|
.requiredOption("--revision-id <revisionId>")
|
|
845
852
|
.action(async (options) => {
|
|
846
|
-
if (
|
|
853
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
847
854
|
exitCode = rejectTokenWrite(dependencies);
|
|
848
855
|
return;
|
|
849
856
|
}
|
|
850
857
|
const idempotencyKey = randomUUID();
|
|
851
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
858
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/glossary/rollback", {
|
|
852
859
|
body: { revisionId: options.revisionId },
|
|
853
860
|
params: {
|
|
854
861
|
header: { "idempotency-key": idempotencyKey },
|
|
855
|
-
path: {
|
|
862
|
+
path: { workspaceId: options.workspaceId },
|
|
856
863
|
},
|
|
857
864
|
}), {
|
|
858
865
|
ambiguousOutcomeMessage: "Glossary Rollback outcome is unknown; inspect the Glossary Changelog before retrying",
|
|
859
866
|
retryTransportOnce: true,
|
|
860
867
|
});
|
|
861
868
|
});
|
|
869
|
+
workspace.command("context").requiredOption("--workspace-id <workspaceId>").action(async (options) => {
|
|
870
|
+
exitCode = await run((client) => client.GET("/v1/workspaces/{workspaceId}/knowledge-context", { params: { path: { workspaceId: options.workspaceId } } }), { rejectWorkspaceReadToken: true });
|
|
871
|
+
});
|
|
862
872
|
const proposal = program.command("proposal");
|
|
863
873
|
proposal
|
|
864
874
|
.command("create-spec")
|
|
865
|
-
.requiredOption("--
|
|
875
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
866
876
|
.requiredOption("--spec-id <specId>")
|
|
867
877
|
.requiredOption("--baseline-content <baselineContent>")
|
|
868
878
|
.requiredOption("--proposed-content <proposedContent>")
|
|
@@ -870,12 +880,12 @@ export async function runCli(arguments_, dependencies) {
|
|
|
870
880
|
.option("--agent-model <agentModel>")
|
|
871
881
|
.option("--source-reference-ids <sourceReferenceIds>")
|
|
872
882
|
.action(async (options) => {
|
|
873
|
-
if (
|
|
883
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
874
884
|
exitCode = rejectTokenWrite(dependencies);
|
|
875
885
|
return;
|
|
876
886
|
}
|
|
877
887
|
const idempotencyKey = randomUUID();
|
|
878
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
888
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/draft-proposals", {
|
|
879
889
|
body: {
|
|
880
890
|
baselineContent: options.baselineContent,
|
|
881
891
|
kind: "Spec",
|
|
@@ -885,7 +895,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
885
895
|
},
|
|
886
896
|
params: {
|
|
887
897
|
header: { "idempotency-key": idempotencyKey },
|
|
888
|
-
path: {
|
|
898
|
+
path: { workspaceId: options.workspaceId },
|
|
889
899
|
},
|
|
890
900
|
}), {
|
|
891
901
|
ambiguousOutcomeMessage: "Draft Proposal Creation outcome is unknown; list open Proposals before retrying",
|
|
@@ -894,19 +904,19 @@ export async function runCli(arguments_, dependencies) {
|
|
|
894
904
|
});
|
|
895
905
|
proposal
|
|
896
906
|
.command("create-glossary")
|
|
897
|
-
.requiredOption("--
|
|
907
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
898
908
|
.requiredOption("--baseline-entries <baselineEntries>")
|
|
899
909
|
.requiredOption("--proposed-entries <proposedEntries>")
|
|
900
910
|
.option("--agent-revision <agentRevision>")
|
|
901
911
|
.option("--agent-model <agentModel>")
|
|
902
912
|
.option("--source-reference-ids <sourceReferenceIds>")
|
|
903
913
|
.action(async (options) => {
|
|
904
|
-
if (
|
|
914
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
905
915
|
exitCode = rejectTokenWrite(dependencies);
|
|
906
916
|
return;
|
|
907
917
|
}
|
|
908
918
|
const idempotencyKey = randomUUID();
|
|
909
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
919
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/draft-proposals", {
|
|
910
920
|
body: {
|
|
911
921
|
baselineEntries: parseGlossaryEntries(options.baselineEntries),
|
|
912
922
|
kind: "Glossary",
|
|
@@ -915,7 +925,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
915
925
|
},
|
|
916
926
|
params: {
|
|
917
927
|
header: { "idempotency-key": idempotencyKey },
|
|
918
|
-
path: {
|
|
928
|
+
path: { workspaceId: options.workspaceId },
|
|
919
929
|
},
|
|
920
930
|
}), {
|
|
921
931
|
ambiguousOutcomeMessage: "Draft Proposal Creation outcome is unknown; list open Proposals before retrying",
|
|
@@ -924,7 +934,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
924
934
|
});
|
|
925
935
|
proposal
|
|
926
936
|
.command("list")
|
|
927
|
-
.requiredOption("--
|
|
937
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
928
938
|
.option("--target-kind <targetKind>", "Spec or Glossary", parseProposalTargetKind)
|
|
929
939
|
.option("--spec-id <specId>")
|
|
930
940
|
.option("--status <status>", "Open, Applied, or Discarded", parseProposalStatus)
|
|
@@ -933,9 +943,9 @@ export async function runCli(arguments_, dependencies) {
|
|
|
933
943
|
(options.targetKind !== "Spec" && options.specId !== undefined)) {
|
|
934
944
|
throw invalidArgument("--spec-id requires --target-kind Spec");
|
|
935
945
|
}
|
|
936
|
-
exitCode = await run((client) => client.GET("/v1/
|
|
946
|
+
exitCode = await run((client) => client.GET("/v1/workspaces/{workspaceId}/draft-proposals", {
|
|
937
947
|
params: {
|
|
938
|
-
path: {
|
|
948
|
+
path: { workspaceId: options.workspaceId },
|
|
939
949
|
query: {
|
|
940
950
|
...(options.specId === undefined ? {} : { specId: options.specId }),
|
|
941
951
|
...(options.status === undefined ? {} : { status: options.status }),
|
|
@@ -948,16 +958,16 @@ export async function runCli(arguments_, dependencies) {
|
|
|
948
958
|
});
|
|
949
959
|
proposal
|
|
950
960
|
.command("apply")
|
|
951
|
-
.requiredOption("--
|
|
961
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
952
962
|
.requiredOption("--proposal-id <proposalId>")
|
|
953
963
|
.option("--change-ids <changeIds>")
|
|
954
964
|
.action(async (options) => {
|
|
955
|
-
if (
|
|
965
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
956
966
|
exitCode = rejectTokenWrite(dependencies);
|
|
957
967
|
return;
|
|
958
968
|
}
|
|
959
969
|
const idempotencyKey = randomUUID();
|
|
960
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
970
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/draft-proposals/{proposalId}/apply", {
|
|
961
971
|
body: {
|
|
962
972
|
changeIds: options.changeIds === undefined
|
|
963
973
|
? null
|
|
@@ -966,7 +976,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
966
976
|
params: {
|
|
967
977
|
header: { "idempotency-key": idempotencyKey },
|
|
968
978
|
path: {
|
|
969
|
-
|
|
979
|
+
workspaceId: options.workspaceId,
|
|
970
980
|
proposalId: options.proposalId,
|
|
971
981
|
},
|
|
972
982
|
},
|
|
@@ -977,19 +987,19 @@ export async function runCli(arguments_, dependencies) {
|
|
|
977
987
|
});
|
|
978
988
|
proposal
|
|
979
989
|
.command("discard")
|
|
980
|
-
.requiredOption("--
|
|
990
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
981
991
|
.requiredOption("--proposal-id <proposalId>")
|
|
982
992
|
.action(async (options) => {
|
|
983
|
-
if (
|
|
993
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
984
994
|
exitCode = rejectTokenWrite(dependencies);
|
|
985
995
|
return;
|
|
986
996
|
}
|
|
987
997
|
const idempotencyKey = randomUUID();
|
|
988
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
998
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/draft-proposals/{proposalId}/discard", {
|
|
989
999
|
params: {
|
|
990
1000
|
header: { "idempotency-key": idempotencyKey },
|
|
991
1001
|
path: {
|
|
992
|
-
|
|
1002
|
+
workspaceId: options.workspaceId,
|
|
993
1003
|
proposalId: options.proposalId,
|
|
994
1004
|
},
|
|
995
1005
|
},
|
|
@@ -1000,32 +1010,30 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1000
1010
|
});
|
|
1001
1011
|
program
|
|
1002
1012
|
.command("authoring-history")
|
|
1003
|
-
.requiredOption("--
|
|
1013
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
1004
1014
|
.action(async (options) => {
|
|
1005
|
-
exitCode = await run((client) => client.GET("/v1/
|
|
1006
|
-
params: { path: { projectId: options.projectId } },
|
|
1007
|
-
}));
|
|
1015
|
+
exitCode = await run((client) => client.GET("/v1/workspaces/{workspaceId}/authoring-history", { params: { path: options } }));
|
|
1008
1016
|
});
|
|
1009
1017
|
const capability = program.command("capability");
|
|
1010
1018
|
capability
|
|
1011
1019
|
.command("create")
|
|
1012
|
-
.requiredOption("--
|
|
1020
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
1013
1021
|
.requiredOption("--name <name>")
|
|
1014
1022
|
.option("--parent-id <parentId>")
|
|
1015
1023
|
.action(async (options) => {
|
|
1016
|
-
if (
|
|
1024
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1017
1025
|
exitCode = rejectTokenWrite(dependencies);
|
|
1018
1026
|
return;
|
|
1019
1027
|
}
|
|
1020
1028
|
const idempotencyKey = randomUUID();
|
|
1021
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
1029
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/capabilities", {
|
|
1022
1030
|
body: {
|
|
1023
1031
|
name: options.name,
|
|
1024
1032
|
parentId: options.parentId ?? null,
|
|
1025
1033
|
},
|
|
1026
1034
|
params: {
|
|
1027
1035
|
header: { "idempotency-key": idempotencyKey },
|
|
1028
|
-
path: {
|
|
1036
|
+
path: { workspaceId: options.workspaceId },
|
|
1029
1037
|
},
|
|
1030
1038
|
}), {
|
|
1031
1039
|
ambiguousOutcomeMessage: "Capability Creation outcome is unknown; inspect the Project directory before retrying",
|
|
@@ -1034,14 +1042,14 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1034
1042
|
});
|
|
1035
1043
|
capability
|
|
1036
1044
|
.command("update")
|
|
1037
|
-
.requiredOption("--
|
|
1045
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
1038
1046
|
.requiredOption("--capability-id <capabilityId>")
|
|
1039
1047
|
.requiredOption("--expected-version <expectedVersion>", "Opaque version returned by SpecFlow", parseOpaqueVersion)
|
|
1040
1048
|
.option("--name <name>")
|
|
1041
1049
|
.option("--parent-id <parentId>")
|
|
1042
1050
|
.option("--move-to-root")
|
|
1043
1051
|
.action(async (options) => {
|
|
1044
|
-
if (
|
|
1052
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1045
1053
|
exitCode = rejectTokenWrite(dependencies);
|
|
1046
1054
|
return;
|
|
1047
1055
|
}
|
|
@@ -1053,7 +1061,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1053
1061
|
options.moveToRoot !== true) {
|
|
1054
1062
|
throw invalidArgument("Capability update requires a change");
|
|
1055
1063
|
}
|
|
1056
|
-
exitCode = await run((client) => client.PATCH("/v1/
|
|
1064
|
+
exitCode = await run((client) => client.PATCH("/v1/workspaces/{workspaceId}/capabilities/{capabilityId}", {
|
|
1057
1065
|
body: {
|
|
1058
1066
|
...(options.name === undefined ? {} : { name: options.name }),
|
|
1059
1067
|
...(options.moveToRoot === true
|
|
@@ -1071,71 +1079,60 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1071
1079
|
capability
|
|
1072
1080
|
.command("delete")
|
|
1073
1081
|
.option("--idempotency-key <key>", "Reuse this key when retrying the same deletion")
|
|
1074
|
-
.requiredOption("--
|
|
1082
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
1075
1083
|
.requiredOption("--capability-id <capabilityId>")
|
|
1076
1084
|
.requiredOption("--expected-version <expectedVersion>", "Opaque version returned by SpecFlow", parseOpaqueVersion)
|
|
1077
1085
|
.action(async (options) => {
|
|
1078
|
-
if (
|
|
1086
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1079
1087
|
exitCode = rejectTokenWrite(dependencies);
|
|
1080
1088
|
return;
|
|
1081
1089
|
}
|
|
1082
1090
|
const idempotencyKey = options.idempotencyKey ?? randomUUID();
|
|
1083
|
-
exitCode = await run(async (client) => withSuccessData(await client.DELETE("/v1/
|
|
1091
|
+
exitCode = await run(async (client) => withSuccessData(await client.DELETE("/v1/workspaces/{workspaceId}/capabilities/{capabilityId}", {
|
|
1084
1092
|
params: {
|
|
1085
1093
|
header: { "if-match": options.expectedVersion, "idempotency-key": idempotencyKey },
|
|
1086
1094
|
path: options,
|
|
1087
1095
|
},
|
|
1088
1096
|
}), { deleted: { capabilityId: options.capabilityId } }));
|
|
1089
1097
|
});
|
|
1090
|
-
const
|
|
1091
|
-
|
|
1098
|
+
const workspaceFinding = workspace.command("finding");
|
|
1099
|
+
workspaceFinding
|
|
1092
1100
|
.command("list")
|
|
1093
|
-
.requiredOption("--
|
|
1094
|
-
.
|
|
1101
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
1102
|
+
.option("--spec-id <specId>")
|
|
1095
1103
|
.option("--status <status>", "Finding status", parseFindingStatus)
|
|
1096
1104
|
.option("--limit <limit>", "Maximum results", parseSearchLimit, 20)
|
|
1097
1105
|
.option("--cursor <cursor>")
|
|
1098
1106
|
.action(async (options) => {
|
|
1099
|
-
exitCode = await run(
|
|
1100
|
-
params: {
|
|
1101
|
-
|
|
1102
|
-
query: {
|
|
1103
|
-
...(options.cursor === undefined
|
|
1104
|
-
? {}
|
|
1105
|
-
: { cursor: options.cursor }),
|
|
1106
|
-
limit: options.limit,
|
|
1107
|
-
...(options.status === undefined
|
|
1108
|
-
? {}
|
|
1109
|
-
: { status: options.status }),
|
|
1110
|
-
},
|
|
1111
|
-
},
|
|
1112
|
-
}), { rejectProjectReadToken: true });
|
|
1107
|
+
exitCode = await run(client => options.specId === undefined
|
|
1108
|
+
? client.GET("/v1/workspaces/{workspaceId}/findings", { params: { path: { workspaceId: options.workspaceId }, query: { limit: options.limit, ...(options.cursor === undefined ? {} : { cursor: options.cursor }), ...(options.status === undefined ? {} : { status: options.status }) } } })
|
|
1109
|
+
: client.GET("/v1/workspaces/{workspaceId}/specs/{specId}/findings", { params: { path: { workspaceId: options.workspaceId, specId: options.specId }, query: { limit: options.limit, ...(options.cursor === undefined ? {} : { cursor: options.cursor }), ...(options.status === undefined ? {} : { status: options.status }) } } }), { rejectWorkspaceReadToken: true });
|
|
1113
1110
|
});
|
|
1114
|
-
|
|
1111
|
+
workspaceFinding
|
|
1115
1112
|
.command("read")
|
|
1116
|
-
.requiredOption("--
|
|
1113
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
1117
1114
|
.requiredOption("--finding-id <findingId>")
|
|
1118
1115
|
.action(async (options) => {
|
|
1119
|
-
exitCode = await run((client) => client.GET("/v1/
|
|
1116
|
+
exitCode = await run((client) => client.GET("/v1/workspaces/{workspaceId}/findings/{findingId}", {
|
|
1120
1117
|
params: { path: options },
|
|
1121
|
-
}), {
|
|
1118
|
+
}), { rejectWorkspaceReadToken: true });
|
|
1122
1119
|
});
|
|
1123
|
-
|
|
1120
|
+
workspaceFinding
|
|
1124
1121
|
.command("create")
|
|
1125
|
-
.requiredOption("--
|
|
1122
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
1126
1123
|
.requiredOption("--input <input>")
|
|
1127
1124
|
.action(async (options) => {
|
|
1128
|
-
if (
|
|
1125
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1129
1126
|
exitCode = rejectTokenWrite(dependencies);
|
|
1130
1127
|
return;
|
|
1131
1128
|
}
|
|
1132
1129
|
const idempotencyKey = randomUUID();
|
|
1133
1130
|
const input = parseFindingInput(options.input);
|
|
1134
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
1131
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/findings", {
|
|
1135
1132
|
body: input,
|
|
1136
1133
|
params: {
|
|
1137
1134
|
header: { "idempotency-key": idempotencyKey },
|
|
1138
|
-
path: {
|
|
1135
|
+
path: { workspaceId: options.workspaceId },
|
|
1139
1136
|
},
|
|
1140
1137
|
}), {
|
|
1141
1138
|
ambiguousOutcomeMessage: "Finding Creation outcome is unknown; inspect the Finding list before retrying",
|
|
@@ -1147,18 +1144,18 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1147
1144
|
["dismiss", "Dismissed"],
|
|
1148
1145
|
["resolve", "Resolved"],
|
|
1149
1146
|
]) {
|
|
1150
|
-
|
|
1147
|
+
workspaceFinding
|
|
1151
1148
|
.command(commandName)
|
|
1152
|
-
.requiredOption("--
|
|
1149
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
1153
1150
|
.requiredOption("--finding-id <findingId>")
|
|
1154
1151
|
.requiredOption("--expected-version <expectedVersion>", "Opaque version returned by SpecFlow", parseOpaqueVersion)
|
|
1155
1152
|
.action(async (options) => {
|
|
1156
|
-
if (
|
|
1153
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1157
1154
|
exitCode = rejectTokenWrite(dependencies);
|
|
1158
1155
|
return;
|
|
1159
1156
|
}
|
|
1160
1157
|
const idempotencyKey = randomUUID();
|
|
1161
|
-
exitCode = await run((client) => client.PATCH("/v1/
|
|
1158
|
+
exitCode = await run((client) => client.PATCH("/v1/workspaces/{workspaceId}/findings/{findingId}/status", {
|
|
1162
1159
|
body: { status },
|
|
1163
1160
|
params: {
|
|
1164
1161
|
header: {
|
|
@@ -1173,10 +1170,39 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1173
1170
|
});
|
|
1174
1171
|
});
|
|
1175
1172
|
}
|
|
1173
|
+
workspaceFinding.command("handler").requiredOption("--workspace-id <workspaceId>").requiredOption("--finding-id <findingId>").option("--user-id <userId>", "Workspace member; omit to clear the handler").requiredOption("--expected-version <expectedVersion>", "Opaque version", parseOpaqueVersion).requiredOption("--idempotency-key <key>").action(async (options) => {
|
|
1174
|
+
exitCode = await run(client => client.PATCH("/v1/workspaces/{workspaceId}/findings/{findingId}/handler", { body: { handlerUserId: options.userId ?? null }, params: { path: options, header: { "idempotency-key": options.idempotencyKey, "if-match": options.expectedVersion } } }), { rejectWorkspaceReadToken: true });
|
|
1175
|
+
});
|
|
1176
|
+
workspaceFinding.command("follow-up").requiredOption("--workspace-id <workspaceId>").requiredOption("--finding-id <findingId>").requiredOption("--project-id <projectId>").requiredOption("--idempotency-key <key>").action(async (options) => {
|
|
1177
|
+
exitCode = await run(client => client.POST("/v1/workspaces/{workspaceId}/findings/{findingId}/work-item", { body: { projectId: options.projectId }, params: { path: { workspaceId: options.workspaceId, findingId: options.findingId }, header: { "idempotency-key": options.idempotencyKey } } }), { rejectWorkspaceReadToken: true });
|
|
1178
|
+
});
|
|
1179
|
+
workspaceFinding.command("discussion").requiredOption("--workspace-id <workspaceId>").requiredOption("--finding-id <findingId>").action(async (options) => {
|
|
1180
|
+
exitCode = await run(client => client.GET("/v1/workspaces/{workspaceId}/findings/{findingId}/discussion", { params: { path: options } }), { rejectWorkspaceReadToken: true });
|
|
1181
|
+
});
|
|
1182
|
+
workspaceFinding.command("comment").requiredOption("--workspace-id <workspaceId>").requiredOption("--finding-id <findingId>").requiredOption("--body <body>").option("--parent-id <parentId>").requiredOption("--idempotency-key <key>").action(async (options) => {
|
|
1183
|
+
exitCode = await run(client => client.POST("/v1/workspaces/{workspaceId}/findings/{findingId}/discussion", { body: { body: options.body, parentId: options.parentId ?? null }, params: { path: options, header: { "idempotency-key": options.idempotencyKey } } }), { rejectWorkspaceReadToken: true });
|
|
1184
|
+
});
|
|
1185
|
+
const workspaceReview = workspace.command("review");
|
|
1186
|
+
workspaceReview.command("request").requiredOption("--workspace-id <workspaceId>").requiredOption("--spec-id <specId>").option("--idempotency-key <key>").action(async (options) => {
|
|
1187
|
+
exitCode = await run(client => client.POST("/v1/workspaces/{workspaceId}/specs/{specId}/reviews", { params: { path: options, header: { "idempotency-key": options.idempotencyKey ?? randomUUID() } } }), { rejectWorkspaceReadToken: true });
|
|
1188
|
+
});
|
|
1189
|
+
workspaceReview.command("history").requiredOption("--workspace-id <workspaceId>").action(async (options) => {
|
|
1190
|
+
exitCode = await run(client => client.GET("/v1/workspaces/{workspaceId}/reviews", { params: { path: options } }), { rejectWorkspaceReadToken: true });
|
|
1191
|
+
});
|
|
1192
|
+
workspaceReview.command("read").requiredOption("--workspace-id <workspaceId>").requiredOption("--review-id <reviewId>").action(async (options) => {
|
|
1193
|
+
exitCode = await run(client => client.GET("/v1/workspaces/{workspaceId}/reviews/{reviewId}", { params: { path: options } }), { rejectWorkspaceReadToken: true });
|
|
1194
|
+
});
|
|
1195
|
+
workspaceReview.command("plan").requiredOption("--workspace-id <workspaceId>").action(async (options) => {
|
|
1196
|
+
exitCode = await run(client => client.GET("/v1/workspaces/{workspaceId}/review-schedule", { params: { path: options } }), { rejectWorkspaceReadToken: true });
|
|
1197
|
+
});
|
|
1198
|
+
workspaceReview.command("configure").requiredOption("--workspace-id <workspaceId>").requiredOption("--expected-version <expectedVersion>", "Opaque version", parseOpaqueVersion).requiredOption("--input <input>", "Review plan JSON").action(async (options) => {
|
|
1199
|
+
const body = reviewPlanInputSchema.parse(JSON.parse(options.input));
|
|
1200
|
+
exitCode = await run(client => client.PUT("/v1/workspaces/{workspaceId}/review-schedule", { body, params: { path: options, header: { "if-match": options.expectedVersion } } }), { rejectWorkspaceReadToken: true });
|
|
1201
|
+
});
|
|
1176
1202
|
const notification = program.command("notification").description("Read and manage your personal task notifications");
|
|
1177
1203
|
notification.command("list").action(async () => {
|
|
1178
|
-
if (
|
|
1179
|
-
exitCode =
|
|
1204
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1205
|
+
exitCode = rejectWorkspaceReadTokenOperation(dependencies);
|
|
1180
1206
|
return;
|
|
1181
1207
|
}
|
|
1182
1208
|
exitCode = await run((client) => client.GET("/v1/notifications"));
|
|
@@ -1191,8 +1217,8 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1191
1217
|
throw invalidArgument("Notification target must be task or workspace"); return value; })
|
|
1192
1218
|
.requiredOption("--idempotency-key <key>", "Reuse the same command key and inputs when retrying", parseNotificationUuid)
|
|
1193
1219
|
.action(async (options) => {
|
|
1194
|
-
if (
|
|
1195
|
-
exitCode =
|
|
1220
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1221
|
+
exitCode = rejectWorkspaceReadTokenOperation(dependencies);
|
|
1196
1222
|
return;
|
|
1197
1223
|
}
|
|
1198
1224
|
if ((options.relatedEntityId === undefined) !== (options.relatedEntityType === undefined))
|
|
@@ -1203,8 +1229,8 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1203
1229
|
.requiredOption("--notification-id <id>", "Notification UUID returned by the list", parseNotificationUuid)
|
|
1204
1230
|
.requiredOption("--idempotency-key <key>", "Reuse the same key when retrying", parseNotificationUuid)
|
|
1205
1231
|
.action(async (options) => {
|
|
1206
|
-
if (
|
|
1207
|
-
exitCode =
|
|
1232
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1233
|
+
exitCode = rejectWorkspaceReadTokenOperation(dependencies);
|
|
1208
1234
|
return;
|
|
1209
1235
|
}
|
|
1210
1236
|
exitCode = await run((client) => client.PATCH("/v1/notifications/{notificationId}/read", { params: { path: { notificationId: options.notificationId }, header: { "idempotency-key": options.idempotencyKey } } }), { retryTransportOnce: true, ambiguousOutcomeMessage: "Notification read outcome is unknown; retry with the same notification and command key" });
|
|
@@ -1212,8 +1238,8 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1212
1238
|
for (const action of ["read-all", "clear"]) {
|
|
1213
1239
|
notification.command(action).requiredOption("--idempotency-key <key>", "Reuse the same key to avoid changing notifications that arrived after the first command", parseNotificationUuid)
|
|
1214
1240
|
.action(async (options) => {
|
|
1215
|
-
if (
|
|
1216
|
-
exitCode =
|
|
1241
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1242
|
+
exitCode = rejectWorkspaceReadTokenOperation(dependencies);
|
|
1217
1243
|
return;
|
|
1218
1244
|
}
|
|
1219
1245
|
const params = { header: { "idempotency-key": options.idempotencyKey } };
|
|
@@ -1222,8 +1248,8 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1222
1248
|
}
|
|
1223
1249
|
const notificationPreferences = notification.command("preferences");
|
|
1224
1250
|
notificationPreferences.command("get").action(async () => {
|
|
1225
|
-
if (
|
|
1226
|
-
exitCode =
|
|
1251
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1252
|
+
exitCode = rejectWorkspaceReadTokenOperation(dependencies);
|
|
1227
1253
|
return;
|
|
1228
1254
|
}
|
|
1229
1255
|
exitCode = await run((client) => client.GET("/v1/notification-preferences"));
|
|
@@ -1233,15 +1259,16 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1233
1259
|
.requiredOption("--preferences <json>", "JSON category settings; omitted settings remain unchanged", parseNotificationPreferences)
|
|
1234
1260
|
.requiredOption("--idempotency-key <key>", "Reuse the same key and settings when retrying", parseNotificationUuid)
|
|
1235
1261
|
.action(async (options) => {
|
|
1236
|
-
if (
|
|
1237
|
-
exitCode =
|
|
1262
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1263
|
+
exitCode = rejectWorkspaceReadTokenOperation(dependencies);
|
|
1238
1264
|
return;
|
|
1239
1265
|
}
|
|
1240
1266
|
exitCode = await run((client) => client.PATCH("/v1/notification-preferences", { body: options.preferences, params: { header: { "idempotency-key": options.idempotencyKey, "if-match": options.expectedVersion } } }), { retryTransportOnce: true, ambiguousOutcomeMessage: "Notification preference outcome is unknown; retry with the same settings and command key" });
|
|
1241
1267
|
});
|
|
1242
1268
|
const workItem = program.command("work-item");
|
|
1243
1269
|
registerWorkItemAssetCommands(workItem, { dependencies, run, setExitCode: (value) => { exitCode = value; }, rejectWrite: () => rejectTokenWrite(dependencies) });
|
|
1244
|
-
|
|
1270
|
+
registerProductMapCommands(program, { run, setExitCode: value => { exitCode = value; }, canWrite: () => !hasWorkspaceReadToken(dependencies.environment), rejectWrite: () => rejectTokenWrite(dependencies), parseOpaqueVersion });
|
|
1271
|
+
registerWorkItemResourceLinkCommands(workItem, spec, { run, setExitCode: (value) => { exitCode = value; }, canWrite: () => !hasWorkspaceReadToken(dependencies.environment), rejectWrite: () => rejectTokenWrite(dependencies), parseOpaqueVersion, parseLimit: parseSearchLimit });
|
|
1245
1272
|
const timeEntry = workItem.command("time-entry").description("Record and read task time entries");
|
|
1246
1273
|
timeEntry.command("list")
|
|
1247
1274
|
.requiredOption("--project-id <projectId>")
|
|
@@ -1299,7 +1326,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1299
1326
|
throw invalidArgument("Time Entry ID must be a UUID");
|
|
1300
1327
|
} }).requiredOption("--expected-version <version>", "Opaque version returned by SpecFlow", parseOpaqueVersion);
|
|
1301
1328
|
command.action(async (options) => {
|
|
1302
|
-
if (
|
|
1329
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1303
1330
|
exitCode = rejectTokenWrite(dependencies);
|
|
1304
1331
|
return;
|
|
1305
1332
|
}
|
|
@@ -1344,7 +1371,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1344
1371
|
.requiredOption("--content <markdown>", "Markdown comment body, up to 20000 characters", parseCommentContent)
|
|
1345
1372
|
.requiredOption("--idempotency-key <key>", "Reuse the same key and inputs when retrying", parseCommentCommandKey)
|
|
1346
1373
|
.action(async (options) => {
|
|
1347
|
-
if (
|
|
1374
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1348
1375
|
exitCode = rejectTokenWrite(dependencies);
|
|
1349
1376
|
return;
|
|
1350
1377
|
}
|
|
@@ -1361,7 +1388,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1361
1388
|
.requiredOption("--expected-version <version>", "Opaque comment version returned by SpecFlow", parseOpaqueVersion)
|
|
1362
1389
|
.requiredOption("--idempotency-key <key>", "Reuse the same key and inputs when retrying", parseCommentCommandKey)
|
|
1363
1390
|
.action(async (options) => {
|
|
1364
|
-
if (
|
|
1391
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1365
1392
|
exitCode = rejectTokenWrite(dependencies);
|
|
1366
1393
|
return;
|
|
1367
1394
|
}
|
|
@@ -1378,7 +1405,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1378
1405
|
.requiredOption("--expected-version <version>", "Opaque comment version returned by SpecFlow", parseOpaqueVersion)
|
|
1379
1406
|
.requiredOption("--idempotency-key <key>", "Reuse the same key and inputs when retrying", parseCommentCommandKey)
|
|
1380
1407
|
.action(async (options) => {
|
|
1381
|
-
if (
|
|
1408
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1382
1409
|
exitCode = rejectTokenWrite(dependencies);
|
|
1383
1410
|
return;
|
|
1384
1411
|
}
|
|
@@ -1407,7 +1434,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1407
1434
|
})
|
|
1408
1435
|
.requiredOption("--idempotency-key <key>", "Reuse the same key and inputs when retrying", parseRelationCommandKey)
|
|
1409
1436
|
.action(async (options) => {
|
|
1410
|
-
if (
|
|
1437
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1411
1438
|
exitCode = rejectTokenWrite(dependencies);
|
|
1412
1439
|
return;
|
|
1413
1440
|
}
|
|
@@ -1428,7 +1455,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1428
1455
|
.requiredOption("--expected-version <expectedVersion>", "Opaque relation version returned by SpecFlow", parseOpaqueVersion)
|
|
1429
1456
|
.requiredOption("--idempotency-key <key>", "Reuse the same key and inputs when retrying", parseRelationCommandKey)
|
|
1430
1457
|
.action(async (options) => {
|
|
1431
|
-
if (
|
|
1458
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1432
1459
|
exitCode = rejectTokenWrite(dependencies);
|
|
1433
1460
|
return;
|
|
1434
1461
|
}
|
|
@@ -1494,7 +1521,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1494
1521
|
.option("--due-date <dueDate>", "ISO 8601 date", parseWorkItemDate)
|
|
1495
1522
|
.option("--status <status>", "Workflow Column slug or virtual status to create the Work Item in")
|
|
1496
1523
|
.action(async (options) => {
|
|
1497
|
-
if (
|
|
1524
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1498
1525
|
exitCode = rejectTokenWrite(dependencies);
|
|
1499
1526
|
return;
|
|
1500
1527
|
}
|
|
@@ -1550,7 +1577,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1550
1577
|
.option("--clear-start-date", "Remove the Work Item start date")
|
|
1551
1578
|
.option("--clear-due-date", "Remove the Work Item due date")
|
|
1552
1579
|
.action(async (options) => {
|
|
1553
|
-
if (
|
|
1580
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1554
1581
|
exitCode = rejectTokenWrite(dependencies);
|
|
1555
1582
|
return;
|
|
1556
1583
|
}
|
|
@@ -1622,7 +1649,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1622
1649
|
.option("--assignee <assignee>", "Workspace member User ID")
|
|
1623
1650
|
.option("--unassign", "Remove the Work Item assignee")
|
|
1624
1651
|
.action(async (options) => {
|
|
1625
|
-
if (
|
|
1652
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1626
1653
|
exitCode = rejectTokenWrite(dependencies);
|
|
1627
1654
|
return;
|
|
1628
1655
|
}
|
|
@@ -1658,7 +1685,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1658
1685
|
.requiredOption("--work-item-id <workItemId>")
|
|
1659
1686
|
.requiredOption("--expected-version <expectedVersion>", "Opaque version returned by SpecFlow", parseOpaqueVersion)
|
|
1660
1687
|
.action(async (options) => {
|
|
1661
|
-
if (
|
|
1688
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1662
1689
|
exitCode = rejectTokenWrite(dependencies);
|
|
1663
1690
|
return;
|
|
1664
1691
|
}
|
|
@@ -1693,7 +1720,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1693
1720
|
.command("bulk")
|
|
1694
1721
|
.requiredOption("--project-id <projectId>")
|
|
1695
1722
|
.requiredOption("--action <action>", `Bulk action: ${workItemBulkActions.join(", ")}`, parseWorkItemBulkAction)
|
|
1696
|
-
.requiredOption("--target <id@version>", "Target
|
|
1723
|
+
.requiredOption("--target <[projectId/]id@version>", "Target with its observed version, e.g. PAY-1@3 or project-id/PAY-2@4; repeat within the same Workspace", parseWorkItemBulkTarget, [])
|
|
1697
1724
|
.option("--status <status>", "Destination Workflow Column slug or virtual status (updateStatus)")
|
|
1698
1725
|
.option("--priority <priority>", "Priority (updatePriority)", parseWorkItemPriority)
|
|
1699
1726
|
.option("--assignee <assignee>", "Assignee User ID (updateAssignee)")
|
|
@@ -1703,7 +1730,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1703
1730
|
.option("--clear-due-date", "Clear the due date (updateDueDate)")
|
|
1704
1731
|
.description("Apply one action to several Work Items, which may span Projects inside the same Workspace")
|
|
1705
1732
|
.action(async (options) => {
|
|
1706
|
-
if (
|
|
1733
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1707
1734
|
exitCode = rejectTokenWrite(dependencies);
|
|
1708
1735
|
return;
|
|
1709
1736
|
}
|
|
@@ -1758,6 +1785,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1758
1785
|
: {}),
|
|
1759
1786
|
workItems: options.target.map((target) => ({
|
|
1760
1787
|
id: target.id,
|
|
1788
|
+
...(target.projectId === undefined ? {} : { projectId: target.projectId }),
|
|
1761
1789
|
version: target.expectedVersion,
|
|
1762
1790
|
})),
|
|
1763
1791
|
},
|
|
@@ -1777,7 +1805,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1777
1805
|
.requiredOption("--file <path>", "JSON task file, at most 1 MiB and 1000 tasks")
|
|
1778
1806
|
.requiredOption("--idempotency-key <key>", "Reuse this key with the same file when retrying")
|
|
1779
1807
|
.action(async (options) => {
|
|
1780
|
-
if (
|
|
1808
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1781
1809
|
exitCode = rejectTokenWrite(dependencies);
|
|
1782
1810
|
return;
|
|
1783
1811
|
}
|
|
@@ -1832,7 +1860,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1832
1860
|
.requiredOption("--expected-version <expectedVersion>", "Opaque version returned by SpecFlow", parseOpaqueVersion)
|
|
1833
1861
|
.option("--destination-status <status>", "Destination Workflow Column slug; defaults to the matching or first column")
|
|
1834
1862
|
.action(async (options) => {
|
|
1835
|
-
if (
|
|
1863
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1836
1864
|
exitCode = rejectTokenWrite(dependencies);
|
|
1837
1865
|
return;
|
|
1838
1866
|
}
|
|
@@ -1859,7 +1887,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1859
1887
|
.requiredOption("--status <status>", "Destination Workflow Column slug or virtual status")
|
|
1860
1888
|
.option("--position <position>", "Board index inside the destination column", parseBoardPosition)
|
|
1861
1889
|
.action(async (options) => {
|
|
1862
|
-
if (
|
|
1890
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1863
1891
|
exitCode = rejectTokenWrite(dependencies);
|
|
1864
1892
|
return;
|
|
1865
1893
|
}
|
|
@@ -1893,7 +1921,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1893
1921
|
.requiredOption("--expected-version <expectedVersion>", "Opaque version returned by SpecFlow", parseOpaqueVersion)
|
|
1894
1922
|
.description("Move a Work Item into the Project's first final Workflow Column")
|
|
1895
1923
|
.action(async (options) => {
|
|
1896
|
-
if (
|
|
1924
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1897
1925
|
exitCode = rejectTokenWrite(dependencies);
|
|
1898
1926
|
return;
|
|
1899
1927
|
}
|
|
@@ -1964,7 +1992,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1964
1992
|
.requiredOption("--color <color>")
|
|
1965
1993
|
.option("--work-item-id <workItemId>", "Create the label directly on the named Work Item instead of the Workspace definition")
|
|
1966
1994
|
.action(async (options) => {
|
|
1967
|
-
if (
|
|
1995
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1968
1996
|
exitCode = rejectTokenWrite(dependencies);
|
|
1969
1997
|
return;
|
|
1970
1998
|
}
|
|
@@ -1994,7 +2022,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
1994
2022
|
.option("--name <name>")
|
|
1995
2023
|
.option("--color <color>")
|
|
1996
2024
|
.action(async (options) => {
|
|
1997
|
-
if (
|
|
2025
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
1998
2026
|
exitCode = rejectTokenWrite(dependencies);
|
|
1999
2027
|
return;
|
|
2000
2028
|
}
|
|
@@ -2031,7 +2059,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
2031
2059
|
.requiredOption("--expected-version <expectedVersion>", "Opaque version returned by SpecFlow", parseOpaqueVersion)
|
|
2032
2060
|
.description("Delete a Work Item Label; a Workspace definition's task-copy cascade resumes automatically across bounded batches")
|
|
2033
2061
|
.action(async (options) => {
|
|
2034
|
-
if (
|
|
2062
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
2035
2063
|
exitCode = rejectTokenWrite(dependencies);
|
|
2036
2064
|
return;
|
|
2037
2065
|
}
|
|
@@ -2081,7 +2109,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
2081
2109
|
.option("--expected-version <expectedVersion>", "Opaque version of the task copy being moved; required when the Label is already attached elsewhere", parseOpaqueVersion)
|
|
2082
2110
|
.description("Attach a Work Item Label to a Work Item as a task-level copy")
|
|
2083
2111
|
.action(async (options) => {
|
|
2084
|
-
if (
|
|
2112
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
2085
2113
|
exitCode = rejectTokenWrite(dependencies);
|
|
2086
2114
|
return;
|
|
2087
2115
|
}
|
|
@@ -2113,7 +2141,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
2113
2141
|
.requiredOption("--expected-version <expectedVersion>", "Opaque version returned by SpecFlow for the attached copy", parseOpaqueVersion)
|
|
2114
2142
|
.description("Detach a Work Item Label copy from a Work Item")
|
|
2115
2143
|
.action(async (options) => {
|
|
2116
|
-
if (
|
|
2144
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
2117
2145
|
exitCode = rejectTokenWrite(dependencies);
|
|
2118
2146
|
return;
|
|
2119
2147
|
}
|
|
@@ -2153,7 +2181,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
2153
2181
|
.option("--default-value <defaultValue>")
|
|
2154
2182
|
.option("--required", "Reject Work Items that leave the field blank")
|
|
2155
2183
|
.action(async (options) => {
|
|
2156
|
-
if (
|
|
2184
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
2157
2185
|
exitCode = rejectTokenWrite(dependencies);
|
|
2158
2186
|
return;
|
|
2159
2187
|
}
|
|
@@ -2188,7 +2216,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
2188
2216
|
.requiredOption("--expected-version <expectedVersion>", "Opaque version returned by SpecFlow", parseOpaqueVersion)
|
|
2189
2217
|
.description("Delete a Work Item Custom Field; its stored values cascade with the definition")
|
|
2190
2218
|
.action(async (options) => {
|
|
2191
|
-
if (
|
|
2219
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
2192
2220
|
exitCode = rejectTokenWrite(dependencies);
|
|
2193
2221
|
return;
|
|
2194
2222
|
}
|
|
@@ -2214,7 +2242,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
2214
2242
|
.requiredOption("--project-id <projectId>")
|
|
2215
2243
|
.requiredOption("--order <order>", "Comma-separated id@version pairs in display order — version is the integer inside the field's opaque \"N\" version")
|
|
2216
2244
|
.action(async (options) => {
|
|
2217
|
-
if (
|
|
2245
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
2218
2246
|
exitCode = rejectTokenWrite(dependencies);
|
|
2219
2247
|
return;
|
|
2220
2248
|
}
|
|
@@ -2263,7 +2291,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
2263
2291
|
.requiredOption("--expected-version <version>", "The opaque Work Item version returned by SpecFlow")
|
|
2264
2292
|
.requiredOption("--value <value>", "Stored value; an empty string clears a non-required field")
|
|
2265
2293
|
.action(async (options) => {
|
|
2266
|
-
if (
|
|
2294
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
2267
2295
|
exitCode = rejectTokenWrite(dependencies);
|
|
2268
2296
|
return;
|
|
2269
2297
|
}
|
|
@@ -2304,7 +2332,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
2304
2332
|
.option("--color <color>", "Column color")
|
|
2305
2333
|
.option("--final", "Mark the column as an explicit completion lane")
|
|
2306
2334
|
.action(async (options) => {
|
|
2307
|
-
if (
|
|
2335
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
2308
2336
|
exitCode = rejectTokenWrite(dependencies);
|
|
2309
2337
|
return;
|
|
2310
2338
|
}
|
|
@@ -2342,7 +2370,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
2342
2370
|
.option("--final", "Mark the column as an explicit completion lane")
|
|
2343
2371
|
.option("--not-final", "Remove the column's completion marker")
|
|
2344
2372
|
.action(async (options) => {
|
|
2345
|
-
if (
|
|
2373
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
2346
2374
|
exitCode = rejectTokenWrite(dependencies);
|
|
2347
2375
|
return;
|
|
2348
2376
|
}
|
|
@@ -2407,7 +2435,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
2407
2435
|
.requiredOption("--column-slug <columnSlug>")
|
|
2408
2436
|
.requiredOption("--expected-version <expectedVersion>", "Opaque version returned by SpecFlow", parseOpaqueVersion)
|
|
2409
2437
|
.action(async (options) => {
|
|
2410
|
-
if (
|
|
2438
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
2411
2439
|
exitCode = rejectTokenWrite(dependencies);
|
|
2412
2440
|
return;
|
|
2413
2441
|
}
|
|
@@ -2433,7 +2461,7 @@ export async function runCli(arguments_, dependencies) {
|
|
|
2433
2461
|
.requiredOption("--project-id <projectId>")
|
|
2434
2462
|
.requiredOption("--order <order>", "Comma-separated slug@version pairs in board order — version is the integer inside the column's opaque \"N\" version")
|
|
2435
2463
|
.action(async (options) => {
|
|
2436
|
-
if (
|
|
2464
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
2437
2465
|
exitCode = rejectTokenWrite(dependencies);
|
|
2438
2466
|
return;
|
|
2439
2467
|
}
|
|
@@ -2453,82 +2481,52 @@ export async function runCli(arguments_, dependencies) {
|
|
|
2453
2481
|
const token = program.command("token");
|
|
2454
2482
|
token
|
|
2455
2483
|
.command("issue")
|
|
2456
|
-
.requiredOption("--
|
|
2484
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
2457
2485
|
.requiredOption("--name <name>")
|
|
2458
2486
|
.option("--expires-at <expiresAt>", "ISO 8601 expiry date-time", parseIsoDateTime)
|
|
2459
2487
|
.action(async (options) => {
|
|
2460
|
-
if (
|
|
2488
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
2461
2489
|
exitCode = rejectTokenWrite(dependencies);
|
|
2462
2490
|
return;
|
|
2463
2491
|
}
|
|
2464
2492
|
const idempotencyKey = randomUUID();
|
|
2465
|
-
exitCode = await run((client) => client.POST("/v1/
|
|
2493
|
+
exitCode = await run((client) => client.POST("/v1/workspaces/{workspaceId}/read-tokens", {
|
|
2466
2494
|
body: {
|
|
2467
2495
|
expiresAt: options.expiresAt ?? null,
|
|
2468
2496
|
name: options.name,
|
|
2469
2497
|
},
|
|
2470
2498
|
params: {
|
|
2471
2499
|
header: { "idempotency-key": idempotencyKey },
|
|
2472
|
-
path: {
|
|
2500
|
+
path: { workspaceId: options.workspaceId },
|
|
2473
2501
|
},
|
|
2474
2502
|
}), {
|
|
2475
|
-
ambiguousOutcomeMessage: "
|
|
2503
|
+
ambiguousOutcomeMessage: "Workspace read-only Token issuance outcome is unknown; list tokens before retrying",
|
|
2476
2504
|
retryTransportOnce: true,
|
|
2477
|
-
validateSuccess:
|
|
2505
|
+
validateSuccess: validateIssuedWorkspaceReadToken,
|
|
2478
2506
|
});
|
|
2479
2507
|
});
|
|
2480
2508
|
token
|
|
2481
2509
|
.command("list")
|
|
2482
|
-
.requiredOption("--
|
|
2510
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
2483
2511
|
.action(async (options) => {
|
|
2484
|
-
exitCode = await run((client) => client.GET("/v1/
|
|
2485
|
-
params: { path: {
|
|
2486
|
-
}), {
|
|
2512
|
+
exitCode = await run((client) => client.GET("/v1/workspaces/{workspaceId}/read-tokens", {
|
|
2513
|
+
params: { path: { workspaceId: options.workspaceId } },
|
|
2514
|
+
}), { rejectWorkspaceReadToken: true });
|
|
2487
2515
|
});
|
|
2488
2516
|
token
|
|
2489
2517
|
.command("revoke")
|
|
2490
|
-
.requiredOption("--
|
|
2518
|
+
.requiredOption("--workspace-id <workspaceId>")
|
|
2491
2519
|
.requiredOption("--token-id <tokenId>")
|
|
2492
2520
|
.action(async (options) => {
|
|
2493
|
-
if (
|
|
2521
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
2494
2522
|
exitCode = rejectTokenWrite(dependencies);
|
|
2495
2523
|
return;
|
|
2496
2524
|
}
|
|
2497
|
-
exitCode = await run(async (client) => withSuccessData(await client.DELETE("/v1/
|
|
2498
|
-
ambiguousOutcomeMessage: "
|
|
2525
|
+
exitCode = await run(async (client) => withSuccessData(await client.DELETE("/v1/workspaces/{workspaceId}/read-tokens/{tokenId}", { params: { path: options } }), { revoked: { tokenId: options.tokenId } }), {
|
|
2526
|
+
ambiguousOutcomeMessage: "Workspace read-only Token revocation outcome is unknown; list tokens before retrying",
|
|
2499
2527
|
retryTransportOnce: true,
|
|
2500
2528
|
});
|
|
2501
2529
|
});
|
|
2502
|
-
const review = program.command("review");
|
|
2503
|
-
review
|
|
2504
|
-
.command("request")
|
|
2505
|
-
.requiredOption("--project-id <projectId>")
|
|
2506
|
-
.requiredOption("--spec-id <specId>")
|
|
2507
|
-
.action(async (options) => {
|
|
2508
|
-
if (hasProjectReadToken(dependencies.environment)) {
|
|
2509
|
-
exitCode = rejectTokenWrite(dependencies);
|
|
2510
|
-
return;
|
|
2511
|
-
}
|
|
2512
|
-
const idempotencyKey = randomUUID();
|
|
2513
|
-
exitCode = await run((client) => client.POST("/v1/projects/{projectId}/specs/{specId}/reviews", {
|
|
2514
|
-
params: {
|
|
2515
|
-
header: { "idempotency-key": idempotencyKey },
|
|
2516
|
-
path: options,
|
|
2517
|
-
},
|
|
2518
|
-
}), {
|
|
2519
|
-
ambiguousOutcomeMessage: "Manual Review request outcome is unknown; inspect Review Records before retrying",
|
|
2520
|
-
retryTransportOnce: true,
|
|
2521
|
-
});
|
|
2522
|
-
});
|
|
2523
|
-
review
|
|
2524
|
-
.command("read")
|
|
2525
|
-
.requiredOption("--project-id <projectId>")
|
|
2526
|
-
.requiredOption("--review-id <reviewId>")
|
|
2527
|
-
.action(async (options) => {
|
|
2528
|
-
exitCode = await run((client) => client.GET("/v1/projects/{projectId}/reviews/{reviewId}", {
|
|
2529
|
-
params: { path: options },
|
|
2530
|
-
}), { rejectProjectReadToken: true });
|
|
2531
|
-
});
|
|
2532
2530
|
try {
|
|
2533
2531
|
await program.parseAsync([...arguments_], { from: "user" });
|
|
2534
2532
|
return exitCode;
|
|
@@ -2539,7 +2537,8 @@ export async function runCli(arguments_, dependencies) {
|
|
|
2539
2537
|
return cause.exitCode;
|
|
2540
2538
|
}
|
|
2541
2539
|
writeSkillError(dependencies, {
|
|
2542
|
-
message:
|
|
2540
|
+
message: cause.message.replace(/'[^']*'/gu, (quoted) => /^'--?[a-z][a-z-]*(?: [<[][^>\]]+[>\]])?'$/u.test(quoted) ? quoted : "'<redacted>'").replace(/[\r\n]/gu, " ").slice(0, 500),
|
|
2541
|
+
code: "INVALID_CLI_INPUT",
|
|
2543
2542
|
reason: "Invalid Operation",
|
|
2544
2543
|
retryable: false,
|
|
2545
2544
|
});
|
|
@@ -2549,15 +2548,19 @@ export async function runCli(arguments_, dependencies) {
|
|
|
2549
2548
|
}
|
|
2550
2549
|
}
|
|
2551
2550
|
async function executeRequest(dependencies, request, options = {}, serverFlag, apiKeyIdFlag) {
|
|
2552
|
-
|
|
2551
|
+
if (dependencies.environment.SPEC_FLOW_PROJECT_READ_TOKEN !== undefined) {
|
|
2552
|
+
writeSkillError(dependencies, { message: "Project Read Tokens are retired; use a Workspace read-only Token", reason: "Authentication Failed", retryable: false });
|
|
2553
|
+
return 2;
|
|
2554
|
+
}
|
|
2555
|
+
const environmentCredential = dependencies.environment.SPEC_FLOW_WORKSPACE_READ_TOKEN;
|
|
2553
2556
|
const apiKeyEnvironment = dependencies.environment.SPEC_FLOW_API_KEY;
|
|
2554
2557
|
const usesApiKey = apiKeyEnvironment !== undefined || apiKeyIdFlag !== undefined;
|
|
2555
|
-
if (options.requireUserSession === true && (usesApiKey ||
|
|
2558
|
+
if (options.requireUserSession === true && (usesApiKey || hasWorkspaceReadToken(dependencies.environment))) {
|
|
2556
2559
|
writeSkillError(dependencies, { message: "A User Session is required for account management", reason: "Permission Denied", retryable: false });
|
|
2557
2560
|
return 3;
|
|
2558
2561
|
}
|
|
2559
|
-
if ((apiKeyEnvironment !== undefined && apiKeyIdFlag !== undefined) || (usesApiKey &&
|
|
2560
|
-
writeSkillError(dependencies, { message: "Select exactly one API Key or
|
|
2562
|
+
if ((apiKeyEnvironment !== undefined && apiKeyIdFlag !== undefined) || (usesApiKey && hasWorkspaceReadToken(dependencies.environment))) {
|
|
2563
|
+
writeSkillError(dependencies, { message: "Select exactly one API Key or Workspace read-only Token credential", reason: "Invalid Operation", retryable: false });
|
|
2561
2564
|
return 2;
|
|
2562
2565
|
}
|
|
2563
2566
|
if (apiKeyIdFlag !== undefined && !z.uuid().safeParse(apiKeyIdFlag).success) {
|
|
@@ -2568,9 +2571,9 @@ async function executeRequest(dependencies, request, options = {}, serverFlag, a
|
|
|
2568
2571
|
writeSkillError(dependencies, { message: "SPEC_FLOW_API_KEY does not contain a User API Key", reason: "Authentication Failed", retryable: false });
|
|
2569
2572
|
return 2;
|
|
2570
2573
|
}
|
|
2571
|
-
if (options.
|
|
2572
|
-
|
|
2573
|
-
return
|
|
2574
|
+
if (options.rejectWorkspaceReadToken === true &&
|
|
2575
|
+
hasWorkspaceReadToken(dependencies.environment)) {
|
|
2576
|
+
return rejectWorkspaceReadTokenOperation(dependencies);
|
|
2574
2577
|
}
|
|
2575
2578
|
const baseUrl = resolveApiOrigin(dependencies, serverFlag);
|
|
2576
2579
|
if (baseUrl === null) {
|
|
@@ -2586,8 +2589,7 @@ async function executeRequest(dependencies, request, options = {}, serverFlag, a
|
|
|
2586
2589
|
credential = await dependencies.credentialStore.readApiKey(apiKeyIdFlag.toLowerCase());
|
|
2587
2590
|
}
|
|
2588
2591
|
else {
|
|
2589
|
-
credential = environmentCredential
|
|
2590
|
-
? await dependencies.credentialStore.read() : environmentCredential;
|
|
2592
|
+
credential = environmentCredential ?? await dependencies.credentialStore.read();
|
|
2591
2593
|
}
|
|
2592
2594
|
}
|
|
2593
2595
|
catch {
|
|
@@ -2600,7 +2602,7 @@ async function executeRequest(dependencies, request, options = {}, serverFlag, a
|
|
|
2600
2602
|
}
|
|
2601
2603
|
if (credential === null || credential.trim().length === 0) {
|
|
2602
2604
|
writeSkillError(dependencies, {
|
|
2603
|
-
message: "An authenticated CLI Session, User API Key or
|
|
2605
|
+
message: "An authenticated CLI Session, User API Key or Workspace read-only Token is required",
|
|
2604
2606
|
reason: "Authentication Failed",
|
|
2605
2607
|
retryable: false,
|
|
2606
2608
|
});
|
|
@@ -2663,18 +2665,19 @@ function retryTransportOnce(fetch) {
|
|
|
2663
2665
|
function ambiguousMutationError(message) {
|
|
2664
2666
|
return {
|
|
2665
2667
|
message: message ??
|
|
2666
|
-
"
|
|
2668
|
+
"Write outcome is unknown; read the target resource before trying a new command identity",
|
|
2669
|
+
code: "EXECUTION_OUTCOME_UNKNOWN",
|
|
2667
2670
|
reason: "Temporary Failure",
|
|
2668
2671
|
retryable: false,
|
|
2669
2672
|
};
|
|
2670
2673
|
}
|
|
2671
|
-
function
|
|
2674
|
+
function validateIssuedWorkspaceReadToken(data) {
|
|
2672
2675
|
if (typeof data === "object" &&
|
|
2673
2676
|
data !== null &&
|
|
2674
2677
|
"credential" in data &&
|
|
2675
2678
|
data.credential === null) {
|
|
2676
2679
|
return {
|
|
2677
|
-
message: "
|
|
2680
|
+
message: "Workspace read-only Token issuance completed, but its credential cannot be recovered; list or revoke the token before deliberately issuing another",
|
|
2678
2681
|
reason: "Temporary Failure",
|
|
2679
2682
|
retryable: false,
|
|
2680
2683
|
};
|
|
@@ -2726,18 +2729,17 @@ function parseProjectStatus(value) {
|
|
|
2726
2729
|
throw new CommanderError(1, "commander.invalidArgument", "Project status must be Active, Archived, or Trashed");
|
|
2727
2730
|
}
|
|
2728
2731
|
function parseProjectId(value) {
|
|
2729
|
-
const normalized = value.trim()
|
|
2730
|
-
if (/^[A-
|
|
2732
|
+
const normalized = value.trim();
|
|
2733
|
+
if (/^[A-Za-z0-9_-]{1,200}$/u.test(normalized))
|
|
2731
2734
|
return normalized;
|
|
2732
|
-
|
|
2733
|
-
throw invalidArgument("Project ID must contain 2-10 letters");
|
|
2735
|
+
throw invalidArgument("Project ID must be the system identity returned by Project discovery");
|
|
2734
2736
|
}
|
|
2735
2737
|
function parseSpecId(value) {
|
|
2736
2738
|
const normalized = value.trim().toUpperCase();
|
|
2737
|
-
if (/^[A-Z]{2,10}-[1-9]\d*$/u.test(normalized)) {
|
|
2739
|
+
if (/^[A-Z]{2,10}-S[1-9]\d*$/u.test(normalized)) {
|
|
2738
2740
|
return normalized;
|
|
2739
2741
|
}
|
|
2740
|
-
throw invalidArgument("Spec ID must
|
|
2742
|
+
throw invalidArgument("Spec ID must have the Workspace prefix, S marker and positive number");
|
|
2741
2743
|
}
|
|
2742
2744
|
function parseWorkItemId(value) {
|
|
2743
2745
|
const normalized = value.trim().toUpperCase();
|
|
@@ -2826,6 +2828,7 @@ function workItemSelectionQuery(options) {
|
|
|
2826
2828
|
...(options.priority.length === 0
|
|
2827
2829
|
? {}
|
|
2828
2830
|
: { priority: options.priority.join(",") }),
|
|
2831
|
+
...(options.repositoryConnectionId === undefined ? {} : { repositoryConnectionId: options.repositoryConnectionId }),
|
|
2829
2832
|
...(options.search === undefined ? {} : { search: options.search }),
|
|
2830
2833
|
...(options.sort === undefined ? {} : { sortBy: options.sort }),
|
|
2831
2834
|
...(options.order === undefined ? {} : { sortOrder: options.order }),
|
|
@@ -2859,6 +2862,7 @@ function workItemSelectionFlags(command) {
|
|
|
2859
2862
|
...previous,
|
|
2860
2863
|
parseWorkItemPriority(value),
|
|
2861
2864
|
], [])
|
|
2865
|
+
.option("--repository-connection-id <id>", "Filter by an explicit GitHub repository connection")
|
|
2862
2866
|
.option("--search <search>", "Filter by title search text")
|
|
2863
2867
|
.option("--sort <field>", "Sort by field", parseWorkItemSortField)
|
|
2864
2868
|
.option("--order <order>", "Sort order", parseWorkItemSortOrder)
|
|
@@ -2873,12 +2877,16 @@ function parseWorkItemBulkAction(value) {
|
|
|
2873
2877
|
throw invalidArgument(`Bulk action must be ${workItemBulkActions.join(", ")}`);
|
|
2874
2878
|
}
|
|
2875
2879
|
/**
|
|
2876
|
-
*
|
|
2877
|
-
*
|
|
2880
|
+
* Targets default to the route Project; an explicit `projectId/` selects
|
|
2881
|
+
* another owner without inferring Project identity from Workspace numbering.
|
|
2878
2882
|
*/
|
|
2879
2883
|
function parseWorkItemBulkTarget(value, previous) {
|
|
2880
|
-
const [
|
|
2881
|
-
|
|
2884
|
+
const [identity, version, extra] = value.split("@");
|
|
2885
|
+
const segments = identity?.split("/") ?? [];
|
|
2886
|
+
const id = segments.length === 2 ? segments[1] : segments[0];
|
|
2887
|
+
const projectId = segments.length === 2 ? parseProjectId(segments[0] ?? "") : undefined;
|
|
2888
|
+
if (segments.length > 2 ||
|
|
2889
|
+
id === undefined ||
|
|
2882
2890
|
version === undefined ||
|
|
2883
2891
|
extra !== undefined ||
|
|
2884
2892
|
!/^[A-Z]{2,10}-[1-9]\d*$/u.test(id.trim().toUpperCase()) ||
|
|
@@ -2892,7 +2900,7 @@ function parseWorkItemBulkTarget(value, previous) {
|
|
|
2892
2900
|
}
|
|
2893
2901
|
return [
|
|
2894
2902
|
...previous,
|
|
2895
|
-
{ expectedVersion: `"${version}"`, id: id.trim().toUpperCase() },
|
|
2903
|
+
{ expectedVersion: `"${version}"`, id: id.trim().toUpperCase(), ...(projectId === undefined ? {} : { projectId }) },
|
|
2896
2904
|
];
|
|
2897
2905
|
}
|
|
2898
2906
|
function parseBoardPosition(value) {
|
|
@@ -3140,9 +3148,9 @@ function isWorkItemLabelDeletionPending(data) {
|
|
|
3140
3148
|
undefined);
|
|
3141
3149
|
}
|
|
3142
3150
|
function rejectTokenWrite(dependencies) {
|
|
3143
|
-
if (
|
|
3151
|
+
if (hasWorkspaceReadToken(dependencies.environment)) {
|
|
3144
3152
|
writeSkillError(dependencies, {
|
|
3145
|
-
message: "
|
|
3153
|
+
message: "Workspace read-only Token does not permit write operations",
|
|
3146
3154
|
reason: "Permission Denied",
|
|
3147
3155
|
retryable: false,
|
|
3148
3156
|
});
|
|
@@ -3155,32 +3163,39 @@ function rejectTokenWrite(dependencies) {
|
|
|
3155
3163
|
});
|
|
3156
3164
|
return 2;
|
|
3157
3165
|
}
|
|
3158
|
-
function
|
|
3166
|
+
function rejectWorkspaceReadTokenOperation(dependencies) {
|
|
3159
3167
|
writeSkillError(dependencies, {
|
|
3160
|
-
message: "
|
|
3168
|
+
message: "Workspace read-only Token does not permit this operation",
|
|
3161
3169
|
reason: "Permission Denied",
|
|
3162
3170
|
retryable: false,
|
|
3163
3171
|
});
|
|
3164
3172
|
return 3;
|
|
3165
3173
|
}
|
|
3166
|
-
function
|
|
3167
|
-
const credential = environment.
|
|
3174
|
+
function hasWorkspaceReadToken(environment) {
|
|
3175
|
+
const credential = environment.SPEC_FLOW_WORKSPACE_READ_TOKEN;
|
|
3168
3176
|
return credential !== undefined && credential.trim().length > 0;
|
|
3169
3177
|
}
|
|
3170
3178
|
function mapHttpFailure(response, payload) {
|
|
3179
|
+
const failure = classifyHttpFailure(response, payload);
|
|
3180
|
+
const issues = z.array(z.object({ location: z.enum(["body", "query", "path", "headers", "tool"]), path: z.array(z.union([z.string().max(100), z.number()])), rule: z.string().max(100), message: z.string().max(500) })).max(20).safeParse(z.object({ issues: z.unknown() }).safeParse(payload).data?.issues);
|
|
3181
|
+
const code = readServerCode(payload);
|
|
3182
|
+
const requestId = response.headers.get("x-request-id");
|
|
3183
|
+
return { ...failure, ...(requestId !== null && /^[A-Za-z0-9._:-]{1,100}$/u.test(requestId) ? { requestId } : {}), status: response.status, ...(code !== null && /^[A-Z][A-Z0-9_]{0,79}$/u.test(code) ? { code } : {}), ...(issues.success ? { issues: issues.data } : {}) };
|
|
3184
|
+
}
|
|
3185
|
+
function classifyHttpFailure(response, payload) {
|
|
3171
3186
|
const { status } = response;
|
|
3172
3187
|
const serverMessage = readServerMessage(payload);
|
|
3173
3188
|
const serverCode = readServerCode(payload);
|
|
3174
3189
|
if (status === 401) {
|
|
3175
3190
|
return {
|
|
3176
|
-
message: serverMessage ?? "
|
|
3191
|
+
message: serverMessage ?? "Workspace read-only Token is invalid, expired, or revoked",
|
|
3177
3192
|
reason: "Authentication Failed",
|
|
3178
3193
|
retryable: false,
|
|
3179
3194
|
};
|
|
3180
3195
|
}
|
|
3181
3196
|
if (status === 403) {
|
|
3182
3197
|
return {
|
|
3183
|
-
message: serverMessage ?? "
|
|
3198
|
+
message: serverMessage ?? "Workspace read-only Token does not permit this operation",
|
|
3184
3199
|
reason: "Permission Denied",
|
|
3185
3200
|
retryable: false,
|
|
3186
3201
|
};
|
|
@@ -3206,7 +3221,7 @@ function mapHttpFailure(response, payload) {
|
|
|
3206
3221
|
retryable: false,
|
|
3207
3222
|
};
|
|
3208
3223
|
}
|
|
3209
|
-
if (status === 400 || status === 409 || status === 422) {
|
|
3224
|
+
if (status === 400 || status === 409 || status === 413 || status === 422 || status === 428) {
|
|
3210
3225
|
const diagnostics = readServerDiagnostics(payload);
|
|
3211
3226
|
return {
|
|
3212
3227
|
...(diagnostics === undefined ? {} : { diagnostics }),
|
|
@@ -3336,4 +3351,5 @@ function parseNotificationPreferences(value) {
|
|
|
3336
3351
|
const data = result.data;
|
|
3337
3352
|
return { ...(data.taskAssignmentEnabled === undefined ? {} : { taskAssignmentEnabled: data.taskAssignmentEnabled }), ...(data.taskCommentEnabled === undefined ? {} : { taskCommentEnabled: data.taskCommentEnabled }), ...(data.taskStatusChangeEnabled === undefined ? {} : { taskStatusChangeEnabled: data.taskStatusChangeEnabled }), ...(data.dueDateReminderEnabled === undefined ? {} : { dueDateReminderEnabled: data.dueDateReminderEnabled }), ...(data.dueDateReminderMinutes === undefined ? {} : { dueDateReminderMinutes: data.dueDateReminderMinutes }) };
|
|
3338
3353
|
}
|
|
3354
|
+
const reviewPlanInputSchema = z.discriminatedUnion("cadence", [z.object({ cadence: z.literal("Disabled") }).strict(), z.object({ cadence: z.literal("Daily"), timeOfDay: z.string(), timeZone: z.string() }).strict(), z.object({ cadence: z.literal("Weekly"), dayOfWeek: z.number().int().min(1).max(7), timeOfDay: z.string(), timeZone: z.string() }).strict()]);
|
|
3339
3355
|
//# sourceMappingURL=cli.js.map
|