@parity-app/cli 0.6.2 → 0.7.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/bin.mjs +14 -15
- package/dist/{client-BUaE9b77.mjs → client-D5kbiMmn.mjs} +1 -1
- package/dist/index.mjs +1 -1
- package/dist/schema-DcQLoUPP.mjs +239 -0
- package/dist/src-BaOpaXkV.mjs +4 -0
- package/dist/{src-V9wTMkxO.mjs → src-CSah1pZ-.mjs} +605 -715
- package/dist/src-D2kRGtaF.mjs +129 -0
- package/dist/src-vUHtM2X4.mjs +1 -0
- package/dist/{src-BvKhu6dX.mjs → src-x0VQ8I6l.mjs} +260 -123
- package/package.json +1 -1
- package/skills/SKILL.md +16 -16
- package/dist/schema-zRNxotYl.mjs +0 -121
- package/dist/src-BIVDlIGc.mjs +0 -53
- package/dist/src-BgQ7gnXE.mjs +0 -3
- package/dist/src-CiqdFzei.mjs +0 -1
package/dist/bin.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { a as describeExec, c as describeProps, f as setCaller, i as describeConsole, l as describeStatus, n as describeAccessibility, o as describeModes, p as mcpCallerName, r as describeComponents, s as describeProblems, t as call, u as describeTokens } from "./client-
|
|
2
|
+
import { c as closest, d as readErrorDetails, l as errorCodes, s as CodedError, u as errorDetails } from "./schema-DcQLoUPP.mjs";
|
|
3
|
+
import { a as describeExec, c as describeProps, f as setCaller, i as describeConsole, l as describeStatus, n as describeAccessibility, o as describeModes, p as mcpCallerName, r as describeComponents, s as describeProblems, t as call, u as describeTokens } from "./client-D5kbiMmn.mjs";
|
|
4
4
|
import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
5
5
|
import { dirname, join, normalize, relative, resolve, sep } from "node:path";
|
|
6
6
|
import { parseArgs } from "node:util";
|
|
@@ -387,16 +387,11 @@ const executeOperation = {
|
|
|
387
387
|
*/
|
|
388
388
|
async function runCheck(library, options) {
|
|
389
389
|
if (!library) throw new Error("parity lib check <library> [--tab t] [--mode m]");
|
|
390
|
-
const {
|
|
391
|
-
const {
|
|
392
|
-
const entry = (await
|
|
390
|
+
const { componentNode, generateId, librarySource, withLibraryContext } = await import("./src-BaOpaXkV.mjs");
|
|
391
|
+
const { newestEntries, registryDir } = await import("./src-vUHtM2X4.mjs");
|
|
392
|
+
const entry = (await newestEntries()).find((item) => item.manifest.id === library);
|
|
393
393
|
if (!entry) throw new Error(`The registry has no library "${library}"`);
|
|
394
|
-
|
|
395
|
-
if (manifest.edits) {
|
|
396
|
-
const edits = typeof manifest.edits === "string" ? parseLibraryEdits(JSON.parse(await readFile(join(dirname(entry.path), manifest.edits), "utf8"))) : manifest.edits;
|
|
397
|
-
manifest = applyLibraryEdits(manifest, edits).manifest;
|
|
398
|
-
}
|
|
399
|
-
const list = manifest.components?.list ?? {};
|
|
394
|
+
const list = entry.manifest.components?.list ?? {};
|
|
400
395
|
const names = Object.keys(list).filter((name) => list[name].visual !== false);
|
|
401
396
|
const id = (name) => `${library}/${name}`;
|
|
402
397
|
const sources = Object.fromEntries(Object.keys(list).map((name) => [id(name), {
|
|
@@ -516,8 +511,8 @@ function describeCheck(report) {
|
|
|
516
511
|
* because it reads the project's files and its own copy of TypeScript.
|
|
517
512
|
*/
|
|
518
513
|
async function runLib(packageName, options) {
|
|
519
|
-
const { appManifestPath, generateLibrary, manifestText, mergeManifest, reviseLibrary } = await import("./src-
|
|
520
|
-
const { covers, registryDir, registryEntries } = await import("./src-
|
|
514
|
+
const { appManifestPath, generateLibrary, manifestText, mergeManifest, reviseLibrary } = await import("./src-x0VQ8I6l.mjs");
|
|
515
|
+
const { covers, registryDir, registryEntries } = await import("./src-vUHtM2X4.mjs");
|
|
521
516
|
const spec = packageName === void 0 ? void 0 : packageSpec(packageName);
|
|
522
517
|
let root = resolve(options.root ?? ".");
|
|
523
518
|
if (spec && (spec.version !== void 0 || options.registry && !options.root)) {
|
|
@@ -528,7 +523,7 @@ async function runLib(packageName, options) {
|
|
|
528
523
|
console.error(`Installing ${spec.name} ${version} on its own…`);
|
|
529
524
|
root = await installedVersion(spec.name, version);
|
|
530
525
|
}
|
|
531
|
-
const { parseLibraryEdits } = await import("./src-
|
|
526
|
+
const { parseLibraryEdits } = await import("./src-x0VQ8I6l.mjs");
|
|
532
527
|
const trialEdits = options.edits ? parseLibraryEdits(JSON.parse(await readFile(resolve(options.edits), "utf8"))) : void 0;
|
|
533
528
|
const recordedId = options.registry && spec ? options.id ?? (await registryEntries()).find((entry) => entry.manifest.package?.name === spec.name)?.manifest.id : void 0;
|
|
534
529
|
const appErrors = recordedId ? await readAppErrors(registryDir(), recordedId) : void 0;
|
|
@@ -948,11 +943,15 @@ const stateSchema = object({
|
|
|
948
943
|
},
|
|
949
944
|
modes: {
|
|
950
945
|
type: "array",
|
|
946
|
+
description: "The project's modes, primary first.",
|
|
951
947
|
items: object({
|
|
952
948
|
id: string,
|
|
953
949
|
name: string,
|
|
954
950
|
width: { type: "number" },
|
|
955
|
-
primary:
|
|
951
|
+
primary: {
|
|
952
|
+
...boolean_,
|
|
953
|
+
description: "The project's first mode: every design's main frame unless it picks another. Only one is."
|
|
954
|
+
}
|
|
956
955
|
})
|
|
957
956
|
},
|
|
958
957
|
components: strings,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as readErrorDetails, f as unknownReference, i as nonBlankString, r as jsonText, s as CodedError } from "./schema-DcQLoUPP.mjs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { readFileSync, readdirSync, realpathSync, rmSync } from "node:fs";
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as call, n as describeAccessibility, r as describeComponents, i as describeConsole, a as describeExec, o as describeModes, s as describeProblems, c as describeProps, l as describeStatus, u as describeTokens, d as registry, f as setCaller } from "./client-
|
|
1
|
+
export { t as call, n as describeAccessibility, r as describeComponents, i as describeConsole, a as describeExec, o as describeModes, s as describeProblems, c as describeProps, l as describeStatus, u as describeTokens, d as registry, f as setCaller } from "./client-D5kbiMmn.mjs";
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// ../core/src/errors.ts
|
|
3
|
+
/**
|
|
4
|
+
* Why an agent's call failed, as a stable code it can act on without reading the message. The CLI and MCP publish
|
|
5
|
+
* these; the app throws them where it knows the cause.
|
|
6
|
+
*/
|
|
7
|
+
const errorCodes = [
|
|
8
|
+
"invalid_input",
|
|
9
|
+
"not_running",
|
|
10
|
+
"not_answering",
|
|
11
|
+
"unknown_tab",
|
|
12
|
+
"tab_not_ready",
|
|
13
|
+
"unknown_design",
|
|
14
|
+
"unknown_node",
|
|
15
|
+
"ambiguous_reference",
|
|
16
|
+
"unknown_state",
|
|
17
|
+
"unknown_mode",
|
|
18
|
+
"unknown_viewport",
|
|
19
|
+
"unknown_component",
|
|
20
|
+
"unknown_icon_set",
|
|
21
|
+
"unknown_edit_id",
|
|
22
|
+
"conflict",
|
|
23
|
+
"execution_failed",
|
|
24
|
+
"app_error"
|
|
25
|
+
];
|
|
26
|
+
/** Details as another process sends them. Each field that's malformed falls back on its own; only the code must hold. */
|
|
27
|
+
const errorDetailsSchema = z.object({
|
|
28
|
+
code: z.enum(errorCodes),
|
|
29
|
+
/** Whether sending the same request again, unchanged, can succeed. */
|
|
30
|
+
retryable: z.boolean().catch(false),
|
|
31
|
+
/** The request field at fault, as a path: `design`, `state`, `edits/0/find`. */
|
|
32
|
+
field: z.string().min(1).optional().catch(void 0),
|
|
33
|
+
/** Valid references to use instead of an unknown or ambiguous one, at most `alternativeLimit` of them. */
|
|
34
|
+
alternatives: z.array(z.unknown()).transform((items) => items.filter((item) => typeof item === "string").slice(0, 20)).optional().catch(void 0)
|
|
35
|
+
});
|
|
36
|
+
/** An error with a stable code, the field it's about and what to use instead. */
|
|
37
|
+
var CodedError = class extends Error {
|
|
38
|
+
details;
|
|
39
|
+
constructor(message, details) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = "CodedError";
|
|
42
|
+
this.details = {
|
|
43
|
+
...details,
|
|
44
|
+
retryable: details.retryable ?? false
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
/** An unknown reference, naming the valid ones closest to what was asked for, up to `alternativeLimit`. */
|
|
49
|
+
function unknownReference(code, message, reference, candidates, field) {
|
|
50
|
+
return new CodedError(message, {
|
|
51
|
+
code,
|
|
52
|
+
...field === void 0 ? {} : { field },
|
|
53
|
+
alternatives: closest(reference, candidates)
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Candidates sharing text with the reference first, ignoring case, then the rest by how few single-character edits
|
|
58
|
+
* away they are, so a typo's intended id makes the cut; ties keep their own order. All of them when they fit.
|
|
59
|
+
*/
|
|
60
|
+
function closest(reference, candidates, limit = 20) {
|
|
61
|
+
const unique = [...new Set(candidates)];
|
|
62
|
+
if (unique.length <= limit) return unique;
|
|
63
|
+
const wanted = reference.toLowerCase();
|
|
64
|
+
const ranked = unique.map((candidate, index) => {
|
|
65
|
+
const lower = candidate.toLowerCase();
|
|
66
|
+
const near = wanted.length > 0 && (lower.includes(wanted) || wanted.includes(lower));
|
|
67
|
+
return {
|
|
68
|
+
candidate,
|
|
69
|
+
index,
|
|
70
|
+
near: near ? 0 : 1,
|
|
71
|
+
distance: near ? 0 : editDistance(wanted, lower)
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
ranked.sort((a, b) => a.near - b.near || a.distance - b.distance || a.index - b.index);
|
|
75
|
+
return ranked.slice(0, limit).map(({ candidate }) => candidate);
|
|
76
|
+
}
|
|
77
|
+
/** How many single-character insertions, deletions or substitutions turn one string into the other. */
|
|
78
|
+
function editDistance(a, b) {
|
|
79
|
+
let previous = Array.from({ length: b.length + 1 }, (_, index) => index);
|
|
80
|
+
for (let i = 1; i <= a.length; i++) {
|
|
81
|
+
const row = [i];
|
|
82
|
+
for (let j = 1; j <= b.length; j++) row[j] = Math.min(previous[j] + 1, row[j - 1] + 1, previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
83
|
+
previous = row;
|
|
84
|
+
}
|
|
85
|
+
return previous[b.length];
|
|
86
|
+
}
|
|
87
|
+
/** A thrown value's details, when it carries them. */
|
|
88
|
+
function errorDetails(error) {
|
|
89
|
+
return error instanceof CodedError ? error.details : void 0;
|
|
90
|
+
}
|
|
91
|
+
/** Details that came from another process, checked before they're trusted. Anything malformed reads as none. */
|
|
92
|
+
function readErrorDetails(value) {
|
|
93
|
+
return errorDetailsSchema.safeParse(value).data;
|
|
94
|
+
}
|
|
95
|
+
// ../core/src/schema.ts
|
|
96
|
+
/**
|
|
97
|
+
* Checks for data Parity didn't make (PAR-578): files, agent input, environment variables, other programs' JSON. A zod
|
|
98
|
+
* schema is both the check and the type. A failed check reads as core's hand-written ones in `validate.ts` do: a JSON
|
|
99
|
+
* pointer to the value at fault, then what was expected there, as in `/containers/0/name: expected a string`.
|
|
100
|
+
*/
|
|
101
|
+
/** An object with string keys, and not an array or null. */
|
|
102
|
+
const plainObject = z.record(z.string(), z.unknown());
|
|
103
|
+
/** Text with something besides whitespace, trimmed. */
|
|
104
|
+
const nonBlankString = z.string().trim().min(1, "can't be blank");
|
|
105
|
+
/** A number other than NaN or ±Infinity, which zod 4 refuses on its own. */
|
|
106
|
+
const finiteNumber = z.number();
|
|
107
|
+
/**
|
|
108
|
+
* An object in a file Parity owns, such as a `.par`. A key it doesn't know is an error, and a key set to `undefined` is
|
|
109
|
+
* left out, as JSON leaves it out, so what the window saves from memory reads as it would from the file.
|
|
110
|
+
*/
|
|
111
|
+
function fileObject(shape) {
|
|
112
|
+
return z.strictObject(shape).overwrite(withoutUnset);
|
|
113
|
+
}
|
|
114
|
+
/** Zod's own copy of an object, without the keys whose values are `undefined`. */
|
|
115
|
+
function withoutUnset(value) {
|
|
116
|
+
for (const [key, entry] of Object.entries(value)) if (entry === void 0) Reflect.deleteProperty(value, key);
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
119
|
+
/** JSON text holding what `schema` checks. Text that isn't JSON fails as `expected JSON`. */
|
|
120
|
+
function jsonText(schema) {
|
|
121
|
+
return z.string().transform((text, context) => {
|
|
122
|
+
try {
|
|
123
|
+
return JSON.parse(text);
|
|
124
|
+
} catch {
|
|
125
|
+
context.addIssue({
|
|
126
|
+
code: "custom",
|
|
127
|
+
message: "expected JSON"
|
|
128
|
+
});
|
|
129
|
+
return z.NEVER;
|
|
130
|
+
}
|
|
131
|
+
}).pipe(schema);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Checks data Parity didn't make and returns what the schema reads from it, or throws `TypeError` with the first
|
|
135
|
+
* problem as `/json/pointer: message`. `at` is where the value sits in a larger one, so its pointers start there.
|
|
136
|
+
*/
|
|
137
|
+
function parseData(schema, value, at = "") {
|
|
138
|
+
const result = schema.safeParse(value, { error: issueText });
|
|
139
|
+
if (result.success) return result.data;
|
|
140
|
+
const { pointer, message } = firstProblem(result.error.issues, at);
|
|
141
|
+
throw new TypeError(`${pointer || "/"}: ${message}`);
|
|
142
|
+
}
|
|
143
|
+
/** A path inside a value as a JSON pointer (RFC 6901): `/edits/0/find`, or `` for the value itself. */
|
|
144
|
+
function jsonPointer(path) {
|
|
145
|
+
return path.map((key) => `/${String(key).replaceAll("~", "~0").replaceAll("/", "~1")}`).join("");
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The problem to report from a failed check: its first issue. An unknown property points at that property. A union
|
|
149
|
+
* that no option matched reports the option that came closest, or every type it takes when none got past the value's
|
|
150
|
+
* type. An option for another type of value isn't close, so `{ size: "big" }` against a string or an object with a
|
|
151
|
+
* numeric size reports the size, however many issues the object has.
|
|
152
|
+
*/
|
|
153
|
+
function firstProblem(issues, at) {
|
|
154
|
+
const [issue] = issues;
|
|
155
|
+
if (!issue) return {
|
|
156
|
+
pointer: at,
|
|
157
|
+
message: "isn't valid"
|
|
158
|
+
};
|
|
159
|
+
const pointer = at + jsonPointer(issue.path);
|
|
160
|
+
if (issue.code === "unrecognized_keys") return {
|
|
161
|
+
pointer: pointer + jsonPointer(issue.keys.slice(0, 1)),
|
|
162
|
+
message: issue.message
|
|
163
|
+
};
|
|
164
|
+
if (issue.code === "invalid_union" && issue.errors.length > 0) return unionProblem(issue.errors, pointer);
|
|
165
|
+
return {
|
|
166
|
+
pointer,
|
|
167
|
+
message: issue.message
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function unionProblem(options, pointer) {
|
|
171
|
+
const issues = options.flat();
|
|
172
|
+
const shallow = issues.every((issue) => issue.path.length === 0);
|
|
173
|
+
const expected = issues.map(expectation);
|
|
174
|
+
if (shallow && expected.every((text) => text !== void 0)) return {
|
|
175
|
+
pointer,
|
|
176
|
+
message: `expected ${[...new Set(expected)].join(" or ")}`
|
|
177
|
+
};
|
|
178
|
+
const depth = (option) => option[0]?.path.length ?? 0;
|
|
179
|
+
const typed = options.filter((option) => !refusesType(option));
|
|
180
|
+
return firstProblem((typed.length > 0 ? typed : options).reduce((best, option) => option.length < best.length || option.length === best.length && depth(option) > depth(best) ? option : best), pointer);
|
|
181
|
+
}
|
|
182
|
+
/** Whether a union's option failed on the value's type itself, as a string option does for an object. */
|
|
183
|
+
function refusesType(option) {
|
|
184
|
+
const [first] = option;
|
|
185
|
+
return first?.code === "invalid_type" && first.path.length === 0;
|
|
186
|
+
}
|
|
187
|
+
/** What one type or value check wanted, as `a string` or `"row"`; nothing for other checks. */
|
|
188
|
+
function expectation(issue) {
|
|
189
|
+
if (issue.code === "invalid_type") return typeName(issue.expected);
|
|
190
|
+
if (issue.code === "invalid_value") return issue.values.map(literal).join(" or ");
|
|
191
|
+
}
|
|
192
|
+
/** Zod's issues in `validate.ts`'s words. Messages a schema gives itself win, and anything else keeps zod's own. */
|
|
193
|
+
function issueText(issue) {
|
|
194
|
+
switch (issue.code) {
|
|
195
|
+
case "invalid_type": return `expected ${typeName(issue.expected)}`;
|
|
196
|
+
case "invalid_value": return issue.values.length === 1 ? `expected ${literal(issue.values[0])}` : `expected one of ${issue.values.map(literal).join(", ")}`;
|
|
197
|
+
case "unrecognized_keys": return "unknown property";
|
|
198
|
+
case "invalid_union": {
|
|
199
|
+
const options = "options" in issue ? issue.options : void 0;
|
|
200
|
+
return Array.isArray(options) && options.length > 0 ? `expected one of ${options.map(literal).join(", ")}` : void 0;
|
|
201
|
+
}
|
|
202
|
+
case "too_small": return bound("at least", "more than", issue.origin, issue.minimum, issue.inclusive);
|
|
203
|
+
case "too_big": return bound("at most", "less than", issue.origin, issue.maximum, issue.inclusive);
|
|
204
|
+
default: return;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const typeNames = {
|
|
208
|
+
array: "an array",
|
|
209
|
+
boolean: "true or false",
|
|
210
|
+
int: "a whole number",
|
|
211
|
+
number: "a number",
|
|
212
|
+
object: "an object",
|
|
213
|
+
record: "an object",
|
|
214
|
+
string: "a string",
|
|
215
|
+
tuple: "an array"
|
|
216
|
+
};
|
|
217
|
+
function typeName(expected) {
|
|
218
|
+
return typeNames[expected] ?? expected;
|
|
219
|
+
}
|
|
220
|
+
function literal(value) {
|
|
221
|
+
return typeof value === "string" ? JSON.stringify(value) : String(value);
|
|
222
|
+
}
|
|
223
|
+
const units = {
|
|
224
|
+
string: "character",
|
|
225
|
+
array: "item",
|
|
226
|
+
set: "item"
|
|
227
|
+
};
|
|
228
|
+
/** A size or range check's limit, as `expected at least 1 item` or `expected less than 10`. */
|
|
229
|
+
function bound(inclusiveWords, exclusiveWords, origin, limit, inclusive = true) {
|
|
230
|
+
const words = inclusive ? inclusiveWords : exclusiveWords;
|
|
231
|
+
const unit = units[origin];
|
|
232
|
+
if (unit) return `expected ${words} ${limit} ${unit}${Number(limit) === 1 ? "" : "s"}`;
|
|
233
|
+
return [
|
|
234
|
+
"number",
|
|
235
|
+
"int",
|
|
236
|
+
"bigint"
|
|
237
|
+
].includes(origin) ? `expected ${words} ${limit}` : void 0;
|
|
238
|
+
}
|
|
239
|
+
export { parseData as a, closest as c, readErrorDetails as d, unknownReference as f, nonBlankString as i, errorCodes as l, finiteNumber as n, plainObject as o, jsonText as r, CodedError as s, fileObject as t, errorDetails as u };
|