@hncode/hncode 0.5.2 → 0.5.4
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/package.json +2 -2
- package/src/agent.js +172 -19
- package/src/cache.js +175 -130
- package/src/clipboard.js +69 -2
- package/src/index.js +29 -5
- package/src/keybindings.js +25 -3
- package/src/llm.js +54 -6
- package/src/mcp.js +419 -384
- package/src/plugin.js +95 -10
- package/src/remote.js +307 -289
- package/src/shell-safety.js +610 -562
- package/src/swarm-progress.js +1 -1
- package/src/team/mailbox.js +216 -139
- package/src/team/permission.js +121 -0
- package/src/team/protocol.js +167 -0
- package/src/team/runner.js +127 -12
- package/src/team/spawn.js +63 -5
- package/src/team/store.js +31 -4
- package/src/team/tasks.js +15 -2
- package/src/team/team.js +51 -16
- package/src/team-panel.js +418 -20
- package/src/term-caps.js +457 -410
- package/src/term.js +142 -26
- package/src/tool-result.js +50 -2
- package/src/tools/agent.js +464 -436
- package/src/tools/bash.js +53 -14
- package/src/tools/diagnostics.js +13 -0
- package/src/tools/edit.js +813 -590
- package/src/tools/glob.js +5 -3
- package/src/tools/grep.js +19 -5
- package/src/tools/ignore.js +17 -3
- package/src/tools/index.js +17 -3
- package/src/tools/read.js +2 -1
- package/src/tools/shell.js +145 -134
- package/src/tools/tasks.js +214 -141
- package/src/tools/team.js +13 -0
- package/src/tools/utils.js +12 -3
- package/src/tools/web-search.js +88 -88
- package/src/tui.js +1815 -628
- package/src/update.js +38 -3
package/src/update.js
CHANGED
|
@@ -166,6 +166,28 @@ export function readUpdateStamp() {
|
|
|
166
166
|
try { return JSON.parse(fs.readFileSync(updateStampFile(), 'utf8')); } catch { return null; }
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
// npm's own stderr from the background install, beside the stamp. A FILE because
|
|
170
|
+
// the install outlives this process: a pipe belonged to hncode, and quitting
|
|
171
|
+
// mid-install closed it under npm — the install died on EPIPE partway through.
|
|
172
|
+
function updateLogFile() {
|
|
173
|
+
const dir = process.env.HNCODE_HOME || path.join(os.homedir(), '.hncode');
|
|
174
|
+
return path.join(dir, 'update-log.txt');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Last `n` bytes of a file, or ''. Never throws. */
|
|
178
|
+
function tailOfFile(p, n = 4000) {
|
|
179
|
+
try {
|
|
180
|
+
const st = fs.statSync(p);
|
|
181
|
+
const fh = fs.openSync(p, 'r');
|
|
182
|
+
try {
|
|
183
|
+
const start = Math.max(0, st.size - n);
|
|
184
|
+
const buf = Buffer.alloc(st.size - start);
|
|
185
|
+
fs.readSync(fh, buf, 0, buf.length, start);
|
|
186
|
+
return buf.toString('utf8');
|
|
187
|
+
} finally { fs.closeSync(fh); }
|
|
188
|
+
} catch { return ''; }
|
|
189
|
+
}
|
|
190
|
+
|
|
169
191
|
/** Forget it, once it has been reported. Never throws. */
|
|
170
192
|
export function clearUpdateStamp() {
|
|
171
193
|
try { fs.unlinkSync(updateStampFile()); return true; } catch { return false; }
|
|
@@ -202,13 +224,23 @@ export function updateBackground(version = '') {
|
|
|
202
224
|
return;
|
|
203
225
|
}
|
|
204
226
|
|
|
227
|
+
// stderr lands in a file (survives this process); when the file cannot be
|
|
228
|
+
// opened, fall back to a pipe and the in-memory capture below.
|
|
229
|
+
const logFile = updateLogFile();
|
|
230
|
+
let logFd = null;
|
|
231
|
+
try {
|
|
232
|
+
fs.mkdirSync(path.dirname(logFile), { recursive: true });
|
|
233
|
+
logFd = fs.openSync(logFile, 'w');
|
|
234
|
+
} catch { logFd = null; }
|
|
235
|
+
|
|
205
236
|
let child;
|
|
206
237
|
try {
|
|
207
238
|
child = spawnNpm(['install', '-g', `${PKG_NAME}@latest`], {
|
|
208
239
|
detached: true,
|
|
209
|
-
stdio: ['ignore', 'ignore', 'pipe'],
|
|
240
|
+
stdio: ['ignore', 'ignore', logFd == null ? 'pipe' : logFd],
|
|
210
241
|
});
|
|
211
242
|
} catch (e) {
|
|
243
|
+
if (logFd != null) { try { fs.closeSync(logFd); } catch { /* already gone */ } }
|
|
212
244
|
releaseInstallLock();
|
|
213
245
|
const error = (e && e.message) || String(e);
|
|
214
246
|
writeUpdateStamp({ status: 'error', version, error });
|
|
@@ -217,7 +249,7 @@ export function updateBackground(version = '') {
|
|
|
217
249
|
}
|
|
218
250
|
|
|
219
251
|
let stderr = '';
|
|
220
|
-
if (child.stderr) {
|
|
252
|
+
if (logFd == null && child.stderr) {
|
|
221
253
|
child.stderr.setEncoding('utf8');
|
|
222
254
|
child.stderr.on('data', (d) => {
|
|
223
255
|
stderr += d;
|
|
@@ -230,17 +262,20 @@ export function updateBackground(version = '') {
|
|
|
230
262
|
// it prevents.
|
|
231
263
|
child.on('error', (e) => {
|
|
232
264
|
releaseInstallLock();
|
|
265
|
+
if (logFd != null) { try { fs.closeSync(logFd); } catch { /* already gone */ } }
|
|
233
266
|
writeUpdateStamp({ status: 'error', version, error: (e && e.message) || String(e) });
|
|
234
267
|
});
|
|
235
268
|
child.on('close', (code) => {
|
|
236
269
|
releaseInstallLock();
|
|
270
|
+
if (logFd != null) { try { fs.closeSync(logFd); } catch { /* already gone */ } }
|
|
237
271
|
// Exit code 0 is the only thing that means the files were replaced. Anything else —
|
|
238
272
|
// no permission, an unreachable registry, a killed process — is recorded with npm's
|
|
239
273
|
// own last words, which is what makes the next launch's message actionable.
|
|
240
274
|
if (code === 0) {
|
|
241
275
|
writeUpdateStamp({ status: 'installed', version });
|
|
242
276
|
} else {
|
|
243
|
-
const
|
|
277
|
+
const raw = logFd != null ? tailOfFile(logFile) : stderr;
|
|
278
|
+
const tail = raw.trim().split(/\r?\n/).slice(-6).join('\n');
|
|
244
279
|
writeUpdateStamp({ status: 'error', version, code, error: tail || `npm exited ${code}` });
|
|
245
280
|
}
|
|
246
281
|
});
|