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