@pmate/cli 0.23.0 → 0.24.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.js +117 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9633,9 +9633,10 @@ function loadRepoConfig(cwd) {
|
|
|
9633
9633
|
return normalizeRepoConfig(parsed, paths.configPath);
|
|
9634
9634
|
}
|
|
9635
9635
|
function loadAppConfig(cwd, options = {}) {
|
|
9636
|
-
const
|
|
9636
|
+
const searchParents = options.searchParents ?? true;
|
|
9637
|
+
const paths = findRepoConfigPaths(cwd, searchParents);
|
|
9637
9638
|
if (!paths) {
|
|
9638
|
-
const suffix =
|
|
9639
|
+
const suffix = searchParents ? " or parent directories" : "";
|
|
9639
9640
|
throw new Error(`No .pmate.yaml found in ${cwd}${suffix}`);
|
|
9640
9641
|
}
|
|
9641
9642
|
const parsed = loadMergedRepoYaml(paths);
|
|
@@ -17233,6 +17234,7 @@ init_sessionStore();
|
|
|
17233
17234
|
|
|
17234
17235
|
// src/appIcon.ts
|
|
17235
17236
|
var import_node_fs15 = require("fs");
|
|
17237
|
+
var import_node_os7 = __toESM(require("os"));
|
|
17236
17238
|
var import_node_path20 = __toESM(require("path"));
|
|
17237
17239
|
var import_sharp = __toESM(require("sharp"));
|
|
17238
17240
|
init_namespacedRef();
|
|
@@ -17254,6 +17256,8 @@ var IOS_ICON_SPECS = [
|
|
|
17254
17256
|
var pngToIco = require("png-to-ico").default;
|
|
17255
17257
|
var APP_ICON_VARIANT_KEY_PATTERN = /^[a-z0-9]+$/;
|
|
17256
17258
|
var DATA_URL_PATTERN = /^data:([^;,]+);base64,([a-z0-9+/=]+)$/i;
|
|
17259
|
+
var DEFAULT_APP_ICON_VARIANT_BUCKET = "parrot-static";
|
|
17260
|
+
var DEFAULT_APP_ICON_VARIANT_PUBLIC_BASE_URL = "https://parrot-static.pmate.chat";
|
|
17257
17261
|
var DEFAULT_APP_ICON_VARIANT_NAME = "webp512x512";
|
|
17258
17262
|
function normalizeAppIcon(icon, cwd) {
|
|
17259
17263
|
if (typeof icon !== "string" || !icon.trim()) {
|
|
@@ -17271,7 +17275,7 @@ function normalizeAppIcon(icon, cwd) {
|
|
|
17271
17275
|
}
|
|
17272
17276
|
throw new Error("App icon must be an http(s) URL. Upload SVG files to OSS first and use the public link.");
|
|
17273
17277
|
}
|
|
17274
|
-
async function prepareAppPayload(payload, cwd) {
|
|
17278
|
+
async function prepareAppPayload(payload, cwd, options) {
|
|
17275
17279
|
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
17276
17280
|
throw new Error("App payload must be a JSON object.");
|
|
17277
17281
|
}
|
|
@@ -17286,7 +17290,8 @@ async function prepareAppPayload(payload, cwd) {
|
|
|
17286
17290
|
normalized.icons = await withDefaultSvgIconVariant(
|
|
17287
17291
|
normalized.icon,
|
|
17288
17292
|
normalized.icons,
|
|
17289
|
-
cwd
|
|
17293
|
+
cwd,
|
|
17294
|
+
options?.appRef || inferAppRefFromPayload(normalized)
|
|
17290
17295
|
);
|
|
17291
17296
|
}
|
|
17292
17297
|
return normalized;
|
|
@@ -17381,17 +17386,35 @@ async function renderAppIconVariant(input) {
|
|
|
17381
17386
|
(0, import_node_fs15.mkdirSync)(import_node_path20.default.dirname(outputPath), { recursive: true });
|
|
17382
17387
|
(0, import_node_fs15.writeFileSync)(outputPath, bytes);
|
|
17383
17388
|
}
|
|
17389
|
+
if (input.name) {
|
|
17390
|
+
return {
|
|
17391
|
+
value: await uploadAppIconVariantAsset({
|
|
17392
|
+
appRef: input.appRef,
|
|
17393
|
+
icon: input.icon,
|
|
17394
|
+
name: input.name,
|
|
17395
|
+
format: input.format,
|
|
17396
|
+
bytes,
|
|
17397
|
+
sourcePath: outputPath
|
|
17398
|
+
}),
|
|
17399
|
+
...outputPath ? { outputPath } : {}
|
|
17400
|
+
};
|
|
17401
|
+
}
|
|
17384
17402
|
return {
|
|
17385
17403
|
value: createImageDataUrl(bytes, input.format),
|
|
17386
17404
|
...outputPath ? { outputPath } : {}
|
|
17387
17405
|
};
|
|
17388
17406
|
}
|
|
17389
|
-
function loadAppIconVariantFile(
|
|
17390
|
-
const absolutePath = import_node_path20.default.resolve(cwd, filePath);
|
|
17407
|
+
async function loadAppIconVariantFile(input) {
|
|
17408
|
+
const absolutePath = import_node_path20.default.resolve(input.cwd, input.filePath);
|
|
17391
17409
|
const format = inferVariantFormatFromPath(absolutePath);
|
|
17392
|
-
const bytes = (0, import_node_fs15.readFileSync)(absolutePath);
|
|
17393
17410
|
return {
|
|
17394
|
-
value:
|
|
17411
|
+
value: input.name ? await uploadAppIconVariantAsset({
|
|
17412
|
+
appRef: input.appRef,
|
|
17413
|
+
icon: input.icon,
|
|
17414
|
+
name: input.name,
|
|
17415
|
+
format,
|
|
17416
|
+
sourcePath: absolutePath
|
|
17417
|
+
}) : createImageDataUrl((0, import_node_fs15.readFileSync)(absolutePath), format),
|
|
17395
17418
|
format,
|
|
17396
17419
|
absolutePath
|
|
17397
17420
|
};
|
|
@@ -17487,9 +17510,11 @@ function isSupportedImageDataUrl(value) {
|
|
|
17487
17510
|
const mimeType = match[1]?.toLowerCase();
|
|
17488
17511
|
return mimeType === "image/png" || mimeType === "image/webp" || mimeType === "image/svg+xml" || mimeType === "image/x-icon";
|
|
17489
17512
|
}
|
|
17490
|
-
async function withDefaultSvgIconVariant(icon, icons, cwd) {
|
|
17513
|
+
async function withDefaultSvgIconVariant(icon, icons, cwd, appRef) {
|
|
17491
17514
|
const variant = await renderAppIconVariant({
|
|
17492
17515
|
icon,
|
|
17516
|
+
name: DEFAULT_APP_ICON_VARIANT_NAME,
|
|
17517
|
+
appRef,
|
|
17493
17518
|
width: 512,
|
|
17494
17519
|
height: 512,
|
|
17495
17520
|
format: "webp",
|
|
@@ -17500,6 +17525,75 @@ async function withDefaultSvgIconVariant(icon, icons, cwd) {
|
|
|
17500
17525
|
[DEFAULT_APP_ICON_VARIANT_NAME]: variant.value
|
|
17501
17526
|
};
|
|
17502
17527
|
}
|
|
17528
|
+
function inferAppRefFromPayload(payload) {
|
|
17529
|
+
const id = payload.id;
|
|
17530
|
+
const namespace = payload.namespace;
|
|
17531
|
+
if (typeof id !== "string" || !id.trim()) {
|
|
17532
|
+
return void 0;
|
|
17533
|
+
}
|
|
17534
|
+
if (typeof namespace !== "string" || !namespace.trim()) {
|
|
17535
|
+
return void 0;
|
|
17536
|
+
}
|
|
17537
|
+
return `${namespace.trim().toLowerCase()}:${id.trim()}`;
|
|
17538
|
+
}
|
|
17539
|
+
async function uploadAppIconVariantAsset(input) {
|
|
17540
|
+
const objectKey = buildAppIconVariantObjectKey(input);
|
|
17541
|
+
const sourcePath = input.sourcePath || writeTempAppIconVariantFile(objectKey, input.format, input.bytes);
|
|
17542
|
+
const shouldCleanup = !input.sourcePath;
|
|
17543
|
+
try {
|
|
17544
|
+
await AliyunService.uploadFile(sourcePath, DEFAULT_APP_ICON_VARIANT_BUCKET, objectKey);
|
|
17545
|
+
} finally {
|
|
17546
|
+
if (shouldCleanup) {
|
|
17547
|
+
(0, import_node_fs15.rmSync)(import_node_path20.default.dirname(sourcePath), { recursive: true, force: true });
|
|
17548
|
+
}
|
|
17549
|
+
}
|
|
17550
|
+
return `${DEFAULT_APP_ICON_VARIANT_PUBLIC_BASE_URL}/${objectKey}`;
|
|
17551
|
+
}
|
|
17552
|
+
function buildAppIconVariantObjectKey(input) {
|
|
17553
|
+
return import_node_path20.default.posix.join(
|
|
17554
|
+
"apps",
|
|
17555
|
+
`${resolveAppIconAssetStem(input.icon, input.appRef)}-${input.name}.${extensionForIconFormat(input.format)}`
|
|
17556
|
+
);
|
|
17557
|
+
}
|
|
17558
|
+
function resolveAppIconAssetStem(icon, appRef) {
|
|
17559
|
+
if (icon) {
|
|
17560
|
+
try {
|
|
17561
|
+
const url = new URL(icon);
|
|
17562
|
+
const ext = import_node_path20.default.posix.extname(url.pathname);
|
|
17563
|
+
const basename = import_node_path20.default.posix.basename(url.pathname, ext);
|
|
17564
|
+
const normalized = sanitizeAppIconAssetStem(basename);
|
|
17565
|
+
if (normalized) {
|
|
17566
|
+
return normalized;
|
|
17567
|
+
}
|
|
17568
|
+
} catch {
|
|
17569
|
+
}
|
|
17570
|
+
}
|
|
17571
|
+
if (appRef) {
|
|
17572
|
+
const { objectId } = parseNamespacedRef(appRef, {
|
|
17573
|
+
entityLabel: "app ref"
|
|
17574
|
+
});
|
|
17575
|
+
const normalized = sanitizeAppIconAssetStem(objectId);
|
|
17576
|
+
if (normalized) {
|
|
17577
|
+
return normalized;
|
|
17578
|
+
}
|
|
17579
|
+
}
|
|
17580
|
+
throw new Error("Unable to determine an asset key for the app icon variant upload.");
|
|
17581
|
+
}
|
|
17582
|
+
function sanitizeAppIconAssetStem(value) {
|
|
17583
|
+
return value.trim().replace(/[^a-z0-9._-]+/gi, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").toLowerCase();
|
|
17584
|
+
}
|
|
17585
|
+
function extensionForIconFormat(format) {
|
|
17586
|
+
return format === "ico" ? "ico" : format;
|
|
17587
|
+
}
|
|
17588
|
+
function writeTempAppIconVariantFile(objectKey, format, bytes) {
|
|
17589
|
+
if (!bytes) {
|
|
17590
|
+
throw new Error("App icon variant upload requires bytes or a source file.");
|
|
17591
|
+
}
|
|
17592
|
+
const tempDir = (0, import_node_fs15.mkdtempSync)(import_node_path20.default.join(import_node_os7.default.tmpdir(), "pmate-app-icon-"));
|
|
17593
|
+
const tempPath = import_node_path20.default.join(tempDir, import_node_path20.default.basename(objectKey) || `variant.${extensionForIconFormat(format)}`);
|
|
17594
|
+
(0, import_node_fs15.writeFileSync)(tempPath, bytes);
|
|
17595
|
+
return tempPath;
|
|
17596
|
+
}
|
|
17503
17597
|
|
|
17504
17598
|
// src/commands/AppCommandHandler.ts
|
|
17505
17599
|
init_namespacedRef();
|
|
@@ -17555,7 +17649,7 @@ var AppCommandHandler = class {
|
|
|
17555
17649
|
return;
|
|
17556
17650
|
}
|
|
17557
17651
|
case "update": {
|
|
17558
|
-
const payload = await this.preparePayload(args.filePath);
|
|
17652
|
+
const payload = await this.preparePayload(args.filePath, args.id);
|
|
17559
17653
|
const pathname = this.buildAppPath(args.id);
|
|
17560
17654
|
const record = await this.request(
|
|
17561
17655
|
baseUrl,
|
|
@@ -17614,7 +17708,13 @@ var AppCommandHandler = class {
|
|
|
17614
17708
|
if (existingIcons[name] && !args.force) {
|
|
17615
17709
|
throw new Error(`App icon variant "${name}" already exists for ${args.id}. Re-run with --force to overwrite it.`);
|
|
17616
17710
|
}
|
|
17617
|
-
const source = args.filePath ?
|
|
17711
|
+
const source = args.filePath ? await loadAppIconVariantFile({
|
|
17712
|
+
filePath: args.filePath,
|
|
17713
|
+
cwd: process.cwd(),
|
|
17714
|
+
name,
|
|
17715
|
+
appRef: args.id,
|
|
17716
|
+
icon: record.icon
|
|
17717
|
+
}) : await this.renderIconVariantFromApp(record, args);
|
|
17618
17718
|
const updatedIcons = {
|
|
17619
17719
|
...existingIcons,
|
|
17620
17720
|
[name]: source.value
|
|
@@ -17711,9 +17811,9 @@ var AppCommandHandler = class {
|
|
|
17711
17811
|
throw new Error(`Invalid JSON in ${absolutePath}: ${message}`);
|
|
17712
17812
|
}
|
|
17713
17813
|
}
|
|
17714
|
-
async preparePayload(filePath) {
|
|
17814
|
+
async preparePayload(filePath, appRef) {
|
|
17715
17815
|
const absolutePath = this.resolveFilePath(filePath);
|
|
17716
|
-
return prepareAppPayload(this.readJsonFile(filePath), import_node_path21.default.dirname(absolutePath));
|
|
17816
|
+
return prepareAppPayload(this.readJsonFile(filePath), import_node_path21.default.dirname(absolutePath), { appRef });
|
|
17717
17817
|
}
|
|
17718
17818
|
resolveFilePath(filePath) {
|
|
17719
17819
|
return import_node_path21.default.resolve(process.cwd(), filePath);
|
|
@@ -17811,6 +17911,8 @@ var AppCommandHandler = class {
|
|
|
17811
17911
|
}
|
|
17812
17912
|
return renderAppIconVariant({
|
|
17813
17913
|
icon: record.icon,
|
|
17914
|
+
name: args.name,
|
|
17915
|
+
appRef: args.id,
|
|
17814
17916
|
width: args.width,
|
|
17815
17917
|
height: args.height,
|
|
17816
17918
|
format: args.format || "png",
|
|
@@ -17838,7 +17940,7 @@ var import_promises6 = require("readline/promises");
|
|
|
17838
17940
|
|
|
17839
17941
|
// src/services/ServiceRuntimeRunner.ts
|
|
17840
17942
|
var import_node_fs17 = require("fs");
|
|
17841
|
-
var
|
|
17943
|
+
var import_node_os8 = __toESM(require("os"));
|
|
17842
17944
|
var import_node_path22 = __toESM(require("path"));
|
|
17843
17945
|
var import_node_child_process10 = require("child_process");
|
|
17844
17946
|
var import_node_readline = require("readline");
|
|
@@ -18010,7 +18112,7 @@ var ServiceRuntimeRunner = class {
|
|
|
18010
18112
|
if (repository) {
|
|
18011
18113
|
const repoName = repository.replace(/\/+$/, "").split("/").pop()?.replace(/\.git$/i, "");
|
|
18012
18114
|
if (repoName) {
|
|
18013
|
-
const candidate = import_node_path22.default.join(
|
|
18115
|
+
const candidate = import_node_path22.default.join(import_node_os8.default.homedir(), "dev", "pmate", repoName);
|
|
18014
18116
|
if ((0, import_node_fs17.existsSync)(candidate)) {
|
|
18015
18117
|
return candidate;
|
|
18016
18118
|
}
|