evolcore 0.0.36 → 0.0.38

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/CHANGELOG.md CHANGED
@@ -5,6 +5,24 @@
5
5
 
6
6
  ## Unreleased
7
7
 
8
+ ## 0.0.38 (2026-10-24)
9
+
10
+ ### npm 升级稳定性
11
+
12
+ - 修复 npm 升级在 registry 元数据暂未同步时误报目标版本不存在的问题。
13
+ - 改进升级失败诊断,保留 npm 错误码和具体错误信息,便于定位网络、权限和版本解析问题。
14
+
15
+ ## 0.0.37 (2026-10-24)
16
+
17
+ ### 升级与重启稳定性
18
+
19
+ - 修复升级重启过程中运行时资源版本不同步的问题,暂存运行文件时一并保留 `kits` 目录。
20
+ - 修复 daemon Owner 通知配置异常或发送失败时可能影响重启恢复流程的问题;通知失败会保留诊断并继续执行重启。
21
+
22
+ ### 配置维护
23
+
24
+ - 改进本地 Provider 配置文件的忽略规则,避免运行时凭据文件被误加入 Git 工作区。
25
+
8
26
  ## 0.0.36 (2026-10-24)
9
27
 
10
28
  ### Agent 创建与所有权
@@ -1184,50 +1184,56 @@ function archiveSelfHealLog(p, log) {
1184
1184
  log(`Archived self-heal log to ${archivePath}`);
1185
1185
  }
1186
1186
  async function notifyDaemonOwners(p, message, log) {
1187
- const cfg = loadDaemonConfig();
1188
- const daemonAid = typeof cfg.aid === 'string' ? cfg.aid.trim() : '';
1189
- if (!daemonAid) {
1190
- log('Daemon owner notification skipped: daemon.json.aid not configured');
1191
- return;
1192
- }
1193
- if (!isValidAid(daemonAid)) {
1194
- log(`Daemon owner notification skipped: invalid daemon.json.aid ${daemonAid}`);
1195
- return;
1196
- }
1197
- const response = await ipcQuery(p.socket, { type: 'aid.ownership', argv: ['aid', 'bind', 'status'] }, OWNER_NOTIFICATION_TIMEOUT_MS).catch(() => null);
1198
- const state = response?.ok ? response.state : undefined;
1199
- const owners = state?.subjectAid === daemonAid && state?.consensusStatus === 'consensus'
1200
- && typeof state.ownerAid === 'string' && isValidAid(state.ownerAid) ? [state.ownerAid] : [];
1201
- if (owners.length === 0) {
1202
- log('Daemon owner notification skipped: fresh protocol consensus unavailable');
1203
- return;
1204
- }
1205
- const validOwners = owners.filter(owner => {
1206
- const valid = isValidAid(owner);
1207
- if (!valid)
1208
- log(`Daemon owner notification skipped invalid owner AID: ${owner}`);
1209
- return valid;
1210
- });
1211
- if (validOwners.length === 0)
1212
- return;
1213
- const text = formatDaemonOwnerNotice(p, message);
1214
- for (const owner of validOwners) {
1215
- try {
1216
- const result = await withTimeout(msgSend({
1217
- from: daemonAid,
1218
- to: owner,
1219
- body: { mode: 'text', text },
1220
- slotId: 'restart-monitor',
1221
- }), OWNER_NOTIFICATION_TIMEOUT_MS);
1222
- if (!result.ok) {
1223
- log(`Daemon owner notification failed for ${owner}: ${result.error}`);
1224
- continue;
1225
- }
1226
- log(`Daemon owner notification sent to ${owner}: ${result.message_id}`);
1187
+ try {
1188
+ const cfg = loadDaemonConfig();
1189
+ const daemonAid = typeof cfg.aid === 'string' ? cfg.aid.trim() : '';
1190
+ if (!daemonAid) {
1191
+ log('Daemon owner notification skipped: daemon.json.aid not configured');
1192
+ return;
1227
1193
  }
1228
- catch (error) {
1229
- log(`Daemon owner notification failed for ${owner}: ${error.message?.slice(0, 200) || error}`);
1194
+ if (!isValidAid(daemonAid)) {
1195
+ log(`Daemon owner notification skipped: invalid daemon.json.aid ${daemonAid}`);
1196
+ return;
1197
+ }
1198
+ const response = await ipcQuery(p.socket, { type: 'aid.ownership', argv: ['aid', 'bind', 'status'] }, OWNER_NOTIFICATION_TIMEOUT_MS).catch(() => null);
1199
+ const state = response?.ok ? response.state : undefined;
1200
+ const owners = state?.subjectAid === daemonAid && state?.consensusStatus === 'consensus'
1201
+ && typeof state.ownerAid === 'string' && isValidAid(state.ownerAid) ? [state.ownerAid] : [];
1202
+ if (owners.length === 0) {
1203
+ log('Daemon owner notification skipped: fresh protocol consensus unavailable');
1204
+ return;
1230
1205
  }
1206
+ const validOwners = owners.filter(owner => {
1207
+ const valid = isValidAid(owner);
1208
+ if (!valid)
1209
+ log(`Daemon owner notification skipped invalid owner AID: ${owner}`);
1210
+ return valid;
1211
+ });
1212
+ if (validOwners.length === 0)
1213
+ return;
1214
+ const text = formatDaemonOwnerNotice(p, message);
1215
+ for (const owner of validOwners) {
1216
+ try {
1217
+ const result = await withTimeout(msgSend({
1218
+ from: daemonAid,
1219
+ to: owner,
1220
+ body: { mode: 'text', text },
1221
+ slotId: 'restart-monitor',
1222
+ }), OWNER_NOTIFICATION_TIMEOUT_MS);
1223
+ if (!result.ok) {
1224
+ log(`Daemon owner notification failed for ${owner}: ${result.error}`);
1225
+ continue;
1226
+ }
1227
+ log(`Daemon owner notification sent to ${owner}: ${result.message_id}`);
1228
+ }
1229
+ catch (error) {
1230
+ log(`Daemon owner notification failed for ${owner}: ${error.message?.slice(0, 200) || error}`);
1231
+ }
1232
+ }
1233
+ }
1234
+ catch (error) {
1235
+ const reason = error instanceof Error ? error.message : String(error);
1236
+ log(`WARN: Daemon owner notification failed: ${reason.slice(0, 200)}`);
1231
1237
  }
1232
1238
  }
1233
1239
  function formatDaemonOwnerNotice(p, message) {
@@ -409,9 +409,10 @@ export async function launchMonitorAndConfirm(args, env, isAliveInRegistry, hasO
409
409
  * in a checkout: `npm install -g` swaps the whole package directory, and the
410
410
  * monitor has ~170 lazy `await import()` sites, so a module it has not loaded
411
411
  * yet would come from the new version while the rest is still the old one.
412
- * Staging `dist/` and `bin/` keeps the package-owned code on one version.
412
+ * Staging `dist/`, `bin/` and `kits/` keeps package-owned code and runtime
413
+ * schemas on one version.
413
414
  *
414
- * Only `dist/`, `bin/` and `package.json` are copied (a few MB). `node_modules` is
415
+ * `dist/`, `bin/`, `kits/` and `package.json` are copied. `node_modules` is
415
416
  * linked, because copying it is hundreds of MB. The link degrades in steps so
416
417
  * that no platform is left without a path forward:
417
418
  *
@@ -447,6 +448,9 @@ export function prepareMonitorStage(packageRoot, stageParent) {
447
448
  const binSource = path.join(packageRoot, 'bin');
448
449
  if (fs.existsSync(binSource))
449
450
  fs.cpSync(binSource, path.join(stageDir, 'bin'), { recursive: true });
451
+ const kitsSource = path.join(packageRoot, 'kits');
452
+ if (fs.existsSync(kitsSource))
453
+ fs.cpSync(kitsSource, path.join(stageDir, 'kits'), { recursive: true });
450
454
  const pkgJson = path.join(packageRoot, 'package.json');
451
455
  if (fs.existsSync(pkgJson))
452
456
  fs.copyFileSync(pkgJson, path.join(stageDir, 'package.json'));
@@ -394,20 +394,36 @@ export async function preparePackageCache(target, registry, options = {}) {
394
394
  const run = (args) => new Promise((resolve, reject) => {
395
395
  let failure = null;
396
396
  let output = '';
397
+ let errorOutput = '';
397
398
  const child = execFile(npm.command, [...npm.argsPrefix, ...args, '--registry', registry, ...npmConfigArgs(options.npmConfig), '--ignore-scripts'], {
398
399
  timeout: 180_000, windowsHide: isWindows, signal: options.signal, maxBuffer: 8 * 1024 * 1024,
399
- }, (error, stdout) => { failure = error; output = String(stdout ?? ''); });
400
+ }, (error, stdout, stderr) => {
401
+ failure = error;
402
+ output = String(stdout ?? '');
403
+ errorOutput = String(stderr ?? '');
404
+ });
400
405
  child.once('error', error => { failure = error; });
401
406
  child.once('close', code => {
402
- if (failure || code !== 0 || options.signal?.aborted)
403
- reject(new Error(options.signal?.aborted
404
- ? 'Package cache preparation timed out or was cancelled' : 'npm cache preparation failed; check registry connectivity, credentials, disk space and permissions'));
405
- else
407
+ if (!failure && code === 0 && !options.signal?.aborted) {
406
408
  resolve(output);
409
+ return;
410
+ }
411
+ if (options.signal?.aborted) {
412
+ reject(new Error('Package cache preparation timed out or was cancelled'));
413
+ return;
414
+ }
415
+ const codeText = failure && 'code' in failure && failure.code ? ` (${String(failure.code)})` : '';
416
+ const detail = (errorOutput || failure?.stderr || failure?.message || '')
417
+ .replace(/\s+/g, ' ').trim().slice(0, 500);
418
+ reject(new Error(`npm cache preparation failed${codeText}${detail ? `: ${detail}` : ''}`));
407
419
  });
408
420
  });
409
421
  options.onPhase?.('downloading');
410
- await run(['cache', 'add', spec, '--prefer-offline']);
422
+ // Revalidate registry metadata before resolving the exact version. A stale
423
+ // install-v1 packument can otherwise report ETARGET even when the registry
424
+ // already contains the selected release. The tarball itself remains cached
425
+ // and is reused when npm can do so.
426
+ await run(['cache', 'add', spec, '--prefer-online']);
411
427
  options.onPhase?.('tarball-check');
412
428
  const metadata = JSON.parse(await run(['view', spec, 'name', 'version', 'dist', '--json', '--offline']));
413
429
  const [packed] = JSON.parse(await run(['pack', spec, '--dry-run', '--json', '--offline']));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evolcore",
3
- "version": "0.0.36",
3
+ "version": "0.0.38",
4
4
  "description": "AI Agent gateway connecting Claude, Codex, Gemini, and the bundled ecagent runner to messaging channels with multi-project session management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",