notoken-core 1.0.0 → 1.1.0
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/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/utils/updater.d.ts +32 -0
- package/dist/utils/updater.js +157 -0
- package/package.json +5 -2
package/dist/index.d.ts
CHANGED
|
@@ -44,6 +44,7 @@ export { formatExplain } from "./utils/explain.js";
|
|
|
44
44
|
export { formatParsedCommand } from "./utils/output.js";
|
|
45
45
|
export { Spinner, withSpinner, progressBar } from "./utils/spinner.js";
|
|
46
46
|
export { createBackup, rollback, listBackups, cleanExpiredBackups, formatBackupList } from "./utils/autoBackup.js";
|
|
47
|
+
export { checkForUpdate, checkForUpdateSync, runUpdate, formatUpdateBanner, type UpdateInfo } from "./utils/updater.js";
|
|
47
48
|
export { logFailure, loadFailures, clearFailures } from "./utils/logger.js";
|
|
48
49
|
export { logUncertainty, loadUncertaintyLog, getUncertaintySummary } from "./nlp/uncertainty.js";
|
|
49
50
|
export { recordHistory, loadHistory, getRecentHistory, searchHistory } from "./context/history.js";
|
package/dist/index.js
CHANGED
|
@@ -56,6 +56,8 @@ export { formatParsedCommand } from "./utils/output.js";
|
|
|
56
56
|
export { Spinner, withSpinner, progressBar } from "./utils/spinner.js";
|
|
57
57
|
// ── Auto-backup ──
|
|
58
58
|
export { createBackup, rollback, listBackups, cleanExpiredBackups, formatBackupList } from "./utils/autoBackup.js";
|
|
59
|
+
// ── Updates ──
|
|
60
|
+
export { checkForUpdate, checkForUpdateSync, runUpdate, formatUpdateBanner } from "./utils/updater.js";
|
|
59
61
|
// ── Logging ──
|
|
60
62
|
export { logFailure, loadFailures, clearFailures } from "./utils/logger.js";
|
|
61
63
|
export { logUncertainty, loadUncertaintyLog, getUncertaintySummary } from "./nlp/uncertainty.js";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update checker.
|
|
3
|
+
*
|
|
4
|
+
* Checks notoken.sh/api/version (primary) or npm registry (fallback)
|
|
5
|
+
* for the latest version. Caches result for 1 hour.
|
|
6
|
+
*
|
|
7
|
+
* Used by both CLI (startup banner) and desktop app (badge).
|
|
8
|
+
*/
|
|
9
|
+
export interface UpdateInfo {
|
|
10
|
+
current: string;
|
|
11
|
+
latest: string;
|
|
12
|
+
updateAvailable: boolean;
|
|
13
|
+
checkedAt: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Check for updates. Returns cached result if fresh.
|
|
17
|
+
* Non-blocking — never throws, returns null on failure.
|
|
18
|
+
*/
|
|
19
|
+
export declare function checkForUpdate(): Promise<UpdateInfo | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Synchronous check — reads cache only, no network.
|
|
22
|
+
* Use this for startup banner (non-blocking).
|
|
23
|
+
*/
|
|
24
|
+
export declare function checkForUpdateSync(): UpdateInfo | null;
|
|
25
|
+
/**
|
|
26
|
+
* Run the actual update.
|
|
27
|
+
*/
|
|
28
|
+
export declare function runUpdate(): string;
|
|
29
|
+
/**
|
|
30
|
+
* Format update banner for terminal.
|
|
31
|
+
*/
|
|
32
|
+
export declare function formatUpdateBanner(info: UpdateInfo): string;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update checker.
|
|
3
|
+
*
|
|
4
|
+
* Checks notoken.sh/api/version (primary) or npm registry (fallback)
|
|
5
|
+
* for the latest version. Caches result for 1 hour.
|
|
6
|
+
*
|
|
7
|
+
* Used by both CLI (startup banner) and desktop app (badge).
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
10
|
+
import { resolve } from "node:path";
|
|
11
|
+
import { execSync } from "node:child_process";
|
|
12
|
+
import { USER_HOME } from "./paths.js";
|
|
13
|
+
const CACHE_FILE = resolve(USER_HOME, ".update-check.json");
|
|
14
|
+
const CACHE_TTL = 3600_000; // 1 hour
|
|
15
|
+
const CURRENT_VERSION = getInstalledVersion();
|
|
16
|
+
/**
|
|
17
|
+
* Check for updates. Returns cached result if fresh.
|
|
18
|
+
* Non-blocking — never throws, returns null on failure.
|
|
19
|
+
*/
|
|
20
|
+
export async function checkForUpdate() {
|
|
21
|
+
try {
|
|
22
|
+
// Check cache first
|
|
23
|
+
const cached = readCache();
|
|
24
|
+
if (cached)
|
|
25
|
+
return cached;
|
|
26
|
+
// Fetch latest version
|
|
27
|
+
const latest = await fetchLatestVersion();
|
|
28
|
+
if (!latest)
|
|
29
|
+
return null;
|
|
30
|
+
const info = {
|
|
31
|
+
current: CURRENT_VERSION,
|
|
32
|
+
latest,
|
|
33
|
+
updateAvailable: isNewer(latest, CURRENT_VERSION),
|
|
34
|
+
checkedAt: new Date().toISOString(),
|
|
35
|
+
};
|
|
36
|
+
writeCache(info);
|
|
37
|
+
return info;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Synchronous check — reads cache only, no network.
|
|
45
|
+
* Use this for startup banner (non-blocking).
|
|
46
|
+
*/
|
|
47
|
+
export function checkForUpdateSync() {
|
|
48
|
+
return readCache();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Run the actual update.
|
|
52
|
+
*/
|
|
53
|
+
export function runUpdate() {
|
|
54
|
+
try {
|
|
55
|
+
const result = execSync("npm install -g notoken@latest", {
|
|
56
|
+
encoding: "utf-8",
|
|
57
|
+
timeout: 120_000,
|
|
58
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
59
|
+
});
|
|
60
|
+
// Clear cache so next check picks up new version
|
|
61
|
+
clearCache();
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
throw new Error(`Update failed: ${err instanceof Error ? err.message : err}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Format update banner for terminal.
|
|
70
|
+
*/
|
|
71
|
+
export function formatUpdateBanner(info) {
|
|
72
|
+
if (!info.updateAvailable)
|
|
73
|
+
return "";
|
|
74
|
+
return `\x1b[33m⬆ Update available: ${info.current} → ${info.latest}\x1b[0m \x1b[2m(notoken update)\x1b[0m`;
|
|
75
|
+
}
|
|
76
|
+
// ─── Internals ──────────────────────────────────────────────────────────────
|
|
77
|
+
async function fetchLatestVersion() {
|
|
78
|
+
// Try notoken.sh API first
|
|
79
|
+
try {
|
|
80
|
+
const response = await fetch("https://notoken.sh/api/version", { signal: AbortSignal.timeout(5000) });
|
|
81
|
+
if (response.ok) {
|
|
82
|
+
const data = (await response.json());
|
|
83
|
+
if (data.version)
|
|
84
|
+
return data.version;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch { }
|
|
88
|
+
// Fallback: npm registry
|
|
89
|
+
try {
|
|
90
|
+
const response = await fetch("https://registry.npmjs.org/notoken/latest", { signal: AbortSignal.timeout(5000) });
|
|
91
|
+
if (response.ok) {
|
|
92
|
+
const data = (await response.json());
|
|
93
|
+
if (data.version)
|
|
94
|
+
return data.version;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch { }
|
|
98
|
+
// Fallback: npm CLI
|
|
99
|
+
try {
|
|
100
|
+
const result = execSync("npm view notoken version", { encoding: "utf-8", timeout: 10_000, stdio: ["pipe", "pipe", "pipe"] });
|
|
101
|
+
return result.trim() || null;
|
|
102
|
+
}
|
|
103
|
+
catch { }
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
function getInstalledVersion() {
|
|
107
|
+
try {
|
|
108
|
+
// Read from our own package.json
|
|
109
|
+
const pkg = JSON.parse(execSync("npm list -g notoken --json --depth=0 2>/dev/null", { encoding: "utf-8", timeout: 5000 }));
|
|
110
|
+
return pkg.dependencies?.notoken?.version ?? "0.0.0";
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return "0.0.0";
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function isNewer(latest, current) {
|
|
117
|
+
const l = latest.split(".").map(Number);
|
|
118
|
+
const c = current.split(".").map(Number);
|
|
119
|
+
for (let i = 0; i < 3; i++) {
|
|
120
|
+
if ((l[i] ?? 0) > (c[i] ?? 0))
|
|
121
|
+
return true;
|
|
122
|
+
if ((l[i] ?? 0) < (c[i] ?? 0))
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
function readCache() {
|
|
128
|
+
try {
|
|
129
|
+
if (!existsSync(CACHE_FILE))
|
|
130
|
+
return null;
|
|
131
|
+
const raw = JSON.parse(readFileSync(CACHE_FILE, "utf-8"));
|
|
132
|
+
const age = Date.now() - new Date(raw.checkedAt).getTime();
|
|
133
|
+
if (age > CACHE_TTL)
|
|
134
|
+
return null;
|
|
135
|
+
// Refresh current version in case user updated
|
|
136
|
+
raw.current = CURRENT_VERSION;
|
|
137
|
+
raw.updateAvailable = isNewer(raw.latest, CURRENT_VERSION);
|
|
138
|
+
return raw;
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function writeCache(info) {
|
|
145
|
+
try {
|
|
146
|
+
mkdirSync(USER_HOME, { recursive: true });
|
|
147
|
+
writeFileSync(CACHE_FILE, JSON.stringify(info));
|
|
148
|
+
}
|
|
149
|
+
catch { }
|
|
150
|
+
}
|
|
151
|
+
function clearCache() {
|
|
152
|
+
try {
|
|
153
|
+
if (existsSync(CACHE_FILE))
|
|
154
|
+
writeFileSync(CACHE_FILE, "{}");
|
|
155
|
+
}
|
|
156
|
+
catch { }
|
|
157
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "notoken-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Shared engine for notoken — NLP parsing, execution, detection, analysis",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,7 +16,10 @@
|
|
|
16
16
|
"exports": {
|
|
17
17
|
".": "./dist/index.js"
|
|
18
18
|
},
|
|
19
|
-
"files": [
|
|
19
|
+
"files": [
|
|
20
|
+
"dist/",
|
|
21
|
+
"config/"
|
|
22
|
+
],
|
|
20
23
|
"scripts": {
|
|
21
24
|
"build": "tsc",
|
|
22
25
|
"test": "vitest run"
|