@khotan/cli 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/khotan.js +2687 -548
- package/package.json +1 -1
package/dist/khotan.js
CHANGED
|
@@ -19,7 +19,7 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
19
19
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
20
20
|
|
|
21
21
|
// ../khotan-core/src/version.ts
|
|
22
|
-
var CATALOG_SCHEMA_VERSION = 2, CATALOG_VERSION = "2026-
|
|
22
|
+
var CATALOG_SCHEMA_VERSION = 2, CATALOG_VERSION = "2026-08-23", KHOTAN_ADAPTER_NAME = "khotan", KHOTAN_ADAPTER_VERSION = "0.10.0", SUPPORTED_CATALOG_SCHEMA_VERSIONS;
|
|
23
23
|
var init_version = __esm(() => {
|
|
24
24
|
SUPPORTED_CATALOG_SCHEMA_VERSIONS = [
|
|
25
25
|
CATALOG_SCHEMA_VERSION
|
|
@@ -1129,7 +1129,7 @@ var init_catalog = __esm(() => {
|
|
|
1129
1129
|
{ name: "slug", location: "body", type: "string", description: "Stable identifier; derived from the name when omitted." },
|
|
1130
1130
|
{ name: "description", location: "body", type: "string", description: "Short summary shown in listings." }
|
|
1131
1131
|
],
|
|
1132
|
-
http: { method: "POST", path: "/api/v1/projects", operationId: "createProject" },
|
|
1132
|
+
http: { method: "POST", path: "/api/v1/projects", operationId: "createProject", bodyMode: "json" },
|
|
1133
1133
|
cli: { command: ["projects", "create"], summary: "Create a project" }
|
|
1134
1134
|
},
|
|
1135
1135
|
{
|
|
@@ -1138,18 +1138,34 @@ var init_catalog = __esm(() => {
|
|
|
1138
1138
|
safety: "destructive",
|
|
1139
1139
|
auth: true,
|
|
1140
1140
|
title: "Delete a project",
|
|
1141
|
-
description: "Soft-delete a project and free its slug. The linked
|
|
1141
|
+
description: "Soft-delete a project and free its slug. The linked tracker project is retained as the record of work done.",
|
|
1142
1142
|
input: [idField("projectId", "The project id or slug.")],
|
|
1143
1143
|
http: { method: "DELETE", path: "/api/v1/projects/{projectId}", operationId: "deleteProject" },
|
|
1144
1144
|
cli: { command: ["projects", "delete"], summary: "Delete a project" }
|
|
1145
1145
|
},
|
|
1146
|
+
{
|
|
1147
|
+
id: "projects.update",
|
|
1148
|
+
domain: "projects",
|
|
1149
|
+
safety: "write",
|
|
1150
|
+
auth: true,
|
|
1151
|
+
title: "Update a project",
|
|
1152
|
+
description: "Update a project's name, description, or lifecycle. Archive with lifecycle archived.",
|
|
1153
|
+
input: [
|
|
1154
|
+
idField("projectId", "The project id or slug."),
|
|
1155
|
+
{ name: "name", location: "body", type: "string", description: "Display name for the project." },
|
|
1156
|
+
{ name: "description", location: "body", type: "string", description: "Short summary shown in listings." },
|
|
1157
|
+
{ name: "lifecycle", location: "body", type: "string", description: "One of: active, archived." }
|
|
1158
|
+
],
|
|
1159
|
+
http: { method: "PATCH", path: "/api/v1/projects/{projectId}", operationId: "updateProject", bodyMode: "json" },
|
|
1160
|
+
cli: { command: ["projects", "update"], summary: "Update a project" }
|
|
1161
|
+
},
|
|
1146
1162
|
{
|
|
1147
1163
|
id: "projects.spec.get",
|
|
1148
1164
|
domain: "projects",
|
|
1149
1165
|
safety: "read",
|
|
1150
1166
|
auth: true,
|
|
1151
1167
|
title: "Read a project spec",
|
|
1152
|
-
description: "Read the spec tree at one altitude: high renders the goal, medium adds phases, low adds items and their mirrored
|
|
1168
|
+
description: "Read the spec tree at one altitude: high renders the goal, medium adds phases, low adds items and their mirrored tracker issues.",
|
|
1153
1169
|
input: [
|
|
1154
1170
|
idField("projectId", "The project id or slug."),
|
|
1155
1171
|
{ name: "altitude", location: "query", type: "string", default: "high", description: "One of: high, medium, low." }
|
|
@@ -1208,7 +1224,7 @@ var init_catalog = __esm(() => {
|
|
|
1208
1224
|
{ name: "resourceKind", location: "body", type: "string", required: true, description: "One of: app, pipeline, database." },
|
|
1209
1225
|
{ name: "resourceId", location: "body", type: "string", required: true, description: "The resource id." }
|
|
1210
1226
|
],
|
|
1211
|
-
http: { method: "POST", path: "/api/v1/projects/{projectId}/members", operationId: "attachProjectMember" },
|
|
1227
|
+
http: { method: "POST", path: "/api/v1/projects/{projectId}/members", operationId: "attachProjectMember", bodyMode: "json" },
|
|
1212
1228
|
cli: { command: ["projects", "attach"], summary: "Attach a resource to a project" }
|
|
1213
1229
|
},
|
|
1214
1230
|
{
|
|
@@ -1223,21 +1239,99 @@ var init_catalog = __esm(() => {
|
|
|
1223
1239
|
{ name: "resourceKind", location: "body", type: "string", required: true, description: "One of: app, pipeline, database." },
|
|
1224
1240
|
{ name: "resourceId", location: "body", type: "string", required: true, description: "The resource id." }
|
|
1225
1241
|
],
|
|
1226
|
-
http: { method: "DELETE", path: "/api/v1/projects/{projectId}/members", operationId: "detachProjectMember" },
|
|
1242
|
+
http: { method: "DELETE", path: "/api/v1/projects/{projectId}/members", operationId: "detachProjectMember", bodyMode: "json" },
|
|
1227
1243
|
cli: { command: ["projects", "detach"], summary: "Detach a resource from a project" }
|
|
1244
|
+
},
|
|
1245
|
+
{
|
|
1246
|
+
id: "projects.nodes.create",
|
|
1247
|
+
domain: "projects",
|
|
1248
|
+
safety: "write",
|
|
1249
|
+
auth: true,
|
|
1250
|
+
title: "Create a spec node",
|
|
1251
|
+
description: "Create a child under an existing spec node — a delivery phase under Milestones, or an item under a phase.",
|
|
1252
|
+
input: [
|
|
1253
|
+
idField("projectId", "The project id or slug."),
|
|
1254
|
+
{ name: "parentId", location: "body", type: "string", required: true, description: "The parent node id." },
|
|
1255
|
+
{ name: "title", location: "body", type: "string", required: true, description: "Display title for the node." },
|
|
1256
|
+
{ name: "body", location: "body", type: "string", description: "Initial body. Empty when omitted." },
|
|
1257
|
+
{ name: "position", location: "body", type: "number", description: "Sibling position. Appended when omitted." }
|
|
1258
|
+
],
|
|
1259
|
+
http: { method: "POST", path: "/api/v1/projects/{projectId}/spec/nodes", operationId: "createProjectSpecNode", bodyMode: "json" },
|
|
1260
|
+
cli: { command: ["projects", "node", "create"], summary: "Create a spec node" }
|
|
1261
|
+
},
|
|
1262
|
+
{
|
|
1263
|
+
id: "projects.nodes.update",
|
|
1264
|
+
domain: "projects",
|
|
1265
|
+
safety: "write",
|
|
1266
|
+
auth: true,
|
|
1267
|
+
title: "Update a spec node",
|
|
1268
|
+
description: "Update a node's title, sibling position, parent, or milestone plan dates.",
|
|
1269
|
+
input: [
|
|
1270
|
+
idField("projectId", "The project id or slug."),
|
|
1271
|
+
idField("nodeId", "The spec node id."),
|
|
1272
|
+
{ name: "title", location: "body", type: "string", description: "Display title for the node." },
|
|
1273
|
+
{ name: "position", location: "body", type: "number", description: "Sibling position." },
|
|
1274
|
+
{ name: "parentId", location: "body", type: "string", description: "Move the node under this parent." },
|
|
1275
|
+
{ name: "startDate", location: "body", type: "string", description: "Milestone plan start (YYYY-MM-DD). Only valid on a phase." },
|
|
1276
|
+
{ name: "targetDate", location: "body", type: "string", description: "Milestone plan target (YYYY-MM-DD). Only valid on a phase." },
|
|
1277
|
+
{ name: "dependsOnNodeId", location: "body", type: "string", description: "Milestone this phase waits on. Only valid on a phase." }
|
|
1278
|
+
],
|
|
1279
|
+
http: { method: "PATCH", path: "/api/v1/projects/{projectId}/spec/nodes/{nodeId}", operationId: "updateProjectSpecNode", bodyMode: "json" },
|
|
1280
|
+
cli: { command: ["projects", "node", "update"], summary: "Update a spec node" }
|
|
1281
|
+
},
|
|
1282
|
+
{
|
|
1283
|
+
id: "projects.nodes.delete",
|
|
1284
|
+
domain: "projects",
|
|
1285
|
+
safety: "destructive",
|
|
1286
|
+
auth: true,
|
|
1287
|
+
title: "Delete a spec node",
|
|
1288
|
+
description: "Soft-delete a spec node and its descendants. The goal node cannot be deleted.",
|
|
1289
|
+
input: [
|
|
1290
|
+
idField("projectId", "The project id or slug."),
|
|
1291
|
+
idField("nodeId", "The spec node id.")
|
|
1292
|
+
],
|
|
1293
|
+
http: { method: "DELETE", path: "/api/v1/projects/{projectId}/spec/nodes/{nodeId}", operationId: "deleteProjectSpecNode" },
|
|
1294
|
+
cli: { command: ["projects", "node", "delete"], summary: "Delete a spec node" }
|
|
1295
|
+
},
|
|
1296
|
+
{
|
|
1297
|
+
id: "projects.linear.options",
|
|
1298
|
+
domain: "projects",
|
|
1299
|
+
safety: "read",
|
|
1300
|
+
auth: true,
|
|
1301
|
+
title: "List Linear projects that can be bound",
|
|
1302
|
+
description: "List Linear projects this workspace can bind a Khotan project to.",
|
|
1303
|
+
input: [
|
|
1304
|
+
{ name: "query", location: "query", type: "string", description: "Filter Linear projects by name." }
|
|
1305
|
+
],
|
|
1306
|
+
http: { method: "GET", path: "/api/v1/projects/linear-options", operationId: "listLinearProjectOptions" },
|
|
1307
|
+
cli: { command: ["projects", "linear", "options"], summary: "List Linear projects that can be bound", defaultOutput: "table" }
|
|
1308
|
+
},
|
|
1309
|
+
{
|
|
1310
|
+
id: "projects.linear.bind",
|
|
1311
|
+
domain: "projects",
|
|
1312
|
+
safety: "write",
|
|
1313
|
+
auth: true,
|
|
1314
|
+
title: "Bind a project to Linear",
|
|
1315
|
+
description: "Bind this project to an existing Linear project. A new project mints its own on first push.",
|
|
1316
|
+
input: [
|
|
1317
|
+
idField("projectId", "The project id or slug."),
|
|
1318
|
+
{ name: "linearProjectId", location: "body", type: "string", required: true, description: "The Linear project id to bind." }
|
|
1319
|
+
],
|
|
1320
|
+
http: { method: "POST", path: "/api/v1/projects/{projectId}/linear", operationId: "bindLinearProject", bodyMode: "json" },
|
|
1321
|
+
cli: { command: ["projects", "linear", "bind"], summary: "Bind a project to Linear" }
|
|
1228
1322
|
}
|
|
1229
1323
|
];
|
|
1230
1324
|
capabilities = [
|
|
1231
1325
|
...identityCapabilities,
|
|
1232
1326
|
...appsCapabilities,
|
|
1233
1327
|
...pipelinesCapabilities,
|
|
1328
|
+
...fileCapabilities,
|
|
1329
|
+
...contextCapabilities,
|
|
1330
|
+
...integrationsCapabilities,
|
|
1234
1331
|
...databaseCapabilities,
|
|
1235
1332
|
...redisCapabilities,
|
|
1236
|
-
...fileCapabilities,
|
|
1237
1333
|
...folderCapabilities,
|
|
1238
|
-
...contextCapabilities,
|
|
1239
1334
|
...projectCapabilities,
|
|
1240
|
-
...integrationsCapabilities,
|
|
1241
1335
|
...emailSubscriptionCapabilities
|
|
1242
1336
|
];
|
|
1243
1337
|
khotanCatalog = {
|
|
@@ -1430,6 +1524,13 @@ function validateCatalogStructure(catalog = khotanCatalog) {
|
|
|
1430
1524
|
});
|
|
1431
1525
|
}
|
|
1432
1526
|
}
|
|
1527
|
+
const hasBodyInput = capability.input.some((field) => field.location === "body");
|
|
1528
|
+
if (hasBodyInput && capability.http.bodyMode !== "json") {
|
|
1529
|
+
errors.push({
|
|
1530
|
+
capabilityId: capability.id,
|
|
1531
|
+
message: 'Has body inputs but does not declare bodyMode: "json".'
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1433
1534
|
}
|
|
1434
1535
|
return { ok: errors.length === 0, errors };
|
|
1435
1536
|
}
|
|
@@ -1497,6 +1598,11 @@ var init_spec = __esm(() => {
|
|
|
1497
1598
|
title: "Khotan API",
|
|
1498
1599
|
version: "1.0.0"
|
|
1499
1600
|
},
|
|
1601
|
+
servers: [
|
|
1602
|
+
{
|
|
1603
|
+
url: "https://app.khotan.com"
|
|
1604
|
+
}
|
|
1605
|
+
],
|
|
1500
1606
|
paths: {
|
|
1501
1607
|
"/api/v1/health": {
|
|
1502
1608
|
get: {
|
|
@@ -4630,7 +4736,7 @@ var init_spec = __esm(() => {
|
|
|
4630
4736
|
}
|
|
4631
4737
|
},
|
|
4632
4738
|
summary: "Create a Redis database",
|
|
4633
|
-
description: "Provisions a
|
|
4739
|
+
description: "Provisions a globally replicated Redis database synchronously and responds 201 with the persisted record whether provisioning ends ready or failed; branch on the returned status. This operation is not idempotent: retrying a request that already succeeded provisions a second database. Omit primaryRegion to use the default region.",
|
|
4634
4740
|
tags: [
|
|
4635
4741
|
"Redis Databases"
|
|
4636
4742
|
],
|
|
@@ -4920,7 +5026,7 @@ var init_spec = __esm(() => {
|
|
|
4920
5026
|
}
|
|
4921
5027
|
},
|
|
4922
5028
|
summary: "Delete a Redis database",
|
|
4923
|
-
description: "Tears down the
|
|
5029
|
+
description: "Tears down the database at the provider, then soft-deletes the record — the same semantics as deleting from the dashboard. Deletion is permanent. Returns 403 resource_protected when the database has deletion protection enabled; protection can only be removed from the dashboard.",
|
|
4924
5030
|
tags: [
|
|
4925
5031
|
"Redis Databases"
|
|
4926
5032
|
],
|
|
@@ -15155,6 +15261,102 @@ var init_spec = __esm(() => {
|
|
|
15155
15261
|
]
|
|
15156
15262
|
}
|
|
15157
15263
|
},
|
|
15264
|
+
"/api/v1/projects/linear-options": {
|
|
15265
|
+
get: {
|
|
15266
|
+
responses: {
|
|
15267
|
+
"200": {
|
|
15268
|
+
description: "Linear projects this workspace can bind to.",
|
|
15269
|
+
content: {
|
|
15270
|
+
"application/json": {
|
|
15271
|
+
schema: {
|
|
15272
|
+
type: "object",
|
|
15273
|
+
properties: {
|
|
15274
|
+
projects: {
|
|
15275
|
+
type: "array",
|
|
15276
|
+
items: {
|
|
15277
|
+
type: "object",
|
|
15278
|
+
properties: {
|
|
15279
|
+
id: {
|
|
15280
|
+
type: "string"
|
|
15281
|
+
},
|
|
15282
|
+
name: {
|
|
15283
|
+
type: "string"
|
|
15284
|
+
},
|
|
15285
|
+
url: {
|
|
15286
|
+
nullable: true,
|
|
15287
|
+
type: "string"
|
|
15288
|
+
},
|
|
15289
|
+
statusName: {
|
|
15290
|
+
nullable: true,
|
|
15291
|
+
type: "string"
|
|
15292
|
+
}
|
|
15293
|
+
},
|
|
15294
|
+
required: [
|
|
15295
|
+
"id",
|
|
15296
|
+
"name",
|
|
15297
|
+
"url",
|
|
15298
|
+
"statusName"
|
|
15299
|
+
],
|
|
15300
|
+
additionalProperties: false
|
|
15301
|
+
}
|
|
15302
|
+
}
|
|
15303
|
+
},
|
|
15304
|
+
required: [
|
|
15305
|
+
"projects"
|
|
15306
|
+
],
|
|
15307
|
+
additionalProperties: false
|
|
15308
|
+
}
|
|
15309
|
+
}
|
|
15310
|
+
}
|
|
15311
|
+
},
|
|
15312
|
+
"401": {
|
|
15313
|
+
description: "Authentication is missing or invalid.",
|
|
15314
|
+
content: {
|
|
15315
|
+
"application/json": {
|
|
15316
|
+
schema: {
|
|
15317
|
+
$ref: "#/components/schemas/Error"
|
|
15318
|
+
}
|
|
15319
|
+
}
|
|
15320
|
+
}
|
|
15321
|
+
},
|
|
15322
|
+
"429": {
|
|
15323
|
+
description: "Too many requests; retry after the indicated delay.",
|
|
15324
|
+
content: {
|
|
15325
|
+
"application/json": {
|
|
15326
|
+
schema: {
|
|
15327
|
+
$ref: "#/components/schemas/Error"
|
|
15328
|
+
}
|
|
15329
|
+
}
|
|
15330
|
+
}
|
|
15331
|
+
}
|
|
15332
|
+
},
|
|
15333
|
+
summary: "List Linear projects that can be bound",
|
|
15334
|
+
description: "Returns Linear projects visible to this workspace. Use this to pick a project to bind; a new Khotan project mints its own Linear project on first push.",
|
|
15335
|
+
tags: [
|
|
15336
|
+
"Projects"
|
|
15337
|
+
],
|
|
15338
|
+
operationId: "listLinearProjectOptions",
|
|
15339
|
+
parameters: [
|
|
15340
|
+
{
|
|
15341
|
+
name: "query",
|
|
15342
|
+
in: "query",
|
|
15343
|
+
required: false,
|
|
15344
|
+
schema: {
|
|
15345
|
+
type: "string",
|
|
15346
|
+
maxLength: 200
|
|
15347
|
+
}
|
|
15348
|
+
}
|
|
15349
|
+
],
|
|
15350
|
+
security: [
|
|
15351
|
+
{
|
|
15352
|
+
bearerAuth: []
|
|
15353
|
+
},
|
|
15354
|
+
{
|
|
15355
|
+
apiKeyHeader: []
|
|
15356
|
+
}
|
|
15357
|
+
]
|
|
15358
|
+
}
|
|
15359
|
+
},
|
|
15158
15360
|
"/api/v1/projects/{projectId}": {
|
|
15159
15361
|
get: {
|
|
15160
15362
|
responses: {
|
|
@@ -15383,7 +15585,7 @@ var init_spec = __esm(() => {
|
|
|
15383
15585
|
}
|
|
15384
15586
|
},
|
|
15385
15587
|
summary: "Update a project",
|
|
15386
|
-
description: "Updates a project's Khotan-owned attributes. The slug is immutable, and execution state is never writable here —
|
|
15588
|
+
description: "Updates a project's Khotan-owned attributes. The slug is immutable, and execution state is never writable here — the tracker owns it.",
|
|
15387
15589
|
tags: [
|
|
15388
15590
|
"Projects"
|
|
15389
15591
|
],
|
|
@@ -15484,7 +15686,7 @@ var init_spec = __esm(() => {
|
|
|
15484
15686
|
}
|
|
15485
15687
|
},
|
|
15486
15688
|
summary: "Delete a project",
|
|
15487
|
-
description: "Soft-deletes a project and frees its slug for reuse. The linked
|
|
15689
|
+
description: "Soft-deletes a project and frees its slug for reuse. The linked tracker project is retained.",
|
|
15488
15690
|
tags: [
|
|
15489
15691
|
"Projects"
|
|
15490
15692
|
],
|
|
@@ -15573,6 +15775,10 @@ var init_spec = __esm(() => {
|
|
|
15573
15775
|
title: {
|
|
15574
15776
|
type: "string"
|
|
15575
15777
|
},
|
|
15778
|
+
sectionKey: {
|
|
15779
|
+
nullable: true,
|
|
15780
|
+
type: "string"
|
|
15781
|
+
},
|
|
15576
15782
|
documentId: {
|
|
15577
15783
|
nullable: true,
|
|
15578
15784
|
type: "string"
|
|
@@ -15589,6 +15795,18 @@ var init_spec = __esm(() => {
|
|
|
15589
15795
|
nullable: true,
|
|
15590
15796
|
type: "string"
|
|
15591
15797
|
},
|
|
15798
|
+
startDate: {
|
|
15799
|
+
nullable: true,
|
|
15800
|
+
type: "string"
|
|
15801
|
+
},
|
|
15802
|
+
targetDate: {
|
|
15803
|
+
nullable: true,
|
|
15804
|
+
type: "string"
|
|
15805
|
+
},
|
|
15806
|
+
dependsOnNodeId: {
|
|
15807
|
+
nullable: true,
|
|
15808
|
+
type: "string"
|
|
15809
|
+
},
|
|
15592
15810
|
children: {
|
|
15593
15811
|
type: "array",
|
|
15594
15812
|
items: {
|
|
@@ -15602,10 +15820,14 @@ var init_spec = __esm(() => {
|
|
|
15602
15820
|
"depth",
|
|
15603
15821
|
"position",
|
|
15604
15822
|
"title",
|
|
15823
|
+
"sectionKey",
|
|
15605
15824
|
"documentId",
|
|
15606
15825
|
"body",
|
|
15607
15826
|
"bodyRevision",
|
|
15608
15827
|
"linearMilestoneId",
|
|
15828
|
+
"startDate",
|
|
15829
|
+
"targetDate",
|
|
15830
|
+
"dependsOnNodeId",
|
|
15609
15831
|
"children"
|
|
15610
15832
|
],
|
|
15611
15833
|
additionalProperties: false
|
|
@@ -15647,7 +15869,7 @@ var init_spec = __esm(() => {
|
|
|
15647
15869
|
}
|
|
15648
15870
|
},
|
|
15649
15871
|
summary: "Read a project spec",
|
|
15650
|
-
description: "Returns the project's spec tree limited to the requested altitude: high renders the goal, medium adds phases, low adds items joined with their mirrored
|
|
15872
|
+
description: "Returns the project's spec tree limited to the requested altitude: high renders the goal, medium adds phases, low adds items joined with their mirrored tracker issues. Defaults to high.",
|
|
15651
15873
|
tags: [
|
|
15652
15874
|
"Projects"
|
|
15653
15875
|
],
|
|
@@ -15673,7 +15895,7 @@ var init_spec = __esm(() => {
|
|
|
15673
15895
|
"medium",
|
|
15674
15896
|
"low"
|
|
15675
15897
|
],
|
|
15676
|
-
description: "Depth cap over the one spec tree: high renders the goal, medium adds phases, low adds items and their mirrored
|
|
15898
|
+
description: "Depth cap over the one spec tree: high renders the goal, medium adds phases, low adds items and their mirrored tracker issues."
|
|
15677
15899
|
}
|
|
15678
15900
|
}
|
|
15679
15901
|
],
|
|
@@ -15923,59 +16145,69 @@ var init_spec = __esm(() => {
|
|
|
15923
16145
|
]
|
|
15924
16146
|
}
|
|
15925
16147
|
},
|
|
15926
|
-
"/api/v1/projects/{projectId}/
|
|
15927
|
-
|
|
16148
|
+
"/api/v1/projects/{projectId}/spec/nodes": {
|
|
16149
|
+
post: {
|
|
15928
16150
|
responses: {
|
|
15929
|
-
"
|
|
15930
|
-
description: "The
|
|
16151
|
+
"201": {
|
|
16152
|
+
description: "The created node.",
|
|
15931
16153
|
content: {
|
|
15932
16154
|
"application/json": {
|
|
15933
16155
|
schema: {
|
|
15934
16156
|
type: "object",
|
|
15935
16157
|
properties: {
|
|
15936
|
-
|
|
15937
|
-
type: "
|
|
15938
|
-
|
|
15939
|
-
|
|
15940
|
-
|
|
15941
|
-
|
|
15942
|
-
|
|
15943
|
-
|
|
15944
|
-
|
|
15945
|
-
|
|
15946
|
-
|
|
15947
|
-
|
|
15948
|
-
|
|
15949
|
-
|
|
15950
|
-
|
|
15951
|
-
|
|
15952
|
-
|
|
15953
|
-
|
|
15954
|
-
|
|
15955
|
-
|
|
15956
|
-
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
15960
|
-
|
|
15961
|
-
|
|
15962
|
-
|
|
15963
|
-
|
|
15964
|
-
|
|
15965
|
-
|
|
15966
|
-
|
|
15967
|
-
|
|
15968
|
-
|
|
15969
|
-
|
|
15970
|
-
|
|
15971
|
-
|
|
15972
|
-
|
|
15973
|
-
|
|
15974
|
-
|
|
16158
|
+
id: {
|
|
16159
|
+
type: "string"
|
|
16160
|
+
},
|
|
16161
|
+
parentId: {
|
|
16162
|
+
nullable: true,
|
|
16163
|
+
type: "string"
|
|
16164
|
+
},
|
|
16165
|
+
depth: {
|
|
16166
|
+
type: "number"
|
|
16167
|
+
},
|
|
16168
|
+
position: {
|
|
16169
|
+
type: "number"
|
|
16170
|
+
},
|
|
16171
|
+
title: {
|
|
16172
|
+
type: "string"
|
|
16173
|
+
},
|
|
16174
|
+
sectionKey: {
|
|
16175
|
+
nullable: true,
|
|
16176
|
+
type: "string"
|
|
16177
|
+
},
|
|
16178
|
+
documentId: {
|
|
16179
|
+
nullable: true,
|
|
16180
|
+
type: "string"
|
|
16181
|
+
},
|
|
16182
|
+
linearMilestoneId: {
|
|
16183
|
+
nullable: true,
|
|
16184
|
+
type: "string"
|
|
16185
|
+
},
|
|
16186
|
+
startDate: {
|
|
16187
|
+
nullable: true,
|
|
16188
|
+
type: "string"
|
|
16189
|
+
},
|
|
16190
|
+
targetDate: {
|
|
16191
|
+
nullable: true,
|
|
16192
|
+
type: "string"
|
|
16193
|
+
},
|
|
16194
|
+
dependsOnNodeId: {
|
|
16195
|
+
nullable: true,
|
|
16196
|
+
type: "string"
|
|
15975
16197
|
}
|
|
15976
16198
|
},
|
|
15977
16199
|
required: [
|
|
15978
|
-
"
|
|
16200
|
+
"id",
|
|
16201
|
+
"parentId",
|
|
16202
|
+
"depth",
|
|
16203
|
+
"position",
|
|
16204
|
+
"title",
|
|
16205
|
+
"sectionKey",
|
|
16206
|
+
"documentId",
|
|
16207
|
+
"linearMilestoneId",
|
|
16208
|
+
"startDate",
|
|
16209
|
+
"targetDate",
|
|
16210
|
+
"dependsOnNodeId"
|
|
15979
16211
|
],
|
|
15980
16212
|
additionalProperties: false
|
|
15981
16213
|
}
|
|
@@ -15992,6 +16224,16 @@ var init_spec = __esm(() => {
|
|
|
15992
16224
|
}
|
|
15993
16225
|
}
|
|
15994
16226
|
},
|
|
16227
|
+
"403": {
|
|
16228
|
+
description: "The caller is not permitted to perform this action.",
|
|
16229
|
+
content: {
|
|
16230
|
+
"application/json": {
|
|
16231
|
+
schema: {
|
|
16232
|
+
$ref: "#/components/schemas/Error"
|
|
16233
|
+
}
|
|
16234
|
+
}
|
|
16235
|
+
}
|
|
16236
|
+
},
|
|
15995
16237
|
"404": {
|
|
15996
16238
|
description: "The resource was not found.",
|
|
15997
16239
|
content: {
|
|
@@ -16002,8 +16244,8 @@ var init_spec = __esm(() => {
|
|
|
16002
16244
|
}
|
|
16003
16245
|
}
|
|
16004
16246
|
},
|
|
16005
|
-
"
|
|
16006
|
-
description: "
|
|
16247
|
+
"422": {
|
|
16248
|
+
description: "Response.",
|
|
16007
16249
|
content: {
|
|
16008
16250
|
"application/json": {
|
|
16009
16251
|
schema: {
|
|
@@ -16011,14 +16253,24 @@ var init_spec = __esm(() => {
|
|
|
16011
16253
|
}
|
|
16012
16254
|
}
|
|
16013
16255
|
}
|
|
16014
|
-
}
|
|
16015
|
-
|
|
16016
|
-
|
|
16017
|
-
|
|
16256
|
+
},
|
|
16257
|
+
"429": {
|
|
16258
|
+
description: "Too many requests; retry after the indicated delay.",
|
|
16259
|
+
content: {
|
|
16260
|
+
"application/json": {
|
|
16261
|
+
schema: {
|
|
16262
|
+
$ref: "#/components/schemas/Error"
|
|
16263
|
+
}
|
|
16264
|
+
}
|
|
16265
|
+
}
|
|
16266
|
+
}
|
|
16267
|
+
},
|
|
16268
|
+
summary: "Create a spec node",
|
|
16269
|
+
description: "Creates a child under an existing spec node. Use this to add a delivery phase under the Milestones section, or an item under a phase. The thirteen section headings are created with the project and cannot be added here.",
|
|
16018
16270
|
tags: [
|
|
16019
16271
|
"Projects"
|
|
16020
16272
|
],
|
|
16021
|
-
operationId: "
|
|
16273
|
+
operationId: "createProjectSpecNode",
|
|
16022
16274
|
parameters: [
|
|
16023
16275
|
{
|
|
16024
16276
|
name: "projectId",
|
|
@@ -16028,18 +16280,42 @@ var init_spec = __esm(() => {
|
|
|
16028
16280
|
type: "string",
|
|
16029
16281
|
minLength: 1
|
|
16030
16282
|
}
|
|
16031
|
-
},
|
|
16032
|
-
{
|
|
16033
|
-
name: "limit",
|
|
16034
|
-
in: "query",
|
|
16035
|
-
required: false,
|
|
16036
|
-
schema: {
|
|
16037
|
-
type: "integer",
|
|
16038
|
-
minimum: 1,
|
|
16039
|
-
maximum: 200
|
|
16040
|
-
}
|
|
16041
16283
|
}
|
|
16042
16284
|
],
|
|
16285
|
+
requestBody: {
|
|
16286
|
+
required: true,
|
|
16287
|
+
content: {
|
|
16288
|
+
"application/json": {
|
|
16289
|
+
schema: {
|
|
16290
|
+
type: "object",
|
|
16291
|
+
properties: {
|
|
16292
|
+
parentId: {
|
|
16293
|
+
type: "string",
|
|
16294
|
+
minLength: 1
|
|
16295
|
+
},
|
|
16296
|
+
title: {
|
|
16297
|
+
type: "string",
|
|
16298
|
+
minLength: 1,
|
|
16299
|
+
maxLength: 200
|
|
16300
|
+
},
|
|
16301
|
+
body: {
|
|
16302
|
+
type: "string",
|
|
16303
|
+
maxLength: 1e6
|
|
16304
|
+
},
|
|
16305
|
+
position: {
|
|
16306
|
+
type: "integer",
|
|
16307
|
+
minimum: 0,
|
|
16308
|
+
maximum: 9007199254740991
|
|
16309
|
+
}
|
|
16310
|
+
},
|
|
16311
|
+
required: [
|
|
16312
|
+
"parentId",
|
|
16313
|
+
"title"
|
|
16314
|
+
]
|
|
16315
|
+
}
|
|
16316
|
+
}
|
|
16317
|
+
}
|
|
16318
|
+
},
|
|
16043
16319
|
security: [
|
|
16044
16320
|
{
|
|
16045
16321
|
bearerAuth: []
|
|
@@ -16050,11 +16326,11 @@ var init_spec = __esm(() => {
|
|
|
16050
16326
|
]
|
|
16051
16327
|
}
|
|
16052
16328
|
},
|
|
16053
|
-
"/api/v1/projects/{projectId}/
|
|
16054
|
-
|
|
16329
|
+
"/api/v1/projects/{projectId}/spec/nodes/{nodeId}": {
|
|
16330
|
+
patch: {
|
|
16055
16331
|
responses: {
|
|
16056
16332
|
"200": {
|
|
16057
|
-
description: "The
|
|
16333
|
+
description: "The updated node.",
|
|
16058
16334
|
content: {
|
|
16059
16335
|
"application/json": {
|
|
16060
16336
|
schema: {
|
|
@@ -16063,106 +16339,56 @@ var init_spec = __esm(() => {
|
|
|
16063
16339
|
id: {
|
|
16064
16340
|
type: "string"
|
|
16065
16341
|
},
|
|
16066
|
-
|
|
16342
|
+
parentId: {
|
|
16343
|
+
nullable: true,
|
|
16344
|
+
type: "string"
|
|
16345
|
+
},
|
|
16346
|
+
depth: {
|
|
16067
16347
|
type: "number"
|
|
16068
16348
|
},
|
|
16069
|
-
|
|
16070
|
-
|
|
16349
|
+
position: {
|
|
16350
|
+
type: "number"
|
|
16351
|
+
},
|
|
16352
|
+
title: {
|
|
16071
16353
|
type: "string"
|
|
16072
16354
|
},
|
|
16073
|
-
|
|
16355
|
+
sectionKey: {
|
|
16356
|
+
nullable: true,
|
|
16074
16357
|
type: "string"
|
|
16075
16358
|
},
|
|
16076
|
-
|
|
16359
|
+
documentId: {
|
|
16360
|
+
nullable: true,
|
|
16077
16361
|
type: "string"
|
|
16078
16362
|
},
|
|
16079
|
-
|
|
16363
|
+
linearMilestoneId: {
|
|
16364
|
+
nullable: true,
|
|
16080
16365
|
type: "string"
|
|
16081
16366
|
},
|
|
16082
|
-
|
|
16083
|
-
|
|
16367
|
+
startDate: {
|
|
16368
|
+
nullable: true,
|
|
16369
|
+
type: "string"
|
|
16084
16370
|
},
|
|
16085
|
-
|
|
16086
|
-
|
|
16087
|
-
|
|
16088
|
-
type: "object",
|
|
16089
|
-
properties: {
|
|
16090
|
-
documentId: {
|
|
16091
|
-
type: "string"
|
|
16092
|
-
},
|
|
16093
|
-
nodeId: {
|
|
16094
|
-
nullable: true,
|
|
16095
|
-
type: "string"
|
|
16096
|
-
},
|
|
16097
|
-
title: {
|
|
16098
|
-
type: "string"
|
|
16099
|
-
},
|
|
16100
|
-
revision: {
|
|
16101
|
-
type: "number"
|
|
16102
|
-
},
|
|
16103
|
-
content: {
|
|
16104
|
-
type: "string"
|
|
16105
|
-
},
|
|
16106
|
-
previousContent: {
|
|
16107
|
-
nullable: true,
|
|
16108
|
-
type: "string"
|
|
16109
|
-
}
|
|
16110
|
-
},
|
|
16111
|
-
required: [
|
|
16112
|
-
"documentId",
|
|
16113
|
-
"nodeId",
|
|
16114
|
-
"title",
|
|
16115
|
-
"revision",
|
|
16116
|
-
"content",
|
|
16117
|
-
"previousContent"
|
|
16118
|
-
],
|
|
16119
|
-
additionalProperties: false
|
|
16120
|
-
}
|
|
16371
|
+
targetDate: {
|
|
16372
|
+
nullable: true,
|
|
16373
|
+
type: "string"
|
|
16121
16374
|
},
|
|
16122
|
-
|
|
16123
|
-
|
|
16124
|
-
|
|
16125
|
-
type: "object",
|
|
16126
|
-
properties: {
|
|
16127
|
-
direction: {
|
|
16128
|
-
type: "string"
|
|
16129
|
-
},
|
|
16130
|
-
kind: {
|
|
16131
|
-
type: "string"
|
|
16132
|
-
},
|
|
16133
|
-
ref: {
|
|
16134
|
-
type: "string"
|
|
16135
|
-
},
|
|
16136
|
-
url: {
|
|
16137
|
-
nullable: true,
|
|
16138
|
-
type: "string"
|
|
16139
|
-
},
|
|
16140
|
-
label: {
|
|
16141
|
-
nullable: true,
|
|
16142
|
-
type: "string"
|
|
16143
|
-
}
|
|
16144
|
-
},
|
|
16145
|
-
required: [
|
|
16146
|
-
"direction",
|
|
16147
|
-
"kind",
|
|
16148
|
-
"ref",
|
|
16149
|
-
"url",
|
|
16150
|
-
"label"
|
|
16151
|
-
],
|
|
16152
|
-
additionalProperties: false
|
|
16153
|
-
}
|
|
16375
|
+
dependsOnNodeId: {
|
|
16376
|
+
nullable: true,
|
|
16377
|
+
type: "string"
|
|
16154
16378
|
}
|
|
16155
16379
|
},
|
|
16156
16380
|
required: [
|
|
16157
16381
|
"id",
|
|
16158
|
-
"
|
|
16159
|
-
"
|
|
16160
|
-
"
|
|
16161
|
-
"
|
|
16162
|
-
"
|
|
16163
|
-
"
|
|
16164
|
-
"
|
|
16165
|
-
"
|
|
16382
|
+
"parentId",
|
|
16383
|
+
"depth",
|
|
16384
|
+
"position",
|
|
16385
|
+
"title",
|
|
16386
|
+
"sectionKey",
|
|
16387
|
+
"documentId",
|
|
16388
|
+
"linearMilestoneId",
|
|
16389
|
+
"startDate",
|
|
16390
|
+
"targetDate",
|
|
16391
|
+
"dependsOnNodeId"
|
|
16166
16392
|
],
|
|
16167
16393
|
additionalProperties: false
|
|
16168
16394
|
}
|
|
@@ -16179,6 +16405,16 @@ var init_spec = __esm(() => {
|
|
|
16179
16405
|
}
|
|
16180
16406
|
}
|
|
16181
16407
|
},
|
|
16408
|
+
"403": {
|
|
16409
|
+
description: "The caller is not permitted to perform this action.",
|
|
16410
|
+
content: {
|
|
16411
|
+
"application/json": {
|
|
16412
|
+
schema: {
|
|
16413
|
+
$ref: "#/components/schemas/Error"
|
|
16414
|
+
}
|
|
16415
|
+
}
|
|
16416
|
+
}
|
|
16417
|
+
},
|
|
16182
16418
|
"404": {
|
|
16183
16419
|
description: "The resource was not found.",
|
|
16184
16420
|
content: {
|
|
@@ -16189,6 +16425,16 @@ var init_spec = __esm(() => {
|
|
|
16189
16425
|
}
|
|
16190
16426
|
}
|
|
16191
16427
|
},
|
|
16428
|
+
"422": {
|
|
16429
|
+
description: "Response.",
|
|
16430
|
+
content: {
|
|
16431
|
+
"application/json": {
|
|
16432
|
+
schema: {
|
|
16433
|
+
$ref: "#/components/schemas/Error"
|
|
16434
|
+
}
|
|
16435
|
+
}
|
|
16436
|
+
}
|
|
16437
|
+
},
|
|
16192
16438
|
"429": {
|
|
16193
16439
|
description: "Too many requests; retry after the indicated delay.",
|
|
16194
16440
|
content: {
|
|
@@ -16200,12 +16446,12 @@ var init_spec = __esm(() => {
|
|
|
16200
16446
|
}
|
|
16201
16447
|
}
|
|
16202
16448
|
},
|
|
16203
|
-
summary: "
|
|
16204
|
-
description: "
|
|
16449
|
+
summary: "Update a spec node",
|
|
16450
|
+
description: "Updates a node's title, sibling position, parent, or milestone plan. A move is applied first so a node that is becoming a phase can then accept dates. Each field is optional; omitted fields are left alone.",
|
|
16205
16451
|
tags: [
|
|
16206
16452
|
"Projects"
|
|
16207
16453
|
],
|
|
16208
|
-
operationId: "
|
|
16454
|
+
operationId: "updateProjectSpecNode",
|
|
16209
16455
|
parameters: [
|
|
16210
16456
|
{
|
|
16211
16457
|
name: "projectId",
|
|
@@ -16217,16 +16463,60 @@ var init_spec = __esm(() => {
|
|
|
16217
16463
|
}
|
|
16218
16464
|
},
|
|
16219
16465
|
{
|
|
16220
|
-
name: "
|
|
16466
|
+
name: "nodeId",
|
|
16221
16467
|
in: "path",
|
|
16222
16468
|
required: true,
|
|
16223
16469
|
schema: {
|
|
16224
|
-
type: "
|
|
16225
|
-
|
|
16226
|
-
maximum: 9007199254740991
|
|
16470
|
+
type: "string",
|
|
16471
|
+
minLength: 1
|
|
16227
16472
|
}
|
|
16228
16473
|
}
|
|
16229
16474
|
],
|
|
16475
|
+
requestBody: {
|
|
16476
|
+
required: true,
|
|
16477
|
+
content: {
|
|
16478
|
+
"application/json": {
|
|
16479
|
+
schema: {
|
|
16480
|
+
type: "object",
|
|
16481
|
+
properties: {
|
|
16482
|
+
title: {
|
|
16483
|
+
type: "string",
|
|
16484
|
+
minLength: 1,
|
|
16485
|
+
maxLength: 200
|
|
16486
|
+
},
|
|
16487
|
+
position: {
|
|
16488
|
+
type: "integer",
|
|
16489
|
+
minimum: 0,
|
|
16490
|
+
maximum: 9007199254740991
|
|
16491
|
+
},
|
|
16492
|
+
parentId: {
|
|
16493
|
+
description: "Move the node under this parent before applying the other fields.",
|
|
16494
|
+
type: "string",
|
|
16495
|
+
minLength: 1
|
|
16496
|
+
},
|
|
16497
|
+
startDate: {
|
|
16498
|
+
description: "Milestone plan start. Only valid on a phase.",
|
|
16499
|
+
nullable: true,
|
|
16500
|
+
type: "string",
|
|
16501
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}(?:T[\\d:.Z+-]+)?$"
|
|
16502
|
+
},
|
|
16503
|
+
targetDate: {
|
|
16504
|
+
description: "Milestone plan target. Only valid on a phase.",
|
|
16505
|
+
nullable: true,
|
|
16506
|
+
type: "string",
|
|
16507
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}(?:T[\\d:.Z+-]+)?$"
|
|
16508
|
+
},
|
|
16509
|
+
dependsOnNodeId: {
|
|
16510
|
+
description: "Milestone this phase waits on. Only valid on a phase.",
|
|
16511
|
+
nullable: true,
|
|
16512
|
+
type: "string",
|
|
16513
|
+
minLength: 1
|
|
16514
|
+
}
|
|
16515
|
+
}
|
|
16516
|
+
}
|
|
16517
|
+
}
|
|
16518
|
+
}
|
|
16519
|
+
},
|
|
16230
16520
|
security: [
|
|
16231
16521
|
{
|
|
16232
16522
|
bearerAuth: []
|
|
@@ -16235,39 +16525,444 @@ var init_spec = __esm(() => {
|
|
|
16235
16525
|
apiKeyHeader: []
|
|
16236
16526
|
}
|
|
16237
16527
|
]
|
|
16238
|
-
}
|
|
16239
|
-
|
|
16240
|
-
"/api/v1/projects/{projectId}/members": {
|
|
16241
|
-
get: {
|
|
16528
|
+
},
|
|
16529
|
+
delete: {
|
|
16242
16530
|
responses: {
|
|
16243
|
-
"
|
|
16244
|
-
description: "The
|
|
16531
|
+
"204": {
|
|
16532
|
+
description: "The node was deleted."
|
|
16533
|
+
},
|
|
16534
|
+
"401": {
|
|
16535
|
+
description: "Authentication is missing or invalid.",
|
|
16245
16536
|
content: {
|
|
16246
16537
|
"application/json": {
|
|
16247
16538
|
schema: {
|
|
16248
|
-
|
|
16249
|
-
|
|
16250
|
-
|
|
16251
|
-
|
|
16252
|
-
|
|
16253
|
-
|
|
16254
|
-
|
|
16255
|
-
|
|
16256
|
-
|
|
16257
|
-
|
|
16258
|
-
|
|
16259
|
-
|
|
16260
|
-
|
|
16261
|
-
|
|
16262
|
-
|
|
16263
|
-
|
|
16264
|
-
|
|
16265
|
-
|
|
16266
|
-
|
|
16267
|
-
|
|
16268
|
-
|
|
16269
|
-
|
|
16270
|
-
|
|
16539
|
+
$ref: "#/components/schemas/Error"
|
|
16540
|
+
}
|
|
16541
|
+
}
|
|
16542
|
+
}
|
|
16543
|
+
},
|
|
16544
|
+
"403": {
|
|
16545
|
+
description: "The caller is not permitted to perform this action.",
|
|
16546
|
+
content: {
|
|
16547
|
+
"application/json": {
|
|
16548
|
+
schema: {
|
|
16549
|
+
$ref: "#/components/schemas/Error"
|
|
16550
|
+
}
|
|
16551
|
+
}
|
|
16552
|
+
}
|
|
16553
|
+
},
|
|
16554
|
+
"404": {
|
|
16555
|
+
description: "The resource was not found.",
|
|
16556
|
+
content: {
|
|
16557
|
+
"application/json": {
|
|
16558
|
+
schema: {
|
|
16559
|
+
$ref: "#/components/schemas/Error"
|
|
16560
|
+
}
|
|
16561
|
+
}
|
|
16562
|
+
}
|
|
16563
|
+
},
|
|
16564
|
+
"422": {
|
|
16565
|
+
description: "Response.",
|
|
16566
|
+
content: {
|
|
16567
|
+
"application/json": {
|
|
16568
|
+
schema: {
|
|
16569
|
+
$ref: "#/components/schemas/Error"
|
|
16570
|
+
}
|
|
16571
|
+
}
|
|
16572
|
+
}
|
|
16573
|
+
},
|
|
16574
|
+
"429": {
|
|
16575
|
+
description: "Too many requests; retry after the indicated delay.",
|
|
16576
|
+
content: {
|
|
16577
|
+
"application/json": {
|
|
16578
|
+
schema: {
|
|
16579
|
+
$ref: "#/components/schemas/Error"
|
|
16580
|
+
}
|
|
16581
|
+
}
|
|
16582
|
+
}
|
|
16583
|
+
}
|
|
16584
|
+
},
|
|
16585
|
+
summary: "Delete a spec node",
|
|
16586
|
+
description: "Soft-deletes the node and its descendants. The goal node cannot be deleted — delete the project instead.",
|
|
16587
|
+
tags: [
|
|
16588
|
+
"Projects"
|
|
16589
|
+
],
|
|
16590
|
+
operationId: "deleteProjectSpecNode",
|
|
16591
|
+
parameters: [
|
|
16592
|
+
{
|
|
16593
|
+
name: "projectId",
|
|
16594
|
+
in: "path",
|
|
16595
|
+
required: true,
|
|
16596
|
+
schema: {
|
|
16597
|
+
type: "string",
|
|
16598
|
+
minLength: 1
|
|
16599
|
+
}
|
|
16600
|
+
},
|
|
16601
|
+
{
|
|
16602
|
+
name: "nodeId",
|
|
16603
|
+
in: "path",
|
|
16604
|
+
required: true,
|
|
16605
|
+
schema: {
|
|
16606
|
+
type: "string",
|
|
16607
|
+
minLength: 1
|
|
16608
|
+
}
|
|
16609
|
+
}
|
|
16610
|
+
],
|
|
16611
|
+
security: [
|
|
16612
|
+
{
|
|
16613
|
+
bearerAuth: []
|
|
16614
|
+
},
|
|
16615
|
+
{
|
|
16616
|
+
apiKeyHeader: []
|
|
16617
|
+
}
|
|
16618
|
+
]
|
|
16619
|
+
}
|
|
16620
|
+
},
|
|
16621
|
+
"/api/v1/projects/{projectId}/revisions": {
|
|
16622
|
+
get: {
|
|
16623
|
+
responses: {
|
|
16624
|
+
"200": {
|
|
16625
|
+
description: "The project's committed spec revisions.",
|
|
16626
|
+
content: {
|
|
16627
|
+
"application/json": {
|
|
16628
|
+
schema: {
|
|
16629
|
+
type: "object",
|
|
16630
|
+
properties: {
|
|
16631
|
+
revisions: {
|
|
16632
|
+
type: "array",
|
|
16633
|
+
items: {
|
|
16634
|
+
type: "object",
|
|
16635
|
+
properties: {
|
|
16636
|
+
id: {
|
|
16637
|
+
type: "string"
|
|
16638
|
+
},
|
|
16639
|
+
revision: {
|
|
16640
|
+
type: "number"
|
|
16641
|
+
},
|
|
16642
|
+
changeSummary: {
|
|
16643
|
+
nullable: true,
|
|
16644
|
+
type: "string"
|
|
16645
|
+
},
|
|
16646
|
+
actorType: {
|
|
16647
|
+
type: "string"
|
|
16648
|
+
},
|
|
16649
|
+
actorId: {
|
|
16650
|
+
type: "string"
|
|
16651
|
+
},
|
|
16652
|
+
committedAt: {
|
|
16653
|
+
type: "string"
|
|
16654
|
+
},
|
|
16655
|
+
documentCount: {
|
|
16656
|
+
type: "number"
|
|
16657
|
+
}
|
|
16658
|
+
},
|
|
16659
|
+
required: [
|
|
16660
|
+
"id",
|
|
16661
|
+
"revision",
|
|
16662
|
+
"changeSummary",
|
|
16663
|
+
"actorType",
|
|
16664
|
+
"actorId",
|
|
16665
|
+
"committedAt",
|
|
16666
|
+
"documentCount"
|
|
16667
|
+
],
|
|
16668
|
+
additionalProperties: false
|
|
16669
|
+
}
|
|
16670
|
+
}
|
|
16671
|
+
},
|
|
16672
|
+
required: [
|
|
16673
|
+
"revisions"
|
|
16674
|
+
],
|
|
16675
|
+
additionalProperties: false
|
|
16676
|
+
}
|
|
16677
|
+
}
|
|
16678
|
+
}
|
|
16679
|
+
},
|
|
16680
|
+
"401": {
|
|
16681
|
+
description: "Authentication is missing or invalid.",
|
|
16682
|
+
content: {
|
|
16683
|
+
"application/json": {
|
|
16684
|
+
schema: {
|
|
16685
|
+
$ref: "#/components/schemas/Error"
|
|
16686
|
+
}
|
|
16687
|
+
}
|
|
16688
|
+
}
|
|
16689
|
+
},
|
|
16690
|
+
"404": {
|
|
16691
|
+
description: "The resource was not found.",
|
|
16692
|
+
content: {
|
|
16693
|
+
"application/json": {
|
|
16694
|
+
schema: {
|
|
16695
|
+
$ref: "#/components/schemas/Error"
|
|
16696
|
+
}
|
|
16697
|
+
}
|
|
16698
|
+
}
|
|
16699
|
+
},
|
|
16700
|
+
"429": {
|
|
16701
|
+
description: "Too many requests; retry after the indicated delay.",
|
|
16702
|
+
content: {
|
|
16703
|
+
"application/json": {
|
|
16704
|
+
schema: {
|
|
16705
|
+
$ref: "#/components/schemas/Error"
|
|
16706
|
+
}
|
|
16707
|
+
}
|
|
16708
|
+
}
|
|
16709
|
+
}
|
|
16710
|
+
},
|
|
16711
|
+
summary: "List spec revisions",
|
|
16712
|
+
description: "Returns the project's committed spec revisions newest-first, with actor, timestamp, change summary, and the number of documents each revision bundled.",
|
|
16713
|
+
tags: [
|
|
16714
|
+
"Projects"
|
|
16715
|
+
],
|
|
16716
|
+
operationId: "listProjectSpecRevisions",
|
|
16717
|
+
parameters: [
|
|
16718
|
+
{
|
|
16719
|
+
name: "projectId",
|
|
16720
|
+
in: "path",
|
|
16721
|
+
required: true,
|
|
16722
|
+
schema: {
|
|
16723
|
+
type: "string",
|
|
16724
|
+
minLength: 1
|
|
16725
|
+
}
|
|
16726
|
+
},
|
|
16727
|
+
{
|
|
16728
|
+
name: "limit",
|
|
16729
|
+
in: "query",
|
|
16730
|
+
required: false,
|
|
16731
|
+
schema: {
|
|
16732
|
+
type: "integer",
|
|
16733
|
+
minimum: 1,
|
|
16734
|
+
maximum: 200
|
|
16735
|
+
}
|
|
16736
|
+
}
|
|
16737
|
+
],
|
|
16738
|
+
security: [
|
|
16739
|
+
{
|
|
16740
|
+
bearerAuth: []
|
|
16741
|
+
},
|
|
16742
|
+
{
|
|
16743
|
+
apiKeyHeader: []
|
|
16744
|
+
}
|
|
16745
|
+
]
|
|
16746
|
+
}
|
|
16747
|
+
},
|
|
16748
|
+
"/api/v1/projects/{projectId}/revisions/{revision}": {
|
|
16749
|
+
get: {
|
|
16750
|
+
responses: {
|
|
16751
|
+
"200": {
|
|
16752
|
+
description: "The revision with its diff and provenance.",
|
|
16753
|
+
content: {
|
|
16754
|
+
"application/json": {
|
|
16755
|
+
schema: {
|
|
16756
|
+
type: "object",
|
|
16757
|
+
properties: {
|
|
16758
|
+
id: {
|
|
16759
|
+
type: "string"
|
|
16760
|
+
},
|
|
16761
|
+
revision: {
|
|
16762
|
+
type: "number"
|
|
16763
|
+
},
|
|
16764
|
+
changeSummary: {
|
|
16765
|
+
nullable: true,
|
|
16766
|
+
type: "string"
|
|
16767
|
+
},
|
|
16768
|
+
actorType: {
|
|
16769
|
+
type: "string"
|
|
16770
|
+
},
|
|
16771
|
+
actorId: {
|
|
16772
|
+
type: "string"
|
|
16773
|
+
},
|
|
16774
|
+
committedAt: {
|
|
16775
|
+
type: "string"
|
|
16776
|
+
},
|
|
16777
|
+
documentCount: {
|
|
16778
|
+
type: "number"
|
|
16779
|
+
},
|
|
16780
|
+
documents: {
|
|
16781
|
+
type: "array",
|
|
16782
|
+
items: {
|
|
16783
|
+
type: "object",
|
|
16784
|
+
properties: {
|
|
16785
|
+
documentId: {
|
|
16786
|
+
type: "string"
|
|
16787
|
+
},
|
|
16788
|
+
nodeId: {
|
|
16789
|
+
nullable: true,
|
|
16790
|
+
type: "string"
|
|
16791
|
+
},
|
|
16792
|
+
title: {
|
|
16793
|
+
type: "string"
|
|
16794
|
+
},
|
|
16795
|
+
revision: {
|
|
16796
|
+
type: "number"
|
|
16797
|
+
},
|
|
16798
|
+
content: {
|
|
16799
|
+
type: "string"
|
|
16800
|
+
},
|
|
16801
|
+
previousContent: {
|
|
16802
|
+
nullable: true,
|
|
16803
|
+
type: "string"
|
|
16804
|
+
}
|
|
16805
|
+
},
|
|
16806
|
+
required: [
|
|
16807
|
+
"documentId",
|
|
16808
|
+
"nodeId",
|
|
16809
|
+
"title",
|
|
16810
|
+
"revision",
|
|
16811
|
+
"content",
|
|
16812
|
+
"previousContent"
|
|
16813
|
+
],
|
|
16814
|
+
additionalProperties: false
|
|
16815
|
+
}
|
|
16816
|
+
},
|
|
16817
|
+
links: {
|
|
16818
|
+
type: "array",
|
|
16819
|
+
items: {
|
|
16820
|
+
type: "object",
|
|
16821
|
+
properties: {
|
|
16822
|
+
direction: {
|
|
16823
|
+
type: "string"
|
|
16824
|
+
},
|
|
16825
|
+
kind: {
|
|
16826
|
+
type: "string"
|
|
16827
|
+
},
|
|
16828
|
+
ref: {
|
|
16829
|
+
type: "string"
|
|
16830
|
+
},
|
|
16831
|
+
url: {
|
|
16832
|
+
nullable: true,
|
|
16833
|
+
type: "string"
|
|
16834
|
+
},
|
|
16835
|
+
label: {
|
|
16836
|
+
nullable: true,
|
|
16837
|
+
type: "string"
|
|
16838
|
+
}
|
|
16839
|
+
},
|
|
16840
|
+
required: [
|
|
16841
|
+
"direction",
|
|
16842
|
+
"kind",
|
|
16843
|
+
"ref",
|
|
16844
|
+
"url",
|
|
16845
|
+
"label"
|
|
16846
|
+
],
|
|
16847
|
+
additionalProperties: false
|
|
16848
|
+
}
|
|
16849
|
+
}
|
|
16850
|
+
},
|
|
16851
|
+
required: [
|
|
16852
|
+
"id",
|
|
16853
|
+
"revision",
|
|
16854
|
+
"changeSummary",
|
|
16855
|
+
"actorType",
|
|
16856
|
+
"actorId",
|
|
16857
|
+
"committedAt",
|
|
16858
|
+
"documentCount",
|
|
16859
|
+
"documents",
|
|
16860
|
+
"links"
|
|
16861
|
+
],
|
|
16862
|
+
additionalProperties: false
|
|
16863
|
+
}
|
|
16864
|
+
}
|
|
16865
|
+
}
|
|
16866
|
+
},
|
|
16867
|
+
"401": {
|
|
16868
|
+
description: "Authentication is missing or invalid.",
|
|
16869
|
+
content: {
|
|
16870
|
+
"application/json": {
|
|
16871
|
+
schema: {
|
|
16872
|
+
$ref: "#/components/schemas/Error"
|
|
16873
|
+
}
|
|
16874
|
+
}
|
|
16875
|
+
}
|
|
16876
|
+
},
|
|
16877
|
+
"404": {
|
|
16878
|
+
description: "The resource was not found.",
|
|
16879
|
+
content: {
|
|
16880
|
+
"application/json": {
|
|
16881
|
+
schema: {
|
|
16882
|
+
$ref: "#/components/schemas/Error"
|
|
16883
|
+
}
|
|
16884
|
+
}
|
|
16885
|
+
}
|
|
16886
|
+
},
|
|
16887
|
+
"429": {
|
|
16888
|
+
description: "Too many requests; retry after the indicated delay.",
|
|
16889
|
+
content: {
|
|
16890
|
+
"application/json": {
|
|
16891
|
+
schema: {
|
|
16892
|
+
$ref: "#/components/schemas/Error"
|
|
16893
|
+
}
|
|
16894
|
+
}
|
|
16895
|
+
}
|
|
16896
|
+
}
|
|
16897
|
+
},
|
|
16898
|
+
summary: "Get a spec revision",
|
|
16899
|
+
description: "Returns one committed spec revision: each bundled document's content alongside the previous revision's content, plus the cause and effect provenance edges attached to it.",
|
|
16900
|
+
tags: [
|
|
16901
|
+
"Projects"
|
|
16902
|
+
],
|
|
16903
|
+
operationId: "getProjectSpecRevision",
|
|
16904
|
+
parameters: [
|
|
16905
|
+
{
|
|
16906
|
+
name: "projectId",
|
|
16907
|
+
in: "path",
|
|
16908
|
+
required: true,
|
|
16909
|
+
schema: {
|
|
16910
|
+
type: "string",
|
|
16911
|
+
minLength: 1
|
|
16912
|
+
}
|
|
16913
|
+
},
|
|
16914
|
+
{
|
|
16915
|
+
name: "revision",
|
|
16916
|
+
in: "path",
|
|
16917
|
+
required: true,
|
|
16918
|
+
schema: {
|
|
16919
|
+
type: "integer",
|
|
16920
|
+
minimum: 1,
|
|
16921
|
+
maximum: 9007199254740991
|
|
16922
|
+
}
|
|
16923
|
+
}
|
|
16924
|
+
],
|
|
16925
|
+
security: [
|
|
16926
|
+
{
|
|
16927
|
+
bearerAuth: []
|
|
16928
|
+
},
|
|
16929
|
+
{
|
|
16930
|
+
apiKeyHeader: []
|
|
16931
|
+
}
|
|
16932
|
+
]
|
|
16933
|
+
}
|
|
16934
|
+
},
|
|
16935
|
+
"/api/v1/projects/{projectId}/members": {
|
|
16936
|
+
get: {
|
|
16937
|
+
responses: {
|
|
16938
|
+
"200": {
|
|
16939
|
+
description: "The project's members.",
|
|
16940
|
+
content: {
|
|
16941
|
+
"application/json": {
|
|
16942
|
+
schema: {
|
|
16943
|
+
type: "object",
|
|
16944
|
+
properties: {
|
|
16945
|
+
members: {
|
|
16946
|
+
type: "array",
|
|
16947
|
+
items: {
|
|
16948
|
+
type: "object",
|
|
16949
|
+
properties: {
|
|
16950
|
+
id: {
|
|
16951
|
+
type: "string"
|
|
16952
|
+
},
|
|
16953
|
+
resourceKind: {
|
|
16954
|
+
type: "string"
|
|
16955
|
+
},
|
|
16956
|
+
resourceId: {
|
|
16957
|
+
type: "string"
|
|
16958
|
+
},
|
|
16959
|
+
attachedAt: {
|
|
16960
|
+
type: "string"
|
|
16961
|
+
}
|
|
16962
|
+
},
|
|
16963
|
+
required: [
|
|
16964
|
+
"id",
|
|
16965
|
+
"resourceKind",
|
|
16271
16966
|
"resourceId",
|
|
16272
16967
|
"attachedAt"
|
|
16273
16968
|
],
|
|
@@ -16276,15 +16971,920 @@ var init_spec = __esm(() => {
|
|
|
16276
16971
|
}
|
|
16277
16972
|
},
|
|
16278
16973
|
required: [
|
|
16279
|
-
"members"
|
|
16974
|
+
"members"
|
|
16975
|
+
],
|
|
16976
|
+
additionalProperties: false
|
|
16977
|
+
}
|
|
16978
|
+
}
|
|
16979
|
+
}
|
|
16980
|
+
},
|
|
16981
|
+
"401": {
|
|
16982
|
+
description: "Authentication is missing or invalid.",
|
|
16983
|
+
content: {
|
|
16984
|
+
"application/json": {
|
|
16985
|
+
schema: {
|
|
16986
|
+
$ref: "#/components/schemas/Error"
|
|
16987
|
+
}
|
|
16988
|
+
}
|
|
16989
|
+
}
|
|
16990
|
+
},
|
|
16991
|
+
"404": {
|
|
16992
|
+
description: "The resource was not found.",
|
|
16993
|
+
content: {
|
|
16994
|
+
"application/json": {
|
|
16995
|
+
schema: {
|
|
16996
|
+
$ref: "#/components/schemas/Error"
|
|
16997
|
+
}
|
|
16998
|
+
}
|
|
16999
|
+
}
|
|
17000
|
+
},
|
|
17001
|
+
"429": {
|
|
17002
|
+
description: "Too many requests; retry after the indicated delay.",
|
|
17003
|
+
content: {
|
|
17004
|
+
"application/json": {
|
|
17005
|
+
schema: {
|
|
17006
|
+
$ref: "#/components/schemas/Error"
|
|
17007
|
+
}
|
|
17008
|
+
}
|
|
17009
|
+
}
|
|
17010
|
+
}
|
|
17011
|
+
},
|
|
17012
|
+
summary: "List project members",
|
|
17013
|
+
description: "Returns the embedded apps, pipelines, and databases attached to this project.",
|
|
17014
|
+
tags: [
|
|
17015
|
+
"Projects"
|
|
17016
|
+
],
|
|
17017
|
+
operationId: "listProjectMembers",
|
|
17018
|
+
parameters: [
|
|
17019
|
+
{
|
|
17020
|
+
name: "projectId",
|
|
17021
|
+
in: "path",
|
|
17022
|
+
required: true,
|
|
17023
|
+
schema: {
|
|
17024
|
+
type: "string",
|
|
17025
|
+
minLength: 1
|
|
17026
|
+
}
|
|
17027
|
+
}
|
|
17028
|
+
],
|
|
17029
|
+
security: [
|
|
17030
|
+
{
|
|
17031
|
+
bearerAuth: []
|
|
17032
|
+
},
|
|
17033
|
+
{
|
|
17034
|
+
apiKeyHeader: []
|
|
17035
|
+
}
|
|
17036
|
+
]
|
|
17037
|
+
},
|
|
17038
|
+
post: {
|
|
17039
|
+
responses: {
|
|
17040
|
+
"201": {
|
|
17041
|
+
description: "The created membership.",
|
|
17042
|
+
content: {
|
|
17043
|
+
"application/json": {
|
|
17044
|
+
schema: {
|
|
17045
|
+
type: "object",
|
|
17046
|
+
properties: {
|
|
17047
|
+
id: {
|
|
17048
|
+
type: "string"
|
|
17049
|
+
},
|
|
17050
|
+
resourceKind: {
|
|
17051
|
+
type: "string"
|
|
17052
|
+
},
|
|
17053
|
+
resourceId: {
|
|
17054
|
+
type: "string"
|
|
17055
|
+
},
|
|
17056
|
+
attachedAt: {
|
|
17057
|
+
type: "string"
|
|
17058
|
+
}
|
|
17059
|
+
},
|
|
17060
|
+
required: [
|
|
17061
|
+
"id",
|
|
17062
|
+
"resourceKind",
|
|
17063
|
+
"resourceId",
|
|
17064
|
+
"attachedAt"
|
|
17065
|
+
],
|
|
17066
|
+
additionalProperties: false
|
|
17067
|
+
}
|
|
17068
|
+
}
|
|
17069
|
+
}
|
|
17070
|
+
},
|
|
17071
|
+
"401": {
|
|
17072
|
+
description: "Authentication is missing or invalid.",
|
|
17073
|
+
content: {
|
|
17074
|
+
"application/json": {
|
|
17075
|
+
schema: {
|
|
17076
|
+
$ref: "#/components/schemas/Error"
|
|
17077
|
+
}
|
|
17078
|
+
}
|
|
17079
|
+
}
|
|
17080
|
+
},
|
|
17081
|
+
"403": {
|
|
17082
|
+
description: "The caller is not permitted to perform this action.",
|
|
17083
|
+
content: {
|
|
17084
|
+
"application/json": {
|
|
17085
|
+
schema: {
|
|
17086
|
+
$ref: "#/components/schemas/Error"
|
|
17087
|
+
}
|
|
17088
|
+
}
|
|
17089
|
+
}
|
|
17090
|
+
},
|
|
17091
|
+
"404": {
|
|
17092
|
+
description: "The resource was not found.",
|
|
17093
|
+
content: {
|
|
17094
|
+
"application/json": {
|
|
17095
|
+
schema: {
|
|
17096
|
+
$ref: "#/components/schemas/Error"
|
|
17097
|
+
}
|
|
17098
|
+
}
|
|
17099
|
+
}
|
|
17100
|
+
},
|
|
17101
|
+
"409": {
|
|
17102
|
+
description: "Response.",
|
|
17103
|
+
content: {
|
|
17104
|
+
"application/json": {
|
|
17105
|
+
schema: {
|
|
17106
|
+
$ref: "#/components/schemas/Error"
|
|
17107
|
+
}
|
|
17108
|
+
}
|
|
17109
|
+
}
|
|
17110
|
+
},
|
|
17111
|
+
"429": {
|
|
17112
|
+
description: "Too many requests; retry after the indicated delay.",
|
|
17113
|
+
content: {
|
|
17114
|
+
"application/json": {
|
|
17115
|
+
schema: {
|
|
17116
|
+
$ref: "#/components/schemas/Error"
|
|
17117
|
+
}
|
|
17118
|
+
}
|
|
17119
|
+
}
|
|
17120
|
+
}
|
|
17121
|
+
},
|
|
17122
|
+
summary: "Attach a resource to a project",
|
|
17123
|
+
description: "Attaches an embedded app, pipeline, or database. A resource already attached elsewhere returns 409 until it is detached.",
|
|
17124
|
+
tags: [
|
|
17125
|
+
"Projects"
|
|
17126
|
+
],
|
|
17127
|
+
operationId: "attachProjectMember",
|
|
17128
|
+
parameters: [
|
|
17129
|
+
{
|
|
17130
|
+
name: "projectId",
|
|
17131
|
+
in: "path",
|
|
17132
|
+
required: true,
|
|
17133
|
+
schema: {
|
|
17134
|
+
type: "string",
|
|
17135
|
+
minLength: 1
|
|
17136
|
+
}
|
|
17137
|
+
}
|
|
17138
|
+
],
|
|
17139
|
+
requestBody: {
|
|
17140
|
+
required: true,
|
|
17141
|
+
content: {
|
|
17142
|
+
"application/json": {
|
|
17143
|
+
schema: {
|
|
17144
|
+
type: "object",
|
|
17145
|
+
properties: {
|
|
17146
|
+
resourceKind: {
|
|
17147
|
+
type: "string",
|
|
17148
|
+
enum: [
|
|
17149
|
+
"app",
|
|
17150
|
+
"pipeline",
|
|
17151
|
+
"database"
|
|
17152
|
+
]
|
|
17153
|
+
},
|
|
17154
|
+
resourceId: {
|
|
17155
|
+
type: "string",
|
|
17156
|
+
minLength: 1
|
|
17157
|
+
}
|
|
17158
|
+
},
|
|
17159
|
+
required: [
|
|
17160
|
+
"resourceKind",
|
|
17161
|
+
"resourceId"
|
|
17162
|
+
]
|
|
17163
|
+
}
|
|
17164
|
+
}
|
|
17165
|
+
}
|
|
17166
|
+
},
|
|
17167
|
+
security: [
|
|
17168
|
+
{
|
|
17169
|
+
bearerAuth: []
|
|
17170
|
+
},
|
|
17171
|
+
{
|
|
17172
|
+
apiKeyHeader: []
|
|
17173
|
+
}
|
|
17174
|
+
]
|
|
17175
|
+
},
|
|
17176
|
+
delete: {
|
|
17177
|
+
responses: {
|
|
17178
|
+
"204": {
|
|
17179
|
+
description: "The membership was removed."
|
|
17180
|
+
},
|
|
17181
|
+
"401": {
|
|
17182
|
+
description: "Authentication is missing or invalid.",
|
|
17183
|
+
content: {
|
|
17184
|
+
"application/json": {
|
|
17185
|
+
schema: {
|
|
17186
|
+
$ref: "#/components/schemas/Error"
|
|
17187
|
+
}
|
|
17188
|
+
}
|
|
17189
|
+
}
|
|
17190
|
+
},
|
|
17191
|
+
"403": {
|
|
17192
|
+
description: "The caller is not permitted to perform this action.",
|
|
17193
|
+
content: {
|
|
17194
|
+
"application/json": {
|
|
17195
|
+
schema: {
|
|
17196
|
+
$ref: "#/components/schemas/Error"
|
|
17197
|
+
}
|
|
17198
|
+
}
|
|
17199
|
+
}
|
|
17200
|
+
},
|
|
17201
|
+
"404": {
|
|
17202
|
+
description: "The resource was not found.",
|
|
17203
|
+
content: {
|
|
17204
|
+
"application/json": {
|
|
17205
|
+
schema: {
|
|
17206
|
+
$ref: "#/components/schemas/Error"
|
|
17207
|
+
}
|
|
17208
|
+
}
|
|
17209
|
+
}
|
|
17210
|
+
},
|
|
17211
|
+
"429": {
|
|
17212
|
+
description: "Too many requests; retry after the indicated delay.",
|
|
17213
|
+
content: {
|
|
17214
|
+
"application/json": {
|
|
17215
|
+
schema: {
|
|
17216
|
+
$ref: "#/components/schemas/Error"
|
|
17217
|
+
}
|
|
17218
|
+
}
|
|
17219
|
+
}
|
|
17220
|
+
}
|
|
17221
|
+
},
|
|
17222
|
+
summary: "Detach a resource from a project",
|
|
17223
|
+
description: "Removes the membership. The underlying app, pipeline, or database is untouched.",
|
|
17224
|
+
tags: [
|
|
17225
|
+
"Projects"
|
|
17226
|
+
],
|
|
17227
|
+
operationId: "detachProjectMember",
|
|
17228
|
+
parameters: [
|
|
17229
|
+
{
|
|
17230
|
+
name: "projectId",
|
|
17231
|
+
in: "path",
|
|
17232
|
+
required: true,
|
|
17233
|
+
schema: {
|
|
17234
|
+
type: "string",
|
|
17235
|
+
minLength: 1
|
|
17236
|
+
}
|
|
17237
|
+
}
|
|
17238
|
+
],
|
|
17239
|
+
requestBody: {
|
|
17240
|
+
required: true,
|
|
17241
|
+
content: {
|
|
17242
|
+
"application/json": {
|
|
17243
|
+
schema: {
|
|
17244
|
+
type: "object",
|
|
17245
|
+
properties: {
|
|
17246
|
+
resourceKind: {
|
|
17247
|
+
type: "string",
|
|
17248
|
+
enum: [
|
|
17249
|
+
"app",
|
|
17250
|
+
"pipeline",
|
|
17251
|
+
"database"
|
|
17252
|
+
]
|
|
17253
|
+
},
|
|
17254
|
+
resourceId: {
|
|
17255
|
+
type: "string",
|
|
17256
|
+
minLength: 1
|
|
17257
|
+
}
|
|
17258
|
+
},
|
|
17259
|
+
required: [
|
|
17260
|
+
"resourceKind",
|
|
17261
|
+
"resourceId"
|
|
17262
|
+
]
|
|
17263
|
+
}
|
|
17264
|
+
}
|
|
17265
|
+
}
|
|
17266
|
+
},
|
|
17267
|
+
security: [
|
|
17268
|
+
{
|
|
17269
|
+
bearerAuth: []
|
|
17270
|
+
},
|
|
17271
|
+
{
|
|
17272
|
+
apiKeyHeader: []
|
|
17273
|
+
}
|
|
17274
|
+
]
|
|
17275
|
+
}
|
|
17276
|
+
},
|
|
17277
|
+
"/api/v1/projects/{projectId}/changes": {
|
|
17278
|
+
post: {
|
|
17279
|
+
responses: {
|
|
17280
|
+
"200": {
|
|
17281
|
+
description: "The issue tracking this change.",
|
|
17282
|
+
content: {
|
|
17283
|
+
"application/json": {
|
|
17284
|
+
schema: {
|
|
17285
|
+
type: "object",
|
|
17286
|
+
properties: {
|
|
17287
|
+
projectId: {
|
|
17288
|
+
type: "string"
|
|
17289
|
+
},
|
|
17290
|
+
changeId: {
|
|
17291
|
+
type: "string"
|
|
17292
|
+
},
|
|
17293
|
+
issueId: {
|
|
17294
|
+
type: "string"
|
|
17295
|
+
},
|
|
17296
|
+
issueUrl: {
|
|
17297
|
+
nullable: true,
|
|
17298
|
+
type: "string"
|
|
17299
|
+
},
|
|
17300
|
+
identifier: {
|
|
17301
|
+
nullable: true,
|
|
17302
|
+
description: "Linear's human key, e.g. ADE-12.",
|
|
17303
|
+
type: "string"
|
|
17304
|
+
},
|
|
17305
|
+
created: {
|
|
17306
|
+
type: "boolean",
|
|
17307
|
+
description: "False when an existing issue was updated."
|
|
17308
|
+
},
|
|
17309
|
+
documentsWritten: {
|
|
17310
|
+
type: "number"
|
|
17311
|
+
}
|
|
17312
|
+
},
|
|
17313
|
+
required: [
|
|
17314
|
+
"projectId",
|
|
17315
|
+
"changeId",
|
|
17316
|
+
"issueId",
|
|
17317
|
+
"issueUrl",
|
|
17318
|
+
"identifier",
|
|
17319
|
+
"created",
|
|
17320
|
+
"documentsWritten"
|
|
17321
|
+
],
|
|
17322
|
+
additionalProperties: false
|
|
17323
|
+
}
|
|
17324
|
+
}
|
|
17325
|
+
}
|
|
17326
|
+
},
|
|
17327
|
+
"401": {
|
|
17328
|
+
description: "Authentication is missing or invalid.",
|
|
17329
|
+
content: {
|
|
17330
|
+
"application/json": {
|
|
17331
|
+
schema: {
|
|
17332
|
+
$ref: "#/components/schemas/Error"
|
|
17333
|
+
}
|
|
17334
|
+
}
|
|
17335
|
+
}
|
|
17336
|
+
},
|
|
17337
|
+
"403": {
|
|
17338
|
+
description: "The caller is not permitted to perform this action.",
|
|
17339
|
+
content: {
|
|
17340
|
+
"application/json": {
|
|
17341
|
+
schema: {
|
|
17342
|
+
$ref: "#/components/schemas/Error"
|
|
17343
|
+
}
|
|
17344
|
+
}
|
|
17345
|
+
}
|
|
17346
|
+
},
|
|
17347
|
+
"404": {
|
|
17348
|
+
description: "The resource was not found.",
|
|
17349
|
+
content: {
|
|
17350
|
+
"application/json": {
|
|
17351
|
+
schema: {
|
|
17352
|
+
$ref: "#/components/schemas/Error"
|
|
17353
|
+
}
|
|
17354
|
+
}
|
|
17355
|
+
}
|
|
17356
|
+
},
|
|
17357
|
+
"422": {
|
|
17358
|
+
description: "Response.",
|
|
17359
|
+
content: {
|
|
17360
|
+
"application/json": {
|
|
17361
|
+
schema: {
|
|
17362
|
+
$ref: "#/components/schemas/Error"
|
|
17363
|
+
}
|
|
17364
|
+
}
|
|
17365
|
+
}
|
|
17366
|
+
},
|
|
17367
|
+
"429": {
|
|
17368
|
+
description: "Too many requests; retry after the indicated delay.",
|
|
17369
|
+
content: {
|
|
17370
|
+
"application/json": {
|
|
17371
|
+
schema: {
|
|
17372
|
+
$ref: "#/components/schemas/Error"
|
|
17373
|
+
}
|
|
17374
|
+
}
|
|
17375
|
+
}
|
|
17376
|
+
}
|
|
17377
|
+
},
|
|
17378
|
+
summary: "File a change as an issue",
|
|
17379
|
+
description: "Creates or updates the issue tracking one OpenSpec change directory under this project. Khotan owns the issue's title and description; its state, assignee, priority, and dates stay with the tracker. Idempotent by change id.",
|
|
17380
|
+
tags: [
|
|
17381
|
+
"Projects"
|
|
17382
|
+
],
|
|
17383
|
+
operationId: "syncProjectChange",
|
|
17384
|
+
parameters: [
|
|
17385
|
+
{
|
|
17386
|
+
name: "projectId",
|
|
17387
|
+
in: "path",
|
|
17388
|
+
required: true,
|
|
17389
|
+
schema: {
|
|
17390
|
+
type: "string",
|
|
17391
|
+
minLength: 1
|
|
17392
|
+
}
|
|
17393
|
+
}
|
|
17394
|
+
],
|
|
17395
|
+
requestBody: {
|
|
17396
|
+
required: true,
|
|
17397
|
+
content: {
|
|
17398
|
+
"application/json": {
|
|
17399
|
+
schema: {
|
|
17400
|
+
type: "object",
|
|
17401
|
+
properties: {
|
|
17402
|
+
changeId: {
|
|
17403
|
+
type: "string",
|
|
17404
|
+
minLength: 1,
|
|
17405
|
+
maxLength: 200,
|
|
17406
|
+
description: "The change directory name. Stable identity for the issue, so renaming the directory files a second one."
|
|
17407
|
+
},
|
|
17408
|
+
title: {
|
|
17409
|
+
type: "string",
|
|
17410
|
+
minLength: 1,
|
|
17411
|
+
maxLength: 200
|
|
17412
|
+
},
|
|
17413
|
+
body: {
|
|
17414
|
+
type: "string",
|
|
17415
|
+
maxLength: 1e6
|
|
17416
|
+
},
|
|
17417
|
+
capabilities: {
|
|
17418
|
+
default: [],
|
|
17419
|
+
description: "Capabilities this change amends, applied as labels in one managed group. Labels outside that group are untouched.",
|
|
17420
|
+
maxItems: 20,
|
|
17421
|
+
type: "array",
|
|
17422
|
+
items: {
|
|
17423
|
+
type: "string",
|
|
17424
|
+
minLength: 1,
|
|
17425
|
+
maxLength: 80
|
|
17426
|
+
}
|
|
17427
|
+
},
|
|
17428
|
+
documents: {
|
|
17429
|
+
default: [],
|
|
17430
|
+
description: "Long parts of the change — design and requirements — attached as documents rather than inlined in the description.",
|
|
17431
|
+
maxItems: 20,
|
|
17432
|
+
type: "array",
|
|
17433
|
+
items: {
|
|
17434
|
+
type: "object",
|
|
17435
|
+
properties: {
|
|
17436
|
+
key: {
|
|
17437
|
+
type: "string",
|
|
17438
|
+
minLength: 1,
|
|
17439
|
+
maxLength: 80,
|
|
17440
|
+
description: "Stable key for this document, so a re-push updates it rather than adding another."
|
|
17441
|
+
},
|
|
17442
|
+
title: {
|
|
17443
|
+
type: "string",
|
|
17444
|
+
minLength: 1,
|
|
17445
|
+
maxLength: 200
|
|
17446
|
+
},
|
|
17447
|
+
content: {
|
|
17448
|
+
type: "string",
|
|
17449
|
+
maxLength: 1e6
|
|
17450
|
+
}
|
|
17451
|
+
},
|
|
17452
|
+
required: [
|
|
17453
|
+
"key",
|
|
17454
|
+
"title",
|
|
17455
|
+
"content"
|
|
17456
|
+
]
|
|
17457
|
+
}
|
|
17458
|
+
},
|
|
17459
|
+
source: {
|
|
17460
|
+
description: "Where the change came from. A url is attached to the issue as a link.",
|
|
17461
|
+
type: "object",
|
|
17462
|
+
properties: {
|
|
17463
|
+
ref: {
|
|
17464
|
+
type: "string",
|
|
17465
|
+
minLength: 1,
|
|
17466
|
+
maxLength: 200
|
|
17467
|
+
},
|
|
17468
|
+
url: {
|
|
17469
|
+
nullable: true,
|
|
17470
|
+
type: "string",
|
|
17471
|
+
format: "uri"
|
|
17472
|
+
},
|
|
17473
|
+
label: {
|
|
17474
|
+
nullable: true,
|
|
17475
|
+
type: "string",
|
|
17476
|
+
maxLength: 200
|
|
17477
|
+
}
|
|
17478
|
+
},
|
|
17479
|
+
required: [
|
|
17480
|
+
"ref"
|
|
17481
|
+
]
|
|
17482
|
+
}
|
|
17483
|
+
},
|
|
17484
|
+
required: [
|
|
17485
|
+
"changeId",
|
|
17486
|
+
"title",
|
|
17487
|
+
"body"
|
|
17488
|
+
]
|
|
17489
|
+
}
|
|
17490
|
+
}
|
|
17491
|
+
}
|
|
17492
|
+
},
|
|
17493
|
+
security: [
|
|
17494
|
+
{
|
|
17495
|
+
bearerAuth: []
|
|
17496
|
+
},
|
|
17497
|
+
{
|
|
17498
|
+
apiKeyHeader: []
|
|
17499
|
+
}
|
|
17500
|
+
]
|
|
17501
|
+
}
|
|
17502
|
+
},
|
|
17503
|
+
"/api/v1/projects/{projectId}/linear": {
|
|
17504
|
+
post: {
|
|
17505
|
+
responses: {
|
|
17506
|
+
"200": {
|
|
17507
|
+
description: "The Linear project now bound, or null if cleared.",
|
|
17508
|
+
content: {
|
|
17509
|
+
"application/json": {
|
|
17510
|
+
schema: {
|
|
17511
|
+
type: "object",
|
|
17512
|
+
properties: {
|
|
17513
|
+
bound: {
|
|
17514
|
+
nullable: true,
|
|
17515
|
+
type: "string"
|
|
17516
|
+
}
|
|
17517
|
+
},
|
|
17518
|
+
required: [
|
|
17519
|
+
"bound"
|
|
17520
|
+
],
|
|
17521
|
+
additionalProperties: false
|
|
17522
|
+
}
|
|
17523
|
+
}
|
|
17524
|
+
}
|
|
17525
|
+
},
|
|
17526
|
+
"401": {
|
|
17527
|
+
description: "Authentication is missing or invalid.",
|
|
17528
|
+
content: {
|
|
17529
|
+
"application/json": {
|
|
17530
|
+
schema: {
|
|
17531
|
+
$ref: "#/components/schemas/Error"
|
|
17532
|
+
}
|
|
17533
|
+
}
|
|
17534
|
+
}
|
|
17535
|
+
},
|
|
17536
|
+
"403": {
|
|
17537
|
+
description: "The caller is not permitted to perform this action.",
|
|
17538
|
+
content: {
|
|
17539
|
+
"application/json": {
|
|
17540
|
+
schema: {
|
|
17541
|
+
$ref: "#/components/schemas/Error"
|
|
17542
|
+
}
|
|
17543
|
+
}
|
|
17544
|
+
}
|
|
17545
|
+
},
|
|
17546
|
+
"404": {
|
|
17547
|
+
description: "The resource was not found.",
|
|
17548
|
+
content: {
|
|
17549
|
+
"application/json": {
|
|
17550
|
+
schema: {
|
|
17551
|
+
$ref: "#/components/schemas/Error"
|
|
17552
|
+
}
|
|
17553
|
+
}
|
|
17554
|
+
}
|
|
17555
|
+
},
|
|
17556
|
+
"422": {
|
|
17557
|
+
description: "Response.",
|
|
17558
|
+
content: {
|
|
17559
|
+
"application/json": {
|
|
17560
|
+
schema: {
|
|
17561
|
+
$ref: "#/components/schemas/Error"
|
|
17562
|
+
}
|
|
17563
|
+
}
|
|
17564
|
+
}
|
|
17565
|
+
},
|
|
17566
|
+
"429": {
|
|
17567
|
+
description: "Too many requests; retry after the indicated delay.",
|
|
17568
|
+
content: {
|
|
17569
|
+
"application/json": {
|
|
17570
|
+
schema: {
|
|
17571
|
+
$ref: "#/components/schemas/Error"
|
|
17572
|
+
}
|
|
17573
|
+
}
|
|
17574
|
+
}
|
|
17575
|
+
}
|
|
17576
|
+
},
|
|
17577
|
+
summary: "Bind a project to Linear",
|
|
17578
|
+
description: "Binds this project to an existing Linear project, or clears the binding when linearProjectId is null. A new project mints its Linear project on first push, so this is only needed when the binding must point at one that already exists.",
|
|
17579
|
+
tags: [
|
|
17580
|
+
"Projects"
|
|
17581
|
+
],
|
|
17582
|
+
operationId: "bindLinearProject",
|
|
17583
|
+
parameters: [
|
|
17584
|
+
{
|
|
17585
|
+
name: "projectId",
|
|
17586
|
+
in: "path",
|
|
17587
|
+
required: true,
|
|
17588
|
+
schema: {
|
|
17589
|
+
type: "string",
|
|
17590
|
+
minLength: 1
|
|
17591
|
+
}
|
|
17592
|
+
}
|
|
17593
|
+
],
|
|
17594
|
+
requestBody: {
|
|
17595
|
+
required: true,
|
|
17596
|
+
content: {
|
|
17597
|
+
"application/json": {
|
|
17598
|
+
schema: {
|
|
17599
|
+
type: "object",
|
|
17600
|
+
properties: {
|
|
17601
|
+
linearProjectId: {
|
|
17602
|
+
nullable: true,
|
|
17603
|
+
description: "The Linear project to bind. Null clears the binding.",
|
|
17604
|
+
type: "string",
|
|
17605
|
+
minLength: 1
|
|
17606
|
+
}
|
|
17607
|
+
},
|
|
17608
|
+
required: [
|
|
17609
|
+
"linearProjectId"
|
|
17610
|
+
]
|
|
17611
|
+
}
|
|
17612
|
+
}
|
|
17613
|
+
}
|
|
17614
|
+
},
|
|
17615
|
+
security: [
|
|
17616
|
+
{
|
|
17617
|
+
bearerAuth: []
|
|
17618
|
+
},
|
|
17619
|
+
{
|
|
17620
|
+
apiKeyHeader: []
|
|
17621
|
+
}
|
|
17622
|
+
]
|
|
17623
|
+
}
|
|
17624
|
+
},
|
|
17625
|
+
"/api/v1/sqlite-databases": {
|
|
17626
|
+
get: {
|
|
17627
|
+
responses: {
|
|
17628
|
+
"200": {
|
|
17629
|
+
description: "The organization's SQLite databases.",
|
|
17630
|
+
content: {
|
|
17631
|
+
"application/json": {
|
|
17632
|
+
schema: {
|
|
17633
|
+
type: "object",
|
|
17634
|
+
properties: {
|
|
17635
|
+
databases: {
|
|
17636
|
+
type: "array",
|
|
17637
|
+
items: {
|
|
17638
|
+
type: "object",
|
|
17639
|
+
properties: {
|
|
17640
|
+
id: {
|
|
17641
|
+
type: "string"
|
|
17642
|
+
},
|
|
17643
|
+
displayName: {
|
|
17644
|
+
type: "string"
|
|
17645
|
+
},
|
|
17646
|
+
status: {
|
|
17647
|
+
type: "string",
|
|
17648
|
+
enum: [
|
|
17649
|
+
"creating",
|
|
17650
|
+
"ready",
|
|
17651
|
+
"failed"
|
|
17652
|
+
]
|
|
17653
|
+
},
|
|
17654
|
+
provider: {
|
|
17655
|
+
type: "string"
|
|
17656
|
+
},
|
|
17657
|
+
primaryRegion: {
|
|
17658
|
+
nullable: true,
|
|
17659
|
+
type: "string"
|
|
17660
|
+
},
|
|
17661
|
+
regions: {
|
|
17662
|
+
nullable: true,
|
|
17663
|
+
type: "array",
|
|
17664
|
+
items: {
|
|
17665
|
+
type: "string"
|
|
17666
|
+
}
|
|
17667
|
+
},
|
|
17668
|
+
providerDatabaseName: {
|
|
17669
|
+
nullable: true,
|
|
17670
|
+
type: "string"
|
|
17671
|
+
},
|
|
17672
|
+
endpointHost: {
|
|
17673
|
+
nullable: true,
|
|
17674
|
+
type: "string"
|
|
17675
|
+
},
|
|
17676
|
+
protected: {
|
|
17677
|
+
type: "boolean"
|
|
17678
|
+
},
|
|
17679
|
+
createdAt: {
|
|
17680
|
+
type: "string"
|
|
17681
|
+
},
|
|
17682
|
+
updatedAt: {
|
|
17683
|
+
type: "string"
|
|
17684
|
+
},
|
|
17685
|
+
readyAt: {
|
|
17686
|
+
nullable: true,
|
|
17687
|
+
type: "string"
|
|
17688
|
+
},
|
|
17689
|
+
failedAt: {
|
|
17690
|
+
nullable: true,
|
|
17691
|
+
type: "string"
|
|
17692
|
+
},
|
|
17693
|
+
failureState: {
|
|
17694
|
+
nullable: true,
|
|
17695
|
+
type: "object",
|
|
17696
|
+
properties: {
|
|
17697
|
+
code: {
|
|
17698
|
+
type: "string",
|
|
17699
|
+
enum: [
|
|
17700
|
+
"provider_unavailable",
|
|
17701
|
+
"provider_rejected",
|
|
17702
|
+
"internal_error"
|
|
17703
|
+
]
|
|
17704
|
+
},
|
|
17705
|
+
message: {
|
|
17706
|
+
type: "string"
|
|
17707
|
+
}
|
|
17708
|
+
},
|
|
17709
|
+
required: [
|
|
17710
|
+
"code",
|
|
17711
|
+
"message"
|
|
17712
|
+
],
|
|
17713
|
+
additionalProperties: false
|
|
17714
|
+
}
|
|
17715
|
+
},
|
|
17716
|
+
required: [
|
|
17717
|
+
"id",
|
|
17718
|
+
"displayName",
|
|
17719
|
+
"status",
|
|
17720
|
+
"provider",
|
|
17721
|
+
"primaryRegion",
|
|
17722
|
+
"regions",
|
|
17723
|
+
"providerDatabaseName",
|
|
17724
|
+
"endpointHost",
|
|
17725
|
+
"protected",
|
|
17726
|
+
"createdAt",
|
|
17727
|
+
"updatedAt",
|
|
17728
|
+
"readyAt",
|
|
17729
|
+
"failedAt",
|
|
17730
|
+
"failureState"
|
|
17731
|
+
],
|
|
17732
|
+
additionalProperties: false
|
|
17733
|
+
}
|
|
17734
|
+
}
|
|
17735
|
+
},
|
|
17736
|
+
required: [
|
|
17737
|
+
"databases"
|
|
17738
|
+
],
|
|
17739
|
+
additionalProperties: false
|
|
17740
|
+
}
|
|
17741
|
+
}
|
|
17742
|
+
}
|
|
17743
|
+
},
|
|
17744
|
+
"401": {
|
|
17745
|
+
description: "Authentication is missing or invalid.",
|
|
17746
|
+
content: {
|
|
17747
|
+
"application/json": {
|
|
17748
|
+
schema: {
|
|
17749
|
+
$ref: "#/components/schemas/Error"
|
|
17750
|
+
}
|
|
17751
|
+
}
|
|
17752
|
+
}
|
|
17753
|
+
},
|
|
17754
|
+
"429": {
|
|
17755
|
+
description: "Too many requests; retry after the indicated delay.",
|
|
17756
|
+
content: {
|
|
17757
|
+
"application/json": {
|
|
17758
|
+
schema: {
|
|
17759
|
+
$ref: "#/components/schemas/Error"
|
|
17760
|
+
}
|
|
17761
|
+
}
|
|
17762
|
+
}
|
|
17763
|
+
}
|
|
17764
|
+
},
|
|
17765
|
+
summary: "List SQLite databases",
|
|
17766
|
+
description: "Returns the organization's non-deleted SQLite databases. Responses never include connection credentials.",
|
|
17767
|
+
tags: [
|
|
17768
|
+
"SQLite Databases"
|
|
17769
|
+
],
|
|
17770
|
+
operationId: "listSqliteDatabases",
|
|
17771
|
+
security: [
|
|
17772
|
+
{
|
|
17773
|
+
bearerAuth: []
|
|
17774
|
+
},
|
|
17775
|
+
{
|
|
17776
|
+
apiKeyHeader: []
|
|
17777
|
+
}
|
|
17778
|
+
]
|
|
17779
|
+
},
|
|
17780
|
+
post: {
|
|
17781
|
+
responses: {
|
|
17782
|
+
"201": {
|
|
17783
|
+
description: "The persisted SQLite database record, ready or failed.",
|
|
17784
|
+
content: {
|
|
17785
|
+
"application/json": {
|
|
17786
|
+
schema: {
|
|
17787
|
+
type: "object",
|
|
17788
|
+
properties: {
|
|
17789
|
+
id: {
|
|
17790
|
+
type: "string"
|
|
17791
|
+
},
|
|
17792
|
+
displayName: {
|
|
17793
|
+
type: "string"
|
|
17794
|
+
},
|
|
17795
|
+
status: {
|
|
17796
|
+
type: "string",
|
|
17797
|
+
enum: [
|
|
17798
|
+
"creating",
|
|
17799
|
+
"ready",
|
|
17800
|
+
"failed"
|
|
17801
|
+
]
|
|
17802
|
+
},
|
|
17803
|
+
provider: {
|
|
17804
|
+
type: "string"
|
|
17805
|
+
},
|
|
17806
|
+
primaryRegion: {
|
|
17807
|
+
nullable: true,
|
|
17808
|
+
type: "string"
|
|
17809
|
+
},
|
|
17810
|
+
regions: {
|
|
17811
|
+
nullable: true,
|
|
17812
|
+
type: "array",
|
|
17813
|
+
items: {
|
|
17814
|
+
type: "string"
|
|
17815
|
+
}
|
|
17816
|
+
},
|
|
17817
|
+
providerDatabaseName: {
|
|
17818
|
+
nullable: true,
|
|
17819
|
+
type: "string"
|
|
17820
|
+
},
|
|
17821
|
+
endpointHost: {
|
|
17822
|
+
nullable: true,
|
|
17823
|
+
type: "string"
|
|
17824
|
+
},
|
|
17825
|
+
protected: {
|
|
17826
|
+
type: "boolean"
|
|
17827
|
+
},
|
|
17828
|
+
createdAt: {
|
|
17829
|
+
type: "string"
|
|
17830
|
+
},
|
|
17831
|
+
updatedAt: {
|
|
17832
|
+
type: "string"
|
|
17833
|
+
},
|
|
17834
|
+
readyAt: {
|
|
17835
|
+
nullable: true,
|
|
17836
|
+
type: "string"
|
|
17837
|
+
},
|
|
17838
|
+
failedAt: {
|
|
17839
|
+
nullable: true,
|
|
17840
|
+
type: "string"
|
|
17841
|
+
},
|
|
17842
|
+
failureState: {
|
|
17843
|
+
nullable: true,
|
|
17844
|
+
type: "object",
|
|
17845
|
+
properties: {
|
|
17846
|
+
code: {
|
|
17847
|
+
type: "string",
|
|
17848
|
+
enum: [
|
|
17849
|
+
"provider_unavailable",
|
|
17850
|
+
"provider_rejected",
|
|
17851
|
+
"internal_error"
|
|
17852
|
+
]
|
|
17853
|
+
},
|
|
17854
|
+
message: {
|
|
17855
|
+
type: "string"
|
|
17856
|
+
}
|
|
17857
|
+
},
|
|
17858
|
+
required: [
|
|
17859
|
+
"code",
|
|
17860
|
+
"message"
|
|
17861
|
+
],
|
|
17862
|
+
additionalProperties: false
|
|
17863
|
+
}
|
|
17864
|
+
},
|
|
17865
|
+
required: [
|
|
17866
|
+
"id",
|
|
17867
|
+
"displayName",
|
|
17868
|
+
"status",
|
|
17869
|
+
"provider",
|
|
17870
|
+
"primaryRegion",
|
|
17871
|
+
"regions",
|
|
17872
|
+
"providerDatabaseName",
|
|
17873
|
+
"endpointHost",
|
|
17874
|
+
"protected",
|
|
17875
|
+
"createdAt",
|
|
17876
|
+
"updatedAt",
|
|
17877
|
+
"readyAt",
|
|
17878
|
+
"failedAt",
|
|
17879
|
+
"failureState"
|
|
16280
17880
|
],
|
|
16281
17881
|
additionalProperties: false
|
|
16282
17882
|
}
|
|
16283
17883
|
}
|
|
16284
17884
|
}
|
|
16285
17885
|
},
|
|
16286
|
-
"
|
|
16287
|
-
description: "
|
|
17886
|
+
"400": {
|
|
17887
|
+
description: "The request was malformed or failed validation.",
|
|
16288
17888
|
content: {
|
|
16289
17889
|
"application/json": {
|
|
16290
17890
|
schema: {
|
|
@@ -16293,8 +17893,8 @@ var init_spec = __esm(() => {
|
|
|
16293
17893
|
}
|
|
16294
17894
|
}
|
|
16295
17895
|
},
|
|
16296
|
-
"
|
|
16297
|
-
description: "
|
|
17896
|
+
"401": {
|
|
17897
|
+
description: "Authentication is missing or invalid.",
|
|
16298
17898
|
content: {
|
|
16299
17899
|
"application/json": {
|
|
16300
17900
|
schema: {
|
|
@@ -16314,23 +17914,37 @@ var init_spec = __esm(() => {
|
|
|
16314
17914
|
}
|
|
16315
17915
|
}
|
|
16316
17916
|
},
|
|
16317
|
-
summary: "
|
|
16318
|
-
description: "
|
|
17917
|
+
summary: "Create a SQLite database",
|
|
17918
|
+
description: "Provisions a SQLite database synchronously and responds 201 with the persisted record whether provisioning ends ready or failed; branch on the returned status. This operation is not idempotent: retrying a request that already succeeded provisions a second database.",
|
|
16319
17919
|
tags: [
|
|
16320
|
-
"
|
|
17920
|
+
"SQLite Databases"
|
|
16321
17921
|
],
|
|
16322
|
-
operationId: "
|
|
16323
|
-
|
|
16324
|
-
|
|
16325
|
-
|
|
16326
|
-
|
|
16327
|
-
|
|
16328
|
-
|
|
16329
|
-
|
|
16330
|
-
|
|
17922
|
+
operationId: "createSqliteDatabase",
|
|
17923
|
+
requestBody: {
|
|
17924
|
+
required: true,
|
|
17925
|
+
content: {
|
|
17926
|
+
"application/json": {
|
|
17927
|
+
schema: {
|
|
17928
|
+
type: "object",
|
|
17929
|
+
properties: {
|
|
17930
|
+
name: {
|
|
17931
|
+
type: "string",
|
|
17932
|
+
minLength: 1,
|
|
17933
|
+
maxLength: 63
|
|
17934
|
+
},
|
|
17935
|
+
idempotencyKey: {
|
|
17936
|
+
type: "string",
|
|
17937
|
+
minLength: 1,
|
|
17938
|
+
maxLength: 200
|
|
17939
|
+
}
|
|
17940
|
+
},
|
|
17941
|
+
required: [
|
|
17942
|
+
"name"
|
|
17943
|
+
]
|
|
17944
|
+
}
|
|
16331
17945
|
}
|
|
16332
17946
|
}
|
|
16333
|
-
|
|
17947
|
+
},
|
|
16334
17948
|
security: [
|
|
16335
17949
|
{
|
|
16336
17950
|
bearerAuth: []
|
|
@@ -16339,11 +17953,13 @@ var init_spec = __esm(() => {
|
|
|
16339
17953
|
apiKeyHeader: []
|
|
16340
17954
|
}
|
|
16341
17955
|
]
|
|
16342
|
-
}
|
|
16343
|
-
|
|
17956
|
+
}
|
|
17957
|
+
},
|
|
17958
|
+
"/api/v1/sqlite-databases/{databaseId}": {
|
|
17959
|
+
get: {
|
|
16344
17960
|
responses: {
|
|
16345
|
-
"
|
|
16346
|
-
description: "The
|
|
17961
|
+
"200": {
|
|
17962
|
+
description: "The SQLite database record.",
|
|
16347
17963
|
content: {
|
|
16348
17964
|
"application/json": {
|
|
16349
17965
|
schema: {
|
|
@@ -16352,21 +17968,94 @@ var init_spec = __esm(() => {
|
|
|
16352
17968
|
id: {
|
|
16353
17969
|
type: "string"
|
|
16354
17970
|
},
|
|
16355
|
-
|
|
17971
|
+
displayName: {
|
|
16356
17972
|
type: "string"
|
|
16357
17973
|
},
|
|
16358
|
-
|
|
17974
|
+
status: {
|
|
17975
|
+
type: "string",
|
|
17976
|
+
enum: [
|
|
17977
|
+
"creating",
|
|
17978
|
+
"ready",
|
|
17979
|
+
"failed"
|
|
17980
|
+
]
|
|
17981
|
+
},
|
|
17982
|
+
provider: {
|
|
16359
17983
|
type: "string"
|
|
16360
17984
|
},
|
|
16361
|
-
|
|
17985
|
+
primaryRegion: {
|
|
17986
|
+
nullable: true,
|
|
17987
|
+
type: "string"
|
|
17988
|
+
},
|
|
17989
|
+
regions: {
|
|
17990
|
+
nullable: true,
|
|
17991
|
+
type: "array",
|
|
17992
|
+
items: {
|
|
17993
|
+
type: "string"
|
|
17994
|
+
}
|
|
17995
|
+
},
|
|
17996
|
+
providerDatabaseName: {
|
|
17997
|
+
nullable: true,
|
|
17998
|
+
type: "string"
|
|
17999
|
+
},
|
|
18000
|
+
endpointHost: {
|
|
18001
|
+
nullable: true,
|
|
18002
|
+
type: "string"
|
|
18003
|
+
},
|
|
18004
|
+
protected: {
|
|
18005
|
+
type: "boolean"
|
|
18006
|
+
},
|
|
18007
|
+
createdAt: {
|
|
18008
|
+
type: "string"
|
|
18009
|
+
},
|
|
18010
|
+
updatedAt: {
|
|
18011
|
+
type: "string"
|
|
18012
|
+
},
|
|
18013
|
+
readyAt: {
|
|
18014
|
+
nullable: true,
|
|
18015
|
+
type: "string"
|
|
18016
|
+
},
|
|
18017
|
+
failedAt: {
|
|
18018
|
+
nullable: true,
|
|
16362
18019
|
type: "string"
|
|
18020
|
+
},
|
|
18021
|
+
failureState: {
|
|
18022
|
+
nullable: true,
|
|
18023
|
+
type: "object",
|
|
18024
|
+
properties: {
|
|
18025
|
+
code: {
|
|
18026
|
+
type: "string",
|
|
18027
|
+
enum: [
|
|
18028
|
+
"provider_unavailable",
|
|
18029
|
+
"provider_rejected",
|
|
18030
|
+
"internal_error"
|
|
18031
|
+
]
|
|
18032
|
+
},
|
|
18033
|
+
message: {
|
|
18034
|
+
type: "string"
|
|
18035
|
+
}
|
|
18036
|
+
},
|
|
18037
|
+
required: [
|
|
18038
|
+
"code",
|
|
18039
|
+
"message"
|
|
18040
|
+
],
|
|
18041
|
+
additionalProperties: false
|
|
16363
18042
|
}
|
|
16364
18043
|
},
|
|
16365
18044
|
required: [
|
|
16366
18045
|
"id",
|
|
16367
|
-
"
|
|
16368
|
-
"
|
|
16369
|
-
"
|
|
18046
|
+
"displayName",
|
|
18047
|
+
"status",
|
|
18048
|
+
"provider",
|
|
18049
|
+
"primaryRegion",
|
|
18050
|
+
"regions",
|
|
18051
|
+
"providerDatabaseName",
|
|
18052
|
+
"endpointHost",
|
|
18053
|
+
"protected",
|
|
18054
|
+
"createdAt",
|
|
18055
|
+
"updatedAt",
|
|
18056
|
+
"readyAt",
|
|
18057
|
+
"failedAt",
|
|
18058
|
+
"failureState"
|
|
16370
18059
|
],
|
|
16371
18060
|
additionalProperties: false
|
|
16372
18061
|
}
|
|
@@ -16383,16 +18072,6 @@ var init_spec = __esm(() => {
|
|
|
16383
18072
|
}
|
|
16384
18073
|
}
|
|
16385
18074
|
},
|
|
16386
|
-
"403": {
|
|
16387
|
-
description: "The caller is not permitted to perform this action.",
|
|
16388
|
-
content: {
|
|
16389
|
-
"application/json": {
|
|
16390
|
-
schema: {
|
|
16391
|
-
$ref: "#/components/schemas/Error"
|
|
16392
|
-
}
|
|
16393
|
-
}
|
|
16394
|
-
}
|
|
16395
|
-
},
|
|
16396
18075
|
"404": {
|
|
16397
18076
|
description: "The resource was not found.",
|
|
16398
18077
|
content: {
|
|
@@ -16403,16 +18082,6 @@ var init_spec = __esm(() => {
|
|
|
16403
18082
|
}
|
|
16404
18083
|
}
|
|
16405
18084
|
},
|
|
16406
|
-
"409": {
|
|
16407
|
-
description: "Response.",
|
|
16408
|
-
content: {
|
|
16409
|
-
"application/json": {
|
|
16410
|
-
schema: {
|
|
16411
|
-
$ref: "#/components/schemas/Error"
|
|
16412
|
-
}
|
|
16413
|
-
}
|
|
16414
|
-
}
|
|
16415
|
-
},
|
|
16416
18085
|
"429": {
|
|
16417
18086
|
description: "Too many requests; retry after the indicated delay.",
|
|
16418
18087
|
content: {
|
|
@@ -16424,15 +18093,15 @@ var init_spec = __esm(() => {
|
|
|
16424
18093
|
}
|
|
16425
18094
|
}
|
|
16426
18095
|
},
|
|
16427
|
-
summary: "
|
|
16428
|
-
description: "
|
|
18096
|
+
summary: "Get a SQLite database",
|
|
18097
|
+
description: "Returns one SQLite database's record, including status and failure state when present. Responses never include connection credentials.",
|
|
16429
18098
|
tags: [
|
|
16430
|
-
"
|
|
18099
|
+
"SQLite Databases"
|
|
16431
18100
|
],
|
|
16432
|
-
operationId: "
|
|
18101
|
+
operationId: "getSqliteDatabase",
|
|
16433
18102
|
parameters: [
|
|
16434
18103
|
{
|
|
16435
|
-
name: "
|
|
18104
|
+
name: "databaseId",
|
|
16436
18105
|
in: "path",
|
|
16437
18106
|
required: true,
|
|
16438
18107
|
schema: {
|
|
@@ -16441,34 +18110,6 @@ var init_spec = __esm(() => {
|
|
|
16441
18110
|
}
|
|
16442
18111
|
}
|
|
16443
18112
|
],
|
|
16444
|
-
requestBody: {
|
|
16445
|
-
required: true,
|
|
16446
|
-
content: {
|
|
16447
|
-
"application/json": {
|
|
16448
|
-
schema: {
|
|
16449
|
-
type: "object",
|
|
16450
|
-
properties: {
|
|
16451
|
-
resourceKind: {
|
|
16452
|
-
type: "string",
|
|
16453
|
-
enum: [
|
|
16454
|
-
"app",
|
|
16455
|
-
"pipeline",
|
|
16456
|
-
"database"
|
|
16457
|
-
]
|
|
16458
|
-
},
|
|
16459
|
-
resourceId: {
|
|
16460
|
-
type: "string",
|
|
16461
|
-
minLength: 1
|
|
16462
|
-
}
|
|
16463
|
-
},
|
|
16464
|
-
required: [
|
|
16465
|
-
"resourceKind",
|
|
16466
|
-
"resourceId"
|
|
16467
|
-
]
|
|
16468
|
-
}
|
|
16469
|
-
}
|
|
16470
|
-
}
|
|
16471
|
-
},
|
|
16472
18113
|
security: [
|
|
16473
18114
|
{
|
|
16474
18115
|
bearerAuth: []
|
|
@@ -16480,8 +18121,27 @@ var init_spec = __esm(() => {
|
|
|
16480
18121
|
},
|
|
16481
18122
|
delete: {
|
|
16482
18123
|
responses: {
|
|
16483
|
-
"
|
|
16484
|
-
description: "The
|
|
18124
|
+
"200": {
|
|
18125
|
+
description: "The SQLite database was deleted.",
|
|
18126
|
+
content: {
|
|
18127
|
+
"application/json": {
|
|
18128
|
+
schema: {
|
|
18129
|
+
type: "object",
|
|
18130
|
+
properties: {
|
|
18131
|
+
deleted: {
|
|
18132
|
+
type: "boolean",
|
|
18133
|
+
enum: [
|
|
18134
|
+
true
|
|
18135
|
+
]
|
|
18136
|
+
}
|
|
18137
|
+
},
|
|
18138
|
+
required: [
|
|
18139
|
+
"deleted"
|
|
18140
|
+
],
|
|
18141
|
+
additionalProperties: false
|
|
18142
|
+
}
|
|
18143
|
+
}
|
|
18144
|
+
}
|
|
16485
18145
|
},
|
|
16486
18146
|
"401": {
|
|
16487
18147
|
description: "Authentication is missing or invalid.",
|
|
@@ -16522,17 +18182,27 @@ var init_spec = __esm(() => {
|
|
|
16522
18182
|
}
|
|
16523
18183
|
}
|
|
16524
18184
|
}
|
|
18185
|
+
},
|
|
18186
|
+
"502": {
|
|
18187
|
+
description: "Response.",
|
|
18188
|
+
content: {
|
|
18189
|
+
"application/json": {
|
|
18190
|
+
schema: {
|
|
18191
|
+
$ref: "#/components/schemas/Error"
|
|
18192
|
+
}
|
|
18193
|
+
}
|
|
18194
|
+
}
|
|
16525
18195
|
}
|
|
16526
18196
|
},
|
|
16527
|
-
summary: "
|
|
16528
|
-
description: "
|
|
18197
|
+
summary: "Delete a SQLite database",
|
|
18198
|
+
description: "Tears down the database at the provider, then soft-deletes the record. Deletion is permanent.",
|
|
16529
18199
|
tags: [
|
|
16530
|
-
"
|
|
18200
|
+
"SQLite Databases"
|
|
16531
18201
|
],
|
|
16532
|
-
operationId: "
|
|
18202
|
+
operationId: "deleteSqliteDatabase",
|
|
16533
18203
|
parameters: [
|
|
16534
18204
|
{
|
|
16535
|
-
name: "
|
|
18205
|
+
name: "databaseId",
|
|
16536
18206
|
in: "path",
|
|
16537
18207
|
required: true,
|
|
16538
18208
|
schema: {
|
|
@@ -16541,34 +18211,6 @@ var init_spec = __esm(() => {
|
|
|
16541
18211
|
}
|
|
16542
18212
|
}
|
|
16543
18213
|
],
|
|
16544
|
-
requestBody: {
|
|
16545
|
-
required: true,
|
|
16546
|
-
content: {
|
|
16547
|
-
"application/json": {
|
|
16548
|
-
schema: {
|
|
16549
|
-
type: "object",
|
|
16550
|
-
properties: {
|
|
16551
|
-
resourceKind: {
|
|
16552
|
-
type: "string",
|
|
16553
|
-
enum: [
|
|
16554
|
-
"app",
|
|
16555
|
-
"pipeline",
|
|
16556
|
-
"database"
|
|
16557
|
-
]
|
|
16558
|
-
},
|
|
16559
|
-
resourceId: {
|
|
16560
|
-
type: "string",
|
|
16561
|
-
minLength: 1
|
|
16562
|
-
}
|
|
16563
|
-
},
|
|
16564
|
-
required: [
|
|
16565
|
-
"resourceKind",
|
|
16566
|
-
"resourceId"
|
|
16567
|
-
]
|
|
16568
|
-
}
|
|
16569
|
-
}
|
|
16570
|
-
}
|
|
16571
|
-
},
|
|
16572
18214
|
security: [
|
|
16573
18215
|
{
|
|
16574
18216
|
bearerAuth: []
|
|
@@ -16663,8 +18305,19 @@ function apiTags() {
|
|
|
16663
18305
|
function operationsForTag(tag) {
|
|
16664
18306
|
return listApiOperations().filter(({ operation }) => operation.tags?.includes(tag));
|
|
16665
18307
|
}
|
|
18308
|
+
function preferOrder(items, preferred) {
|
|
18309
|
+
const rank = new Map(preferred.map((item, index) => [item, index]));
|
|
18310
|
+
return [...items].sort((a, b) => {
|
|
18311
|
+
const left = rank.get(a) ?? preferred.length;
|
|
18312
|
+
const right = rank.get(b) ?? preferred.length;
|
|
18313
|
+
if (left !== right) {
|
|
18314
|
+
return left - right;
|
|
18315
|
+
}
|
|
18316
|
+
return items.indexOf(a) - items.indexOf(b);
|
|
18317
|
+
});
|
|
18318
|
+
}
|
|
16666
18319
|
function referenceTags() {
|
|
16667
|
-
return apiTags().filter((tag) => !OVERVIEW_TAGS.has(tag));
|
|
18320
|
+
return preferOrder(apiTags().filter((tag) => !OVERVIEW_TAGS.has(tag)), REFERENCE_TAG_ORDER);
|
|
16668
18321
|
}
|
|
16669
18322
|
function typeLabel(schema) {
|
|
16670
18323
|
if (!schema) {
|
|
@@ -16783,7 +18436,7 @@ function authSection() {
|
|
|
16783
18436
|
const how = scheme.type === "http" && scheme.scheme === "bearer" ? "`Authorization: Bearer <key>`" : scheme.in === "header" && scheme.name ? `\`${scheme.name}: <key>\`` : `\`${name}\``;
|
|
16784
18437
|
lines.push(`- ${how} — ${scheme.description ?? name}`);
|
|
16785
18438
|
}
|
|
16786
|
-
lines.push("", "Never commit a key. See [auth](/cli/auth/) for how the CLI
|
|
18439
|
+
lines.push("", "Never commit a key. See [authentication](/api/auth/) for how keys are scoped, stored, and managed, or [CLI auth](/cli/auth/) for how the CLI selects between them.");
|
|
16787
18440
|
return lines;
|
|
16788
18441
|
}
|
|
16789
18442
|
function errorSection() {
|
|
@@ -16796,9 +18449,9 @@ function errorSection() {
|
|
|
16796
18449
|
'{ "error": { "code": "not_found", "message": "App not found.", "details": {} } }',
|
|
16797
18450
|
"```",
|
|
16798
18451
|
"",
|
|
16799
|
-
"`401` means the key is missing or invalid, `403` means the key's organization cannot reach the resource, `404` means it does not exist, `400` means the request failed validation, and `429` means a rate limit was exceeded. Rate limits are applied per key; back off and retry on `429
|
|
18452
|
+
"`401` means the key is missing or invalid, `403` means the key's organization cannot reach the resource, `404` means it does not exist, `400` means the request failed validation, and `429` means a rate limit was exceeded. Rate limits are applied per key; back off and retry on `429`, which carries a `Retry-After` header.",
|
|
16800
18453
|
"",
|
|
16801
|
-
"See [errors](/cli/errors/) for how the CLI surfaces these."
|
|
18454
|
+
"See [conventions](/api/conventions/) for retries, idempotency, and the rest of the shared contract, or [CLI errors](/cli/errors/) for how the CLI surfaces these."
|
|
16802
18455
|
];
|
|
16803
18456
|
}
|
|
16804
18457
|
function coreOperationsSection() {
|
|
@@ -16826,14 +18479,16 @@ function renderApiOverviewMarkdown() {
|
|
|
16826
18479
|
"",
|
|
16827
18480
|
"## Base URL",
|
|
16828
18481
|
"",
|
|
16829
|
-
|
|
18482
|
+
`Every request goes to \`${API_ORIGIN_EXAMPLE}\`:`,
|
|
16830
18483
|
"",
|
|
16831
18484
|
"```bash",
|
|
16832
18485
|
`curl ${API_ORIGIN_EXAMPLE}/api/v1/apps \\`,
|
|
16833
18486
|
' -H "Authorization: Bearer $KHOTAN_API_KEY"',
|
|
16834
18487
|
"```",
|
|
16835
18488
|
"",
|
|
16836
|
-
|
|
18489
|
+
"There is no per-workspace API host. A key carries its own organization and no operation reads the request host, so the base URL never varies by account or workspace.",
|
|
18490
|
+
"",
|
|
18491
|
+
`The machine-readable document is at [\`${OPENAPI_SPEC_PATH}\`](${API_ORIGIN_EXAMPLE}${OPENAPI_SPEC_PATH}) on the same origin, and is also published on this site for reading without an account. Generate a client from the document rather than scraping these pages; they summarize each operation and omit nested response schemas.`,
|
|
16837
18492
|
"",
|
|
16838
18493
|
...authSection(),
|
|
16839
18494
|
"",
|
|
@@ -16851,7 +18506,7 @@ function renderApiOverviewMarkdown() {
|
|
|
16851
18506
|
return lines.join(`
|
|
16852
18507
|
`);
|
|
16853
18508
|
}
|
|
16854
|
-
var apiSpec, OPENAPI_SPEC_PATH = "/api/v1/openapi.json", API_ORIGIN_EXAMPLE = "https
|
|
18509
|
+
var apiSpec, OPENAPI_SPEC_PATH = "/api/v1/openapi.json", API_ORIGIN_EXAMPLE = "https://app.khotan.com", HTTP_METHODS2, OVERVIEW_TAGS, REFERENCE_TAG_ORDER;
|
|
16855
18510
|
var init_reference2 = __esm(() => {
|
|
16856
18511
|
init_validate();
|
|
16857
18512
|
init_version();
|
|
@@ -16863,6 +18518,18 @@ var init_reference2 = __esm(() => {
|
|
|
16863
18518
|
"Identity",
|
|
16864
18519
|
"API keys"
|
|
16865
18520
|
]);
|
|
18521
|
+
REFERENCE_TAG_ORDER = [
|
|
18522
|
+
"Apps",
|
|
18523
|
+
"Pipelines",
|
|
18524
|
+
"Files",
|
|
18525
|
+
"Context",
|
|
18526
|
+
"Integrations",
|
|
18527
|
+
"Databases",
|
|
18528
|
+
"Redis Databases",
|
|
18529
|
+
"SQLite Databases",
|
|
18530
|
+
"Folders",
|
|
18531
|
+
"Projects"
|
|
18532
|
+
];
|
|
16866
18533
|
});
|
|
16867
18534
|
|
|
16868
18535
|
// ../khotan-core/src/client/api-client.ts
|
|
@@ -16949,6 +18616,40 @@ function createApiClient(context) {
|
|
|
16949
18616
|
buildRequest(capabilityOrId, input = {}) {
|
|
16950
18617
|
return buildHttpRequest(capabilityOrId, input, context);
|
|
16951
18618
|
},
|
|
18619
|
+
async request(method, path, body) {
|
|
18620
|
+
if (!context.apiKey) {
|
|
18621
|
+
throw new KhotanClientError("not_authenticated", `${method} ${path} requires authentication but no API key is configured.`);
|
|
18622
|
+
}
|
|
18623
|
+
const headers = {
|
|
18624
|
+
accept: "application/json",
|
|
18625
|
+
"x-api-key": context.apiKey
|
|
18626
|
+
};
|
|
18627
|
+
if (body !== undefined) {
|
|
18628
|
+
headers["content-type"] = "application/json";
|
|
18629
|
+
}
|
|
18630
|
+
let response;
|
|
18631
|
+
try {
|
|
18632
|
+
response = await doFetch(`${normalizeApiUrl(context.apiUrl)}${path}`, {
|
|
18633
|
+
method,
|
|
18634
|
+
headers,
|
|
18635
|
+
body: body === undefined ? undefined : JSON.stringify(body)
|
|
18636
|
+
});
|
|
18637
|
+
} catch (error) {
|
|
18638
|
+
throw new KhotanClientError("network_error", `Could not reach the Khotan API at ${context.apiUrl}: ${error instanceof Error ? error.message : String(error)}`);
|
|
18639
|
+
}
|
|
18640
|
+
const rawBody = await response.text();
|
|
18641
|
+
if (!response.ok) {
|
|
18642
|
+
throw toApiError(response.status, rawBody);
|
|
18643
|
+
}
|
|
18644
|
+
if (!rawBody) {
|
|
18645
|
+
return null;
|
|
18646
|
+
}
|
|
18647
|
+
try {
|
|
18648
|
+
return JSON.parse(rawBody);
|
|
18649
|
+
} catch {
|
|
18650
|
+
throw new KhotanClientError("invalid_response", `The Khotan API returned a non-JSON success response for ${method} ${path}.`);
|
|
18651
|
+
}
|
|
18652
|
+
},
|
|
16952
18653
|
async execute(capabilityOrId, input = {}) {
|
|
16953
18654
|
const capability = resolveCapability(capabilityOrId);
|
|
16954
18655
|
const request = buildHttpRequest(capability, input, context);
|
|
@@ -17135,77 +18836,442 @@ var init_repo_env = __esm(() => {
|
|
|
17135
18836
|
OVERLAY_KEYS = [ENV_API_URL, ENV_API_KEY, ENV_PROFILE, ENV_ORG_ID];
|
|
17136
18837
|
});
|
|
17137
18838
|
|
|
17138
|
-
// ../khotan-core/src/
|
|
17139
|
-
|
|
17140
|
-
|
|
17141
|
-
|
|
17142
|
-
|
|
17143
|
-
|
|
17144
|
-
|
|
17145
|
-
|
|
17146
|
-
|
|
17147
|
-
|
|
17148
|
-
|
|
17149
|
-
|
|
17150
|
-
|
|
17151
|
-
|
|
17152
|
-
|
|
17153
|
-
|
|
17154
|
-
|
|
17155
|
-
|
|
17156
|
-
|
|
17157
|
-
|
|
17158
|
-
|
|
17159
|
-
|
|
17160
|
-
|
|
17161
|
-
|
|
17162
|
-
|
|
17163
|
-
|
|
17164
|
-
|
|
17165
|
-
|
|
17166
|
-
|
|
17167
|
-
|
|
17168
|
-
|
|
17169
|
-
|
|
17170
|
-
|
|
17171
|
-
|
|
17172
|
-
|
|
17173
|
-
|
|
17174
|
-
|
|
17175
|
-
|
|
17176
|
-
|
|
17177
|
-
|
|
17178
|
-
|
|
17179
|
-
|
|
17180
|
-
|
|
17181
|
-
|
|
17182
|
-
|
|
17183
|
-
|
|
17184
|
-
|
|
17185
|
-
|
|
17186
|
-
|
|
17187
|
-
|
|
17188
|
-
|
|
17189
|
-
|
|
17190
|
-
|
|
17191
|
-
|
|
17192
|
-
|
|
17193
|
-
|
|
17194
|
-
|
|
17195
|
-
|
|
17196
|
-
|
|
17197
|
-
|
|
17198
|
-
|
|
17199
|
-
|
|
17200
|
-
|
|
17201
|
-
|
|
17202
|
-
|
|
17203
|
-
|
|
17204
|
-
|
|
17205
|
-
|
|
17206
|
-
|
|
18839
|
+
// ../khotan-core/src/openspec/change.ts
|
|
18840
|
+
function splitMarkdownSections(markdown) {
|
|
18841
|
+
const sections = new Map;
|
|
18842
|
+
let heading;
|
|
18843
|
+
let lines = [];
|
|
18844
|
+
const flush = () => {
|
|
18845
|
+
if (heading !== undefined) {
|
|
18846
|
+
sections.set(heading.toLowerCase(), lines.join(`
|
|
18847
|
+
`).trim());
|
|
18848
|
+
}
|
|
18849
|
+
};
|
|
18850
|
+
for (const line of markdown.split(`
|
|
18851
|
+
`)) {
|
|
18852
|
+
const match = SECTION_HEADING.exec(line);
|
|
18853
|
+
if (match && !line.startsWith("###")) {
|
|
18854
|
+
flush();
|
|
18855
|
+
heading = match[1];
|
|
18856
|
+
lines = [];
|
|
18857
|
+
continue;
|
|
18858
|
+
}
|
|
18859
|
+
lines.push(line);
|
|
18860
|
+
}
|
|
18861
|
+
flush();
|
|
18862
|
+
return sections;
|
|
18863
|
+
}
|
|
18864
|
+
function parseTasks(markdown) {
|
|
18865
|
+
const phases = [];
|
|
18866
|
+
let current;
|
|
18867
|
+
for (const line of markdown.split(`
|
|
18868
|
+
`)) {
|
|
18869
|
+
if (line.startsWith("## ")) {
|
|
18870
|
+
const match = PHASE_HEADING.exec(line);
|
|
18871
|
+
const title = match?.[2]?.trim();
|
|
18872
|
+
if (title) {
|
|
18873
|
+
current = { number: match?.[1], title, items: [] };
|
|
18874
|
+
phases.push(current);
|
|
18875
|
+
}
|
|
18876
|
+
continue;
|
|
18877
|
+
}
|
|
18878
|
+
const task = TASK_LINE.exec(line);
|
|
18879
|
+
if (task && current) {
|
|
18880
|
+
const title = task[3]?.trim();
|
|
18881
|
+
if (title) {
|
|
18882
|
+
current.items.push({
|
|
18883
|
+
number: task[2],
|
|
18884
|
+
title,
|
|
18885
|
+
done: task[1]?.toLowerCase() === "x"
|
|
18886
|
+
});
|
|
18887
|
+
}
|
|
18888
|
+
}
|
|
18889
|
+
}
|
|
18890
|
+
return phases;
|
|
18891
|
+
}
|
|
18892
|
+
function parseSpecDelta(delta) {
|
|
18893
|
+
const requirements = [];
|
|
18894
|
+
let verb = "ADDED";
|
|
18895
|
+
let current;
|
|
18896
|
+
let awaitingStatement = false;
|
|
18897
|
+
let pending = [];
|
|
18898
|
+
const flushStatement = () => {
|
|
18899
|
+
if (current && pending.length > 0) {
|
|
18900
|
+
current.statement = pending.join(" ");
|
|
18901
|
+
awaitingStatement = false;
|
|
18902
|
+
}
|
|
18903
|
+
pending = [];
|
|
18904
|
+
};
|
|
18905
|
+
for (const line of delta.content.split(`
|
|
18906
|
+
`)) {
|
|
18907
|
+
const deltaHeading = DELTA_HEADING.exec(line);
|
|
18908
|
+
if (deltaHeading?.[1]) {
|
|
18909
|
+
flushStatement();
|
|
18910
|
+
verb = deltaHeading[1].toUpperCase();
|
|
18911
|
+
current = undefined;
|
|
18912
|
+
awaitingStatement = false;
|
|
18913
|
+
continue;
|
|
18914
|
+
}
|
|
18915
|
+
const requirement = REQUIREMENT_HEADING.exec(line);
|
|
18916
|
+
if (requirement?.[1]) {
|
|
18917
|
+
flushStatement();
|
|
18918
|
+
current = {
|
|
18919
|
+
capability: delta.capability,
|
|
18920
|
+
verb,
|
|
18921
|
+
title: requirement[1],
|
|
18922
|
+
scenarios: []
|
|
18923
|
+
};
|
|
18924
|
+
requirements.push(current);
|
|
18925
|
+
awaitingStatement = true;
|
|
18926
|
+
continue;
|
|
18927
|
+
}
|
|
18928
|
+
const scenario = SCENARIO_HEADING.exec(line);
|
|
18929
|
+
if (scenario?.[1] && current) {
|
|
18930
|
+
flushStatement();
|
|
18931
|
+
current.scenarios.push(scenario[1]);
|
|
18932
|
+
awaitingStatement = false;
|
|
18933
|
+
continue;
|
|
18934
|
+
}
|
|
18935
|
+
if (awaitingStatement && current) {
|
|
18936
|
+
if (line.trim()) {
|
|
18937
|
+
pending.push(line.trim());
|
|
18938
|
+
} else {
|
|
18939
|
+
flushStatement();
|
|
18940
|
+
}
|
|
18941
|
+
}
|
|
18942
|
+
}
|
|
18943
|
+
flushStatement();
|
|
18944
|
+
return requirements;
|
|
18945
|
+
}
|
|
18946
|
+
function renderChangeIssue(changeId, sources) {
|
|
18947
|
+
const proposal = sources.proposal?.trim();
|
|
18948
|
+
const design = sources.design?.trim();
|
|
18949
|
+
const documents = [];
|
|
18950
|
+
const parts = [];
|
|
18951
|
+
if (proposal) {
|
|
18952
|
+
parts.push(proposal);
|
|
18953
|
+
}
|
|
18954
|
+
const phases = parseTasks(sources.tasks ?? "");
|
|
18955
|
+
if (phases.length > 0) {
|
|
18956
|
+
parts.push(renderTasks(phases));
|
|
18957
|
+
}
|
|
18958
|
+
const requirements = (sources.specs ?? []).flatMap(parseSpecDelta);
|
|
18959
|
+
if (requirements.length > 0) {
|
|
18960
|
+
documents.push({
|
|
18961
|
+
key: "requirements",
|
|
18962
|
+
title: "Requirements",
|
|
18963
|
+
content: renderRequirements(requirements)
|
|
18964
|
+
});
|
|
18965
|
+
}
|
|
18966
|
+
if (design) {
|
|
18967
|
+
documents.push({ key: "design", title: "Design", content: design });
|
|
18968
|
+
}
|
|
18969
|
+
const footer = [`OpenSpec change: \`openspec/changes/${changeId}\``];
|
|
18970
|
+
if (documents.length > 0) {
|
|
18971
|
+
footer.push(`Also on this issue: ${documents.map((document) => document.title).join(" and ")}.`);
|
|
18972
|
+
}
|
|
18973
|
+
parts.push(`---
|
|
18974
|
+
|
|
18975
|
+
${footer.join(`
|
|
18976
|
+
|
|
18977
|
+
`)}`);
|
|
18978
|
+
return {
|
|
18979
|
+
title: humanizeChangeId(changeId),
|
|
18980
|
+
body: parts.join(`
|
|
18981
|
+
|
|
18982
|
+
`),
|
|
18983
|
+
documents
|
|
18984
|
+
};
|
|
18985
|
+
}
|
|
18986
|
+
function renderTasks(phases) {
|
|
18987
|
+
const lines = [
|
|
18988
|
+
"# Tasks",
|
|
18989
|
+
"Tracked in `tasks.md`. Tick them there — this list is rewritten on every push."
|
|
18990
|
+
];
|
|
18991
|
+
for (const phase of phases) {
|
|
18992
|
+
lines.push(`## ${phase.number ? `${phase.number}. ` : ""}${phase.title}`, phase.items.map((item) => {
|
|
18993
|
+
const box = item.done ? "- [x]" : "- [ ]";
|
|
18994
|
+
const number = item.number ? `${item.number} ` : "";
|
|
18995
|
+
return `${box} ${number}${item.title}`;
|
|
18996
|
+
}).join(`
|
|
18997
|
+
`));
|
|
18998
|
+
}
|
|
18999
|
+
return lines.filter(Boolean).join(`
|
|
19000
|
+
|
|
19001
|
+
`);
|
|
19002
|
+
}
|
|
19003
|
+
function renderRequirements(requirements) {
|
|
19004
|
+
const byCapability = new Map;
|
|
19005
|
+
for (const requirement of requirements) {
|
|
19006
|
+
const list = byCapability.get(requirement.capability) ?? [];
|
|
19007
|
+
list.push(requirement);
|
|
19008
|
+
byCapability.set(requirement.capability, list);
|
|
19009
|
+
}
|
|
19010
|
+
const lines = [];
|
|
19011
|
+
for (const [capability, group] of byCapability) {
|
|
19012
|
+
lines.push(`## ${capability}`);
|
|
19013
|
+
for (const requirement of group) {
|
|
19014
|
+
lines.push(`**${requirement.verb} — ${requirement.title}**`);
|
|
19015
|
+
if (requirement.statement) {
|
|
19016
|
+
lines.push(requirement.statement);
|
|
19017
|
+
}
|
|
19018
|
+
if (requirement.scenarios.length > 0) {
|
|
19019
|
+
lines.push(requirement.scenarios.map((title) => `- ${title}`).join(`
|
|
19020
|
+
`));
|
|
19021
|
+
}
|
|
19022
|
+
}
|
|
19023
|
+
}
|
|
19024
|
+
return lines.join(`
|
|
19025
|
+
|
|
19026
|
+
`);
|
|
19027
|
+
}
|
|
19028
|
+
function humanizeChangeId(id) {
|
|
19029
|
+
const words = id.replace(/[-_]+/g, " ").trim();
|
|
19030
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
19031
|
+
}
|
|
19032
|
+
var SECTION_HEADING, PHASE_HEADING, TASK_LINE, DELTA_HEADING, REQUIREMENT_HEADING, SCENARIO_HEADING;
|
|
19033
|
+
var init_change = __esm(() => {
|
|
19034
|
+
SECTION_HEADING = /^##\s+(.+?)\s*$/;
|
|
19035
|
+
PHASE_HEADING = /^##\s+(?:(\d+(?:\.\d+)*)\.\s*)?(.+?)\s*$/;
|
|
19036
|
+
TASK_LINE = /^\s*-\s+\[([ xX])\]\s+(?:(\d+(?:\.\d+)+)\s+)?(.*)$/;
|
|
19037
|
+
DELTA_HEADING = /^##\s+(ADDED|MODIFIED|REMOVED|RENAMED)\s+Requirements\s*$/i;
|
|
19038
|
+
REQUIREMENT_HEADING = /^###\s+Requirement:\s*(.+?)\s*$/;
|
|
19039
|
+
SCENARIO_HEADING = /^####\s+Scenario:\s*(.+?)\s*$/;
|
|
19040
|
+
});
|
|
19041
|
+
|
|
19042
|
+
// ../khotan-core/src/openspec/config.ts
|
|
19043
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
|
|
19044
|
+
import { join as join3 } from "node:path";
|
|
19045
|
+
function parseKhotanConfig(text) {
|
|
19046
|
+
const lines = text.split(`
|
|
19047
|
+
`);
|
|
19048
|
+
const start = lines.findIndex((line) => KHOTAN_BLOCK.test(line));
|
|
19049
|
+
if (start === -1) {
|
|
19050
|
+
return {};
|
|
19051
|
+
}
|
|
19052
|
+
for (const line of lines.slice(start + 1)) {
|
|
19053
|
+
if (line.trim().startsWith("#") || line.trim() === "") {
|
|
19054
|
+
continue;
|
|
19055
|
+
}
|
|
19056
|
+
if (TOP_LEVEL_KEY.test(line)) {
|
|
19057
|
+
break;
|
|
19058
|
+
}
|
|
19059
|
+
const project = PROJECT_ENTRY.exec(line)?.[1];
|
|
19060
|
+
if (project) {
|
|
19061
|
+
return { project: unquote(project) };
|
|
19062
|
+
}
|
|
19063
|
+
}
|
|
19064
|
+
return {};
|
|
19065
|
+
}
|
|
19066
|
+
function readKhotanConfig(openspecRoot) {
|
|
19067
|
+
const path = join3(openspecRoot, "config.yaml");
|
|
19068
|
+
if (!existsSync2(path)) {
|
|
19069
|
+
return {};
|
|
19070
|
+
}
|
|
19071
|
+
return parseKhotanConfig(readFileSync3(path, "utf8"));
|
|
19072
|
+
}
|
|
19073
|
+
function unquote(value) {
|
|
19074
|
+
const trimmed = value.trim();
|
|
19075
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
|
19076
|
+
return trimmed.slice(1, -1);
|
|
19077
|
+
}
|
|
19078
|
+
if (trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
19079
|
+
return trimmed.slice(1, -1);
|
|
19080
|
+
}
|
|
19081
|
+
return trimmed.split("#")[0]?.trim() ?? "";
|
|
19082
|
+
}
|
|
19083
|
+
var KHOTAN_CONFIG_KEY = "khotan", KHOTAN_BLOCK, TOP_LEVEL_KEY, PROJECT_ENTRY;
|
|
19084
|
+
var init_config = __esm(() => {
|
|
19085
|
+
KHOTAN_BLOCK = /^khotan:\s*$/;
|
|
19086
|
+
TOP_LEVEL_KEY = /^\S/;
|
|
19087
|
+
PROJECT_ENTRY = /^\s+project:\s*(.+?)\s*$/;
|
|
19088
|
+
});
|
|
19089
|
+
|
|
19090
|
+
// ../khotan-core/src/openspec/source-url.ts
|
|
19091
|
+
function changeSourceUrl(input) {
|
|
19092
|
+
const parsed = parseRemote(input.remote);
|
|
19093
|
+
if (!parsed) {
|
|
19094
|
+
return;
|
|
19095
|
+
}
|
|
19096
|
+
const { host, path } = parsed;
|
|
19097
|
+
const ref = input.ref ?? "HEAD";
|
|
19098
|
+
const dir = `openspec/changes/${input.changeId}`;
|
|
19099
|
+
if (host === "github.com") {
|
|
19100
|
+
return `https://github.com/${path}/tree/${ref}/${dir}`;
|
|
19101
|
+
}
|
|
19102
|
+
if (host === "gitlab.com") {
|
|
19103
|
+
return `https://gitlab.com/${path}/-/tree/${ref}/${dir}`;
|
|
19104
|
+
}
|
|
19105
|
+
return;
|
|
19106
|
+
}
|
|
19107
|
+
function parseRemote(remote) {
|
|
19108
|
+
const trimmed = remote.trim();
|
|
19109
|
+
for (const pattern of [SSH_REMOTE, HTTPS_REMOTE]) {
|
|
19110
|
+
const match = pattern.exec(trimmed);
|
|
19111
|
+
const host = match?.[1];
|
|
19112
|
+
const path = match?.[2];
|
|
19113
|
+
if (host && path) {
|
|
19114
|
+
return { host: host.toLowerCase(), path: path.replace(/\/+$/, "") };
|
|
19115
|
+
}
|
|
19116
|
+
}
|
|
19117
|
+
return null;
|
|
19118
|
+
}
|
|
19119
|
+
var SSH_REMOTE, HTTPS_REMOTE;
|
|
19120
|
+
var init_source_url = __esm(() => {
|
|
19121
|
+
SSH_REMOTE = /^(?:ssh:\/\/)?git@([^:/]+)[:/](.+?)(?:\.git)?$/;
|
|
19122
|
+
HTTPS_REMOTE = /^https?:\/\/(?:[^@]+@)?([^/]+)\/(.+?)(?:\.git)?$/;
|
|
19123
|
+
});
|
|
19124
|
+
|
|
19125
|
+
// ../khotan-core/src/openspec/read.ts
|
|
19126
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync4, statSync } from "node:fs";
|
|
19127
|
+
import { dirname as dirname3, join as join4 } from "node:path";
|
|
19128
|
+
function findOpenSpecRoot(startDir) {
|
|
19129
|
+
let dir = startDir;
|
|
19130
|
+
for (;; ) {
|
|
19131
|
+
const candidate = join4(dir, OPENSPEC_DIRNAME);
|
|
19132
|
+
if (isDirectory(candidate)) {
|
|
19133
|
+
return candidate;
|
|
19134
|
+
}
|
|
19135
|
+
if (existsSync3(join4(dir, ".git"))) {
|
|
19136
|
+
return;
|
|
19137
|
+
}
|
|
19138
|
+
const parent = dirname3(dir);
|
|
19139
|
+
if (parent === dir) {
|
|
19140
|
+
return;
|
|
19141
|
+
}
|
|
19142
|
+
dir = parent;
|
|
19143
|
+
}
|
|
19144
|
+
}
|
|
19145
|
+
function listChangeIds(openspecRoot) {
|
|
19146
|
+
const changesDir = join4(openspecRoot, "changes");
|
|
19147
|
+
if (!isDirectory(changesDir)) {
|
|
19148
|
+
return [];
|
|
19149
|
+
}
|
|
19150
|
+
return readdirSync(changesDir).filter((entry) => entry !== "archive" && !entry.startsWith(".")).filter((entry) => isDirectory(join4(changesDir, entry))).sort();
|
|
19151
|
+
}
|
|
19152
|
+
function readChangeDirectory(openspecRoot, id) {
|
|
19153
|
+
const path = join4(openspecRoot, "changes", id);
|
|
19154
|
+
if (!isDirectory(path)) {
|
|
19155
|
+
throw new Error(`No change directory at ${path}`);
|
|
19156
|
+
}
|
|
19157
|
+
return {
|
|
19158
|
+
id,
|
|
19159
|
+
path,
|
|
19160
|
+
sources: {
|
|
19161
|
+
proposal: readIfPresent(join4(path, "proposal.md")),
|
|
19162
|
+
design: readIfPresent(join4(path, "design.md")),
|
|
19163
|
+
tasks: readIfPresent(join4(path, "tasks.md")),
|
|
19164
|
+
specs: readSpecDeltas(path)
|
|
19165
|
+
}
|
|
19166
|
+
};
|
|
19167
|
+
}
|
|
19168
|
+
function readSpecDeltas(changePath) {
|
|
19169
|
+
const specsDir = join4(changePath, "specs");
|
|
19170
|
+
if (!isDirectory(specsDir)) {
|
|
19171
|
+
return [];
|
|
19172
|
+
}
|
|
19173
|
+
return readdirSync(specsDir).filter((entry) => !entry.startsWith(".")).sort().flatMap((capability) => {
|
|
19174
|
+
const content = readIfPresent(join4(specsDir, capability, "spec.md"));
|
|
19175
|
+
return content ? [{ capability, content }] : [];
|
|
19176
|
+
});
|
|
19177
|
+
}
|
|
19178
|
+
function readIfPresent(path) {
|
|
19179
|
+
return existsSync3(path) ? readFileSync4(path, "utf8") : undefined;
|
|
19180
|
+
}
|
|
19181
|
+
function isDirectory(path) {
|
|
19182
|
+
try {
|
|
19183
|
+
return statSync(path).isDirectory();
|
|
19184
|
+
} catch {
|
|
19185
|
+
return false;
|
|
19186
|
+
}
|
|
19187
|
+
}
|
|
19188
|
+
var OPENSPEC_DIRNAME = "openspec";
|
|
19189
|
+
var init_read = () => {};
|
|
19190
|
+
|
|
19191
|
+
// ../khotan-core/src/index.ts
|
|
19192
|
+
var exports_src = {};
|
|
19193
|
+
__export(exports_src, {
|
|
19194
|
+
API_ORIGIN_EXAMPLE: () => API_ORIGIN_EXAMPLE,
|
|
17207
19195
|
AUTH_LOGIN_CAPABILITY_ID: () => AUTH_LOGIN_CAPABILITY_ID,
|
|
17208
|
-
|
|
19196
|
+
CATALOG_SCHEMA_VERSION: () => CATALOG_SCHEMA_VERSION,
|
|
19197
|
+
CATALOG_VERSION: () => CATALOG_VERSION,
|
|
19198
|
+
ENV_API_KEY: () => ENV_API_KEY,
|
|
19199
|
+
ENV_API_URL: () => ENV_API_URL,
|
|
19200
|
+
ENV_ORG_ID: () => ENV_ORG_ID,
|
|
19201
|
+
ENV_PROFILE: () => ENV_PROFILE,
|
|
19202
|
+
KHOTAN_ADAPTER_NAME: () => KHOTAN_ADAPTER_NAME,
|
|
19203
|
+
KHOTAN_ADAPTER_VERSION: () => KHOTAN_ADAPTER_VERSION,
|
|
19204
|
+
KHOTAN_CONFIG_KEY: () => KHOTAN_CONFIG_KEY,
|
|
19205
|
+
KhotanApiError: () => KhotanApiError,
|
|
19206
|
+
KhotanCatalogVersionError: () => KhotanCatalogVersionError,
|
|
19207
|
+
KhotanClientError: () => KhotanClientError,
|
|
19208
|
+
KhotanConfirmationRequiredError: () => KhotanConfirmationRequiredError,
|
|
19209
|
+
KhotanError: () => KhotanError,
|
|
19210
|
+
KhotanUnknownCapabilityError: () => KhotanUnknownCapabilityError,
|
|
19211
|
+
OPENAPI_SPEC_PATH: () => OPENAPI_SPEC_PATH,
|
|
19212
|
+
OPENSPEC_DIRNAME: () => OPENSPEC_DIRNAME,
|
|
19213
|
+
OVERVIEW_DOMAINS: () => OVERVIEW_DOMAINS,
|
|
19214
|
+
OVERVIEW_TAGS: () => OVERVIEW_TAGS,
|
|
19215
|
+
REPO_ENV_FILENAME: () => REPO_ENV_FILENAME,
|
|
19216
|
+
SAFETY_LEVELS: () => SAFETY_LEVELS,
|
|
19217
|
+
SUPPORTED_CATALOG_SCHEMA_VERSIONS: () => SUPPORTED_CATALOG_SCHEMA_VERSIONS,
|
|
19218
|
+
apiSpec: () => apiSpec,
|
|
19219
|
+
apiTags: () => apiTags,
|
|
19220
|
+
apiVersion: () => apiVersion,
|
|
19221
|
+
assertSupportedCatalogSchemaVersion: () => assertSupportedCatalogSchemaVersion,
|
|
19222
|
+
buildHttpRequest: () => buildHttpRequest,
|
|
19223
|
+
camelToKebab: () => camelToKebab,
|
|
19224
|
+
capabilitiesByOperationId: () => capabilitiesByOperationId,
|
|
19225
|
+
catalogStamp: () => catalogStamp,
|
|
19226
|
+
changeSourceUrl: () => changeSourceUrl,
|
|
19227
|
+
commandDomains: () => commandDomains,
|
|
19228
|
+
commandUsage: () => commandUsage,
|
|
19229
|
+
createApiClient: () => createApiClient,
|
|
19230
|
+
domainLabel: () => domainLabel,
|
|
19231
|
+
domainTitle: () => domainTitle,
|
|
19232
|
+
fieldFlag: () => fieldFlag,
|
|
19233
|
+
fileTransferSection: () => fileTransferSection,
|
|
19234
|
+
findOpenSpecRoot: () => findOpenSpecRoot,
|
|
19235
|
+
findRepoEnvFile: () => findRepoEnvFile,
|
|
19236
|
+
getCapability: () => getCapability,
|
|
19237
|
+
getProfileStorePath: () => getProfileStorePath,
|
|
19238
|
+
humanizeChangeId: () => humanizeChangeId,
|
|
19239
|
+
indexOpenApiOperations: () => indexOpenApiOperations,
|
|
19240
|
+
isDestructive: () => isDestructive,
|
|
19241
|
+
isReadOnly: () => isReadOnly,
|
|
19242
|
+
isSecret: () => isSecret,
|
|
19243
|
+
khotanCatalog: () => khotanCatalog,
|
|
19244
|
+
listApiOperations: () => listApiOperations,
|
|
19245
|
+
listCapabilities: () => listCapabilities,
|
|
19246
|
+
listChangeIds: () => listChangeIds,
|
|
19247
|
+
listDomains: () => listDomains,
|
|
19248
|
+
loadProfileStore: () => loadProfileStore,
|
|
19249
|
+
openApiStamp: () => openApiStamp,
|
|
19250
|
+
operationsForDomain: () => operationsForDomain,
|
|
19251
|
+
operationsForTag: () => operationsForTag,
|
|
19252
|
+
overlayRepoEnv: () => overlayRepoEnv,
|
|
19253
|
+
parseKhotanConfig: () => parseKhotanConfig,
|
|
19254
|
+
parseRepoEnvFile: () => parseRepoEnvFile,
|
|
19255
|
+
parseSpecDelta: () => parseSpecDelta,
|
|
19256
|
+
parseTasks: () => parseTasks,
|
|
19257
|
+
readChangeDirectory: () => readChangeDirectory,
|
|
19258
|
+
readKhotanConfig: () => readKhotanConfig,
|
|
19259
|
+
referenceTags: () => referenceTags,
|
|
19260
|
+
renderApiOperation: () => renderApiOperation,
|
|
19261
|
+
renderApiOverviewMarkdown: () => renderApiOverviewMarkdown,
|
|
19262
|
+
renderChangeIssue: () => renderChangeIssue,
|
|
19263
|
+
renderDomainCommandsMarkdown: () => renderDomainCommandsMarkdown,
|
|
19264
|
+
renderOperation: () => renderOperation,
|
|
19265
|
+
renderTagReferenceMarkdown: () => renderTagReferenceMarkdown,
|
|
19266
|
+
requiresConfirmation: () => requiresConfirmation,
|
|
19267
|
+
resolveProfile: () => resolveProfile,
|
|
19268
|
+
saveProfileStore: () => saveProfileStore,
|
|
19269
|
+
selectProfile: () => selectProfile,
|
|
19270
|
+
setProfile: () => setProfile,
|
|
19271
|
+
splitMarkdownSections: () => splitMarkdownSections,
|
|
19272
|
+
tagSlug: () => tagSlug,
|
|
19273
|
+
validateCatalogAgainstOpenApi: () => validateCatalogAgainstOpenApi,
|
|
19274
|
+
validateCatalogStructure: () => validateCatalogStructure
|
|
17209
19275
|
});
|
|
17210
19276
|
var init_src = __esm(() => {
|
|
17211
19277
|
init_version();
|
|
@@ -17218,6 +19284,10 @@ var init_src = __esm(() => {
|
|
|
17218
19284
|
init_api_client();
|
|
17219
19285
|
init_profiles();
|
|
17220
19286
|
init_repo_env();
|
|
19287
|
+
init_change();
|
|
19288
|
+
init_config();
|
|
19289
|
+
init_source_url();
|
|
19290
|
+
init_read();
|
|
17221
19291
|
});
|
|
17222
19292
|
|
|
17223
19293
|
// src/cli/run.ts
|
|
@@ -17262,7 +19332,7 @@ function parseArgs(argv) {
|
|
|
17262
19332
|
continue;
|
|
17263
19333
|
}
|
|
17264
19334
|
const next = argv[i + 1];
|
|
17265
|
-
if (next !== undefined && !next.startsWith("-")) {
|
|
19335
|
+
if (next !== undefined && (next === "-" || !next.startsWith("-"))) {
|
|
17266
19336
|
addFlag(body, next);
|
|
17267
19337
|
i++;
|
|
17268
19338
|
} else {
|
|
@@ -17530,6 +19600,88 @@ async function whoami(ctx) {
|
|
|
17530
19600
|
return 0;
|
|
17531
19601
|
}
|
|
17532
19602
|
|
|
19603
|
+
// src/cli/commands/change-push.ts
|
|
19604
|
+
init_src();
|
|
19605
|
+
import { execFileSync } from "node:child_process";
|
|
19606
|
+
async function changePush(deps, options) {
|
|
19607
|
+
const { session, io, json } = deps;
|
|
19608
|
+
const root = findOpenSpecRoot(options.cwd ?? process.cwd());
|
|
19609
|
+
if (!root) {
|
|
19610
|
+
throw new KhotanClientError("not_found", "No openspec/ directory found at or above this directory.");
|
|
19611
|
+
}
|
|
19612
|
+
const project = options.project ?? readKhotanConfig(root).project;
|
|
19613
|
+
if (!project) {
|
|
19614
|
+
throw new KhotanClientError("missing_argument", "No contract project named. Add a `khotan:` block with `project: <slug>` to openspec/config.yaml, or pass --project.");
|
|
19615
|
+
}
|
|
19616
|
+
const changeId = options.changeId ?? soleChangeId(root);
|
|
19617
|
+
const change = readChangeDirectory(root, changeId);
|
|
19618
|
+
const issue = renderChangeIssue(changeId, change.sources);
|
|
19619
|
+
const capabilities2 = (change.sources.specs ?? []).map((delta) => delta.capability);
|
|
19620
|
+
const sourceUrl = resolveSourceUrl(change.path, changeId, options.ref);
|
|
19621
|
+
if (!issue.body.trim()) {
|
|
19622
|
+
throw new KhotanClientError("invalid_argument", `Change "${changeId}" has no proposal or design content to file.`);
|
|
19623
|
+
}
|
|
19624
|
+
if (options.dryRun) {
|
|
19625
|
+
renderResult(io, {
|
|
19626
|
+
project,
|
|
19627
|
+
changeId,
|
|
19628
|
+
openspecRoot: root,
|
|
19629
|
+
title: issue.title,
|
|
19630
|
+
bodyLength: issue.body.length,
|
|
19631
|
+
documents: issue.documents.map((document) => ({
|
|
19632
|
+
title: document.title,
|
|
19633
|
+
length: document.content.length
|
|
19634
|
+
})),
|
|
19635
|
+
capabilities: capabilities2,
|
|
19636
|
+
sourceUrl: sourceUrl ?? null
|
|
19637
|
+
}, { json });
|
|
19638
|
+
return 0;
|
|
19639
|
+
}
|
|
19640
|
+
if (!session) {
|
|
19641
|
+
throw new KhotanClientError("not_authenticated", "Filing a change needs an API key. Run `khotan login`, or pass --dry-run.");
|
|
19642
|
+
}
|
|
19643
|
+
const documentNote = issue.documents.length > 0 ? ` with ${issue.documents.map((document) => document.title.toLowerCase()).join(" and ")}` : "";
|
|
19644
|
+
errLine(io, `Filing ${changeId} under ${project}${documentNote}…`);
|
|
19645
|
+
const result = await session.client.request("POST", `/api/v1/projects/${encodeURIComponent(project)}/changes`, {
|
|
19646
|
+
changeId,
|
|
19647
|
+
title: issue.title,
|
|
19648
|
+
body: issue.body,
|
|
19649
|
+
capabilities: capabilities2,
|
|
19650
|
+
documents: issue.documents,
|
|
19651
|
+
...options.ref || sourceUrl ? {
|
|
19652
|
+
source: {
|
|
19653
|
+
ref: options.ref ?? changeId,
|
|
19654
|
+
...sourceUrl ? { url: sourceUrl } : {},
|
|
19655
|
+
label: `openspec/changes/${changeId}`
|
|
19656
|
+
}
|
|
19657
|
+
} : {}
|
|
19658
|
+
});
|
|
19659
|
+
renderResult(io, result, { json });
|
|
19660
|
+
return 0;
|
|
19661
|
+
}
|
|
19662
|
+
function resolveSourceUrl(changePath, changeId, ref) {
|
|
19663
|
+
try {
|
|
19664
|
+
const remote = execFileSync("git", ["remote", "get-url", "origin"], {
|
|
19665
|
+
cwd: changePath,
|
|
19666
|
+
encoding: "utf8",
|
|
19667
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
19668
|
+
});
|
|
19669
|
+
return changeSourceUrl({ remote, ref, changeId });
|
|
19670
|
+
} catch {
|
|
19671
|
+
return;
|
|
19672
|
+
}
|
|
19673
|
+
}
|
|
19674
|
+
function soleChangeId(openspecRoot) {
|
|
19675
|
+
const ids = listChangeIds(openspecRoot);
|
|
19676
|
+
if (ids.length === 1 && ids[0]) {
|
|
19677
|
+
return ids[0];
|
|
19678
|
+
}
|
|
19679
|
+
if (ids.length === 0) {
|
|
19680
|
+
throw new KhotanClientError("not_found", "No active changes under openspec/changes. Write one first.");
|
|
19681
|
+
}
|
|
19682
|
+
throw new KhotanClientError("missing_argument", `This repo has ${ids.length} active changes. Name one: ${ids.join(", ")}.`);
|
|
19683
|
+
}
|
|
19684
|
+
|
|
17533
19685
|
// src/cli/commands/files-transfer.ts
|
|
17534
19686
|
init_src();
|
|
17535
19687
|
import { basename } from "node:path";
|
|
@@ -17602,9 +19754,65 @@ async function downloadFile(deps, options) {
|
|
|
17602
19754
|
return 0;
|
|
17603
19755
|
}
|
|
17604
19756
|
|
|
19757
|
+
// src/cli/commands/spec-commit.ts
|
|
19758
|
+
init_src();
|
|
19759
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
19760
|
+
async function specCommit(deps, options) {
|
|
19761
|
+
const { session, io, json } = deps;
|
|
19762
|
+
const raw = readCommitDocument(options.file);
|
|
19763
|
+
const document = parseCommitDocument(raw);
|
|
19764
|
+
if (options.expectedRevision !== undefined) {
|
|
19765
|
+
document.expectedRevision = options.expectedRevision;
|
|
19766
|
+
}
|
|
19767
|
+
if (options.changeSummary !== undefined) {
|
|
19768
|
+
document.changeSummary = options.changeSummary;
|
|
19769
|
+
}
|
|
19770
|
+
if (typeof document.expectedRevision !== "number") {
|
|
19771
|
+
throw new KhotanClientError("missing_argument", "A commit needs expectedRevision. Put it in the JSON document, or pass --expected-revision.");
|
|
19772
|
+
}
|
|
19773
|
+
if (!Array.isArray(document.edits) || document.edits.length === 0) {
|
|
19774
|
+
throw new KhotanClientError("invalid_argument", "A commit needs a non-empty edits array.");
|
|
19775
|
+
}
|
|
19776
|
+
errLine(io, `Committing ${document.edits.length} edit${document.edits.length === 1 ? "" : "s"} on ${options.projectId} at revision ${document.expectedRevision}…`);
|
|
19777
|
+
try {
|
|
19778
|
+
const result = await session.client.request("POST", `/api/v1/projects/${encodeURIComponent(options.projectId)}/spec`, document);
|
|
19779
|
+
renderResult(io, result, { json });
|
|
19780
|
+
return 0;
|
|
19781
|
+
} catch (error) {
|
|
19782
|
+
if (error instanceof KhotanApiError && error.code === "revision_conflict") {
|
|
19783
|
+
const expected = error.details?.expectedRevision;
|
|
19784
|
+
const actual = error.details?.actualRevision;
|
|
19785
|
+
throw new KhotanClientError("revision_conflict", `The spec changed since revision ${expected ?? document.expectedRevision}; current is ${actual ?? "?"}. Re-read with khotan projects spec, then commit again.`);
|
|
19786
|
+
}
|
|
19787
|
+
throw error;
|
|
19788
|
+
}
|
|
19789
|
+
}
|
|
19790
|
+
function readCommitDocument(file) {
|
|
19791
|
+
if (file === "-") {
|
|
19792
|
+
return readFileSync5(0, "utf8");
|
|
19793
|
+
}
|
|
19794
|
+
try {
|
|
19795
|
+
return readFileSync5(file, "utf8");
|
|
19796
|
+
} catch (error) {
|
|
19797
|
+
throw new KhotanClientError("not_found", `Could not read ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
19798
|
+
}
|
|
19799
|
+
}
|
|
19800
|
+
function parseCommitDocument(raw) {
|
|
19801
|
+
let parsed;
|
|
19802
|
+
try {
|
|
19803
|
+
parsed = JSON.parse(raw);
|
|
19804
|
+
} catch {
|
|
19805
|
+
throw new KhotanClientError("invalid_argument", "The commit document is not valid JSON.");
|
|
19806
|
+
}
|
|
19807
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
19808
|
+
throw new KhotanClientError("invalid_argument", "The commit document must be a JSON object with an edits array.");
|
|
19809
|
+
}
|
|
19810
|
+
return parsed;
|
|
19811
|
+
}
|
|
19812
|
+
|
|
17605
19813
|
// src/cli/commands/init.ts
|
|
17606
|
-
import { existsSync as
|
|
17607
|
-
import { dirname as
|
|
19814
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "node:fs";
|
|
19815
|
+
import { dirname as dirname4, join as join5, relative } from "node:path";
|
|
17608
19816
|
|
|
17609
19817
|
// src/cli/skills.ts
|
|
17610
19818
|
init_src();
|
|
@@ -17777,25 +19985,25 @@ function toRelative(cwd, absolutePath) {
|
|
|
17777
19985
|
return relative(cwd, absolutePath) || absolutePath;
|
|
17778
19986
|
}
|
|
17779
19987
|
function detectMonoRoot(cwd) {
|
|
17780
|
-
if (hasWorkspacesManifest(
|
|
19988
|
+
if (hasWorkspacesManifest(join5(cwd, "package.json")))
|
|
17781
19989
|
return true;
|
|
17782
|
-
if (
|
|
19990
|
+
if (existsSync4(join5(cwd, "turbo.json")))
|
|
17783
19991
|
return true;
|
|
17784
|
-
if (
|
|
19992
|
+
if (existsSync4(join5(cwd, "WORKSPACE.md")))
|
|
17785
19993
|
return true;
|
|
17786
|
-
if (
|
|
19994
|
+
if (existsSync4(join5(cwd, "package.json")))
|
|
17787
19995
|
return false;
|
|
17788
19996
|
try {
|
|
17789
|
-
return
|
|
19997
|
+
return readdirSync2(cwd, { withFileTypes: true }).some((entry) => entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules" && existsSync4(join5(cwd, entry.name, "package.json")));
|
|
17790
19998
|
} catch {
|
|
17791
19999
|
return false;
|
|
17792
20000
|
}
|
|
17793
20001
|
}
|
|
17794
20002
|
function hasWorkspacesManifest(packageJsonPath) {
|
|
17795
|
-
if (!
|
|
20003
|
+
if (!existsSync4(packageJsonPath))
|
|
17796
20004
|
return false;
|
|
17797
20005
|
try {
|
|
17798
|
-
const parsed = JSON.parse(
|
|
20006
|
+
const parsed = JSON.parse(readFileSync6(packageJsonPath, "utf8"));
|
|
17799
20007
|
if (typeof parsed !== "object" || parsed === null)
|
|
17800
20008
|
return false;
|
|
17801
20009
|
const workspaces = parsed.workspaces;
|
|
@@ -17806,19 +20014,19 @@ function hasWorkspacesManifest(packageJsonPath) {
|
|
|
17806
20014
|
}
|
|
17807
20015
|
function writeTextAsset(ctx, absolutePath, content) {
|
|
17808
20016
|
const path = toRelative(ctx.cwd, absolutePath);
|
|
17809
|
-
const existed =
|
|
20017
|
+
const existed = existsSync4(absolutePath);
|
|
17810
20018
|
if (existed && !ctx.force) {
|
|
17811
20019
|
ctx.results.push({ path, action: "skipped" });
|
|
17812
20020
|
return;
|
|
17813
20021
|
}
|
|
17814
|
-
mkdirSync2(
|
|
20022
|
+
mkdirSync2(dirname4(absolutePath), { recursive: true });
|
|
17815
20023
|
writeFileSync2(absolutePath, content);
|
|
17816
20024
|
ctx.results.push({ path, action: existed ? "forced" : "created" });
|
|
17817
20025
|
}
|
|
17818
20026
|
function writeManagedAsset(ctx, absolutePath, content) {
|
|
17819
20027
|
const path = toRelative(ctx.cwd, absolutePath);
|
|
17820
|
-
const existed =
|
|
17821
|
-
mkdirSync2(
|
|
20028
|
+
const existed = existsSync4(absolutePath);
|
|
20029
|
+
mkdirSync2(dirname4(absolutePath), { recursive: true });
|
|
17822
20030
|
writeFileSync2(absolutePath, content);
|
|
17823
20031
|
ctx.results.push({ path, action: existed ? "updated" : "created" });
|
|
17824
20032
|
}
|
|
@@ -17826,13 +20034,13 @@ function runInit(options) {
|
|
|
17826
20034
|
const { io, cwd, client, force, json } = options;
|
|
17827
20035
|
const ctx = { cwd, force, results: [] };
|
|
17828
20036
|
if (client === "cursor") {
|
|
17829
|
-
writeTextAsset(ctx,
|
|
20037
|
+
writeTextAsset(ctx, join5(cwd, ".cursor", "rules", "khotan.mdc"), CURSOR_RULES);
|
|
17830
20038
|
} else {
|
|
17831
|
-
writeTextAsset(ctx,
|
|
20039
|
+
writeTextAsset(ctx, join5(cwd, "khotan-agents.md"), GENERIC_GUIDE);
|
|
17832
20040
|
}
|
|
17833
20041
|
for (const skill of generateSkills()) {
|
|
17834
20042
|
for (const base of SKILL_BASES) {
|
|
17835
|
-
writeManagedAsset(ctx,
|
|
20043
|
+
writeManagedAsset(ctx, join5(cwd, base, "skills", skill.name, "SKILL.md"), skill.content);
|
|
17836
20044
|
}
|
|
17837
20045
|
}
|
|
17838
20046
|
const monoRoot = detectMonoRoot(cwd);
|
|
@@ -17859,115 +20067,9 @@ function runInit(options) {
|
|
|
17859
20067
|
return 0;
|
|
17860
20068
|
}
|
|
17861
20069
|
|
|
17862
|
-
// src/cli/commands/spec-drift.ts
|
|
17863
|
-
import { execFileSync } from "node:child_process";
|
|
17864
|
-
import { readFileSync as readFileSync4 } from "node:fs";
|
|
17865
|
-
import { join as join4 } from "node:path";
|
|
17866
|
-
var SPEC_LOCK_PATH = ".khotan/spec.lock.json";
|
|
17867
|
-
async function runSpecDrift(options) {
|
|
17868
|
-
const { session, io, json, dir } = options;
|
|
17869
|
-
const defaultBranch = options.defaultBranch ?? resolveDefaultBranch(dir);
|
|
17870
|
-
if (!defaultBranch) {
|
|
17871
|
-
errLine(io, "Could not determine the default branch. Pass --branch <name>, or run inside a git checkout.");
|
|
17872
|
-
return 1;
|
|
17873
|
-
}
|
|
17874
|
-
const pinned = readPinnedRevisions(dir, defaultBranch);
|
|
17875
|
-
if (pinned === null) {
|
|
17876
|
-
errLine(io, `No ${SPEC_LOCK_PATH} found at the merge base with ${defaultBranch}. Nothing has been materialized into this repository yet.`);
|
|
17877
|
-
return json ? 0 : 1;
|
|
17878
|
-
}
|
|
17879
|
-
const response = await session.client.execute("projects.list");
|
|
17880
|
-
const rows = (response.projects ?? []).map((project) => {
|
|
17881
|
-
const slug = typeof project.slug === "string" ? project.slug : null;
|
|
17882
|
-
if (!slug)
|
|
17883
|
-
return null;
|
|
17884
|
-
const latestRevision = typeof project.latestSpecRevision === "number" ? project.latestSpecRevision : 0;
|
|
17885
|
-
const pinnedRevision = pinned.get(slug) ?? null;
|
|
17886
|
-
return {
|
|
17887
|
-
project: slug,
|
|
17888
|
-
pinnedRevision,
|
|
17889
|
-
latestRevision,
|
|
17890
|
-
behindBy: Math.max(0, latestRevision - (pinnedRevision ?? 0))
|
|
17891
|
-
};
|
|
17892
|
-
}).filter((row) => row !== null);
|
|
17893
|
-
if (json) {
|
|
17894
|
-
outLine(io, JSON.stringify({ defaultBranch, projects: rows }, null, 2));
|
|
17895
|
-
return 0;
|
|
17896
|
-
}
|
|
17897
|
-
if (rows.length === 0) {
|
|
17898
|
-
outLine(io, "No projects in this workspace.");
|
|
17899
|
-
return 0;
|
|
17900
|
-
}
|
|
17901
|
-
const drifted = rows.filter((row) => row.behindBy > 0);
|
|
17902
|
-
for (const row of rows) {
|
|
17903
|
-
const pinnedLabel = row.pinnedRevision === null ? "not materialized" : `r${row.pinnedRevision}`;
|
|
17904
|
-
const suffix = row.behindBy === 0 ? "up to date" : `${row.behindBy} revision${row.behindBy === 1 ? "" : "s"} behind (latest r${row.latestRevision})`;
|
|
17905
|
-
outLine(io, `${row.project}: ${pinnedLabel} — ${suffix}`);
|
|
17906
|
-
}
|
|
17907
|
-
if (drifted.length > 0) {
|
|
17908
|
-
outLine(io, `
|
|
17909
|
-
${drifted.length} project${drifted.length === 1 ? " has" : "s have"} moved on since this branch was cut.`);
|
|
17910
|
-
}
|
|
17911
|
-
return 0;
|
|
17912
|
-
}
|
|
17913
|
-
function readPinnedRevisions(dir, defaultBranch) {
|
|
17914
|
-
const mergeBase = git(dir, ["merge-base", "HEAD", defaultBranch]) ?? git(dir, ["rev-parse", defaultBranch]);
|
|
17915
|
-
const content = mergeBase ? git(dir, ["show", `${mergeBase}:${SPEC_LOCK_PATH}`]) : readWorkingTreeLock(dir);
|
|
17916
|
-
if (!content) {
|
|
17917
|
-
return null;
|
|
17918
|
-
}
|
|
17919
|
-
let parsed;
|
|
17920
|
-
try {
|
|
17921
|
-
parsed = JSON.parse(content);
|
|
17922
|
-
} catch {
|
|
17923
|
-
return null;
|
|
17924
|
-
}
|
|
17925
|
-
const pinned = new Map;
|
|
17926
|
-
for (const [slug, entry] of Object.entries(parsed.projects ?? {})) {
|
|
17927
|
-
if (entry && typeof entry.revision === "number") {
|
|
17928
|
-
pinned.set(slug, entry.revision);
|
|
17929
|
-
}
|
|
17930
|
-
}
|
|
17931
|
-
return pinned;
|
|
17932
|
-
}
|
|
17933
|
-
function readWorkingTreeLock(dir) {
|
|
17934
|
-
try {
|
|
17935
|
-
return readFileSync4(join4(dir, SPEC_LOCK_PATH), "utf8");
|
|
17936
|
-
} catch {
|
|
17937
|
-
return null;
|
|
17938
|
-
}
|
|
17939
|
-
}
|
|
17940
|
-
function resolveDefaultBranch(dir) {
|
|
17941
|
-
const remoteHead = git(dir, ["symbolic-ref", "refs/remotes/origin/HEAD"]);
|
|
17942
|
-
if (remoteHead) {
|
|
17943
|
-
const name = remoteHead.split("/").pop();
|
|
17944
|
-
if (name)
|
|
17945
|
-
return `origin/${name}`;
|
|
17946
|
-
}
|
|
17947
|
-
for (const candidate of ["origin/main", "origin/master", "main", "master"]) {
|
|
17948
|
-
if (git(dir, ["rev-parse", "--verify", candidate])) {
|
|
17949
|
-
return candidate;
|
|
17950
|
-
}
|
|
17951
|
-
}
|
|
17952
|
-
return null;
|
|
17953
|
-
}
|
|
17954
|
-
function git(dir, args) {
|
|
17955
|
-
try {
|
|
17956
|
-
const output = execFileSync("git", args, {
|
|
17957
|
-
cwd: dir,
|
|
17958
|
-
encoding: "utf8",
|
|
17959
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
17960
|
-
});
|
|
17961
|
-
const trimmed = output.trim();
|
|
17962
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
17963
|
-
} catch {
|
|
17964
|
-
return null;
|
|
17965
|
-
}
|
|
17966
|
-
}
|
|
17967
|
-
|
|
17968
20070
|
// src/cli/commands/status.ts
|
|
17969
20071
|
import { writeFileSync as writeFileSync3 } from "node:fs";
|
|
17970
|
-
import { join as
|
|
20072
|
+
import { join as join6, relative as relative2 } from "node:path";
|
|
17971
20073
|
function str(value) {
|
|
17972
20074
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
17973
20075
|
}
|
|
@@ -18247,7 +20349,7 @@ async function runStatus(options) {
|
|
|
18247
20349
|
const { session, io, json, writeDir } = options;
|
|
18248
20350
|
const topology = await loadTopology(session);
|
|
18249
20351
|
if (writeDir) {
|
|
18250
|
-
const target =
|
|
20352
|
+
const target = join6(writeDir, "WORKSPACE.md");
|
|
18251
20353
|
writeFileSync3(target, buildWorkspaceManifest(topology));
|
|
18252
20354
|
const shown = relative2(process.cwd(), target) || target;
|
|
18253
20355
|
if (json) {
|
|
@@ -18329,6 +20431,10 @@ function printTopLevelHelp(io) {
|
|
|
18329
20431
|
outLine(io, " files upload <path> Upload a local file (presigned flow)");
|
|
18330
20432
|
outLine(io, " files download <fileId> Download a file to --output (presigned flow)");
|
|
18331
20433
|
outLine(io);
|
|
20434
|
+
outLine(io, "OpenSpec:");
|
|
20435
|
+
outLine(io, " change push [changeId] File a change directory as an issue");
|
|
20436
|
+
outLine(io, " projects spec commit Commit spec edits from a JSON document");
|
|
20437
|
+
outLine(io);
|
|
18332
20438
|
outLine(io, "Workspace:");
|
|
18333
20439
|
outLine(io, " status Show the workspace topology (apps, pipelines, databases)");
|
|
18334
20440
|
outLine(io, " status --write Refresh a committable WORKSPACE.md from live data");
|
|
@@ -18477,25 +20583,25 @@ init_src();
|
|
|
18477
20583
|
// src/cli/assert-org.ts
|
|
18478
20584
|
init_src();
|
|
18479
20585
|
import { createHash } from "node:crypto";
|
|
18480
|
-
import { existsSync as
|
|
20586
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "node:fs";
|
|
18481
20587
|
import { homedir as homedir2 } from "node:os";
|
|
18482
|
-
import { dirname as
|
|
20588
|
+
import { dirname as dirname5, join as join7 } from "node:path";
|
|
18483
20589
|
var CACHE_TTL_MS = 5 * 60 * 1000;
|
|
18484
20590
|
function cacheDir(env) {
|
|
18485
20591
|
const xdg = env.XDG_CACHE_HOME;
|
|
18486
|
-
const base = xdg && xdg.trim() ? xdg :
|
|
18487
|
-
return
|
|
20592
|
+
const base = xdg && xdg.trim() ? xdg : join7(homedir2(), ".cache");
|
|
20593
|
+
return join7(base, "khotan");
|
|
18488
20594
|
}
|
|
18489
20595
|
function cacheFilePath(env, apiUrl, orgId) {
|
|
18490
20596
|
const hash = createHash("sha256").update(`${apiUrl}
|
|
18491
20597
|
${orgId}`).digest("hex").slice(0, 32);
|
|
18492
|
-
return
|
|
20598
|
+
return join7(cacheDir(env), `org-assert-${hash}.json`);
|
|
18493
20599
|
}
|
|
18494
20600
|
function readAssertionCache(path, expectedOrgId) {
|
|
18495
|
-
if (!
|
|
20601
|
+
if (!existsSync5(path))
|
|
18496
20602
|
return false;
|
|
18497
20603
|
try {
|
|
18498
|
-
const parsed = JSON.parse(
|
|
20604
|
+
const parsed = JSON.parse(readFileSync7(path, "utf8"));
|
|
18499
20605
|
if (parsed.organizationId !== expectedOrgId)
|
|
18500
20606
|
return false;
|
|
18501
20607
|
if (Date.now() - parsed.verifiedAt > CACHE_TTL_MS)
|
|
@@ -18507,7 +20613,7 @@ function readAssertionCache(path, expectedOrgId) {
|
|
|
18507
20613
|
}
|
|
18508
20614
|
function writeAssertionCache(path, organizationId) {
|
|
18509
20615
|
try {
|
|
18510
|
-
mkdirSync3(
|
|
20616
|
+
mkdirSync3(dirname5(path), { recursive: true });
|
|
18511
20617
|
const payload = { organizationId, verifiedAt: Date.now() };
|
|
18512
20618
|
writeFileSync4(path, `${JSON.stringify(payload)}
|
|
18513
20619
|
`);
|
|
@@ -18686,29 +20792,6 @@ async function run(argv, options = {}) {
|
|
|
18686
20792
|
const writeDir = write ? flagValue(args, "dir") ?? (writeValue && writeValue !== "true" ? writeValue : undefined) ?? process.cwd() : undefined;
|
|
18687
20793
|
return await runStatus({ session, io, json, writeDir });
|
|
18688
20794
|
}
|
|
18689
|
-
if (first === "spec" && positionals[1] === "drift") {
|
|
18690
|
-
if (helpFlag) {
|
|
18691
|
-
errLine(io, "Usage: khotan spec drift [--dir <path>] [--branch <name>] [--json]");
|
|
18692
|
-
return 0;
|
|
18693
|
-
}
|
|
18694
|
-
const session = await resolveSessionAsserted({
|
|
18695
|
-
env,
|
|
18696
|
-
storeOptions: options.storeOptions,
|
|
18697
|
-
profileName,
|
|
18698
|
-
apiUrlOverride,
|
|
18699
|
-
apiKeyOverride,
|
|
18700
|
-
fetch: options.fetch,
|
|
18701
|
-
assertOrgOverride
|
|
18702
|
-
});
|
|
18703
|
-
const json = jsonFlag || session.resolved.defaultOutput === "json";
|
|
18704
|
-
return await runSpecDrift({
|
|
18705
|
-
session,
|
|
18706
|
-
io,
|
|
18707
|
-
json,
|
|
18708
|
-
dir: flagValue(args, "dir") ?? process.cwd(),
|
|
18709
|
-
defaultBranch: flagValue(args, "branch")
|
|
18710
|
-
});
|
|
18711
|
-
}
|
|
18712
20795
|
if (first === "login") {
|
|
18713
20796
|
return await authLogin(authCtx);
|
|
18714
20797
|
}
|
|
@@ -18734,6 +20817,62 @@ async function run(argv, options = {}) {
|
|
|
18734
20817
|
errLine(io, `Unknown auth command "${sub ?? ""}". Try: set-key, login, use, list.`);
|
|
18735
20818
|
return 1;
|
|
18736
20819
|
}
|
|
20820
|
+
if (first === "projects" && positionals[1] === "spec" && positionals[2] === "commit") {
|
|
20821
|
+
if (helpFlag) {
|
|
20822
|
+
errLine(io, "Usage: khotan projects spec commit <projectId> --file <path> [--expected-revision <n>] [--change-summary <text>] [--json]");
|
|
20823
|
+
return 0;
|
|
20824
|
+
}
|
|
20825
|
+
const projectId = positionals[3];
|
|
20826
|
+
const file = flagValue(args, "file");
|
|
20827
|
+
if (!projectId || !file) {
|
|
20828
|
+
throw new KhotanClientError("missing_argument", "Usage: khotan projects spec commit <projectId> --file <path>.");
|
|
20829
|
+
}
|
|
20830
|
+
const session = await resolveSessionAsserted({
|
|
20831
|
+
env,
|
|
20832
|
+
storeOptions: options.storeOptions,
|
|
20833
|
+
profileName,
|
|
20834
|
+
apiUrlOverride,
|
|
20835
|
+
apiKeyOverride,
|
|
20836
|
+
fetch: options.fetch,
|
|
20837
|
+
assertOrgOverride
|
|
20838
|
+
});
|
|
20839
|
+
const json = jsonFlag || session.resolved.defaultOutput === "json";
|
|
20840
|
+
const expectedRevisionRaw = flagValue(args, "expected-revision");
|
|
20841
|
+
const expectedRevision = expectedRevisionRaw ? Number(expectedRevisionRaw) : undefined;
|
|
20842
|
+
if (expectedRevisionRaw && Number.isNaN(expectedRevision)) {
|
|
20843
|
+
throw new KhotanClientError("invalid_argument", "--expected-revision expects a number.");
|
|
20844
|
+
}
|
|
20845
|
+
return await specCommit({ session, io, json }, {
|
|
20846
|
+
projectId,
|
|
20847
|
+
file,
|
|
20848
|
+
expectedRevision,
|
|
20849
|
+
changeSummary: flagValue(args, "change-summary")
|
|
20850
|
+
});
|
|
20851
|
+
}
|
|
20852
|
+
if (first === "change" && positionals[1] === "push") {
|
|
20853
|
+
if (helpFlag) {
|
|
20854
|
+
errLine(io, "Usage: khotan change push [changeId] [--project <slug>] [--ref <sha>] [--dir <path>] [--dry-run] [--json]");
|
|
20855
|
+
return 0;
|
|
20856
|
+
}
|
|
20857
|
+
const dryRun = flagBool(args, "dry-run");
|
|
20858
|
+
const session = dryRun ? undefined : await resolveSessionAsserted({
|
|
20859
|
+
env,
|
|
20860
|
+
storeOptions: options.storeOptions,
|
|
20861
|
+
profileName,
|
|
20862
|
+
apiUrlOverride,
|
|
20863
|
+
apiKeyOverride,
|
|
20864
|
+
fetch: options.fetch,
|
|
20865
|
+
assertOrgOverride
|
|
20866
|
+
});
|
|
20867
|
+
const json = jsonFlag || session?.resolved.defaultOutput === "json";
|
|
20868
|
+
return await changePush({ session, io, json }, {
|
|
20869
|
+
changeId: positionals[2],
|
|
20870
|
+
project: flagValue(args, "project"),
|
|
20871
|
+
cwd: flagValue(args, "dir"),
|
|
20872
|
+
ref: flagValue(args, "ref"),
|
|
20873
|
+
dryRun
|
|
20874
|
+
});
|
|
20875
|
+
}
|
|
18737
20876
|
if (first === "files" && (positionals[1] === "upload" || positionals[1] === "download")) {
|
|
18738
20877
|
if (helpFlag) {
|
|
18739
20878
|
errLine(io, positionals[1] === "upload" ? "Usage: khotan files upload <localPath> [--name <n>] [--folder-id <id>] [--folder-path <p>] [--content-type <t>]" : "Usage: khotan files download <fileId> --output <path>");
|