md4ai 0.15.0 → 0.16.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.
@@ -122,7 +122,7 @@ var CURRENT_VERSION;
122
122
  var init_check_update = __esm({
123
123
  "dist/check-update.js"() {
124
124
  "use strict";
125
- CURRENT_VERSION = true ? "0.15.0" : "0.0.0-dev";
125
+ CURRENT_VERSION = true ? "0.16.1" : "0.0.0-dev";
126
126
  }
127
127
  });
128
128
 
@@ -304,6 +304,13 @@ var init_login = __esm({
304
304
  });
305
305
 
306
306
  // dist/device-utils.js
307
+ var device_utils_exports = {};
308
+ __export(device_utils_exports, {
309
+ detectDeviceName: () => detectDeviceName,
310
+ detectOs: () => detectOs,
311
+ resolveDeviceId: () => resolveDeviceId,
312
+ updateDeviceCliVersion: () => updateDeviceCliVersion
313
+ });
307
314
  import { hostname, platform } from "node:os";
308
315
  function detectOs() {
309
316
  const p = platform();
@@ -1769,6 +1776,51 @@ async function discoverSkills(installPath) {
1769
1776
  skills.sort((a, b) => a.name.localeCompare(b.name));
1770
1777
  return skills;
1771
1778
  }
1779
+ async function checkPluginLatestVersions(plugins) {
1780
+ const results = [];
1781
+ for (const plugin of plugins) {
1782
+ let latestVersion = null;
1783
+ if (plugin.homepageUrl && plugin.homepageUrl.includes("github.com") && !plugin.homepageUrl.includes("/tree/main/plugins/")) {
1784
+ try {
1785
+ const match = plugin.homepageUrl.match(/github\.com\/([^/]+\/[^/]+)/);
1786
+ if (match) {
1787
+ const ownerRepo = match[1];
1788
+ const controller = new AbortController();
1789
+ const timeout = setTimeout(() => controller.abort(), 3e3);
1790
+ let res = await fetch(`https://api.github.com/repos/${ownerRepo}/releases/latest`, {
1791
+ signal: controller.signal,
1792
+ headers: { Accept: "application/vnd.github.v3+json" }
1793
+ });
1794
+ clearTimeout(timeout);
1795
+ if (res.ok) {
1796
+ const data = await res.json();
1797
+ latestVersion = data.tag_name?.replace(/^v/, "") ?? null;
1798
+ } else {
1799
+ const controller2 = new AbortController();
1800
+ const timeout2 = setTimeout(() => controller2.abort(), 3e3);
1801
+ res = await fetch(`https://api.github.com/repos/${ownerRepo}/tags?per_page=1`, {
1802
+ signal: controller2.signal,
1803
+ headers: { Accept: "application/vnd.github.v3+json" }
1804
+ });
1805
+ clearTimeout(timeout2);
1806
+ if (res.ok) {
1807
+ const data = await res.json();
1808
+ latestVersion = data[0]?.name?.replace(/^v/, "") ?? null;
1809
+ }
1810
+ }
1811
+ }
1812
+ } catch {
1813
+ }
1814
+ }
1815
+ results.push({
1816
+ pluginName: plugin.pluginName,
1817
+ installedVersion: plugin.version,
1818
+ latestVersion,
1819
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString()
1820
+ });
1821
+ }
1822
+ return results;
1823
+ }
1772
1824
  var init_marketplace_scanner = __esm({
1773
1825
  "dist/scanner/marketplace-scanner.js"() {
1774
1826
  "use strict";
@@ -2056,6 +2108,7 @@ async function scanProject(projectRoot, folderId) {
2056
2108
  brokenRefs.sort((a, b) => a.depth - b.depth || a.from.localeCompare(b.from));
2057
2109
  const scanData = JSON.stringify({ graph, orphans, brokenRefs, skills, staleFiles, toolings, envManifest, marketplacePlugins, doppler: doppler2 });
2058
2110
  const dataHash = createHash("sha256").update(scanData).digest("hex");
2111
+ const pluginVersions = await checkPluginLatestVersions(marketplacePlugins);
2059
2112
  return {
2060
2113
  graph,
2061
2114
  orphans,
@@ -2066,6 +2119,7 @@ async function scanProject(projectRoot, folderId) {
2066
2119
  envManifest,
2067
2120
  doppler: doppler2,
2068
2121
  marketplacePlugins,
2122
+ pluginVersions,
2069
2123
  scannedAt: (/* @__PURE__ */ new Date()).toISOString(),
2070
2124
  dataHash
2071
2125
  };
@@ -2586,6 +2640,7 @@ ${proposedFiles.length} file(s) proposed for deletion:
2586
2640
  env_manifest_json: result.envManifest,
2587
2641
  doppler_json: result.doppler,
2588
2642
  marketplace_plugins_json: result.marketplacePlugins,
2643
+ plugin_versions_json: result.pluginVersions,
2589
2644
  data_hash: result.dataHash,
2590
2645
  scanned_at: result.scannedAt,
2591
2646
  cli_version: CURRENT_VERSION
@@ -2706,6 +2761,7 @@ ${proposedFiles.length} file(s) proposed for deletion:
2706
2761
  env_manifest_json: result.envManifest,
2707
2762
  doppler_json: result.doppler,
2708
2763
  marketplace_plugins_json: result.marketplacePlugins,
2764
+ plugin_versions_json: result.pluginVersions,
2709
2765
  data_hash: result.dataHash,
2710
2766
  scanned_at: result.scannedAt,
2711
2767
  cli_version: CURRENT_VERSION
@@ -2772,7 +2828,8 @@ function isValidProjectPath(p) {
2772
2828
  async function syncCommand(options) {
2773
2829
  const { supabase, userId } = await getAuthenticatedClient();
2774
2830
  if (options.all) {
2775
- const { data: devices, error } = await supabase.from("device_paths").select("folder_id, device_name, path");
2831
+ const currentDeviceName = detectDeviceName();
2832
+ const { data: devices, error } = await supabase.from("device_paths").select("folder_id, device_name, path").eq("device_name", currentDeviceName);
2776
2833
  if (error || !devices?.length) {
2777
2834
  console.error(chalk15.red("No devices found."));
2778
2835
  process.exit(1);
@@ -2819,6 +2876,7 @@ async function syncCommand(options) {
2819
2876
  stale_files_json: result.staleFiles,
2820
2877
  broken_refs_json: result.brokenRefs,
2821
2878
  env_manifest_json: result.envManifest,
2879
+ plugin_versions_json: result.pluginVersions,
2822
2880
  data_hash: result.dataHash,
2823
2881
  scanned_at: result.scannedAt,
2824
2882
  cli_version: CURRENT_VERSION
@@ -2882,6 +2940,7 @@ async function syncCommand(options) {
2882
2940
  skills_table_json: result.skills,
2883
2941
  stale_files_json: result.staleFiles,
2884
2942
  broken_refs_json: result.brokenRefs,
2943
+ plugin_versions_json: result.pluginVersions,
2885
2944
  data_hash: result.dataHash,
2886
2945
  scanned_at: result.scannedAt,
2887
2946
  cli_version: CURRENT_VERSION
@@ -2901,6 +2960,7 @@ var init_sync = __esm({
2901
2960
  init_scanner();
2902
2961
  init_push_toolings();
2903
2962
  init_check_update();
2963
+ init_device_utils();
2904
2964
  }
2905
2965
  });
2906
2966
 
@@ -4099,6 +4159,7 @@ Linking "${folder.name}" to this device...
4099
4159
  env_manifest_json: result.envManifest,
4100
4160
  doppler_json: result.doppler,
4101
4161
  marketplace_plugins_json: result.marketplacePlugins,
4162
+ plugin_versions_json: result.pluginVersions,
4102
4163
  data_hash: result.dataHash,
4103
4164
  scanned_at: result.scannedAt,
4104
4165
  cli_version: CURRENT_VERSION
@@ -4704,7 +4765,9 @@ async function postUpdateFlow() {
4704
4765
  }
4705
4766
  }
4706
4767
  const { supabase } = await getAuthenticatedClient();
4707
- const { data: linkedPaths } = await supabase.from("device_paths").select("path, folder_id").order("path");
4768
+ const { detectDeviceName: detectDeviceName2 } = await Promise.resolve().then(() => (init_device_utils(), device_utils_exports));
4769
+ const currentDeviceName = detectDeviceName2();
4770
+ const { data: linkedPaths } = await supabase.from("device_paths").select("path, folder_id").eq("device_name", currentDeviceName).order("path");
4708
4771
  let linkedDisplay = "";
4709
4772
  if (linkedPaths?.length) {
4710
4773
  const folderIds = [...new Set(linkedPaths.map((p) => p.folder_id))];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "md4ai",
3
- "version": "0.15.0",
3
+ "version": "0.16.1",
4
4
  "description": "CLI for MD4AI — scan Claude projects and sync to your dashboard",
5
5
  "type": "module",
6
6
  "bin": {