|
| 1 | +import type { CliContract } from './types.js' |
| 2 | + |
| 3 | +/** |
| 4 | + * The CLI contract for the v2 surface. |
| 5 | + * |
| 6 | + * Read this as a diff against what is already derivable — an operation absent |
| 7 | + * from this table still gets a command, built entirely from the generated |
| 8 | + * operation table. Only the entries below needed a human. |
| 9 | + * |
| 10 | + * Derived by default: |
| 11 | + * listTables → sim tables list |
| 12 | + * getKnowledgeDocument → sim knowledge documents get <id> <documentId> |
| 13 | + * upsertTableRow → sim tables upsert <tableId> |
| 14 | + */ |
| 15 | +export const CLI_CONTRACT: CliContract = { |
| 16 | + // ─── Name collisions: REST overloads one path for single and bulk ───────── |
| 17 | + // The derived name is identical for both, so the bulk form is renamed. AWS's |
| 18 | + // `batch-` prefix rather than a `--all` flag: the plural is a different and |
| 19 | + // more dangerous operation, and it should be a different word. |
| 20 | + deleteTableRows: { |
| 21 | + command: 'tables rows batch-delete', |
| 22 | + describe: 'Delete rows matching a filter, or an explicit list of ids', |
| 23 | + flags: { rowIds: { name: 'row', list: true }, filter: { json: true } }, |
| 24 | + confirm: 'This deletes every matching row and cannot be undone.', |
| 25 | + }, |
| 26 | + updateRowsByFilter: { |
| 27 | + command: 'tables rows batch-update', |
| 28 | + describe: 'Update every row matching a filter', |
| 29 | + flags: { filter: { json: true }, data: { json: true } }, |
| 30 | + confirm: 'This updates every matching row and cannot be undone.', |
| 31 | + }, |
| 32 | + // `DELETE /workflows/[id]/deploy` is an undeploy, not a delete. |
| 33 | + undeployWorkflow: { |
| 34 | + command: 'workflows undeploy', |
| 35 | + describe: 'Take a workflow out of deployment', |
| 36 | + }, |
| 37 | + |
| 38 | + // ─── Destructive single-resource operations ─────────────────────────────── |
| 39 | + deleteTable: { confirm: 'This deletes the table and all of its rows.' }, |
| 40 | + deleteTableRow: { confirm: 'This deletes the row.' }, |
| 41 | + deleteTableColumn: { confirm: 'This deletes the column and its values in every row.' }, |
| 42 | + deleteKnowledgeBase: { confirm: 'This deletes the knowledge base and every document in it.' }, |
| 43 | + deleteKnowledgeDocument: { confirm: 'This deletes the document and its embeddings.' }, |
| 44 | + deleteFile: { confirm: 'This archives the file.' }, |
| 45 | + |
| 46 | + // ─── Fields whose type misdescribes their meaning ───────────────────────── |
| 47 | + // `z.string()` that the route splits on commas. No generator can infer this. |
| 48 | + listLogs: { |
| 49 | + flags: { |
| 50 | + workflowIds: { name: 'workflow', list: true }, |
| 51 | + folderIds: { name: 'folder', list: true }, |
| 52 | + triggers: { name: 'trigger', list: true }, |
| 53 | + }, |
| 54 | + columns: [ |
| 55 | + { header: 'started', path: 'startedAt', format: 'timestamp' }, |
| 56 | + { header: 'level' }, |
| 57 | + { header: 'trigger' }, |
| 58 | + { header: 'workflow', path: 'workflow.name' }, |
| 59 | + { header: 'duration', path: 'totalDurationMs', format: 'duration' }, |
| 60 | + { header: 'cost', path: 'cost.total', format: 'cost' }, |
| 61 | + { header: 'execution', path: 'executionId' }, |
| 62 | + ], |
| 63 | + }, |
| 64 | + searchKnowledge: { |
| 65 | + // Accepts a string or an array on the wire; the CLI always sends the array. |
| 66 | + flags: { knowledgeBaseIds: { name: 'kb', list: true }, tagFilters: { json: true } }, |
| 67 | + columns: [ |
| 68 | + { header: 'score', path: 'similarity' }, |
| 69 | + { header: 'document', path: 'documentName' }, |
| 70 | + { header: 'chunk', path: 'chunkIndex' }, |
| 71 | + { header: 'content' }, |
| 72 | + ], |
| 73 | + }, |
| 74 | + |
| 75 | + // ─── Friendlier flag names ──────────────────────────────────────────────── |
| 76 | + upsertTableRow: { |
| 77 | + describe: 'Insert a row, or update the one that conflicts on a unique column', |
| 78 | + flags: { |
| 79 | + data: { json: true }, |
| 80 | + conflictTarget: { name: 'on', describe: 'Unique column to resolve the conflict against' }, |
| 81 | + }, |
| 82 | + columns: [{ header: 'id' }, { header: 'operation' }], |
| 83 | + }, |
| 84 | + queryRows: { |
| 85 | + command: 'tables rows query', |
| 86 | + flags: { predicate: { name: 'filter', json: true }, sort: { json: true } }, |
| 87 | + }, |
| 88 | + |
| 89 | + // ─── Output columns for list commands ───────────────────────────────────── |
| 90 | + listTables: { |
| 91 | + columns: [ |
| 92 | + { header: 'id' }, |
| 93 | + { header: 'name' }, |
| 94 | + { header: 'rows', path: 'rowCount' }, |
| 95 | + { header: 'updated', path: 'updatedAt', format: 'timestamp' }, |
| 96 | + ], |
| 97 | + }, |
| 98 | + listWorkflows: { |
| 99 | + columns: [ |
| 100 | + { header: 'id' }, |
| 101 | + { header: 'name' }, |
| 102 | + { header: 'deployed', path: 'isDeployed', format: 'bool' }, |
| 103 | + { header: 'runs', path: 'runCount' }, |
| 104 | + { header: 'last run', path: 'lastRunAt', format: 'timestamp' }, |
| 105 | + ], |
| 106 | + }, |
| 107 | + listFiles: { |
| 108 | + columns: [ |
| 109 | + { header: 'id' }, |
| 110 | + { header: 'name' }, |
| 111 | + { header: 'size', format: 'bytes' }, |
| 112 | + { header: 'type' }, |
| 113 | + { header: 'uploaded', path: 'uploadedAt', format: 'timestamp' }, |
| 114 | + ], |
| 115 | + }, |
| 116 | + listKnowledgeBases: { |
| 117 | + columns: [ |
| 118 | + { header: 'id' }, |
| 119 | + { header: 'name' }, |
| 120 | + { header: 'docs', path: 'docCount' }, |
| 121 | + { header: 'tokens', path: 'tokenCount' }, |
| 122 | + { header: 'model', path: 'embeddingModel' }, |
| 123 | + ], |
| 124 | + }, |
| 125 | + listKnowledgeDocuments: { |
| 126 | + columns: [ |
| 127 | + { header: 'id' }, |
| 128 | + { header: 'filename' }, |
| 129 | + { header: 'size', path: 'fileSize', format: 'bytes' }, |
| 130 | + { header: 'status', path: 'processingStatus' }, |
| 131 | + { header: 'chunks', path: 'chunkCount' }, |
| 132 | + ], |
| 133 | + }, |
| 134 | + listAuditLogs: { |
| 135 | + columns: [ |
| 136 | + { header: 'at', path: 'createdAt', format: 'timestamp' }, |
| 137 | + { header: 'actor', path: 'actorEmail' }, |
| 138 | + { header: 'action' }, |
| 139 | + { header: 'resource', path: 'resourceName' }, |
| 140 | + ], |
| 141 | + }, |
| 142 | + |
| 143 | + // ─── Execution ──────────────────────────────────────────────────────────── |
| 144 | + // The derived names land badly here: `/execute` and `/cancel` are verbs in |
| 145 | + // the path, but neither is in the action list, so POST would derive |
| 146 | + // `workflows execute create` and `workflows cancel create`. |
| 147 | + executeWorkflow: { |
| 148 | + command: 'workflows run', |
| 149 | + describe: 'Run a deployed workflow and wait for the result', |
| 150 | + flags: { |
| 151 | + input: { json: true, describe: 'Trigger input as JSON' }, |
| 152 | + selectedOutputs: { name: 'output', list: true }, |
| 153 | + // SSE, not JSON — the generic client cannot consume it. A `sim workflows |
| 154 | + // run --follow` that renders the stream is a separate, hand-written |
| 155 | + // command; advertising a flag that breaks the response is worse than |
| 156 | + // not offering it yet. |
| 157 | + stream: { omit: true }, |
| 158 | + }, |
| 159 | + }, |
| 160 | + getWorkflowExecution: { |
| 161 | + command: 'workflows executions get', |
| 162 | + describe: 'Show the status of one execution', |
| 163 | + }, |
| 164 | + cancelWorkflowExecution: { |
| 165 | + command: 'workflows executions cancel', |
| 166 | + describe: 'Cancel a running execution', |
| 167 | + // Not `confirm`-gated: cancelling is recoverable (re-run it), and the |
| 168 | + // whole point is to stop something that is already going wrong. |
| 169 | + }, |
| 170 | + |
| 171 | + // ─── Not a terminal-shaped operation ────────────────────────────────────── |
| 172 | + // Multipart upload; `sim files upload <path>` needs its own file-reading |
| 173 | + // command rather than a generated flag surface. |
| 174 | + uploadFile: { hidden: true }, |
| 175 | + uploadKnowledgeDocument: { hidden: true }, |
| 176 | +} |
0 commit comments