@yeaft/webchat-agent 1.0.251 → 1.0.253

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
@@ -16,6 +16,6 @@
16
16
  </head>
17
17
  <body>
18
18
  <div id="app"></div>
19
- <script type="module" src="app.bundle.js?v=1fdba61f"></script>
19
+ <script type="module" src="app.bundle.js?v=055156d8"></script>
20
20
  </body>
21
21
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "1.0.251",
3
+ "version": "1.0.253",
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",
@@ -5,6 +5,7 @@ import { execSync, spawn } from 'child_process';
5
5
  import { existsSync, mkdirSync, writeFileSync, readFileSync, unlinkSync } from 'fs';
6
6
  import { join, dirname } from 'path';
7
7
  import { getConfigDir, getLogDir, getNodePath, getCliPath, getPm2AppName, loadServiceConfig, DEFAULT_INSTANCE_ID } from './config.js';
8
+ import { buildUpgradeInstallCommand } from '../upgrade-command.js';
8
9
 
9
10
  const WIN_TASK_NAME = 'YeaftAgent';
10
11
 
@@ -17,7 +18,7 @@ function ensurePm2() {
17
18
  execSync('pm2 --version', { stdio: 'pipe' });
18
19
  } catch {
19
20
  console.log('Installing pm2...');
20
- execSync('npm install -g pm2', { stdio: 'inherit' });
21
+ execSync(buildUpgradeInstallCommand('pm2'), { stdio: 'inherit' });
21
22
  }
22
23
  }
23
24
 
@@ -1,11 +1,191 @@
1
+ import { existsSync, unlinkSync } from 'node:fs';
2
+ import { setTimeout as delay } from 'node:timers/promises';
3
+
1
4
  export const DEFAULT_UPGRADE_REGISTRY = 'https://pkg.yeaft.com/';
2
5
 
6
+ const ONLINE_METADATA_FLAGS = [
7
+ '--prefer-online',
8
+ '--prefer-offline=false',
9
+ '--offline=false',
10
+ ];
11
+
12
+ /** Build argv for an online npm metadata lookup against the Yeaft registry. */
13
+ export function buildUpgradeMetadataArgs(packageSpec, field) {
14
+ return [
15
+ 'view',
16
+ packageSpec,
17
+ field,
18
+ `--registry=${DEFAULT_UPGRADE_REGISTRY}`,
19
+ ...ONLINE_METADATA_FLAGS,
20
+ ];
21
+ }
22
+
23
+ /** Build argv for an npm install against the Yeaft registry. */
24
+ export function buildUpgradeInstallArgs(packageSpec, { global = true } = {}) {
25
+ return [
26
+ 'install',
27
+ ...(global ? ['-g'] : []),
28
+ packageSpec,
29
+ `--registry=${DEFAULT_UPGRADE_REGISTRY}`,
30
+ ];
31
+ }
32
+
33
+ /** Build argv for updating an installed package through the Yeaft registry. */
34
+ export function buildUpgradeUpdateArgs(packageName, { global = true } = {}) {
35
+ return [
36
+ 'update',
37
+ ...(global ? ['-g'] : []),
38
+ packageName,
39
+ `--registry=${DEFAULT_UPGRADE_REGISTRY}`,
40
+ ];
41
+ }
42
+
3
43
  /** Build the npm metadata command used by `yeaft-agent upgrade`. */
4
44
  export function buildUpgradeVersionCommand(packageName) {
5
- return `npm view ${packageName} version --registry=${DEFAULT_UPGRADE_REGISTRY}`;
45
+ return ['npm', ...buildUpgradeMetadataArgs(packageName, 'version')].join(' ');
46
+ }
47
+
48
+ /** Build an npm install command against the Yeaft registry. */
49
+ export function buildUpgradeInstallCommand(packageSpec, options) {
50
+ return ['npm', ...buildUpgradeInstallArgs(packageSpec, options)].join(' ');
51
+ }
52
+
53
+ /** Build the npm update command used after a Windows Agent has exited. */
54
+ export function buildUpgradeUpdateCommand(packageName) {
55
+ return ['npm', ...buildUpgradeUpdateArgs(packageName)].join(' ');
56
+ }
57
+
58
+ function quoteCmdPath(path) {
59
+ return `"${String(path).replace(/"/g, '""')}"`;
60
+ }
61
+
62
+ /**
63
+ * Build the exact CreateProcess contract for a batch file path. cmd.exe needs
64
+ * the full command string quoted once; windowsVerbatimArguments prevents Node
65
+ * from escaping those quotes a second time when the path contains spaces.
66
+ */
67
+ export function buildWindowsUpgradeInvocation(batPath) {
68
+ return {
69
+ command: 'cmd.exe',
70
+ args: ['/d', '/s', '/c', quoteCmdPath(batPath)],
71
+ options: {
72
+ detached: true,
73
+ stdio: 'ignore',
74
+ windowsHide: true,
75
+ windowsVerbatimArguments: true,
76
+ },
77
+ };
78
+ }
79
+
80
+ function waitForSpawn(child) {
81
+ return new Promise((resolve, reject) => {
82
+ const onError = err => {
83
+ child.removeListener('spawn', onSpawn);
84
+ reject(err);
85
+ };
86
+ const onSpawn = () => {
87
+ child.removeListener('error', onError);
88
+ resolve();
89
+ };
90
+ child.once('error', onError);
91
+ child.once('spawn', onSpawn);
92
+ });
93
+ }
94
+
95
+ async function waitForUpgradeHandoff({
96
+ handoffPath,
97
+ child,
98
+ fileExists,
99
+ sleep,
100
+ timeoutMs,
101
+ pollIntervalMs,
102
+ getChildError,
103
+ }) {
104
+ const deadline = Date.now() + timeoutMs;
105
+ let handoffSeen = false;
106
+ while (Date.now() < deadline) {
107
+ const childError = getChildError();
108
+ if (childError) throw childError;
109
+ if (child.exitCode != null || child.signalCode != null) {
110
+ const status = child.exitCode != null ? `code ${child.exitCode}` : `signal ${child.signalCode}`;
111
+ throw new Error(`Windows upgrade launcher exited before handoff (${status})`);
112
+ }
113
+
114
+ // Require the marker on two consecutive polls. A batch file that writes the
115
+ // marker and immediately exits must not be allowed to tear down PM2.
116
+ if (fileExists(handoffPath)) {
117
+ if (handoffSeen) return;
118
+ handoffSeen = true;
119
+ } else {
120
+ handoffSeen = false;
121
+ }
122
+ await sleep(pollIntervalMs);
123
+ }
124
+ throw new Error(`Windows upgrade launcher did not confirm handoff within ${timeoutMs}ms`);
125
+ }
126
+
127
+ /**
128
+ * Launch the detached Windows updater and wait for the batch script itself to
129
+ * confirm execution before the caller stops PM2 or exits. `spawn` only proves
130
+ * that cmd.exe was created; the handoff file proves the updater took control.
131
+ */
132
+ export async function launchWindowsUpgradeScript({
133
+ batPath,
134
+ handoffPath,
135
+ spawnProcess,
136
+ fileExists = existsSync,
137
+ removeFile = unlinkSync,
138
+ sleep = delay,
139
+ timeoutMs = 5000,
140
+ pollIntervalMs = 50,
141
+ onHandoff,
142
+ }) {
143
+ if (typeof spawnProcess !== 'function') throw new TypeError('spawnProcess is required');
144
+ if (!handoffPath) throw new TypeError('handoffPath is required');
145
+
146
+ try { removeFile(handoffPath); } catch (err) {
147
+ if (err?.code !== 'ENOENT') throw err;
148
+ }
149
+
150
+ const invocation = buildWindowsUpgradeInvocation(batPath);
151
+ let child;
152
+ try {
153
+ child = spawnProcess(invocation.command, invocation.args, invocation.options);
154
+ } catch (err) {
155
+ throw new Error(`Windows upgrade launcher failed: ${err.message}`, { cause: err });
156
+ }
157
+
158
+ let childError = null;
159
+ const onChildError = err => { childError = err; };
160
+ child.on('error', onChildError);
161
+ try {
162
+ await waitForSpawn(child);
163
+ await waitForUpgradeHandoff({
164
+ handoffPath,
165
+ child,
166
+ fileExists,
167
+ sleep,
168
+ timeoutMs,
169
+ pollIntervalMs,
170
+ getChildError: () => childError,
171
+ });
172
+ await onHandoff?.();
173
+ } catch (err) {
174
+ try { child.kill(); } catch {}
175
+ try { removeFile(handoffPath); } catch {}
176
+ if (childError === err) {
177
+ throw new Error(`Windows upgrade launcher failed: ${err.message}`, { cause: err });
178
+ }
179
+ throw err;
180
+ } finally {
181
+ child.removeListener('error', onChildError);
182
+ }
183
+
184
+ child.unref();
185
+ return 'cmd.exe';
6
186
  }
7
187
 
8
- /** Build the npm install command used by `yeaft-agent upgrade`. */
9
- export function buildUpgradeInstallCommand(packageSpec) {
10
- return `npm install -g ${packageSpec} --registry=${DEFAULT_UPGRADE_REGISTRY}`;
188
+ /** Build the URL used by the startup-only update notification. */
189
+ export function buildUpgradeMetadataUrl(packageName) {
190
+ return `${DEFAULT_UPGRADE_REGISTRY}${encodeURIComponent(packageName)}/latest`;
11
191
  }