Skip to content

Commit d233491

Browse files
feat(cli): add resource mkdir commands
1 parent 03187ab commit d233491

4 files changed

Lines changed: 76 additions & 14 deletions

File tree

‎packages/sim-cli/README.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,16 @@ Each folder-backed resource has the same path commands:
161161

162162
```bash
163163
sim tables folders ls --parent /Reports
164+
sim tables mkdir /Reports/Quarterly
164165
sim tables folders create /Reports/Quarterly
165166
sim tables folders mv /Reports/Quarterly /Archive/Quarterly
166167
sim tables folders delete /Archive/Quarterly --recursive false --yes
167168
```
168169

169-
Replace `tables` with `files`, `workflows`, or `knowledge`. Paths are canonical,
170-
start with `/`, and use `/` for root. A slash that belongs to a folder name is
171-
percent-encoded as `%2F` rather than treated as a separator.
170+
`mkdir` is the concise form of `folders create`. Replace `tables` with `files`,
171+
`workflows`, or `knowledge`. Paths are canonical, start with `/`, and use `/` for
172+
root. A slash that belongs to a folder name is percent-encoded as `%2F` rather
173+
than treated as a separator.
172174

173175
### List inputs
174176

‎packages/sim-cli/src/commands/protocol/index.ts‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Command } from 'commander'
22
import { attachFileDownload } from './files-download.js'
33
import { attachFileUpload } from './files-upload.js'
44
import { attachKnowledgeDocumentUpload } from './knowledge-document-upload.js'
5-
import { attachResourceList } from './resource-ls.js'
5+
import { attachResourceDirectoryCommands } from './resource-directory.js'
66
import { attachTableImport } from './tables-import.js'
77

88
function group(program: Command, name: string): Command {
@@ -18,31 +18,35 @@ export function attachProtocolCommands(program: Command): void {
1818
const files = group(program, 'files')
1919
attachFileUpload(files)
2020
attachFileDownload(files)
21-
attachResourceList(files, {
21+
attachResourceDirectoryCommands(files, {
2222
kind: 'file',
2323
resources: 'listFiles',
2424
folders: 'listFileFolders',
25+
createFolder: 'createFileFolder',
2526
})
2627

2728
const knowledge = group(program, 'knowledge')
2829
attachKnowledgeDocumentUpload(group(knowledge, 'documents'))
29-
attachResourceList(knowledge, {
30+
attachResourceDirectoryCommands(knowledge, {
3031
kind: 'knowledge',
3132
resources: 'listKnowledgeBases',
3233
folders: 'listKnowledgeFolders',
34+
createFolder: 'createKnowledgeFolder',
3335
})
3436

3537
const tables = group(program, 'tables')
3638
attachTableImport(tables)
37-
attachResourceList(tables, {
39+
attachResourceDirectoryCommands(tables, {
3840
kind: 'table',
3941
resources: 'listTables',
4042
folders: 'listTableFolders',
43+
createFolder: 'createTableFolder',
4144
})
4245

43-
attachResourceList(group(program, 'workflows'), {
46+
attachResourceDirectoryCommands(group(program, 'workflows'), {
4447
kind: 'workflow',
4548
resources: 'listWorkflows',
4649
folders: 'listWorkflowFolders',
50+
createFolder: 'createWorkflowFolder',
4751
})
4852
}

packages/sim-cli/src/commands/protocol/resource-ls.test.ts renamed to packages/sim-cli/src/commands/protocol/resource-directory.test.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,12 @@ beforeEach(() => {
3434
output.format = 'json'
3535
})
3636

37-
describe('resource ls', () => {
38-
it('is available for every folder-backed resource', () => {
37+
describe('resource directory', () => {
38+
it('makes ls and mkdir available for every folder-backed resource', () => {
3939
for (const resource of ['files', 'knowledge', 'tables', 'workflows']) {
4040
const group = program().commands.find((command) => command.name() === resource)
4141
expect(group?.commands.some((command) => command.name() === 'ls')).toBe(true)
42+
expect(group?.commands.some((command) => command.name() === 'mkdir')).toBe(true)
4243
}
4344
})
4445

@@ -124,4 +125,26 @@ describe('resource ls', () => {
124125
},
125126
])
126127
})
128+
129+
it('creates a folder through the generated resource operation', async () => {
130+
mockRequest.mockResolvedValue({
131+
data: {
132+
folder: {
133+
name: 'Quarterly',
134+
path: '/Reports/Quarterly',
135+
parentPath: '/Reports',
136+
createdAt: '2026-08-04T00:00:00.000Z',
137+
updatedAt: '2026-08-04T00:00:00.000Z',
138+
},
139+
},
140+
})
141+
vi.spyOn(console, 'log').mockImplementation(() => {})
142+
143+
await program().parseAsync(['node', 'sim', 'table', 'mkdir', '/Reports/Quarterly'])
144+
145+
expect(mockRequest).toHaveBeenCalledWith('/api/v2/tables/folders', {
146+
method: 'POST',
147+
body: { workspaceId: 'ws_local', path: '/Reports/Quarterly' },
148+
})
149+
})
127150
})

packages/sim-cli/src/commands/protocol/resource-ls.ts renamed to packages/sim-cli/src/commands/protocol/resource-directory.ts

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
import { SimApiError, type SimClient, type V2Page } from '../../http/client.js'
1616
import { type Column, printList, text, timestamp } from '../../output/render.js'
1717
import { DEFAULT_LIMIT } from '../../runtime/options.js'
18+
import { renderResult } from '../../runtime/result.js'
1819

1920
type FolderListOperation =
2021
| 'listFileFolders'
@@ -43,14 +44,30 @@ interface DirectoryEntry {
4344
}
4445

4546
type ResourceDirectoryConfig =
46-
| { kind: 'file'; resources: 'listFiles'; folders: 'listFileFolders' }
47+
| {
48+
kind: 'file'
49+
resources: 'listFiles'
50+
folders: 'listFileFolders'
51+
createFolder: 'createFileFolder'
52+
}
4753
| {
4854
kind: 'knowledge'
4955
resources: 'listKnowledgeBases'
5056
folders: 'listKnowledgeFolders'
57+
createFolder: 'createKnowledgeFolder'
58+
}
59+
| {
60+
kind: 'table'
61+
resources: 'listTables'
62+
folders: 'listTableFolders'
63+
createFolder: 'createTableFolder'
64+
}
65+
| {
66+
kind: 'workflow'
67+
resources: 'listWorkflows'
68+
folders: 'listWorkflowFolders'
69+
createFolder: 'createWorkflowFolder'
5170
}
52-
| { kind: 'table'; resources: 'listTables'; folders: 'listTableFolders' }
53-
| { kind: 'workflow'; resources: 'listWorkflows'; folders: 'listWorkflowFolders' }
5471

5572
interface ListOptions {
5673
folder: string
@@ -141,7 +158,10 @@ function entriesFor(
141158
)
142159
}
143160

144-
export function attachResourceList(group: Command, config: ResourceDirectoryConfig): void {
161+
export function attachResourceDirectoryCommands(
162+
group: Command,
163+
config: ResourceDirectoryConfig
164+
): void {
145165
group
146166
.command('ls')
147167
.description(`List ${config.kind} resources and child folders together`)
@@ -168,4 +188,17 @@ export function attachResourceList(group: Command, config: ResourceDirectoryConf
168188
const entries = entriesFor(config, folders, resources)
169189
printList(profile.output, entries.slice(0, limit), COLUMNS)
170190
})
191+
192+
group
193+
.command('mkdir <path>')
194+
.description(`Create a ${config.kind} directory at a canonical path`)
195+
.action(async (path: string, _options: Record<string, never>, command: Command) => {
196+
const { client, profile } = clientFrom(command)
197+
const operation = V2_OPERATIONS[config.createFolder]
198+
const result = await client.request<{ data?: unknown }>(operation.path, {
199+
method: operation.method,
200+
body: { workspaceId: client.requireWorkspace(), path },
201+
})
202+
renderResult(config.createFolder, profile.output, result.data ?? result, {})
203+
})
171204
}

0 commit comments

Comments
 (0)