@soat/cli 0.22.1 → 0.23.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.
- package/dist/index.mjs +145 -82
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import { load } from "js-yaml";
|
|
|
13
13
|
import * as os from "node:os";
|
|
14
14
|
|
|
15
15
|
//#region package.json
|
|
16
|
-
var version = "0.
|
|
16
|
+
var version = "0.23.0";
|
|
17
17
|
|
|
18
18
|
//#endregion
|
|
19
19
|
//#region src/cli-wrappers/wrappers/formations.ts
|
|
@@ -745,19 +745,7 @@ var routes = {
|
|
|
745
745
|
"in": "body"
|
|
746
746
|
}, {
|
|
747
747
|
"name": "tool_bindings",
|
|
748
|
-
"description": "Tools to attach, one binding object per tool — the
|
|
749
|
-
"required": false,
|
|
750
|
-
"type": "array",
|
|
751
|
-
"in": "body"
|
|
752
|
-
}, {
|
|
753
|
-
"name": "tool_ids",
|
|
754
|
-
"description": "Deprecated shorthand — each entry becomes a bare `{ \"tool_id\": … }` binding. Use `tool_bindings` instead.",
|
|
755
|
-
"required": false,
|
|
756
|
-
"type": "array",
|
|
757
|
-
"in": "body"
|
|
758
|
-
}, {
|
|
759
|
-
"name": "tools",
|
|
760
|
-
"description": "Deprecated shorthand — each entry becomes a bare `{ \"tool\": … }` binding (an ephemeral definition: no separate Tool resource is created, any `project_id` on an entry is ignored, entries never appear in `GET /tools`, cannot be targeted by `active_tool_ids`/`step_rules`, and cannot be of type `pipeline`). Use `tool_bindings` instead.",
|
|
748
|
+
"description": "Tools to attach, one binding object per tool — the only attachment field. An entry is either a reference (`{ \"tool_id\": … }`) or an inline definition (`{ \"tool\": … }`). See [Tool Bindings](/docs/modules/agents#tool-bindings).",
|
|
761
749
|
"required": false,
|
|
762
750
|
"type": "array",
|
|
763
751
|
"in": "body"
|
|
@@ -909,19 +897,7 @@ var routes = {
|
|
|
909
897
|
"in": "body"
|
|
910
898
|
}, {
|
|
911
899
|
"name": "tool_bindings",
|
|
912
|
-
"description": "Tools attached to the agent — the
|
|
913
|
-
"required": false,
|
|
914
|
-
"type": "array",
|
|
915
|
-
"in": "body"
|
|
916
|
-
}, {
|
|
917
|
-
"name": "tool_ids",
|
|
918
|
-
"description": "Deprecated shorthand — replaces only the reference (`tool_id`) bindings, rewriting them bare. Use `tool_bindings` instead.",
|
|
919
|
-
"required": false,
|
|
920
|
-
"type": "array",
|
|
921
|
-
"in": "body"
|
|
922
|
-
}, {
|
|
923
|
-
"name": "tools",
|
|
924
|
-
"description": "Deprecated shorthand — replaces only the inline (`tool`) bindings (ephemeral definitions: no separate Tool resource is created, any `project_id` on an entry is ignored, entries never appear in `GET /tools`, cannot be targeted by `active_tool_ids`/`step_rules`, and cannot be of type `pipeline`). Set to `null` to clear the inline bindings. Use `tool_bindings` instead.",
|
|
900
|
+
"description": "Tools attached to the agent — the only attachment field. Replaces the whole binding list; set to `null` to clear. See [Tool Bindings](/docs/modules/agents#tool-bindings).",
|
|
925
901
|
"required": false,
|
|
926
902
|
"type": "array",
|
|
927
903
|
"in": "body"
|
|
@@ -1057,19 +1033,7 @@ var routes = {
|
|
|
1057
1033
|
"in": "body"
|
|
1058
1034
|
}, {
|
|
1059
1035
|
"name": "tool_bindings",
|
|
1060
|
-
"description": "Tools attached to the agent — the
|
|
1061
|
-
"required": false,
|
|
1062
|
-
"type": "array",
|
|
1063
|
-
"in": "body"
|
|
1064
|
-
}, {
|
|
1065
|
-
"name": "tool_ids",
|
|
1066
|
-
"description": "Deprecated shorthand — replaces only the reference (`tool_id`) bindings, rewriting them bare. Use `tool_bindings` instead.",
|
|
1067
|
-
"required": false,
|
|
1068
|
-
"type": "array",
|
|
1069
|
-
"in": "body"
|
|
1070
|
-
}, {
|
|
1071
|
-
"name": "tools",
|
|
1072
|
-
"description": "Deprecated shorthand — replaces only the inline (`tool`) bindings (ephemeral definitions: no separate Tool resource is created, any `project_id` on an entry is ignored, entries never appear in `GET /tools`, cannot be targeted by `active_tool_ids`/`step_rules`, and cannot be of type `pipeline`). Set to `null` to clear the inline bindings. Use `tool_bindings` instead.",
|
|
1036
|
+
"description": "Tools attached to the agent — the only attachment field. Replaces the whole binding list; set to `null` to clear. See [Tool Bindings](/docs/modules/agents#tool-bindings).",
|
|
1073
1037
|
"required": false,
|
|
1074
1038
|
"type": "array",
|
|
1075
1039
|
"in": "body"
|
|
@@ -2126,7 +2090,7 @@ var routes = {
|
|
|
2126
2090
|
"type": "string",
|
|
2127
2091
|
"in": "body"
|
|
2128
2092
|
}, {
|
|
2129
|
-
"name": "
|
|
2093
|
+
"name": "instructions",
|
|
2130
2094
|
"description": "Optional system message applied to all completions on this chat",
|
|
2131
2095
|
"required": false,
|
|
2132
2096
|
"type": "string",
|
|
@@ -2171,57 +2135,35 @@ var routes = {
|
|
|
2171
2135
|
"in": "path"
|
|
2172
2136
|
}]
|
|
2173
2137
|
},
|
|
2174
|
-
"create-chat-completion
|
|
2138
|
+
"create-chat-completion": {
|
|
2175
2139
|
serviceClass: "Chats",
|
|
2176
|
-
operationId: "
|
|
2177
|
-
description: "
|
|
2140
|
+
operationId: "createChatCompletion",
|
|
2141
|
+
description: "OpenAI Chat Completions-compatible endpoint. Mirrors OpenAI's `POST /v1/chat/completions` path so an OpenAI SDK can target it by base URL alone. Names exactly one target. With `ai_provider_id` the completion is stateless: the provider's secret is decrypted and the appropriate Vercel AI SDK provider is called, with no server-side model fallback. With `chat_id` the stored chat supplies the provider (or the project's `default_model_route_id`), model and instructions. System content travels only in `instructions` — a `role: \"system\"` entry in `messages` is refused with `400 SYSTEM_MESSAGE_NOT_ALLOWED`. With `chat_id`, a request `instructions` replaces the chat's stored one for this call only; the stored value applies when the request carries none, and the two are never merged. Messages may use `document_id` instead of `content` with either target. Chats hold no message history — send the full `messages` array every time.",
|
|
2178
2142
|
moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/chats",
|
|
2179
2143
|
httpMethod: "post",
|
|
2180
|
-
pathParams: [
|
|
2144
|
+
pathParams: [],
|
|
2181
2145
|
queryParams: [],
|
|
2182
2146
|
flags: [{
|
|
2183
|
-
"name": "
|
|
2184
|
-
"description": "",
|
|
2185
|
-
"required":
|
|
2147
|
+
"name": "ai_provider_id",
|
|
2148
|
+
"description": "Public ID of the AI provider to run the completion against. Mutually exclusive with `chat_id`; exactly one of the two is required.\n",
|
|
2149
|
+
"required": false,
|
|
2186
2150
|
"type": "string",
|
|
2187
|
-
"in": "path"
|
|
2188
|
-
}, {
|
|
2189
|
-
"name": "messages",
|
|
2190
|
-
"description": "",
|
|
2191
|
-
"required": true,
|
|
2192
|
-
"type": "array",
|
|
2193
2151
|
"in": "body"
|
|
2194
2152
|
}, {
|
|
2195
|
-
"name": "
|
|
2196
|
-
"description": "
|
|
2153
|
+
"name": "chat_id",
|
|
2154
|
+
"description": "Public ID of a stored chat supplying the provider, model and instructions. Mutually exclusive with `ai_provider_id`; exactly one of the two is required.\n",
|
|
2197
2155
|
"required": false,
|
|
2198
2156
|
"type": "string",
|
|
2199
2157
|
"in": "body"
|
|
2200
2158
|
}, {
|
|
2201
|
-
"name": "
|
|
2202
|
-
"description": "
|
|
2159
|
+
"name": "model",
|
|
2160
|
+
"description": "Model identifier. Overrides the provider's `default_model`, or the chat's `model`, when specified.\n",
|
|
2203
2161
|
"required": false,
|
|
2204
|
-
"type": "boolean",
|
|
2205
|
-
"in": "body"
|
|
2206
|
-
}]
|
|
2207
|
-
},
|
|
2208
|
-
"create-chat-completion": {
|
|
2209
|
-
serviceClass: "Chats",
|
|
2210
|
-
operationId: "createChatCompletion",
|
|
2211
|
-
description: "OpenAI Chat Completions-compatible endpoint. Mirrors OpenAI's `POST /v1/chat/completions` path so an OpenAI SDK can target it by base URL alone. Resolves the AI provider from `ai_provider_id`, decrypts its secret, and calls the appropriate Vercel AI SDK provider. `ai_provider_id` is required — there is no server-side model fallback.",
|
|
2212
|
-
moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/chats",
|
|
2213
|
-
httpMethod: "post",
|
|
2214
|
-
pathParams: [],
|
|
2215
|
-
queryParams: [],
|
|
2216
|
-
flags: [{
|
|
2217
|
-
"name": "ai_provider_id",
|
|
2218
|
-
"description": "Public ID of the AI provider to use.",
|
|
2219
|
-
"required": true,
|
|
2220
2162
|
"type": "string",
|
|
2221
2163
|
"in": "body"
|
|
2222
2164
|
}, {
|
|
2223
|
-
"name": "
|
|
2224
|
-
"description": "
|
|
2165
|
+
"name": "instructions",
|
|
2166
|
+
"description": "System instructions for this call. Sent to the provider as its `instructions` argument rather than as a message, which is the only place the AI SDK accepts system content (`allowSystemInMessages` defaults to false). This field is the only channel — a `role: \"system\"` entry in `messages` is refused with `400 SYSTEM_MESSAGE_NOT_ALLOWED`. With `chat_id`, this replaces the chat's stored `instructions` for this call only; the stored value applies when the request carries none, and the two are never merged.\n",
|
|
2225
2167
|
"required": false,
|
|
2226
2168
|
"type": "string",
|
|
2227
2169
|
"in": "body"
|
|
@@ -3129,6 +3071,40 @@ var routes = {
|
|
|
3129
3071
|
"in": "body"
|
|
3130
3072
|
}]
|
|
3131
3073
|
},
|
|
3074
|
+
"create-dataset-item-from-generation": {
|
|
3075
|
+
serviceClass: "Evaluations",
|
|
3076
|
+
operationId: "createDatasetItemFromGeneration",
|
|
3077
|
+
description: "Promotes a real, completed generation into a test case: its input messages become the item's `input`, and its own answer becomes `expected_output` unless you supply one. Use it to build an evaluation set out of production traffic rather than hand-authoring fixtures. The item is a **copy**, not a view. It keeps working after the source generation's content is purged, and `source_generation_id` goes null if that generation is deleted — a purge can never quietly stop a suite from being runnable. Requires both `evaluations:CreateDataset` and `generations:GetGeneration`: the call copies content out of a generation, so a principal that may not read that generation may not curate it either. Only a **completed** generation can be promoted (`409 GENERATION_NOT_COMPLETED`), and only while its content is still available: an agent or project running with `trace_content_mode: none` never stored the input, and a purged or expired generation no longer has it (`409 GENERATION_CONTENT_UNAVAILABLE`). Generations that predate input recording answer the same way.",
|
|
3078
|
+
moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/evaluations",
|
|
3079
|
+
httpMethod: "post",
|
|
3080
|
+
pathParams: ["dataset_id"],
|
|
3081
|
+
queryParams: [],
|
|
3082
|
+
flags: [{
|
|
3083
|
+
"name": "dataset_id",
|
|
3084
|
+
"description": "Dataset ID",
|
|
3085
|
+
"required": true,
|
|
3086
|
+
"type": "string",
|
|
3087
|
+
"in": "path"
|
|
3088
|
+
}, {
|
|
3089
|
+
"name": "generation_id",
|
|
3090
|
+
"description": "The completed generation to promote. Must belong to the same project as the dataset.",
|
|
3091
|
+
"required": true,
|
|
3092
|
+
"type": "string",
|
|
3093
|
+
"in": "body"
|
|
3094
|
+
}, {
|
|
3095
|
+
"name": "expected_output",
|
|
3096
|
+
"description": "Reference answer. Omit to use the generation's own answer; pass `null` to store the item with no reference answer.",
|
|
3097
|
+
"required": false,
|
|
3098
|
+
"type": "string",
|
|
3099
|
+
"in": "body"
|
|
3100
|
+
}, {
|
|
3101
|
+
"name": "metadata",
|
|
3102
|
+
"description": "Free-form tags, opaque to the platform",
|
|
3103
|
+
"required": false,
|
|
3104
|
+
"type": "object",
|
|
3105
|
+
"in": "body"
|
|
3106
|
+
}]
|
|
3107
|
+
},
|
|
3132
3108
|
"update-dataset-item": {
|
|
3133
3109
|
serviceClass: "Evaluations",
|
|
3134
3110
|
operationId: "updateDatasetItem",
|
|
@@ -4110,7 +4086,7 @@ var routes = {
|
|
|
4110
4086
|
"delete-formation": {
|
|
4111
4087
|
serviceClass: "Formations",
|
|
4112
4088
|
operationId: "deleteFormation",
|
|
4113
|
-
description: "Deletes the formation stack and all its managed resources in reverse dependency order.",
|
|
4089
|
+
description: "Deletes the formation stack and all its managed resources in reverse dependency order. A resource the platform refuses to delete on its own — most often an agent that has generation or trace history — fails the teardown with `409 FORMATION_DELETE_FAILED`, naming every blocking resource in `error.meta.failures`. Resolve the blockers (for an agent, `DELETE /api/v1/agents/{agent_id}?force=true` also removes its generations and traces, and `deletion_policy: retain` exempts it from teardown entirely) and delete the formation again. A refusal the platform can foresee is found by a pre-flight, before the first delete: nothing is removed, and the formation stays `active` and intact for the retry. An unforeseeable error surfaces mid-teardown instead, where resources deleted before the blocker stay deleted and the formation is left in `delete_failed`. The error message states which happened.",
|
|
4114
4090
|
moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/formations",
|
|
4115
4091
|
httpMethod: "delete",
|
|
4116
4092
|
pathParams: ["formation_id"],
|
|
@@ -5564,7 +5540,7 @@ var routes = {
|
|
|
5564
5540
|
"start-orchestration-run": {
|
|
5565
5541
|
serviceClass: "Orchestrations",
|
|
5566
5542
|
operationId: "startOrchestrationRun",
|
|
5567
|
-
description: "Creates a new run for the orchestration named by orchestration_id. By default the run executes durably in the background: the response returns immediately with status \"queued\" (a worker then claims it and moves it to \"running\") and progress is observed via get-orchestration-run or run lifecycle webhook events (orchestration_runs.started/awaiting_input/succeeded/failed). Delay and poll waits park the run as \"sleeping\" and are woken by a background scheduler, surviving restarts. Pass wait=true to block until the run reaches a terminal or awaiting_input state
|
|
5543
|
+
description: "Creates a new run for the orchestration named by orchestration_id. By default the run executes durably in the background: the response returns immediately with status \"queued\" (a worker then claims it and moves it to \"running\") and progress is observed via get-orchestration-run or run lifecycle webhook events (orchestration_runs.started/awaiting_input/succeeded/failed). Delay and poll waits park the run as \"sleeping\" and are woken by a background scheduler, surviving restarts. Pass wait=true to block until the run reaches a terminal or awaiting_input state.",
|
|
5568
5544
|
moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/orchestrations",
|
|
5569
5545
|
httpMethod: "post",
|
|
5570
5546
|
pathParams: [],
|
|
@@ -7444,11 +7420,11 @@ var routes = {
|
|
|
7444
7420
|
"list-usage-meters": {
|
|
7445
7421
|
serviceClass: "Usage",
|
|
7446
7422
|
operationId: "listUsageMeters",
|
|
7447
|
-
description: "Returns the raw usage-meter rows the caller can access, most recent first, optionally filtered by agent, generation, trace, actor, or
|
|
7423
|
+
description: "Returns the raw usage-meter rows the caller can access, most recent first, optionally filtered by agent, generation, trace, actor, session, or `source`. Each row is the per-generation token usage as reported by the provider, for audit and reconciliation.",
|
|
7448
7424
|
moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/usage",
|
|
7449
7425
|
httpMethod: "get",
|
|
7450
7426
|
pathParams: [],
|
|
7451
|
-
queryParams: ["agent_id", "generation_id", "trace_id", "actor_id", "session_id", "trigger_id", "action_id", "meter_type", "limit", "offset"],
|
|
7427
|
+
queryParams: ["agent_id", "generation_id", "trace_id", "actor_id", "session_id", "trigger_id", "action_id", "meter_type", "source", "limit", "offset"],
|
|
7452
7428
|
flags: [{
|
|
7453
7429
|
"name": "agent_id",
|
|
7454
7430
|
"description": "Filter by agent public ID",
|
|
@@ -7497,6 +7473,12 @@ var routes = {
|
|
|
7497
7473
|
"required": false,
|
|
7498
7474
|
"type": "string",
|
|
7499
7475
|
"in": "query"
|
|
7476
|
+
}, {
|
|
7477
|
+
"name": "source",
|
|
7478
|
+
"description": "Filter by what the spend was incurred for. `eval` is an eval run's item generations and `eval_judge` an `llm_judge` scorer's own completion, so verification spend is `source` in (`eval`, `eval_judge`). Ordinary agent traffic carries no source and is matched by neither.\n",
|
|
7479
|
+
"required": false,
|
|
7480
|
+
"type": "string",
|
|
7481
|
+
"in": "query"
|
|
7500
7482
|
}, {
|
|
7501
7483
|
"name": "limit",
|
|
7502
7484
|
"description": "",
|
|
@@ -7527,7 +7509,7 @@ var routes = {
|
|
|
7527
7509
|
"in": "query"
|
|
7528
7510
|
}, {
|
|
7529
7511
|
"name": "group_by",
|
|
7530
|
-
"description": "Dimension to bucket by. `day` buckets on the event's UTC calendar day; the others bucket on the matching column.\n",
|
|
7512
|
+
"description": "Dimension to bucket by. `day` buckets on the event's UTC calendar day; the others bucket on the matching column. `source` buckets by what the spend was incurred for (`eval`, `eval_judge`), which is how verification spend is priced apart from the traffic serving real users; unlabelled traffic collapses into the single `null` bucket.\n",
|
|
7531
7513
|
"required": true,
|
|
7532
7514
|
"type": "string",
|
|
7533
7515
|
"in": "query"
|
|
@@ -8314,7 +8296,12 @@ var routes = {
|
|
|
8314
8296
|
};
|
|
8315
8297
|
|
|
8316
8298
|
//#endregion
|
|
8317
|
-
//#region src/
|
|
8299
|
+
//#region src/naming.ts
|
|
8300
|
+
/**
|
|
8301
|
+
* Flag-name spellings. The CLI accepts kebab-case (the documented convention),
|
|
8302
|
+
* snake_case (the wire spelling, so a body field can be typed exactly as the
|
|
8303
|
+
* spec names it), and camelCase alike; matching happens on the canonical form.
|
|
8304
|
+
*/
|
|
8318
8305
|
/**
|
|
8319
8306
|
* Normalize kebab-case, snake_case, or camelCase to camelCase for param matching.
|
|
8320
8307
|
* e.g. agent-id → agentId, actor_id → actorId, agentId → agentId
|
|
@@ -8338,6 +8325,73 @@ var kebabToSnake = s => {
|
|
|
8338
8325
|
var toKebab = s => {
|
|
8339
8326
|
return s.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/_/g, "-").toLowerCase();
|
|
8340
8327
|
};
|
|
8328
|
+
|
|
8329
|
+
//#endregion
|
|
8330
|
+
//#region src/validateFlags.ts
|
|
8331
|
+
/** Accepted on any command: Commander globals plus the generic id alias. */
|
|
8332
|
+
var ALWAYS_ALLOWED = /* @__PURE__ */new Set(["profile", "id"]);
|
|
8333
|
+
/**
|
|
8334
|
+
* Every flag name this command accepts, canonicalized. Wrapper-added flags are
|
|
8335
|
+
* absent on purpose — a wrapper deletes the flags it consumed before this runs,
|
|
8336
|
+
* so anything left over really is unrecognized.
|
|
8337
|
+
*/
|
|
8338
|
+
var knownFlagsFor = route => {
|
|
8339
|
+
return new Set([...route.flags.map(f => {
|
|
8340
|
+
return f.name;
|
|
8341
|
+
}), ...route.pathParams, ...route.queryParams].map(toCanonical));
|
|
8342
|
+
};
|
|
8343
|
+
/**
|
|
8344
|
+
* Offer the closest known flag, so a typo is one line away from its fix rather
|
|
8345
|
+
* than a trip to `--help`. Prefix matching in either direction covers the real
|
|
8346
|
+
* cases (`limitt`/`limit`, `agent`/`agent_id`) without a full edit-distance pass.
|
|
8347
|
+
*/
|
|
8348
|
+
var suggestionFor = args => {
|
|
8349
|
+
const target = toCanonical(args.flag).toLowerCase();
|
|
8350
|
+
const near = [...args.known].find(known => {
|
|
8351
|
+
const candidate = known.toLowerCase();
|
|
8352
|
+
return candidate.startsWith(target) || target.startsWith(candidate);
|
|
8353
|
+
});
|
|
8354
|
+
return near ? ` Did you mean --${toKebab(near)}?` : "";
|
|
8355
|
+
};
|
|
8356
|
+
/**
|
|
8357
|
+
* Reject an unrecognized flag **only where the server cannot catch it** — a flag
|
|
8358
|
+
* the CLI would otherwise append to the query string.
|
|
8359
|
+
*
|
|
8360
|
+
* An undeclared query param never reaches a check: the server ignores what it
|
|
8361
|
+
* does not know, so `list-agents --limitt 1` returned every row instead of one.
|
|
8362
|
+
* The filter failed **open**, with exit 0 and no warning, and the caller acted on
|
|
8363
|
+
* a superset it never asked for. The name does not survive the request, so only
|
|
8364
|
+
* the client can catch it.
|
|
8365
|
+
*
|
|
8366
|
+
* An unrecognized flag on a **write** is deliberately still forwarded. The server
|
|
8367
|
+
* already answers `400 VALIDATION_FAILED` naming the field (`strictFields`), and
|
|
8368
|
+
* that check is the authority on what a body may contain — rejecting locally
|
|
8369
|
+
* would front-run it, hide the real error, and make an older CLI refuse a field a
|
|
8370
|
+
* newer server accepts. It would also make the behavior untestable through the
|
|
8371
|
+
* CLI: `tests/smoke-tests.sh` asserts precisely that the server rejects
|
|
8372
|
+
* `update-agent --reasoning` with a 400, which a client-side refusal turns into a
|
|
8373
|
+
* usage error the assertion cannot read.
|
|
8374
|
+
*
|
|
8375
|
+
* Returns the error lines to print; empty when every flag is recognized.
|
|
8376
|
+
*/
|
|
8377
|
+
var findUnknownFlags = args => {
|
|
8378
|
+
if (args.route.httpMethod !== "get") return [];
|
|
8379
|
+
const known = knownFlagsFor(args.route);
|
|
8380
|
+
const unknown = args.flagKeys.filter(flagKey => {
|
|
8381
|
+
if (ALWAYS_ALLOWED.has(flagKey)) return false;
|
|
8382
|
+
return !known.has(toCanonical(flagKey));
|
|
8383
|
+
});
|
|
8384
|
+
if (unknown.length === 0) return [];
|
|
8385
|
+
return [...unknown.map(flag => {
|
|
8386
|
+
return `Unknown flag --${flag} for '${args.commandName}'.${suggestionFor({
|
|
8387
|
+
flag,
|
|
8388
|
+
known
|
|
8389
|
+
})}`;
|
|
8390
|
+
}), `Run "soat ${args.commandName} --help" to see the flags this command accepts.`];
|
|
8391
|
+
};
|
|
8392
|
+
|
|
8393
|
+
//#endregion
|
|
8394
|
+
//#region src/index.ts
|
|
8341
8395
|
/**
|
|
8342
8396
|
* Renders a command's payload for stdout.
|
|
8343
8397
|
*
|
|
@@ -8536,6 +8590,15 @@ program.argument("[command]", "API command in kebab-case (e.g. list-actors)").ar
|
|
|
8536
8590
|
const flagTypeByCanonical = new Map(route.flags.map(f => {
|
|
8537
8591
|
return [toCanonical(f.name), f.type];
|
|
8538
8592
|
}));
|
|
8593
|
+
const unknownFlagErrors = findUnknownFlags({
|
|
8594
|
+
commandName,
|
|
8595
|
+
route,
|
|
8596
|
+
flagKeys: Object.keys(flags)
|
|
8597
|
+
});
|
|
8598
|
+
if (unknownFlagErrors.length > 0) {
|
|
8599
|
+
for (const line of unknownFlagErrors) console.error(line);
|
|
8600
|
+
process.exit(1);
|
|
8601
|
+
}
|
|
8539
8602
|
const pathArgs = {};
|
|
8540
8603
|
const queryArgs = {};
|
|
8541
8604
|
const bodyArgs = {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soat/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@inquirer/input": "^5.1.2",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"@ttoss/logger": "^0.8.19",
|
|
9
9
|
"commander": "^15.0.0",
|
|
10
10
|
"js-yaml": "^5.2.1",
|
|
11
|
-
"@soat/sdk": "0.
|
|
11
|
+
"@soat/sdk": "0.23.0"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@ttoss/config": "^1.37.17",
|