maesttro 0.4.0 → 0.4.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
@@ -177,6 +177,9 @@ config, keeping your own keys. So `maesttro update` has two steps:
177
177
  Your session state (in the `maesttro-home` volume) and your project files are
178
178
  untouched by an update.
179
179
 
180
+ On start, `maesttro` checks for a newer published version and offers to update.
181
+ Declining only skips it for that run; the next start asks again.
182
+
180
183
  ---
181
184
 
182
185
  ## What's mounted, and why
package/dist/maesttro.js CHANGED
@@ -2443,16 +2443,60 @@ async function setup({ args }) {
2443
2443
 
2444
2444
  // src/update.ts
2445
2445
  import { execSync as execSync5 } from "node:child_process";
2446
- import { readFileSync as readFileSync8 } from "node:fs";
2446
+
2447
+ // src/version-check.ts
2448
+ import { execFile } from "node:child_process";
2449
+ import { existsSync as existsSync6, readFileSync as readFileSync8 } from "node:fs";
2447
2450
  import { join as join12 } from "node:path";
2448
- function installedPackageName() {
2449
- const manifest = JSON.parse(readFileSync8(join12(PACKAGE_ROOT, "package.json"), "utf8"));
2450
- return manifest.name;
2451
+ var LOOKUP_TIMEOUT_MS = 3000;
2452
+ function installedManifest() {
2453
+ return JSON.parse(readFileSync8(join12(PACKAGE_ROOT, "package.json"), "utf8"));
2454
+ }
2455
+ function canOfferUpdate({
2456
+ interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY),
2457
+ inRunner = existsSync6(RUNNER_MARKER)
2458
+ } = {}) {
2459
+ return interactive && !inRunner;
2460
+ }
2461
+ function releaseNumbers(version) {
2462
+ const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version.trim());
2463
+ return match ? match.slice(1).map(Number) : undefined;
2451
2464
  }
2465
+ function isNewer({
2466
+ candidate,
2467
+ current
2468
+ }) {
2469
+ const candidateNumbers = releaseNumbers(candidate);
2470
+ const currentNumbers = releaseNumbers(current);
2471
+ if (!candidateNumbers || !currentNumbers)
2472
+ return false;
2473
+ for (let index = 0;index < candidateNumbers.length; index++) {
2474
+ const difference = (candidateNumbers[index] ?? 0) - (currentNumbers[index] ?? 0);
2475
+ if (difference !== 0)
2476
+ return difference > 0;
2477
+ }
2478
+ return false;
2479
+ }
2480
+ function publishedVersion(name) {
2481
+ return new Promise((resolve, reject) => execFile("npm", ["view", name, "version"], { timeout: LOOKUP_TIMEOUT_MS }, (error, stdout) => error ? reject(error) : resolve(stdout.trim())));
2482
+ }
2483
+ async function findNewerVersion({
2484
+ manifest = installedManifest(),
2485
+ lookupLatest = publishedVersion
2486
+ } = {}) {
2487
+ try {
2488
+ const latest = await lookupLatest(manifest.name);
2489
+ return isNewer({ candidate: latest, current: manifest.version }) ? { name: manifest.name, current: manifest.version, latest } : undefined;
2490
+ } catch {
2491
+ return;
2492
+ }
2493
+ }
2494
+
2495
+ // src/update.ts
2452
2496
  function update() {
2453
2497
  console.log(`== maesttro update ==
2454
2498
  `);
2455
- const packageName = installedPackageName();
2499
+ const packageName = installedManifest().name;
2456
2500
  console.log(`-> Updating ${packageName} package...`);
2457
2501
  execSync5(`npm i -g ${packageName}@latest`, { stdio: "inherit" });
2458
2502
  console.log(`
@@ -2475,8 +2519,27 @@ var defaultCommands = {
2475
2519
  login,
2476
2520
  logout,
2477
2521
  status,
2478
- print: (text) => console.log(text)
2522
+ print: (text) => console.log(text),
2523
+ findNewerVersion: () => canOfferUpdate() ? findNewerVersion() : Promise.resolve(undefined),
2524
+ ask
2479
2525
  };
2526
+ var SKIPS_UPDATE_CHECK = new Set(["update", "list", "help", "--help", "-h"]);
2527
+ async function updatedInstead({
2528
+ command,
2529
+ commands
2530
+ }) {
2531
+ if (command !== undefined && SKIPS_UPDATE_CHECK.has(command))
2532
+ return false;
2533
+ const available = await commands.findNewerVersion();
2534
+ if (!available)
2535
+ return false;
2536
+ const answer = await commands.ask(`${available.name} ${available.latest} is available (you have ${available.current}). Update now? [Y/n] `);
2537
+ if (!/^(y(es)?)?$/i.test(answer))
2538
+ return false;
2539
+ await commands.update();
2540
+ commands.print("Re-run maesttro to continue.");
2541
+ return true;
2542
+ }
2480
2543
  var MODE_FLAGS = {
2481
2544
  "--strict": true,
2482
2545
  "--no-strict": false
@@ -2516,6 +2579,8 @@ async function main(argv, commands = defaultCommands) {
2516
2579
  commands.print(`--strict and --no-strict apply to launching a session, not to \`${command}\`.`);
2517
2580
  return;
2518
2581
  }
2582
+ if (await updatedInstead({ command, commands }))
2583
+ return;
2519
2584
  switch (command) {
2520
2585
  case undefined:
2521
2586
  await commands.launch({ args: [], ...mode });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maesttro",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Isolated Docker runner for local coding agents (opencode, claude, ...) under a dedicated bot GitHub identity, with curated configs baked in per client.",
5
5
  "type": "module",
6
6
  "bin": {