Skip to content

Commit c2ccac2

Browse files
fix(cli): read share fields from the v2 share object
The file-share columns pointed at a `sharing` wrapper that v2 does not return. The share travels under `share` on file metadata (null when unshared) and as the unwrapped body on the share endpoints, and its flag is `isActive`, not `enabled`. Every one of those columns was therefore rendering an em-dash on `files describe`, `files share get`, and `files share set`. A missing field path renders blank instead of failing, so nothing caught this. Added a rendering test over both surfaces; it fails if a path stops resolving. `hasPassword` is surfaced on the two share commands while they are being fixed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JNFjchn6dcM7xevh34PKHE
1 parent 52f7d27 commit c2ccac2

2 files changed

Lines changed: 56 additions & 12 deletions

File tree

packages/sim-cli/src/contract/commands.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -469,10 +469,12 @@ export const CLI_CONTRACT: CliContract = {
469469
{ header: 'uploaded by', path: 'uploadedByEmail' },
470470
{ header: 'uploaded', path: 'uploadedAt', format: 'timestamp' },
471471
{ header: 'updated', path: 'updatedAt', format: 'timestamp' },
472-
{ header: 'shared', path: 'sharing.enabled', format: 'bool' },
473-
{ header: 'share URL', path: 'sharing.url' },
474-
{ header: 'share auth', path: 'sharing.authType' },
475-
{ header: 'allowed emails', path: 'sharing.allowedEmails', format: 'count' },
472+
// v2 returns the share under `share` (null when unshared), and its flag
473+
// is `isActive`.
474+
{ header: 'shared', path: 'share.isActive', format: 'bool' },
475+
{ header: 'share URL', path: 'share.url' },
476+
{ header: 'share auth', path: 'share.authType' },
477+
{ header: 'allowed emails', path: 'share.allowedEmails', format: 'count' },
476478
],
477479
},
478480
moveFileItems: {
@@ -500,14 +502,17 @@ export const CLI_CONTRACT: CliContract = {
500502
encoding: { choices: ['utf-8', 'base64'], describe: 'Content encoding' },
501503
},
502504
},
505+
// Both share commands return the share itself as `data`, which the runtime
506+
// unwraps, so these fields sit at the top level rather than under a wrapper.
503507
getFileShare: {
504508
command: 'files share get',
505509
describe: 'Show a file’s share settings',
506510
fields: [
507-
{ header: 'shared', path: 'sharing.enabled', format: 'bool' },
508-
{ header: 'URL', path: 'sharing.url' },
509-
{ header: 'auth', path: 'sharing.authType' },
510-
{ header: 'allowed emails', path: 'sharing.allowedEmails', format: 'count' },
511+
{ header: 'shared', path: 'isActive', format: 'bool' },
512+
{ header: 'URL', path: 'url' },
513+
{ header: 'auth', path: 'authType' },
514+
{ header: 'password set', path: 'hasPassword', format: 'bool' },
515+
{ header: 'allowed emails', path: 'allowedEmails', format: 'count' },
511516
],
512517
},
513518
// v2 folds share and unshare into one PATCH; `--is-active false` disables it,
@@ -519,10 +524,11 @@ export const CLI_CONTRACT: CliContract = {
519524
allowedEmails: { list: true },
520525
},
521526
fields: [
522-
{ header: 'shared', path: 'sharing.enabled', format: 'bool' },
523-
{ header: 'URL', path: 'sharing.url' },
524-
{ header: 'auth', path: 'sharing.authType' },
525-
{ header: 'allowed emails', path: 'sharing.allowedEmails', format: 'count' },
527+
{ header: 'shared', path: 'isActive', format: 'bool' },
528+
{ header: 'URL', path: 'url' },
529+
{ header: 'auth', path: 'authType' },
530+
{ header: 'password set', path: 'hasPassword', format: 'bool' },
531+
{ header: 'allowed emails', path: 'allowedEmails', format: 'count' },
526532
],
527533
},
528534

packages/sim-cli/src/runtime/build.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,44 @@ describe('contract-selected list rendering', () => {
945945
expect(secrets[0]).toContain('STRIPE_API_KEY')
946946
expect(secrets[0]).toContain('workspace')
947947
})
948+
949+
/**
950+
* A field path that misses renders as an em-dash rather than failing, so a
951+
* renamed response key is invisible until someone reads the output. v2 nests
952+
* the share under `share` and calls the flag `isActive`; the CLI briefly read
953+
* a `sharing` wrapper and silently showed nothing for all four columns.
954+
*/
955+
it('reads share fields from the v2 share object, not a sharing wrapper', async () => {
956+
const described = (
957+
await lines(['files', 'describe', 'file_1'], {
958+
id: 'file_1',
959+
name: 'notes.txt',
960+
uploadedByEmail: 'ada@example.com',
961+
share: {
962+
isActive: true,
963+
url: 'https://sim.ai/s/tok_1',
964+
authType: 'email',
965+
hasPassword: false,
966+
allowedEmails: ['ada@example.com'],
967+
},
968+
})
969+
).join('\n')
970+
expect(described).toContain('https://sim.ai/s/tok_1')
971+
expect(described).toContain('email')
972+
expect(described).toContain('ada@example.com')
973+
974+
const share = (
975+
await lines(['files', 'share', 'get', 'file_1'], {
976+
isActive: true,
977+
url: 'https://sim.ai/s/tok_2',
978+
authType: 'sso',
979+
hasPassword: true,
980+
allowedEmails: ['ada@example.com', 'grace@example.com'],
981+
})
982+
).join('\n')
983+
expect(share).toContain('https://sim.ai/s/tok_2')
984+
expect(share).toContain('sso')
985+
})
948986
})
949987

950988
describe('pagination slot', () => {

0 commit comments

Comments
 (0)