@hncode/hncode 0.3.3 → 0.3.5
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/LICENSE +131 -674
- package/README.md +5 -4
- package/README_CN.md +5 -4
- package/package.json +2 -2
- package/src/agent-task.js +78 -0
- package/src/agent.js +75 -45
- package/src/config.js +63 -19
- package/src/git.js +170 -1
- package/src/index.js +27 -13
- package/src/llm.js +7 -3
- package/src/mcp.js +21 -13
- package/src/plugin.js +10 -8
- package/src/term.js +84 -46
- package/src/tui.js +659 -186
- package/src/tui.js.bak_20260921_191527 +9203 -0
- package/src/update.js +35 -14
package/src/update.js
CHANGED
|
@@ -10,26 +10,48 @@
|
|
|
10
10
|
// resolve to a status string, never throw to the caller. The TUI calls them from
|
|
11
11
|
// timers / startup without awaiting.
|
|
12
12
|
|
|
13
|
-
import { spawn
|
|
13
|
+
import { spawn } from 'node:child_process';
|
|
14
14
|
import { localVersion } from './version.js';
|
|
15
15
|
|
|
16
16
|
const PKG_NAME = '@hncode/hncode';
|
|
17
|
+
// Spawn npm portably. On Windows npm is a `.cmd` shim, and Node refuses to spawn
|
|
18
|
+
// a `.cmd` directly (EINVAL) — it must go through a shell. Using
|
|
19
|
+
// `cmd.exe /c npm ...` keeps that behaviour while avoiding `shell: true`, which
|
|
20
|
+
// Node warns about (with a shell, args are concatenated rather than escaped).
|
|
21
|
+
function spawnNpm(args, opts) {
|
|
22
|
+
if (process.platform === 'win32') return spawn('cmd.exe', ['/c', 'npm', ...args], opts);
|
|
23
|
+
return spawn('npm', args, opts);
|
|
24
|
+
}
|
|
17
25
|
// How often the auto-check runs once we are past the startup check.
|
|
18
26
|
export const AUTO_UPDATE_INTERVAL_MS = 30 * 60 * 1000; // 30 minutes
|
|
19
27
|
export { localVersion };
|
|
20
28
|
|
|
21
29
|
// Latest version published to npm, or '' if the registry is unreachable /
|
|
22
30
|
// not installed / not a package.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
//
|
|
32
|
+
// ASYNC on purpose: `execSync` blocks the whole event loop, so a cold `npm view`
|
|
33
|
+
// (measured at ~15s on a slow registry, vs ~2s warm) froze the TUI — no key
|
|
34
|
+
// handling, no repaint — for the entire duration. `spawn` runs the same command
|
|
35
|
+
// off the main thread, and the timeout kills it rather than waiting it out.
|
|
36
|
+
export function remoteVersion(timeoutMs = 10000) {
|
|
37
|
+
return new Promise((resolve) => {
|
|
38
|
+
let child;
|
|
39
|
+
try {
|
|
40
|
+
child = spawnNpm(['view', PKG_NAME, 'version', '--silent'], {
|
|
41
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
42
|
+
});
|
|
43
|
+
} catch {
|
|
44
|
+
resolve('');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
let out = '';
|
|
48
|
+
let done = false;
|
|
49
|
+
const finish = (v) => { if (!done) { done = true; clearTimeout(timer); resolve(v); } };
|
|
50
|
+
const timer = setTimeout(() => { try { child.kill(); } catch {} finish(''); }, timeoutMs);
|
|
51
|
+
if (child.stdout) child.stdout.on('data', (d) => { out += d.toString(); });
|
|
52
|
+
child.on('error', () => finish(''));
|
|
53
|
+
child.on('close', () => finish((out || '').trim()));
|
|
54
|
+
});
|
|
33
55
|
}
|
|
34
56
|
|
|
35
57
|
// Parse a semver-ish "x.y.z" (ignore prerelease tags) into comparable numbers.
|
|
@@ -55,10 +77,9 @@ export function updateBackground() {
|
|
|
55
77
|
return new Promise((resolve) => {
|
|
56
78
|
try {
|
|
57
79
|
// `npm install -g` needs to run detached; no need to wait here.
|
|
58
|
-
const child =
|
|
80
|
+
const child = spawnNpm(['install', '-g', `${PKG_NAME}@latest`], {
|
|
59
81
|
detached: true,
|
|
60
82
|
stdio: 'ignore',
|
|
61
|
-
shell: process.platform === 'win32', // npm is npm.cmd on Windows
|
|
62
83
|
});
|
|
63
84
|
child.unref();
|
|
64
85
|
child.on('error', (e) => resolve({ ok: false, error: e.message }));
|
|
@@ -77,7 +98,7 @@ export function updateBackground() {
|
|
|
77
98
|
export async function checkAndUpdate() {
|
|
78
99
|
const local = localVersion();
|
|
79
100
|
if (!local) return { status: 'none', message: "can't read local version" };
|
|
80
|
-
const remote = remoteVersion();
|
|
101
|
+
const remote = await remoteVersion();
|
|
81
102
|
if (!remote) return { status: 'none', message: 'npm registry unreachable' };
|
|
82
103
|
|
|
83
104
|
if (isNewer(remote, local)) {
|