@weirgate/cli 0.2.0 → 0.3.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/README.md +13 -0
- package/dist/cli/index.js +16 -5
- package/dist/cli/listing.js +66 -0
- package/dist/mcp/server.js +1 -1
- package/dist/shared/tools.js +6 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,4 +30,17 @@ Provider-key values are entered only through `weirgate provider-keys put|rotate`
|
|
|
30
30
|
local browser page by default, or hidden terminal input with `--stdin`) and never appear
|
|
31
31
|
in output. Exit codes are listed in the guide.
|
|
32
32
|
|
|
33
|
+
`weirgate models list` shows model prices and provider policy (`--upstream`,
|
|
34
|
+
`--modality`), and `weirgate audit list --all` reads the whole audit log (up to 10,000
|
|
35
|
+
events; `--limit` and `--cursor` page by hand).
|
|
36
|
+
|
|
37
|
+
## Changes
|
|
38
|
+
|
|
39
|
+
- **0.3.0**: `weirgate models list` and the MCP tool `weirgate_list_models` (model prices
|
|
40
|
+
and provider policy, with the reason a model isn't allowed); `weirgate audit list`
|
|
41
|
+
pages with `--limit`, `--cursor`, and `--all`.
|
|
42
|
+
- **0.2.0**: CLI and MCP failures use the API's error envelope; `grants create
|
|
43
|
+
--source`; `doctor payments`.
|
|
44
|
+
- **0.1.0**: first release.
|
|
45
|
+
|
|
33
46
|
MIT licensed. Copyright 2026 Astraen Labs LLC.
|
package/dist/cli/index.js
CHANGED
|
@@ -10,7 +10,10 @@ import { AgentApiClient, API_VERSION, DEFAULT_API_URL, pathPart, WeirgateApiErro
|
|
|
10
10
|
import { invokeTool } from "../shared/tools.js";
|
|
11
11
|
import { browserSessionGrant } from "./browser-session-grant.js";
|
|
12
12
|
import { exitCodeFor } from "./exit-codes.js";
|
|
13
|
+
import { AUDIT_ALL_CAP, listAllAuditEvents, modelsTable } from "./listing.js";
|
|
13
14
|
let deferringRequiredFlags = false;
|
|
15
|
+
/** A command-specific `--output table` view; other commands print YAML. */
|
|
16
|
+
let tableView;
|
|
14
17
|
const parsed = parse(process.argv.slice(2));
|
|
15
18
|
try {
|
|
16
19
|
const result = await run(parsed);
|
|
@@ -140,11 +143,13 @@ async function commandToTool(client, noun, verb, flags) {
|
|
|
140
143
|
"proposals:get": ["weirgate_get_proposal", { proposal_id: requiredFlag(flags, "proposal") }],
|
|
141
144
|
"proposals:cancel": ["weirgate_cancel_proposal", { proposal_id: requiredFlag(flags, "proposal") }],
|
|
142
145
|
"proposals:apply": ["weirgate_apply_proposal", { proposal_id: requiredFlag(flags, "proposal"), expected_base_revision: numberFlag(flags, "expected-base-revision"), idempotency_key: requiredFlag(flags, "idempotency-key") }],
|
|
143
|
-
"usage:query": ["weirgate_query_usage", { ...common, since: requiredFlag(flags, "since"), until: requiredFlag(flags, "until"), group_by: stringFlag(flags, "group-by"), limit: numberFlag(flags, "limit") }],
|
|
146
|
+
"usage:query": ["weirgate_query_usage", { ...common, since: requiredFlag(flags, "since"), until: requiredFlag(flags, "until"), group_by: stringFlag(flags, "group-by"), bucket: stringFlag(flags, "bucket"), limit: numberFlag(flags, "limit") }],
|
|
147
|
+
"usage:failures": ["weirgate_list_failures", { ...common, since: stringFlag(flags, "since"), until: stringFlag(flags, "until"), cursor: stringFlag(flags, "cursor"), limit: numberFlag(flags, "limit") }],
|
|
144
148
|
"pricing-insights:get": ["weirgate_get_pricing_insights", { ...common, since: requiredFlag(flags, "since"), until: requiredFlag(flags, "until") }],
|
|
145
149
|
"users:timeline": ["weirgate_get_user_timeline", { ...common, external_id: requiredFlag(flags, "user") }],
|
|
146
150
|
"events:list": ["weirgate_list_events", common],
|
|
147
|
-
"audit:list": ["weirgate_list_audit_events", { ...common, since: stringFlag(flags, "since"), until: stringFlag(flags, "until"), action: stringFlag(flags, "action") }],
|
|
151
|
+
"audit:list": ["weirgate_list_audit_events", { ...common, since: stringFlag(flags, "since"), until: stringFlag(flags, "until"), action: stringFlag(flags, "action"), limit: numberFlag(flags, "limit"), cursor: stringFlag(flags, "cursor") }],
|
|
152
|
+
"models:list": ["weirgate_list_models", { upstream: stringFlag(flags, "upstream"), modality: stringFlag(flags, "modality") }],
|
|
148
153
|
"provider-keys:list": ["weirgate_list_provider_key_slots", common],
|
|
149
154
|
"provider-keys:test": ["weirgate_test_provider_key", { ...common, provider: requiredFlag(flags, "provider") }],
|
|
150
155
|
"grants:create": ["weirgate_grant_allowance", { ...common, external_id: requiredFlag(flags, "user"), units: numberRequired(flags, "units"), source: stringFlag(flags, "source") }],
|
|
@@ -170,6 +175,12 @@ async function commandToTool(client, noun, verb, flags) {
|
|
|
170
175
|
return invokeTool(client, "weirgate_get_proposal", { proposal_id: entry[1].proposal_id });
|
|
171
176
|
return localResult({ dry_run: true, operation: `${noun}:${verb}`, input: redact(entry[1]) });
|
|
172
177
|
}
|
|
178
|
+
if (noun === "models")
|
|
179
|
+
tableView = modelsTable;
|
|
180
|
+
if (noun === "audit" && flags.all) {
|
|
181
|
+
const input = entry[1];
|
|
182
|
+
return listAllAuditEvents(client, { app_id: input.app_id, action: input.action, since: input.since, until: input.until }, { cursor: input.cursor, pageSize: input.limit });
|
|
183
|
+
}
|
|
173
184
|
if (entry[0] === "__auth_presets")
|
|
174
185
|
return client.request("/v1/admin/auth-presets");
|
|
175
186
|
if (entry[0] === "__config_propose")
|
|
@@ -298,7 +309,7 @@ function printSuccess(result, flags) {
|
|
|
298
309
|
if (output === "yaml")
|
|
299
310
|
stdout.write(`${YAML.stringify(envelope)}`);
|
|
300
311
|
else if (output === "table")
|
|
301
|
-
stdout.write(`${human(result.data)}${flags["request-id"] ? `\nrequest_id: ${result.request_id}` : ""}\n`);
|
|
312
|
+
stdout.write(`${(tableView ?? human)(result.data)}${flags["request-id"] ? `\nrequest_id: ${result.request_id}` : ""}\n`);
|
|
302
313
|
else
|
|
303
314
|
stdout.write(`${JSON.stringify(envelope)}\n`);
|
|
304
315
|
}
|
|
@@ -343,10 +354,10 @@ function redact(value) { if (Array.isArray(value))
|
|
|
343
354
|
return value.map(redact); if (!value || typeof value !== "object")
|
|
344
355
|
return value; return Object.fromEntries(Object.entries(value).map(([key, item]) => [/^(key|secret|token|password|credential|authorization)$/i.test(key) ? key : key, /^(key|secret|token|password|credential|authorization)$/i.test(key) ? "[redacted]" : redact(item)])); }
|
|
345
356
|
function help() {
|
|
346
|
-
return `weirgate <noun> <verb> [flags]\n\nAuth: auth login|status|logout, mcp install, init\nApps: apps list|get|propose, config export|validate|propose|apply, auth-presets list\nConfig: features/tiers/rules/overrides/proposals, doctor, sandbox\nOps: usage, pricing-insights, users, user-tiers, events, audit, provider-keys, grants, docs\nOutput: --output json|table|yaml; --json; mutations use --idempotency-key\nAuth login: browser consent by default; --stdin accepts a pre-minted key\nSecrets: provider-keys put|rotate defaults to --browser; --stdin rejects pipes without --allow-pipe\n`;
|
|
357
|
+
return `weirgate <noun> <verb> [flags]\n\nAuth: auth login|status|logout, mcp install, init\nApps: apps list|get|propose, config export|validate|propose|apply, auth-presets list\nConfig: features/tiers/rules/overrides/proposals, doctor, sandbox\nOps: usage, pricing-insights, users, user-tiers, events, audit, provider-keys, grants, docs\nModels: models list [--upstream openrouter|openai|anthropic|google|xai] [--modality chat|embedding|image|audio]\nAudit: audit list [--limit n] [--cursor c] [--all] (--all follows next_cursor, up to ${AUDIT_ALL_CAP} events)\nOutput: --output json|table|yaml; --json; mutations use --idempotency-key\nAuth login: browser consent by default; --stdin accepts a pre-minted key\nSecrets: provider-keys put|rotate defaults to --browser; --stdin rejects pipes without --allow-pipe\n`;
|
|
347
358
|
}
|
|
348
359
|
function completion(shell) {
|
|
349
|
-
const commands = "auth mcp init apps config auth-presets features tiers rules overrides proposals usage pricing-insights users user-tiers events audit provider-keys grants doctor sandbox docs completion";
|
|
360
|
+
const commands = "auth mcp init apps config auth-presets models features tiers rules overrides proposals usage pricing-insights users user-tiers events audit provider-keys grants doctor sandbox docs completion";
|
|
350
361
|
if (shell === "zsh")
|
|
351
362
|
return `#compdef weirgate\n_arguments '1:command:(${commands})'\n`;
|
|
352
363
|
if (shell === "fish")
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { record } from "../shared/api-client.js";
|
|
2
|
+
/** `weirgate audit list --all` stops after this many events; resume with `--cursor <next_cursor>`. */
|
|
3
|
+
export const AUDIT_ALL_CAP = 10_000;
|
|
4
|
+
const AUDIT_MAX_PAGE = 500;
|
|
5
|
+
/**
|
|
6
|
+
* Follows `pagination.next_cursor` from `cursor` (or the newest event) until the log ends or
|
|
7
|
+
* `cap` events are read. The first page asks for `include=total`, so the result says how many
|
|
8
|
+
* events match the filters. A capped result keeps `truncated: true` and the `next_cursor` to resume from.
|
|
9
|
+
*/
|
|
10
|
+
export async function listAllAuditEvents(client, filters, options = {}) {
|
|
11
|
+
const cap = options.cap ?? AUDIT_ALL_CAP;
|
|
12
|
+
const pageSize = Math.min(options.pageSize ?? AUDIT_MAX_PAGE, AUDIT_MAX_PAGE);
|
|
13
|
+
const events = [];
|
|
14
|
+
let cursor = options.cursor;
|
|
15
|
+
let total;
|
|
16
|
+
let pages = 0;
|
|
17
|
+
let last;
|
|
18
|
+
do {
|
|
19
|
+
const limit = Math.min(pageSize, cap - events.length);
|
|
20
|
+
last = await client.request("/v1/admin/audit", {
|
|
21
|
+
query: { ...filters, limit, cursor, ...(pages === 0 ? { include: "total" } : {}) },
|
|
22
|
+
});
|
|
23
|
+
pages += 1;
|
|
24
|
+
const page = record(last.data);
|
|
25
|
+
if (pages === 1)
|
|
26
|
+
total = page.pagination?.total;
|
|
27
|
+
events.push(...(page.data ?? []));
|
|
28
|
+
cursor = page.pagination?.truncated ? page.pagination.next_cursor ?? undefined : undefined;
|
|
29
|
+
} while (cursor && events.length < cap);
|
|
30
|
+
return {
|
|
31
|
+
...last,
|
|
32
|
+
data: {
|
|
33
|
+
data: events,
|
|
34
|
+
pagination: {
|
|
35
|
+
limit: pageSize,
|
|
36
|
+
returned: events.length,
|
|
37
|
+
pages,
|
|
38
|
+
cap,
|
|
39
|
+
truncated: cursor !== undefined,
|
|
40
|
+
next_cursor: cursor ?? null,
|
|
41
|
+
...(total === undefined ? {} : { total }),
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const price = (value) => value === null ? "-" : `$${value}`;
|
|
47
|
+
const policyCell = (entry) => entry.allowed ? (entry.state === "allowed" ? "yes" : `yes (${entry.state})`) : "no";
|
|
48
|
+
/** The `--output table` view of `weirgate models list`: one line per row, prices in USD per 1M tokens. */
|
|
49
|
+
export function modelsTable(data) {
|
|
50
|
+
const catalog = record(data);
|
|
51
|
+
const rows = catalog.data ?? [];
|
|
52
|
+
const header = ["UPSTREAM", "MODEL", "IN/1M", "OUT/1M", "CONTEXT", "DEV KEY", "USER KEY"];
|
|
53
|
+
const lines = rows.map((row) => [
|
|
54
|
+
row.upstream,
|
|
55
|
+
row.model,
|
|
56
|
+
price(row.input_usd_per_million),
|
|
57
|
+
price(row.output_usd_per_million),
|
|
58
|
+
row.context_length === null ? "-" : String(row.context_length),
|
|
59
|
+
policyCell(row.policy.developer),
|
|
60
|
+
policyCell(row.policy.user),
|
|
61
|
+
]);
|
|
62
|
+
const widths = header.map((title, column) => Math.max(title.length, ...lines.map((line) => line[column].length)));
|
|
63
|
+
const format = (line) => line.map((cell, column) => column === line.length - 1 ? cell : cell.padEnd(widths[column])).join(" ");
|
|
64
|
+
const footer = `${rows.length} models · prices as of ${catalog.as_of ?? "unknown"}${catalog.stale ? " (stale)" : ""} · policy revision ${catalog.policy_revision}`;
|
|
65
|
+
return [format(header), ...lines.map(format), "", footer].join("\n");
|
|
66
|
+
}
|
package/dist/mcp/server.js
CHANGED
|
@@ -20,7 +20,7 @@ const rank = { read: 0, propose: 1, apply: 2 };
|
|
|
20
20
|
export function createMcpServer(auth) {
|
|
21
21
|
const server = new Server({ name: "weirgate", version: API_VERSION }, {
|
|
22
22
|
capabilities: { tools: { listChanged: false } },
|
|
23
|
-
instructions: "Operate Weirgate only through the
|
|
23
|
+
instructions: "Operate Weirgate only through the 2026-07-18 public API. Propose before apply. Provider keys are entered outside the model-facing MCP surface.",
|
|
24
24
|
});
|
|
25
25
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
26
26
|
tools: allowedTools({ scope: auth.identity.scope, tool_groups: auth.identity.tool_groups }).map((tool) => ({
|
package/dist/shared/tools.js
CHANGED
|
@@ -16,6 +16,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
16
16
|
{ name: "weirgate_get_app", title: "Get app", description: "Get one visible app configuration.", scope: "read", group: "setup", inputSchema: objectSchema(app, appRequired) },
|
|
17
17
|
{ name: "weirgate_list_features", title: "List features", description: "List configured features for an app.", scope: "read", group: "setup", inputSchema: objectSchema(app, appRequired) },
|
|
18
18
|
{ name: "weirgate_get_feature", title: "Get feature", description: "Get a configured feature.", scope: "read", group: "setup", inputSchema: objectSchema({ ...app, feature_id: str() }, ["app_id", "feature_id"]) },
|
|
19
|
+
{ name: "weirgate_list_models", title: "List models", description: "List models a feature can use, with list prices per million tokens (USD), context length, and whether the provider policy allows each for the developer's key and the user's own key (with a reason when not). Use `upstream` and `model` from a row as the feature's values.", scope: "read", group: "setup", inputSchema: objectSchema({ upstream: { enum: ["openrouter", "openai", "anthropic", "google", "xai"], description: "Provider slot the feature uses" }, modality: { enum: ["chat", "embedding", "image", "audio"] } }) },
|
|
19
20
|
{ name: "weirgate_search_docs", title: "Search docs", description: "Search the authenticated canonical Markdown corpus.", scope: "read", group: "docs", inputSchema: objectSchema({ query: str(), section: str(), limit: integer() }, ["query"]) },
|
|
20
21
|
{ name: "weirgate_get_doc", title: "Get doc", description: "Read one canonical Markdown document.", scope: "read", group: "docs", inputSchema: objectSchema({ page_id: str() }, ["page_id"]) },
|
|
21
22
|
{ name: "weirgate_get_onboarding_state", title: "Get onboarding state", description: "Read durable onboarding readiness evidence.", scope: "read", group: "setup", inputSchema: objectSchema(app, appRequired) },
|
|
@@ -24,7 +25,8 @@ export const TOOL_DEFINITIONS = [
|
|
|
24
25
|
{ name: "weirgate_test_provider_key", title: "Test provider key", description: "Run a non-billable metadata probe for an existing provider slot.", scope: "read", group: "provider_keys", inputSchema: objectSchema({ ...app, provider: str() }, ["app_id", "provider"]) },
|
|
25
26
|
{ name: "weirgate_get_integration_snippet", title: "Get integration snippet", description: "Generate an HTTP/curl integration snippet.", scope: "read", group: "setup", inputSchema: objectSchema({ ...app, mode: { enum: ["http", "curl"] }, feature_id: str() }, appRequired) },
|
|
26
27
|
{ name: "weirgate_run_mock_call", title: "Run mock call", description: "Run a deterministic sandbox fixture; never invokes live inference.", scope: "apply", group: "sandbox", inputSchema: objectSchema({ ...app, fixture: str(), session_name: str(), idempotency_key: str() }, ["app_id", "fixture"]) },
|
|
27
|
-
{ name: "weirgate_query_usage", title: "Query usage", description: "Query windowed usage
|
|
28
|
+
{ name: "weirgate_query_usage", title: "Query usage", description: "Query windowed usage totals, groups, latency, refusals, and an optional day/hour series.", scope: "read", group: "usage", inputSchema: objectSchema({ ...app, since: str(), until: str(), group_by: { enum: ["feature", "user", "model", "funding_rail", "refusal_code"] }, bucket: { enum: ["day", "hour"] }, limit: integer() }, ["app_id", "since", "until"]) },
|
|
29
|
+
{ name: "weirgate_list_failures", title: "List failures", description: "List recent refused and failed metered requests, newest first, with request ids for request traces.", scope: "read", group: "usage", inputSchema: objectSchema({ ...app, since: str(), until: str(), cursor: str(), limit: integer() }, appRequired) },
|
|
28
30
|
{ name: "weirgate_get_pricing_insights", title: "Get pricing insights", description: "Read closed-window pricing evidence.", scope: "read", group: "usage", inputSchema: objectSchema({ ...app, since: str(), until: str() }, ["app_id", "since", "until"]) },
|
|
29
31
|
{ name: "weirgate_get_user_timeline", title: "Get user timeline", description: "Read one user's tenant-scoped operational timeline.", scope: "read", group: "usage", inputSchema: objectSchema({ ...app, external_id: str() }, ["app_id", "external_id"]) },
|
|
30
32
|
{ name: "weirgate_list_events", title: "List events", description: "List webhook delivery events for an app.", scope: "read", group: "webhooks", inputSchema: objectSchema({ ...app, status: str(), cursor: str(), limit: integer() }, appRequired) },
|
|
@@ -106,6 +108,7 @@ export async function invokeTool(client, name, rawInput) {
|
|
|
106
108
|
const r = await client.request("/v1/admin/config");
|
|
107
109
|
return { ...r, data: record(findApp(r.data, String(input.app_id)).features)[String(input.feature_id)] };
|
|
108
110
|
}
|
|
111
|
+
case "weirgate_list_models": return client.request("/v1/admin/provider-policy/models", { query: q(input, ["upstream", "modality"]) });
|
|
109
112
|
case "weirgate_search_docs": return client.request("/v1/admin/docs/search", { query: q(input, ["query", "section", "limit"]) });
|
|
110
113
|
case "weirgate_get_doc": return client.request(`/v1/admin/docs/${pathPart(input.page_id)}`);
|
|
111
114
|
case "weirgate_get_onboarding_state": return client.request(`/v1/admin/apps/${a()}/readiness`);
|
|
@@ -117,7 +120,8 @@ export async function invokeTool(client, name, rawInput) {
|
|
|
117
120
|
const session = await client.request(`/v1/admin/apps/${a()}/sandbox/sessions`, { method: "POST", body: { name: input.session_name ?? "agent mock call" }, idempotencyKey: input.idempotency_key });
|
|
118
121
|
return client.request(`/v1/admin/apps/${a()}/sandbox/sessions/${pathPart(session.data.id)}/runs`, { method: "POST", body: { fixture: input.fixture } });
|
|
119
122
|
}
|
|
120
|
-
case "weirgate_query_usage": return client.request(`/v1/admin/apps/${a()}/usage`, { query: q(input, ["since", "until", "group_by", "limit"]) });
|
|
123
|
+
case "weirgate_query_usage": return client.request(`/v1/admin/apps/${a()}/usage`, { query: q(input, ["since", "until", "group_by", "bucket", "limit"]) });
|
|
124
|
+
case "weirgate_list_failures": return client.request(`/v1/admin/apps/${a()}/failures`, { query: q(input, ["since", "until", "cursor", "limit"]) });
|
|
121
125
|
case "weirgate_get_pricing_insights": return client.request(`/v1/admin/apps/${a()}/pricing-insights`, { query: q(input, ["since", "until"]) });
|
|
122
126
|
case "weirgate_get_user_timeline": return client.request(`/v1/admin/apps/${a()}/users/${pathPart(input.external_id)}`);
|
|
123
127
|
case "weirgate_list_events": return client.request(`/v1/admin/apps/${a()}/webhooks/deliveries`, { query: q(input, ["status", "cursor", "limit"]) });
|