noterai 0.1.2 → 0.1.3

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/bin/noter.js CHANGED
@@ -11,9 +11,11 @@ import { loadConfig } from '../packages/server/dist/config.js';
11
11
  import { resolveRepoContext } from '../packages/server/dist/repoContext.js';
12
12
  import { stateManager } from '../packages/server/dist/stateManager.js';
13
13
  import { execSync } from 'child_process';
14
- import { resolve, dirname, basename } from 'path';
14
+ import { request } from 'node:https';
15
+ import { resolve, dirname, basename, join } from 'path';
16
+ import { homedir } from 'node:os';
15
17
  import { fileURLToPath } from 'url';
16
- import { existsSync, readFileSync } from 'fs';
18
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
17
19
  const __filename = fileURLToPath(import.meta.url);
18
20
  const __dirname = dirname(__filename);
19
21
  const ROOT = resolve(__dirname, '..');
@@ -30,6 +32,106 @@ function getVersion() {
30
32
  const pkg = JSON.parse(raw);
31
33
  return pkg.version ?? '0.0.1';
32
34
  }
35
+ /** Cache path for the npm update check so we don't hit the registry on every launch. */
36
+ const UPDATE_CACHE_DIR = process.env.NOTER_UPDATE_CACHE_DIR ?? join(homedir(), '.noter');
37
+ const UPDATE_CACHE_FILE = join(UPDATE_CACHE_DIR, 'update-check.json');
38
+ const UPDATE_CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24h
39
+ const UPDATE_CHECK_TIMEOUT_MS = 2500;
40
+ const NPM_PACKAGE = 'noterai';
41
+ function readUpdateCache() {
42
+ try {
43
+ const raw = readFileSync(UPDATE_CACHE_FILE, 'utf-8');
44
+ const parsed = JSON.parse(raw);
45
+ if (typeof parsed.lastChecked === 'number') {
46
+ return { lastChecked: parsed.lastChecked, latestVersion: parsed.latestVersion ?? null };
47
+ }
48
+ }
49
+ catch {
50
+ // ignore missing/corrupt cache
51
+ }
52
+ return null;
53
+ }
54
+ function writeUpdateCache(cache) {
55
+ try {
56
+ if (!existsSync(UPDATE_CACHE_DIR))
57
+ mkdirSync(UPDATE_CACHE_DIR, { recursive: true });
58
+ writeFileSync(UPDATE_CACHE_FILE, JSON.stringify(cache));
59
+ }
60
+ catch {
61
+ // cache is best-effort; never block launch on it
62
+ }
63
+ }
64
+ /** Fetch latest published version from the npm registry. Resolves to null on any error. */
65
+ function fetchLatestVersion() {
66
+ return new Promise((resolvePromise) => {
67
+ let settled = false;
68
+ const finish = (v) => {
69
+ if (!settled) {
70
+ settled = true;
71
+ resolvePromise(v);
72
+ }
73
+ };
74
+ const timer = setTimeout(() => finish(null), UPDATE_CHECK_TIMEOUT_MS);
75
+ try {
76
+ const req = request({
77
+ hostname: 'registry.npmjs.org',
78
+ path: `/${NPM_PACKAGE}/latest`,
79
+ method: 'GET',
80
+ headers: { 'accept': 'application/json' },
81
+ }, (res) => {
82
+ let body = '';
83
+ res.setEncoding('utf-8');
84
+ res.on('data', (chunk) => { body += chunk; });
85
+ res.on('end', () => {
86
+ clearTimeout(timer);
87
+ try {
88
+ const data = JSON.parse(body);
89
+ finish(typeof data.version === 'string' ? data.version : null);
90
+ }
91
+ catch {
92
+ finish(null);
93
+ }
94
+ });
95
+ });
96
+ req.on('error', () => { clearTimeout(timer); finish(null); });
97
+ req.end();
98
+ }
99
+ catch {
100
+ clearTimeout(timer);
101
+ finish(null);
102
+ }
103
+ });
104
+ }
105
+ /** Simple semver "is b newer than a" comparator (major.minor.patch, no pre-release). */
106
+ function isNewerVersion(current, latest) {
107
+ const parse = (v) => v.split('-')[0].split('.').map((n) => parseInt(n, 10) || 0);
108
+ const [a0, a1, a2] = parse(current);
109
+ const [b0, b1, b2] = parse(latest);
110
+ if (b0 !== a0)
111
+ return b0 > a0;
112
+ if (b1 !== a1)
113
+ return b1 > a1;
114
+ return b2 > a2;
115
+ }
116
+ /**
117
+ * Non-blocking launch-time update check. Checks the npm registry at most once per
118
+ * UPDATE_CACHE_TTL_MS and prints an upgrade hint if a newer version of `noterai`
119
+ * is published. Never throws or blocks startup.
120
+ */
121
+ async function checkForUpdate() {
122
+ const current = getVersion();
123
+ const cache = readUpdateCache();
124
+ let latest = cache?.latestVersion ?? null;
125
+ const stale = !cache || Date.now() - cache.lastChecked > UPDATE_CACHE_TTL_MS;
126
+ if (stale) {
127
+ latest = await fetchLatestVersion();
128
+ writeUpdateCache({ lastChecked: Date.now(), latestVersion: latest });
129
+ }
130
+ if (latest && isNewerVersion(current, latest)) {
131
+ console.log(`update noterai v${latest} available (you have v${current})`);
132
+ console.log(' run `npm install -g noterai` to upgrade');
133
+ }
134
+ }
33
135
  function showHelp() {
34
136
  const version = getVersion();
35
137
  const help = `
@@ -46,6 +148,12 @@ Commands:
46
148
  help Show this help message
47
149
  version Print the version number
48
150
 
151
+ Update Behavior:
152
+ On launch, noter checks the npm registry (at most once per 24h) for a newer
153
+ "noterai" release and prints an upgrade hint. Disable by deleting
154
+ ~/.noter/update-check.json or setting NOTER_UPDATE_CACHE_DIR. To upgrade:
155
+ npm install -g noterai
156
+
49
157
  Options:
50
158
  serve --open Open the browser after starting the server
51
159
  serve --no-open Do not open the browser (default for 'serve')
@@ -182,6 +290,9 @@ async function serve(openBrowser) {
182
290
  console.log(`port ${portLine}`);
183
291
  console.log(divider);
184
292
  console.log('ready. press ctrl+c to stop.');
293
+ // Non-blocking update check — prints an upgrade hint if a newer noterai is on npm.
294
+ // Fire-and-forget so it never delays startup; output may land just after "ready".
295
+ void checkForUpdate();
185
296
  if (openBrowser) {
186
297
  const url = `http://localhost:${resolvedPort}`;
187
298
  const opener = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "noterai",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Locally-run, browser-based AI agent dashboard for developers using LLM coding assistants",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -28,7 +28,6 @@
28
28
  },
29
29
  "files": [
30
30
  "bin/noter.js",
31
- "bin/noter.js.map",
32
31
  "packages/client/dist",
33
32
  "packages/server/dist",
34
33
  "packages/shared/dist",