@audiofool/moondog 0.2.0 → 0.2.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.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  <h1 align="center">Moondog</h1>
6
6
 
7
- <p align="center">Version 0.2.0</p>
7
+ <p align="center">Version 0.2.1</p>
8
8
 
9
9
  <p align="center"><strong>A listening room that shows its work.</strong></p>
10
10
 
@@ -33,7 +33,7 @@ npm ci
33
33
  npm start
34
34
  ```
35
35
 
36
- [@audiofool/moondog](https://www.npmjs.com/package/@audiofool/moondog) 0.1.0 is the published package.
36
+ [@audiofool/moondog](https://www.npmjs.com/package/@audiofool/moondog) 0.2.0 is the published package; `npm install --global @audiofool/moondog` installs it.
37
37
  To see the agent work through fictional data, with no sign-in at all, run `npm run demo` from the checkout.
38
38
 
39
39
  The source version supports `moondog update` and `/update`, with stable (`latest`) and preview (`beta`) channels.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@audiofool/moondog",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "description": "Local-first personal AI music agent.",
6
6
  "license": "Apache-2.0",
@@ -151,21 +151,31 @@ export function createApplicationUpdater({ root = DEFAULT_ROOT, environment = pr
151
151
  let result;
152
152
  try {
153
153
  const controller = AbortSignal.timeout(5_000);
154
- const response = await fetchImpl(`https://registry.npmjs.org/@audiofool%2fmoondog/${channel}`, {
155
- signal: signal ? AbortSignal.any([signal, controller]) : controller,
156
- redirect: "error", headers: { Accept: "application/json" },
157
- });
158
- if (response.status === 404) throw failure("update_channel_empty", `No ${channel} release has been published yet.`);
159
- if (!response.ok) throw new Error("Registry unavailable");
160
- const body = (await boundedBody(response, 512_000)).toString("utf8");
161
- const release = JSON.parse(body);
162
- if (release.name !== UPDATE_PACKAGE || !releaseVersion(release.version) ||
163
- channel === "latest" && release.version.includes("-") ||
164
- ![`${REPOSITORY}.git`, `git+${REPOSITORY}.git`].includes(release.repository?.url)) throw new Error("Invalid release metadata");
165
- const minimum = release.engines?.node?.match(/^>=(\d+\.\d+\.\d+)$/u)?.[1];
166
- if (!minimum || !releaseVersion(minimum)) throw new Error("Unsupported runtime requirement");
167
- const tarball = `https://registry.npmjs.org/@audiofool/moondog/-/moondog-${release.version}.tgz`;
168
- if (release.dist?.tarball !== tarball || !/^sha512-[A-Za-z0-9+/]{86}==$/u.test(release.dist?.integrity ?? "")) throw new Error("Unsupported package integrity metadata");
154
+ const fetchChannel = async candidate => {
155
+ const response = await fetchImpl(`https://registry.npmjs.org/@audiofool%2fmoondog/${candidate}`, {
156
+ signal: signal ? AbortSignal.any([signal, controller]) : controller,
157
+ redirect: "error", headers: { Accept: "application/json" },
158
+ });
159
+ if (response.status === 404) throw failure("update_channel_empty", `No ${candidate} release has been published yet.`);
160
+ if (!response.ok) throw new Error("Registry unavailable");
161
+ const release = JSON.parse((await boundedBody(response, 512_000)).toString("utf8"));
162
+ if (release.name !== UPDATE_PACKAGE || !releaseVersion(release.version) ||
163
+ candidate === "latest" && release.version.includes("-") ||
164
+ ![`${REPOSITORY}.git`, `git+${REPOSITORY}.git`].includes(release.repository?.url)) throw new Error("Invalid release metadata");
165
+ const minimum = release.engines?.node?.match(/^>=(\d+\.\d+\.\d+)$/u)?.[1];
166
+ if (!minimum || !releaseVersion(minimum)) throw new Error("Unsupported runtime requirement");
167
+ const tarball = `https://registry.npmjs.org/@audiofool/moondog/-/moondog-${release.version}.tgz`;
168
+ if (release.dist?.tarball !== tarball || !/^sha512-[A-Za-z0-9+/]{86}==$/u.test(release.dist?.integrity ?? "")) throw new Error("Unsupported package integrity metadata");
169
+ return { release, minimum, tarball };
170
+ };
171
+ // Preview users receive the stable successor without changing their saved beta preference.
172
+ // One unavailable channel must not hide a valid release from the other channel.
173
+ const checks = await Promise.allSettled((channel === "beta" ? ["beta", "latest"] : ["latest"]).map(fetchChannel));
174
+ const candidates = checks.filter(check => check.status === "fulfilled").map(check => check.value)
175
+ .sort((a, b) => compareReleaseVersions(b.release.version, a.release.version));
176
+ if (!candidates.length) throw checks[0].reason;
177
+ signal?.throwIfAborted();
178
+ const { release, minimum, tarball } = candidates[0];
169
179
  result = { state: compareReleaseVersions(release.version, current.version) > 0 ? "available" : "current", current: current.version,
170
180
  latest: release.version, channel, minimumNode: minimum,
171
181
  compatible: compareReleaseVersions(process.versions.node, minimum) >= 0,