evolcore 0.0.26 → 0.0.28
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 +36 -0
- package/bin/codex-managed-acl.ps1 +43 -0
- package/dist/agents/baseagent-availability.js +68 -0
- package/dist/agents/baseagent.js +10 -5
- package/dist/agents/claude-runner.js +123 -22
- package/dist/agents/codex/app-server-client.js +70 -26
- package/dist/agents/codex/catalog.js +7 -1
- package/dist/agents/codex-runner.js +363 -421
- package/dist/agents/ecagent-runner.js +170 -25
- package/dist/agents/gemini-runner.js +6 -0
- package/dist/agents/runner-types.js +50 -2
- package/dist/aun/aid/agentmd.js +73 -31
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/control-aid.js +180 -1
- package/dist/aun/aid/identity.js +3 -3
- package/dist/aun/group/history.js +303 -0
- package/dist/aun/group/identity.js +43 -0
- package/dist/aun/group/index.js +5 -0
- package/dist/aun/{msg/group.js → group/operations.js} +161 -38
- package/dist/aun/{menu-client.js → menu/client.js} +13 -7
- package/dist/aun/menu/index.js +2 -0
- package/dist/aun/menu/transport.js +49 -0
- package/dist/aun/msg/index.js +2 -1
- package/dist/aun/msg/managed-operation.js +84 -18
- package/dist/aun/msg/mention-schema.js +51 -0
- package/dist/aun/msg/p2p.js +13 -8
- package/dist/aun/msg/upload.js +43 -88
- package/dist/aun/outbox.js +29 -7
- package/dist/aun/rpc/client.js +1 -0
- package/dist/aun/storage/client.js +39 -50
- package/dist/channels/aun.js +544 -239
- package/dist/channels/daemon.js +10 -6
- package/dist/cli/agent-command.js +108 -6
- package/dist/cli/agent-create.js +515 -2
- package/dist/cli/agent.js +109 -8
- package/dist/cli/aun-commands.js +191 -42
- package/dist/cli/config.js +8 -5
- package/dist/cli/contact.js +2 -2
- package/dist/cli/ctl-command.js +2 -2
- package/dist/cli/daemon-commands.js +111 -162
- package/dist/cli/diag.js +3 -3
- package/dist/cli/fs-command.js +3 -3
- package/dist/cli/handoff-command.js +6 -6
- package/dist/cli/index.js +8 -2
- package/dist/cli/init.js +34 -1
- package/dist/cli/managed-command-guard.js +2 -1
- package/dist/cli/menu-client.js +13 -5
- package/dist/cli/model.js +3 -3
- package/dist/cli/queue-command.js +2 -2
- package/dist/cli/response.js +2 -2
- package/dist/cli/restart-monitor.js +81 -19
- package/dist/cli/task-command.js +59 -0
- package/dist/cli/task-context.js +97 -49
- package/dist/cli/trigger-command.js +20 -10
- package/dist/config/builtin-roles.js +10 -0
- package/dist/config/config-field-policy.js +11 -0
- package/dist/config/config-manager.js +32 -4
- package/dist/config/config-operation-service.js +20 -5
- package/dist/config/contact-book-store.js +1 -1
- package/dist/config/contact-book.js +1 -1
- package/dist/config/contact-operation-service.js +1 -1
- package/dist/config/peer-role-resolver.js +1 -1
- package/dist/config/resolved-config-op.js +3 -0
- package/dist/config-store.js +1 -1
- package/dist/core/agent-application-service.js +5 -0
- package/dist/core/audit/event-key.js +17 -2
- package/dist/core/audit/log-integrity.js +34 -8
- package/dist/core/auth/agent-delegation.js +48 -14
- package/dist/core/auth/auth-gateway.js +2 -0
- package/dist/core/auth/authorization-audit.js +34 -38
- package/dist/core/auth/operation-authorizer.js +67 -5
- package/dist/core/auth/operation-catalog.js +110 -0
- package/dist/core/auth/remote-access-store.js +115 -9
- package/dist/core/bootstrap-messages.js +66 -7
- package/dist/core/bootstrap-service.js +110 -19
- package/dist/core/command/agent-control.js +88 -7
- package/dist/core/command/agent-storage-menu.js +443 -0
- package/dist/core/command/cli-intent-parser.js +19 -0
- package/dist/core/command/command-handler.js +105 -40
- package/dist/core/command/data-root-resolver.js +273 -0
- package/dist/core/command/diag-service.js +292 -27
- package/dist/core/command/group-menu.js +7 -2
- package/dist/core/command/menu-catalog.js +34 -4
- package/dist/core/command/menu-handler.js +364 -96
- package/dist/core/command/menu-protocol.js +43 -6
- package/dist/core/command/role-menu.js +2 -2
- package/dist/core/command/slash-handler.js +61 -37
- package/dist/core/event-catalog.js +4 -0
- package/dist/core/evolagent-registry.js +28 -2
- package/dist/core/group/invite-service.js +924 -0
- package/dist/core/interaction-router.js +22 -8
- package/dist/core/message/im-renderer.js +94 -16
- package/dist/core/message/message-bridge.js +140 -13
- package/dist/core/message/message-log.js +5 -3
- package/dist/core/message/message-queue.js +73 -41
- package/dist/core/message/response-engine.js +729 -118
- package/dist/core/permission/approval-gateway.js +36 -3
- package/dist/core/permission/ec-command-parser.js +76 -36
- package/dist/core/permission/protected-paths.js +134 -16
- package/dist/core/permission/sandbox-runtime.js +72 -3
- package/dist/core/permission/tool-error-code.js +15 -0
- package/dist/core/permission/tool-policy.js +8 -8
- package/dist/core/relation/peer-identity.js +57 -6
- package/dist/core/relation/shared-data.js +106 -0
- package/dist/core/role/runtime-policy.js +64 -0
- package/dist/core/runtime-lock.js +10 -26
- package/dist/core/session/runner-task-history.js +170 -0
- package/dist/core/session/session-manager.js +38 -6
- package/dist/core/session/session-mapper.js +41 -0
- package/dist/core/session/session-turn-coordinator.js +37 -7
- package/dist/core/session/session-turns.js +48 -7
- package/dist/core/task/task-recovery-service.js +176 -0
- package/dist/core/task/task-resume-operation.js +32 -0
- package/dist/eck/group-rules-sync.js +5 -3
- package/dist/eck/kit-renderer.js +1 -0
- package/dist/index.js +322 -207
- package/dist/ipc.js +141 -15
- package/dist/paths.js +17 -4
- package/dist/product.js +3 -0
- package/dist/trigger/event-source.js +19 -0
- package/dist/trigger/feedback.js +233 -40
- package/dist/trigger/parser.js +55 -5
- package/dist/trigger/patch.js +9 -0
- package/dist/trigger/scheduler.js +30 -4
- package/dist/trigger/validation.js +20 -3
- package/dist/utils/atomic-write.js +98 -0
- package/dist/utils/cross-platform.js +87 -16
- package/dist/utils/ecweb-utils.js +1 -0
- package/dist/utils/error-utils.js +40 -2
- package/dist/utils/logger.js +23 -13
- package/dist/utils/npm-ops.js +119 -4
- package/dist/utils/package-version-info.js +244 -0
- package/dist/utils/tool-summary.js +59 -3
- package/dist/utils/welcome.js +174 -1
- package/dist/utils/windows-shell-trust.js +37 -0
- package/ecagent/dist/harness/agent-harness.js +3 -0
- package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
- package/kits/docs/INDEX.md +0 -6
- package/kits/docs/channels/aun.md +23 -2
- package/kits/docs/channels/feishu.md +1 -1
- package/kits/docs/context-assembly.md +29 -17
- package/kits/docs/evolcore/INDEX.md +8 -3
- package/kits/docs/evolcore/agent-create.md +39 -7
- package/kits/docs/evolcore/agent.md +33 -1
- package/kits/docs/evolcore/aid.md +9 -1
- package/kits/docs/evolcore/config.md +40 -1
- package/kits/docs/evolcore/group-collaboration.md +1 -1
- package/kits/docs/evolcore/group.md +117 -2
- package/kits/docs/evolcore/menu-client.md +16 -0
- package/kits/docs/evolcore/msg.md +3 -0
- package/kits/docs/evolcore/storage.md +3 -0
- package/kits/docs/evolcore/task.md +14 -0
- package/kits/docs/evolcore/trigger.md +51 -3
- package/kits/docs/venues/group.md +5 -0
- package/kits/eck_manifest.json +27 -0
- package/kits/rules/01-overview.md +11 -7
- package/kits/rules/04-relation.md +2 -1
- package/kits/rules/05-venue.md +1 -1
- package/kits/rules/06-channel.md +6 -4
- package/kits/schemas/agent-config.schema.12.json +25 -1
- package/kits/schemas/daemon.schema.6.json +2 -2
- package/kits/schemas/defaults.schema.5.json +1 -1
- package/kits/schemas/relation-config.schema.1.json +1 -1
- package/kits/schemas/relation-config.schema.5.json +1 -1
- package/kits/schemas/role-config.schema.1.json +14 -0
- package/kits/templates/roles/member.json +5 -0
- package/kits/templates/roles/visitor.json +5 -0
- package/kits/templates/system-fragments/baseagent.md +1 -1
- package/kits/templates/system-fragments/bootstrap.md +26 -9
- package/kits/templates/system-fragments/channel.md +8 -44
- package/kits/templates/system-fragments/commands.md +10 -2
- package/kits/templates/system-fragments/group-unread-history.md +7 -0
- package/kits/templates/system-fragments/reply.md +56 -0
- package/package.json +7 -3
- package/dist/aun/group-identity.js +0 -9
- /package/dist/aun/{group-fs-download.js → group/fs-download.js} +0 -0
- /package/dist/aun/{msg/group-index.js → group/index-rpc.js} +0 -0
|
@@ -9,22 +9,23 @@ import { loadDefaults, loadAllAgents, loadDaemonConfig, saveDaemonConfig } from
|
|
|
9
9
|
import { resolveEffective } from '../config/config-manager.js';
|
|
10
10
|
import { resolveAnthropicConfig } from '../agents/baseagent.js';
|
|
11
11
|
import { migrateProject } from '../config-store.js';
|
|
12
|
-
import { ipcQuery } from '../ipc.js';
|
|
12
|
+
import { ipcQuery, IpcTransportError } from '../ipc.js';
|
|
13
13
|
import { isHelpFlag } from './help.js';
|
|
14
14
|
import { cmdInit, needsControlAidInit, initTail } from './init.js';
|
|
15
15
|
import * as platform from '../utils/cross-platform.js';
|
|
16
16
|
import { EventBus } from '../core/event-bus.js';
|
|
17
|
-
import {
|
|
17
|
+
import { tryUpgradeGlobalPkg, resolveGlobalPkg } from '../utils/npm-ops.js';
|
|
18
|
+
import { ensureFreshPackageVersionInfo } from '../utils/package-version-info.js';
|
|
18
19
|
import { ecwebVersionRequirementError, resolveEcwebLaunchCommand, fetchRemotePairingCode } from '../utils/ecweb-utils.js';
|
|
19
20
|
import { isHostChinese } from '../utils/locale.js';
|
|
20
|
-
import { scanInstances, cleanupInstances, findOrphanProcesses
|
|
21
|
+
import { scanInstances, cleanupInstances, findOrphanProcesses } from '../utils/instance-registry.js';
|
|
21
22
|
import { filterLogFiles, deriveLogTypes, computePreChecked, validateLogTypes, shortLogName as shortLogNameLocal, isWatchLogFile } from './watch-logs.js';
|
|
22
23
|
import { displaySessionTitle } from '../core/session/session-title.js';
|
|
23
24
|
import { isNonAgentSessionChannel } from '../core/system-channels.js';
|
|
24
25
|
import { printCodeStats } from './code-stats.js';
|
|
25
26
|
import { getProcessStartTime, startTimeMatches } from '../utils/process-introspect.js';
|
|
26
|
-
import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
|
|
27
|
-
import { WEB_CLI_BIN, WEB_PACKAGE_LATEST, WEB_PACKAGE_NAME } from '../product.js';
|
|
27
|
+
import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
28
|
+
import { RUNTIME_HOME_ENV, WEB_CLI_BIN, WEB_PACKAGE_LATEST, WEB_PACKAGE_NAME } from '../product.js';
|
|
28
29
|
import { rotateStdoutLog } from '../utils/log-writer.js';
|
|
29
30
|
import { inspectDataMigrationRequirement } from '../core/data-migration.js';
|
|
30
31
|
import { isInitCancelledError, printInitCancelHint } from './init-cancel.js';
|
|
@@ -40,6 +41,8 @@ export function ensureCodexHookBeforeLifecycle(onRepaired) {
|
|
|
40
41
|
try {
|
|
41
42
|
const usesCodex = loadDefaults()?.active_baseagent === 'codex'
|
|
42
43
|
|| loadAllAgents().agents.some(agent => {
|
|
44
|
+
if (agent.enabled === false)
|
|
45
|
+
return false;
|
|
43
46
|
try {
|
|
44
47
|
return resolveEffective({ self: agent.aid }).active_baseagent === 'codex';
|
|
45
48
|
}
|
|
@@ -146,7 +149,7 @@ function rejectPidIsolatedLifecycle(action, status, ping) {
|
|
|
146
149
|
}
|
|
147
150
|
async function tryDelegatedDaemonRestart(socketPath) {
|
|
148
151
|
const sessionId = process.env.EVOLCORE_SESSION_ID;
|
|
149
|
-
const delegationToken =
|
|
152
|
+
const delegationToken = readDelegationCredential();
|
|
150
153
|
if (!sessionId || !delegationToken)
|
|
151
154
|
return false;
|
|
152
155
|
const response = await ipcQuery(socketPath, {
|
|
@@ -248,27 +251,46 @@ function runSourceBuild() {
|
|
|
248
251
|
});
|
|
249
252
|
});
|
|
250
253
|
}
|
|
251
|
-
/**
|
|
252
|
-
* Spawn the restart monitor and confirm it actually reached its own code.
|
|
253
|
-
*
|
|
254
|
-
* The daemon is already stopped at this point, so a monitor that dies on
|
|
255
|
-
* startup leaves nothing running and nobody watching — the exact silent
|
|
256
|
-
* failure this mechanism exists to prevent.
|
|
257
|
-
*/
|
|
258
|
-
async function spawnRestartMonitorAndConfirm(monitorEntry, reportLine) {
|
|
259
|
-
const result = await platform.launchMonitorAndConfirm([...monitorEntry.args, 'restart-monitor'], { EVOLCORE_HOME: resolvePaths().root, ...(monitorEntry.env ?? {}) }, pid => scanInstances().restartMonitors.some(m => m.alive && m.record.pid === pid), pid => scanInstances().restartMonitors.some(m => m.alive && m.record.pid !== pid));
|
|
260
|
-
if (result.ok)
|
|
261
|
-
return { ok: true };
|
|
262
|
-
for (const line of (result.stderrTail ?? '').split(/\r?\n/).filter(Boolean).slice(-8)) {
|
|
263
|
-
reportLine(` | ${line}`);
|
|
264
|
-
}
|
|
265
|
-
return { ok: false, reason: result.reason ?? 'unknown' };
|
|
266
|
-
}
|
|
267
254
|
async function requireFreshSourceBuild() {
|
|
268
255
|
if (!sourceBuildNeedsRefresh())
|
|
269
256
|
return true;
|
|
270
257
|
return await runSourceBuild();
|
|
271
258
|
}
|
|
259
|
+
async function launchPackageLifecycle(source, log, options = {}) {
|
|
260
|
+
if (!options.prepared)
|
|
261
|
+
await ensureFreshPackageVersionInfo(undefined, { source, log });
|
|
262
|
+
const root = resolvePaths().root;
|
|
263
|
+
const launch = platform.resolveMonitorLaunch(getPackageRoot(), path.join(root, 'data', 'monitor-stage'));
|
|
264
|
+
if (launch.note)
|
|
265
|
+
log(launch.note);
|
|
266
|
+
if (!fs.existsSync(launch.entry)) {
|
|
267
|
+
if (launch.stageDir)
|
|
268
|
+
platform.cleanupMonitorStage(launch.stageDir);
|
|
269
|
+
return { ok: false, reason: 'RESTART_ENTRY_MISSING' };
|
|
270
|
+
}
|
|
271
|
+
const args = [...launch.args, 'restart-monitor', ...(options.clear ? ['--clear'] : [])];
|
|
272
|
+
const env = { ...options.env, [RUNTIME_HOME_ENV]: root, ...launch.env, [AGENT_DELEGATION_TOKEN_ENV]: '' };
|
|
273
|
+
if (options.foreground) {
|
|
274
|
+
return new Promise(resolve => {
|
|
275
|
+
const child = spawn(process.execPath, [...args, '--foreground'], {
|
|
276
|
+
stdio: 'inherit', detached: false, windowsHide: true, env: { ...process.env, ...env },
|
|
277
|
+
});
|
|
278
|
+
child.once('error', () => {
|
|
279
|
+
if (launch.stageDir)
|
|
280
|
+
platform.cleanupMonitorStage(launch.stageDir);
|
|
281
|
+
resolve({ ok: false, reason: 'Foreground monitor could not start' });
|
|
282
|
+
});
|
|
283
|
+
child.once('exit', code => {
|
|
284
|
+
process.exitCode = code ?? 1;
|
|
285
|
+
resolve({ ok: code === 0, ...(code !== 0 ? { reason: 'Foreground lifecycle exited unsuccessfully' } : {}) });
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
const result = await platform.launchMonitorAndConfirm(args, env, pid => scanInstances().restartMonitors.some(item => item.alive && item.record.pid === pid), pid => scanInstances().restartMonitors.some(item => item.alive && item.record.pid !== pid));
|
|
290
|
+
if (!result.ok && launch.stageDir)
|
|
291
|
+
platform.cleanupMonitorStage(launch.stageDir);
|
|
292
|
+
return { ok: result.ok, ...(!result.ok ? { reason: result.reason } : {}) };
|
|
293
|
+
}
|
|
272
294
|
function requireCompletedDataMigration(root, action = 'start') {
|
|
273
295
|
const requirement = inspectDataMigrationRequirement(root);
|
|
274
296
|
if (!requirement.required)
|
|
@@ -289,7 +311,11 @@ function requireCompletedDataMigration(root, action = 'start') {
|
|
|
289
311
|
* A failed upgrade is reported, but the currently installed version remains
|
|
290
312
|
* usable and the caller continues with its normal lifecycle.
|
|
291
313
|
*/
|
|
292
|
-
export async function runUpgradeChecks(upgradeFn
|
|
314
|
+
export async function runUpgradeChecks(upgradeFn, ecwebUpgradeFn, timeoutMs = 60_000) {
|
|
315
|
+
if (!upgradeFn || !ecwebUpgradeFn) {
|
|
316
|
+
await ensureFreshPackageVersionInfo(undefined, { source: 'start', log: console.log });
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
293
319
|
console.log('📦 Checking for updates...');
|
|
294
320
|
const runWithTimeout = async (label, fn) => {
|
|
295
321
|
const controller = new AbortController();
|
|
@@ -468,7 +494,9 @@ export async function cmdStart(opts = {}) {
|
|
|
468
494
|
return;
|
|
469
495
|
// A stopped container may miss the daily upgrade trigger. Check once on
|
|
470
496
|
// every real start so the service does not stay on an old installation.
|
|
471
|
-
await (
|
|
497
|
+
const versionInfo = await ensureFreshPackageVersionInfo(undefined, { source: 'start', log: console.log });
|
|
498
|
+
if (opts.upgradeChecks)
|
|
499
|
+
await opts.upgradeChecks();
|
|
472
500
|
// 旧配置自动迁移(daemon.json → 新结构)
|
|
473
501
|
const { autoMigrateIfNeeded } = await import('../config-store.js');
|
|
474
502
|
autoMigrateIfNeeded();
|
|
@@ -593,6 +621,20 @@ export async function cmdStart(opts = {}) {
|
|
|
593
621
|
return;
|
|
594
622
|
}
|
|
595
623
|
reportOrphans(orphans);
|
|
624
|
+
if (versionInfo.some(result => result.hasUpdate)) {
|
|
625
|
+
cleanEnv();
|
|
626
|
+
const launched = await launchPackageLifecycle('start', console.log, {
|
|
627
|
+
prepared: true, foreground: opts.foreground, env: buildDaemonEnv(p, opts),
|
|
628
|
+
});
|
|
629
|
+
if (!launched.ok) {
|
|
630
|
+
console.error(`❌ 启动事务未能建立:${launched.reason}`);
|
|
631
|
+
process.exitCode = 1;
|
|
632
|
+
}
|
|
633
|
+
else if (!opts.foreground) {
|
|
634
|
+
console.log('📦 已交由 restart-monitor 应用缓存版本并启动服务');
|
|
635
|
+
}
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
596
638
|
console.log('🚀 Starting EvolCore...');
|
|
597
639
|
const stdoutRotation = rotateStdoutLog(p.logs);
|
|
598
640
|
if (stdoutRotation.rotatedPath) {
|
|
@@ -881,126 +923,18 @@ export async function cmdRestart(opts = {}) {
|
|
|
881
923
|
if (initialRuntimeOrphans.length === 0 && rejectPidIsolatedLifecycle('restart', initialStatus, ping))
|
|
882
924
|
return;
|
|
883
925
|
}
|
|
884
|
-
//
|
|
885
|
-
//
|
|
886
|
-
//
|
|
887
|
-
// normal restart to perform every registry lookup twice, and in installed
|
|
888
|
-
// mode could race the monitor while it was preparing its rollback point.
|
|
926
|
+
// The shared launchPackageLifecycle path delegates to launchMonitorAndConfirm;
|
|
927
|
+
// the monitor retains shutdown, orphan checks, build and rollback ownership.
|
|
928
|
+
// Network preflight must finish before a confirmed monitor stops the daemon.
|
|
889
929
|
if (!requireCompletedDataMigration(resolveRoot(), 'restart'))
|
|
890
930
|
return;
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
if (aliveMains.length > 0) {
|
|
895
|
-
if (aliveMains.length > 1) {
|
|
896
|
-
console.log(`⚠ 检测到 ${aliveMains.length} 个 main 实例,将一并停止: ${aliveMains.map(m => m.record.pid).join(', ')}`);
|
|
897
|
-
}
|
|
898
|
-
const mainPids = new Set(aliveMains.map(entry => entry.record.pid));
|
|
899
|
-
const currentPing = await probeDaemon(socketPath);
|
|
900
|
-
const gracefulPid = currentPing && mainPids.has(currentPing.pid)
|
|
901
|
-
? await requestDaemonShutdown(socketPath, DAEMON_SHUTDOWN_TIMEOUT_MS, 'ec restart', mainPids)
|
|
902
|
-
: null;
|
|
903
|
-
const stopped = await Promise.all(aliveMains.map(m => stopPid(m.record.pid, m.record.pid === gracefulPid, m.record.startedAt)));
|
|
904
|
-
if (stopped.some(result => !result)) {
|
|
905
|
-
console.error('❌ Restart aborted because an existing EvolCore process could not be stopped');
|
|
906
|
-
process.exitCode = 1;
|
|
907
|
-
return;
|
|
908
|
-
}
|
|
909
|
-
await sleep(500);
|
|
910
|
-
}
|
|
911
|
-
cleanupInstances();
|
|
912
|
-
const remainingMainProcesses = scanInstances().mains.filter(entry => entry.alive);
|
|
913
|
-
if (remainingMainProcesses.length > 0) {
|
|
914
|
-
console.error(`❌ Restart aborted: EvolCore process still registered and alive (PID: ${remainingMainProcesses.map(entry => entry.record.pid).join(', ')})`);
|
|
915
|
-
process.exitCode = 1;
|
|
916
|
-
return;
|
|
917
|
-
}
|
|
918
|
-
// 孤儿处理:同 HOME/同安装包的孤儿属于本运行时,先确认退出再替换;
|
|
919
|
-
// 跨 HOME 的孤儿只在 --clear 时 kill,否则仅警告。findOrphanProcesses
|
|
920
|
-
// 在 Windows 上需要一次 CIM 查询;保留一个快照,避免同一阶段重复扫描。
|
|
921
|
-
{
|
|
922
|
-
const orphans = findOrphanProcesses();
|
|
923
|
-
const confirmedTestDaemons = orphans.filter(o => o.confirmedTestDaemon);
|
|
924
|
-
if (confirmedTestDaemons.length > 0) {
|
|
925
|
-
const killed = killOrphans(confirmedTestDaemons);
|
|
926
|
-
console.log(`☠ 已清理 ${killed.length} 个泄漏的测试 daemon: ${killed.join(', ')}`);
|
|
927
|
-
await sleep(500);
|
|
928
|
-
}
|
|
929
|
-
const runtimeOrphans = orphans.filter(o => isRuntimeOrphan(o));
|
|
930
|
-
if (runtimeOrphans.length > 0) {
|
|
931
|
-
console.log(`⚠ 检测到未登记的 EvolCore 进程,将一并停止: ${runtimeOrphans.map(o => o.pid).join(', ')}`);
|
|
932
|
-
const orphanPids = new Set(runtimeOrphans.map(orphan => orphan.pid));
|
|
933
|
-
const currentPing = await probeDaemon(socketPath);
|
|
934
|
-
const gracefulPid = currentPing && orphanPids.has(currentPing.pid)
|
|
935
|
-
? await requestDaemonShutdown(socketPath, DAEMON_SHUTDOWN_TIMEOUT_MS, 'ec restart', orphanPids)
|
|
936
|
-
: null;
|
|
937
|
-
const stopped = await Promise.all(runtimeOrphans.map(o => stopPid(o.pid, o.pid === gracefulPid)));
|
|
938
|
-
if (stopped.some(result => !result)) {
|
|
939
|
-
console.error('❌ Restart aborted because an unregistered EvolCore process could not be stopped');
|
|
940
|
-
process.exitCode = 1;
|
|
941
|
-
return;
|
|
942
|
-
}
|
|
943
|
-
await sleep(500);
|
|
944
|
-
}
|
|
945
|
-
// stopPid() already waited for every runtime orphan above, so avoid a
|
|
946
|
-
// second scan before handling cross-HOME records.
|
|
947
|
-
const otherHome = orphans.filter(o => !o.confirmedTestDaemon && !isRuntimeOrphan(o));
|
|
948
|
-
if (opts.clear && otherHome.length > 0) {
|
|
949
|
-
const killed = killOrphans(otherHome);
|
|
950
|
-
console.log(`☠ 已 SIGKILL ${killed.length} 个跨 HOME 孤儿进程: ${killed.join(', ')}`);
|
|
951
|
-
await sleep(500);
|
|
952
|
-
}
|
|
953
|
-
else if (otherHome.length > 0) {
|
|
954
|
-
reportOrphans(otherHome);
|
|
955
|
-
}
|
|
956
|
-
// Keep the post-stop ownership guard: a process that appeared during the
|
|
957
|
-
// cleanup window must still block replacement.
|
|
958
|
-
const remainingRuntimeOrphans = findOrphanProcesses().filter(o => isRuntimeOrphan(o));
|
|
959
|
-
if (remainingRuntimeOrphans.length > 0) {
|
|
960
|
-
console.error(`❌ Restart aborted: EvolCore process still running (PID: ${remainingRuntimeOrphans.map(o => o.pid).join(', ')})`);
|
|
961
|
-
process.exitCode = 1;
|
|
962
|
-
return;
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
// 只清理 EvolCore 自己登记的 codex app-server,不能影响桌面端实例。
|
|
966
|
-
{
|
|
967
|
-
const killed = stopCodexAppServerOrphans();
|
|
968
|
-
if (killed > 0) {
|
|
969
|
-
console.log(`☠ 已清理 ${killed} 个 EvolCore codex app-server 孤儿进程`);
|
|
970
|
-
await sleep(500);
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
console.log(`⏱ restart prep done in ${((Date.now() - cmdStartedAt) / 1000).toFixed(1)}s, starting...`);
|
|
974
|
-
// 通过 restart-monitor 启动,避免在 agent 内调用时自杀。
|
|
975
|
-
// 开发仓下 monitor 从源码跑;安装包下先复制到 stage 目录,两种情况都让看门狗
|
|
976
|
-
// 不住在会被替换的产物里。
|
|
977
|
-
const monitorEntry = platform.resolveMonitorLaunch(getPackageRoot(), path.join(resolvePaths().root, 'data', 'monitor-stage'));
|
|
978
|
-
if (monitorEntry.note)
|
|
979
|
-
console.log(`ℹ ${monitorEntry.note}`);
|
|
980
|
-
if (!fs.existsSync(monitorEntry.entry)) {
|
|
981
|
-
console.error(`❌ 重启中止:找不到 restart-monitor 入口 ${monitorEntry.entry}`);
|
|
982
|
-
console.error(' 请先执行 npm run build 重建产物');
|
|
983
|
-
process.exitCode = 1;
|
|
984
|
-
return;
|
|
985
|
-
}
|
|
986
|
-
const monitorStarted = await spawnRestartMonitorAndConfirm(monitorEntry, log => console.error(log));
|
|
987
|
-
if (!monitorStarted.ok) {
|
|
988
|
-
if (monitorEntry.stageDir)
|
|
989
|
-
platform.cleanupMonitorStage(monitorEntry.stageDir);
|
|
990
|
-
console.error(`❌ 重启中止:restart-monitor 未能启动(${monitorStarted.reason})`);
|
|
991
|
-
if (fs.existsSync(path.join(getPackageRoot(), 'src', 'cli', 'index.ts'))) {
|
|
992
|
-
console.error(' 源码可能存在语法错误导致 tsx 无法加载。请执行 npx tsc --noEmit 检查。');
|
|
993
|
-
}
|
|
994
|
-
console.error(' 服务已停止,请修复后执行 ec start。');
|
|
931
|
+
const launched = await launchPackageLifecycle('restart', console.log, { clear: opts.clear });
|
|
932
|
+
if (!launched.ok) {
|
|
933
|
+
console.error(`❌ 重启中止:restart-monitor 未能启动(${launched.reason});当前服务未主动停止`);
|
|
995
934
|
process.exitCode = 1;
|
|
996
935
|
return;
|
|
997
936
|
}
|
|
998
|
-
console.log(
|
|
999
|
-
// 代码统计(开发环境)
|
|
1000
|
-
if (path.normalize(resolveRoot()) === path.normalize(getPackageRoot())) {
|
|
1001
|
-
console.log('');
|
|
1002
|
-
printCodeStats(getPackageRoot(), resolvePaths().logs);
|
|
1003
|
-
}
|
|
937
|
+
console.log(`🔄 Restart monitor started (${((Date.now() - cmdStartedAt) / 1000).toFixed(1)}s); service is restarting...`);
|
|
1004
938
|
}
|
|
1005
939
|
function normalizeRuntimePath(value) {
|
|
1006
940
|
return value.replace(/[\\/]+/g, '/').toLowerCase();
|
|
@@ -1308,8 +1242,13 @@ export async function cmdStatus() {
|
|
|
1308
1242
|
console.log(' 请稍后再次执行 ec status。');
|
|
1309
1243
|
}
|
|
1310
1244
|
else {
|
|
1311
|
-
|
|
1312
|
-
|
|
1245
|
+
// With no live main/monitor, a missing Windows pipe is the normal stopped
|
|
1246
|
+
// state. Preserve uncertainty for permissions, timeouts, unknown errors,
|
|
1247
|
+
// and Unix callers that may be isolated from the daemon's PID namespace.
|
|
1248
|
+
const stopped = !ipcFailure || (platform.isWindows && ipcFailure instanceof IpcTransportError
|
|
1249
|
+
&& ['ENOENT', 'ECONNREFUSED'].includes(ipcFailure.code));
|
|
1250
|
+
console.log(stopped ? '⚠ EvolCore is not running' : '⚠ 无法确认 EvolCore 运行状态:IPC 不可用,且没有可见的存活 PID。');
|
|
1251
|
+
if (!stopped && ipcFailure)
|
|
1313
1252
|
console.log(` ${ipcFailure instanceof Error ? ipcFailure.message : String(ipcFailure)}`);
|
|
1314
1253
|
}
|
|
1315
1254
|
// Session & Project statistics (从文件系统读)
|
|
@@ -2720,17 +2659,18 @@ function findAliveEcweb(p) {
|
|
|
2720
2659
|
return alive[0] ?? null;
|
|
2721
2660
|
}
|
|
2722
2661
|
/**
|
|
2723
|
-
* 轻量 HTTP 就绪探测:
|
|
2724
|
-
* 不走 /api/pair-code
|
|
2725
|
-
* 根路径由 serveStatic 处理,返回 index.html,无副作用。
|
|
2662
|
+
* 轻量 HTTP 就绪探测:ECWeb 的健康端点必须返回明确的服务标识。
|
|
2663
|
+
* 不走 /api/pair-code(会触发配对码刷新副作用),也不依赖静态页面内容。
|
|
2726
2664
|
*/
|
|
2727
2665
|
async function probeEcwebReady(port) {
|
|
2728
2666
|
try {
|
|
2729
|
-
const res = await fetch(`http://127.0.0.1:${port}
|
|
2730
|
-
method: 'GET',
|
|
2667
|
+
const res = await fetch(`http://127.0.0.1:${port}/api/health`, {
|
|
2731
2668
|
signal: AbortSignal.timeout(2000),
|
|
2732
2669
|
});
|
|
2733
|
-
|
|
2670
|
+
if (!res.ok)
|
|
2671
|
+
return false;
|
|
2672
|
+
const body = await res.json();
|
|
2673
|
+
return body.ok === true && body.service === 'ecweb';
|
|
2734
2674
|
}
|
|
2735
2675
|
catch {
|
|
2736
2676
|
return false;
|
|
@@ -2756,8 +2696,9 @@ async function waitForExistingEcweb(p, timeoutMs = 3_000) {
|
|
|
2756
2696
|
}
|
|
2757
2697
|
/**
|
|
2758
2698
|
* 输出 ECWeb 状态。判定口径:
|
|
2759
|
-
* 1.
|
|
2760
|
-
* 2.
|
|
2699
|
+
* 1. HTTP 是否就绪——探测 ECWeb 专用 /api/health 端点。
|
|
2700
|
+
* 2. 进程是否存活(instance/ 下的 pid 文件 + isProcessRunning)仅用于补充诊断;
|
|
2701
|
+
* 某些 CLI 运行在隔离 PID namespace 中,看不到宿主 ECWeb PID 是正常情况。
|
|
2761
2702
|
*/
|
|
2762
2703
|
async function printEcwebStatus(p) {
|
|
2763
2704
|
try {
|
|
@@ -2773,6 +2714,15 @@ async function printEcwebStatus(p) {
|
|
|
2773
2714
|
// still provide an authoritative runtime status without local config access.
|
|
2774
2715
|
}
|
|
2775
2716
|
const entries = readEcwebInstanceEntries(p);
|
|
2717
|
+
// Probe before consulting PID visibility. The daemon and CLI can be in
|
|
2718
|
+
// different PID namespaces while sharing the host network namespace.
|
|
2719
|
+
let readyEntry;
|
|
2720
|
+
for (const entry of entries) {
|
|
2721
|
+
if (await probeEcwebReady(entry.record.port)) {
|
|
2722
|
+
readyEntry = entry;
|
|
2723
|
+
break;
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2776
2726
|
const aliveEntries = [];
|
|
2777
2727
|
for (const entry of entries) {
|
|
2778
2728
|
if (platform.isProcessRunning(entry.record.pid)) {
|
|
@@ -2781,22 +2731,21 @@ async function printEcwebStatus(p) {
|
|
|
2781
2731
|
else {
|
|
2782
2732
|
// A stale EC Web record must never be used to report the PID of an
|
|
2783
2733
|
// unrelated process that later inherited the port.
|
|
2784
|
-
|
|
2785
|
-
|
|
2734
|
+
// Keep a record whose dedicated health endpoint just proved live: the
|
|
2735
|
+
// PID may be hidden by a namespace boundary rather than actually dead.
|
|
2736
|
+
if (entry.filePath !== readyEntry?.filePath) {
|
|
2737
|
+
try {
|
|
2738
|
+
fs.unlinkSync(entry.filePath);
|
|
2739
|
+
}
|
|
2740
|
+
catch { }
|
|
2786
2741
|
}
|
|
2787
|
-
catch { }
|
|
2788
|
-
}
|
|
2789
|
-
}
|
|
2790
|
-
let readyEntry;
|
|
2791
|
-
for (const entry of aliveEntries) {
|
|
2792
|
-
if (await probeEcwebReady(entry.record.port)) {
|
|
2793
|
-
readyEntry = entry;
|
|
2794
|
-
break;
|
|
2795
2742
|
}
|
|
2796
2743
|
}
|
|
2797
2744
|
if (readyEntry) {
|
|
2798
2745
|
console.log('');
|
|
2799
|
-
|
|
2746
|
+
const pidVisible = aliveEntries.some(entry => entry.filePath === readyEntry.filePath);
|
|
2747
|
+
const pidText = pidVisible ? `PID: ${readyEntry.record.pid}` : `PID: ${readyEntry.record.pid}(当前 namespace 不可见)`;
|
|
2748
|
+
console.log(`🔭 ECWeb: 运行中 (${pidText}) http://localhost:${readyEntry.record.port}`);
|
|
2800
2749
|
return;
|
|
2801
2750
|
}
|
|
2802
2751
|
const occupiedPids = new Set();
|
|
@@ -2991,7 +2940,7 @@ export async function startEcwebIfEnabled(p, options = {}) {
|
|
|
2991
2940
|
console.log(`✓ ECWeb ${actionLabel} (PID: ${pid}) http://localhost:${port}`);
|
|
2992
2941
|
if (pair) {
|
|
2993
2942
|
const mins = Math.max(0, Math.round((pair.expiresAt - Date.now()) / 60000));
|
|
2994
|
-
console.log(` 配对码: ${pair.code} (约 ${mins}
|
|
2943
|
+
console.log(` 配对码: ${pair.code} (约 ${mins} 分钟内有效,仅可配对一次,已配对过的浏览器无需重新配对)`);
|
|
2995
2944
|
}
|
|
2996
2945
|
else {
|
|
2997
2946
|
console.log(' daemon 尚未提供配对码;EvolCore 启动后可通过 /pair 或 ECWeb 页面获取');
|
|
@@ -3027,7 +2976,7 @@ async function printEcwebAccess(port) {
|
|
|
3027
2976
|
}
|
|
3028
2977
|
if (pair) {
|
|
3029
2978
|
const mins = Math.max(0, Math.round((pair.expiresAt - Date.now()) / 60000));
|
|
3030
|
-
console.log(` 配对码: ${pair.code} (约 ${mins}
|
|
2979
|
+
console.log(` 配对码: ${pair.code} (约 ${mins} 分钟内有效,仅可配对一次,token 缓存 7 天,有访问自动续期)`);
|
|
3031
2980
|
}
|
|
3032
2981
|
else {
|
|
3033
2982
|
console.log(' 配对码: 暂不可用(稍后重试 ec watch web,或查看 logs/watch-web.log)');
|
package/dist/cli/diag.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ipcQuery } from '../ipc.js';
|
|
2
2
|
import { resolvePaths } from '../paths.js';
|
|
3
|
-
import {
|
|
3
|
+
import { readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
4
4
|
import { parseDiagArgs } from '../core/command/diag-service.js';
|
|
5
5
|
import { wantsHelp } from './help.js';
|
|
6
6
|
export async function cmdDiag(args) {
|
|
7
7
|
if (wantsHelp(args)) {
|
|
8
|
-
console.log('用法:ec diag <问题描述> [--owner <daemonOwner-aid>] [--format json]\n ec diag stop [--format json]\n未指定 --owner 时联系本机 daemon.json.owners[0]。');
|
|
8
|
+
console.log('用法:ec diag <问题描述> [--owner <daemonOwner-aid>] [--format json]\n ec diag stop [--format json]\n未指定 --owner 时联系本机 daemon.json.owners[0];有效诊断期间再次执行会追加到原 case。');
|
|
9
9
|
return;
|
|
10
10
|
}
|
|
11
11
|
const json = args.at(-2) === '--format' && args.at(-1) === 'json';
|
|
@@ -17,7 +17,7 @@ export async function cmdDiag(args) {
|
|
|
17
17
|
type: 'diag', argv,
|
|
18
18
|
...(process.env.EVOLCORE_SESSION_ID ? {
|
|
19
19
|
sessionId: process.env.EVOLCORE_SESSION_ID,
|
|
20
|
-
delegationToken:
|
|
20
|
+
delegationToken: readDelegationCredential(),
|
|
21
21
|
} : {}),
|
|
22
22
|
}, 30_000) ?? { ok: false, code: 'DAEMON_UNAVAILABLE', message: 'daemon 未返回结果,请检查其运行状态;发送结果尚未确认' };
|
|
23
23
|
}
|
package/dist/cli/fs-command.js
CHANGED
|
@@ -5,8 +5,8 @@ import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
|
|
|
5
5
|
import { agentmdGet, getAidStore, isValidAid, loadClient, SLOT } from '../aun/aid/index.js';
|
|
6
6
|
import { ipcQuery } from '../ipc.js';
|
|
7
7
|
import { resolvePaths } from '../paths.js';
|
|
8
|
-
import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
|
|
9
|
-
import { downloadGroupFsBytes } from '../aun/group
|
|
8
|
+
import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
9
|
+
import { downloadGroupFsBytes } from '../aun/group/index.js';
|
|
10
10
|
class FsCliError extends Error {
|
|
11
11
|
code;
|
|
12
12
|
suggestion;
|
|
@@ -209,7 +209,7 @@ export async function cmdFs(args) {
|
|
|
209
209
|
}
|
|
210
210
|
async function runManagedFs(args, formatJson) {
|
|
211
211
|
const sessionId = process.env.EVOLCORE_SESSION_ID;
|
|
212
|
-
const delegationToken =
|
|
212
|
+
const delegationToken = readDelegationCredential();
|
|
213
213
|
const fail = (code, message) => {
|
|
214
214
|
if (formatJson)
|
|
215
215
|
console.log(JSON.stringify({ ok: false, code, error: message }));
|
|
@@ -4,7 +4,7 @@ import { ipcQuery } from '../ipc.js';
|
|
|
4
4
|
import { HANDOFF_QUERY_DEFAULT_LIMIT, HANDOFF_QUERY_MAX_LIMIT, HANDOFF_STATES } from '../core/handoff/types.js';
|
|
5
5
|
import { HANDOFF_ID_RE } from '../core/handoff/store.js';
|
|
6
6
|
import { isHelpFlag, wantsHelp } from './help.js';
|
|
7
|
-
import {
|
|
7
|
+
import { readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
8
8
|
function parseLimit(value) {
|
|
9
9
|
const limit = Number(value);
|
|
10
10
|
if (!value || !Number.isInteger(limit) || limit < 1 || limit > HANDOFF_QUERY_MAX_LIMIT) {
|
|
@@ -186,7 +186,7 @@ Commands:
|
|
|
186
186
|
sessionId: process.env.EVOLCORE_SESSION_ID,
|
|
187
187
|
handoffId: parsed.handoffId,
|
|
188
188
|
content: parsed.content,
|
|
189
|
-
delegationToken:
|
|
189
|
+
delegationToken: readDelegationCredential(),
|
|
190
190
|
}, 5000);
|
|
191
191
|
if (!result) {
|
|
192
192
|
console.error('✗ daemon 暂时不可用');
|
|
@@ -216,7 +216,7 @@ Commands:
|
|
|
216
216
|
sessionId: process.env.EVOLCORE_SESSION_ID,
|
|
217
217
|
handoffId: parsed.handoffId,
|
|
218
218
|
content: parsed.content,
|
|
219
|
-
delegationToken:
|
|
219
|
+
delegationToken: readDelegationCredential(),
|
|
220
220
|
}, 5000);
|
|
221
221
|
if (!result) {
|
|
222
222
|
console.error('✗ daemon 暂时不可用');
|
|
@@ -235,7 +235,7 @@ Commands:
|
|
|
235
235
|
}
|
|
236
236
|
const result = await ipcQuery(resolvePaths().socket, {
|
|
237
237
|
type: 'handoff-status', sessionId: process.env.EVOLCORE_SESSION_ID, handoffId,
|
|
238
|
-
delegationToken:
|
|
238
|
+
delegationToken: readDelegationCredential(),
|
|
239
239
|
}, 5000);
|
|
240
240
|
if (!result) {
|
|
241
241
|
console.error('✗ daemon 暂时不可用');
|
|
@@ -267,7 +267,7 @@ Commands:
|
|
|
267
267
|
state: parsed.state,
|
|
268
268
|
filterSessionId: parsed.sessionId,
|
|
269
269
|
limit: parsed.limit,
|
|
270
|
-
delegationToken:
|
|
270
|
+
delegationToken: readDelegationCredential(),
|
|
271
271
|
}, 5000);
|
|
272
272
|
if (!result) {
|
|
273
273
|
console.error('✗ daemon 暂时不可用');
|
|
@@ -310,7 +310,7 @@ Commands:
|
|
|
310
310
|
agent: parsed.agent,
|
|
311
311
|
handoffId: parsed.handoffId,
|
|
312
312
|
limit: parsed.limit,
|
|
313
|
-
delegationToken:
|
|
313
|
+
delegationToken: readDelegationCredential(),
|
|
314
314
|
}, 5000);
|
|
315
315
|
if (!result) {
|
|
316
316
|
console.error('✗ daemon 暂时不可用');
|
package/dist/cli/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import fs from 'fs';
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { getPackageRoot, resolvePaths } from '../paths.js';
|
|
7
7
|
import { ipcQuery } from '../ipc.js';
|
|
8
|
-
import {
|
|
8
|
+
import { readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
9
9
|
import { cmdInit } from './init.js';
|
|
10
10
|
import { cmdInitWechat, cmdInitFeishu, cmdInitDingtalk, cmdInitQQBot, cmdInitWecom, cmdInitAun } from './init-channel.js';
|
|
11
11
|
import { isHelpFlag, wantsHelp, getArgValue } from './help.js';
|
|
@@ -34,6 +34,7 @@ Agent 与会话:
|
|
|
34
34
|
agent 管理 EvolAgent
|
|
35
35
|
ctl 当前托管会话的控制命令
|
|
36
36
|
queue 查询或操作 agent 消息队列
|
|
37
|
+
task 恢复暂停或异常中断的会话任务
|
|
37
38
|
trigger 管理定时与事件触发器
|
|
38
39
|
handoff 查询和完成跨会话回流
|
|
39
40
|
model 查看或设置模型与推理强度
|
|
@@ -247,7 +248,7 @@ export async function main(args) {
|
|
|
247
248
|
}
|
|
248
249
|
if (process.env.EVOLCORE_SESSION_ID) {
|
|
249
250
|
const sessionId = process.env.EVOLCORE_SESSION_ID;
|
|
250
|
-
const delegationToken =
|
|
251
|
+
const delegationToken = readDelegationCredential();
|
|
251
252
|
const result = await ipcQuery(resolvePaths().socket, {
|
|
252
253
|
type: 'status.auth', sessionId, delegationToken,
|
|
253
254
|
});
|
|
@@ -328,6 +329,11 @@ export async function main(args) {
|
|
|
328
329
|
case 'queue':
|
|
329
330
|
await cmdQueue(args.slice(1));
|
|
330
331
|
break;
|
|
332
|
+
case 'task': {
|
|
333
|
+
const { cmdTask } = await import('./task-command.js');
|
|
334
|
+
await cmdTask(args.slice(1));
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
331
337
|
case 'trigger':
|
|
332
338
|
{
|
|
333
339
|
const { cmdTrigger } = await import('./trigger-command.js');
|
package/dist/cli/init.js
CHANGED
|
@@ -7,7 +7,7 @@ import { commandExists } from '../utils/cross-platform.js';
|
|
|
7
7
|
import { scanInstances } from '../utils/instance-registry.js';
|
|
8
8
|
import { saveDefaultsSafe, loadAllAgents, loadDaemonConfig, saveDaemonConfig } from '../config-store.js';
|
|
9
9
|
import { ecwebService, setEcwebEnabled } from '../config/daemon-services.js';
|
|
10
|
-
import { generateControlAid, resolveControlAidDomain } from '../aun/aid/control-aid.js';
|
|
10
|
+
import { ensureControlAgentMd, generateControlAid, resolveControlAidDomain } from '../aun/aid/control-aid.js';
|
|
11
11
|
import { getCodexAppServerAvailability } from '../agents/codex-runner.js';
|
|
12
12
|
import { DEFAULT_ECAGENT_BASE_URL, resolveEcagentConfig } from '../agents/baseagent.js';
|
|
13
13
|
import { defaultProjectsRoot } from '../utils/project-path.js';
|
|
@@ -484,6 +484,12 @@ export async function initTail(options = {}) {
|
|
|
484
484
|
let ownerBindingInterrupted = false;
|
|
485
485
|
if (daemonConfig.aid) {
|
|
486
486
|
console.log(`✓ 控制 AID 已存在: ${daemonConfig.aid}`);
|
|
487
|
+
try {
|
|
488
|
+
await ensureControlAgentMd(daemonConfig.aid);
|
|
489
|
+
}
|
|
490
|
+
catch (e) {
|
|
491
|
+
console.error(`⚠️ 控制 AID agent.md 补全失败(本次继续,后续启动会重试): ${e?.message || e}`);
|
|
492
|
+
}
|
|
487
493
|
}
|
|
488
494
|
else {
|
|
489
495
|
try {
|
|
@@ -861,6 +867,33 @@ export async function cmdInitNonInteractive(opts, dependencies = {}) {
|
|
|
861
867
|
fail('CONTROL_AID_CREATE_FAILED', `control AID creation failed: ${e?.message || e}`, EXIT_RUNTIME, format);
|
|
862
868
|
}
|
|
863
869
|
}
|
|
870
|
+
if (controlAid) {
|
|
871
|
+
const certPath = path.join(resolvePaths().root, 'AIDs', controlAid, 'public', 'cert.pem');
|
|
872
|
+
if (!fs.existsSync(certPath)) {
|
|
873
|
+
// An externally supplied/pre-created AID without a local certificate
|
|
874
|
+
// cannot be signed or uploaded by this process. Avoid entering the SDK
|
|
875
|
+
// network path during non-interactive init; later daemon startup can
|
|
876
|
+
// retry once the identity material is provisioned.
|
|
877
|
+
console.error(`control AID agent.md publish skipped: local certificate not found for ${controlAid}`);
|
|
878
|
+
}
|
|
879
|
+
else {
|
|
880
|
+
try {
|
|
881
|
+
await ensureControlAgentMd(controlAid);
|
|
882
|
+
}
|
|
883
|
+
catch (e) {
|
|
884
|
+
// A registered control AID remains usable when the Name Service is
|
|
885
|
+
// temporarily unavailable; startup and the next init retry publication.
|
|
886
|
+
if (format === 'json') {
|
|
887
|
+
// Keep the successful init result machine-readable; surface the
|
|
888
|
+
// warning through stderr so stdout remains valid JSON.
|
|
889
|
+
console.error(`control AID agent.md publish warning: ${e?.message || e}`);
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
console.error(`⚠️ 控制 AID agent.md 补全失败(本次继续,后续启动会重试): ${e?.message || e}`);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
864
897
|
// ── 9. 写 daemon.json(aid + owners + ecweb)──
|
|
865
898
|
try {
|
|
866
899
|
const next = {
|
|
@@ -20,6 +20,7 @@ const MANAGED_TASK_COMMANDS = new Set([
|
|
|
20
20
|
'stats',
|
|
21
21
|
'status',
|
|
22
22
|
'storage',
|
|
23
|
+
'task',
|
|
23
24
|
'trigger',
|
|
24
25
|
'version',
|
|
25
26
|
'-v',
|
|
@@ -30,7 +31,7 @@ export class ManagedCommandNotAllowedError extends Error {
|
|
|
30
31
|
command;
|
|
31
32
|
code = 'NOT_ALLOWED';
|
|
32
33
|
constructor(command) {
|
|
33
|
-
super(`Command ${command} is not available in a managed Agent task`);
|
|
34
|
+
super(`Command ${command} is not available in a managed Agent task; run it from the host terminal after the task completes`);
|
|
34
35
|
this.command = command;
|
|
35
36
|
this.name = 'ManagedCommandNotAllowedError';
|
|
36
37
|
}
|
package/dist/cli/menu-client.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { getArgValue, wantsHelp } from './help.js';
|
|
3
|
-
import { executeMenuClientRequest, MenuClientError } from '../aun/menu
|
|
4
|
-
import {
|
|
3
|
+
import { executeMenuClientRequest, MenuClientError } from '../aun/menu/index.js';
|
|
4
|
+
import { readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
5
5
|
function parseDurationMs(value) {
|
|
6
6
|
if (value === undefined)
|
|
7
7
|
return undefined;
|
|
@@ -94,12 +94,16 @@ export async function cmdMenuClient(args) {
|
|
|
94
94
|
}
|
|
95
95
|
let response;
|
|
96
96
|
if (process.env.EVOLCORE_SESSION_ID) {
|
|
97
|
-
const { ipcQuery } = await import('../ipc.js');
|
|
97
|
+
const { ipcQuery, IpcTransportError } = await import('../ipc.js');
|
|
98
98
|
const { resolvePaths } = await import('../paths.js');
|
|
99
99
|
const result = await ipcQuery(resolvePaths().socket, {
|
|
100
100
|
type: 'menu-client.request', argv: args, sessionId: process.env.EVOLCORE_SESSION_ID,
|
|
101
|
-
delegationToken:
|
|
102
|
-
}, 250_000)
|
|
101
|
+
delegationToken: readDelegationCredential(),
|
|
102
|
+
}, 250_000, { throwOnError: true }).catch(error => {
|
|
103
|
+
if (!(error instanceof IpcTransportError))
|
|
104
|
+
throw error;
|
|
105
|
+
throw new MenuClientError(error.code, error.message);
|
|
106
|
+
});
|
|
103
107
|
if (!result?.ok)
|
|
104
108
|
throw new MenuClientError(result?.code ?? 'DAEMON_UNAVAILABLE', result?.error ?? 'Managed Menu daemon is unavailable');
|
|
105
109
|
response = result.response;
|
|
@@ -107,4 +111,8 @@ export async function cmdMenuClient(args) {
|
|
|
107
111
|
else
|
|
108
112
|
response = await executeMenuClientRequest(parseMenuClientArgs(args));
|
|
109
113
|
console.log(JSON.stringify(response, null, 2));
|
|
114
|
+
// Transport success does not imply the requested operation succeeded.
|
|
115
|
+
// Preserve the complete wire response for callers while failing the CLI.
|
|
116
|
+
if (response?.error)
|
|
117
|
+
process.exitCode = 1;
|
|
110
118
|
}
|