@weirgate/cli 0.1.0 → 0.2.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.
@@ -74,10 +74,10 @@ async function exchangeSessionGrantCode(apiUrl, code, fetchImpl) {
74
74
  const apiVersion = response.headers.get("Weirgate-Api-Version") ?? "unknown";
75
75
  const payload = await response.json().catch(() => ({}));
76
76
  if (apiVersion !== API_VERSION) {
77
- throw new WeirgateApiError({ message: `API version mismatch: expected ${API_VERSION}, received ${apiVersion}`, errorType: "api_version_mismatch", status: 502, requestId, apiVersion, details: payload });
77
+ throw new WeirgateApiError({ message: `API version mismatch: expected ${API_VERSION}, received ${apiVersion}`, errorType: "api_version_mismatch", status: 502, requestId, apiVersion, detail: { expected: API_VERSION, received: apiVersion } });
78
78
  }
79
79
  if (!response.ok || typeof payload.value !== "string") {
80
- throw new WeirgateApiError({ message: payload.error?.message ?? `Weirgate API returned HTTP ${response.status}`, errorType: response.headers.get("X-Weirgate-Error-Type") ?? payload.error?.type ?? "remote_error", status: response.status, requestId, apiVersion, details: payload.error?.details ?? payload });
80
+ throw new WeirgateApiError({ message: payload.error?.message ?? `Weirgate API returned HTTP ${response.status}`, errorType: response.headers.get("X-Weirgate-Error-Type") ?? payload.error?.type ?? "remote_error", status: response.status, requestId, apiVersion, ...(payload.error?.detail ? { detail: payload.error.detail } : {}) });
81
81
  }
82
82
  return payload.value;
83
83
  }
package/dist/cli/index.js CHANGED
@@ -147,14 +147,15 @@ async function commandToTool(client, noun, verb, flags) {
147
147
  "audit:list": ["weirgate_list_audit_events", { ...common, since: stringFlag(flags, "since"), until: stringFlag(flags, "until"), action: stringFlag(flags, "action") }],
148
148
  "provider-keys:list": ["weirgate_list_provider_key_slots", common],
149
149
  "provider-keys:test": ["weirgate_test_provider_key", { ...common, provider: requiredFlag(flags, "provider") }],
150
- "grants:create": ["weirgate_grant_allowance", { ...common, external_id: requiredFlag(flags, "user"), units: numberRequired(flags, "units"), reason: stringFlag(flags, "reason") }],
150
+ "grants:create": ["weirgate_grant_allowance", { ...common, external_id: requiredFlag(flags, "user"), units: numberRequired(flags, "units"), source: stringFlag(flags, "source") }],
151
151
  "grants:reverse": ["weirgate_reverse_grant", { ...common, grant_id: requiredFlag(flags, "grant") }],
152
152
  "user-tiers:assign": ["weirgate_assign_user_tier", { ...common, external_id: requiredFlag(flags, "user"), tier: requiredFlag(flags, "tier"), top_up_now: booleanFlag(flags, "top-up-now") }],
153
153
  "user-tiers:revert": ["weirgate_revert_user_tier", { ...common, external_id: requiredFlag(flags, "user"), top_up_now: booleanFlag(flags, "top-up-now") }],
154
- "doctor:all": ["weirgate_run_config_doctor", { ...common, checks: ["auth", "provider", "webhook"] }],
154
+ "doctor:all": ["weirgate_run_config_doctor", { ...common, checks: ["auth", "provider", "webhook", "payments"] }],
155
155
  "doctor:auth": ["weirgate_run_config_doctor", { ...common, checks: ["auth"] }],
156
156
  "doctor:provider": ["weirgate_run_config_doctor", { ...common, checks: ["provider"] }],
157
157
  "doctor:webhook": ["weirgate_run_config_doctor", { ...common, checks: ["webhook"] }],
158
+ "doctor:payments": ["weirgate_run_config_doctor", { ...common, checks: ["payments"] }],
158
159
  "sandbox:call": ["weirgate_run_mock_call", { ...common, fixture: stringFlag(flags, "fixture") ?? "success", session_name: stringFlag(flags, "session-name") }],
159
160
  "docs:search": ["weirgate_search_docs", { query: requiredFlag(flags, "query"), section: stringFlag(flags, "section"), limit: numberFlag(flags, "limit") }],
160
161
  "docs:get": ["weirgate_get_doc", { page_id: requiredFlag(flags, "page") }],
@@ -303,7 +304,7 @@ function printSuccess(result, flags) {
303
304
  }
304
305
  function printError(error, flags) {
305
306
  const typed = error instanceof WeirgateApiError ? error : new WeirgateApiError({ message: error instanceof Error ? error.message : String(error), errorType: "internal", status: 500, requestId: "local", apiVersion: API_VERSION });
306
- const envelope = { ok: false, error: { type: typed.errorType, message: typed.message, details: typed.details }, request_id: typed.requestId, api_version: typed.apiVersion };
307
+ const envelope = { ok: false, error: { type: typed.errorType, message: typed.message, request_id: typed.requestId, ...(typed.detail ? { detail: typed.detail } : {}) }, api_version: typed.apiVersion };
307
308
  if (flags.json || !process.stderr.isTTY)
308
309
  process.stderr.write(`${JSON.stringify(envelope)}\n`);
309
310
  else
@@ -60,7 +60,7 @@ export function createMcpServer(auth) {
60
60
  }
61
61
  catch (error) {
62
62
  if (error instanceof WeirgateApiError)
63
- return errorResult(error.errorType, error.message, error.requestId, error.details, error.apiVersion);
63
+ return errorResult(error.errorType, error.message, error.requestId, error.detail, error.apiVersion);
64
64
  return errorResult("invalid_request", error instanceof Error ? error.message : String(error), "local");
65
65
  }
66
66
  });
@@ -75,8 +75,9 @@ function removeSecretValues(value) {
75
75
  ? []
76
76
  : [[key, removeSecretValues(item)]]));
77
77
  }
78
- function errorResult(type, message, requestId, details, apiVersion = API_VERSION) {
79
- const body = { error: { type, message, ...(details === undefined ? {} : { details }) }, request_id: requestId, api_version: apiVersion };
78
+ /** Mirrors the HTTP error envelope (`error.type`, `message`, `request_id`, `detail`), plus `api_version`. */
79
+ function errorResult(type, message, requestId, detail, apiVersion = API_VERSION) {
80
+ const body = { error: { type, message, request_id: requestId, ...(detail === undefined ? {} : { detail }) }, api_version: apiVersion };
80
81
  return {
81
82
  isError: true,
82
83
  content: [{ type: "text", text: JSON.stringify(body) }],
@@ -5,7 +5,8 @@ export class WeirgateApiError extends Error {
5
5
  status;
6
6
  requestId;
7
7
  apiVersion;
8
- details;
8
+ /** The API error's `detail` (for example `detail.reason`), as the HTTP envelope carries it. */
9
+ detail;
9
10
  constructor(input) {
10
11
  super(input.message);
11
12
  this.name = "WeirgateApiError";
@@ -13,7 +14,7 @@ export class WeirgateApiError extends Error {
13
14
  this.status = input.status;
14
15
  this.requestId = input.requestId;
15
16
  this.apiVersion = input.apiVersion;
16
- this.details = input.details;
17
+ this.detail = input.detail;
17
18
  }
18
19
  }
19
20
  export class AgentApiClient {
@@ -73,7 +74,7 @@ export class AgentApiClient {
73
74
  status: 502,
74
75
  requestId,
75
76
  apiVersion,
76
- details: payload,
77
+ detail: { expected: API_VERSION, received: apiVersion },
77
78
  });
78
79
  }
79
80
  if (!response.ok) {
@@ -84,7 +85,7 @@ export class AgentApiClient {
84
85
  status: response.status,
85
86
  requestId,
86
87
  apiVersion,
87
- details: body?.error?.details ?? payload,
88
+ ...(body?.error?.detail ? { detail: body.error.detail } : {}),
88
89
  });
89
90
  }
90
91
  return { data: payload, request_id: requestId, api_version: API_VERSION };
@@ -19,7 +19,7 @@ export const TOOL_DEFINITIONS = [
19
19
  { 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
20
  { 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
21
  { name: "weirgate_get_onboarding_state", title: "Get onboarding state", description: "Read durable onboarding readiness evidence.", scope: "read", group: "setup", inputSchema: objectSchema(app, appRequired) },
22
- { name: "weirgate_run_config_doctor", title: "Run config doctor", description: "Run non-billable configuration checks.", scope: "read", group: "setup", inputSchema: objectSchema({ ...app, checks: { type: "array", items: { enum: ["auth", "provider", "webhook"] } } }, appRequired) },
22
+ { name: "weirgate_run_config_doctor", title: "Run config doctor", description: "Run non-billable configuration checks.", scope: "read", group: "setup", inputSchema: objectSchema({ ...app, checks: { type: "array", items: { enum: ["auth", "provider", "webhook", "payments"] } } }, appRequired) },
23
23
  { name: "weirgate_list_provider_key_slots", title: "List provider key slots", description: "List write-only provider slot metadata. No key values are returned.", scope: "read", group: "provider_keys", inputSchema: objectSchema(app) },
24
24
  { 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
25
  { 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) },
@@ -44,7 +44,7 @@ export const TOOL_DEFINITIONS = [
44
44
  { name: "weirgate_preview_rules", title: "Preview rules", description: "Preview rules against recent traffic and bind a content hash.", scope: "propose", group: "rules", inputSchema: objectSchema({ ...app, ruleset: document(), since: str(), until: str() }, ["app_id", "ruleset", "since", "until"]) },
45
45
  { name: "weirgate_propose_rules", title: "Propose rules", description: "Create a preview-hash-bound rules proposal.", scope: "propose", group: "rules", inputSchema: objectSchema({ ...app, ruleset: document(), preview_id: str() }, ["app_id", "ruleset", "preview_id"]) },
46
46
  { name: "weirgate_propose_user_override", title: "Propose user override", description: "Preview and propose a per-user velocity override.", scope: "propose", group: "rules", inputSchema: objectSchema({ ...app, external_id: str(), override: document(), since: str(), until: str() }, ["app_id", "external_id", "override"]) },
47
- { name: "weirgate_grant_allowance", title: "Grant allowance", description: "Grant units idempotently to a user.", scope: "apply", group: "credits", inputSchema: objectSchema({ ...app, external_id: str(), units: integer(), reason: str(), idempotency_key: str() }, ["app_id", "external_id", "units", "idempotency_key"]) },
47
+ { name: "weirgate_grant_allowance", title: "Grant allowance", description: "Grant units idempotently to a user.", scope: "apply", group: "credits", inputSchema: objectSchema({ ...app, external_id: str(), units: { type: "number", exclusiveMinimum: 0 }, source: str(), idempotency_key: str() }, ["app_id", "external_id", "units", "idempotency_key"]) },
48
48
  { name: "weirgate_reverse_grant", title: "Reverse grant", description: "Reverse an allowance grant idempotently.", scope: "apply", group: "credits", inputSchema: objectSchema({ ...app, grant_id: str(), idempotency_key: str() }, ["app_id", "grant_id", "idempotency_key"]) },
49
49
  { name: "weirgate_assign_user_tier", title: "Assign user tier", description: "Schedule a configured user tier for the next monthly grant, with an optional current-period delta top-up.", scope: "apply", group: "plans", inputSchema: objectSchema({ ...app, external_id: str(), tier: str(), top_up_now: { type: "boolean" }, idempotency_key: str() }, ["app_id", "external_id", "tier", "idempotency_key"]) },
50
50
  { name: "weirgate_revert_user_tier", title: "Revert user tier", description: "Schedule a user to return to the app default tier, with an optional current-period delta top-up.", scope: "apply", group: "plans", inputSchema: objectSchema({ ...app, external_id: str(), top_up_now: { type: "boolean" }, idempotency_key: str() }, ["app_id", "external_id", "idempotency_key"]) },
@@ -109,7 +109,7 @@ export async function invokeTool(client, name, rawInput) {
109
109
  case "weirgate_search_docs": return client.request("/v1/admin/docs/search", { query: q(input, ["query", "section", "limit"]) });
110
110
  case "weirgate_get_doc": return client.request(`/v1/admin/docs/${pathPart(input.page_id)}`);
111
111
  case "weirgate_get_onboarding_state": return client.request(`/v1/admin/apps/${a()}/readiness`);
112
- case "weirgate_run_config_doctor": return client.request(`/v1/admin/apps/${a()}/doctor`, { method: "POST", body: { checks: input.checks ?? ["auth", "provider", "webhook"] } });
112
+ case "weirgate_run_config_doctor": return client.request(`/v1/admin/apps/${a()}/doctor`, { method: "POST", body: { checks: input.checks ?? ["auth", "provider", "webhook", "payments"] } });
113
113
  case "weirgate_list_provider_key_slots": return client.request("/v1/admin/provider-keys", { query: q(input, ["app_id"]) });
114
114
  case "weirgate_test_provider_key": return client.request(`/v1/admin/provider-keys/${pathPart(input.provider)}/health`, { method: "POST", query: { app_id: String(input.app_id) } });
115
115
  case "weirgate_get_integration_snippet": return client.request(`/v1/admin/apps/${a()}/integration-snippet`, { query: q(input, ["mode", "feature_id"]) });
@@ -154,7 +154,7 @@ export async function invokeTool(client, name, rawInput) {
154
154
  const preview = await client.request(`/v1/admin/apps/${a()}/rules:preview`, { method: "POST", body: { ruleset, since: input.since, until: input.until } });
155
155
  return client.request(`/v1/admin/apps/${a()}/rules/proposals`, { method: "POST", body: { ruleset, preview_id: preview.data.preview_id } });
156
156
  }
157
- case "weirgate_grant_allowance": return client.request(`/v1/admin/apps/${a()}/users/${pathPart(input.external_id)}/grants`, { method: "POST", idempotencyKey: String(input.idempotency_key), body: { units: input.units, reason: input.reason ?? "agent grant" } });
157
+ case "weirgate_grant_allowance": return client.request(`/v1/admin/apps/${a()}/users/${pathPart(input.external_id)}/grants`, { method: "POST", idempotencyKey: String(input.idempotency_key), body: { units: input.units, ...(input.source === undefined ? {} : { source: input.source }) } });
158
158
  case "weirgate_reverse_grant": return client.request(`/v1/admin/apps/${a()}/grants/${pathPart(input.grant_id)}/reverse`, { method: "POST", idempotencyKey: String(input.idempotency_key) });
159
159
  case "weirgate_assign_user_tier": return client.request(`/v1/admin/apps/${a()}/users/${pathPart(input.external_id)}/tier`, { method: "PUT", idempotencyKey: String(input.idempotency_key), body: { tier: input.tier, top_up_now: input.top_up_now ?? false } });
160
160
  case "weirgate_revert_user_tier": return client.request(`/v1/admin/apps/${a()}/users/${pathPart(input.external_id)}/tier`, { method: "DELETE", idempotencyKey: String(input.idempotency_key), body: { top_up_now: input.top_up_now ?? false } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weirgate/cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Weirgate CLI and local stdio MCP server: scoped, proposal-first management of Weirgate apps.",
5
5
  "license": "MIT",
6
6
  "author": "Astraen Labs LLC",