@solidnumber/cli 1.9.28 → 1.10.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/commands/agent.js +85 -0
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/ai.d.ts.map +1 -1
- package/dist/commands/ai.js +15 -0
- package/dist/commands/ai.js.map +1 -1
- package/dist/commands/doctor.js +94 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/mcp.d.ts +17 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +261 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/schema.d.ts.map +1 -1
- package/dist/commands/schema.js +60 -0
- package/dist/commands/schema.js.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/api-client.d.ts +7 -0
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +76 -9
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/command-kit.d.ts.map +1 -1
- package/dist/lib/command-kit.js +20 -1
- package/dist/lib/command-kit.js.map +1 -1
- package/dist/lib/dry-run.d.ts +11 -0
- package/dist/lib/dry-run.d.ts.map +1 -1
- package/dist/lib/dry-run.js +90 -0
- package/dist/lib/dry-run.js.map +1 -1
- package/dist/lib/error-codes.d.ts +81 -0
- package/dist/lib/error-codes.d.ts.map +1 -0
- package/dist/lib/error-codes.js +166 -0
- package/dist/lib/error-codes.js.map +1 -0
- package/dist/lib/list-envelope.d.ts +67 -0
- package/dist/lib/list-envelope.d.ts.map +1 -0
- package/dist/lib/list-envelope.js +170 -0
- package/dist/lib/list-envelope.js.map +1 -0
- package/dist/lib/mcp-client-config.d.ts +57 -0
- package/dist/lib/mcp-client-config.d.ts.map +1 -0
- package/dist/lib/mcp-client-config.js +166 -0
- package/dist/lib/mcp-client-config.js.map +1 -0
- package/dist/lib/program-registry.d.ts +19 -0
- package/dist/lib/program-registry.d.ts.map +1 -0
- package/dist/lib/program-registry.js +17 -0
- package/dist/lib/program-registry.js.map +1 -0
- package/dist/lib/scope-diagnostic.d.ts +42 -0
- package/dist/lib/scope-diagnostic.d.ts.map +1 -0
- package/dist/lib/scope-diagnostic.js +104 -0
- package/dist/lib/scope-diagnostic.js.map +1 -0
- package/dist/lib/verb-manifest.d.ts +66 -0
- package/dist/lib/verb-manifest.d.ts.map +1 -0
- package/dist/lib/verb-manifest.js +104 -0
- package/dist/lib/verb-manifest.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured error classification (Sprint 1 — T1.1).
|
|
3
|
+
*
|
|
4
|
+
* Takes the raw pieces of an axios failure (status, body, network code)
|
|
5
|
+
* and returns a stable {code, hint, scope, ...} envelope that agents can
|
|
6
|
+
* branch on deterministically instead of regex-matching prose messages.
|
|
7
|
+
*
|
|
8
|
+
* This file is deliberately pure — no axios, no commander, no I/O — so
|
|
9
|
+
* every branch has a unit test in src/__tests__/error-codes.test.ts.
|
|
10
|
+
* Callers:
|
|
11
|
+
* - src/lib/api-client.ts (handleApiError) — enriches ApiError with code/hint
|
|
12
|
+
* - src/lib/command-kit.ts (run catch) — emits JSON envelope under --json
|
|
13
|
+
*
|
|
14
|
+
* The enum is closed so TypeScript can exhaustive-switch on it.
|
|
15
|
+
*/
|
|
16
|
+
/** Fixed vocabulary of error codes the CLI can surface. */
|
|
17
|
+
export type ErrorCode = 'AUTH_REQUIRED' | 'FORBIDDEN' | 'FEATURE_GATED' | 'SCOPE_MISSING' | 'NOT_FOUND' | 'VALIDATION_FAILED' | 'CONFLICT' | 'RATE_LIMITED' | 'SERVER_ERROR' | 'NETWORK_ERROR' | 'TIMEOUT' | 'DRY_RUN_BLOCKED';
|
|
18
|
+
export declare const ERROR_CODES: ErrorCode[];
|
|
19
|
+
/** Extra structured details paired with the code. */
|
|
20
|
+
export interface ClassifiedError {
|
|
21
|
+
code: ErrorCode;
|
|
22
|
+
/** Short actionable next step — e.g. "Run: solid auth login". */
|
|
23
|
+
hint?: string;
|
|
24
|
+
/** Link into docs where relevant. */
|
|
25
|
+
docs_url?: string;
|
|
26
|
+
/** Populated for SCOPE_MISSING. */
|
|
27
|
+
scope?: string;
|
|
28
|
+
/** Populated for FEATURE_GATED. */
|
|
29
|
+
feature?: string;
|
|
30
|
+
/** Populated for FEATURE_GATED — tier the user must upgrade to. */
|
|
31
|
+
upgrade_to?: string;
|
|
32
|
+
/** X-Request-ID echoed back for cross-service correlation. */
|
|
33
|
+
request_id?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface ClassifyInput {
|
|
36
|
+
/** HTTP status; 0 when there was no response (network / timeout). */
|
|
37
|
+
status: number;
|
|
38
|
+
/** Parsed response body (may be anything). */
|
|
39
|
+
data?: unknown;
|
|
40
|
+
/** axios `error.code` — ECONNABORTED, ECONNREFUSED, ETIMEDOUT, etc. */
|
|
41
|
+
networkErrorCode?: string;
|
|
42
|
+
/** X-Request-ID pulled off the response headers, if any. */
|
|
43
|
+
requestId?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Extract a scope name from the backend's prose 403 message.
|
|
47
|
+
* Backend shape today: `detail: "Missing scope: agents:read"`.
|
|
48
|
+
* Returns undefined if the pattern doesn't match.
|
|
49
|
+
*/
|
|
50
|
+
export declare function extractScopeFromDetail(detail: unknown): string | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Normalize varied backend error payloads to a single ErrorCode + metadata.
|
|
53
|
+
* Pure: input → output, no side effects.
|
|
54
|
+
*/
|
|
55
|
+
export declare function classifyError(input: ClassifyInput): ClassifiedError;
|
|
56
|
+
/**
|
|
57
|
+
* Build the JSON envelope emitted under --json when SOLID_JSON_V2=1.
|
|
58
|
+
* Separate from ClassifiedError so the exact wire shape is locked in one
|
|
59
|
+
* place — agent clients depend on this being stable.
|
|
60
|
+
*/
|
|
61
|
+
export interface ErrorEnvelope {
|
|
62
|
+
error: {
|
|
63
|
+
code: ErrorCode;
|
|
64
|
+
status: number;
|
|
65
|
+
message: string;
|
|
66
|
+
scope?: string;
|
|
67
|
+
feature?: string;
|
|
68
|
+
upgrade_to?: string;
|
|
69
|
+
hint?: string;
|
|
70
|
+
docs_url?: string;
|
|
71
|
+
request_id?: string;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export declare function toErrorEnvelope(classified: ClassifiedError, status: number, message: string): ErrorEnvelope;
|
|
75
|
+
/**
|
|
76
|
+
* True when the caller has opted into structured JSON errors (Sprint 1 T1.7
|
|
77
|
+
* two-step rollout). Default behavior stays legacy-prose until a later minor
|
|
78
|
+
* flips this on unconditionally.
|
|
79
|
+
*/
|
|
80
|
+
export declare function jsonErrorEnvelopeEnabled(): boolean;
|
|
81
|
+
//# sourceMappingURL=error-codes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-codes.d.ts","sourceRoot":"","sources":["../../src/lib/error-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,2DAA2D;AAC3D,MAAM,MAAM,SAAS,GACjB,eAAe,GACf,WAAW,GACX,eAAe,GACf,eAAe,GACf,WAAW,GACX,mBAAmB,GACnB,UAAU,GACV,cAAc,GACd,cAAc,GACd,eAAe,GACf,SAAS,GACT,iBAAiB,CAAC;AAEtB,eAAO,MAAM,WAAW,EAAE,SAAS,EAalC,CAAC;AAEF,qDAAqD;AACrD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,CAAC;IAChB,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,uEAAuE;IACvE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAWD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAI1E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,eAAe,CAkGnE;AAoBD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE;QACL,IAAI,EAAE,SAAS,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,wBAAgB,eAAe,CAC7B,UAAU,EAAE,eAAe,EAC3B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,aAAa,CAaf;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAGlD"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Structured error classification (Sprint 1 — T1.1).
|
|
4
|
+
*
|
|
5
|
+
* Takes the raw pieces of an axios failure (status, body, network code)
|
|
6
|
+
* and returns a stable {code, hint, scope, ...} envelope that agents can
|
|
7
|
+
* branch on deterministically instead of regex-matching prose messages.
|
|
8
|
+
*
|
|
9
|
+
* This file is deliberately pure — no axios, no commander, no I/O — so
|
|
10
|
+
* every branch has a unit test in src/__tests__/error-codes.test.ts.
|
|
11
|
+
* Callers:
|
|
12
|
+
* - src/lib/api-client.ts (handleApiError) — enriches ApiError with code/hint
|
|
13
|
+
* - src/lib/command-kit.ts (run catch) — emits JSON envelope under --json
|
|
14
|
+
*
|
|
15
|
+
* The enum is closed so TypeScript can exhaustive-switch on it.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.ERROR_CODES = void 0;
|
|
19
|
+
exports.extractScopeFromDetail = extractScopeFromDetail;
|
|
20
|
+
exports.classifyError = classifyError;
|
|
21
|
+
exports.toErrorEnvelope = toErrorEnvelope;
|
|
22
|
+
exports.jsonErrorEnvelopeEnabled = jsonErrorEnvelopeEnabled;
|
|
23
|
+
exports.ERROR_CODES = [
|
|
24
|
+
'AUTH_REQUIRED',
|
|
25
|
+
'FORBIDDEN',
|
|
26
|
+
'FEATURE_GATED',
|
|
27
|
+
'SCOPE_MISSING',
|
|
28
|
+
'NOT_FOUND',
|
|
29
|
+
'VALIDATION_FAILED',
|
|
30
|
+
'CONFLICT',
|
|
31
|
+
'RATE_LIMITED',
|
|
32
|
+
'SERVER_ERROR',
|
|
33
|
+
'NETWORK_ERROR',
|
|
34
|
+
'TIMEOUT',
|
|
35
|
+
'DRY_RUN_BLOCKED',
|
|
36
|
+
];
|
|
37
|
+
function asRecord(v) {
|
|
38
|
+
return v && typeof v === 'object' ? v : {};
|
|
39
|
+
}
|
|
40
|
+
function pickString(obj, key) {
|
|
41
|
+
const v = obj[key];
|
|
42
|
+
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Extract a scope name from the backend's prose 403 message.
|
|
46
|
+
* Backend shape today: `detail: "Missing scope: agents:read"`.
|
|
47
|
+
* Returns undefined if the pattern doesn't match.
|
|
48
|
+
*/
|
|
49
|
+
function extractScopeFromDetail(detail) {
|
|
50
|
+
if (typeof detail !== 'string')
|
|
51
|
+
return undefined;
|
|
52
|
+
const m = detail.match(/Missing scope[:\s]+([a-z0-9_:\-*]+)/i);
|
|
53
|
+
return m ? m[1] : undefined;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Normalize varied backend error payloads to a single ErrorCode + metadata.
|
|
57
|
+
* Pure: input → output, no side effects.
|
|
58
|
+
*/
|
|
59
|
+
function classifyError(input) {
|
|
60
|
+
const { status, data, networkErrorCode, requestId } = input;
|
|
61
|
+
const body = asRecord(data);
|
|
62
|
+
const serverCode = pickString(body, 'code');
|
|
63
|
+
const serverError = asRecord(body.error);
|
|
64
|
+
const errEnvCode = pickString(serverError, 'code');
|
|
65
|
+
// Prefer the server's own `error.code` when it matches our vocabulary
|
|
66
|
+
// (backend middleware like MCPRateLimitMiddleware uses RATE_LIMITED).
|
|
67
|
+
const preferred = (errEnvCode || serverCode);
|
|
68
|
+
if (preferred && exports.ERROR_CODES.includes(preferred)) {
|
|
69
|
+
return withRequestId({ code: preferred, ...extractEnvelopeExtras(serverError, body) }, requestId);
|
|
70
|
+
}
|
|
71
|
+
// No HTTP response → network layer
|
|
72
|
+
if (!status || status === 0) {
|
|
73
|
+
if (networkErrorCode === 'ECONNABORTED' || networkErrorCode === 'ETIMEDOUT') {
|
|
74
|
+
return withRequestId({ code: 'TIMEOUT', hint: 'Try --timeout=60, or run: solid health' }, requestId);
|
|
75
|
+
}
|
|
76
|
+
return withRequestId({ code: 'NETWORK_ERROR', hint: 'Check network, or run: solid health' }, requestId);
|
|
77
|
+
}
|
|
78
|
+
switch (true) {
|
|
79
|
+
case status === 401:
|
|
80
|
+
return withRequestId({ code: 'AUTH_REQUIRED', hint: 'Run: solid auth login (or set SOLID_TOKEN)' }, requestId);
|
|
81
|
+
case status === 403: {
|
|
82
|
+
// FEATURE_GATED signal comes as `data.code === 'FEATURE_GATED'` at the
|
|
83
|
+
// top level today.
|
|
84
|
+
if (serverCode === 'FEATURE_GATED') {
|
|
85
|
+
return withRequestId({
|
|
86
|
+
code: 'FEATURE_GATED',
|
|
87
|
+
feature: pickString(body, 'feature'),
|
|
88
|
+
upgrade_to: pickString(body, 'upgrade_to'),
|
|
89
|
+
hint: 'Run: solid whoami --features · Upgrade: solid upgrade',
|
|
90
|
+
}, requestId);
|
|
91
|
+
}
|
|
92
|
+
// Scope-missing: extract from prose `detail: "Missing scope: X"`.
|
|
93
|
+
const detailStr = pickString(body, 'detail') ?? pickString(body, 'message');
|
|
94
|
+
const scope = extractScopeFromDetail(detailStr);
|
|
95
|
+
if (scope) {
|
|
96
|
+
return withRequestId({
|
|
97
|
+
code: 'SCOPE_MISSING',
|
|
98
|
+
scope,
|
|
99
|
+
hint: `Rotate your key with scope ${scope}: solid keys rotate --add-scope ${scope}`,
|
|
100
|
+
}, requestId);
|
|
101
|
+
}
|
|
102
|
+
return withRequestId({
|
|
103
|
+
code: 'FORBIDDEN',
|
|
104
|
+
hint: 'Check your tier: solid whoami --features',
|
|
105
|
+
}, requestId);
|
|
106
|
+
}
|
|
107
|
+
case status === 404:
|
|
108
|
+
return withRequestId({ code: 'NOT_FOUND' }, requestId);
|
|
109
|
+
case status === 409:
|
|
110
|
+
return withRequestId({ code: 'CONFLICT' }, requestId);
|
|
111
|
+
case status === 422:
|
|
112
|
+
return withRequestId({ code: 'VALIDATION_FAILED', hint: 'Run with --help to see required flags' }, requestId);
|
|
113
|
+
case status === 429:
|
|
114
|
+
return withRequestId({ code: 'RATE_LIMITED', hint: 'Slow down or run with --timeout=60' }, requestId);
|
|
115
|
+
case status >= 500 && status < 600:
|
|
116
|
+
return withRequestId({ code: 'SERVER_ERROR', hint: 'Try again, or run: solid health' }, requestId);
|
|
117
|
+
default:
|
|
118
|
+
return withRequestId({ code: 'SERVER_ERROR' }, requestId);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function extractEnvelopeExtras(serverError, body) {
|
|
122
|
+
const out = {};
|
|
123
|
+
const scope = pickString(serverError, 'scope') ?? pickString(body, 'scope');
|
|
124
|
+
if (scope)
|
|
125
|
+
out.scope = scope;
|
|
126
|
+
const feature = pickString(serverError, 'feature') ?? pickString(body, 'feature');
|
|
127
|
+
if (feature)
|
|
128
|
+
out.feature = feature;
|
|
129
|
+
const upgrade = pickString(serverError, 'upgrade_to') ?? pickString(body, 'upgrade_to');
|
|
130
|
+
if (upgrade)
|
|
131
|
+
out.upgrade_to = upgrade;
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
function withRequestId(c, requestId) {
|
|
135
|
+
return requestId ? { ...c, request_id: requestId } : c;
|
|
136
|
+
}
|
|
137
|
+
function toErrorEnvelope(classified, status, message) {
|
|
138
|
+
const envelope = {
|
|
139
|
+
code: classified.code,
|
|
140
|
+
status: Number(status) || 0,
|
|
141
|
+
message,
|
|
142
|
+
};
|
|
143
|
+
if (classified.scope)
|
|
144
|
+
envelope.scope = classified.scope;
|
|
145
|
+
if (classified.feature)
|
|
146
|
+
envelope.feature = classified.feature;
|
|
147
|
+
if (classified.upgrade_to)
|
|
148
|
+
envelope.upgrade_to = classified.upgrade_to;
|
|
149
|
+
if (classified.hint)
|
|
150
|
+
envelope.hint = classified.hint;
|
|
151
|
+
if (classified.docs_url)
|
|
152
|
+
envelope.docs_url = classified.docs_url;
|
|
153
|
+
if (classified.request_id)
|
|
154
|
+
envelope.request_id = classified.request_id;
|
|
155
|
+
return { error: envelope };
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* True when the caller has opted into structured JSON errors (Sprint 1 T1.7
|
|
159
|
+
* two-step rollout). Default behavior stays legacy-prose until a later minor
|
|
160
|
+
* flips this on unconditionally.
|
|
161
|
+
*/
|
|
162
|
+
function jsonErrorEnvelopeEnabled() {
|
|
163
|
+
const v = process.env.SOLID_JSON_V2;
|
|
164
|
+
return typeof v === 'string' && /^(1|true|yes|on)$/i.test(v);
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=error-codes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-codes.js","sourceRoot":"","sources":["../../src/lib/error-codes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List-envelope normalization (Sprint 1 T1.4).
|
|
3
|
+
*
|
|
4
|
+
* Backend list endpoints return an inconsistent bag of keys:
|
|
5
|
+
* { pages: [...], total: N }
|
|
6
|
+
* { results: [...] }
|
|
7
|
+
* { logs: [...], has_more: true }
|
|
8
|
+
* { agents: [...] }
|
|
9
|
+
* { api_keys: [...] }
|
|
10
|
+
* { items: [...] }
|
|
11
|
+
* ...
|
|
12
|
+
*
|
|
13
|
+
* That's fine for humans but forces agents to write `d.pages || d.items
|
|
14
|
+
* || d.results || d.logs || ...` fallbacks before they can loop. This
|
|
15
|
+
* module adds a stable `.items` alias + `total / page / has_more`
|
|
16
|
+
* siblings on every response whose body looks like a list envelope.
|
|
17
|
+
* Original keys are preserved so existing callers never break.
|
|
18
|
+
*
|
|
19
|
+
* Pure — no HTTP, no axios. Wired into the response interceptor in
|
|
20
|
+
* api-client.ts; unit-tested with synthetic inputs.
|
|
21
|
+
*
|
|
22
|
+
* Opt-out: `SOLID_LEGACY_LIST_SHAPES=1` disables normalization for one
|
|
23
|
+
* minor release while consumers migrate (per T1.7 two-step rollout).
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Keys backend responses use to expose a list of rows, in preference
|
|
27
|
+
* order. The FIRST key found on the response body whose value is an
|
|
28
|
+
* array is promoted to `.items`. Order matters: when multiple keys
|
|
29
|
+
* coexist (rare), the earlier one wins.
|
|
30
|
+
*/
|
|
31
|
+
export declare const KNOWN_LIST_KEYS: readonly string[];
|
|
32
|
+
export interface NormalizedEnvelope {
|
|
33
|
+
items: unknown[];
|
|
34
|
+
total: number | null;
|
|
35
|
+
page: number | string | null;
|
|
36
|
+
has_more: boolean | null;
|
|
37
|
+
/** Which source key the alias came from ("items" when already canonical). */
|
|
38
|
+
_source_key: string | null;
|
|
39
|
+
}
|
|
40
|
+
/** Truthy values for the SOLID_LEGACY_LIST_SHAPES opt-out. */
|
|
41
|
+
export declare function legacyListShapesEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Detect which known list key (if any) holds the array payload.
|
|
44
|
+
* Returns null when the body is not shaped like a list response.
|
|
45
|
+
* Pure.
|
|
46
|
+
*/
|
|
47
|
+
export declare function detectListKey(body: unknown, knownKeys?: readonly string[]): string | null;
|
|
48
|
+
/**
|
|
49
|
+
* Produce a canonical {items, total, page, has_more} view of a list
|
|
50
|
+
* response. Returns null when the body isn't a list envelope, so callers
|
|
51
|
+
* can short-circuit without mutating.
|
|
52
|
+
*/
|
|
53
|
+
export declare function normalizeListEnvelope(body: unknown): NormalizedEnvelope | null;
|
|
54
|
+
/**
|
|
55
|
+
* Apply the normalization in-place on a response body, adding the
|
|
56
|
+
* aliased keys without removing existing ones. Returns the body back
|
|
57
|
+
* for easy chaining in the axios response interceptor.
|
|
58
|
+
*
|
|
59
|
+
* No-op when:
|
|
60
|
+
* - body is not a list envelope
|
|
61
|
+
* - body already has `items` (then we just ensure `total` is present)
|
|
62
|
+
* - SOLID_LEGACY_LIST_SHAPES is truthy
|
|
63
|
+
*
|
|
64
|
+
* Pure wrt env: caller can pass its own env map for tests.
|
|
65
|
+
*/
|
|
66
|
+
export declare function applyListEnvelope<T>(body: T, env?: NodeJS.ProcessEnv): T;
|
|
67
|
+
//# sourceMappingURL=list-envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-envelope.d.ts","sourceRoot":"","sources":["../../src/lib/list-envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EA4B5C,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,8DAA8D;AAC9D,wBAAgB,uBAAuB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAGxE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,OAAO,EACb,SAAS,GAAE,SAAS,MAAM,EAAoB,GAC7C,MAAM,GAAG,IAAI,CAOf;AAsBD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,kBAAkB,GAAG,IAAI,CAuB9E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,IAAI,EAAE,CAAC,EACP,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,GACtB,CAAC,CAoBH"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* List-envelope normalization (Sprint 1 T1.4).
|
|
4
|
+
*
|
|
5
|
+
* Backend list endpoints return an inconsistent bag of keys:
|
|
6
|
+
* { pages: [...], total: N }
|
|
7
|
+
* { results: [...] }
|
|
8
|
+
* { logs: [...], has_more: true }
|
|
9
|
+
* { agents: [...] }
|
|
10
|
+
* { api_keys: [...] }
|
|
11
|
+
* { items: [...] }
|
|
12
|
+
* ...
|
|
13
|
+
*
|
|
14
|
+
* That's fine for humans but forces agents to write `d.pages || d.items
|
|
15
|
+
* || d.results || d.logs || ...` fallbacks before they can loop. This
|
|
16
|
+
* module adds a stable `.items` alias + `total / page / has_more`
|
|
17
|
+
* siblings on every response whose body looks like a list envelope.
|
|
18
|
+
* Original keys are preserved so existing callers never break.
|
|
19
|
+
*
|
|
20
|
+
* Pure — no HTTP, no axios. Wired into the response interceptor in
|
|
21
|
+
* api-client.ts; unit-tested with synthetic inputs.
|
|
22
|
+
*
|
|
23
|
+
* Opt-out: `SOLID_LEGACY_LIST_SHAPES=1` disables normalization for one
|
|
24
|
+
* minor release while consumers migrate (per T1.7 two-step rollout).
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.KNOWN_LIST_KEYS = void 0;
|
|
28
|
+
exports.legacyListShapesEnabled = legacyListShapesEnabled;
|
|
29
|
+
exports.detectListKey = detectListKey;
|
|
30
|
+
exports.normalizeListEnvelope = normalizeListEnvelope;
|
|
31
|
+
exports.applyListEnvelope = applyListEnvelope;
|
|
32
|
+
/**
|
|
33
|
+
* Keys backend responses use to expose a list of rows, in preference
|
|
34
|
+
* order. The FIRST key found on the response body whose value is an
|
|
35
|
+
* array is promoted to `.items`. Order matters: when multiple keys
|
|
36
|
+
* coexist (rare), the earlier one wins.
|
|
37
|
+
*/
|
|
38
|
+
exports.KNOWN_LIST_KEYS = [
|
|
39
|
+
// Already canonical — nothing to alias.
|
|
40
|
+
'items',
|
|
41
|
+
// CMS / CRM / commerce
|
|
42
|
+
'pages',
|
|
43
|
+
'results',
|
|
44
|
+
'leads',
|
|
45
|
+
'agents',
|
|
46
|
+
'templates',
|
|
47
|
+
'companies',
|
|
48
|
+
'sites',
|
|
49
|
+
'api_keys',
|
|
50
|
+
'logs',
|
|
51
|
+
'rows',
|
|
52
|
+
'records',
|
|
53
|
+
'entries',
|
|
54
|
+
'products',
|
|
55
|
+
'services',
|
|
56
|
+
'contacts',
|
|
57
|
+
'customers',
|
|
58
|
+
'orders',
|
|
59
|
+
'invoices',
|
|
60
|
+
'transactions',
|
|
61
|
+
'webhooks',
|
|
62
|
+
'chains',
|
|
63
|
+
'flows',
|
|
64
|
+
'modules',
|
|
65
|
+
'domains',
|
|
66
|
+
];
|
|
67
|
+
/** Truthy values for the SOLID_LEGACY_LIST_SHAPES opt-out. */
|
|
68
|
+
function legacyListShapesEnabled(env) {
|
|
69
|
+
const v = (env ?? process.env).SOLID_LEGACY_LIST_SHAPES;
|
|
70
|
+
return typeof v === 'string' && /^(1|true|yes|on)$/i.test(v);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Detect which known list key (if any) holds the array payload.
|
|
74
|
+
* Returns null when the body is not shaped like a list response.
|
|
75
|
+
* Pure.
|
|
76
|
+
*/
|
|
77
|
+
function detectListKey(body, knownKeys = exports.KNOWN_LIST_KEYS) {
|
|
78
|
+
if (!body || typeof body !== 'object' || Array.isArray(body))
|
|
79
|
+
return null;
|
|
80
|
+
const record = body;
|
|
81
|
+
for (const k of knownKeys) {
|
|
82
|
+
if (Array.isArray(record[k]))
|
|
83
|
+
return k;
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
function safeNumber(v) {
|
|
88
|
+
if (typeof v === 'number' && Number.isFinite(v))
|
|
89
|
+
return v;
|
|
90
|
+
if (typeof v === 'string' && v.trim() !== '' && !Number.isNaN(Number(v))) {
|
|
91
|
+
return Number(v);
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
function safePage(v) {
|
|
96
|
+
if (v == null)
|
|
97
|
+
return null;
|
|
98
|
+
if (typeof v === 'number' && Number.isFinite(v))
|
|
99
|
+
return v;
|
|
100
|
+
if (typeof v === 'string' && v.trim() !== '')
|
|
101
|
+
return v;
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
function safeBool(v) {
|
|
105
|
+
if (typeof v === 'boolean')
|
|
106
|
+
return v;
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Produce a canonical {items, total, page, has_more} view of a list
|
|
111
|
+
* response. Returns null when the body isn't a list envelope, so callers
|
|
112
|
+
* can short-circuit without mutating.
|
|
113
|
+
*/
|
|
114
|
+
function normalizeListEnvelope(body) {
|
|
115
|
+
const key = detectListKey(body);
|
|
116
|
+
if (!key)
|
|
117
|
+
return null;
|
|
118
|
+
const record = body;
|
|
119
|
+
const items = record[key] ?? [];
|
|
120
|
+
const total = safeNumber(record.total) ??
|
|
121
|
+
safeNumber(record.count) ??
|
|
122
|
+
items.length;
|
|
123
|
+
const page = safePage(record.page) ??
|
|
124
|
+
safePage(record.cursor) ??
|
|
125
|
+
safePage(record.next_cursor) ??
|
|
126
|
+
null;
|
|
127
|
+
const has_more = safeBool(record.has_more) ?? safeBool(record.hasMore) ?? null;
|
|
128
|
+
return {
|
|
129
|
+
items,
|
|
130
|
+
total,
|
|
131
|
+
page,
|
|
132
|
+
has_more,
|
|
133
|
+
_source_key: key,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Apply the normalization in-place on a response body, adding the
|
|
138
|
+
* aliased keys without removing existing ones. Returns the body back
|
|
139
|
+
* for easy chaining in the axios response interceptor.
|
|
140
|
+
*
|
|
141
|
+
* No-op when:
|
|
142
|
+
* - body is not a list envelope
|
|
143
|
+
* - body already has `items` (then we just ensure `total` is present)
|
|
144
|
+
* - SOLID_LEGACY_LIST_SHAPES is truthy
|
|
145
|
+
*
|
|
146
|
+
* Pure wrt env: caller can pass its own env map for tests.
|
|
147
|
+
*/
|
|
148
|
+
function applyListEnvelope(body, env) {
|
|
149
|
+
if (legacyListShapesEnabled(env))
|
|
150
|
+
return body;
|
|
151
|
+
const normalized = normalizeListEnvelope(body);
|
|
152
|
+
if (!normalized)
|
|
153
|
+
return body;
|
|
154
|
+
const record = body;
|
|
155
|
+
// Only fill in what's missing; never clobber a caller-supplied field.
|
|
156
|
+
if (!('items' in record) || record.items === undefined) {
|
|
157
|
+
record.items = normalized.items;
|
|
158
|
+
}
|
|
159
|
+
if (!('total' in record) || record.total === undefined || record.total === null) {
|
|
160
|
+
record.total = normalized.total;
|
|
161
|
+
}
|
|
162
|
+
if (!('page' in record) || record.page === undefined) {
|
|
163
|
+
record.page = normalized.page;
|
|
164
|
+
}
|
|
165
|
+
if (!('has_more' in record) || record.has_more === undefined) {
|
|
166
|
+
record.has_more = normalized.has_more;
|
|
167
|
+
}
|
|
168
|
+
return body;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=list-envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-envelope.js","sourceRoot":"","sources":["../../src/lib/list-envelope.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export type McpClient = 'claude' | 'cursor' | 'windsurf';
|
|
2
|
+
export declare const SUPPORTED_CLIENTS: McpClient[];
|
|
3
|
+
/** Returns true if the string is a known supported client. */
|
|
4
|
+
export declare function isSupportedClient(value: string | undefined | null): value is McpClient;
|
|
5
|
+
export interface ServerEntry {
|
|
6
|
+
command: string;
|
|
7
|
+
args: string[];
|
|
8
|
+
env?: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
export interface McpConfigFile {
|
|
11
|
+
mcpServers?: Record<string, ServerEntry>;
|
|
12
|
+
[k: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Per-OS default path for each supported client. Returns the path
|
|
16
|
+
* relative to `homeDir` so callers can pass their own for testing.
|
|
17
|
+
*/
|
|
18
|
+
export declare function configPathForClient(client: McpClient, opts?: {
|
|
19
|
+
platform?: NodeJS.Platform;
|
|
20
|
+
homeDir?: string;
|
|
21
|
+
}): string;
|
|
22
|
+
export interface BuildEntryInput {
|
|
23
|
+
/** API key or token the MCP server will use to call the backend. */
|
|
24
|
+
apiKey?: string;
|
|
25
|
+
/** Base URL for the backend. Defaults to api.solidnumber.com. */
|
|
26
|
+
apiUrl?: string;
|
|
27
|
+
/** Npm package to invoke via npx. Defaults to @solidnumber/mcp. */
|
|
28
|
+
packageName?: string;
|
|
29
|
+
/** Optional extra env vars (merged in). */
|
|
30
|
+
extraEnv?: Record<string, string>;
|
|
31
|
+
/** Company-id pin (adds X-Company-Id via SOLID_COMPANY_ID env). */
|
|
32
|
+
companyId?: number | string;
|
|
33
|
+
}
|
|
34
|
+
/** Default package that ships the stdio MCP server. */
|
|
35
|
+
export declare const DEFAULT_MCP_PACKAGE = "@solidnumber/mcp";
|
|
36
|
+
/**
|
|
37
|
+
* Build the `mcpServers.solid` entry. Pure — no I/O, no env reads.
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildServerEntry(input?: BuildEntryInput): ServerEntry;
|
|
40
|
+
/**
|
|
41
|
+
* Merge a new `solid` server entry into an existing config file.
|
|
42
|
+
* Preserves any other mcpServers keys and any top-level keys we don't
|
|
43
|
+
* recognize. Returns a NEW object — input is not mutated.
|
|
44
|
+
*/
|
|
45
|
+
export declare function mergeIntoConfig(existing: McpConfigFile | null | undefined, entry: ServerEntry, serverKey?: string): McpConfigFile;
|
|
46
|
+
/**
|
|
47
|
+
* Remove the `solid` entry from a config, preserving other keys.
|
|
48
|
+
* Returns the NEW config (unmutated input). When only `solid` existed
|
|
49
|
+
* in mcpServers, keeps an empty `mcpServers: {}` to be explicit.
|
|
50
|
+
*/
|
|
51
|
+
export declare function removeFromConfig(existing: McpConfigFile | null | undefined, serverKey?: string): McpConfigFile;
|
|
52
|
+
/**
|
|
53
|
+
* Pretty-print a config with stable key order + 2-space indent. Writes
|
|
54
|
+
* this string is the caller's responsibility.
|
|
55
|
+
*/
|
|
56
|
+
export declare function serializeConfig(cfg: McpConfigFile): string;
|
|
57
|
+
//# sourceMappingURL=mcp-client-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-client-config.d.ts","sourceRoot":"","sources":["../../src/lib/mcp-client-config.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEzD,eAAO,MAAM,iBAAiB,EAAE,SAAS,EAAqC,CAAC;AAE/E,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,KAAK,IAAI,SAAS,CAEtF;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAEzC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAC1D,MAAM,CAiCR;AAED,MAAM,WAAW,eAAe;IAC9B,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7B;AAED,uDAAuD;AACvD,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AAEtD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,GAAE,eAAoB,GAAG,WAAW,CAkBzE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,EAC1C,KAAK,EAAE,WAAW,EAClB,SAAS,GAAE,MAAgB,GAC1B,aAAa,CAMf;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,EAC1C,SAAS,GAAE,MAAgB,GAC1B,aAAa,CAOf;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAE1D"}
|