@yeaft/webchat-agent 1.0.673 → 1.0.675

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.
Binary file
@@ -17,6 +17,6 @@
17
17
  </head>
18
18
  <body>
19
19
  <div id="app"></div>
20
- <script type="module" src="app.bundle.js?v=2c6c7372"></script>
20
+ <script type="module" src="app.bundle.js?v=0251076a"></script>
21
21
  </body>
22
22
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "1.0.673",
3
+ "version": "1.0.675",
4
4
  "description": "Remote worker agent for Yeaft Web Code Agent — connects the native Yeaft engine, CLI providers, and workbench tools",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -0,0 +1,135 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { execFile, spawn } from 'node:child_process';
3
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, writeFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { setTimeout as delay } from 'node:timers/promises';
6
+ import { promisify } from 'node:util';
7
+
8
+ const execFileAsync = promisify(execFile);
9
+
10
+ export function shellQuote(value) {
11
+ return `'${String(value).replace(/'/g, `'\\''`)}'`;
12
+ }
13
+
14
+ /** A shared install has one kernel lock, independent of the requesting instance. */
15
+ export function getUnixUpgradeLockPath(installDir, lockRoot) {
16
+ const key = createHash('sha256').update(realpathSync(installDir)).digest('hex');
17
+ mkdirSync(lockRoot, { recursive: true, mode: 0o700 });
18
+ return join(lockRoot, `${key}.lock`);
19
+ }
20
+
21
+ /** Runtime files live outside the npm package and never contain public credentials. */
22
+ export function createUnixUpgradeRun(configDir) {
23
+ const root = join(configDir, 'upgrade-runtime');
24
+ mkdirSync(root, { recursive: true, mode: 0o700 });
25
+ const dir = mkdtempSync(join(root, 'unix-'));
26
+ return {
27
+ dir,
28
+ scriptPath: join(dir, 'upgrade.sh'),
29
+ readyPath: join(dir, 'ready'),
30
+ authorizePath: join(dir, 'authorized'),
31
+ acceptedPath: join(dir, 'accepted'),
32
+ cancelPath: join(dir, 'cancelled'),
33
+ errorPath: join(dir, 'error'),
34
+ };
35
+ }
36
+
37
+ function processRunning(pid) {
38
+ try { process.kill(pid, 0); return true; } catch (error) { return error.code === 'EPERM'; }
39
+ }
40
+
41
+ /**
42
+ * Start an updater in a separate systemd service (never a detached child in the
43
+ * Agent cgroup). The shell must acquire its install lock and signal readiness
44
+ * before the caller acknowledges or exits. Failure leaves the Agent online.
45
+ */
46
+ export async function launchUnixUpgrade({
47
+ run,
48
+ instanceId,
49
+ isSystemd,
50
+ env = process.env,
51
+ nodePath = process.execPath,
52
+ serviceRunnerPath,
53
+ sendUpgradeAck,
54
+ version,
55
+ timeoutMs = 10_000,
56
+ }, dependencies = {}) {
57
+ const exec = dependencies.execFileAsync || execFileAsync;
58
+ const spawnProcess = dependencies.spawn || spawn;
59
+ const running = dependencies.processRunning || processRunning;
60
+ const unit = `yeaft-upgrade-${instanceId.slice(0, 60)}-${process.pid}-${run.dir.split('unix-').at(-1)}.service`;
61
+ const uid = process.getuid?.();
62
+ const managerEnv = {
63
+ ...env,
64
+ XDG_RUNTIME_DIR: env.XDG_RUNTIME_DIR || `/run/user/${uid}`,
65
+ DBUS_SESSION_BUS_ADDRESS: env.DBUS_SESSION_BUS_ADDRESS || `unix:path=/run/user/${uid}/bus`,
66
+ };
67
+ let child;
68
+ try {
69
+ if (isSystemd) {
70
+ // Pass the inherited environment privately, not as --setenv command-line
71
+ // arguments. The runner consumes/removes this payload before npm runs.
72
+ const payloadDir = join(run.dir, 'invocation');
73
+ mkdirSync(payloadDir, { mode: 0o700 });
74
+ const payloadPath = join(payloadDir, 'invocation.json');
75
+ writeFileSync(payloadPath, JSON.stringify({
76
+ command: '/bin/bash', args: [run.scriptPath], cwd: run.dir, env: managerEnv,
77
+ }), { mode: 0o600 });
78
+ await exec('systemd-run', [
79
+ '--user', '--quiet', '--collect', '--service-type=exec',
80
+ `--unit=${unit}`, '--', nodePath, serviceRunnerPath, payloadPath,
81
+ ], { env: managerEnv, timeout: timeoutMs });
82
+ } else {
83
+ child = spawnProcess('bash', [run.scriptPath], {
84
+ cwd: run.dir, env, detached: true, stdio: 'ignore',
85
+ });
86
+ await new Promise((resolve, reject) => {
87
+ child.once('spawn', resolve);
88
+ child.once('error', reject);
89
+ });
90
+ child.unref();
91
+ }
92
+
93
+ const deadline = Date.now() + timeoutMs;
94
+ let ownerPid;
95
+ while (Date.now() < deadline) {
96
+ if (existsSync(run.errorPath)) throw new Error(readFileSync(run.errorPath, 'utf8').trim());
97
+ try {
98
+ const pid = Number(readFileSync(run.readyPath, 'utf8'));
99
+ if (Number.isInteger(pid) && pid > 0 && running(pid)) { ownerPid = pid; break; }
100
+ } catch {}
101
+ if (child && child.exitCode != null) throw new Error(`Unix upgrade runner exited with code ${child.exitCode}`);
102
+ await delay(50);
103
+ }
104
+ if (!ownerPid) throw new Error('Unix upgrade runner did not become ready; Agent remains online');
105
+ let ackTimer;
106
+ try {
107
+ const outcome = await Promise.race([
108
+ sendUpgradeAck({ success: true, version, pendingRestart: true }),
109
+ new Promise((_, reject) => {
110
+ ackTimer = setTimeout(() => reject(new Error('Upgrade acknowledgement timed out; Agent remains online')), timeoutMs);
111
+ }),
112
+ ]);
113
+ if (outcome !== 'sent') throw new Error('Upgrade acknowledgement was not sent; Agent remains online');
114
+ } finally { clearTimeout(ackTimer); }
115
+ if (!running(ownerPid)) throw new Error('Unix upgrade runner exited during acknowledgement; Agent remains online');
116
+ writeFileSync(run.authorizePath, 'authorized');
117
+ const acceptDeadline = Date.now() + timeoutMs;
118
+ while (Date.now() < acceptDeadline) {
119
+ if (!running(ownerPid)) throw new Error('Unix upgrade runner exited before accepting handoff; Agent remains online');
120
+ if (existsSync(run.acceptedPath)) return { unit: isSystemd ? unit : null };
121
+ await delay(50);
122
+ }
123
+ throw new Error('Unix upgrade runner did not accept handoff; Agent remains online');
124
+ } catch (error) {
125
+ // Revoke authorization even if the manager is slow or start timed out.
126
+ writeFileSync(run.cancelPath, 'cancelled');
127
+ if (isSystemd) {
128
+ try { await exec('systemctl', ['--user', 'stop', unit], { env: managerEnv, timeout: 5000 }); } catch {}
129
+ } else if (child?.pid) {
130
+ try { process.kill(-child.pid, 'SIGTERM'); } catch {}
131
+ }
132
+ // Keep cancellation files: an ambiguously started runner must see them.
133
+ throw error;
134
+ }
135
+ }
@@ -6324,6 +6324,7 @@ async function runVpTurn({ prompt, promptParts = null, sessionId, vpId, threadId
6324
6324
  sendSessionOutputFrame({
6325
6325
  type: 'result',
6326
6326
  result_text: '',
6327
+ is_error: true,
6327
6328
  }, envelope);
6328
6329
  } finally {
6329
6330
  // Emit terminal vp_turn_end for the error path (normal + abort + route