taskplane 0.1.8 → 0.1.9

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.
@@ -604,6 +604,90 @@ export default function (pi: ExtensionAPI) {
604
604
  "/orch-sessions List TMUX sessions",
605
605
  "info",
606
606
  );
607
+
608
+ // Check for taskplane updates (non-blocking)
609
+ checkForUpdate(ctx);
607
610
  });
608
611
  }
609
612
 
613
+ // ── Update Check ─────────────────────────────────────────────────────
614
+
615
+ /**
616
+ * Check npm registry for a newer version of taskplane.
617
+ *
618
+ * Runs asynchronously and never throws — update check failures are
619
+ * silently ignored so they don't interfere with normal operation.
620
+ */
621
+ async function checkForUpdate(ctx: ExtensionContext): Promise<void> {
622
+ try {
623
+ // Get installed version from our own package.json
624
+ const { readFileSync: readFS } = await import("fs");
625
+ const { dirname, join: joinPath } = await import("path");
626
+ const { fileURLToPath } = await import("url");
627
+
628
+ // Resolve package.json relative to this extension file.
629
+ // In npm install layout: node_modules/taskplane/extensions/taskplane/extension.ts
630
+ // package.json is at: node_modules/taskplane/package.json
631
+ let pkgJsonPath: string;
632
+ try {
633
+ const thisDir = dirname(fileURLToPath(import.meta.url));
634
+ pkgJsonPath = joinPath(thisDir, "..", "..", "package.json");
635
+ } catch {
636
+ // Fallback for environments where import.meta.url is unavailable
637
+ pkgJsonPath = joinPath(__dirname, "..", "..", "package.json");
638
+ }
639
+
640
+ let installedVersion: string;
641
+ try {
642
+ const pkg = JSON.parse(readFS(pkgJsonPath, "utf-8"));
643
+ installedVersion = pkg.version;
644
+ } catch {
645
+ return; // Can't determine installed version — skip check
646
+ }
647
+
648
+ // Fetch latest version from npm registry (5s timeout)
649
+ const controller = new AbortController();
650
+ const timeout = setTimeout(() => controller.abort(), 5000);
651
+
652
+ const response = await fetch("https://registry.npmjs.org/taskplane/latest", {
653
+ signal: controller.signal,
654
+ headers: { "Accept": "application/json" },
655
+ });
656
+ clearTimeout(timeout);
657
+
658
+ if (!response.ok) return;
659
+
660
+ const data = await response.json() as { version?: string };
661
+ const latestVersion = data.version;
662
+ if (!latestVersion) return;
663
+
664
+ // Compare versions (simple semver comparison)
665
+ if (latestVersion !== installedVersion && isNewerVersion(latestVersion, installedVersion)) {
666
+ ctx.ui.notify(
667
+ `\n` +
668
+ ` Update Available\n` +
669
+ ` New version ${latestVersion} is available (installed: ${installedVersion}).\n` +
670
+ ` Run: npm install -g taskplane\n`,
671
+ "info",
672
+ );
673
+ }
674
+ } catch {
675
+ // Silently ignore — network errors, offline, etc.
676
+ }
677
+ }
678
+
679
+ /**
680
+ * Compare two semver version strings. Returns true if `a` is newer than `b`.
681
+ */
682
+ function isNewerVersion(a: string, b: string): boolean {
683
+ const pa = a.split(".").map(Number);
684
+ const pb = b.split(".").map(Number);
685
+ for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
686
+ const na = pa[i] || 0;
687
+ const nb = pb[i] || 0;
688
+ if (na > nb) return true;
689
+ if (na < nb) return false;
690
+ }
691
+ return false;
692
+ }
693
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskplane",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "AI agent orchestration for pi — parallel task execution with checkpoint discipline",
5
5
  "keywords": [
6
6
  "pi-package",