@novare-technologies/nvaid 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
@@ -31,6 +31,27 @@ nvaid init --owning-repo frontend # preset the config's owning_repo
31
31
  nvaid init --yes # non-interactive (defaults to the AGENTS.md catch-all)
32
32
  ```
33
33
 
34
+ ## Upgrading
35
+
36
+ Upgrading is **two steps**, because `nvaid update` re-syncs a repo to the version of the
37
+ tool installed on your machine — it does not upgrade the tool itself:
38
+
39
+ ```bash
40
+ # 1. upgrade the tool (once per machine, when a new version ships)
41
+ npm i -g @novare-technologies/nvaid@latest
42
+
43
+ # 2. re-sync each repo to the new version (run inside each repo)
44
+ nvaid update
45
+ ```
46
+
47
+ nvaid checks npm (at most once a day, cached, non-blocking) and prints a one-line nudge
48
+ when a newer version is available — it never upgrades itself (the package manager owns the
49
+ tool's lifecycle). Silence the check with `NVAID_NO_UPDATE_CHECK=1`.
50
+
51
+ Note: `nvaid update` never touches hand-owned files (`config.yml`, `PROJECT-RULES.md`,
52
+ `DESIGN-CODE-DICTIONARY.md`, `intents/`). If a new version adds a config field, add it to
53
+ your `config.yml` by hand — the changelog will call these out.
54
+
34
55
  ## How it works
35
56
 
36
57
  - **Full skill set, no profiles.** `init` injects every skill into each selected agent. A
package/dist/cli.js CHANGED
@@ -109,8 +109,8 @@ var NVAID_DIR_NAME = "nvaid";
109
109
  var CONFIG_FILE = "config.yml";
110
110
  var AIDLC_ROOT_TOKEN = "{{AIDLC_ROOT}}";
111
111
  async function nvaidVersion() {
112
- const { readFile: readFile3 } = await import("fs/promises");
113
- const pkg = JSON.parse(await readFile3(resolve(TEMPLATES_DIR, "..", "package.json"), "utf8"));
112
+ const { readFile: readFile4 } = await import("fs/promises");
113
+ const pkg = JSON.parse(await readFile4(resolve(TEMPLATES_DIR, "..", "package.json"), "utf8"));
114
114
  return pkg.version;
115
115
  }
116
116
 
@@ -460,6 +460,81 @@ async function runValidate() {
460
460
  return 0;
461
461
  }
462
462
 
463
+ // src/updateNotifier.ts
464
+ import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
465
+ import { homedir, tmpdir } from "os";
466
+ import { join as join4 } from "path";
467
+ import pc4 from "picocolors";
468
+ var PKG = "@novare-technologies/nvaid";
469
+ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
470
+ var FETCH_TIMEOUT_MS = 1500;
471
+ function cacheFile() {
472
+ const base = process.env.XDG_CACHE_HOME || join4(homedir(), ".cache");
473
+ return join4(base || tmpdir(), "nvaid", "update-check.json");
474
+ }
475
+ async function readCache() {
476
+ try {
477
+ return JSON.parse(await readFile3(cacheFile(), "utf8"));
478
+ } catch {
479
+ return null;
480
+ }
481
+ }
482
+ async function writeCache(c) {
483
+ try {
484
+ const f = cacheFile();
485
+ await mkdir3(join4(f, ".."), { recursive: true });
486
+ await writeFile3(f, JSON.stringify(c), "utf8");
487
+ } catch {
488
+ }
489
+ }
490
+ async function fetchLatest() {
491
+ try {
492
+ const ctrl = new AbortController();
493
+ const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
494
+ const res = await fetch(`https://registry.npmjs.org/${PKG}/latest`, {
495
+ signal: ctrl.signal
496
+ });
497
+ clearTimeout(timer);
498
+ if (!res.ok) return null;
499
+ const data = await res.json();
500
+ return data.version ?? null;
501
+ } catch {
502
+ return null;
503
+ }
504
+ }
505
+ function isNewer(a, b) {
506
+ const pa = a.split(".").map((n) => parseInt(n, 10));
507
+ const pb = b.split(".").map((n) => parseInt(n, 10));
508
+ for (let i = 0; i < 3; i++) {
509
+ const x = pa[i] ?? 0;
510
+ const y = pb[i] ?? 0;
511
+ if (x > y) return true;
512
+ if (x < y) return false;
513
+ }
514
+ return false;
515
+ }
516
+ async function notifyIfOutdated() {
517
+ if (process.env.NVAID_NO_UPDATE_CHECK) return;
518
+ const current = await nvaidVersion();
519
+ const cache = await readCache();
520
+ const now = Date.now();
521
+ let latest = null;
522
+ if (cache && now - cache.lastCheck < CHECK_INTERVAL_MS) {
523
+ latest = cache.latest;
524
+ } else {
525
+ latest = await fetchLatest();
526
+ if (latest) await writeCache({ lastCheck: now, latest });
527
+ }
528
+ if (!latest || !isNewer(latest, current)) return;
529
+ const line = (s) => process.stderr.write(s + "\n");
530
+ line("");
531
+ line(pc4.yellow(` \u250C\u2500 nvaid update available \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`));
532
+ line(pc4.yellow(" \u2502 ") + `${pc4.dim(current)} \u2192 ${pc4.green(latest)}`);
533
+ line(pc4.yellow(" \u2502 ") + `run: ${pc4.cyan(`npm i -g ${PKG}@latest`)}`);
534
+ line(pc4.yellow(" \u2502 ") + pc4.dim(`then re-sync your repo: nvaid update`));
535
+ line(pc4.yellow(` \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`));
536
+ }
537
+
463
538
  // src/cli.ts
464
539
  var program = new Command();
465
540
  program.name("nvaid").description("nvaid \u2014 install an AI-DLC skills + workflow toolkit into any coding agent").version(await nvaidVersion());
@@ -475,9 +550,13 @@ program.command("update").description("Re-sync agent files to the installed nvai
475
550
  await runUpdate();
476
551
  });
477
552
  program.command("validate").description("Fail if generated agent files are stale or hand-edited").action(async () => {
478
- process.exit(await runValidate());
553
+ const code = await runValidate();
554
+ await notifyIfOutdated();
555
+ process.exit(code);
479
556
  });
480
- program.parseAsync().catch((err) => {
557
+ program.parseAsync().then(async () => {
558
+ await notifyIfOutdated();
559
+ }).catch((err) => {
481
560
  console.error(err instanceof Error ? err.message : err);
482
561
  process.exit(1);
483
562
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@novare-technologies/nvaid",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "nvaid — one CLI that installs an AI-DLC skills-and-workflow toolkit into any coding agent, and houses intents, config, and the design-code dictionary in a single nvaid/ folder.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -84,4 +84,4 @@ context: ""
84
84
 
85
85
  # nvaid version this repo was last generated against. `nvaid validate` compares the
86
86
  # installed CLI version to this and flags drift.
87
- generated_with: "0.2.0"
87
+ generated_with: "0.2.1"