@khotan/cli 0.8.0 → 0.10.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.
Files changed (3) hide show
  1. package/README.md +15 -2
  2. package/dist/khotan.js +136 -3
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -142,9 +142,11 @@ documented surface and the executable surface cannot drift. Run `khotan help` or
142
142
  | App env | `apps env list <id>`, `apps env set <id> <KEY> --value V`, `apps env reveal <id> <KEY>`, `apps env unset <id> <KEY>`, `apps env bulk-set <id> --var A=1 --var B=2` |
143
143
  | Pipelines | same shape as apps under `pipelines …` |
144
144
  | Databases | `databases list`, `databases create --name db`, `databases connection <id>`, `databases rotate-credentials <id>`, `databases delete <id>` |
145
- | Files | `files list`, `files get <id>`, `files upload <path>`, `files download <id> --output <path>`, `files update <id> --name new.txt`, `files delete <id>` |
145
+ | Files | `files list`, `files get <id>`, `files upload <path>`, `files download <id> --output <path>`, `files download-url <id>`, `files preview-url <id>`, `files update <id> --name new.txt`, `files delete <id>` |
146
146
  | Folders | `folders list`, `folders create --name docs`, `folders rename <id> --name new`, `folders delete <id>` |
147
- | Context | `context list`, `context get <slug>`, `context raw <slug>`, `context create --title T --kind knowledge --content '...'`, `context update <slug> --expected-revision 3 --content '...'`, `context delete <slug>` |
147
+ | Context | `context list`, `context get <slug>`, `context raw <slug>`, `context create --title T --kind knowledge --content '...' --folder-id <id>`, `context update <slug> --expected-revision 3 --content '...' --folder-id <id>`, `context delete <slug>` |
148
+ | Context folders | `context folders list`, `context folders create --name docs --parent-id <id>`, `context folders update <id> --name new --parent-id <id>`, `context folders delete <id> --recursive` |
149
+ | Context revisions | `context revisions list <slug>`, `context revisions get <slug> <revision>`, `context revisions restore <slug> <revision>` |
148
150
 
149
151
  ### Output modes
150
152
 
@@ -173,6 +175,17 @@ khotan files upload ./report.pdf --folder-path /reports/2026
173
175
  khotan files download file_123 --output ./report.pdf
174
176
  ```
175
177
 
178
+ To hand a file to a browser instead of saving it locally, mint a short-lived
179
+ presigned URL and load it directly (no API key on the URL; expires in ~5 minutes):
180
+
181
+ ```bash
182
+ khotan files preview-url file_123 # inline disposition, images and PDFs only
183
+ khotan files download-url file_123 # attachment disposition, any file type
184
+ ```
185
+
186
+ See [Serving file attachments](../../docs/files-api-attachments.md) for the full
187
+ preview/download flow and the receiver wiring guidance.
188
+
176
189
  ## MCP server
177
190
 
178
191
  `khotan mcp serve` starts a local stdio MCP server that reuses the same profile,
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 = 1, CATALOG_VERSION = "2026-06-28", KHOTAN_ADAPTER_NAME = "khotan", KHOTAN_ADAPTER_VERSION = "0.7.0", SUPPORTED_CATALOG_SCHEMA_VERSIONS;
22
+ var CATALOG_SCHEMA_VERSION = 1, CATALOG_VERSION = "2026-07-01", 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
@@ -906,6 +906,19 @@ var init_catalog = __esm(() => {
906
906
  cli: { command: ["files", "download-url"], summary: "Get a file download URL", defaultOutput: "detail" },
907
907
  mcp: { tool: { name: "khotan_files_download", title: "Get a file download URL", description: "Return a short-lived presigned GET URL for a ready file." } }
908
908
  },
909
+ {
910
+ id: "files.preview",
911
+ kind: "operation",
912
+ domain: "files",
913
+ safety: "read",
914
+ auth: true,
915
+ title: "Get a file preview URL",
916
+ description: "Return a short-lived presigned inline GET URL for a ready, preview-eligible file (images and PDFs).",
917
+ input: [idField("fileId", "The file id.")],
918
+ http: { method: "GET", path: "/api/v1/files/{fileId}/preview", operationId: "getFilePreviewUrl" },
919
+ cli: { command: ["files", "preview-url"], summary: "Get a file preview URL", defaultOutput: "detail" },
920
+ mcp: { tool: { name: "khotan_files_preview", title: "Get a file preview URL", description: "Return a short-lived presigned inline GET URL for a ready, preview-eligible file (images and PDFs)." } }
921
+ },
909
922
  {
910
923
  id: "files.resource",
911
924
  kind: "resource",
@@ -1063,7 +1076,8 @@ var init_catalog = __esm(() => {
1063
1076
  { name: "content", location: "body", type: "string", required: true, description: "Canonical markdown content." },
1064
1077
  { name: "slug", location: "body", type: "string", description: "Optional slug; derived from the title when omitted." },
1065
1078
  { name: "description", location: "body", type: "string", description: "One-line purpose statement." },
1066
- { name: "tags", location: "body", type: "string[]", description: "Flat tag list." }
1079
+ { name: "tags", location: "body", type: "string[]", description: "Flat tag list." },
1080
+ { name: "folderId", location: "body", type: "string", description: "Folder placement; omit for the organization root." }
1067
1081
  ],
1068
1082
  http: { method: "POST", path: "/api/v1/context", operationId: "createContextDocument", bodyMode: "json" },
1069
1083
  cli: { command: ["context", "create"], summary: "Create a context document", defaultOutput: "detail" },
@@ -1085,6 +1099,7 @@ var init_catalog = __esm(() => {
1085
1099
  { name: "content", location: "body", type: "string", description: "New markdown content." },
1086
1100
  { name: "description", location: "body", type: "string", description: "New description (null clears it)." },
1087
1101
  { name: "tags", location: "body", type: "string[]", description: "New tag list." },
1102
+ { name: "folderId", location: "body", type: "string", description: "Move the document to this folder; omit to leave unchanged. (Sending null to move to the root is not reachable via CLI flags.)" },
1088
1103
  { name: "changeSummary", location: "body", type: "string", description: "Optional revision-history note." }
1089
1104
  ],
1090
1105
  http: { method: "PATCH", path: "/api/v1/context/{slug}", operationId: "updateContextDocument", bodyMode: "json" },
@@ -1104,6 +1119,113 @@ var init_catalog = __esm(() => {
1104
1119
  cli: { command: ["context", "delete"], summary: "Delete a context document" },
1105
1120
  mcp: { tool: { name: "khotan_context_delete", title: "Delete a context document", description: "Soft-delete a context document. Requires confirmation." } }
1106
1121
  },
1122
+ {
1123
+ id: "context.folders.list",
1124
+ kind: "operation",
1125
+ domain: "context",
1126
+ safety: "read",
1127
+ auth: true,
1128
+ title: "List context folders",
1129
+ description: "List the organization's context folders as a flat list, each carrying parentId, path, depth, and its direct active-document count.",
1130
+ input: [],
1131
+ http: { method: "GET", path: "/api/v1/context/folders", operationId: "listContextFolders" },
1132
+ cli: { command: ["context", "folders", "list"], summary: "List context folders", defaultOutput: "table" },
1133
+ mcp: { tool: { name: "khotan_context_folders_list", title: "List context folders", description: "List context folders as a flat list with parentId, path, depth, and document count." } }
1134
+ },
1135
+ {
1136
+ id: "context.folders.create",
1137
+ kind: "operation",
1138
+ domain: "context",
1139
+ safety: "write",
1140
+ auth: true,
1141
+ title: "Create a context folder",
1142
+ description: "Create a folder under an optional parent (omit parentId for the organization root).",
1143
+ input: [
1144
+ { name: "name", location: "body", type: "string", required: true, description: "The folder name; must be unique among active siblings." },
1145
+ { name: "parentId", location: "body", type: "string", description: "Parent folder id; omit for the organization root." }
1146
+ ],
1147
+ http: { method: "POST", path: "/api/v1/context/folders", operationId: "createContextFolder", bodyMode: "json" },
1148
+ cli: { command: ["context", "folders", "create"], summary: "Create a context folder", defaultOutput: "detail" },
1149
+ mcp: { tool: { name: "khotan_context_folders_create", title: "Create a context folder", description: "Create a context folder under an optional parent." } }
1150
+ },
1151
+ {
1152
+ id: "context.folders.update",
1153
+ kind: "operation",
1154
+ domain: "context",
1155
+ safety: "write",
1156
+ auth: true,
1157
+ title: "Rename or move a context folder",
1158
+ description: "Rename a folder (name) and/or move it under a new parent (parentId).",
1159
+ input: [
1160
+ idField("id", "The folder id."),
1161
+ { name: "name", location: "body", type: "string", description: "New folder name." },
1162
+ { name: "parentId", location: "body", type: "string", description: "New parent folder id. (Sending null to move to the root is not reachable via CLI flags.)" }
1163
+ ],
1164
+ http: { method: "PATCH", path: "/api/v1/context/folders/{id}", operationId: "updateContextFolder", bodyMode: "json" },
1165
+ cli: { command: ["context", "folders", "update"], summary: "Rename or move a context folder", defaultOutput: "detail" },
1166
+ mcp: { tool: { name: "khotan_context_folders_update", title: "Rename or move a context folder", description: "Rename a context folder and/or move it under a new parent (parentId null moves it to the root)." } }
1167
+ },
1168
+ {
1169
+ id: "context.folders.delete",
1170
+ kind: "operation",
1171
+ domain: "context",
1172
+ safety: "destructive",
1173
+ auth: true,
1174
+ title: "Delete a context folder",
1175
+ description: "Soft-delete a folder. A non-empty folder requires --recursive, which also soft-deletes its subfolders and documents.",
1176
+ input: [
1177
+ idField("id", "The folder id."),
1178
+ { name: "recursive", location: "query", type: "boolean", default: false, description: "Delete a non-empty folder and all of its contents." }
1179
+ ],
1180
+ http: { method: "DELETE", path: "/api/v1/context/folders/{id}", operationId: "deleteContextFolder" },
1181
+ cli: { command: ["context", "folders", "delete"], summary: "Delete a context folder" },
1182
+ mcp: { tool: { name: "khotan_context_folders_delete", title: "Delete a context folder", description: "Soft-delete a context folder. Pass recursive=true to delete a non-empty folder and its contents. Requires confirmation." } }
1183
+ },
1184
+ {
1185
+ id: "context.revisions.list",
1186
+ kind: "operation",
1187
+ domain: "context",
1188
+ safety: "read",
1189
+ auth: true,
1190
+ title: "List a context document's revisions",
1191
+ description: "List a document's revision history, newest first (metadata only, never snapshot content).",
1192
+ input: [idField("slug", "The document slug.")],
1193
+ http: { method: "GET", path: "/api/v1/context/{slug}/revisions", operationId: "listContextDocumentRevisions" },
1194
+ cli: { command: ["context", "revisions", "list"], summary: "List a document's revisions", defaultOutput: "table" },
1195
+ mcp: { tool: { name: "khotan_context_revisions_list", title: "List document revisions", description: "List a context document's revision history, newest first (metadata only)." } }
1196
+ },
1197
+ {
1198
+ id: "context.revisions.get",
1199
+ kind: "operation",
1200
+ domain: "context",
1201
+ safety: "read",
1202
+ auth: true,
1203
+ title: "Get a context document revision",
1204
+ description: "Get a single captured revision including its markdown snapshot.",
1205
+ input: [
1206
+ idField("slug", "The document slug."),
1207
+ { name: "revision", location: "path", type: "number", required: true, description: "The revision number." }
1208
+ ],
1209
+ http: { method: "GET", path: "/api/v1/context/{slug}/revisions/{revision}", operationId: "getContextDocumentRevision" },
1210
+ cli: { command: ["context", "revisions", "get"], summary: "Get a document revision", defaultOutput: "detail" },
1211
+ mcp: { tool: { name: "khotan_context_revisions_get", title: "Get a document revision", description: "Get a single context document revision including its markdown snapshot." } }
1212
+ },
1213
+ {
1214
+ id: "context.revisions.restore",
1215
+ kind: "operation",
1216
+ domain: "context",
1217
+ safety: "write",
1218
+ auth: true,
1219
+ title: "Restore a context document revision",
1220
+ description: "Restore a document to an earlier revision by writing a new forward revision matching that snapshot (history is never rewritten).",
1221
+ input: [
1222
+ idField("slug", "The document slug."),
1223
+ { name: "revision", location: "path", type: "number", required: true, description: "The revision number to restore." }
1224
+ ],
1225
+ http: { method: "POST", path: "/api/v1/context/{slug}/revisions/{revision}/restore", operationId: "restoreContextDocumentRevision" },
1226
+ cli: { command: ["context", "revisions", "restore"], summary: "Restore a document revision", defaultOutput: "detail" },
1227
+ mcp: { tool: { name: "khotan_context_revisions_restore", title: "Restore a document revision", description: "Restore a context document to an earlier revision by writing a new forward revision." } }
1228
+ },
1107
1229
  {
1108
1230
  id: "context.resource",
1109
1231
  kind: "resource",
@@ -2315,6 +2437,17 @@ function singleArrayProperty(record) {
2315
2437
  }
2316
2438
  return;
2317
2439
  }
2440
+ function singleObjectProperty(record) {
2441
+ const keys = Object.keys(record);
2442
+ if (keys.length !== 1) {
2443
+ return;
2444
+ }
2445
+ const value = record[keys[0]];
2446
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
2447
+ return value;
2448
+ }
2449
+ return;
2450
+ }
2318
2451
  function renderResult(io, result, options) {
2319
2452
  if (options.json) {
2320
2453
  outLine(io, JSON.stringify(result, null, 2));
@@ -2341,7 +2474,7 @@ function renderResult(io, result, options) {
2341
2474
  renderTable(io, list);
2342
2475
  return;
2343
2476
  }
2344
- renderDetail(io, record);
2477
+ renderDetail(io, singleObjectProperty(record) ?? record);
2345
2478
  return;
2346
2479
  }
2347
2480
  outLine(io, scalar(result));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khotan/cli",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "description": "Khotan CLI and MCP server: human- and agent-facing adapters over the Khotan /api/v1 surface.",
6
6
  "license": "SEE LICENSE IN LICENSE.md",