@este.systems/dsc 0.2.2 → 0.3.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/update.js ADDED
@@ -0,0 +1,163 @@
1
+ import { promises as fsp } from "node:fs";
2
+ import { spawn } from "node:child_process";
3
+ import { homedir } from "node:os";
4
+ import * as path from "node:path";
5
+ import { VERSION } from "./version.js";
6
+ const PACKAGE_NAME = "@este.systems/dsc";
7
+ const REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
8
+ const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24h — npm's once-a-day cadence
9
+ function stateDir() {
10
+ const xdg = process.env.XDG_STATE_HOME;
11
+ const base = xdg && xdg.length ? xdg : path.join(homedir(), ".local", "state");
12
+ return path.join(base, "dsc");
13
+ }
14
+ function cachePath() {
15
+ return path.join(stateDir(), "version-check.json");
16
+ }
17
+ async function readCache() {
18
+ try {
19
+ const txt = await fsp.readFile(cachePath(), "utf8");
20
+ const parsed = JSON.parse(txt);
21
+ if (typeof parsed?.latest === "string" && typeof parsed?.fetched_at === "number") {
22
+ return parsed;
23
+ }
24
+ }
25
+ catch {
26
+ // missing / invalid — treat as no cache
27
+ }
28
+ return null;
29
+ }
30
+ async function writeCache(c) {
31
+ try {
32
+ await fsp.mkdir(stateDir(), { recursive: true });
33
+ await fsp.writeFile(cachePath(), JSON.stringify(c, null, 2), "utf8");
34
+ }
35
+ catch {
36
+ // best-effort
37
+ }
38
+ }
39
+ async function fetchLatestVersion(signal) {
40
+ const res = await fetch(REGISTRY_URL, {
41
+ headers: { Accept: "application/json" },
42
+ signal,
43
+ });
44
+ if (!res.ok)
45
+ throw new Error(`registry returned ${res.status}`);
46
+ const data = (await res.json());
47
+ if (typeof data.version !== "string")
48
+ throw new Error("malformed registry response");
49
+ return data.version;
50
+ }
51
+ /**
52
+ * Compare two semver-ish strings (X.Y.Z, ignoring pre-release tails). Returns
53
+ * -1 if a < b, 0 if equal, 1 if a > b. Non-numeric segments compare as 0
54
+ * so we don't accidentally flag "0.3.0-beta.1" as newer than "0.3.0".
55
+ */
56
+ export function compareSemver(a, b) {
57
+ const parse = (s) => s.split(/[.+-]/, 3).map((p) => {
58
+ const n = parseInt(p, 10);
59
+ return Number.isFinite(n) ? n : 0;
60
+ });
61
+ const pa = parse(a);
62
+ const pb = parse(b);
63
+ for (let i = 0; i < 3; i++) {
64
+ const x = pa[i] ?? 0;
65
+ const y = pb[i] ?? 0;
66
+ if (x < y)
67
+ return -1;
68
+ if (x > y)
69
+ return 1;
70
+ }
71
+ return 0;
72
+ }
73
+ /**
74
+ * Returns the latest published version from npm, with a 24h on-disk cache so
75
+ * we don't hammer the registry every launch. Resolves on network failure too
76
+ * — falls back to whatever cached value exists, or just reports current as
77
+ * latest. Designed to be called fire-and-forget at startup.
78
+ *
79
+ * When `force` is true the cache is ignored and a fresh fetch happens. Use
80
+ * for `/update`-style explicit checks.
81
+ */
82
+ export async function checkForUpdate(opts = {}) {
83
+ const current = VERSION;
84
+ const cache = await readCache();
85
+ const fresh = cache && Date.now() - cache.fetched_at < CACHE_TTL_MS;
86
+ if (fresh && !opts.force && cache) {
87
+ return {
88
+ current,
89
+ latest: cache.latest,
90
+ newerAvailable: compareSemver(cache.latest, current) > 0,
91
+ fromCache: true,
92
+ };
93
+ }
94
+ try {
95
+ const latest = await fetchLatestVersion(opts.signal);
96
+ await writeCache({ latest, fetched_at: Date.now() });
97
+ return {
98
+ current,
99
+ latest,
100
+ newerAvailable: compareSemver(latest, current) > 0,
101
+ fromCache: false,
102
+ };
103
+ }
104
+ catch {
105
+ // Network down / registry hiccup — surface whatever we last knew. If we
106
+ // never knew, claim "up to date" so we don't false-positive an upgrade.
107
+ const latest = cache?.latest ?? current;
108
+ return {
109
+ current,
110
+ latest,
111
+ newerAvailable: compareSemver(latest, current) > 0,
112
+ fromCache: !!cache,
113
+ };
114
+ }
115
+ }
116
+ /**
117
+ * Runs `npm install -g <package>@latest`. Streams nothing — we wait for the
118
+ * whole install to finish and return its combined output. Suitable behind
119
+ * the /update slash command, where the user has explicitly asked.
120
+ *
121
+ * The currently-running dsc process keeps running on the old code (Node
122
+ * has already loaded everything into memory). The caller should advise a
123
+ * restart after success.
124
+ */
125
+ export function runUpdate(signal) {
126
+ return new Promise((resolve) => {
127
+ // shell: true so Windows finds npm.cmd; on POSIX it's just `sh -c` which
128
+ // is harmless. Single quoted argv so spaces in package names don't bite.
129
+ const child = spawn("npm", ["install", "-g", `${PACKAGE_NAME}@latest`], {
130
+ shell: true,
131
+ stdio: ["ignore", "pipe", "pipe"],
132
+ windowsHide: true,
133
+ });
134
+ let out = "";
135
+ let aborted = false;
136
+ const onAbort = () => {
137
+ aborted = true;
138
+ child.kill();
139
+ };
140
+ if (signal) {
141
+ if (signal.aborted)
142
+ onAbort();
143
+ else
144
+ signal.addEventListener("abort", onAbort, { once: true });
145
+ }
146
+ child.stdout.on("data", (d) => (out += d.toString()));
147
+ child.stderr.on("data", (d) => (out += d.toString()));
148
+ let settled = false;
149
+ const settle = (ok) => {
150
+ if (settled)
151
+ return;
152
+ settled = true;
153
+ signal?.removeEventListener("abort", onAbort);
154
+ resolve({ ok: ok && !aborted, output: out.trim() });
155
+ };
156
+ child.on("exit", (code) => settle(code === 0));
157
+ child.on("error", (e) => {
158
+ out += `\nspawn error: ${e.message}`;
159
+ settle(false);
160
+ });
161
+ });
162
+ }
163
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@este.systems/dsc",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "CLI coding agent for DeepSeek",
5
5
  "keywords": [
6
6
  "deepseek",