Skip to content

Commit 6102106

Browse files
committed
fix(cli): close the gaps black-box testing the shipped CLI found
`sim profiles <anything>` still exited 0, so a probe reading the exit code to ask whether a command exists was told yes — the one group the earlier guard missed. The exemption was written for commands that are both a group and a leaf, but only `files restore` takes an operand; `profiles` takes none. Registering its listing as a default subcommand puts it back among the pure dispatchers the existing guard already covers, so the guard itself did not need widening. Three commands refuse a workspace API key and said nothing, while their menu siblings said so — reading as though they accept one. They are hand-written, so they never reached the code that appends the note. That note now comes from a helper taking the operation, so a command names the operation it invokes and the two cannot disagree, and a test fails if a hand-written command ever calls a restricted operation without it. A blank numeric value in a request body still became a real zero, the same coercion already fixed for query strings: the guard keyed off the slot when the distinction is the field's declared type. Twenty-one fields across fifteen operations were affected. An empty body string still clears a description. Blank values for the root endpoint, workspace and profile flags fell back to what was configured instead of being refused, and a whitespace workspace was accepted verbatim. A hand-written profile name carrying padding listed as reachable but resolved to defaults rather than erroring. Two schema descriptions named request fields that no flag spells, and a rejected value was echoed unredacted by four messages while their siblings redacted it. A write now re-emits a section header it was not asked to touch byte for byte. The blank-line normalisation around it is left alone: making the writer position-faithful is a change to its model, not a fix.
1 parent d229a1d commit 6102106

25 files changed

Lines changed: 483 additions & 57 deletions

apps/docs/content/docs/en/cli/credentials.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ Update Credential (personal API key required)
123123
sim credentials create <providerId> [options]
124124
```
125125

126+
Create a service-account credential using its discovered provider schema (personal API key required)
127+
126128
**Arguments**
127129

128130
<CommandTable>
@@ -152,6 +154,8 @@ sim credentials create <providerId> [options]
152154
sim credentials connect <providerId> [options]
153155
```
154156

157+
Create a short-lived link for connecting an OAuth provider (personal API key required)
158+
155159
**Arguments**
156160

157161
<CommandTable>
@@ -178,6 +182,8 @@ sim credentials connect <providerId> [options]
178182
sim credentials reconnect <credentialId>
179183
```
180184

185+
Create a short-lived link for reconnecting an OAuth credential (personal API key required)
186+
181187
**Arguments**
182188

183189
<CommandTable>

apps/docs/content/docs/en/cli/logs.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,10 @@ sim logs list [options]
8585
| `--limit <n>` | No | Maximum items to return (0 for everything). Defaults to `100`. |
8686
| `--status <value>` | No | Comma-separated execution statuses to include, from `pending` \| `running` \| `paused` \| `redacting` \| `completed` \| `failed` \| `cancelled`. An empty entry is rejected. ANDed with `level`, which reports severity rather than lifecycle. |
8787
| `--workflow-name <value>` | No | Case-insensitive substring match against the run's workflow name. Runs whose workflow has been deleted match nothing, because the name is no longer joinable. |
88-
| `--include-job-runs` | No | Whether Chat and Sim-agent job runs join the sequence alongside workflow runs. Job runs report `kind: "job"`, carry no `workflow` summary, and never carry a cost ledger. They are dropped entirely — not partially matched — whenever a filter they cannot answer is set (`workflowIds`, `workflowName`, `folderPaths`, `model`, or `status`), so a filter never means two different things across the union. Accepted only under `sortBy=startedAt`: job runs record cost as a document and no comparable status, so they cannot participate in the other orderings. |
88+
| `--include-job-runs` | No | Whether Chat and Sim-agent job runs join the sequence alongside workflow runs. Job runs report `kind: "job"`, carry no `workflow` summary, and never carry a cost ledger. They are dropped entirely — not partially matched — whenever a filter they cannot answer is set: by workflow, workflow name, folder, model, or status. A filter therefore never means two different things across the union. Accepted only when sorting by `startedAt`: job runs record cost as a document and no comparable status, so they cannot participate in the other orderings. |
8989
| `--no-include-job-runs` | No | Send --include-job-runs as false. |
9090
| `--run-id <value>` | No | Exact run identifier to match. |
91-
| `--sort-by <value>` | No | Field used to sort the result. `durationMs` and `cost` are null until a run settles; those runs order as though the value were below every recorded one, so they trail an ascending page and lead a descending one. Only `startedAt` can order Chat and Sim-agent job runs, so any other value is rejected together with `includeJobRuns=true`. Accepted values: `startedAt`, `durationMs`, `cost`, `status`. |
91+
| `--sort-by <value>` | No | Field used to sort the result. `durationMs` and `cost` are null until a run settles; those runs order as though the value were below every recorded one, so they trail an ascending page and lead a descending one. Only `startedAt` can order Chat and Sim-agent job runs, so any other value is rejected when job runs are included. Accepted values: `startedAt`, `durationMs`, `cost`, `status`. |
9292
| `--sort-order <value>` | No | Sort direction. Accepted values: `asc`, `desc`. |
9393
| `--folder <value...>` | No | Folder path as shown in the app; the leading / is optional (space-separated, or @path / @- with one value per line; @@value for a literal leading @). |
9494

apps/docs/content/docs/en/cli/reference.mdx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ sim credentials update <credentialId> [options]
479479

480480
### sim credentials create
481481

482-
Create a service-account credential using its discovered provider schema
482+
Create a service-account credential using its discovered provider schema (personal API key required)
483483

484484
```bash
485485
sim credentials create <providerId> [options]
@@ -510,7 +510,7 @@ sim credentials create <providerId> [options]
510510

511511
### sim credentials connect
512512

513-
Create a short-lived link for connecting an OAuth provider
513+
Create a short-lived link for connecting an OAuth provider (personal API key required)
514514

515515
```bash
516516
sim credentials connect <providerId> [options]
@@ -538,7 +538,7 @@ sim credentials connect <providerId> [options]
538538

539539
### sim credentials reconnect
540540

541-
Create a short-lived link for reconnecting an OAuth credential
541+
Create a short-lived link for reconnecting an OAuth credential (personal API key required)
542542

543543
```bash
544544
sim credentials reconnect <credentialId>
@@ -2475,10 +2475,10 @@ sim logs list [options]
24752475
| `--limit <n>` | No | Maximum items to return (0 for everything). Defaults to `100`. |
24762476
| `--status <value>` | No | Comma-separated execution statuses to include, from `pending` \| `running` \| `paused` \| `redacting` \| `completed` \| `failed` \| `cancelled`. An empty entry is rejected. ANDed with `level`, which reports severity rather than lifecycle. |
24772477
| `--workflow-name <value>` | No | Case-insensitive substring match against the run's workflow name. Runs whose workflow has been deleted match nothing, because the name is no longer joinable. |
2478-
| `--include-job-runs` | No | Whether Chat and Sim-agent job runs join the sequence alongside workflow runs. Job runs report `kind: "job"`, carry no `workflow` summary, and never carry a cost ledger. They are dropped entirely — not partially matched — whenever a filter they cannot answer is set (`workflowIds`, `workflowName`, `folderPaths`, `model`, or `status`), so a filter never means two different things across the union. Accepted only under `sortBy=startedAt`: job runs record cost as a document and no comparable status, so they cannot participate in the other orderings. |
2478+
| `--include-job-runs` | No | Whether Chat and Sim-agent job runs join the sequence alongside workflow runs. Job runs report `kind: "job"`, carry no `workflow` summary, and never carry a cost ledger. They are dropped entirely — not partially matched — whenever a filter they cannot answer is set: by workflow, workflow name, folder, model, or status. A filter therefore never means two different things across the union. Accepted only when sorting by `startedAt`: job runs record cost as a document and no comparable status, so they cannot participate in the other orderings. |
24792479
| `--no-include-job-runs` | No | Send --include-job-runs as false. |
24802480
| `--run-id <value>` | No | Exact run identifier to match. |
2481-
| `--sort-by <value>` | No | Field used to sort the result. `durationMs` and `cost` are null until a run settles; those runs order as though the value were below every recorded one, so they trail an ascending page and lead a descending one. Only `startedAt` can order Chat and Sim-agent job runs, so any other value is rejected together with `includeJobRuns=true`. Accepted values: `startedAt`, `durationMs`, `cost`, `status`. |
2481+
| `--sort-by <value>` | No | Field used to sort the result. `durationMs` and `cost` are null until a run settles; those runs order as though the value were below every recorded one, so they trail an ascending page and lead a descending one. Only `startedAt` can order Chat and Sim-agent job runs, so any other value is rejected when job runs are included. Accepted values: `startedAt`, `durationMs`, `cost`, `status`. |
24822482
| `--sort-order <value>` | No | Sort direction. Accepted values: `asc`, `desc`. |
24832483
| `--folder <value...>` | No | Folder path as shown in the app; the leading / is optional (space-separated, or @path / @- with one value per line; @@value for a literal leading @). |
24842484

@@ -2743,7 +2743,7 @@ sim secrets list [options]
27432743

27442744
### sim secrets set
27452745

2746-
Create or replace a named secret
2746+
Create or replace a named secret (personal API key required)
27472747

27482748
```bash
27492749
sim secrets set <name> [options]
@@ -5410,7 +5410,7 @@ sim workflows list [options]
54105410

54115411
| Option | Required | Description |
54125412
| --- | --- | --- |
5413-
| `--scope <value>` | No | Which lifecycle set to list: `active` (default) for live workflows, `archived` for workflows a `DELETE` archived. `folderPath` resolves against active folders only, so pairing it with `scope=archived` returns an empty page when the containing folder was archived too. Accepted values: `active`, `archived`. |
5413+
| `--scope <value>` | No | Which lifecycle set to list: `active` (default) for live workflows, `archived` for workflows a `DELETE` archived. The folder filter resolves against active folders only, so pairing it with `archived` returns an empty page when the containing folder was archived too. Accepted values: `active`, `archived`. |
54145414
| `--folder <value>` | No | Folder path as shown in the app; the leading / is optional. |
54155415
| `--deployed-only` | No | Return only workflows with an active deployment when true. |
54165416
| `--no-deployed-only` | No | Send --deployed-only as false. |

apps/docs/content/docs/en/cli/secrets.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ List Secrets (personal API key required)
6666
sim secrets set <name> [options]
6767
```
6868

69+
Create or replace a named secret (personal API key required)
70+
6971
**Arguments**
7072

7173
<CommandTable>

apps/docs/content/docs/en/cli/workflows.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,7 @@ sim workflows list [options]
767767

768768
| Option | Required | Description |
769769
| --- | --- | --- |
770-
| `--scope <value>` | No | Which lifecycle set to list: `active` (default) for live workflows, `archived` for workflows a `DELETE` archived. `folderPath` resolves against active folders only, so pairing it with `scope=archived` returns an empty page when the containing folder was archived too. Accepted values: `active`, `archived`. |
770+
| `--scope <value>` | No | Which lifecycle set to list: `active` (default) for live workflows, `archived` for workflows a `DELETE` archived. The folder filter resolves against active folders only, so pairing it with `archived` returns an empty page when the containing folder was archived too. Accepted values: `active`, `archived`. |
771771
| `--folder <value>` | No | Folder path as shown in the app; the leading / is optional. |
772772
| `--deployed-only` | No | Return only workflows with an active deployment when true. |
773773
| `--no-deployed-only` | No | Send --deployed-only as false. |

apps/docs/openapi-v2-logs.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,9 @@
244244
"name": "includeJobRuns",
245245
"in": "query",
246246
"required": false,
247-
"description": "Whether Chat and Sim-agent job runs join the sequence alongside workflow runs. Job runs report `kind: \"job\"`, carry no `workflow` summary, and never carry a cost ledger. They are dropped entirely — not partially matched — whenever a filter they cannot answer is set (`workflowIds`, `workflowName`, `folderPaths`, `model`, or `status`), so a filter never means two different things across the union. Accepted only under `sortBy=startedAt`: job runs record cost as a document and no comparable status, so they cannot participate in the other orderings.",
247+
"description": "Whether Chat and Sim-agent job runs join the sequence alongside workflow runs. Job runs report `kind: \"job\"`, carry no `workflow` summary, and never carry a cost ledger. They are dropped entirely — not partially matched — whenever a filter they cannot answer is set: by workflow, workflow name, folder, model, or status. A filter therefore never means two different things across the union. Accepted only when sorting by `startedAt`: job runs record cost as a document and no comparable status, so they cannot participate in the other orderings.",
248248
"schema": {
249-
"description": "Whether Chat and Sim-agent job runs join the sequence alongside workflow runs. Job runs report `kind: \"job\"`, carry no `workflow` summary, and never carry a cost ledger. They are dropped entirely — not partially matched — whenever a filter they cannot answer is set (`workflowIds`, `workflowName`, `folderPaths`, `model`, or `status`), so a filter never means two different things across the union. Accepted only under `sortBy=startedAt`: job runs record cost as a document and no comparable status, so they cannot participate in the other orderings.",
249+
"description": "Whether Chat and Sim-agent job runs join the sequence alongside workflow runs. Job runs report `kind: \"job\"`, carry no `workflow` summary, and never carry a cost ledger. They are dropped entirely — not partially matched — whenever a filter they cannot answer is set: by workflow, workflow name, folder, model, or status. A filter therefore never means two different things across the union. Accepted only when sorting by `startedAt`: job runs record cost as a document and no comparable status, so they cannot participate in the other orderings.",
250250
"type": "boolean"
251251
}
252252
},
@@ -267,10 +267,10 @@
267267
"name": "sortBy",
268268
"in": "query",
269269
"required": false,
270-
"description": "Field used to sort the result. `durationMs` and `cost` are null until a run settles; those runs order as though the value were below every recorded one, so they trail an ascending page and lead a descending one. Only `startedAt` can order Chat and Sim-agent job runs, so any other value is rejected together with `includeJobRuns=true`.",
270+
"description": "Field used to sort the result. `durationMs` and `cost` are null until a run settles; those runs order as though the value were below every recorded one, so they trail an ascending page and lead a descending one. Only `startedAt` can order Chat and Sim-agent job runs, so any other value is rejected when job runs are included.",
271271
"schema": {
272272
"default": "startedAt",
273-
"description": "Field used to sort the result. `durationMs` and `cost` are null until a run settles; those runs order as though the value were below every recorded one, so they trail an ascending page and lead a descending one. Only `startedAt` can order Chat and Sim-agent job runs, so any other value is rejected together with `includeJobRuns=true`.",
273+
"description": "Field used to sort the result. `durationMs` and `cost` are null until a run settles; those runs order as though the value were below every recorded one, so they trail an ascending page and lead a descending one. Only `startedAt` can order Chat and Sim-agent job runs, so any other value is rejected when job runs are included.",
274274
"type": "string",
275275
"enum": ["startedAt", "durationMs", "cost", "status"]
276276
}

apps/docs/openapi-v2-workflows.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@
5959
"name": "scope",
6060
"in": "query",
6161
"required": false,
62-
"description": "Which lifecycle set to list: `active` (default) for live workflows, `archived` for workflows a `DELETE` archived. `folderPath` resolves against active folders only, so pairing it with `scope=archived` returns an empty page when the containing folder was archived too.",
62+
"description": "Which lifecycle set to list: `active` (default) for live workflows, `archived` for workflows a `DELETE` archived. The folder filter resolves against active folders only, so pairing it with `archived` returns an empty page when the containing folder was archived too.",
6363
"schema": {
6464
"default": "active",
65-
"description": "Which lifecycle set to list: `active` (default) for live workflows, `archived` for workflows a `DELETE` archived. `folderPath` resolves against active folders only, so pairing it with `scope=archived` returns an empty page when the containing folder was archived too.",
65+
"description": "Which lifecycle set to list: `active` (default) for live workflows, `archived` for workflows a `DELETE` archived. The folder filter resolves against active folders only, so pairing it with `archived` returns an empty page when the containing folder was archived too.",
6666
"type": "string",
6767
"enum": ["active", "archived"]
6868
}

apps/sim/lib/api/contracts/v2/logs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ export const v2ListLogsQuerySchema = v1ListLogsQuerySchema
526526
workflowName: v2WorkflowNameFilterSchema.optional(),
527527
includeJobRuns: booleanQueryFlagSchema
528528
.describe(
529-
'Whether Chat and Sim-agent job runs join the sequence alongside workflow runs. Job runs report `kind: "job"`, carry no `workflow` summary, and never carry a cost ledger. They are dropped entirely — not partially matched — whenever a filter they cannot answer is set (`workflowIds`, `workflowName`, `folderPaths`, `model`, or `status`), so a filter never means two different things across the union. Accepted only under `sortBy=startedAt`: job runs record cost as a document and no comparable status, so they cannot participate in the other orderings.'
529+
'Whether Chat and Sim-agent job runs join the sequence alongside workflow runs. Job runs report `kind: "job"`, carry no `workflow` summary, and never carry a cost ledger. They are dropped entirely — not partially matched — whenever a filter they cannot answer is set: by workflow, workflow name, folder, model, or status. A filter therefore never means two different things across the union. Accepted only when sorting by `startedAt`: job runs record cost as a document and no comparable status, so they cannot participate in the other orderings.'
530530
)
531531
.optional()
532532
.default(false),
@@ -570,7 +570,7 @@ export const v2ListLogsQuerySchema = v1ListLogsQuerySchema
570570
* local to this resource.
571571
*/
572572
sortBy: v2LogSortFieldSchemas.sortBy.describe(
573-
'Field used to sort the result. `durationMs` and `cost` are null until a run settles; those runs order as though the value were below every recorded one, so they trail an ascending page and lead a descending one. Only `startedAt` can order Chat and Sim-agent job runs, so any other value is rejected together with `includeJobRuns=true`.'
573+
'Field used to sort the result. `durationMs` and `cost` are null until a run settles; those runs order as though the value were below every recorded one, so they trail an ascending page and lead a descending one. Only `startedAt` can order Chat and Sim-agent job runs, so any other value is rejected when job runs are included.'
574574
),
575575
folderPaths: z
576576
.string()

apps/sim/lib/api/contracts/v2/workflows.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ export const v2ListWorkflowsQuerySchema = z
158158
scope: v2WorkflowScopeSchema
159159
.default('active')
160160
.describe(
161-
'Which lifecycle set to list: `active` (default) for live workflows, `archived` for workflows a `DELETE` archived. `folderPath` resolves against active folders only, so pairing it with `scope=archived` returns an empty page when the containing folder was archived too.'
161+
'Which lifecycle set to list: `active` (default) for live workflows, `archived` for workflows a `DELETE` archived. The folder filter resolves against active folders only, so pairing it with `archived` returns an empty page when the containing folder was archived too.'
162162
),
163163
folderPath: v2FolderPathInputSchema
164164
.optional()

0 commit comments

Comments
 (0)