@unbound-app/cli 1.1.0 → 1.1.1
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/index.mjs +452 -413
- package/dist/rollup/index.mjs +31 -112
- package/dist/settings/schema.d.mts +133 -0
- package/dist/settings/schema.mjs +169 -0
- package/dist/{settings-typings-CnJ5F-rP.mjs → settings-typings-BRlzDlLI.mjs} +107 -4
- package/package.json +15 -2
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
2
|
-
import { A as readIcuMessage, E as writeLocaleTypings, F as formatDiagnostic,
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { $ as ASSET_NAME_PATTERN, A as readIcuMessage, E as writeLocaleTypings, F as formatDiagnostic, H as withoutFullStop, I as isDiagnostic, J as LOCALES_DIRECTORY, M as findFile, O as buildReportSchema, P as diagnostic, U as bytecodeFileName, V as sortDiagnostics, X as SOURCE_LOCALE, Y as LOCALE_CODE_PATTERN, Z as isLocaleCode, _ as formatBytes, at as __commonJSMin, b as LOCALE_TYPINGS, ct as __require, et as ASSET_SCALES, it as ADDON_KINDS, j as IcuSyntaxError, k as readIcuArguments, p as BUILD_REPORT_ENV, q as listAddonFiles, t as SETTINGS_TYPINGS, tt as ASSET_TYPES, ut as __toESM, y as LOCALE_MODULE } from "./settings-typings-BRlzDlLI.mjs";
|
|
3
3
|
import { cli, command } from "cleye";
|
|
4
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
5
|
import { CONTROLLER_ENDPOINT_MARKER, DEFAULT_BRIDGE_PORT, DEFAULT_EVAL_TIMEOUT_MS, MAX_EVAL_TIMEOUT_MS } from "@unbound-app/debugger-protocol";
|
|
6
6
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
7
7
|
import { ControllerClient } from "@unbound-app/debugger-protocol/controller";
|
|
8
|
-
import { Type, Type as Type$
|
|
8
|
+
import { Type, Type as Type$2 } from "typebox";
|
|
9
9
|
import { Compile } from "typebox/compile";
|
|
10
10
|
import { Format } from "typebox/format";
|
|
11
11
|
import { Clone } from "typebox/value";
|
|
@@ -13,18 +13,18 @@ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprot
|
|
|
13
13
|
import blockScoping from "@babel/plugin-transform-block-scoping";
|
|
14
14
|
import { transformSync } from "@babel/core";
|
|
15
15
|
import { execFile, spawn, spawnSync } from "node:child_process";
|
|
16
|
-
import { basename, delimiter, dirname, extname, join, relative, resolve, sep } from "node:path";
|
|
17
16
|
import { closeSync, existsSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, watch, writeFileSync } from "node:fs";
|
|
18
|
-
import {
|
|
17
|
+
import { availableParallelism, homedir, tmpdir } from "node:os";
|
|
18
|
+
import { basename, delimiter, dirname, extname, join, relative, resolve, sep } from "node:path";
|
|
19
19
|
import { readdir, stat } from "node:fs/promises";
|
|
20
|
+
import { promisify } from "node:util";
|
|
21
|
+
import { createHash } from "node:crypto";
|
|
20
22
|
import ts from "typescript-api";
|
|
21
23
|
import pc from "picocolors";
|
|
22
24
|
import { Visitor, parseSync } from "rolldown/utils";
|
|
23
25
|
import { Lexer, walkTokens } from "marked";
|
|
24
26
|
import { rgbaToThumbHash } from "thumbhash";
|
|
25
|
-
import { promisify } from "node:util";
|
|
26
27
|
import sharp from "sharp";
|
|
27
|
-
import { availableParallelism, homedir, tmpdir } from "node:os";
|
|
28
28
|
import { gzipSync } from "node:zlib";
|
|
29
29
|
import MagicString from "magic-string";
|
|
30
30
|
import { connect } from "node:net";
|
|
@@ -386,14 +386,14 @@ function safeParse(schema, value) {
|
|
|
386
386
|
* @returns A schema that decodes to `value` when the field is missing.
|
|
387
387
|
*/
|
|
388
388
|
function defaulted(schema, value) {
|
|
389
|
-
return Type$
|
|
389
|
+
return Type$2.Unsafe(Type$2.Decode(Type$2.Optional({
|
|
390
390
|
...schema,
|
|
391
391
|
default: value
|
|
392
392
|
}), (encoded) => encoded ?? value));
|
|
393
393
|
}
|
|
394
394
|
// src/lib/context.ts
|
|
395
395
|
/** The `port` field of every command that talks to the bridge; the CLI adapter dials the port it holds. */
|
|
396
|
-
const bridgePortField = defaulted(Type$
|
|
396
|
+
const bridgePortField = defaulted(Type$2.Number({ description: "The port the debugger bridge listens on." }), DEFAULT_BRIDGE_PORT);
|
|
397
397
|
/** How long a one-shot command waits for the bridge to report a device before giving up. */
|
|
398
398
|
const DEVICE_WAIT_TIMEOUT_MS = 2e3;
|
|
399
399
|
/** How often the device-wait polls the controller's connection state. */
|
|
@@ -733,50 +733,50 @@ function summary(report, found) {
|
|
|
733
733
|
return parts.length ? `(${parts.join(", ")})` : "";
|
|
734
734
|
}
|
|
735
735
|
// src/lib/inspect-report.ts
|
|
736
|
-
const platformSchema = Type$
|
|
737
|
-
const classReportSchema = Type$
|
|
736
|
+
const platformSchema = Type$2.Enum(["android", "ios"]);
|
|
737
|
+
const classReportSchema = Type$2.Object({
|
|
738
738
|
platform: platformSchema,
|
|
739
|
-
name: Type$
|
|
740
|
-
superclasses: Type$
|
|
741
|
-
interfaces: Type$
|
|
742
|
-
constructors: Type$
|
|
743
|
-
methods: Type$
|
|
744
|
-
name: Type$
|
|
745
|
-
parameters: Type$
|
|
746
|
-
returnType: Type$
|
|
747
|
-
static: Type$
|
|
739
|
+
name: Type$2.String(),
|
|
740
|
+
superclasses: Type$2.Array(Type$2.String()),
|
|
741
|
+
interfaces: Type$2.Array(Type$2.String()),
|
|
742
|
+
constructors: Type$2.Array(Type$2.Array(Type$2.String())),
|
|
743
|
+
methods: Type$2.Array(Type$2.Object({
|
|
744
|
+
name: Type$2.String(),
|
|
745
|
+
parameters: Type$2.Array(Type$2.String()),
|
|
746
|
+
returnType: Type$2.String(),
|
|
747
|
+
static: Type$2.Boolean()
|
|
748
748
|
})),
|
|
749
|
-
fields: Type$
|
|
750
|
-
name: Type$
|
|
751
|
-
type: Type$
|
|
752
|
-
static: Type$
|
|
749
|
+
fields: Type$2.Array(Type$2.Object({
|
|
750
|
+
name: Type$2.String(),
|
|
751
|
+
type: Type$2.String(),
|
|
752
|
+
static: Type$2.Boolean()
|
|
753
753
|
})),
|
|
754
|
-
members: Type$
|
|
754
|
+
members: Type$2.Boolean()
|
|
755
755
|
});
|
|
756
|
-
const viewRecordSchema = Type$
|
|
757
|
-
depth: Type$
|
|
758
|
-
className: Type$
|
|
759
|
-
id: Type$
|
|
760
|
-
width: Type$
|
|
761
|
-
height: Type$
|
|
762
|
-
visibility: Type$
|
|
756
|
+
const viewRecordSchema = Type$2.Object({
|
|
757
|
+
depth: Type$2.Number(),
|
|
758
|
+
className: Type$2.String(),
|
|
759
|
+
id: Type$2.Union([Type$2.String(), Type$2.Null()]),
|
|
760
|
+
width: Type$2.Number(),
|
|
761
|
+
height: Type$2.Number(),
|
|
762
|
+
visibility: Type$2.Enum([
|
|
763
763
|
"visible",
|
|
764
764
|
"invisible",
|
|
765
765
|
"gone",
|
|
766
766
|
"hidden"
|
|
767
767
|
]),
|
|
768
|
-
text: Type$
|
|
769
|
-
handle: Type$
|
|
768
|
+
text: Type$2.Union([Type$2.String(), Type$2.Null()]),
|
|
769
|
+
handle: Type$2.Union([Type$2.String(), Type$2.Null()])
|
|
770
770
|
});
|
|
771
|
-
const viewsReportSchema = Type$
|
|
771
|
+
const viewsReportSchema = Type$2.Object({
|
|
772
772
|
platform: platformSchema,
|
|
773
|
-
roots: Type$
|
|
774
|
-
visited: Type$
|
|
775
|
-
truncated: Type$
|
|
773
|
+
roots: Type$2.Array(Type$2.Array(viewRecordSchema)),
|
|
774
|
+
visited: Type$2.Union([Type$2.Number(), Type$2.Null()]),
|
|
775
|
+
truncated: Type$2.Boolean()
|
|
776
776
|
});
|
|
777
777
|
/** What `inspectNative` answers with on the device, as `ubd inspect` reads it back. */
|
|
778
|
-
const inspectReportSchema = Type$
|
|
779
|
-
Type$
|
|
778
|
+
const inspectReportSchema = Type$2.Union([
|
|
779
|
+
Type$2.Object({ error: Type$2.String() }),
|
|
780
780
|
classReportSchema,
|
|
781
781
|
viewsReportSchema
|
|
782
782
|
]);
|
|
@@ -1092,25 +1092,25 @@ const inspectCommand = {
|
|
|
1092
1092
|
cli: "root",
|
|
1093
1093
|
mcp: true
|
|
1094
1094
|
},
|
|
1095
|
-
schema: Type$
|
|
1096
|
-
what: Type$
|
|
1095
|
+
schema: Type$2.Object({
|
|
1096
|
+
what: Type$2.Enum([
|
|
1097
1097
|
"class",
|
|
1098
1098
|
"views",
|
|
1099
1099
|
"find"
|
|
1100
1100
|
], { description: "What to inspect: class, views or find." }),
|
|
1101
|
-
name: defaulted(Type$
|
|
1102
|
-
class: defaulted(Type$
|
|
1103
|
-
depth: defaulted(Type$
|
|
1101
|
+
name: defaulted(Type$2.String({ description: "The class to describe (class) or to look for (find)." }), ""),
|
|
1102
|
+
class: defaulted(Type$2.String({ description: "For views: dump only the subtrees of attached views of this class." }), ""),
|
|
1103
|
+
depth: defaulted(Type$2.Integer({
|
|
1104
1104
|
minimum: 1,
|
|
1105
1105
|
description: "For views: how deep to print."
|
|
1106
1106
|
}), 40),
|
|
1107
|
-
max: defaulted(Type$
|
|
1107
|
+
max: defaulted(Type$2.Integer({
|
|
1108
1108
|
minimum: 1,
|
|
1109
1109
|
description: "How many views to visit at most."
|
|
1110
1110
|
}), 2e3),
|
|
1111
|
-
filter: defaulted(Type$
|
|
1111
|
+
filter: defaulted(Type$2.String({ description: "For class: keep only constructors, methods and fields whose name contains this." }), ""),
|
|
1112
1112
|
port: bridgePortField,
|
|
1113
|
-
timeout: defaulted(Type$
|
|
1113
|
+
timeout: defaulted(Type$2.Integer({
|
|
1114
1114
|
minimum: 1,
|
|
1115
1115
|
maximum: MAX_EVAL_TIMEOUT_MS,
|
|
1116
1116
|
description: "How long the device may take, in milliseconds."
|
|
@@ -1349,7 +1349,7 @@ const MANIFEST_FILENAME = "manifest.json";
|
|
|
1349
1349
|
/** The file `ubd install` leaves in an installed addon's folder so the client treats it as a development copy. */
|
|
1350
1350
|
const DEVELOPMENT_MARKER = "development";
|
|
1351
1351
|
// ../contracts/src/manifest.ts
|
|
1352
|
-
const semverSchema = Type$
|
|
1352
|
+
const semverSchema = Type$2.String({
|
|
1353
1353
|
maxLength: 64,
|
|
1354
1354
|
pattern: `^${SEMVER_PATTERN}$`,
|
|
1355
1355
|
errorMessage: "Must be a semver version."
|
|
@@ -1358,43 +1358,43 @@ const semverSchema = Type$1.String({
|
|
|
1358
1358
|
* Addon ids become object-storage path segments (`addons/{id}/{version}/...`), so they are limited to
|
|
1359
1359
|
* path-safe characters: alphanumeric runs joined by single `.`, `_` or `-`.
|
|
1360
1360
|
*/
|
|
1361
|
-
const addonIdSchema = Type$
|
|
1361
|
+
const addonIdSchema = Type$2.String({
|
|
1362
1362
|
maxLength: 100,
|
|
1363
1363
|
pattern: ADDON_ID_PATTERN,
|
|
1364
1364
|
errorMessage: "Must be alphanumeric segments joined by \".\", \"_\" or \"-\"."
|
|
1365
1365
|
});
|
|
1366
|
-
const addonMainSchema = Type$
|
|
1366
|
+
const addonMainSchema = Type$2.String({
|
|
1367
1367
|
pattern: ADDON_MAIN_PATTERN,
|
|
1368
1368
|
errorMessage: "Must be a relative path inside the addon."
|
|
1369
1369
|
});
|
|
1370
1370
|
/** Maps each Hermes bytecode version an addon ships to the SHA-512 of that compiled bundle. */
|
|
1371
|
-
const bytecodeDigestsSchema = Type$
|
|
1371
|
+
const bytecodeDigestsSchema = Type$2.Record(Type$2.String({
|
|
1372
1372
|
pattern: "^\\d{1,10}$",
|
|
1373
1373
|
errorMessage: "Must be a Hermes bytecode version."
|
|
1374
|
-
}), Type$
|
|
1374
|
+
}), Type$2.String({
|
|
1375
1375
|
pattern: "^[\\da-f]{128}$",
|
|
1376
1376
|
errorMessage: "Must be a lowercase SHA-512 digest."
|
|
1377
1377
|
}), { additionalProperties: false });
|
|
1378
1378
|
/** Maps each locale a plugin ships beside its bundle, other than en-US, to the SHA-256 of that `i18n/<code>.json`. */
|
|
1379
|
-
const localeDigestsSchema = Type$
|
|
1379
|
+
const localeDigestsSchema = Type$2.Record(Type$2.String({
|
|
1380
1380
|
pattern: LOCALE_CODE_PATTERN,
|
|
1381
1381
|
errorMessage: "Must be a Discord locale code."
|
|
1382
|
-
}), Type$
|
|
1382
|
+
}), Type$2.String({
|
|
1383
1383
|
pattern: "^[\\da-f]{64}$",
|
|
1384
1384
|
errorMessage: "Must be a lowercase SHA-256 digest."
|
|
1385
1385
|
}), { additionalProperties: false });
|
|
1386
1386
|
/** One image a plugin ships: its type, its size in points at scale 1, and the SHA-256 of its file at each scale. */
|
|
1387
|
-
const addonAssetSchema = Type$
|
|
1388
|
-
type: Type$
|
|
1389
|
-
width: Type$
|
|
1387
|
+
const addonAssetSchema = Type$2.Object({
|
|
1388
|
+
type: Type$2.Enum(ASSET_TYPES),
|
|
1389
|
+
width: Type$2.Integer({
|
|
1390
1390
|
minimum: 1,
|
|
1391
1391
|
maximum: 16384
|
|
1392
1392
|
}),
|
|
1393
|
-
height: Type$
|
|
1393
|
+
height: Type$2.Integer({
|
|
1394
1394
|
minimum: 1,
|
|
1395
1395
|
maximum: 16384
|
|
1396
1396
|
}),
|
|
1397
|
-
scales: Type$
|
|
1397
|
+
scales: Type$2.Record(Type$2.Enum(ASSET_SCALES), Type$2.String({
|
|
1398
1398
|
pattern: "^[\\da-f]{64}$",
|
|
1399
1399
|
errorMessage: "Must be a lowercase SHA-256 digest."
|
|
1400
1400
|
}), {
|
|
@@ -1403,46 +1403,46 @@ const addonAssetSchema = Type$1.Object({
|
|
|
1403
1403
|
})
|
|
1404
1404
|
}, { additionalProperties: false });
|
|
1405
1405
|
/** Maps each image a plugin ships, by asset name, to its {@link addonAssetSchema} entry. */
|
|
1406
|
-
const addonAssetsSchema = Type$
|
|
1406
|
+
const addonAssetsSchema = Type$2.Record(Type$2.String({
|
|
1407
1407
|
pattern: ASSET_NAME_PATTERN,
|
|
1408
1408
|
maxLength: 200,
|
|
1409
1409
|
errorMessage: "Must be an asset name."
|
|
1410
1410
|
}), addonAssetSchema, { additionalProperties: false });
|
|
1411
|
-
const addonPlatformsSchema = Type$
|
|
1412
|
-
ios: Type$
|
|
1413
|
-
android: Type$
|
|
1411
|
+
const addonPlatformsSchema = Type$2.Refine(Type$2.Object({
|
|
1412
|
+
ios: Type$2.Optional(Type$2.Object({ capabilities: Type$2.Optional(Type$2.Array(Type$2.Enum(NATIVE_PLUGIN_PLATFORM_CAPABILITIES.ios))) }, { additionalProperties: false })),
|
|
1413
|
+
android: Type$2.Optional(Type$2.Object({ capabilities: Type$2.Optional(Type$2.Array(Type$2.Enum(NATIVE_PLUGIN_PLATFORM_CAPABILITIES.android))) }, { additionalProperties: false }))
|
|
1414
1414
|
}, { additionalProperties: false }), (platforms) => Object.keys(platforms).length > 0, () => "Must list a platform.");
|
|
1415
|
-
const addonAuthorSchema = Type$
|
|
1416
|
-
name: Type$
|
|
1417
|
-
id: Type$
|
|
1415
|
+
const addonAuthorSchema = Type$2.Object({
|
|
1416
|
+
name: Type$2.String({ minLength: 1 }),
|
|
1417
|
+
id: Type$2.Unsafe(Type$2.String({ pattern: "^\\d+$" }))
|
|
1418
1418
|
});
|
|
1419
1419
|
/**
|
|
1420
1420
|
* The manifest an author publishes. Unknown keys pass through untouched, so the stored manifest is
|
|
1421
1421
|
* what the author shipped; only the fields the platform relies on are validated.
|
|
1422
1422
|
*/
|
|
1423
|
-
const addonManifestSchema = Type$
|
|
1423
|
+
const addonManifestSchema = Type$2.Object({
|
|
1424
1424
|
id: addonIdSchema,
|
|
1425
|
-
type: Type$
|
|
1426
|
-
name: Type$
|
|
1427
|
-
description: Type$
|
|
1428
|
-
authors: Type$
|
|
1429
|
-
icon: Type$
|
|
1425
|
+
type: Type$2.Optional(Type$2.Enum(ADDON_KINDS)),
|
|
1426
|
+
name: Type$2.String({ minLength: 1 }),
|
|
1427
|
+
description: Type$2.String(),
|
|
1428
|
+
authors: Type$2.Array(addonAuthorSchema, { minItems: 1 }),
|
|
1429
|
+
icon: Type$2.Optional(Type$2.Union([Type$2.String(), Type$2.Object({ uri: Type$2.String() })])),
|
|
1430
1430
|
main: addonMainSchema,
|
|
1431
1431
|
version: semverSchema,
|
|
1432
1432
|
/** The platforms the addon runs on, each with its capabilities; absent means every platform. */
|
|
1433
|
-
platforms: Type$
|
|
1434
|
-
capabilities: Type$
|
|
1435
|
-
minNativePluginApi: Type$
|
|
1436
|
-
unbound: Type$
|
|
1437
|
-
bytecode: Type$
|
|
1433
|
+
platforms: Type$2.Optional(addonPlatformsSchema),
|
|
1434
|
+
capabilities: Type$2.Optional(Type$2.Array(Type$2.Enum(NATIVE_PLUGIN_CAPABILITIES))),
|
|
1435
|
+
minNativePluginApi: Type$2.Optional(Type$2.String()),
|
|
1436
|
+
unbound: Type$2.Optional(Type$2.Object({ min: Type$2.Optional(semverSchema) })),
|
|
1437
|
+
bytecode: Type$2.Optional(bytecodeDigestsSchema),
|
|
1438
1438
|
/** The locale files `ubd build` emits beside the bundle, by code; en-US is in the bundle. */
|
|
1439
|
-
locales: Type$
|
|
1439
|
+
locales: Type$2.Optional(localeDigestsSchema),
|
|
1440
1440
|
/** The images `ubd build` emits beside the bundle, by asset name. */
|
|
1441
|
-
assets: Type$
|
|
1441
|
+
assets: Type$2.Optional(addonAssetsSchema),
|
|
1442
1442
|
/** Marks a plugin other plugins build on, which the plugin list hides by default. */
|
|
1443
|
-
library: Type$
|
|
1443
|
+
library: Type$2.Optional(Type$2.Boolean()),
|
|
1444
1444
|
/** The addons this one needs, by id, each with the semver range it accepts. */
|
|
1445
|
-
dependencies: Type$
|
|
1445
|
+
dependencies: Type$2.Optional(Type$2.Record(addonIdSchema, Type$2.String({ minLength: 1 }), { additionalProperties: false }))
|
|
1446
1446
|
}, { additionalProperties: true });
|
|
1447
1447
|
// src/lib/device-paths.ts
|
|
1448
1448
|
/** Discord's bundle id on iOS. */
|
|
@@ -3516,17 +3516,17 @@ var import_picomatch = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((
|
|
|
3516
3516
|
/** The workspace config's filename; the directory holding one is a workspace root. */
|
|
3517
3517
|
const CONFIG_FILENAME = "unbound.config.json";
|
|
3518
3518
|
/** The validated shape of an `unbound.config.json`. */
|
|
3519
|
-
const workspaceConfigSchema = Type$
|
|
3520
|
-
$schema: Type$
|
|
3521
|
-
addons: Type$
|
|
3522
|
-
build: Type$
|
|
3523
|
-
output: Type$
|
|
3519
|
+
const workspaceConfigSchema = Type$2.Object({
|
|
3520
|
+
$schema: Type$2.Optional(Type$2.String()),
|
|
3521
|
+
addons: Type$2.Array(Type$2.String(), { default: ["plugins/*", "themes/*"] }),
|
|
3522
|
+
build: Type$2.String({ default: "bun run build" }),
|
|
3523
|
+
output: Type$2.String({ default: "dist" })
|
|
3524
3524
|
});
|
|
3525
|
-
const manifestFieldsSchema = Type$
|
|
3526
|
-
id: Type$
|
|
3527
|
-
main: Type$
|
|
3525
|
+
const manifestFieldsSchema = Type$2.Object({
|
|
3526
|
+
id: Type$2.String(),
|
|
3527
|
+
main: Type$2.String()
|
|
3528
3528
|
});
|
|
3529
|
-
const packageScriptsSchema = Type$
|
|
3529
|
+
const packageScriptsSchema = Type$2.Object({ scripts: Type$2.Optional(Type$2.Object({ build: Type$2.Optional(Type$2.String()) }, { additionalProperties: true })) });
|
|
3530
3530
|
/**
|
|
3531
3531
|
* @description Picks, out of the directories holding a `manifest.json`, the ones the workspace registers.
|
|
3532
3532
|
* @param config The workspace config.
|
|
@@ -3663,9 +3663,9 @@ function toError(error) {
|
|
|
3663
3663
|
return error instanceof Error ? error : new Error(String(error));
|
|
3664
3664
|
}
|
|
3665
3665
|
// src/lib/manifest.ts
|
|
3666
|
-
const devManifestSchema = Type$
|
|
3667
|
-
id: Type$
|
|
3668
|
-
main: Type$
|
|
3666
|
+
const devManifestSchema = Type$2.Unsafe(Type$2.Object({
|
|
3667
|
+
id: Type$2.String(),
|
|
3668
|
+
main: Type$2.String()
|
|
3669
3669
|
}, { additionalProperties: true }));
|
|
3670
3670
|
function readWith(dir, schema) {
|
|
3671
3671
|
const path = join(dir, MANIFEST_FILENAME);
|
|
@@ -3789,24 +3789,32 @@ function sha512Digests(compiled) {
|
|
|
3789
3789
|
// src/lib/plugin-install.ts
|
|
3790
3790
|
const SAFE_ADDON_ID = /^[\w.-]+$/;
|
|
3791
3791
|
/**
|
|
3792
|
-
* @description Lists the built files a plugin install copies onto a device: its manifest, bundle
|
|
3792
|
+
* @description Lists the built files a plugin install copies onto a device: its manifest, bundle, Hermes bytecode and the
|
|
3793
|
+
* extra files the manifest lists. The manifest copied names each bytecode file's digest, which the loader checks before it
|
|
3794
|
+
* runs the bytecode instead of compiling the source.
|
|
3793
3795
|
* @param addon The built plugin.
|
|
3794
3796
|
* @returns The plugin's id and files, or why its id cannot be used as a folder name on the device.
|
|
3795
3797
|
*/
|
|
3796
3798
|
function readPluginPayload(addon) {
|
|
3797
3799
|
if (!SAFE_ADDON_ID.test(addon.id)) return { error: `${addon.id} is not a valid plugin id for a device folder.` };
|
|
3798
|
-
const { manifest } = readBuiltAddon(addon);
|
|
3800
|
+
const { manifest, bytecode = {} } = readBuiltAddon(addon);
|
|
3801
|
+
const bundle = getBundleName(addon.static, manifest.main);
|
|
3799
3802
|
const names = [
|
|
3800
|
-
|
|
3801
|
-
|
|
3803
|
+
bundle,
|
|
3804
|
+
...Object.keys(bytecode).map((version) => bytecodeFileName(bundle, Number(version))),
|
|
3802
3805
|
...listAddonFiles(manifest).map((file) => file.path)
|
|
3803
3806
|
];
|
|
3807
|
+
const staged = join(mkdtempSync(join(tmpdir(), "ubd-install-")), MANIFEST_FILENAME);
|
|
3808
|
+
writeFileSync(staged, JSON.stringify(manifest, null, " "));
|
|
3804
3809
|
return {
|
|
3805
3810
|
id: addon.id,
|
|
3806
|
-
files:
|
|
3811
|
+
files: [{
|
|
3812
|
+
name: MANIFEST_FILENAME,
|
|
3813
|
+
path: staged
|
|
3814
|
+
}, ...names.map((name) => ({
|
|
3807
3815
|
name,
|
|
3808
3816
|
path: join(addon.output, name)
|
|
3809
|
-
}))
|
|
3817
|
+
}))]
|
|
3810
3818
|
};
|
|
3811
3819
|
}
|
|
3812
3820
|
/**
|
|
@@ -12248,51 +12256,51 @@ function splitFrontmatter(source) {
|
|
|
12248
12256
|
// ../contracts/src/addon-page.ts
|
|
12249
12257
|
const UNDOTTED_SEGMENT = String.raw`[\w-][\w.-]*`;
|
|
12250
12258
|
const MEDIA_PATH = new RegExp(String.raw`^media/(?:${UNDOTTED_SEGMENT}/)*${UNDOTTED_SEGMENT}$`);
|
|
12251
|
-
const mediaPathSchema = Type$
|
|
12259
|
+
const mediaPathSchema = Type$2.Refine(Type$2.String({
|
|
12252
12260
|
maxLength: 200,
|
|
12253
12261
|
pattern: MEDIA_PATH,
|
|
12254
12262
|
errorMessage: "Must be a relative path inside the media/ folder."
|
|
12255
12263
|
}), (path) => getMediaKind(path) !== void 0, () => `Must end in ${Object.keys(MEDIA_EXTENSIONS).join(", ")}.`);
|
|
12256
|
-
const imagePathSchema = Type$
|
|
12257
|
-
const videoPathSchema = Type$
|
|
12264
|
+
const imagePathSchema = Type$2.Refine(mediaPathSchema, (path) => getMediaKind(path) === "image", () => "Must be an image.");
|
|
12265
|
+
const videoPathSchema = Type$2.Refine(mediaPathSchema, (path) => getMediaKind(path) === "video", () => "Must be a video.");
|
|
12258
12266
|
const altSchema = trimmedString(...ALT_CHECKS);
|
|
12259
12267
|
/** One gallery entry: an image, or a video with an optional poster image. */
|
|
12260
|
-
const pageMediaSchema = Type$
|
|
12268
|
+
const pageMediaSchema = Type$2.Union([Type$2.Object({
|
|
12261
12269
|
image: imagePathSchema,
|
|
12262
12270
|
alt: altSchema
|
|
12263
|
-
}, { additionalProperties: false }), Type$
|
|
12271
|
+
}, { additionalProperties: false }), Type$2.Object({
|
|
12264
12272
|
video: videoPathSchema,
|
|
12265
|
-
poster: Type$
|
|
12273
|
+
poster: Type$2.Optional(imagePathSchema),
|
|
12266
12274
|
alt: altSchema
|
|
12267
12275
|
}, { additionalProperties: false })]);
|
|
12268
12276
|
/** The YAML frontmatter of ADDON.md. The title and description come from the manifest, so neither is allowed. */
|
|
12269
|
-
const addonPageFrontmatterSchema = Type$
|
|
12277
|
+
const addonPageFrontmatterSchema = Type$2.Object({
|
|
12270
12278
|
banner: imagePathSchema,
|
|
12271
|
-
media: Type$
|
|
12279
|
+
media: Type$2.Array(pageMediaSchema, {
|
|
12272
12280
|
maxItems: 20,
|
|
12273
12281
|
default: []
|
|
12274
12282
|
})
|
|
12275
12283
|
}, { additionalProperties: false });
|
|
12276
|
-
const pixelsSchema = Type$
|
|
12284
|
+
const pixelsSchema = Type$2.Integer({ exclusiveMinimum: 0 });
|
|
12277
12285
|
/** One media file as `ubd build` measured it. */
|
|
12278
|
-
const measuredMediaSchema = Type$
|
|
12286
|
+
const measuredMediaSchema = Type$2.Refine(Type$2.Refine(Type$2.Object({
|
|
12279
12287
|
path: mediaPathSchema,
|
|
12280
|
-
kind: Type$
|
|
12288
|
+
kind: Type$2.Enum(MEDIA_KINDS),
|
|
12281
12289
|
width: pixelsSchema,
|
|
12282
12290
|
height: pixelsSchema,
|
|
12283
12291
|
/** The video's length in seconds. */
|
|
12284
|
-
duration: Type$
|
|
12292
|
+
duration: Type$2.Optional(Type$2.Number({ exclusiveMinimum: 0 })),
|
|
12285
12293
|
/** The base64 ThumbHash placeholder shown while the file loads. */
|
|
12286
|
-
thumbhash: Type$
|
|
12294
|
+
thumbhash: Type$2.String({
|
|
12287
12295
|
pattern: /^[A-Za-z0-9+/]{1,64}={0,2}$/,
|
|
12288
12296
|
errorMessage: "Must be base64."
|
|
12289
12297
|
}),
|
|
12290
|
-
bytes: Type$
|
|
12298
|
+
bytes: Type$2.Integer({ exclusiveMinimum: 0 })
|
|
12291
12299
|
}), (media) => media.kind === getMediaKind(media.path), () => "The kind must match the file extension."), (media) => media.kind === "video" || media.duration === void 0, () => "Only a video has a duration.");
|
|
12292
12300
|
/** The measured page `ubd build` writes to `{output}/page.json`: the frontmatter and every media file it measured. */
|
|
12293
|
-
const addonPageSchema = superRefine(Type$
|
|
12301
|
+
const addonPageSchema = superRefine(Type$2.Object({
|
|
12294
12302
|
frontmatter: addonPageFrontmatterSchema,
|
|
12295
|
-
media: Type$
|
|
12303
|
+
media: Type$2.Array(measuredMediaSchema)
|
|
12296
12304
|
}), measuredPageIssues);
|
|
12297
12305
|
/**
|
|
12298
12306
|
* @description Reads ADDON.md's frontmatter as YAML and validates it against the page contract.
|
|
@@ -12370,16 +12378,16 @@ const VIDEO_CODECS = {
|
|
|
12370
12378
|
]
|
|
12371
12379
|
};
|
|
12372
12380
|
const execFileAsync = promisify(execFile);
|
|
12373
|
-
const ffprobeSchema = Type$
|
|
12374
|
-
streams: Type$
|
|
12375
|
-
codec_name: Type$
|
|
12376
|
-
width: Type$
|
|
12377
|
-
height: Type$
|
|
12378
|
-
side_data_list: Type$
|
|
12381
|
+
const ffprobeSchema = Type$2.Object({
|
|
12382
|
+
streams: Type$2.Array(Type$2.Object({
|
|
12383
|
+
codec_name: Type$2.String(),
|
|
12384
|
+
width: Type$2.Number(),
|
|
12385
|
+
height: Type$2.Number(),
|
|
12386
|
+
side_data_list: Type$2.Optional(Type$2.Array(Type$2.Object({ rotation: Type$2.Optional(Type$2.Number()) })))
|
|
12379
12387
|
}), { minItems: 1 }),
|
|
12380
|
-
format: Type$
|
|
12381
|
-
format_name: Type$
|
|
12382
|
-
duration: Type$
|
|
12388
|
+
format: Type$2.Object({
|
|
12389
|
+
format_name: Type$2.String(),
|
|
12390
|
+
duration: Type$2.Optional(Type$2.Unknown())
|
|
12383
12391
|
})
|
|
12384
12392
|
});
|
|
12385
12393
|
/**
|
|
@@ -12518,27 +12526,27 @@ function describeError(error) {
|
|
|
12518
12526
|
}
|
|
12519
12527
|
// ../contracts/src/api.ts
|
|
12520
12528
|
/** The origin of the Unbound web API, reduced from any http(s) URL; production when unset. */
|
|
12521
|
-
const apiUrlSchema = Type$
|
|
12529
|
+
const apiUrlSchema = Type$2.Codec(Type$2.String({
|
|
12522
12530
|
format: "url",
|
|
12523
12531
|
pattern: /^https?:\/\//i,
|
|
12524
12532
|
default: "https://unbound.rip"
|
|
12525
12533
|
})).Decode((url) => new URL(url).origin).Encode((origin) => String(origin));
|
|
12526
12534
|
// src/lib/env.ts
|
|
12527
|
-
const schema$9 = Type$
|
|
12535
|
+
const schema$9 = Type$2.Object({
|
|
12528
12536
|
/** The origin of the Unbound web API that `ubd login` and `ubd publish` talk to. */
|
|
12529
12537
|
UNBOUND_API_URL: apiUrlSchema,
|
|
12530
12538
|
/** An API key for CI; when set, `ubd publish` sends it instead of the stored login. */
|
|
12531
|
-
UNBOUND_API_KEY: Type$
|
|
12532
|
-
XDG_CONFIG_HOME: Type$
|
|
12539
|
+
UNBOUND_API_KEY: Type$2.Optional(Type$2.String({ minLength: 1 })),
|
|
12540
|
+
XDG_CONFIG_HOME: Type$2.Optional(Type$2.String({ minLength: 1 }))
|
|
12533
12541
|
});
|
|
12534
|
-
const positiveInteger = Type$
|
|
12535
|
-
const mediaLimitsSource = Type$
|
|
12542
|
+
const positiveInteger = Type$2.Refine(Type$2.String(), (value) => Number.isInteger(Number(value)) && Number(value) > 0, () => "Too small: expected number to be >0");
|
|
12543
|
+
const mediaLimitsSource = Type$2.Object({
|
|
12536
12544
|
/** The largest media file ADDON.md may reference, in bytes. */
|
|
12537
|
-
ADDON_MEDIA_MAX_BYTES: Type$
|
|
12545
|
+
ADDON_MEDIA_MAX_BYTES: Type$2.Optional(positiveInteger),
|
|
12538
12546
|
/** The most bytes all of an addon's media may take together. */
|
|
12539
|
-
ADDON_MEDIA_TOTAL_MAX_BYTES: Type$
|
|
12547
|
+
ADDON_MEDIA_TOTAL_MAX_BYTES: Type$2.Optional(positiveInteger)
|
|
12540
12548
|
});
|
|
12541
|
-
const mediaLimitsSchema = Type$
|
|
12549
|
+
const mediaLimitsSchema = Type$2.Decode(mediaLimitsSource, (raw) => ({
|
|
12542
12550
|
ADDON_MEDIA_MAX_BYTES: Number(raw.ADDON_MEDIA_MAX_BYTES ?? 10485760),
|
|
12543
12551
|
ADDON_MEDIA_TOTAL_MAX_BYTES: Number(raw.ADDON_MEDIA_TOTAL_MAX_BYTES ?? 52428800)
|
|
12544
12552
|
}));
|
|
@@ -12797,15 +12805,15 @@ const IOS_TIMEOUTS = {
|
|
|
12797
12805
|
restart: 6e4
|
|
12798
12806
|
};
|
|
12799
12807
|
const DEVICE_TIMEOUT_GRACE_MS = 1e4;
|
|
12800
|
-
const shellOutputSchema = Type$
|
|
12801
|
-
exitCode: Type$
|
|
12802
|
-
output: Type$
|
|
12808
|
+
const shellOutputSchema = Type$2.Object({
|
|
12809
|
+
exitCode: Type$2.Optional(Type$2.Number()),
|
|
12810
|
+
output: Type$2.Optional(Type$2.String())
|
|
12803
12811
|
});
|
|
12804
|
-
const deviceListSchema = Type$
|
|
12805
|
-
id: Type$
|
|
12806
|
-
bridge: Type$
|
|
12812
|
+
const deviceListSchema = Type$2.Object({ devices: Type$2.Optional(Type$2.Array(Type$2.Object({
|
|
12813
|
+
id: Type$2.Unknown(),
|
|
12814
|
+
bridge: Type$2.Optional(Type$2.Boolean())
|
|
12807
12815
|
}))) });
|
|
12808
|
-
const appContainerSchema = Type$
|
|
12816
|
+
const appContainerSchema = Type$2.Object({ dataContainer: Type$2.Optional(Type$2.String()) });
|
|
12809
12817
|
/**
|
|
12810
12818
|
* @description Finds the `jb-p1lot` binary on the PATH, falling back to Go's install directory.
|
|
12811
12819
|
* @param env The environment to read `PATH` and `GOPATH` from.
|
|
@@ -13069,13 +13077,13 @@ const installCommand = {
|
|
|
13069
13077
|
cli: "root",
|
|
13070
13078
|
mcp: true
|
|
13071
13079
|
},
|
|
13072
|
-
schema: Type$
|
|
13073
|
-
addon: defaulted(Type$
|
|
13074
|
-
build: defaulted(Type$
|
|
13075
|
-
serial: Type$
|
|
13076
|
-
ios: defaulted(Type$
|
|
13077
|
-
udid: Type$
|
|
13078
|
-
restart: defaulted(Type$
|
|
13080
|
+
schema: Type$2.Object({
|
|
13081
|
+
addon: defaulted(Type$2.String({ description: "The plugin to install, as its manifest id or directory." }), "."),
|
|
13082
|
+
build: defaulted(Type$2.Boolean({ description: "Build the plugin before installing it." }), true),
|
|
13083
|
+
serial: Type$2.Optional(Type$2.String({ description: "The adb serial of the Android device, when several are attached." })),
|
|
13084
|
+
ios: defaulted(Type$2.Boolean({ description: "Install on a jailbroken iPhone through jb-p1lot instead of over adb." }), false),
|
|
13085
|
+
udid: Type$2.Optional(Type$2.String({ description: "The UDID of the iPhone, when several are connected. Implies --ios." })),
|
|
13086
|
+
restart: defaulted(Type$2.Boolean({ description: "Restart Discord afterwards so it loads the plugin." }), false)
|
|
13079
13087
|
}),
|
|
13080
13088
|
cli: { positionals: ["addon"] },
|
|
13081
13089
|
async handler({ addon: target, build, serial, ios, udid, restart }) {
|
|
@@ -13239,9 +13247,9 @@ function migrateEntry(code, id) {
|
|
|
13239
13247
|
};
|
|
13240
13248
|
}
|
|
13241
13249
|
// src/commands/migrate.ts
|
|
13242
|
-
const schema$8 = Type$
|
|
13243
|
-
what: Type$
|
|
13244
|
-
dir: defaulted(Type$
|
|
13250
|
+
const schema$8 = Type$2.Object({
|
|
13251
|
+
what: Type$2.Enum(["entry"], { description: "What to migrate: entry." }),
|
|
13252
|
+
dir: defaulted(Type$2.String({ description: "A plugin folder, or a folder of plugins, whose src/index entries to migrate." }), ".")
|
|
13245
13253
|
});
|
|
13246
13254
|
function entriesIn(dir) {
|
|
13247
13255
|
const own = findFile(resolve(dir, "src", "index"));
|
|
@@ -13608,9 +13616,9 @@ const modulesCommand = {
|
|
|
13608
13616
|
cli: "root",
|
|
13609
13617
|
mcp: true
|
|
13610
13618
|
},
|
|
13611
|
-
schema: Type$
|
|
13612
|
-
pattern: Type$
|
|
13613
|
-
max: defaulted(Type$
|
|
13619
|
+
schema: Type$2.Object({
|
|
13620
|
+
pattern: Type$2.String({ description: "A case-insensitive regular expression for file paths or export names." }),
|
|
13621
|
+
max: defaulted(Type$2.Number({ description: "How many modules to list." }), 40),
|
|
13614
13622
|
port: bridgePortField
|
|
13615
13623
|
}),
|
|
13616
13624
|
cli: { positionals: ["pattern"] },
|
|
@@ -13619,16 +13627,16 @@ const modulesCommand = {
|
|
|
13619
13627
|
}
|
|
13620
13628
|
};
|
|
13621
13629
|
// src/lib/profile-summary.ts
|
|
13622
|
-
const frameId = Type$
|
|
13623
|
-
const stackFrameSchema = Type$
|
|
13624
|
-
name: Type$
|
|
13625
|
-
category: Type$
|
|
13626
|
-
parent: Type$
|
|
13630
|
+
const frameId = Type$2.Union([Type$2.String(), Type$2.Number()]);
|
|
13631
|
+
const stackFrameSchema = Type$2.Object({
|
|
13632
|
+
name: Type$2.Optional(Type$2.String()),
|
|
13633
|
+
category: Type$2.Optional(Type$2.String()),
|
|
13634
|
+
parent: Type$2.Optional(frameId)
|
|
13627
13635
|
});
|
|
13628
13636
|
/** The parts of a Hermes sampled Chrome trace the summary reads. */
|
|
13629
|
-
const chromeTraceSchema = Type$
|
|
13630
|
-
samples: defaulted(Type$
|
|
13631
|
-
stackFrames: defaulted(Type$
|
|
13637
|
+
const chromeTraceSchema = Type$2.Object({
|
|
13638
|
+
samples: defaulted(Type$2.Array(Type$2.Object({ sf: Type$2.Optional(frameId) })), []),
|
|
13639
|
+
stackFrames: defaulted(Type$2.Record(Type$2.String(), stackFrameSchema), {})
|
|
13632
13640
|
});
|
|
13633
13641
|
const NATIVE_FRAME_HOPS = 16;
|
|
13634
13642
|
function javaScriptFrame(frames, id) {
|
|
@@ -13723,17 +13731,17 @@ function formatProfile(summary) {
|
|
|
13723
13731
|
}
|
|
13724
13732
|
// src/commands/profile.ts
|
|
13725
13733
|
const RESULT_GRACE_MS = 1e4;
|
|
13726
|
-
const schema$7 = Type$
|
|
13727
|
-
duration: defaulted(Type$
|
|
13734
|
+
const schema$7 = Type$2.Object({
|
|
13735
|
+
duration: defaulted(Type$2.Integer({
|
|
13728
13736
|
minimum: 1,
|
|
13729
13737
|
maximum: 6e4,
|
|
13730
13738
|
description: "How long to sample the JavaScript thread, in milliseconds."
|
|
13731
13739
|
}), 5e3),
|
|
13732
|
-
top: defaulted(Type$
|
|
13740
|
+
top: defaulted(Type$2.Integer({
|
|
13733
13741
|
minimum: 1,
|
|
13734
13742
|
description: "How many functions and sources to list."
|
|
13735
13743
|
}), 20),
|
|
13736
|
-
out: defaulted(Type$
|
|
13744
|
+
out: defaulted(Type$2.String({ description: "Also save the raw Chrome trace here, to open in Perfetto or chrome://tracing." }), ""),
|
|
13737
13745
|
port: bridgePortField
|
|
13738
13746
|
});
|
|
13739
13747
|
async function recordProfile(_unbound, duration) {
|
|
@@ -13912,16 +13920,16 @@ const CHANGE_TYPES = [
|
|
|
13912
13920
|
"fixed",
|
|
13913
13921
|
"removed"
|
|
13914
13922
|
];
|
|
13915
|
-
const changeTypeSchema = Type$
|
|
13923
|
+
const changeTypeSchema = Type$2.Enum(CHANGE_TYPES);
|
|
13916
13924
|
/** An unknown type reads as `changed`, so an older client keeps rendering a newer changelog. */
|
|
13917
|
-
const changeTypeValueSchema = Type$
|
|
13925
|
+
const changeTypeValueSchema = Type$2.Codec(Type$2.Any()).Decode((value) => {
|
|
13918
13926
|
const parsed = safeParse(changeTypeSchema, value);
|
|
13919
13927
|
return parsed.success ? parsed.data : "changed";
|
|
13920
13928
|
}).Encode((value) => value);
|
|
13921
13929
|
/** One `### Type` block. Items are plain text; a type this client does not know reads as `changed`. */
|
|
13922
|
-
const changelogSectionSchema = Type$
|
|
13930
|
+
const changelogSectionSchema = Type$2.Object({
|
|
13923
13931
|
type: changeTypeValueSchema,
|
|
13924
|
-
items: Type$
|
|
13932
|
+
items: Type$2.Array(Type$2.String({
|
|
13925
13933
|
minLength: 1,
|
|
13926
13934
|
maxLength: 500
|
|
13927
13935
|
}), {
|
|
@@ -13929,9 +13937,9 @@ const changelogSectionSchema = Type$1.Object({
|
|
|
13929
13937
|
maxItems: 50
|
|
13930
13938
|
})
|
|
13931
13939
|
});
|
|
13932
|
-
Type$
|
|
13933
|
-
date: Type$
|
|
13934
|
-
sections: Type$
|
|
13940
|
+
Type$2.Object({
|
|
13941
|
+
date: Type$2.Union([Type$2.String({ format: "date" }), Type$2.Null()]),
|
|
13942
|
+
sections: Type$2.Array(changelogSectionSchema, { maxItems: CHANGE_TYPES.length })
|
|
13935
13943
|
});
|
|
13936
13944
|
const MAX_ITEMS = 50;
|
|
13937
13945
|
const MAX_ITEM_LENGTH = 500;
|
|
@@ -13943,7 +13951,7 @@ const FOLDED_HEADINGS = {
|
|
|
13943
13951
|
const RELEASE_HEADING = /^(?:\[([^\]]+)\]|([^\s[\]]+))(?:\s+-\s+(\S+))?$/;
|
|
13944
13952
|
const LINK_DEFINITION = /^\[[^\]]+\]:\s*\S+/;
|
|
13945
13953
|
const BULLET = /^[-*](?:\s+(.*))?$/;
|
|
13946
|
-
const ISO_DATE = Type$
|
|
13954
|
+
const ISO_DATE = Type$2.String({ format: "date" });
|
|
13947
13955
|
/**
|
|
13948
13956
|
* @description Parses a `CHANGELOG.md`, collecting every issue instead of stopping at the first. Never throws.
|
|
13949
13957
|
* @param text The file's text.
|
|
@@ -14121,14 +14129,14 @@ function addIssue(parser, line, message) {
|
|
|
14121
14129
|
});
|
|
14122
14130
|
}
|
|
14123
14131
|
// ../contracts/src/errors.ts
|
|
14124
|
-
const apiErrorCodeSchema = Type$
|
|
14125
|
-
Type$
|
|
14132
|
+
const apiErrorCodeSchema = Type$2.Enum([...API_ERROR_CODES]);
|
|
14133
|
+
Type$2.Object({ error: Type$2.Object({
|
|
14126
14134
|
code: apiErrorCodeSchema,
|
|
14127
|
-
message: Type$
|
|
14135
|
+
message: Type$2.String()
|
|
14128
14136
|
}) });
|
|
14129
14137
|
// ../contracts/src/source.ts
|
|
14130
14138
|
/** A GitHub repository as `owner/name`. */
|
|
14131
|
-
const repositorySchema = Type$
|
|
14139
|
+
const repositorySchema = Type$2.String({
|
|
14132
14140
|
pattern: /^[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\/[A-Za-z0-9._-]+$/,
|
|
14133
14141
|
errorMessage: "Must be a GitHub owner/name."
|
|
14134
14142
|
});
|
|
@@ -14166,139 +14174,139 @@ function readRepository$1(input) {
|
|
|
14166
14174
|
return parseRepository(input)?.repository ?? input;
|
|
14167
14175
|
}
|
|
14168
14176
|
/** Accepts every form {@link parseRepository} reads and outputs `owner/name`. */
|
|
14169
|
-
const repositoryInputSchema = Type$
|
|
14177
|
+
const repositoryInputSchema = Type$2.Codec(Type$2.Refine(Type$2.String({ maxLength: 300 }), (input) => parseRepository(input) !== void 0, () => "Must be a GitHub repository URL or owner/name.")).Decode((input) => readRepository$1(input)).Encode((repository) => repository);
|
|
14170
14178
|
/** A full, lowercase git object id. */
|
|
14171
|
-
const commitShaSchema = Type$
|
|
14179
|
+
const commitShaSchema = Type$2.String({
|
|
14172
14180
|
pattern: /^[0-9a-f]{40}$/,
|
|
14173
14181
|
errorMessage: "Must be a full commit SHA."
|
|
14174
14182
|
});
|
|
14175
14183
|
/** A branch, tag or full commit SHA. */
|
|
14176
|
-
const gitRefSchema = Type$
|
|
14184
|
+
const gitRefSchema = Type$2.String({
|
|
14177
14185
|
minLength: 1,
|
|
14178
14186
|
maxLength: 255,
|
|
14179
14187
|
pattern: /^[^\s~^:?*[\\]+$/,
|
|
14180
14188
|
errorMessage: "Must be a branch, tag or commit SHA."
|
|
14181
14189
|
});
|
|
14182
14190
|
/** An addon directory relative to the repository root, `/`-separated; `''` is the root. */
|
|
14183
|
-
const addonPathSchema = Type$
|
|
14191
|
+
const addonPathSchema = Type$2.Refine(Type$2.String({
|
|
14184
14192
|
maxLength: 255,
|
|
14185
14193
|
pattern: /^(?:[\w.-]+(?:\/[\w.-]+)*)?$/,
|
|
14186
14194
|
errorMessage: "Must be a directory inside the repository."
|
|
14187
14195
|
}), (path) => !path.split("/").includes(".."), () => "Must stay inside the repository.");
|
|
14188
14196
|
/** Where a submitted version was read from: everything a reviewer needs to find the exact bytes. */
|
|
14189
|
-
const sourcePinSchema = Type$
|
|
14197
|
+
const sourcePinSchema = Type$2.Object({
|
|
14190
14198
|
repository: repositorySchema,
|
|
14191
14199
|
/** GitHub's numeric id, which survives renames and transfers. */
|
|
14192
|
-
repositoryId: Type$
|
|
14200
|
+
repositoryId: Type$2.Integer({ exclusiveMinimum: 0 }),
|
|
14193
14201
|
path: addonPathSchema,
|
|
14194
14202
|
/** The branch, tag or SHA the author named; `commitSha` is what it resolved to. */
|
|
14195
14203
|
ref: gitRefSchema,
|
|
14196
14204
|
commitSha: commitShaSchema,
|
|
14197
14205
|
/** The shipped file, relative to the repository root. */
|
|
14198
|
-
bundlePath: Type$
|
|
14206
|
+
bundlePath: Type$2.String({ minLength: 1 }),
|
|
14199
14207
|
/** The git blob id of `bundlePath` at `commitSha`. */
|
|
14200
14208
|
bundleBlobSha: commitShaSchema
|
|
14201
14209
|
});
|
|
14202
|
-
const repositoryContributorSchema = Type$
|
|
14203
|
-
login: Type$
|
|
14204
|
-
contributions: Type$
|
|
14210
|
+
const repositoryContributorSchema = Type$2.Object({
|
|
14211
|
+
login: Type$2.String({ minLength: 1 }),
|
|
14212
|
+
contributions: Type$2.Integer({ minimum: 0 })
|
|
14205
14213
|
});
|
|
14206
|
-
const repositoryReleaseSchema = Type$
|
|
14207
|
-
tag: Type$
|
|
14208
|
-
name: Type$
|
|
14209
|
-
publishedAt: Type$
|
|
14210
|
-
url: Type$
|
|
14214
|
+
const repositoryReleaseSchema = Type$2.Object({
|
|
14215
|
+
tag: Type$2.String({ minLength: 1 }),
|
|
14216
|
+
name: Type$2.Union([Type$2.String(), Type$2.Null()]),
|
|
14217
|
+
publishedAt: Type$2.Union([Type$2.String({ format: "date-time" }), Type$2.Null()]),
|
|
14218
|
+
url: Type$2.String({ format: "url" })
|
|
14211
14219
|
});
|
|
14212
14220
|
/** What GitHub said about the repository when the version was submitted; never refreshed live. */
|
|
14213
|
-
const repositoryDetailsSchema = Type$
|
|
14214
|
-
description: Type$
|
|
14215
|
-
homepage: Type$
|
|
14216
|
-
tags: Type$
|
|
14221
|
+
const repositoryDetailsSchema = Type$2.Object({
|
|
14222
|
+
description: Type$2.Union([Type$2.String(), Type$2.Null()]),
|
|
14223
|
+
homepage: Type$2.Union([Type$2.String({ format: "url" }), Type$2.Null()]),
|
|
14224
|
+
tags: Type$2.Array(Type$2.String({
|
|
14217
14225
|
minLength: 1,
|
|
14218
14226
|
maxLength: 50
|
|
14219
14227
|
}), { maxItems: 20 }),
|
|
14220
14228
|
/** An SPDX id such as `MIT`, or `null` when GitHub detected none. */
|
|
14221
|
-
license: Type$
|
|
14222
|
-
stars: Type$
|
|
14223
|
-
defaultBranch: Type$
|
|
14224
|
-
htmlUrl: Type$
|
|
14225
|
-
readmeUrl: Type$
|
|
14226
|
-
contributors: Type$
|
|
14227
|
-
latestRelease: Type$
|
|
14229
|
+
license: Type$2.Union([Type$2.String(), Type$2.Null()]),
|
|
14230
|
+
stars: Type$2.Integer({ minimum: 0 }),
|
|
14231
|
+
defaultBranch: Type$2.String({ minLength: 1 }),
|
|
14232
|
+
htmlUrl: Type$2.String({ format: "url" }),
|
|
14233
|
+
readmeUrl: Type$2.Union([Type$2.String({ format: "url" }), Type$2.Null()]),
|
|
14234
|
+
contributors: Type$2.Array(repositoryContributorSchema, { maxItems: 10 }),
|
|
14235
|
+
latestRelease: Type$2.Union([repositoryReleaseSchema, Type$2.Null()])
|
|
14228
14236
|
});
|
|
14229
14237
|
/** Why an addon cannot be submitted, with the code the submission itself would fail with. */
|
|
14230
|
-
const repositoryAddonIssueSchema = Type$
|
|
14238
|
+
const repositoryAddonIssueSchema = Type$2.Object({
|
|
14231
14239
|
code: apiErrorCodeSchema,
|
|
14232
|
-
message: Type$
|
|
14240
|
+
message: Type$2.String()
|
|
14233
14241
|
});
|
|
14234
14242
|
/** One addon a repository registers at a commit, as the repository picker lists it. */
|
|
14235
|
-
const repositoryAddonSchema = Type$
|
|
14236
|
-
id: Type$
|
|
14243
|
+
const repositoryAddonSchema = Type$2.Object({
|
|
14244
|
+
id: Type$2.String(),
|
|
14237
14245
|
/** `null` when the manifest does not pass the manifest contract; `issues` says why. */
|
|
14238
|
-
name: Type$
|
|
14239
|
-
version: Type$
|
|
14240
|
-
kind: Type$
|
|
14246
|
+
name: Type$2.Union([Type$2.String(), Type$2.Null()]),
|
|
14247
|
+
version: Type$2.Union([Type$2.String(), Type$2.Null()]),
|
|
14248
|
+
kind: Type$2.Enum(["plugin", "theme"]),
|
|
14241
14249
|
path: addonPathSchema,
|
|
14242
|
-
static: Type$
|
|
14250
|
+
static: Type$2.Boolean(),
|
|
14243
14251
|
/** The file that ships, relative to the repository root. */
|
|
14244
|
-
bundle: Type$
|
|
14245
|
-
hasAddonMd: Type$
|
|
14246
|
-
hasChangelog: Type$
|
|
14252
|
+
bundle: Type$2.String(),
|
|
14253
|
+
hasAddonMd: Type$2.Boolean(),
|
|
14254
|
+
hasChangelog: Type$2.Boolean(),
|
|
14247
14255
|
/** Why the addon cannot be submitted at this commit as it is; empty when it can. */
|
|
14248
|
-
issues: Type$
|
|
14256
|
+
issues: Type$2.Array(repositoryAddonIssueSchema),
|
|
14249
14257
|
/** This version is already published, so there is nothing new to submit. */
|
|
14250
|
-
upToDate: Type$
|
|
14258
|
+
upToDate: Type$2.Boolean()
|
|
14251
14259
|
});
|
|
14252
14260
|
/** A directory a workspace registers that is not an addon, and why. */
|
|
14253
|
-
const skippedDirectorySchema = Type$
|
|
14254
|
-
path: Type$
|
|
14255
|
-
reason: Type$
|
|
14261
|
+
const skippedDirectorySchema = Type$2.Object({
|
|
14262
|
+
path: Type$2.String(),
|
|
14263
|
+
reason: Type$2.String()
|
|
14256
14264
|
});
|
|
14257
|
-
Type$
|
|
14265
|
+
Type$2.Object({
|
|
14258
14266
|
repository: repositoryInputSchema,
|
|
14259
14267
|
/** Defaults to the repository's default branch. */
|
|
14260
|
-
ref: Type$
|
|
14268
|
+
ref: Type$2.Optional(gitRefSchema)
|
|
14261
14269
|
});
|
|
14262
|
-
Type$
|
|
14270
|
+
Type$2.Object({
|
|
14263
14271
|
repository: repositorySchema,
|
|
14264
14272
|
ref: gitRefSchema,
|
|
14265
14273
|
commitSha: commitShaSchema,
|
|
14266
14274
|
details: repositoryDetailsSchema,
|
|
14267
|
-
addons: Type$
|
|
14268
|
-
skipped: Type$
|
|
14275
|
+
addons: Type$2.Array(repositoryAddonSchema),
|
|
14276
|
+
skipped: Type$2.Array(skippedDirectorySchema)
|
|
14269
14277
|
});
|
|
14270
14278
|
/** A public repository the caller's linked GitHub account can push to. */
|
|
14271
|
-
const pushableRepositorySchema = Type$
|
|
14279
|
+
const pushableRepositorySchema = Type$2.Object({
|
|
14272
14280
|
repository: repositorySchema,
|
|
14273
|
-
description: Type$
|
|
14274
|
-
pushedAt: Type$
|
|
14281
|
+
description: Type$2.Union([Type$2.String(), Type$2.Null()]),
|
|
14282
|
+
pushedAt: Type$2.Union([Type$2.String({ format: "date-time" }), Type$2.Null()]),
|
|
14275
14283
|
/** The owning user's or organization's GitHub avatar. */
|
|
14276
|
-
ownerAvatarUrl: Type$
|
|
14284
|
+
ownerAvatarUrl: Type$2.Union([Type$2.String(), Type$2.Null()])
|
|
14277
14285
|
});
|
|
14278
|
-
Type$
|
|
14286
|
+
Type$2.Object({ repositories: Type$2.Array(pushableRepositorySchema) });
|
|
14279
14287
|
/** A tag's id: a lowercase slug. */
|
|
14280
|
-
const tagIdSchema = Type$
|
|
14288
|
+
const tagIdSchema = Type$2.String({
|
|
14281
14289
|
pattern: /^[a-z\d]+(?:-[a-z\d]+)*$/,
|
|
14282
14290
|
maxLength: 64
|
|
14283
14291
|
});
|
|
14284
|
-
Type$
|
|
14292
|
+
Type$2.Object({
|
|
14285
14293
|
id: tagIdSchema,
|
|
14286
|
-
label: Type$
|
|
14294
|
+
label: Type$2.String(),
|
|
14287
14295
|
/** A CSS color for the tag's dot. */
|
|
14288
|
-
color: Type$
|
|
14296
|
+
color: Type$2.String()
|
|
14289
14297
|
});
|
|
14290
14298
|
/** The tags an author files a submission under, by id. */
|
|
14291
|
-
const submissionTagsSchema = Type$
|
|
14299
|
+
const submissionTagsSchema = Type$2.Refine(Type$2.Array(tagIdSchema, { maxItems: 5 }), (tags) => new Set(tags).size === tags.length, () => "Tag ids must be unique.");
|
|
14292
14300
|
// ../contracts/src/icons.ts
|
|
14293
14301
|
/** An icon the website shows for an addon: a Nucleo Micro Bold export name, such as `IconPlug`. */
|
|
14294
|
-
const addonIconSchema = Type$
|
|
14302
|
+
const addonIconSchema = Type$2.String({
|
|
14295
14303
|
pattern: /^Icon[A-Z][A-Za-z\d]*$/,
|
|
14296
14304
|
maxLength: 64
|
|
14297
14305
|
});
|
|
14298
14306
|
// ../contracts/src/publish.ts
|
|
14299
14307
|
/** `listing` claims a new addon id; `update` publishes a new version of an addon the caller maintains. */
|
|
14300
|
-
const submissionKindSchema = Type$
|
|
14301
|
-
const submissionStatusSchema = Type$
|
|
14308
|
+
const submissionKindSchema = Type$2.Enum(["listing", "update"]);
|
|
14309
|
+
const submissionStatusSchema = Type$2.Enum([
|
|
14302
14310
|
"pending_review",
|
|
14303
14311
|
"changes_requested",
|
|
14304
14312
|
"approved",
|
|
@@ -14307,53 +14315,53 @@ const submissionStatusSchema = Type$1.Enum([
|
|
|
14307
14315
|
"expired",
|
|
14308
14316
|
"cancelled"
|
|
14309
14317
|
]);
|
|
14310
|
-
Type$
|
|
14311
|
-
const reviewDecisionSchema = Type$
|
|
14318
|
+
Type$2.Enum(["pending_review", "changes_requested"]);
|
|
14319
|
+
const reviewDecisionSchema = Type$2.Enum([
|
|
14312
14320
|
"approved",
|
|
14313
14321
|
"rejected",
|
|
14314
14322
|
"changes_requested"
|
|
14315
14323
|
]);
|
|
14316
|
-
const submissionReviewSchema = Type$
|
|
14324
|
+
const submissionReviewSchema = Type$2.Object({
|
|
14317
14325
|
decision: reviewDecisionSchema,
|
|
14318
14326
|
/** The rejection reason or requested changes; optional only on approval. */
|
|
14319
|
-
note: Type$
|
|
14320
|
-
reviewedAt: Type$
|
|
14327
|
+
note: Type$2.Union([Type$2.String(), Type$2.Null()]),
|
|
14328
|
+
reviewedAt: Type$2.String({ format: "date-time" })
|
|
14321
14329
|
});
|
|
14322
|
-
const submissionSchema = Type$
|
|
14323
|
-
id: Type$
|
|
14330
|
+
const submissionSchema = Type$2.Object({
|
|
14331
|
+
id: Type$2.String({ minLength: 1 }),
|
|
14324
14332
|
addonId: addonIdSchema,
|
|
14325
|
-
version: Type$
|
|
14333
|
+
version: Type$2.String(),
|
|
14326
14334
|
kind: submissionKindSchema,
|
|
14327
14335
|
status: submissionStatusSchema,
|
|
14328
14336
|
/** Where the submitted version was read from. */
|
|
14329
14337
|
source: sourcePinSchema,
|
|
14330
14338
|
/** The reviewer's decision, once one was made. */
|
|
14331
|
-
review: Type$
|
|
14339
|
+
review: Type$2.Union([submissionReviewSchema, Type$2.Null()])
|
|
14332
14340
|
});
|
|
14333
14341
|
/** The users an owner makes an addon's maintainers, by user id. */
|
|
14334
|
-
const submissionMaintainersSchema = Type$
|
|
14342
|
+
const submissionMaintainersSchema = Type$2.Refine(Type$2.Array(Type$2.String({
|
|
14335
14343
|
minLength: 1,
|
|
14336
14344
|
maxLength: 64
|
|
14337
14345
|
}), { maxItems: 20 }), (ids) => new Set(ids).size === ids.length, () => "User ids must be unique.");
|
|
14338
14346
|
/** What the author chose for the listing; an omitted field keeps what the addon has. */
|
|
14339
|
-
const submissionDetailsSchema = Type$
|
|
14347
|
+
const submissionDetailsSchema = Type$2.Object({
|
|
14340
14348
|
/** Replaces the addon's tags on approval; `[]` clears them. */
|
|
14341
|
-
tags: Type$
|
|
14349
|
+
tags: Type$2.Optional(submissionTagsSchema),
|
|
14342
14350
|
/** Replaces the addon's maintainers other than its owners on approval; `[]` removes them. Owners only. */
|
|
14343
|
-
maintainers: Type$
|
|
14351
|
+
maintainers: Type$2.Optional(submissionMaintainersSchema),
|
|
14344
14352
|
/** The website icon a new listing starts with; updates change it from the dashboard. */
|
|
14345
|
-
icon: Type$
|
|
14353
|
+
icon: Type$2.Optional(addonIconSchema)
|
|
14346
14354
|
});
|
|
14347
|
-
Type$
|
|
14355
|
+
Type$2.Object({
|
|
14348
14356
|
repository: repositoryInputSchema,
|
|
14349
14357
|
path: addonPathSchema,
|
|
14350
14358
|
/** The branch, tag or SHA the author named; it must still resolve to `commitSha`. */
|
|
14351
14359
|
ref: gitRefSchema,
|
|
14352
14360
|
commitSha: commitShaSchema,
|
|
14353
|
-
details: Type$
|
|
14361
|
+
details: Type$2.Optional(submissionDetailsSchema)
|
|
14354
14362
|
});
|
|
14355
|
-
const createSubmissionResponseSchema = Type$
|
|
14356
|
-
Type$
|
|
14363
|
+
const createSubmissionResponseSchema = Type$2.Object({ submission: submissionSchema });
|
|
14364
|
+
Type$2.Object({
|
|
14357
14365
|
repository: repositoryInputSchema,
|
|
14358
14366
|
path: addonPathSchema,
|
|
14359
14367
|
/** The tag or branch holding the build commit; it must still resolve to `commitSha`. */
|
|
@@ -14361,31 +14369,31 @@ Type$1.Object({
|
|
|
14361
14369
|
commitSha: commitShaSchema
|
|
14362
14370
|
});
|
|
14363
14371
|
/** `unchanged` when that version was already published, so a re-run is a no-op. */
|
|
14364
|
-
const firstPartyPublishStatusSchema = Type$
|
|
14372
|
+
const firstPartyPublishStatusSchema = Type$2.Enum([
|
|
14365
14373
|
"published",
|
|
14366
14374
|
"replaced",
|
|
14367
14375
|
"unchanged"
|
|
14368
14376
|
]);
|
|
14369
|
-
Type$
|
|
14377
|
+
Type$2.Object({
|
|
14370
14378
|
status: firstPartyPublishStatusSchema,
|
|
14371
14379
|
addonId: addonIdSchema,
|
|
14372
|
-
version: Type$
|
|
14380
|
+
version: Type$2.String(),
|
|
14373
14381
|
/** The SHA-256 of the live bundle of that version. */
|
|
14374
|
-
sha256: Type$
|
|
14382
|
+
sha256: Type$2.String()
|
|
14375
14383
|
});
|
|
14376
14384
|
/** One addon of the first-party repository, delisted or not, at its newest published version. */
|
|
14377
|
-
const firstPartyAddonSchema = Type$
|
|
14385
|
+
const firstPartyAddonSchema = Type$2.Object({
|
|
14378
14386
|
id: addonIdSchema,
|
|
14379
14387
|
/** The newest version ever published, rolled back or not, so it is never published again. */
|
|
14380
|
-
version: Type$
|
|
14388
|
+
version: Type$2.String(),
|
|
14381
14389
|
/** The commit that version was read from, or `null` for a legacy upload. */
|
|
14382
|
-
commitSha: Type$
|
|
14390
|
+
commitSha: Type$2.Union([Type$2.String(), Type$2.Null()]),
|
|
14383
14391
|
/** The SHA-256 of that version's published bundle. */
|
|
14384
|
-
sha256: Type$
|
|
14392
|
+
sha256: Type$2.Optional(Type$2.String()),
|
|
14385
14393
|
/** That version's `manifest.bytecode`, when it ships compiled bundles. */
|
|
14386
|
-
bytecode: Type$
|
|
14394
|
+
bytecode: Type$2.Optional(bytecodeDigestsSchema)
|
|
14387
14395
|
});
|
|
14388
|
-
Type$
|
|
14396
|
+
Type$2.Object({ addons: Type$2.Array(firstPartyAddonSchema) });
|
|
14389
14397
|
// ../../apps/web/src/api/schema-client.ts
|
|
14390
14398
|
/**
|
|
14391
14399
|
* @description Creates a typed client for the Unbound web API that parses each answer with the
|
|
@@ -14402,11 +14410,11 @@ function createApiClient(options) {
|
|
|
14402
14410
|
};
|
|
14403
14411
|
}
|
|
14404
14412
|
// src/lib/credentials.ts
|
|
14405
|
-
const schema$6 = Type$
|
|
14413
|
+
const schema$6 = Type$2.Object({
|
|
14406
14414
|
/** The API origin the session belongs to; it is never sent to any other origin. */
|
|
14407
|
-
apiUrl: Type$
|
|
14415
|
+
apiUrl: Type$2.String({ format: "url" }),
|
|
14408
14416
|
/** The Better Auth session token from the device authorization flow, sent as a bearer token. */
|
|
14409
|
-
token: Type$
|
|
14417
|
+
token: Type$2.String({ minLength: 1 })
|
|
14410
14418
|
});
|
|
14411
14419
|
/**
|
|
14412
14420
|
* @description Reads the stored credentials, throwing when the file exists but is not valid.
|
|
@@ -14557,10 +14565,10 @@ const publishCommand = {
|
|
|
14557
14565
|
cli: "root",
|
|
14558
14566
|
mcp: false
|
|
14559
14567
|
},
|
|
14560
|
-
schema: Type$
|
|
14561
|
-
addon: Type$
|
|
14562
|
-
ref: Type$
|
|
14563
|
-
repository: Type$
|
|
14568
|
+
schema: Type$2.Object({
|
|
14569
|
+
addon: Type$2.Optional(Type$2.String({ description: "The id of the addon to publish; required when the workspace has several." })),
|
|
14570
|
+
ref: Type$2.Optional(Type$2.String({ description: "The branch, tag or commit to submit; defaults to the tag on HEAD, else its SHA." })),
|
|
14571
|
+
repository: Type$2.Optional(Type$2.String({ description: "The GitHub repository to submit from; defaults to the `origin` remote." }))
|
|
14564
14572
|
}),
|
|
14565
14573
|
async handler({ addon: id, ref, repository }) {
|
|
14566
14574
|
try {
|
|
@@ -14610,14 +14618,13 @@ function toFailure(error) {
|
|
|
14610
14618
|
};
|
|
14611
14619
|
}
|
|
14612
14620
|
// src/commands/bridge.ts
|
|
14613
|
-
const schema$5 = Type$
|
|
14614
|
-
action: Type$
|
|
14621
|
+
const schema$5 = Type$2.Object({
|
|
14622
|
+
action: Type$2.Enum(["restart", "start"], { description: "Restart the running bridge, or start one when none runs." }),
|
|
14615
14623
|
port: bridgePortField
|
|
14616
14624
|
});
|
|
14617
14625
|
const LISTEN_TIMEOUT_MS = 15e3;
|
|
14618
14626
|
const LISTEN_POLL_MS = 250;
|
|
14619
14627
|
const LOOKUP_TIMEOUT_MS = 5e3;
|
|
14620
|
-
const BRIDGE_ENTRY = join(import.meta.dir, "..", "..", "..", "debugger", "src", "index.ts");
|
|
14621
14628
|
function isListening(port) {
|
|
14622
14629
|
return new Promise((resolve) => {
|
|
14623
14630
|
const socket = connect({
|
|
@@ -14660,8 +14667,9 @@ function bridgeLogPath(port) {
|
|
|
14660
14667
|
function startDetached(port) {
|
|
14661
14668
|
const log = bridgeLogPath(port);
|
|
14662
14669
|
const output = openSync(log, "a");
|
|
14670
|
+
const entry = Bun.resolveSync("@unbound-app/debugger", import.meta.dir);
|
|
14663
14671
|
spawn("bun", [
|
|
14664
|
-
|
|
14672
|
+
entry,
|
|
14665
14673
|
"--port",
|
|
14666
14674
|
String(port)
|
|
14667
14675
|
], {
|
|
@@ -14749,6 +14757,11 @@ const KEBAB_CASE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
|
14749
14757
|
*/
|
|
14750
14758
|
async function resolveOptions(input, workspace) {
|
|
14751
14759
|
intro("ubd create");
|
|
14760
|
+
const unprompted = process.stdin.isTTY ? [] : missingFlags(input, Boolean(workspace));
|
|
14761
|
+
if (unprompted.length) {
|
|
14762
|
+
cancel(`No terminal to prompt in. Pass ${unprompted.join(", ")}.`);
|
|
14763
|
+
process.exit(2);
|
|
14764
|
+
}
|
|
14752
14765
|
const shape = await resolveShape(input.shape, Boolean(workspace));
|
|
14753
14766
|
const kind = await resolveKind(input.kind);
|
|
14754
14767
|
const name = await resolveName(input.name);
|
|
@@ -14773,6 +14786,27 @@ async function resolveOptions(input, workspace) {
|
|
|
14773
14786
|
install: repository ? await resolveConfirm(input.install, "Install dependencies with bun?") : false
|
|
14774
14787
|
};
|
|
14775
14788
|
}
|
|
14789
|
+
/** The flag for each value `ubd create` prompts for, in prompt order; the optional author id has a fallback instead. */
|
|
14790
|
+
const PROMPTED_FLAGS = [
|
|
14791
|
+
["shape", "--shape"],
|
|
14792
|
+
["kind", "--kind"],
|
|
14793
|
+
["name", "--name"],
|
|
14794
|
+
["displayName", "--display-name"],
|
|
14795
|
+
["description", "--description"],
|
|
14796
|
+
["authorName", "--author-name"],
|
|
14797
|
+
["id", "--id"],
|
|
14798
|
+
["dir", "--dir"],
|
|
14799
|
+
["gitInit", "--git-init"],
|
|
14800
|
+
["install", "--install"]
|
|
14801
|
+
];
|
|
14802
|
+
function missingFlags(input, hasWorkspace) {
|
|
14803
|
+
const repository = input.shape === "repository";
|
|
14804
|
+
return PROMPTED_FLAGS.filter(([key]) => {
|
|
14805
|
+
if (key === "gitInit" || key === "install") return repository && input[key] === void 0;
|
|
14806
|
+
if (key === "dir" && !repository && hasWorkspace) return false;
|
|
14807
|
+
return input[key] === void 0;
|
|
14808
|
+
}).map(([, flag]) => flag);
|
|
14809
|
+
}
|
|
14776
14810
|
async function resolveShape(flag, hasWorkspace) {
|
|
14777
14811
|
if (flag === "repository") return "repository";
|
|
14778
14812
|
if (flag === "addon") return hasWorkspace ? "add" : "addon";
|
|
@@ -15005,18 +15039,18 @@ const createCommand = {
|
|
|
15005
15039
|
cli: "root",
|
|
15006
15040
|
mcp: false
|
|
15007
15041
|
},
|
|
15008
|
-
schema: Type$
|
|
15009
|
-
kind: Type$
|
|
15010
|
-
name: Type$
|
|
15011
|
-
dir: Type$
|
|
15012
|
-
displayName: Type$
|
|
15013
|
-
description: Type$
|
|
15014
|
-
authorName: Type$
|
|
15015
|
-
authorId: Type$
|
|
15016
|
-
id: Type$
|
|
15017
|
-
shape: Type$
|
|
15018
|
-
gitInit: Type$
|
|
15019
|
-
install: Type$
|
|
15042
|
+
schema: Type$2.Object({
|
|
15043
|
+
kind: Type$2.Optional(Type$2.Enum(["plugin", "theme"], { description: "The addon kind to scaffold." })),
|
|
15044
|
+
name: Type$2.Optional(Type$2.String({ description: "The addon name (kebab-case)." })),
|
|
15045
|
+
dir: Type$2.Optional(Type$2.String({ description: "The target directory (default ./<name>)." })),
|
|
15046
|
+
displayName: Type$2.Optional(Type$2.String({ description: "The human-readable addon name." })),
|
|
15047
|
+
description: Type$2.Optional(Type$2.String({ description: "A one-line description." })),
|
|
15048
|
+
authorName: Type$2.Optional(Type$2.String({ description: "The author name." })),
|
|
15049
|
+
authorId: Type$2.Optional(Type$2.String({ description: "The author Discord id." })),
|
|
15050
|
+
id: Type$2.Optional(Type$2.String({ description: "The manifest id (default <authorName>.<name>)." })),
|
|
15051
|
+
shape: Type$2.Optional(Type$2.Enum(["repository", "addon"], { description: "Scaffold a repository or a single addon." })),
|
|
15052
|
+
gitInit: Type$2.Optional(Type$2.Boolean({ description: "Initialize a git repository (repository shape only)." })),
|
|
15053
|
+
install: Type$2.Optional(Type$2.Boolean({ description: "Install dependencies with bun (repository shape only)." }))
|
|
15020
15054
|
}),
|
|
15021
15055
|
async handler(input) {
|
|
15022
15056
|
const config = loadConfig();
|
|
@@ -15043,9 +15077,12 @@ const createCommand = {
|
|
|
15043
15077
|
function printOutro(result) {
|
|
15044
15078
|
const kindDocs = `${DOCS_BASE_URL}/${result.kind}s/introduction`;
|
|
15045
15079
|
const manifestDocs = `${DOCS_BASE_URL}/addons/manifest`;
|
|
15080
|
+
const cd = relative(process.cwd(), result.dir) || ".";
|
|
15081
|
+
const installed = !existsSync(join(result.dir, "package.json")) || existsSync(join(result.dir, "node_modules"));
|
|
15046
15082
|
const steps = [
|
|
15047
|
-
`cd ${
|
|
15048
|
-
"
|
|
15083
|
+
`cd ${cd}`,
|
|
15084
|
+
...installed ? [] : ["bun install"],
|
|
15085
|
+
"bunx @unbound-app/cli dev",
|
|
15049
15086
|
`Learn the ${result.kind} API: ${kindDocs}`,
|
|
15050
15087
|
`Manifest reference: ${manifestDocs}`
|
|
15051
15088
|
];
|
|
@@ -15434,18 +15471,18 @@ const deviceCommand = {
|
|
|
15434
15471
|
cli: "root",
|
|
15435
15472
|
mcp: true
|
|
15436
15473
|
},
|
|
15437
|
-
schema: Type$
|
|
15438
|
-
action: Type$
|
|
15474
|
+
schema: Type$2.Object({
|
|
15475
|
+
action: Type$2.Enum([
|
|
15439
15476
|
"reset",
|
|
15440
15477
|
"save",
|
|
15441
15478
|
"restore",
|
|
15442
15479
|
"list"
|
|
15443
15480
|
], { description: "reset moves Unbound aside for a fresh start, save and restore snapshots, list shows them." }),
|
|
15444
|
-
name: defaulted(Type$
|
|
15445
|
-
serial: Type$
|
|
15446
|
-
ios: defaulted(Type$
|
|
15447
|
-
udid: Type$
|
|
15448
|
-
restart: defaulted(Type$
|
|
15481
|
+
name: defaulted(Type$2.String({ description: "The snapshot to save or restore." }), ""),
|
|
15482
|
+
serial: Type$2.Optional(Type$2.String({ description: "The adb serial of the Android device, when several are attached." })),
|
|
15483
|
+
ios: defaulted(Type$2.Boolean({ description: "Act on a jailbroken iPhone through jb-p1lot instead of over adb." }), false),
|
|
15484
|
+
udid: Type$2.Optional(Type$2.String({ description: "The UDID of the iPhone, when several are connected. Implies --ios." })),
|
|
15485
|
+
restart: defaulted(Type$2.Boolean({ description: "Relaunch Discord afterwards." }), false)
|
|
15449
15486
|
}),
|
|
15450
15487
|
cli: { positionals: ["action", "name"] },
|
|
15451
15488
|
async handler({ action, name, ...options }) {
|
|
@@ -15466,7 +15503,7 @@ const logoutCommand = {
|
|
|
15466
15503
|
cli: "root",
|
|
15467
15504
|
mcp: false
|
|
15468
15505
|
},
|
|
15469
|
-
schema: Type$
|
|
15506
|
+
schema: Type$2.Object({}),
|
|
15470
15507
|
async handler() {
|
|
15471
15508
|
try {
|
|
15472
15509
|
const path = getCredentialsPath(parseEnv());
|
|
@@ -15491,8 +15528,8 @@ const logoutCommand = {
|
|
|
15491
15528
|
const TOKEN_KEY = "__UBD_RELOAD__";
|
|
15492
15529
|
/** How often the reload command probes for the fresh bundle. */
|
|
15493
15530
|
const RELOAD_POLL_MS = 500;
|
|
15494
|
-
const schema$4 = Type$
|
|
15495
|
-
timeout: defaulted(Type$
|
|
15531
|
+
const schema$4 = Type$2.Object({
|
|
15532
|
+
timeout: defaulted(Type$2.Number({ description: "How long to wait for the reloaded app to reconnect, in milliseconds." }), 6e4),
|
|
15496
15533
|
port: bridgePortField
|
|
15497
15534
|
});
|
|
15498
15535
|
function tagAndReload(unbound, key, token) {
|
|
@@ -15537,11 +15574,11 @@ const reloadCommand = {
|
|
|
15537
15574
|
}
|
|
15538
15575
|
};
|
|
15539
15576
|
// src/commands/status.ts
|
|
15540
|
-
const schema$3 = Type$
|
|
15577
|
+
const schema$3 = Type$2.Object({
|
|
15541
15578
|
port: bridgePortField,
|
|
15542
|
-
watch: defaulted(Type$
|
|
15543
|
-
interval: defaulted(Type$
|
|
15544
|
-
samples: defaulted(Type$
|
|
15579
|
+
watch: defaulted(Type$2.Boolean({ description: "Sample the native resources repeatedly and report which ones keep growing." }), false),
|
|
15580
|
+
interval: defaulted(Type$2.Number({ description: "Milliseconds between samples when watching." }), 5e3),
|
|
15581
|
+
samples: defaulted(Type$2.Number({ description: "How many samples to take when watching." }), 12)
|
|
15545
15582
|
});
|
|
15546
15583
|
const WATCHED_RESOURCES = [
|
|
15547
15584
|
"handles",
|
|
@@ -15579,13 +15616,13 @@ function analyzeSamples(samples) {
|
|
|
15579
15616
|
growing
|
|
15580
15617
|
};
|
|
15581
15618
|
}
|
|
15582
|
-
const deviceStatusReportSchema = Type$
|
|
15583
|
-
started: Type$
|
|
15584
|
-
failed: Type$
|
|
15585
|
-
stopped: Type$
|
|
15586
|
-
resources: Type$
|
|
15587
|
-
slowestStarts: defaulted(Type$
|
|
15588
|
-
startTotal: defaulted(Type$
|
|
15619
|
+
const deviceStatusReportSchema = Type$2.Object({
|
|
15620
|
+
started: Type$2.Number(),
|
|
15621
|
+
failed: Type$2.Array(Type$2.String()),
|
|
15622
|
+
stopped: Type$2.Array(Type$2.String()),
|
|
15623
|
+
resources: Type$2.Union([Type$2.Record(Type$2.String(), Type$2.Number()), Type$2.Null()]),
|
|
15624
|
+
slowestStarts: defaulted(Type$2.Array(Type$2.Tuple([Type$2.String(), Type$2.Number()])), []),
|
|
15625
|
+
startTotal: defaulted(Type$2.Number(), 0)
|
|
15589
15626
|
});
|
|
15590
15627
|
function readDeviceStatus(unbound) {
|
|
15591
15628
|
const collect = globalThis.gc;
|
|
@@ -15701,8 +15738,8 @@ const timingCommand = {
|
|
|
15701
15738
|
cli: "root",
|
|
15702
15739
|
mcp: true
|
|
15703
15740
|
},
|
|
15704
|
-
schema: Type$
|
|
15705
|
-
rounds: defaulted(Type$
|
|
15741
|
+
schema: Type$2.Object({
|
|
15742
|
+
rounds: defaulted(Type$2.Number({ description: "How many samples to take." }), 3),
|
|
15706
15743
|
port: bridgePortField
|
|
15707
15744
|
}),
|
|
15708
15745
|
handler({ rounds }, { client }) {
|
|
@@ -15852,10 +15889,10 @@ const buildCommand = {
|
|
|
15852
15889
|
cli: "root",
|
|
15853
15890
|
mcp: false
|
|
15854
15891
|
},
|
|
15855
|
-
schema: Type$
|
|
15856
|
-
declaredCapabilities: defaulted(Type$
|
|
15857
|
-
strictBudget: defaulted(Type$
|
|
15858
|
-
verbose: defaulted(Type$
|
|
15892
|
+
schema: Type$2.Object({
|
|
15893
|
+
declaredCapabilities: defaulted(Type$2.Boolean({ description: "Keep the hand-written platforms and Capabilities of plugins that still declare them, until they select platform code with native.definePlatform." }), false),
|
|
15894
|
+
strictBudget: defaulted(Type$2.Boolean({ description: "Fail the build when a plugin goes over a size budget, instead of warning." }), false),
|
|
15895
|
+
verbose: defaulted(Type$2.Boolean({ description: "Also list the largest source modules of each plugin, and log each metro filter the build rewrote into a built-in filter, with its file and line." }), false)
|
|
15859
15896
|
}),
|
|
15860
15897
|
async handler({ declaredCapabilities, strictBudget, verbose }) {
|
|
15861
15898
|
const resolved = loadConfig();
|
|
@@ -16249,9 +16286,10 @@ const typesCheck = {
|
|
|
16249
16286
|
* @description Type-checks the addon with its `tsconfig.json` through TypeScript 7's `tsc --noEmit -p`.
|
|
16250
16287
|
* Slow, so `ubd check` runs it only with `--types`.
|
|
16251
16288
|
* @param context The addon to check.
|
|
16252
|
-
* @returns One diagnostic per type error; none for an addon without a tsconfig.
|
|
16289
|
+
* @returns One diagnostic per type error; none for a theme or an addon without a tsconfig.
|
|
16253
16290
|
*/
|
|
16254
16291
|
async run({ addon }) {
|
|
16292
|
+
if (addon.kind !== "plugin") return [];
|
|
16255
16293
|
const configPath = findConfig(addon.dir);
|
|
16256
16294
|
if (!configPath) return [];
|
|
16257
16295
|
const { diagnostics, failure } = await runTsc([
|
|
@@ -16271,15 +16309,15 @@ const typesCheck = {
|
|
|
16271
16309
|
const CONFIG_FILE = ".oxlintrc.json";
|
|
16272
16310
|
const BINARY = join("node_modules", ".bin", "oxlint");
|
|
16273
16311
|
const MAX_OUTPUT_BYTES$1 = 67108864;
|
|
16274
|
-
const lintOutputSchema = Type$
|
|
16275
|
-
message: Type$
|
|
16276
|
-
code: Type$
|
|
16277
|
-
severity: Type$
|
|
16278
|
-
help: Type$
|
|
16279
|
-
filename: Type$
|
|
16280
|
-
labels: Type$
|
|
16281
|
-
line: Type$
|
|
16282
|
-
column: Type$
|
|
16312
|
+
const lintOutputSchema = Type$2.Object({ diagnostics: Type$2.Array(Type$2.Object({
|
|
16313
|
+
message: Type$2.String(),
|
|
16314
|
+
code: Type$2.Optional(Type$2.String()),
|
|
16315
|
+
severity: Type$2.String(),
|
|
16316
|
+
help: Type$2.Optional(Type$2.String()),
|
|
16317
|
+
filename: Type$2.String(),
|
|
16318
|
+
labels: Type$2.Array(Type$2.Object({ span: Type$2.Object({
|
|
16319
|
+
line: Type$2.Number(),
|
|
16320
|
+
column: Type$2.Number()
|
|
16283
16321
|
}) }))
|
|
16284
16322
|
})) });
|
|
16285
16323
|
function findUp(from, name) {
|
|
@@ -16355,9 +16393,10 @@ const CHECKS = [
|
|
|
16355
16393
|
* @description Runs oxlint over the addon with the nearest `.oxlintrc.json`, the plugin lint
|
|
16356
16394
|
* `docs/developer/addons/standards.mdx` describes.
|
|
16357
16395
|
* @param context The addon to check.
|
|
16358
|
-
* @returns One diagnostic per lint finding, or a warning when oxlint is not installed.
|
|
16396
|
+
* @returns One diagnostic per lint finding, or a warning when oxlint is not installed; none for a theme.
|
|
16359
16397
|
*/
|
|
16360
16398
|
async run({ addon }) {
|
|
16399
|
+
if (addon.kind !== "plugin") return [];
|
|
16361
16400
|
const setup = findLintSetup(addon.dir);
|
|
16362
16401
|
if (!setup) return [diagnostic({
|
|
16363
16402
|
file: "",
|
|
@@ -16567,16 +16606,16 @@ async function checkAddons(addons, selection, cache) {
|
|
|
16567
16606
|
// src/lib/check/shard.ts
|
|
16568
16607
|
const MAX_OUTPUT_BYTES = 268435456;
|
|
16569
16608
|
const MAX_SHARDS = 8;
|
|
16570
|
-
const shardOutputSchema = Type$
|
|
16571
|
-
dir: Type$
|
|
16572
|
-
file: Type$
|
|
16573
|
-
line: Type$
|
|
16574
|
-
column: Type$
|
|
16575
|
-
path: Type$
|
|
16576
|
-
severity: Type$
|
|
16577
|
-
message: Type$
|
|
16578
|
-
fix: Type$
|
|
16579
|
-
check: Type$
|
|
16609
|
+
const shardOutputSchema = Type$2.Object({ diagnostics: Type$2.Array(Type$2.Object({
|
|
16610
|
+
dir: Type$2.String(),
|
|
16611
|
+
file: Type$2.String(),
|
|
16612
|
+
line: Type$2.Number(),
|
|
16613
|
+
column: Type$2.Number(),
|
|
16614
|
+
path: Type$2.Optional(Type$2.String()),
|
|
16615
|
+
severity: Type$2.Union([Type$2.Literal("error"), Type$2.Literal("warning")]),
|
|
16616
|
+
message: Type$2.String(),
|
|
16617
|
+
fix: Type$2.Optional(Type$2.String()),
|
|
16618
|
+
check: Type$2.Optional(Type$2.String())
|
|
16580
16619
|
})) });
|
|
16581
16620
|
function runShard(entry, args, addons) {
|
|
16582
16621
|
const plugins = addons.flatMap((addon) => ["--plugin", addon.dir]);
|
|
@@ -16629,15 +16668,15 @@ async function checkInShards(addons, args, entry = process.argv[1] ?? "") {
|
|
|
16629
16668
|
return addons.flatMap((addon) => byDir.get(addon.dir) ?? []);
|
|
16630
16669
|
}
|
|
16631
16670
|
// src/commands/check.ts
|
|
16632
|
-
const schema$2 = Type$
|
|
16633
|
-
plugin: defaulted(Type$
|
|
16634
|
-
all: defaulted(Type$
|
|
16635
|
-
watch: defaulted(Type$
|
|
16636
|
-
only: defaulted(Type$
|
|
16637
|
-
strict: defaulted(Type$
|
|
16638
|
-
types: defaulted(Type$
|
|
16639
|
-
declaredCapabilities: defaulted(Type$
|
|
16640
|
-
json: defaulted(Type$
|
|
16671
|
+
const schema$2 = Type$2.Object({
|
|
16672
|
+
plugin: defaulted(Type$2.Array(Type$2.String(), { description: "An addon directory to check, repeatable; defaults to the addon holding the current directory." }), []),
|
|
16673
|
+
all: defaulted(Type$2.Boolean({ description: "Check every addon in the workspace." }), false),
|
|
16674
|
+
watch: defaulted(Type$2.Boolean({ description: "Re-check an addon on every save, printing only what changed." }), false),
|
|
16675
|
+
only: defaulted(Type$2.Array(Type$2.String(), { description: `Run only these checks, comma-separated: ${listCheckIds().join(", ")}.` }), []),
|
|
16676
|
+
strict: defaulted(Type$2.Boolean({ description: "Fail on warnings too." }), false),
|
|
16677
|
+
types: defaulted(Type$2.Boolean({ description: "Also type-check each addon with its tsconfig, like tsc --noEmit; slow." }), false),
|
|
16678
|
+
declaredCapabilities: defaulted(Type$2.Boolean({ description: "Check the capabilities as `ubd build --declared-capabilities` does, keeping hand-written platforms and Capabilities." }), false),
|
|
16679
|
+
json: defaulted(Type$2.Boolean({ description: "Print the diagnostics as JSON." }), false)
|
|
16641
16680
|
});
|
|
16642
16681
|
async function selectAddons(plugins, all) {
|
|
16643
16682
|
const targets = (plugins.length ? plugins : ["."]).map((plugin) => resolve(plugin));
|
|
@@ -16797,7 +16836,7 @@ const loginCommand = {
|
|
|
16797
16836
|
cli: "root",
|
|
16798
16837
|
mcp: false
|
|
16799
16838
|
},
|
|
16800
|
-
schema: Type$
|
|
16839
|
+
schema: Type$2.Object({}),
|
|
16801
16840
|
async handler() {
|
|
16802
16841
|
try {
|
|
16803
16842
|
const env = parseEnv();
|
|
@@ -16881,7 +16920,7 @@ const routeCommand = {
|
|
|
16881
16920
|
cli: "mcp",
|
|
16882
16921
|
mcp: true
|
|
16883
16922
|
},
|
|
16884
|
-
schema: Type$
|
|
16923
|
+
schema: Type$2.Object({ port: bridgePortField }),
|
|
16885
16924
|
handler(_input, { client }) {
|
|
16886
16925
|
return runOnDevice(client, toDeviceCode(currentRoute));
|
|
16887
16926
|
}
|
|
@@ -16894,9 +16933,9 @@ const spansCommand = {
|
|
|
16894
16933
|
cli: "root",
|
|
16895
16934
|
mcp: true
|
|
16896
16935
|
},
|
|
16897
|
-
schema: Type$
|
|
16898
|
-
match: Type$
|
|
16899
|
-
max: defaulted(Type$
|
|
16936
|
+
schema: Type$2.Object({
|
|
16937
|
+
match: Type$2.String({ description: "Text the text views must contain." }),
|
|
16938
|
+
max: defaulted(Type$2.Number({ description: "How many matching text views to print." }), 5),
|
|
16900
16939
|
port: bridgePortField
|
|
16901
16940
|
}),
|
|
16902
16941
|
cli: { positionals: ["match"] },
|
|
@@ -16912,13 +16951,13 @@ const traceCommand = {
|
|
|
16912
16951
|
cli: "root",
|
|
16913
16952
|
mcp: true
|
|
16914
16953
|
},
|
|
16915
|
-
schema: Type$
|
|
16916
|
-
props: Type$
|
|
16954
|
+
schema: Type$2.Object({
|
|
16955
|
+
props: Type$2.Array(Type$2.String(), {
|
|
16917
16956
|
minItems: 1,
|
|
16918
16957
|
description: "Props of the module to find; the first is the function to trace."
|
|
16919
16958
|
}),
|
|
16920
|
-
duration: defaulted(Type$
|
|
16921
|
-
samples: defaulted(Type$
|
|
16959
|
+
duration: defaulted(Type$2.Number({ description: "How long to record calls, in milliseconds." }), 3e3),
|
|
16960
|
+
samples: defaulted(Type$2.Number({ description: "How many calls to describe." }), 10),
|
|
16922
16961
|
port: bridgePortField
|
|
16923
16962
|
}),
|
|
16924
16963
|
cli: { positionals: ["props"] },
|
|
@@ -16934,10 +16973,10 @@ const viewsCommand = {
|
|
|
16934
16973
|
cli: "root",
|
|
16935
16974
|
mcp: true
|
|
16936
16975
|
},
|
|
16937
|
-
schema: Type$
|
|
16938
|
-
filter: defaulted(Type$
|
|
16939
|
-
depth: defaulted(Type$
|
|
16940
|
-
max: defaulted(Type$
|
|
16976
|
+
schema: Type$2.Object({
|
|
16977
|
+
filter: defaulted(Type$2.String({ description: "Keep only views whose class name contains this text, plus their ancestors." }), ""),
|
|
16978
|
+
depth: defaulted(Type$2.Number({ description: "How deep to print below each view; iOS caps this at 12 levels." }), 40),
|
|
16979
|
+
max: defaulted(Type$2.Number({ description: "How many views to visit at most." }), 1500),
|
|
16941
16980
|
port: bridgePortField
|
|
16942
16981
|
}),
|
|
16943
16982
|
cli: { positionals: ["filter"] },
|
|
@@ -16954,10 +16993,10 @@ const evalCommand = {
|
|
|
16954
16993
|
cli: "root",
|
|
16955
16994
|
mcp: true
|
|
16956
16995
|
},
|
|
16957
|
-
schema: Type$
|
|
16958
|
-
code: Type$
|
|
16996
|
+
schema: Type$2.Object({
|
|
16997
|
+
code: Type$2.String({ description: "The JavaScript to evaluate on the device." }),
|
|
16959
16998
|
port: bridgePortField,
|
|
16960
|
-
timeout: Type$
|
|
16999
|
+
timeout: Type$2.Optional(Type$2.Integer({
|
|
16961
17000
|
minimum: 1,
|
|
16962
17001
|
maximum: MAX_EVAL_TIMEOUT_MS,
|
|
16963
17002
|
description: `How long to wait for the result, in milliseconds. Defaults to the bridge's ${DEFAULT_EVAL_TIMEOUT_MS}ms.`
|
|
@@ -16976,12 +17015,12 @@ const hookCommand = {
|
|
|
16976
17015
|
cli: "root",
|
|
16977
17016
|
mcp: true
|
|
16978
17017
|
},
|
|
16979
|
-
schema: Type$
|
|
16980
|
-
className: Type$
|
|
16981
|
-
method: Type$
|
|
16982
|
-
parameters: defaulted(Type$
|
|
16983
|
-
duration: defaulted(Type$
|
|
16984
|
-
samples: defaulted(Type$
|
|
17018
|
+
schema: Type$2.Object({
|
|
17019
|
+
className: Type$2.String({ description: "The class that declares or inherits the method." }),
|
|
17020
|
+
method: Type$2.String({ description: "The Java method name, or the Objective-C selector." }),
|
|
17021
|
+
parameters: defaulted(Type$2.Array(Type$2.String(), { description: "The Java parameter type names, such as int or android.view.MotionEvent." }), []),
|
|
17022
|
+
duration: defaulted(Type$2.Number({ description: "How long to record calls, in milliseconds." }), 3e3),
|
|
17023
|
+
samples: defaulted(Type$2.Number({ description: "How many calls to describe." }), 10),
|
|
16985
17024
|
port: bridgePortField
|
|
16986
17025
|
}),
|
|
16987
17026
|
cli: { positionals: ["className", "method"] },
|
|
@@ -17185,15 +17224,15 @@ function addSourceKey(pluginRoot, sourceFile, key, text) {
|
|
|
17185
17224
|
}
|
|
17186
17225
|
}
|
|
17187
17226
|
// src/commands/i18n.ts
|
|
17188
|
-
const flag = (description) => defaulted(Type$
|
|
17189
|
-
const schema$1 = Type$
|
|
17190
|
-
text: defaulted(Type$
|
|
17191
|
-
plugin: Type$
|
|
17227
|
+
const flag = (description) => defaulted(Type$2.Boolean({ description }), false);
|
|
17228
|
+
const schema$1 = Type$2.Object({
|
|
17229
|
+
text: defaulted(Type$2.Array(Type$2.String(), { description: "The English text of the key `--add` adds." }), []),
|
|
17230
|
+
plugin: Type$2.Optional(Type$2.String({ description: "The plugin directory. Defaults to the current directory." })),
|
|
17192
17231
|
fix: flag("Add each missing key to every translation, with its en-US text as a stub."),
|
|
17193
17232
|
prune: flag("With --fix, also remove keys en-US does not have. Implies --fix."),
|
|
17194
17233
|
unused: flag("List en-US keys no source uses, and used keys en-US lacks."),
|
|
17195
17234
|
strict: flag("Fail on missing and untranslated keys too."),
|
|
17196
|
-
add: Type$
|
|
17235
|
+
add: Type$2.Optional(Type$2.String({ description: "Add this key to en-US with the text given after it." }))
|
|
17197
17236
|
});
|
|
17198
17237
|
function findUnused(pluginRoot, source) {
|
|
17199
17238
|
const { usages, dynamic, failures } = collectPluginKeys(pluginRoot);
|
|
@@ -17843,9 +17882,9 @@ const LOG_FILE_POLL_MS = 1e3;
|
|
|
17843
17882
|
const LOG_FILE_CHUNK_BYTES = 65536;
|
|
17844
17883
|
const LOG_FILE_TAIL_LINES = 200;
|
|
17845
17884
|
const PILOT_TIMEOUT_MS = 15e3;
|
|
17846
|
-
const fileReadSchema = Type$
|
|
17847
|
-
data: Type$
|
|
17848
|
-
size: Type$
|
|
17885
|
+
const fileReadSchema = Type$2.Object({
|
|
17886
|
+
data: Type$2.Optional(Type$2.String()),
|
|
17887
|
+
size: Type$2.Number()
|
|
17849
17888
|
});
|
|
17850
17889
|
async function loaderLogPath(target) {
|
|
17851
17890
|
const container = await discordDataContainer(target, PILOT_TIMEOUT_MS);
|
|
@@ -17969,14 +18008,14 @@ async function followLoaderLogFile(options) {
|
|
|
17969
18008
|
}
|
|
17970
18009
|
}
|
|
17971
18010
|
// src/lib/log-tail.ts
|
|
17972
|
-
const archiveEventSchema = Type$
|
|
17973
|
-
eventType: Type$
|
|
17974
|
-
timestamp: Type$
|
|
17975
|
-
messageType: Type$
|
|
17976
|
-
processImagePath: Type$
|
|
17977
|
-
senderImagePath: Type$
|
|
17978
|
-
processID: Type$
|
|
17979
|
-
eventMessage: Type$
|
|
18011
|
+
const archiveEventSchema = Type$2.Object({
|
|
18012
|
+
eventType: Type$2.Literal("logEvent"),
|
|
18013
|
+
timestamp: Type$2.String(),
|
|
18014
|
+
messageType: Type$2.Optional(Type$2.String()),
|
|
18015
|
+
processImagePath: Type$2.Optional(Type$2.String()),
|
|
18016
|
+
senderImagePath: Type$2.Optional(Type$2.String()),
|
|
18017
|
+
processID: Type$2.Optional(Type$2.Number()),
|
|
18018
|
+
eventMessage: Type$2.Optional(Type$2.String())
|
|
17980
18019
|
});
|
|
17981
18020
|
const ADB_TIMEOUT_MS = 15e3;
|
|
17982
18021
|
const WAIT_FOR_DEVICE_MS = 12e4;
|
|
@@ -18333,18 +18372,18 @@ const logsCommand = {
|
|
|
18333
18372
|
cli: "root",
|
|
18334
18373
|
mcp: false
|
|
18335
18374
|
},
|
|
18336
|
-
schema: Type$
|
|
18337
|
-
serial: Type$
|
|
18338
|
-
ios: defaulted(Type$
|
|
18339
|
-
udid: Type$
|
|
18340
|
-
level: defaulted(Type$
|
|
18341
|
-
grep: Type$
|
|
18342
|
-
since: Type$
|
|
18343
|
-
follow: defaulted(Type$
|
|
18344
|
-
symbolicate: defaulted(Type$
|
|
18345
|
-
bundle: Type$
|
|
18346
|
-
pull: defaulted(Type$
|
|
18347
|
-
out: Type$
|
|
18375
|
+
schema: Type$2.Object({
|
|
18376
|
+
serial: Type$2.Optional(Type$2.String({ description: "The adb serial of the Android device, when several are attached." })),
|
|
18377
|
+
ios: defaulted(Type$2.Boolean({ description: "Tail a jailbroken iPhone over USB instead of an Android device over adb." }), false),
|
|
18378
|
+
udid: Type$2.Optional(Type$2.String({ description: "The UDID of the iPhone, when several are connected. Implies --ios." })),
|
|
18379
|
+
level: defaulted(Type$2.String({ description: `The lowest level to print: ${LOG_LEVELS.join(", ")}, or their first letter.` }), "verbose"),
|
|
18380
|
+
grep: Type$2.Optional(Type$2.String({ description: "Print only lines matching this regular expression." })),
|
|
18381
|
+
since: Type$2.Optional(Type$2.String({ description: "Start from history: a duration such as 5m, a clock time such as 14:30, or a date. iOS history holds notices, errors and faults only." })),
|
|
18382
|
+
follow: defaulted(Type$2.Boolean({ description: "Keep printing new lines; pass --follow=false to print the history and exit." }), true),
|
|
18383
|
+
symbolicate: defaulted(Type$2.Boolean({ description: "Rewrite Hermes frames of the client bundle to source positions using packages/client/dist's maps." }), false),
|
|
18384
|
+
bundle: Type$2.Optional(Type$2.String({ description: "The Hermes bundle to symbolicate against; defaults to the bytecode version the loader reports, else the newest built." })),
|
|
18385
|
+
pull: defaulted(Type$2.Boolean({ description: "Copy the loader's own log files off the device instead of tailing; they survive restarts and hold the JavaScript console too." }), false),
|
|
18386
|
+
out: Type$2.Optional(Type$2.String({ description: "The folder --pull writes the log files into; defaults to a timestamped folder here." }))
|
|
18348
18387
|
}),
|
|
18349
18388
|
async handler({ serial, ios, udid, level, grep, since, follow, symbolicate, bundle, pull, out }) {
|
|
18350
18389
|
const onIOS = ios || udid !== void 0;
|
|
@@ -18415,19 +18454,19 @@ const logsCommand = {
|
|
|
18415
18454
|
}
|
|
18416
18455
|
};
|
|
18417
18456
|
// src/commands/open.ts
|
|
18418
|
-
const schema = Type$
|
|
18419
|
-
screen: Type$
|
|
18457
|
+
const schema = Type$2.Object({
|
|
18458
|
+
screen: Type$2.String({
|
|
18420
18459
|
minLength: 1,
|
|
18421
18460
|
description: "The settings screen to open: a `Screens` key such as `Marketplace` or `Plugins`, or any `SETTING_RENDERER_CONFIG` route key."
|
|
18422
18461
|
}),
|
|
18423
|
-
params: defaulted(Type$
|
|
18462
|
+
params: defaulted(Type$2.String({ description: "Route parameters for the screen, as a JSON object, e.g. `{\"kind\":\"theme\"}`." }), "{}"),
|
|
18424
18463
|
port: bridgePortField
|
|
18425
18464
|
});
|
|
18426
|
-
const paramsSchema = Type$
|
|
18427
|
-
Type$
|
|
18428
|
-
Type$
|
|
18429
|
-
Type$
|
|
18430
|
-
Type$
|
|
18465
|
+
const paramsSchema = Type$2.Record(Type$2.String(), Type$2.Union([
|
|
18466
|
+
Type$2.String(),
|
|
18467
|
+
Type$2.Number(),
|
|
18468
|
+
Type$2.Boolean(),
|
|
18469
|
+
Type$2.Null()
|
|
18431
18470
|
]));
|
|
18432
18471
|
const openCommand = {
|
|
18433
18472
|
name: "open",
|
|
@@ -18453,9 +18492,9 @@ const openCommand = {
|
|
|
18453
18492
|
};
|
|
18454
18493
|
// src/lib/stale-build.ts
|
|
18455
18494
|
const SKIPPED = /* @__PURE__ */ new Set(["node_modules", ".git"]);
|
|
18456
|
-
const packageManifestSchema = Type$
|
|
18457
|
-
dependencies: Type$
|
|
18458
|
-
devDependencies: Type$
|
|
18495
|
+
const packageManifestSchema = Type$2.Object({
|
|
18496
|
+
dependencies: Type$2.Optional(Type$2.Record(Type$2.String(), Type$2.String(), { additionalProperties: false })),
|
|
18497
|
+
devDependencies: Type$2.Optional(Type$2.Record(Type$2.String(), Type$2.String(), { additionalProperties: false }))
|
|
18459
18498
|
});
|
|
18460
18499
|
const TEST_FILE = /\.test\.[cm]?[jt]sx?$/;
|
|
18461
18500
|
function newer(a, b) {
|
|
@@ -18545,9 +18584,9 @@ const pushCommand = {
|
|
|
18545
18584
|
cli: "root",
|
|
18546
18585
|
mcp: true
|
|
18547
18586
|
},
|
|
18548
|
-
schema: Type$
|
|
18549
|
-
addon: defaulted(Type$
|
|
18550
|
-
build: defaulted(Type$
|
|
18587
|
+
schema: Type$2.Object({
|
|
18588
|
+
addon: defaulted(Type$2.String({ description: "The plugin or theme to push, as its manifest id or directory." }), "."),
|
|
18589
|
+
build: defaulted(Type$2.Boolean({ description: "Build the addon before pushing it." }), true),
|
|
18551
18590
|
port: bridgePortField
|
|
18552
18591
|
}),
|
|
18553
18592
|
cli: { positionals: ["addon"] },
|
|
@@ -18707,7 +18746,7 @@ const commands = [
|
|
|
18707
18746
|
cli: "root",
|
|
18708
18747
|
mcp: false
|
|
18709
18748
|
},
|
|
18710
|
-
schema: Type$
|
|
18749
|
+
schema: Type$2.Object({ port: bridgePortField }),
|
|
18711
18750
|
async handler(_input, context) {
|
|
18712
18751
|
const resolved = loadConfig();
|
|
18713
18752
|
if ("error" in resolved) return {
|