@pmate/cli 0.28.4 → 0.28.6

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/README.md CHANGED
@@ -52,6 +52,7 @@ pmate im1 health
52
52
  pmate im1 threads --limit 20
53
53
  pmate im1 threads --search "titlte" --limit 5
54
54
  pmate im1 messages --thread "<conversationId-or-thread-name>" --limit 50
55
+ pmate im1 pending-mentions --hours 24 --context 10
55
56
  pmate im1 reply --thread "<conversationId-or-thread-name>" --text "hello"
56
57
  ```
57
58
 
package/dist/index.d.ts CHANGED
@@ -628,6 +628,16 @@ type CollectCommandArgs = {
628
628
  thread: string;
629
629
  limit?: number;
630
630
  json?: boolean;
631
+ } | {
632
+ type: Command.Collect;
633
+ action: "pending-mentions";
634
+ me: string;
635
+ from?: string;
636
+ to?: string;
637
+ hours: number;
638
+ context: number;
639
+ limit?: number;
640
+ json?: boolean;
631
641
  } | {
632
642
  type: Command.Collect;
633
643
  action: "reply";
@@ -1044,6 +1054,8 @@ type ServiceCommandArgs = {
1044
1054
  bump: "patch" | "minor" | "major";
1045
1055
  cwd?: string;
1046
1056
  force: boolean;
1057
+ releaseNotes?: string;
1058
+ minimumVersionCode?: number;
1047
1059
  baseUrl?: string;
1048
1060
  json: boolean;
1049
1061
  } | {
package/dist/index.js CHANGED
@@ -12073,7 +12073,7 @@ var AliyunService = class {
12073
12073
  static getStaticAssetCacheControl(filePath) {
12074
12074
  const normalized = filePath.replace(/\\/g, "/");
12075
12075
  const base = import_node_path6.default.posix.basename(normalized).toLowerCase();
12076
- if (base === "index.html" || base === "200.html" || base === "404.html" || base === "apple-app-site-association") {
12076
+ if (base === "index.html" || base === "200.html" || base === "404.html" || base === "latest.json" || base === "apple-app-site-association") {
12077
12077
  return "no-cache, no-store, must-revalidate";
12078
12078
  }
12079
12079
  if (/[.-][a-z0-9_-]{8,}\./i.test(base)) {
@@ -16869,6 +16869,16 @@ var Im1BotClient = class {
16869
16869
  );
16870
16870
  return json.messages ?? [];
16871
16871
  }
16872
+ async listPendingMentions(input) {
16873
+ const params = new URLSearchParams({
16874
+ me: input.me,
16875
+ from: input.from,
16876
+ to: input.to,
16877
+ context: String(input.context)
16878
+ });
16879
+ if (input.limit) params.set("limit", String(input.limit));
16880
+ return this.request(`/mentions/pending?${params.toString()}`);
16881
+ }
16872
16882
  async sendMessage(input) {
16873
16883
  return this.request("/messages/send", {
16874
16884
  method: "POST",
@@ -17105,6 +17115,10 @@ var CollectCommandHandler = class {
17105
17115
  await this.handleBotMessages(args);
17106
17116
  return;
17107
17117
  }
17118
+ if (args.action === "pending-mentions") {
17119
+ await this.handleBotPendingMentions(args);
17120
+ return;
17121
+ }
17108
17122
  if (args.action === "reply") {
17109
17123
  await this.handleBotReply(args);
17110
17124
  return;
@@ -17148,6 +17162,32 @@ var CollectCommandHandler = class {
17148
17162
  ui.plain(formatBotMessage(message));
17149
17163
  }
17150
17164
  }
17165
+ async handleBotPendingMentions(args) {
17166
+ const to = args.to ? new Date(args.to) : /* @__PURE__ */ new Date();
17167
+ const from = args.from ? new Date(args.from) : new Date(to.getTime() - args.hours * 60 * 60 * 1e3);
17168
+ if (from >= to) throw new Error("Expected --from to be earlier than --to");
17169
+ const result = await new Im1BotClient().listPendingMentions({
17170
+ me: args.me,
17171
+ from: from.toISOString(),
17172
+ to: to.toISOString(),
17173
+ context: args.context,
17174
+ limit: args.limit
17175
+ });
17176
+ if (args.json !== false) {
17177
+ ui.plain(JSON.stringify(result, null, 2));
17178
+ return;
17179
+ }
17180
+ if (result.mentions.length === 0) {
17181
+ ui.plain("No pending mentions found.");
17182
+ return;
17183
+ }
17184
+ for (const mention of result.mentions) {
17185
+ ui.plain(`${mention.sentAt} ${mention.thread?.name ?? mention.conversationId} ${mention.sender ?? "unknown"}: ${mention.body}`);
17186
+ for (const message of mention.context) {
17187
+ ui.plain(` ${message.sentAt} ${message.sender ?? "unknown"}: ${message.body}`);
17188
+ }
17189
+ }
17190
+ }
17151
17191
  async handleBotReply(args) {
17152
17192
  const client = new Im1BotClient();
17153
17193
  const attachment = args.file ? await readOutgoingAttachment(args.file) : void 0;
@@ -20034,9 +20074,29 @@ var AndroidApkReleaseService = class {
20034
20074
  ui.warn("APK uploaded but registry artifact record failed", error instanceof Error ? error.message : String(error));
20035
20075
  }
20036
20076
  }
20077
+ if (options.env === "prod" && options.variant.toLowerCase() === "release") {
20078
+ await this.publishLatestManifest(service, artifact, options);
20079
+ }
20037
20080
  ui.success(`Released APK ${artifact.downloadUrl}`);
20038
20081
  return artifact;
20039
20082
  }
20083
+ async publishLatestManifest(service, artifact, options) {
20084
+ const manifest = buildAndroidLatestManifest(artifact, {
20085
+ releaseNotes: options.releaseNotes,
20086
+ minimumVersionCode: options.minimumVersionCode
20087
+ });
20088
+ const objectKey = buildAndroidLatestManifestObjectKey(service.namespace, service.name);
20089
+ const tempDir = (0, import_node_fs20.mkdtempSync)(import_node_path25.default.join(import_node_os9.default.tmpdir(), "pmate-apk-latest-"));
20090
+ const manifestPath = import_node_path25.default.join(tempDir, "latest.json");
20091
+ try {
20092
+ (0, import_node_fs20.writeFileSync)(manifestPath, `${JSON.stringify(manifest, null, 2)}
20093
+ `);
20094
+ await AliyunService.uploadFile(manifestPath, ANDROID_APK_BUCKET, objectKey);
20095
+ ui.success(`Published Android update manifest ${ANDROID_APK_PUBLIC_BASE_URL}/${objectKey}`);
20096
+ } finally {
20097
+ (0, import_node_fs20.rmSync)(tempDir, { recursive: true, force: true });
20098
+ }
20099
+ }
20040
20100
  async list(service, options) {
20041
20101
  const serviceId = service.id;
20042
20102
  if (this.registry) {
@@ -20169,6 +20229,26 @@ function bumpVersionName(versionName, bump) {
20169
20229
  function buildAndroidApkObjectKey(namespace, serviceName, versionName) {
20170
20230
  return `apks/${encodePathSegment(namespace)}/${encodePathSegment(serviceName)}/${encodePathSegment(versionName)}.apk`;
20171
20231
  }
20232
+ function buildAndroidLatestManifestObjectKey(namespace, serviceName) {
20233
+ return `apks/${namespace}/${serviceName}/latest.json`;
20234
+ }
20235
+ function buildAndroidLatestManifest(artifact, options = {}) {
20236
+ const minimumVersionCode = options.minimumVersionCode ?? 0;
20237
+ if (!Number.isInteger(minimumVersionCode) || minimumVersionCode < 0 || minimumVersionCode > artifact.versionCode) {
20238
+ throw new Error(`minimumVersionCode must be between 0 and released versionCode ${artifact.versionCode}`);
20239
+ }
20240
+ return {
20241
+ applicationId: artifact.applicationId,
20242
+ versionName: artifact.versionName,
20243
+ versionCode: artifact.versionCode,
20244
+ downloadUrl: artifact.downloadUrl,
20245
+ sha256: artifact.sha256,
20246
+ size: artifact.size,
20247
+ releaseNotes: options.releaseNotes?.trim() ?? "",
20248
+ minimumVersionCode,
20249
+ publishedAt: options.publishedAt ?? (/* @__PURE__ */ new Date()).toISOString()
20250
+ };
20251
+ }
20172
20252
  function resolveRepositoryLocalRoot(repository) {
20173
20253
  const repoName = repository.replace(/\/+$/, "").split("/").pop()?.replace(/\.git$/i, "");
20174
20254
  if (!repoName) {
@@ -22289,7 +22369,9 @@ var ServiceCommandHandler = class {
22289
22369
  variant: args.variant,
22290
22370
  bump: args.bump,
22291
22371
  cwd: args.cwd,
22292
- force: args.force
22372
+ force: args.force,
22373
+ releaseNotes: args.releaseNotes,
22374
+ minimumVersionCode: args.minimumVersionCode
22293
22375
  });
22294
22376
  this.renderApkArtifacts([artifact], args.json);
22295
22377
  return;
@@ -26135,6 +26217,8 @@ function parseServiceApkArgs(tokens, defaults) {
26135
26217
  let force = false;
26136
26218
  let major = false;
26137
26219
  let minor = false;
26220
+ let releaseNotes;
26221
+ let minimumVersionCode;
26138
26222
  while (rest.length > 0) {
26139
26223
  const token = rest.shift();
26140
26224
  switch (token) {
@@ -26171,6 +26255,17 @@ function parseServiceApkArgs(tokens, defaults) {
26171
26255
  }
26172
26256
  minor = true;
26173
26257
  break;
26258
+ case "--release-notes":
26259
+ if (apkAction !== "release") throw new Error(`Unknown service apk ${apkAction} option: ${token}`);
26260
+ releaseNotes = requireValue6(rest, token);
26261
+ break;
26262
+ case "--minimum-version-code": {
26263
+ if (apkAction !== "release") throw new Error(`Unknown service apk ${apkAction} option: ${token}`);
26264
+ const value = Number(requireValue6(rest, token));
26265
+ if (!Number.isInteger(value) || value < 0) throw new Error("--minimum-version-code must be a non-negative integer");
26266
+ minimumVersionCode = value;
26267
+ break;
26268
+ }
26174
26269
  case "--base-url":
26175
26270
  baseUrl = requireValue6(rest, token);
26176
26271
  break;
@@ -26205,6 +26300,8 @@ function parseServiceApkArgs(tokens, defaults) {
26205
26300
  bump: major ? "major" : minor ? "minor" : "patch",
26206
26301
  cwd,
26207
26302
  force,
26303
+ releaseNotes,
26304
+ minimumVersionCode,
26208
26305
  baseUrl,
26209
26306
  json
26210
26307
  };
@@ -27610,6 +27707,9 @@ function parseIm1Args(tokens) {
27610
27707
  if (action === "messages") {
27611
27708
  return parseIm1MessagesArgs(rest);
27612
27709
  }
27710
+ if (action === "pending-mentions") {
27711
+ return parseIm1PendingMentionsArgs(rest);
27712
+ }
27613
27713
  if (action === "reply") {
27614
27714
  return parseIm1ReplyArgs(rest);
27615
27715
  }
@@ -27618,6 +27718,51 @@ function parseIm1Args(tokens) {
27618
27718
  }
27619
27719
  throw new Error(`Unknown im1 action: ${action}`);
27620
27720
  }
27721
+ function parseIm1PendingMentionsArgs(tokens) {
27722
+ const rest = [...tokens];
27723
+ let me = "Chef Ryan";
27724
+ let from;
27725
+ let to;
27726
+ let hours = 24;
27727
+ let context = 10;
27728
+ let limit;
27729
+ let json = true;
27730
+ while (rest.length > 0) {
27731
+ const token = rest.shift();
27732
+ switch (token) {
27733
+ case "--me":
27734
+ me = requireValue12(rest, token);
27735
+ break;
27736
+ case "--from":
27737
+ from = parseIsoDate(requireValue12(rest, token), token);
27738
+ break;
27739
+ case "--to":
27740
+ to = parseIsoDate(requireValue12(rest, token), token);
27741
+ break;
27742
+ case "--hours":
27743
+ hours = parsePositiveInt2(requireValue12(rest, token), token);
27744
+ break;
27745
+ case "--context":
27746
+ context = parseBoundedPositiveInt(requireValue12(rest, token), token, 50);
27747
+ break;
27748
+ case "--limit":
27749
+ limit = parseBoundedPositiveInt(requireValue12(rest, token), token, 500);
27750
+ break;
27751
+ case "--json":
27752
+ json = true;
27753
+ break;
27754
+ case "--text":
27755
+ json = false;
27756
+ break;
27757
+ default:
27758
+ throw new Error(`Unknown im1 pending-mentions option: ${token}`);
27759
+ }
27760
+ }
27761
+ if (from && !to || !from && to) {
27762
+ throw new Error("Use --from and --to together");
27763
+ }
27764
+ return { type: "collect" /* Collect */, action: "pending-mentions", me, from, to, hours, context, limit, json };
27765
+ }
27621
27766
  function parseIm1HealthArgs(tokens) {
27622
27767
  const rest = [...tokens];
27623
27768
  let json = false;
@@ -27782,6 +27927,16 @@ function parsePositiveInt2(value, optionName) {
27782
27927
  }
27783
27928
  return parsed;
27784
27929
  }
27930
+ function parseBoundedPositiveInt(value, optionName, max) {
27931
+ const parsed = parsePositiveInt2(value, optionName);
27932
+ if (parsed > max) throw new Error(`Invalid value for ${optionName}: ${value} (max ${max})`);
27933
+ return parsed;
27934
+ }
27935
+ function parseIsoDate(value, optionName) {
27936
+ const date = new Date(value);
27937
+ if (!Number.isFinite(date.getTime())) throw new Error(`Invalid value for ${optionName}: ${value}`);
27938
+ return date.toISOString();
27939
+ }
27785
27940
 
27786
27941
  // src/chatRoomCommandParser.ts
27787
27942
  function parseChatRoomArgs(tokens) {
@@ -28007,6 +28162,7 @@ var HELP_TEXT = [
28007
28162
  ` ${import_chalk4.default.gray(" health [--json]")}`,
28008
28163
  ` ${import_chalk4.default.gray(" threads [--q <keyword>] [--search <title>] [--limit <n>] [--json|--text]")}`,
28009
28164
  ` ${import_chalk4.default.gray(" messages --thread <name|conversation-id> [--limit <n>] [--json|--text]")}`,
28165
+ ` ${import_chalk4.default.gray(" pending-mentions [--me <name>] [--hours <n>|--from <iso> --to <iso>] [--context <1-50>] [--limit <1-500>] [--json|--text]")}`,
28010
28166
  ` ${import_chalk4.default.gray(" reply --thread <name|conversation-id> [--text <text>] [--file|--image <path>] [--dryrun]")}`,
28011
28167
  ` ${import_chalk4.default.gray(" react --thread <name|conversation-id> --emoji <emoji> [--message <id|timestamp>] [--remove] [--dryrun]")}`,
28012
28168
  ` ${import_chalk4.default.cyan("collect")} Legacy alias for CC/yelling collection`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pmate/cli",
3
- "version": "0.28.4",
3
+ "version": "0.28.6",
4
4
  "description": "CLI utilities for the pMate project",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -11,16 +11,6 @@
11
11
  "files": [
12
12
  "dist"
13
13
  ],
14
- "scripts": {
15
- "build": "npm run clean && tsup --config tsup.config.ts && node scripts/copy-templates.js",
16
- "clean": "rimraf dist",
17
- "dev": "ts-node src/index.ts",
18
- "release": "npm publish",
19
- "start": "node dist/index.js",
20
- "test": "vitest run src/tests",
21
- "typecheck": "tsc --noEmit",
22
- "prepare": "npm run build"
23
- },
24
14
  "keywords": [
25
15
  "cli",
26
16
  "typescript",
@@ -67,10 +57,13 @@
67
57
  "typescript": "^5.9.3",
68
58
  "vitest": "^4.0.17"
69
59
  },
70
- "pnpm": {
71
- "overrides": {
72
- "@pmate/meta": "^1.1.15",
73
- "@pmate/utils": "^1.1.4"
74
- }
60
+ "scripts": {
61
+ "build": "npm run clean && tsup --config tsup.config.ts && node scripts/copy-templates.js",
62
+ "clean": "rimraf dist",
63
+ "dev": "ts-node src/index.ts",
64
+ "release": "pnpm publish",
65
+ "start": "node dist/index.js",
66
+ "test": "vitest run src/tests",
67
+ "typecheck": "tsc --noEmit"
75
68
  }
76
- }
69
+ }