@x12i/sdk 0.4.0 → 1.1.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.
Files changed (48) hide show
  1. package/README.md +62 -0
  2. package/dist/admin-import.d.ts +6 -0
  3. package/dist/admin-import.js +127 -0
  4. package/dist/admin-import.js.map +1 -0
  5. package/dist/admin-mcp.d.ts +3 -0
  6. package/dist/admin-mcp.js +95 -0
  7. package/dist/admin-mcp.js.map +1 -0
  8. package/dist/admin.d.ts +156 -0
  9. package/dist/admin.js +369 -0
  10. package/dist/admin.js.map +1 -0
  11. package/dist/cli.d.ts +2 -0
  12. package/dist/cli.js +68 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/client.d.ts +74 -195
  15. package/dist/client.js +187 -695
  16. package/dist/client.js.map +1 -1
  17. package/dist/identity.d.ts +8 -0
  18. package/dist/identity.js +34 -0
  19. package/dist/identity.js.map +1 -0
  20. package/dist/index.d.ts +6 -22
  21. package/dist/index.js +6 -12
  22. package/dist/index.js.map +1 -1
  23. package/dist/init.d.ts +18 -0
  24. package/dist/init.js +147 -0
  25. package/dist/init.js.map +1 -0
  26. package/dist/maturity.d.ts +65 -0
  27. package/dist/maturity.js +138 -0
  28. package/dist/maturity.js.map +1 -0
  29. package/dist/mcp.d.ts +27 -0
  30. package/dist/mcp.js +168 -0
  31. package/dist/mcp.js.map +1 -0
  32. package/dist/protocol.d.ts +38 -0
  33. package/dist/protocol.js +168 -0
  34. package/dist/protocol.js.map +1 -0
  35. package/dist/rank.d.ts +19 -0
  36. package/dist/rank.js +82 -0
  37. package/dist/rank.js.map +1 -0
  38. package/dist/runner.d.ts +22 -0
  39. package/dist/runner.js +99 -0
  40. package/dist/runner.js.map +1 -0
  41. package/package.json +66 -61
  42. package/LICENSE +0 -21
  43. package/dist/client.d.ts.map +0 -1
  44. package/dist/index.d.ts.map +0 -1
  45. package/dist/registry.d.ts +0 -8
  46. package/dist/registry.d.ts.map +0 -1
  47. package/dist/registry.js +0 -21
  48. package/dist/registry.js.map +0 -1
package/dist/mcp.js ADDED
@@ -0,0 +1,168 @@
1
+ import { AGENT_INSTRUCTION } from "./init.js";
2
+ export const MCP_PROTOCOL_VERSIONS = ["2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05"];
3
+ const str = (description) => ({ type: "string", description });
4
+ const object = (properties, required) => ({ type: "object", properties, required, additionalProperties: false });
5
+ const agent = { type: "string", enum: ["cursor", "claude-code", "codex", "other"], description: "Code agent that used the package" };
6
+ const outcome = { type: "string", enum: ["succeeded", "partial", "failed", "not-used"], description: "What happened when the package was tried" };
7
+ const notes = {
8
+ worked: str("What worked"),
9
+ failed: str("What did not work"),
10
+ needed: str("What was needed"),
11
+ improve: str("What should improve"),
12
+ };
13
+ export const MCP_TOOLS = [
14
+ {
15
+ name: "x12i_search",
16
+ description: "Find the @x12i packages most relevant to a task. Results include why each package matched, its maturity, rating, use cases, tags, tiers, lifecycle, install command, license, vulnerabilities, and public example. A confirmed superseded package points at its canonical successor.",
17
+ inputSchema: object({ task: str("What the agent is trying to do") }, ["task"]),
18
+ annotations: { readOnlyHint: true },
19
+ run: (client, args) => client.search(String(args.task ?? "")),
20
+ },
21
+ {
22
+ name: "x12i_catalog",
23
+ description: "List every x12i package this catalog counts, including unscoped packages the org owns. Newest update is first. Each package includes family, familyTitle, license, vulnerabilities, and maturityLabel, which states the 0 to 100 maturity score and its band. Pass the returned cursor for the next page.",
24
+ inputSchema: object({ cursor: str("Cursor returned by the previous page"), limit: { type: "integer", description: "Page size, up to 2000" } }, []),
25
+ annotations: { readOnlyHint: true },
26
+ run: (client, args) => client.catalog(typeof args.cursor === "string" ? args.cursor : undefined, typeof args.limit === "number" ? args.limit : 50),
27
+ },
28
+ {
29
+ name: "x12i_package",
30
+ description: "Read one package. Returns the cached record, then fetches the current README and metadata when the catalog knows the package was published after that cache.",
31
+ inputSchema: object({ name: str("Package name, for example @x12i/sdk") }, ["name"]),
32
+ annotations: { readOnlyHint: true },
33
+ run: (client, args) => client.package(String(args.name ?? "")),
34
+ },
35
+ {
36
+ name: "x12i_readme",
37
+ description: "Read one package README. Returns the cached text first. When the catalog knows a newer publish exists, fetches that README and returns it too.",
38
+ inputSchema: object({ name: str("Package name") }, ["name"]),
39
+ annotations: { readOnlyHint: true },
40
+ run: (client, args) => client.readme(String(args.name ?? "")),
41
+ },
42
+ {
43
+ name: "x12i_reviews",
44
+ description: "Read recent signed reviews for one package so you can see how it went for other agents.",
45
+ inputSchema: object({ name: str("Package name") }, ["name"]),
46
+ annotations: { readOnlyHint: true },
47
+ run: (client, args) => client.reviews(String(args.name ?? "")),
48
+ },
49
+ {
50
+ name: "x12i_report",
51
+ description: "Report SDK usage without a star rating: version, outcome, and what worked, failed, was needed, or should improve.",
52
+ inputSchema: object({
53
+ package: str("Package that was used"),
54
+ packageVersion: str("Version that was used"),
55
+ agent,
56
+ outcome,
57
+ ...notes,
58
+ }, ["package", "packageVersion", "agent", "outcome"]),
59
+ run: (client, args) => client.report(args),
60
+ },
61
+ {
62
+ name: "x12i_review",
63
+ description: "File a 1 to 5 rating after trying a package. Include the version and what worked, failed, was needed, or should improve.",
64
+ inputSchema: object({
65
+ package: str("Package that was tried"),
66
+ packageVersion: str("Version that was tried"),
67
+ agent,
68
+ outcome,
69
+ rating: { type: "integer", minimum: 1, description: "Stars from 1 to 5" },
70
+ ...notes,
71
+ }, ["package", "packageVersion", "agent", "outcome", "rating"]),
72
+ run: (client, args) => client.review(args),
73
+ },
74
+ {
75
+ name: "x12i_status",
76
+ description: "Show this SDK version, whether this install is enrolled, and whether the catalog service is reachable.",
77
+ inputSchema: object({}, []),
78
+ annotations: { readOnlyHint: true },
79
+ run: (client) => client.status(),
80
+ },
81
+ ];
82
+ const rpcError = (id, code, message) => ({ jsonrpc: "2.0", id, error: { code, message } });
83
+ export async function handleMcpMessage(message, client, server = { name: "x12i", version: "0.1.0" }) {
84
+ const rpc = message;
85
+ if (!rpc || typeof rpc !== "object" || Array.isArray(rpc) || rpc.jsonrpc !== "2.0" || typeof rpc.method !== "string")
86
+ return rpcError(null, -32600, "Invalid Request");
87
+ if (rpc.id === undefined)
88
+ return undefined;
89
+ const id = rpc.id ?? null;
90
+ const params = (rpc.params ?? {});
91
+ try {
92
+ switch (rpc.method) {
93
+ case "initialize": {
94
+ const requested = params.protocolVersion;
95
+ const version = MCP_PROTOCOL_VERSIONS.includes(requested) ? requested : MCP_PROTOCOL_VERSIONS[0];
96
+ return {
97
+ jsonrpc: "2.0",
98
+ id,
99
+ result: {
100
+ protocolVersion: version,
101
+ capabilities: { tools: { listChanged: false } },
102
+ serverInfo: server,
103
+ instructions: AGENT_INSTRUCTION,
104
+ },
105
+ };
106
+ }
107
+ case "ping":
108
+ return { jsonrpc: "2.0", id, result: {} };
109
+ case "tools/list":
110
+ return { jsonrpc: "2.0", id, result: { tools: MCP_TOOLS.map(({ run: _run, ...tool }) => tool) } };
111
+ case "tools/call": {
112
+ if (!client)
113
+ return rpcError(id, -32603, "MCP client is not configured");
114
+ const tool = MCP_TOOLS.find((item) => item.name === params.name);
115
+ if (!tool)
116
+ return rpcError(id, -32602, "Unknown tool");
117
+ const args = (params.arguments ?? {});
118
+ if (!args || typeof args !== "object" || Array.isArray(args))
119
+ return rpcError(id, -32602, "arguments must be an object");
120
+ try {
121
+ const value = await tool.run(client, args);
122
+ return { jsonrpc: "2.0", id, result: { content: [{ type: "text", text: JSON.stringify(value) }], structuredContent: value, isError: false } };
123
+ }
124
+ catch (error) {
125
+ const messageText = error instanceof Error ? error.message : String(error);
126
+ return { jsonrpc: "2.0", id, result: { content: [{ type: "text", text: messageText }], isError: true } };
127
+ }
128
+ }
129
+ default:
130
+ return rpcError(id, -32601, "Method not found");
131
+ }
132
+ }
133
+ catch (error) {
134
+ return rpcError(id, -32603, error instanceof Error ? error.message : "Internal error");
135
+ }
136
+ }
137
+ export async function handleMcpFrame(client, line) {
138
+ if (!line.trim())
139
+ return undefined;
140
+ let message;
141
+ try {
142
+ message = JSON.parse(line);
143
+ }
144
+ catch {
145
+ return JSON.stringify(rpcError(null, -32700, "Parse error"));
146
+ }
147
+ if (Array.isArray(message))
148
+ return JSON.stringify(rpcError(null, -32600, "Batching is not supported"));
149
+ const response = await handleMcpMessage(message, client);
150
+ return response ? JSON.stringify(response) : undefined;
151
+ }
152
+ export async function serveMcp(client) {
153
+ const decoder = new TextDecoder();
154
+ let buffer = "";
155
+ for await (const chunk of process.stdin) {
156
+ buffer += typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true });
157
+ let newline = buffer.indexOf("\n");
158
+ while (newline >= 0) {
159
+ const line = buffer.slice(0, newline);
160
+ buffer = buffer.slice(newline + 1);
161
+ const response = await handleMcpFrame(client, line);
162
+ if (response)
163
+ process.stdout.write(`${response}\n`);
164
+ newline = buffer.indexOf("\n");
165
+ }
166
+ }
167
+ }
168
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ export declare const AGENTS: readonly ["cursor", "claude-code", "codex", "other"];
2
+ export declare const OUTCOMES: readonly ["succeeded", "partial", "failed", "not-used"];
3
+ export type AgentName = (typeof AGENTS)[number];
4
+ export type Outcome = (typeof OUTCOMES)[number];
5
+ export type KeyMaterial = {
6
+ publicKey: string;
7
+ privateKey: string;
8
+ fingerprint: string;
9
+ };
10
+ export type UsageFields = {
11
+ package: string;
12
+ packageVersion: string;
13
+ agent: AgentName;
14
+ outcome: Outcome;
15
+ worked: string;
16
+ failed: string;
17
+ needed: string;
18
+ improve: string;
19
+ };
20
+ export declare function b64u(bytes: Uint8Array): string;
21
+ export declare function fromB64u(value: string): Uint8Array;
22
+ export declare function sha256(bytes: Uint8Array): Promise<Uint8Array>;
23
+ export declare function sha256Hex(value: string): Promise<string>;
24
+ export declare function leadingZeroBits(digest: Uint8Array): number;
25
+ export declare function constantEqual(left: string, right: string): boolean;
26
+ export declare function createKeyPair(): Promise<KeyMaterial>;
27
+ export declare function fingerprintOf(publicKey: string): Promise<string>;
28
+ export declare function sign(privateKey: string, message: string): Promise<string>;
29
+ export declare function verifySignature(publicKey: string, message: string, signature: string): Promise<boolean>;
30
+ export declare function canonicalRequest(method: string, path: string, timestamp: string, nonce: string, body: string): Promise<string>;
31
+ export declare function randomNonce(): string;
32
+ /** Leading-zero bits required for a new install. The first few from a network are free. */
33
+ export declare function workBits(enrollmentsToday: number): number;
34
+ export declare function networkKey(ip: string | null): string;
35
+ export declare function solveWork(challenge: string, bits: number): Promise<string>;
36
+ export declare function checkWork(challenge: string, bits: number, work: string): Promise<boolean>;
37
+ export declare function usageFields(input: Record<string, unknown>): UsageFields;
38
+ export declare function reviewRating(value: unknown): number;
@@ -0,0 +1,168 @@
1
+ const textEncoder = new TextEncoder();
2
+ export const AGENTS = ["cursor", "claude-code", "codex", "other"];
3
+ export const OUTCOMES = ["succeeded", "partial", "failed", "not-used"];
4
+ const PACKAGE_NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
5
+ const SECRET = /-----BEGIN |sk-[A-Za-z0-9]{16,}|api[_-]?key\s*[:=]/i;
6
+ export function b64u(bytes) {
7
+ let binary = "";
8
+ for (const byte of bytes)
9
+ binary += String.fromCharCode(byte);
10
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
11
+ }
12
+ export function fromB64u(value) {
13
+ const padded = value.replaceAll("-", "+").replaceAll("_", "/") + "=".repeat((4 - (value.length % 4)) % 4);
14
+ const binary = atob(padded);
15
+ const bytes = new Uint8Array(binary.length);
16
+ for (let i = 0; i < binary.length; i++)
17
+ bytes[i] = binary.charCodeAt(i);
18
+ return bytes;
19
+ }
20
+ export async function sha256(bytes) {
21
+ return new Uint8Array(await crypto.subtle.digest("SHA-256", bytes));
22
+ }
23
+ export async function sha256Hex(value) {
24
+ const digest = await sha256(textEncoder.encode(value));
25
+ return [...digest].map((byte) => byte.toString(16).padStart(2, "0")).join("");
26
+ }
27
+ export function leadingZeroBits(digest) {
28
+ let bits = 0;
29
+ for (const byte of digest) {
30
+ if (byte === 0) {
31
+ bits += 8;
32
+ continue;
33
+ }
34
+ for (let mask = 128; mask > 0; mask >>= 1) {
35
+ if ((byte & mask) !== 0)
36
+ return bits;
37
+ bits += 1;
38
+ }
39
+ }
40
+ return bits;
41
+ }
42
+ export function constantEqual(left, right) {
43
+ const a = textEncoder.encode(left);
44
+ const b = textEncoder.encode(right);
45
+ if (a.length !== b.length)
46
+ return false;
47
+ let diff = 0;
48
+ for (let i = 0; i < a.length; i++)
49
+ diff |= a[i] ^ b[i];
50
+ return diff === 0;
51
+ }
52
+ export async function createKeyPair() {
53
+ const pair = await crypto.subtle.generateKey({ name: "Ed25519" }, true, ["sign", "verify"]);
54
+ const publicKey = b64u(new Uint8Array(await crypto.subtle.exportKey("raw", pair.publicKey)));
55
+ const privateKey = b64u(new Uint8Array(await crypto.subtle.exportKey("pkcs8", pair.privateKey)));
56
+ return { publicKey, privateKey, fingerprint: await fingerprintOf(publicKey) };
57
+ }
58
+ export async function fingerprintOf(publicKey) {
59
+ const raw = fromB64u(publicKey);
60
+ if (raw.length !== 32)
61
+ throw new Error("Ed25519 public key must be 32 bytes");
62
+ const digest = await sha256(raw);
63
+ return [...digest].map((byte) => byte.toString(16).padStart(2, "0")).join("");
64
+ }
65
+ export async function sign(privateKey, message) {
66
+ const key = await crypto.subtle.importKey("pkcs8", fromB64u(privateKey), { name: "Ed25519" }, false, ["sign"]);
67
+ const signature = await crypto.subtle.sign("Ed25519", key, textEncoder.encode(message));
68
+ return b64u(new Uint8Array(signature));
69
+ }
70
+ export async function verifySignature(publicKey, message, signature) {
71
+ try {
72
+ const key = await crypto.subtle.importKey("raw", fromB64u(publicKey), { name: "Ed25519" }, false, ["verify"]);
73
+ return await crypto.subtle.verify("Ed25519", key, fromB64u(signature), textEncoder.encode(message));
74
+ }
75
+ catch {
76
+ return false;
77
+ }
78
+ }
79
+ export async function canonicalRequest(method, path, timestamp, nonce, body) {
80
+ return ["X12I-SDK-v1", method.toUpperCase(), path, timestamp, nonce, await sha256Hex(body)].join("\n");
81
+ }
82
+ export function randomNonce() {
83
+ const bytes = new Uint8Array(16);
84
+ crypto.getRandomValues(bytes);
85
+ return b64u(bytes);
86
+ }
87
+ /** Leading-zero bits required for a new install. The first few from a network are free. */
88
+ export function workBits(enrollmentsToday) {
89
+ if (enrollmentsToday <= 3)
90
+ return 0;
91
+ return Math.min(16, 8 + Math.floor(Math.log2(enrollmentsToday)));
92
+ }
93
+ export function networkKey(ip) {
94
+ if (!ip)
95
+ return "unknown";
96
+ const first = ip.split(",")[0]?.trim() ?? "";
97
+ if (/^\d{1,3}(\.\d{1,3}){3}$/.test(first))
98
+ return `v4:${first.split(".").slice(0, 3).join(".")}`;
99
+ if (first.startsWith("::ffff:"))
100
+ return networkKey(first.slice(7));
101
+ if (first.includes(":")) {
102
+ const groups = first.split("::")[0]?.split(":").filter(Boolean) ?? [];
103
+ return `v6:${groups.slice(0, 3).join(":")}`;
104
+ }
105
+ return "unknown";
106
+ }
107
+ export async function solveWork(challenge, bits) {
108
+ if (bits <= 0)
109
+ return "";
110
+ for (let counter = 0; counter < 5_000_000; counter++) {
111
+ const work = String(counter);
112
+ const digest = await sha256(textEncoder.encode(`${challenge}:${work}`));
113
+ if (leadingZeroBits(digest) >= bits)
114
+ return work;
115
+ }
116
+ throw new Error("Proof of work exceeded the search limit");
117
+ }
118
+ export async function checkWork(challenge, bits, work) {
119
+ if (bits <= 0)
120
+ return work === "";
121
+ if (!/^\d{1,12}$/.test(work) || bits > 24)
122
+ return false;
123
+ const digest = await sha256(textEncoder.encode(`${challenge}:${work}`));
124
+ return leadingZeroBits(digest) >= bits;
125
+ }
126
+ function note(value, field) {
127
+ if (value == null || value === "")
128
+ return "";
129
+ if (typeof value !== "string")
130
+ throw new Error(`${field} must be text`);
131
+ const text = value.trim();
132
+ if (text.length > 1000)
133
+ throw new Error(`${field} is longer than 1000 characters`);
134
+ if (SECRET.test(text))
135
+ throw new Error(`${field} looks like a secret; remove it before sending`);
136
+ return text;
137
+ }
138
+ export function usageFields(input) {
139
+ const packageName = input.package;
140
+ if (typeof packageName !== "string" || !PACKAGE_NAME.test(packageName))
141
+ throw new Error("package name is invalid");
142
+ const packageVersion = input.packageVersion;
143
+ if (typeof packageVersion !== "string" || packageVersion.trim().length === 0 || packageVersion.length > 64) {
144
+ throw new Error("packageVersion is required");
145
+ }
146
+ const agent = input.agent;
147
+ if (typeof agent !== "string" || !AGENTS.includes(agent))
148
+ throw new Error("agent must be cursor, claude-code, codex, or other");
149
+ const outcome = input.outcome;
150
+ if (typeof outcome !== "string" || !OUTCOMES.includes(outcome))
151
+ throw new Error("outcome is invalid");
152
+ return {
153
+ package: packageName,
154
+ packageVersion: packageVersion.trim(),
155
+ agent: agent,
156
+ outcome: outcome,
157
+ worked: note(input.worked, "worked"),
158
+ failed: note(input.failed, "failed"),
159
+ needed: note(input.needed, "needed"),
160
+ improve: note(input.improve, "improve"),
161
+ };
162
+ }
163
+ export function reviewRating(value) {
164
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1 || value > 5)
165
+ throw new Error("rating must be an integer from 1 to 5");
166
+ return value;
167
+ }
168
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
package/dist/rank.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ export type CatalogDocument = {
2
+ name: string;
3
+ description?: string;
4
+ keywords?: string[];
5
+ headings?: string[];
6
+ readme?: string;
7
+ maturity?: number;
8
+ rating?: number | null;
9
+ };
10
+ export type RankedPackage = {
11
+ name: string;
12
+ score: number;
13
+ confidence: "high" | "low";
14
+ matched: string[];
15
+ reasons: string[];
16
+ };
17
+ export declare function tokenize(text: string): string[];
18
+ /** Explainable ranking. No model. A task with no overlapping terms comes back at low confidence. */
19
+ export declare function rankPackages(task: string, entries: CatalogDocument[], limit?: number): RankedPackage[];
package/dist/rank.js ADDED
@@ -0,0 +1,82 @@
1
+ import { bandFor } from "./maturity.js";
2
+ const STOP = new Set(["the", "a", "an", "to", "for", "of", "and", "or", "in", "on", "with", "using", "use", "via", "from", "that", "this", "is", "be", "it", "as", "at", "by"]);
3
+ export function tokenize(text) {
4
+ return text
5
+ .toLowerCase()
6
+ .split(/[^a-z0-9@/+.-]+/)
7
+ .map((token) => token.replace(/^[.@/+-]+|[.@/+-]+$/g, ""))
8
+ .filter((token) => token.length > 1 && !STOP.has(token));
9
+ }
10
+ function unique(tokens) {
11
+ return [...new Set(tokens)];
12
+ }
13
+ function nameTokens(name) {
14
+ return unique(tokenize(name.replaceAll(/[@/]/g, " "))).filter((token) => token !== "x12i");
15
+ }
16
+ function hits(term, tokens) {
17
+ return tokens.some((token) => token === term || (term.length >= 4 && token.length >= 4 && (token.startsWith(term) || term.startsWith(token))));
18
+ }
19
+ /** Explainable ranking. No model. A task with no overlapping terms comes back at low confidence. */
20
+ export function rankPackages(task, entries, limit = 5) {
21
+ const terms = unique(tokenize(task));
22
+ const scored = entries.map((entry) => {
23
+ const name = nameTokens(entry.name);
24
+ const keywords = unique((entry.keywords ?? []).flatMap((keyword) => tokenize(keyword)));
25
+ const description = unique(tokenize(entry.description ?? ""));
26
+ const headings = unique((entry.headings ?? []).flatMap((heading) => tokenize(heading)));
27
+ const readme = unique(tokenize((entry.readme ?? "").slice(0, 2000)));
28
+ const matched = [];
29
+ const reasons = [];
30
+ let score = 0;
31
+ for (const term of terms) {
32
+ let termScore = 0;
33
+ if (hits(term, name)) {
34
+ termScore += 8;
35
+ reasons.push(`name matches ${term}`);
36
+ }
37
+ if (hits(term, keywords)) {
38
+ termScore += 6;
39
+ reasons.push(`keyword matches ${term}`);
40
+ }
41
+ if (hits(term, description)) {
42
+ termScore += 3;
43
+ reasons.push(`description matches ${term}`);
44
+ }
45
+ if (hits(term, headings)) {
46
+ termScore += 3;
47
+ reasons.push(`heading matches ${term}`);
48
+ }
49
+ if (hits(term, readme)) {
50
+ termScore += 1;
51
+ reasons.push(`readme matches ${term}`);
52
+ }
53
+ if (termScore > 0) {
54
+ matched.push(term);
55
+ score += termScore;
56
+ }
57
+ }
58
+ const maturity = entry.maturity ?? 0;
59
+ const ratingBoost = entry.rating == null ? 0 : (entry.rating - 3) * 0.5;
60
+ score += (maturity / 100) * 2 + ratingBoost;
61
+ if (maturity > 0)
62
+ reasons.push(`maturity ${Math.round(maturity)} of 100, ${bandFor(maturity)}`);
63
+ if (entry.rating != null)
64
+ reasons.push(`rating ${entry.rating}`);
65
+ return {
66
+ name: entry.name,
67
+ score: Math.round(score * 1000) / 1000,
68
+ confidence: matched.length > 0 ? "high" : "low",
69
+ matched,
70
+ reasons,
71
+ };
72
+ });
73
+ const matchedAny = scored.some((item) => item.confidence === "high");
74
+ const chosen = (matchedAny ? scored.filter((item) => item.confidence === "high") : scored)
75
+ .sort((a, b) => b.score - a.score || a.name.localeCompare(b.name))
76
+ .slice(0, limit);
77
+ if (!matchedAny) {
78
+ return chosen.map((item) => ({ ...item, reasons: ["no catalog terms matched", ...item.reasons.filter((reason) => reason.startsWith("maturity") || reason.startsWith("rating"))] }));
79
+ }
80
+ return chosen;
81
+ }
82
+ //# sourceMappingURL=rank.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rank.js","sourceRoot":"","sources":["../src/rank.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAoBhL,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,IAAI;SACR,WAAW,EAAE;SACb,KAAK,CAAC,iBAAiB,CAAC;SACxB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC;SACzD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,MAAM,CAAC,MAAgB;IAC9B,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC;AAC7F,CAAC;AAED,SAAS,IAAI,CAAC,IAAY,EAAE,MAAgB;IAC1C,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACjJ,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,OAA0B,EAAE,KAAK,GAAG,CAAC;IAC9E,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACnC,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACxF,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACxF,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QACrE,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,IAAI,KAAK,GAAG,CAAC,CAAC;QAEd,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,SAAS,GAAG,CAAC,CAAC;YAClB,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBACrB,SAAS,IAAI,CAAC,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC;YACvC,CAAC;YACD,IAAI,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;gBACzB,SAAS,IAAI,CAAC,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;YAC1C,CAAC;YACD,IAAI,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC;gBAC5B,SAAS,IAAI,CAAC,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC;YAC9C,CAAC;YACD,IAAI,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;gBACzB,SAAS,IAAI,CAAC,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;YAC1C,CAAC;YACD,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;gBACvB,SAAS,IAAI,CAAC,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC;YACzC,CAAC;YACD,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;gBAClB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACnB,KAAK,IAAI,SAAS,CAAC;YACrB,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;QACrC,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;QACxE,KAAK,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC;QAC5C,IAAI,QAAQ,GAAG,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAChG,IAAI,KAAK,CAAC,MAAM,IAAI,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,UAAU,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAEjE,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,IAAI;YACtC,UAAU,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAe,CAAC,CAAC,CAAC,KAAc;YACjE,OAAO;YACP,OAAO;SACR,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,KAAK,MAAM,CAAC,CAAC;IACrE,MAAM,MAAM,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;SACvF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;SACjE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAEnB,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,0BAA0B,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACtL,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { X12iAdmin } from "./admin.js";
2
+ export type CommandResult = {
3
+ code: number;
4
+ stdout: string;
5
+ stderr: string;
6
+ };
7
+ export type CommandRunner = (command: string, args: string[], cwd: string) => Promise<CommandResult>;
8
+ export declare function npmRunner(): CommandRunner;
9
+ export declare function validateUsageDirectory(directory: string, run: CommandRunner, install: boolean): Promise<{
10
+ packageName: string;
11
+ packageVersion: string;
12
+ status: "passed" | "failed";
13
+ scope: string;
14
+ hashes: Record<string, string>;
15
+ results: Array<{
16
+ packageName: string;
17
+ status: string;
18
+ output: string;
19
+ }>;
20
+ environment: Record<string, unknown>;
21
+ }>;
22
+ export declare function runValidationRunner(admin: X12iAdmin, directory?: string, run?: CommandRunner): Promise<unknown>;
package/dist/runner.js ADDED
@@ -0,0 +1,99 @@
1
+ import { createHash } from "node:crypto";
2
+ import { spawn } from "node:child_process";
3
+ import { readFile, readdir } from "node:fs/promises";
4
+ import { join } from "node:path";
5
+ export function npmRunner() {
6
+ return (command, args, cwd) => new Promise((resolve, reject) => {
7
+ const child = spawn(command, args, { cwd, shell: process.platform === "win32" });
8
+ let stdout = "";
9
+ let stderr = "";
10
+ child.stdout.on("data", (chunk) => { stdout += String(chunk); });
11
+ child.stderr.on("data", (chunk) => { stderr += String(chunk); });
12
+ child.on("error", reject);
13
+ child.on("close", (code) => resolve({ code: code ?? 1, stdout: stdout.slice(-4000), stderr: stderr.slice(-4000) }));
14
+ });
15
+ }
16
+ export async function validateUsageDirectory(directory, run, install) {
17
+ const usage = JSON.parse(await readFile(join(directory, "usage.json"), "utf8"));
18
+ if (install) {
19
+ const installed = await run("npm", ["ci", "--ignore-scripts", "--no-audit", "--no-fund"], directory);
20
+ if (installed.code !== 0) {
21
+ return failed(usage, installed.stderr || installed.stdout, {});
22
+ }
23
+ }
24
+ const files = await sourceFiles(directory);
25
+ const hashes = Object.fromEntries(await Promise.all(Object.entries(files).map(async ([path, body]) => [path, createHash("sha256").update(body).digest("hex")])));
26
+ const results = [];
27
+ const primary = await run("node", [usage.example.entrypoint ?? "src/index.mjs"], directory);
28
+ results.push({ packageName: usage.package, status: primary.code === 0 ? "passed" : "failed", output: primary.code === 0 ? primary.stdout : primary.stderr });
29
+ for (const [name, extra] of Object.entries(usage.additionalExamples ?? {})) {
30
+ const ran = await run("node", [extra.entrypoint], directory);
31
+ results.push({ packageName: name, status: ran.code === 0 ? "passed" : "failed", output: ran.code === 0 ? ran.stdout : ran.stderr });
32
+ }
33
+ const status = results.every((item) => item.status === "passed") ? "passed" : "failed";
34
+ return {
35
+ packageName: usage.package,
36
+ packageVersion: usage.packageVersion,
37
+ status,
38
+ scope: "fixture",
39
+ hashes,
40
+ results,
41
+ environment: { node: process.version, runner: "x12i-sdk admin runner", scope: "fixture", liveIntegration: false },
42
+ };
43
+ }
44
+ function failed(usage, output, hashes) {
45
+ return {
46
+ packageName: usage.package,
47
+ packageVersion: usage.packageVersion,
48
+ status: "failed",
49
+ scope: "fixture",
50
+ hashes,
51
+ results: [{ packageName: usage.package, status: "failed", output }],
52
+ environment: { node: process.version, scope: "fixture", liveIntegration: false },
53
+ };
54
+ }
55
+ async function sourceFiles(directory) {
56
+ const files = {};
57
+ files["package.json"] = await readFile(join(directory, "package.json"), "utf8");
58
+ const src = join(directory, "src");
59
+ for (const name of await readdir(src)) {
60
+ if (name.endsWith(".mjs") || name.endsWith(".js") || name.endsWith(".json"))
61
+ files[`src/${name}`] = await readFile(join(src, name), "utf8");
62
+ }
63
+ return files;
64
+ }
65
+ export async function runValidationRunner(admin, directory, run = npmRunner()) {
66
+ if (!directory)
67
+ return { status: "idle", note: "Pass a usage directory to validate. The runner does not publish." };
68
+ const minted = await admin.mint(["examples:prepare", "examples:validate"], "runner");
69
+ const scoped = admin.withToken(minted.token);
70
+ const result = await validateUsageDirectory(directory, run, true);
71
+ const files = await sourceFiles(directory);
72
+ const usage = JSON.parse(await readFile(join(directory, "usage.json"), "utf8"));
73
+ const draft = await scoped.prepareDraft({
74
+ packageName: result.packageName,
75
+ version: result.packageVersion,
76
+ scenario: usage.example?.command ?? "Run the package consumer and check its printed result.",
77
+ entrypoint: "src/index.mjs",
78
+ command: usage.example?.command ?? "node src/index.mjs",
79
+ files,
80
+ });
81
+ const versions = new Map([[result.packageName, result.packageVersion]]);
82
+ for (const [name, extra] of Object.entries(usage.additionalExamples ?? {}))
83
+ versions.set(name, extra.packageVersion ?? result.packageVersion);
84
+ const validations = [];
85
+ for (const item of result.results) {
86
+ validations.push(await scoped.recordValidation({
87
+ draftId: draft.draftId,
88
+ packageName: item.packageName,
89
+ packageVersion: versions.get(item.packageName) ?? result.packageVersion,
90
+ status: item.status === "passed" ? "passed" : "failed",
91
+ scope: "fixture",
92
+ hashes: result.hashes,
93
+ environment: result.environment,
94
+ output: item.output,
95
+ }));
96
+ }
97
+ return { ...result, draft, validations };
98
+ }
99
+ //# sourceMappingURL=runner.js.map