@hienlh/ppm 0.9.44 → 0.9.46

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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.46] - 2026-04-06
4
+
5
+ ### Added
6
+ - **/version command**: Shows current PPM version in Telegram.
7
+
8
+ ## [0.9.45] - 2026-04-06
9
+
10
+ ### Fixed
11
+ - **Identity lost on server restart**: Identity save ran AFTER `streamToTelegram()` — if streaming timed out, the save was skipped. Moved identity persistence to before streaming so it writes to SQLite immediately.
12
+
13
+ ### Added
14
+ - **Restart notification includes version**: `/restart` now sends "PPM v0.9.45 restarted successfully" instead of generic message.
15
+
3
16
  ## [0.9.42] - 2026-04-06
4
17
 
5
18
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hienlh/ppm",
3
- "version": "0.9.44",
3
+ "version": "0.9.46",
4
4
  "description": "Personal Project Manager — mobile-first web IDE with AI assistance",
5
5
  "author": "hienlh",
6
6
  "license": "MIT",
@@ -182,6 +182,7 @@ class PPMBotService {
182
182
  case "forget": await this.cmdForget(chatId, cmd.args); break;
183
183
  case "remember": await this.cmdRemember(chatId, cmd.args); break;
184
184
  case "restart": await this.cmdRestart(chatId); break;
185
+ case "version": await this.cmdVersion(chatId); break;
185
186
  case "help": await this.cmdHelp(chatId); break;
186
187
  default: await tg.sendMessage(Number(chatId), `Unknown command: /${cmd.command}`);
187
188
  }
@@ -407,12 +408,31 @@ class PPMBotService {
407
408
  // Only notify if restart was recent (< 60s)
408
409
  if (Date.now() - data.ts > 60_000) return;
409
410
 
411
+ // Read version from package.json
412
+ let version = "";
413
+ try {
414
+ const pkgPath = join(import.meta.dir, "../../../package.json");
415
+ const pkg = await Bun.file(pkgPath).json();
416
+ version = pkg.version ? ` v${pkg.version}` : "";
417
+ } catch {}
418
+
410
419
  for (const cid of data.chatIds) {
411
- await this.telegram?.sendMessage(Number(cid), "✅ PPM restarted successfully.");
420
+ await this.telegram?.sendMessage(Number(cid), `✅ PPM${version} restarted successfully.`);
412
421
  }
413
422
  } catch {}
414
423
  }
415
424
 
425
+ private async cmdVersion(chatId: string): Promise<void> {
426
+ let version = "unknown";
427
+ try {
428
+ const { join } = await import("node:path");
429
+ const pkgPath = join(import.meta.dir, "../../../package.json");
430
+ const pkg = await Bun.file(pkgPath).json();
431
+ version = pkg.version ?? "unknown";
432
+ } catch {}
433
+ await this.telegram!.sendMessage(Number(chatId), `<b>PPM</b> v${version}`);
434
+ }
435
+
416
436
  private async cmdHelp(chatId: string): Promise<void> {
417
437
  const text = `<b>PPMBot Commands</b>
418
438
 
@@ -427,6 +447,7 @@ class PPMBotService {
427
447
  /forget &lt;topic&gt; — Remove matching memories
428
448
  /remember &lt;fact&gt; — Save a fact
429
449
  /restart — Restart PPM server
450
+ /version — Show PPM version
430
451
  /help — This message`;
431
452
  await this.telegram!.sendMessage(Number(chatId), text);
432
453
  }
@@ -500,6 +521,20 @@ class PPMBotService {
500
521
  fullMessage = `<system-context>\n${systemPrompt}\n</system-context>\n\n${text}`;
501
522
  }
502
523
 
524
+ // Save identity BEFORE streaming — must persist even if streaming times out
525
+ if (this.identityPending.has(chatId)) {
526
+ this.identityPending.delete(chatId);
527
+ this.memory.saveOne("_global", `User identity: ${text}`, "preference", session.sessionId);
528
+ console.log("[ppmbot] Saved identity memory from onboarding");
529
+ } else if (!this.hasCheckedIdentity.has(chatId)) {
530
+ this.hasCheckedIdentity.add(chatId);
531
+ const globalMems = this.memory.getSummary("_global", 50);
532
+ if (!globalMems.some((m) => m.category === "preference" && /identity/i.test(m.content))) {
533
+ this.memory.saveOne("_global", `User identity: ${text}`, "preference", session.sessionId);
534
+ console.log("[ppmbot] Saved identity memory (first message, no identity found)");
535
+ }
536
+ }
537
+
503
538
  const events = chatService.sendMessage(
504
539
  session.providerId,
505
540
  session.sessionId,
@@ -518,21 +553,6 @@ class PPMBotService {
518
553
  },
519
554
  );
520
555
 
521
- // Capture identity: save when onboarding was shown OR when no identity exists
522
- // (handles server restarts losing the in-memory flag)
523
- if (this.identityPending.has(chatId)) {
524
- this.identityPending.delete(chatId);
525
- this.memory.saveOne("_global", `User identity: ${text}`, "preference", session.sessionId);
526
- console.log("[ppmbot] Saved identity memory from onboarding");
527
- } else if (!this.hasCheckedIdentity.has(chatId)) {
528
- this.hasCheckedIdentity.add(chatId);
529
- const globalMems = this.memory.getSummary("_global", 50);
530
- if (!globalMems.some((m) => m.category === "preference" && /identity/i.test(m.content))) {
531
- this.memory.saveOne("_global", `User identity: ${text}`, "preference", session.sessionId);
532
- console.log("[ppmbot] Saved identity memory (first message, no identity found)");
533
- }
534
- }
535
-
536
556
  // Periodic memory extraction — fire-and-forget every N messages
537
557
  const count = (this.messageCount.get(session.sessionId) ?? 0) + 1;
538
558
  this.messageCount.set(session.sessionId, count);
@@ -13,7 +13,7 @@ const BOT_TOKEN_RE = /^\d+:[A-Za-z0-9_-]{30,50}$/;
13
13
  /** Known PPMBot slash commands */
14
14
  const COMMANDS = new Set([
15
15
  "start", "project", "new", "sessions", "resume",
16
- "status", "stop", "memory", "forget", "remember", "restart", "help",
16
+ "status", "stop", "memory", "forget", "remember", "restart", "version", "help",
17
17
  ]);
18
18
 
19
19
  export type UpdateHandler = (update: TelegramUpdate) => Promise<void>;
@@ -53,6 +53,7 @@ export class PPMBotTelegram {
53
53
  { command: "forget", description: "Remove matching memories" },
54
54
  { command: "remember", description: "Save a fact" },
55
55
  { command: "restart", description: "Restart PPM server" },
56
+ { command: "version", description: "Show PPM version" },
56
57
  { command: "help", description: "Show all commands" },
57
58
  ],
58
59
  });