evolcore 0.0.20 → 0.0.22
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 +65 -0
- package/README.md +58 -9
- package/bin/codex-managed-hook.mjs +3 -0
- package/bin/install-codex-managed-hooks.mjs +3 -1
- package/dist/agents/baseagent.js +10 -6
- package/dist/agents/claude-runner.js +393 -108
- package/dist/agents/codex-app-server-client.js +41 -7
- package/dist/agents/codex-runner.js +1292 -220
- package/dist/agents/ecagent-runner.js +171 -61
- package/dist/agents/gemini-runner.js +130 -30
- package/dist/agents/request-identity.js +25 -0
- package/dist/agents/runner-types.js +19 -0
- package/dist/aun/aid/agentmd.js +59 -2
- package/dist/aun/aid/identity.js +4 -1
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/msg/group.js +72 -6
- package/dist/aun/msg/history.js +213 -36
- package/dist/aun/msg/managed-operation.js +58 -9
- package/dist/aun/msg/p2p.js +5 -0
- package/dist/aun/outbox.js +189 -80
- package/dist/aun/service-proxy.js +43 -25
- package/dist/channels/aun.js +618 -123
- package/dist/channels/daemon.js +6 -1
- package/dist/cli/agent-command.js +4 -3
- package/dist/cli/agent.js +66 -56
- package/dist/cli/aun-commands.js +177 -42
- package/dist/cli/command-log.js +10 -11
- package/dist/cli/contact.js +1 -0
- package/dist/cli/daemon-commands.js +98 -123
- package/dist/cli/init.js +27 -15
- package/dist/cli/task-context.js +50 -0
- package/dist/cli/trigger-command.js +14 -5
- package/dist/cli/watch-logs.js +10 -3
- package/dist/config/builtin-roles.js +1 -0
- package/dist/config/config-field-policy.js +19 -5
- package/dist/config/config-manager.js +167 -22
- package/dist/config/contact-book-store.js +25 -3
- package/dist/config/contact-operation-service.js +32 -1
- package/dist/config/contact-request-service.js +44 -0
- package/dist/config/daemon-services.js +186 -0
- package/dist/config/gateway-config.js +20 -9
- package/dist/config/role-service.js +54 -3
- package/dist/config/schema-migration.js +550 -0
- package/dist/config-store.js +151 -9
- package/dist/core/agent-application-service.js +279 -0
- package/dist/core/audit/log-integrity.js +102 -0
- package/dist/core/auth/agent-delegation.js +43 -1
- package/dist/core/auth/auth-gateway.js +41 -4
- package/dist/core/auth/authorization-audit.js +216 -8
- package/dist/core/auth/operation-authorizer.js +41 -1
- package/dist/core/auth/operation-catalog.js +9 -1
- package/dist/core/bootstrap-messages.js +8 -0
- package/dist/core/bootstrap-service.js +99 -27
- package/dist/core/causation/aun-association.js +7 -4
- package/dist/core/command/agent-control.js +56 -16
- package/dist/core/command/command-handler.js +311 -44
- package/dist/core/command/connect-menu.js +3 -4
- package/dist/core/command/group-menu.js +5 -7
- package/dist/core/command/menu-handler.js +288 -80
- package/dist/core/command/menu-protocol.js +1 -1
- package/dist/core/command/role-menu.js +21 -11
- package/dist/core/command/slash-gate.js +85 -18
- package/dist/core/command/slash-handler.js +377 -36
- package/dist/core/data-migration.js +11 -1
- package/dist/core/event-catalog.js +37 -0
- package/dist/core/evolagent.js +4 -0
- package/dist/core/handoff/dispatcher.js +4 -0
- package/dist/core/handoff/runtime.js +33 -3
- package/dist/core/handoff/store.js +32 -9
- package/dist/core/inference/text-inference.js +7 -15
- package/dist/core/message/im-renderer.js +90 -87
- package/dist/core/message/{inbound-admission.js → message-admission.js} +51 -1
- package/dist/core/message/message-bridge.js +184 -12
- package/dist/core/message/message-log.js +47 -7
- package/dist/core/message/message-queue.js +227 -16
- package/dist/core/message/message-utils.js +12 -5
- package/dist/core/message/response-engine.js +658 -109
- package/dist/core/message/send-receipt.js +1 -0
- package/dist/core/message/stream-debouncer.js +9 -2
- package/dist/core/model/model-catalog.js +23 -15
- package/dist/core/model/model-diagnostics.js +28 -10
- package/dist/core/permission/approval-gateway.js +180 -6
- package/dist/core/permission/ec-command-parser.js +627 -69
- package/dist/core/permission/mode.js +18 -3
- package/dist/core/{protected-paths.js → permission/protected-paths.js} +27 -14
- package/dist/core/permission/readonly-shell-query.js +263 -9
- package/dist/core/permission/sandbox-runtime.js +159 -1
- package/dist/core/permission/tool-error-code.js +12 -0
- package/dist/core/permission/tool-policy.js +618 -23
- package/dist/core/session/session-fs-store.js +154 -5
- package/dist/core/session/session-manager.js +329 -30
- package/dist/core/session/session-renew.js +37 -13
- package/dist/core/session/session-turn-coordinator.js +16 -5
- package/dist/eck/kit-renderer.js +1 -1
- package/dist/index.js +316 -50
- package/dist/ipc.js +459 -29
- package/dist/paths.js +82 -7
- package/dist/response-system/context-builder.js +1 -7
- package/dist/response-system/engines/v1/proactive-flow.js +7 -2
- package/dist/stats/price-resolver.js +4 -0
- package/dist/trigger/anomaly-store.js +1 -0
- package/dist/trigger/feedback.js +70 -7
- package/dist/trigger/history.js +79 -4
- package/dist/trigger/legacy-session-history.js +2 -2
- package/dist/trigger/parser.js +13 -3
- package/dist/trigger/scheduler.js +20 -3
- package/dist/trigger/validation.js +6 -1
- package/dist/utils/atomic-write.js +27 -0
- package/dist/utils/ecweb-utils.js +16 -2
- package/dist/utils/error-utils.js +4 -1
- package/dist/utils/logger.js +30 -6
- package/dist/utils/process-tree-stats.js +24 -4
- package/dist/utils/process-tree-worker.js +31 -0
- package/dist/utils/project-path.js +1 -2
- package/dist/utils/tool-summary.js +59 -0
- package/dist/utils/windows-shell-trust.js +201 -0
- package/kits/docs/INDEX.md +1 -1
- package/kits/docs/evolcore/INDEX.md +3 -3
- package/kits/docs/evolcore/agent-create.md +146 -0
- package/kits/docs/evolcore/agent.md +6 -0
- package/kits/docs/evolcore/contact.md +7 -1
- package/kits/docs/evolcore/group-collaboration.md +251 -0
- package/kits/docs/evolcore/group-rules.md +1 -19
- package/kits/docs/evolcore/group.md +3 -1
- package/kits/docs/evolcore/msg.md +16 -0
- package/kits/docs/evolcore/trigger.md +6 -3
- package/kits/docs/prompt-loading-architecture.md +6 -0
- package/kits/eck_message_manifest.json +6 -6
- package/kits/schemas/_meta.json +7 -4
- package/kits/schemas/agent-config.schema.11.json +13 -0
- package/kits/schemas/agent-config.schema.12.json +427 -0
- package/kits/schemas/daemon.schema.5.json +0 -1
- package/kits/schemas/daemon.schema.6.json +131 -0
- package/kits/schemas/defaults.schema.5.json +15 -3
- package/kits/schemas/migrations/README.md +3 -1
- package/kits/schemas/relation-config.schema.8.json +13 -0
- package/kits/schemas/role-config.schema.1.json +1 -2
- package/kits/schemas/single-session.schema.3.json +32 -0
- package/kits/templates/message-fragments/item.md +1 -1
- package/kits/templates/roles/admin.json +1 -0
- package/kits/templates/roles/member.json +1 -0
- package/kits/templates/roles/visitor.json +1 -0
- package/kits/templates/system-fragments/bootstrap.md +2 -1
- package/kits/templates/system-fragments/commands.md +2 -2
- package/package.json +6 -3
- package/skills/eclink/SKILL.md +2 -0
- package/dist/config/aun-gateway-config.js +0 -2
|
@@ -18,7 +18,7 @@ import { tryUpgrade, tryUpgradeGlobalPkg, resolveGlobalPkg } from '../utils/npm-
|
|
|
18
18
|
import { ecwebVersionRequirementError, fetchEcwebPairCode, resolveEcwebLaunchCommand } from '../utils/ecweb-utils.js';
|
|
19
19
|
import { isHostChinese } from '../utils/locale.js';
|
|
20
20
|
import { scanInstances, cleanupInstances, findOrphanProcesses, killOrphans } from '../utils/instance-registry.js';
|
|
21
|
-
import { filterLogFiles, deriveLogTypes, computePreChecked, validateLogTypes, shortLogName as shortLogNameLocal } from './watch-logs.js';
|
|
21
|
+
import { filterLogFiles, deriveLogTypes, computePreChecked, validateLogTypes, shortLogName as shortLogNameLocal, isWatchLogFile } from './watch-logs.js';
|
|
22
22
|
import { displaySessionTitle } from '../core/session/session-title.js';
|
|
23
23
|
import { isNonAgentSessionChannel } from '../core/system-channels.js';
|
|
24
24
|
import { printCodeStats } from './code-stats.js';
|
|
@@ -29,6 +29,7 @@ import { rotateStdoutLog } from '../utils/log-writer.js';
|
|
|
29
29
|
import { inspectDataMigrationRequirement } from '../core/data-migration.js';
|
|
30
30
|
import { isInitCancelledError, printInitCancelHint } from './init-cancel.js';
|
|
31
31
|
import { listCodexAppServerProcesses, unregisterCodexAppServerProcess } from '../utils/codex-app-server-registry.js';
|
|
32
|
+
import { DEFAULT_ECWEB_PORT, ecwebService, setEcwebEnabled } from '../config/daemon-services.js';
|
|
32
33
|
const execFileAsync = promisify(execFile);
|
|
33
34
|
async function runAutomaticInit(action) {
|
|
34
35
|
try {
|
|
@@ -146,11 +147,6 @@ function buildDaemonEnv(p, opts) {
|
|
|
146
147
|
...(opts.bindBootstrap ? { EVOLCORE_BIND_BOOTSTRAP: '1' } : {}),
|
|
147
148
|
};
|
|
148
149
|
}
|
|
149
|
-
export function serviceProxyNeedsEcweb(cfg) {
|
|
150
|
-
if (!cfg.serviceProxy?.enabled)
|
|
151
|
-
return false;
|
|
152
|
-
return (cfg.serviceProxy.services ?? []).some(s => s.enabled !== false && s.source === 'ecweb');
|
|
153
|
-
}
|
|
154
150
|
function latestSourceMtime(dir) {
|
|
155
151
|
let latest = 0;
|
|
156
152
|
try {
|
|
@@ -178,14 +174,35 @@ function sourceBuildNeedsRefresh() {
|
|
|
178
174
|
const sourceMtime = Math.max(latestSourceMtime(path.join(packageRoot, 'src')), latestSourceMtime(path.join(packageRoot, 'ecagent', 'src')));
|
|
179
175
|
return sourceMtime > fs.statSync(daemonEntry).mtimeMs;
|
|
180
176
|
}
|
|
181
|
-
function
|
|
177
|
+
function runSourceBuild() {
|
|
178
|
+
return new Promise(resolve => {
|
|
179
|
+
console.log('🔧 源码比 daemon 编译产物更新,自动重新构建...');
|
|
180
|
+
const child = spawn(platform.isWindows ? 'npm.cmd' : 'npm', ['run', 'build'], {
|
|
181
|
+
cwd: getPackageRoot(),
|
|
182
|
+
stdio: 'inherit',
|
|
183
|
+
shell: platform.isWindows,
|
|
184
|
+
});
|
|
185
|
+
child.on('error', err => {
|
|
186
|
+
console.error(`❌ 无法启动构建进程: ${err.message}`);
|
|
187
|
+
resolve(false);
|
|
188
|
+
});
|
|
189
|
+
child.on('exit', code => {
|
|
190
|
+
if (code === 0) {
|
|
191
|
+
console.log('✅ 构建完成');
|
|
192
|
+
resolve(true);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
console.error(`❌ 自动构建失败 (exit ${code}),服务未启动。`);
|
|
196
|
+
console.error(' 请手动执行: npm run build 排查错误');
|
|
197
|
+
resolve(false);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
async function requireFreshSourceBuild() {
|
|
182
203
|
if (!sourceBuildNeedsRefresh())
|
|
183
204
|
return true;
|
|
184
|
-
|
|
185
|
-
console.error(' 请先执行: ec stop && npm run build');
|
|
186
|
-
console.error(' 然后执行: ec start');
|
|
187
|
-
process.exitCode = 2;
|
|
188
|
-
return false;
|
|
205
|
+
return await runSourceBuild();
|
|
189
206
|
}
|
|
190
207
|
function requireCompletedDataMigration(root) {
|
|
191
208
|
const requirement = inspectDataMigrationRequirement(root);
|
|
@@ -310,7 +327,7 @@ export async function cmdStart(opts = {}) {
|
|
|
310
327
|
return;
|
|
311
328
|
}
|
|
312
329
|
ensureDataDirs();
|
|
313
|
-
if (!requireFreshSourceBuild())
|
|
330
|
+
if (!await requireFreshSourceBuild())
|
|
314
331
|
return;
|
|
315
332
|
// 旧配置自动迁移(daemon.json → 新结构)
|
|
316
333
|
const { autoMigrateIfNeeded } = await import('../config-store.js');
|
|
@@ -437,8 +454,6 @@ export async function cmdStart(opts = {}) {
|
|
|
437
454
|
console.log(` Rotated: stdout.log -> ${path.basename(stdoutRotation.rotatedPath)}`);
|
|
438
455
|
}
|
|
439
456
|
cleanEnv();
|
|
440
|
-
// 在启动前确保 serviceProxy 配置完整(如果 ecweb 启用但 serviceProxy 未配置)
|
|
441
|
-
ensureServiceProxyConfigBeforeStart(p);
|
|
442
457
|
// 删除旧的 ready signal
|
|
443
458
|
try {
|
|
444
459
|
fs.unlinkSync(p.readySignal);
|
|
@@ -567,7 +582,7 @@ export async function cmdStart(opts = {}) {
|
|
|
567
582
|
}
|
|
568
583
|
console.log('');
|
|
569
584
|
// 代码统计仅在开发环境显示(EVOLCORE_HOME 指向包目录)
|
|
570
|
-
if (resolveRoot() === getPackageRoot()) {
|
|
585
|
+
if (path.normalize(resolveRoot()) === path.normalize(getPackageRoot())) {
|
|
571
586
|
printCodeStats(getPackageRoot(), p.logs);
|
|
572
587
|
}
|
|
573
588
|
console.log(`⏱ done in ${((Date.now() - cmdStartedAt) / 1000).toFixed(1)}s`);
|
|
@@ -687,7 +702,7 @@ export async function cmdRestart(opts = {}) {
|
|
|
687
702
|
if (initialRuntimeOrphans.length === 0 && rejectPidIsolatedLifecycle('restart', initialStatus, ping))
|
|
688
703
|
return;
|
|
689
704
|
}
|
|
690
|
-
if (!requireFreshSourceBuild())
|
|
705
|
+
if (!await requireFreshSourceBuild())
|
|
691
706
|
return;
|
|
692
707
|
// 版本检查与自动升级
|
|
693
708
|
console.log('📦 Checking for updates...');
|
|
@@ -808,7 +823,7 @@ export async function cmdRestart(opts = {}) {
|
|
|
808
823
|
console.log('🔄 Restart monitor started, waiting for service to come back online...');
|
|
809
824
|
await sleep(2000);
|
|
810
825
|
// 代码统计(开发环境)
|
|
811
|
-
if (resolveRoot() === getPackageRoot()) {
|
|
826
|
+
if (path.normalize(resolveRoot()) === path.normalize(getPackageRoot())) {
|
|
812
827
|
console.log('');
|
|
813
828
|
printCodeStats(getPackageRoot(), resolvePaths().logs);
|
|
814
829
|
}
|
|
@@ -975,7 +990,17 @@ export async function cmdStatus() {
|
|
|
975
990
|
const p = resolvePaths();
|
|
976
991
|
const status = scanInstances();
|
|
977
992
|
const aliveMains = status.mains.filter(m => m.alive);
|
|
978
|
-
|
|
993
|
+
// Start all read-only daemon queries together. On a busy Windows host each
|
|
994
|
+
// query can otherwise wait behind the same IPC/event-loop delay and make the
|
|
995
|
+
// total `ec status` time the sum of several individual timeouts.
|
|
996
|
+
const pingPromise = probeDaemon(p.socket).catch(() => null);
|
|
997
|
+
const statusPromise = ipcQuery(p.socket, { type: 'status' }).catch(() => null);
|
|
998
|
+
const aidsPromise = ipcQuery(p.socket, { type: 'aun-aids' }).catch(() => null);
|
|
999
|
+
const agentsPromise = ipcQuery(p.socket, { type: 'evolagent.list' }).catch(() => null);
|
|
1000
|
+
// Only the ping is needed to decide whether to show the live-daemon
|
|
1001
|
+
// sections. The remaining responses continue in parallel while local
|
|
1002
|
+
// process/session information is rendered.
|
|
1003
|
+
const ping = await pingPromise;
|
|
979
1004
|
const pid = ping?.pid ?? (aliveMains.length > 0 ? aliveMains[0].record.pid : null);
|
|
980
1005
|
const processVisible = !!pid && aliveMains.some(entry => entry.record.pid === pid);
|
|
981
1006
|
if (aliveMains.length > 1) {
|
|
@@ -1131,42 +1156,47 @@ export async function cmdStatus() {
|
|
|
1131
1156
|
}
|
|
1132
1157
|
// Channel status. A running daemon is authoritative and avoids reading
|
|
1133
1158
|
// protected config files from the CLI's potentially sandboxed process.
|
|
1159
|
+
let agentsResponse = null;
|
|
1134
1160
|
if (pid) {
|
|
1135
1161
|
console.log('');
|
|
1136
|
-
const
|
|
1137
|
-
|
|
1162
|
+
const [statusResponse, aidsResponse, agentResponse] = await Promise.all([
|
|
1163
|
+
statusPromise,
|
|
1164
|
+
aidsPromise,
|
|
1165
|
+
agentsPromise,
|
|
1166
|
+
]);
|
|
1167
|
+
agentsResponse = agentResponse;
|
|
1168
|
+
if (statusResponse) {
|
|
1138
1169
|
// 🔑 AUN AIDs 表格(详细 AUN 实例状态)
|
|
1139
1170
|
try {
|
|
1140
|
-
|
|
1141
|
-
if (aidsResp?.ok && aidsResp.aids?.length > 0) {
|
|
1171
|
+
if (aidsResponse?.ok && aidsResponse.aids?.length > 0) {
|
|
1142
1172
|
console.log('🔑 AUN AIDs:');
|
|
1143
|
-
renderAunAidsTable(
|
|
1173
|
+
renderAunAidsTable(aidsResponse.aids);
|
|
1144
1174
|
}
|
|
1145
1175
|
}
|
|
1146
1176
|
catch { /* ignore */ }
|
|
1147
1177
|
// 控制 AID(daemon 进程身份)状态
|
|
1148
|
-
if (
|
|
1149
|
-
const state =
|
|
1150
|
-
console.log(`control: ${
|
|
1178
|
+
if (statusResponse.controlAid) {
|
|
1179
|
+
const state = statusResponse.controlAid.connected ? 'connected' : 'disconnected';
|
|
1180
|
+
console.log(`control: ${statusResponse.controlAid.aid} [${state}]`);
|
|
1151
1181
|
}
|
|
1152
1182
|
else {
|
|
1153
1183
|
console.log('control: not configured');
|
|
1154
1184
|
}
|
|
1155
|
-
if (
|
|
1185
|
+
if (statusResponse.stats) {
|
|
1156
1186
|
console.log('');
|
|
1157
1187
|
console.log('📊 Last hour:');
|
|
1158
|
-
console.log(` Messages: ${
|
|
1159
|
-
if (
|
|
1160
|
-
console.log(` Errors: ${
|
|
1161
|
-
if (
|
|
1162
|
-
console.log(` Avg response: ${(
|
|
1188
|
+
console.log(` Messages: ${statusResponse.stats.received} received, ${statusResponse.stats.completed} completed`);
|
|
1189
|
+
if (statusResponse.stats.errors > 0)
|
|
1190
|
+
console.log(` Errors: ${statusResponse.stats.errors}`);
|
|
1191
|
+
if (statusResponse.stats.completed > 0)
|
|
1192
|
+
console.log(` Avg response: ${(statusResponse.stats.avgResponseMs / 1000).toFixed(1)}s`);
|
|
1163
1193
|
}
|
|
1164
1194
|
}
|
|
1165
1195
|
else {
|
|
1166
1196
|
// IPC unreachable but PID exists — fall back to local config if readable.
|
|
1167
1197
|
const config = readStatusDefaultsConfig(p.defaultsConfig);
|
|
1168
1198
|
if (config) {
|
|
1169
|
-
console.log('🔌 Channels (
|
|
1199
|
+
console.log('🔌 Channels (live status unavailable; configuration is stale):');
|
|
1170
1200
|
showConfigChannels(config);
|
|
1171
1201
|
}
|
|
1172
1202
|
}
|
|
@@ -1182,7 +1212,7 @@ export async function cmdStatus() {
|
|
|
1182
1212
|
// EvolAgent summary (via IPC, only when running)
|
|
1183
1213
|
if (pid) {
|
|
1184
1214
|
try {
|
|
1185
|
-
const agentResult =
|
|
1215
|
+
const agentResult = agentsResponse;
|
|
1186
1216
|
if (agentResult?.ok && agentResult.agents?.length > 0) {
|
|
1187
1217
|
const agents = agentResult.agents;
|
|
1188
1218
|
if (agents.length > 0) {
|
|
@@ -1196,6 +1226,22 @@ export async function cmdStatus() {
|
|
|
1196
1226
|
}
|
|
1197
1227
|
}
|
|
1198
1228
|
}
|
|
1229
|
+
else {
|
|
1230
|
+
const { EvolAgentRegistry } = await import('../core/evolagent-registry.js');
|
|
1231
|
+
const diskRegistry = new EvolAgentRegistry(p.agentsDir);
|
|
1232
|
+
diskRegistry.loadAll();
|
|
1233
|
+
const agents = diskRegistry.list();
|
|
1234
|
+
if (agents.length > 0) {
|
|
1235
|
+
console.log('');
|
|
1236
|
+
console.log('🤖 EvolAgents (live status unavailable; stale configuration):');
|
|
1237
|
+
for (const a of agents) {
|
|
1238
|
+
const diskStatus = a.status === 'disabled' || a.status === 'error' ? a.status : 'unknown';
|
|
1239
|
+
const channels = summarizeChannelFingerprints(a.channels || []);
|
|
1240
|
+
const shortName = a.name.replace(/\.agentid\.pub$/, '');
|
|
1241
|
+
console.log(` ? ${shortName.padEnd(20)} ${`${diskStatus} (stale)`.padEnd(18)} ${channels}`);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1199
1245
|
}
|
|
1200
1246
|
catch {
|
|
1201
1247
|
// IPC query for agents failed — skip section
|
|
@@ -1789,10 +1835,10 @@ async function cmdWatchLogsFlow() {
|
|
|
1789
1835
|
console.log(`❌ Log directory not found: ${p.logs}`);
|
|
1790
1836
|
process.exit(1);
|
|
1791
1837
|
}
|
|
1792
|
-
const files = fs.readdirSync(p.logs).filter(
|
|
1838
|
+
const files = fs.readdirSync(p.logs).filter(isWatchLogFile);
|
|
1793
1839
|
const types = deriveLogTypes(files);
|
|
1794
1840
|
if (types.length === 0) {
|
|
1795
|
-
console.log(`⚠ ${p.logs}
|
|
1841
|
+
console.log(`⚠ ${p.logs} 下暂无可监听日志文件`);
|
|
1796
1842
|
return;
|
|
1797
1843
|
}
|
|
1798
1844
|
const fileCount = new Map();
|
|
@@ -1863,7 +1909,7 @@ function cmdWatch(filterTypes) {
|
|
|
1863
1909
|
return c;
|
|
1864
1910
|
};
|
|
1865
1911
|
const listLogs = () => {
|
|
1866
|
-
const all = fs.readdirSync(p.logs).filter(
|
|
1912
|
+
const all = fs.readdirSync(p.logs).filter(isWatchLogFile).map(f => path.join(p.logs, f));
|
|
1867
1913
|
return filterLogFiles(all, filterTypes);
|
|
1868
1914
|
};
|
|
1869
1915
|
const shortName = shortLogNameLocal;
|
|
@@ -1885,7 +1931,7 @@ function cmdWatch(filterTypes) {
|
|
|
1885
1931
|
const content = formatWatchContent(line);
|
|
1886
1932
|
return `${timeStr} ${paddedName} ${content}`;
|
|
1887
1933
|
};
|
|
1888
|
-
console.log(`🔭 Watching ${p.logs}
|
|
1934
|
+
console.log(`🔭 Watching ${p.logs}/* log files (ESC to stop)\n`);
|
|
1889
1935
|
// 显示当前实例信息和 AID 状态
|
|
1890
1936
|
const instStatus = scanInstances();
|
|
1891
1937
|
const aliveMainEntries = instStatus.mains.filter(m => m.alive);
|
|
@@ -2508,9 +2554,9 @@ async function waitForExistingEcweb(p, timeoutMs = 3_000) {
|
|
|
2508
2554
|
async function printEcwebStatus(p) {
|
|
2509
2555
|
try {
|
|
2510
2556
|
const cfg = loadDaemonConfig();
|
|
2511
|
-
if (cfg.
|
|
2557
|
+
if (ecwebService(cfg.services)?.enabled === false) {
|
|
2512
2558
|
console.log('');
|
|
2513
|
-
console.log('🔭 ECWeb: 已禁用 (daemon.json → ecweb.enabled: false)');
|
|
2559
|
+
console.log('🔭 ECWeb: 已禁用 (daemon.json → services[name=ecweb].enabled: false)');
|
|
2514
2560
|
return;
|
|
2515
2561
|
}
|
|
2516
2562
|
}
|
|
@@ -2608,7 +2654,7 @@ export function stopCodexAppServerOrphans() {
|
|
|
2608
2654
|
/** 若 ecweb 在运行则杀掉并确认 pid/端口都已释放。 */
|
|
2609
2655
|
async function stopEcwebIfRunning(p) {
|
|
2610
2656
|
const alive = findAliveEcweb(p);
|
|
2611
|
-
const port = loadDaemonConfig().
|
|
2657
|
+
const port = ecwebService(loadDaemonConfig().services)?.port ?? DEFAULT_ECWEB_PORT;
|
|
2612
2658
|
const pids = new Set([
|
|
2613
2659
|
...(alive ? [alive.pid] : []),
|
|
2614
2660
|
...platform.findProcessByPort(port),
|
|
@@ -2634,78 +2680,6 @@ async function waitForPortRelease(port, timeoutMs) {
|
|
|
2634
2680
|
}
|
|
2635
2681
|
return platform.findProcessByPort(port).length === 0;
|
|
2636
2682
|
}
|
|
2637
|
-
/**
|
|
2638
|
-
* 后台 detached 启动 ecweb;若已运行则先停再启(确保加载最新代码)。
|
|
2639
|
-
* 启动后轮询端口确认 HTTP 服务真正就绪,打印明确的成功/失败结论(而非模糊的「已在后台启动」状态描述)。
|
|
2640
|
-
* 返回 true=本次确实启动成功,false=未启用/未安装/启动失败。
|
|
2641
|
-
*/
|
|
2642
|
-
/**
|
|
2643
|
-
* 启动前检查并补全 serviceProxy 配置(如果 ecweb 启用但 serviceProxy 未配置)
|
|
2644
|
-
*/
|
|
2645
|
-
function ensureServiceProxyConfigBeforeStart(p) {
|
|
2646
|
-
const cfg = loadDaemonConfig();
|
|
2647
|
-
// 仅在 ecweb 启用 + 控制 AID 已配置 + serviceProxy 未配置 ecweb 时自动添加
|
|
2648
|
-
if (!cfg.ecweb?.enabled || !cfg.aid)
|
|
2649
|
-
return;
|
|
2650
|
-
const hasEcwebService = (cfg.serviceProxy?.services ?? []).some(s => s.name === 'ecweb' || s.source === 'ecweb');
|
|
2651
|
-
if (!hasEcwebService) {
|
|
2652
|
-
const updatedCfg = {
|
|
2653
|
-
...cfg,
|
|
2654
|
-
serviceProxy: {
|
|
2655
|
-
enabled: true,
|
|
2656
|
-
...(cfg.serviceProxy ?? {}),
|
|
2657
|
-
services: [
|
|
2658
|
-
...(cfg.serviceProxy?.services ?? []),
|
|
2659
|
-
{
|
|
2660
|
-
name: 'ecweb',
|
|
2661
|
-
source: 'ecweb',
|
|
2662
|
-
serviceType: 'http',
|
|
2663
|
-
visibility: 'public',
|
|
2664
|
-
enabled: true,
|
|
2665
|
-
metadata: {
|
|
2666
|
-
label: 'EvolCore Dashboard',
|
|
2667
|
-
},
|
|
2668
|
-
},
|
|
2669
|
-
],
|
|
2670
|
-
},
|
|
2671
|
-
};
|
|
2672
|
-
saveDaemonConfig(updatedCfg);
|
|
2673
|
-
console.log(`✓ 自动配置 Service Proxy: https://${cfg.aid}/proxy/ecweb/`);
|
|
2674
|
-
}
|
|
2675
|
-
}
|
|
2676
|
-
/**
|
|
2677
|
-
* 确保 serviceProxy 配置包含 ecweb 服务(ECWeb 启动成功后自动配置)
|
|
2678
|
-
*/
|
|
2679
|
-
function ensureServiceProxyConfig(cfg, port) {
|
|
2680
|
-
// 仅在控制 AID 已配置时自动添加 serviceProxy
|
|
2681
|
-
if (!cfg.aid)
|
|
2682
|
-
return;
|
|
2683
|
-
const hasEcwebService = (cfg.serviceProxy?.services ?? []).some(s => s.name === 'ecweb' || s.source === 'ecweb');
|
|
2684
|
-
if (!hasEcwebService) {
|
|
2685
|
-
const updatedCfg = {
|
|
2686
|
-
...cfg,
|
|
2687
|
-
serviceProxy: {
|
|
2688
|
-
enabled: true,
|
|
2689
|
-
...(cfg.serviceProxy ?? {}),
|
|
2690
|
-
services: [
|
|
2691
|
-
...(cfg.serviceProxy?.services ?? []),
|
|
2692
|
-
{
|
|
2693
|
-
name: 'ecweb',
|
|
2694
|
-
source: 'ecweb',
|
|
2695
|
-
serviceType: 'http',
|
|
2696
|
-
visibility: 'public',
|
|
2697
|
-
enabled: true,
|
|
2698
|
-
metadata: {
|
|
2699
|
-
label: 'EvolCore Dashboard',
|
|
2700
|
-
},
|
|
2701
|
-
},
|
|
2702
|
-
],
|
|
2703
|
-
},
|
|
2704
|
-
};
|
|
2705
|
-
saveDaemonConfig(updatedCfg);
|
|
2706
|
-
console.log(` 自动配置 Service Proxy: https://${cfg.aid}/proxy/ecweb/`);
|
|
2707
|
-
}
|
|
2708
|
-
}
|
|
2709
2683
|
/**
|
|
2710
2684
|
* Start the separately installed `ec-web` process for a configured runtime.
|
|
2711
2685
|
* Kept public for restart-monitor, which launches the daemon directly and
|
|
@@ -2713,7 +2687,8 @@ function ensureServiceProxyConfig(cfg, port) {
|
|
|
2713
2687
|
*/
|
|
2714
2688
|
export async function startEcwebIfEnabled(p, options = {}) {
|
|
2715
2689
|
const cfg = loadDaemonConfig();
|
|
2716
|
-
|
|
2690
|
+
const service = ecwebService(cfg.services);
|
|
2691
|
+
if (!service?.enabled)
|
|
2717
2692
|
return false;
|
|
2718
2693
|
// The daemon is the lifecycle owner. CLI callers normally only need to
|
|
2719
2694
|
// ensure ECWeb is available, so adopt a healthy process instead of killing
|
|
@@ -2750,7 +2725,7 @@ export async function startEcwebIfEnabled(p, options = {}) {
|
|
|
2750
2725
|
console.log(`❌ EC Web 旧进程未清理干净,取消启动: ${error instanceof Error ? error.message : String(error)}`);
|
|
2751
2726
|
return false;
|
|
2752
2727
|
}
|
|
2753
|
-
const port =
|
|
2728
|
+
const port = service.port ?? DEFAULT_ECWEB_PORT;
|
|
2754
2729
|
const args = ['--home', p.root, '--port', String(port)];
|
|
2755
2730
|
const launch = resolveEcwebLaunchCommand(args, { installedPkg });
|
|
2756
2731
|
if (!launch) {
|
|
@@ -2880,10 +2855,9 @@ async function cmdWatchWeb() {
|
|
|
2880
2855
|
}
|
|
2881
2856
|
// 2. 启动(后台)并同步配置。默认行为是替换旧实例,确保新配置/新版静态资源生效。
|
|
2882
2857
|
const cfg = loadDaemonConfig();
|
|
2883
|
-
const
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
ensureServiceProxyConfigBeforeStart(p);
|
|
2858
|
+
const currentService = ecwebService(cfg.services);
|
|
2859
|
+
const port = currentService?.port ?? DEFAULT_ECWEB_PORT;
|
|
2860
|
+
saveDaemonConfig({ ...cfg, services: setEcwebEnabled(cfg.services, true, port) });
|
|
2887
2861
|
const ok = await startEcwebIfEnabled(p, { forceRestart: true });
|
|
2888
2862
|
if (!ok)
|
|
2889
2863
|
process.exit(1); // 失败原因已由 startEcwebIfEnabled 打印
|
|
@@ -3011,8 +2985,9 @@ export async function cmdDiagnose() {
|
|
|
3011
2985
|
// 6. 检查 EC Web 端口与实例记录是否一致。
|
|
3012
2986
|
try {
|
|
3013
2987
|
const cfg = loadDaemonConfig();
|
|
3014
|
-
|
|
3015
|
-
|
|
2988
|
+
const service = ecwebService(cfg.services);
|
|
2989
|
+
if (service?.enabled) {
|
|
2990
|
+
const port = service.port ?? DEFAULT_ECWEB_PORT;
|
|
3016
2991
|
const portPids = platform.findProcessByPort(port);
|
|
3017
2992
|
const recordedPids = new Set(readEcwebInstanceEntries(p).map(entry => entry.record.pid));
|
|
3018
2993
|
const unregisteredPids = portPids.filter(pid => !recordedPids.has(pid));
|
|
@@ -3083,7 +3058,7 @@ export async function cmdWatchCommand(args) {
|
|
|
3083
3058
|
if (requested.length > 0) {
|
|
3084
3059
|
const p2 = resolvePaths();
|
|
3085
3060
|
const avail = fs.existsSync(p2.logs)
|
|
3086
|
-
? deriveLogTypes(fs.readdirSync(p2.logs).filter(
|
|
3061
|
+
? deriveLogTypes(fs.readdirSync(p2.logs).filter(isWatchLogFile))
|
|
3087
3062
|
: [];
|
|
3088
3063
|
const invalid = validateLogTypes(requested, avail);
|
|
3089
3064
|
if (invalid.length > 0) {
|
package/dist/cli/init.js
CHANGED
|
@@ -6,6 +6,7 @@ import { resolvePaths, ensureDataDirs } from '../paths.js';
|
|
|
6
6
|
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
|
+
import { ecwebService, setEcwebEnabled } from '../config/daemon-services.js';
|
|
9
10
|
import { generateControlAid, resolveControlAidDomain } from '../aun/aid/control-aid.js';
|
|
10
11
|
import { getCodexAppServerAvailability } from '../agents/codex-runner.js';
|
|
11
12
|
import { DEFAULT_ECAGENT_BASE_URL, resolveEcagentConfig } from '../agents/baseagent.js';
|
|
@@ -421,6 +422,12 @@ export async function cmdInit(options) {
|
|
|
421
422
|
const lower = normalized.toLowerCase();
|
|
422
423
|
return !lower.includes('your-') && !lower.includes('placeholder');
|
|
423
424
|
};
|
|
425
|
+
const configuredBaseUrl = [
|
|
426
|
+
configured?.baseUrl,
|
|
427
|
+
process.env.ECAGENT_BASE_URL,
|
|
428
|
+
DEFAULT_ECAGENT_BASE_URL,
|
|
429
|
+
].find(usable) || DEFAULT_ECAGENT_BASE_URL;
|
|
430
|
+
const baseUrl = (await ask(rl, `ecagent Base URL [${configuredBaseUrl}]: `)).trim() || configuredBaseUrl;
|
|
424
431
|
const configuredApiKey = usable(configured?.apiKey) ? configured.apiKey.trim() : undefined;
|
|
425
432
|
const environmentApiKeyName = !configuredApiKey
|
|
426
433
|
? (usable(process.env.ECAGENT_API_KEY)
|
|
@@ -435,12 +442,6 @@ export async function cmdInit(options) {
|
|
|
435
442
|
if (!apiKey)
|
|
436
443
|
console.log(' API Key 不能为空,请重新输入');
|
|
437
444
|
}
|
|
438
|
-
const configuredBaseUrl = [
|
|
439
|
-
configured?.baseUrl,
|
|
440
|
-
process.env.ECAGENT_BASE_URL,
|
|
441
|
-
DEFAULT_ECAGENT_BASE_URL,
|
|
442
|
-
].find(usable) || DEFAULT_ECAGENT_BASE_URL;
|
|
443
|
-
const baseUrl = (await ask(rl, `ecagent Base URL [${configuredBaseUrl}]: `)).trim() || configuredBaseUrl;
|
|
444
445
|
return { apiKey, baseUrl };
|
|
445
446
|
}
|
|
446
447
|
try {
|
|
@@ -618,25 +619,34 @@ export async function initTail(options = {}) {
|
|
|
618
619
|
}
|
|
619
620
|
async function handleEcwebPrompt(rl) {
|
|
620
621
|
const daemonConfigForEcweb = loadDaemonConfig();
|
|
621
|
-
if (daemonConfigForEcweb.
|
|
622
|
+
if (ecwebService(daemonConfigForEcweb.services)?.enabled === undefined) {
|
|
622
623
|
const ans = (await ask(rl, '\n是否在 ec start 时自动启动 ECWeb 控制台?[y/N] ')).trim().toLowerCase();
|
|
623
624
|
if (ans === 'y' || ans === 'yes') {
|
|
624
625
|
const installResult = await ensureEcwebInstalledForInit();
|
|
625
626
|
if (installResult.ok) {
|
|
626
627
|
const cfg = loadDaemonConfig();
|
|
627
|
-
saveDaemonConfig({
|
|
628
|
+
saveDaemonConfig({
|
|
629
|
+
...cfg,
|
|
630
|
+
services: setEcwebEnabled(cfg.services, true),
|
|
631
|
+
});
|
|
628
632
|
console.log(' ✓ 已启用 ECWeb(ec start 将自动在后台启动)');
|
|
629
633
|
console.log(' 提示:首次访问运行 ec watch web 查看配对码和 URL');
|
|
630
634
|
}
|
|
631
635
|
else {
|
|
632
636
|
const cfg = loadDaemonConfig();
|
|
633
|
-
saveDaemonConfig({
|
|
637
|
+
saveDaemonConfig({
|
|
638
|
+
...cfg,
|
|
639
|
+
services: setEcwebEnabled(cfg.services, false),
|
|
640
|
+
});
|
|
634
641
|
console.log(' 提示:安装完成后运行 ec start;如需立即打开控制台,运行 ec watch web');
|
|
635
642
|
}
|
|
636
643
|
}
|
|
637
644
|
else {
|
|
638
645
|
const cfg = loadDaemonConfig();
|
|
639
|
-
saveDaemonConfig({
|
|
646
|
+
saveDaemonConfig({
|
|
647
|
+
...cfg,
|
|
648
|
+
services: setEcwebEnabled(cfg.services, false),
|
|
649
|
+
});
|
|
640
650
|
console.log(' 已跳过(可日后运行 ec watch web 手动启动,或编辑 daemon.json)');
|
|
641
651
|
}
|
|
642
652
|
}
|
|
@@ -658,7 +668,7 @@ export async function initTail(options = {}) {
|
|
|
658
668
|
const finalCfg = loadDaemonConfig();
|
|
659
669
|
console.log(` 控制 AID: ${finalCfg.aid || '(未配置)'}`);
|
|
660
670
|
console.log(` 管理者: ${finalCfg.owners?.join(', ') || '(未配置)'}`);
|
|
661
|
-
console.log(` ECWeb 自启动: ${finalCfg.
|
|
671
|
+
console.log(` ECWeb 自启动: ${ecwebService(finalCfg.services)?.enabled ? '已启用' : '已禁用'}`);
|
|
662
672
|
const { agents: finalAgents } = loadAllAgents();
|
|
663
673
|
if (finalAgents.length === 0) {
|
|
664
674
|
console.log('\n📌 下一步:创建 agent');
|
|
@@ -826,11 +836,11 @@ export async function cmdInitNonInteractive(opts, dependencies = {}) {
|
|
|
826
836
|
const ensureEcweb = dependencies.ensureEcweb ?? (() => ensureEcwebInstalledForInit({ quiet: true }));
|
|
827
837
|
const installResult = await ensureEcweb();
|
|
828
838
|
if (!installResult.ok) {
|
|
829
|
-
if (existingCfg.
|
|
839
|
+
if (ecwebService(existingCfg.services)?.enabled === true) {
|
|
830
840
|
try {
|
|
831
841
|
saveDaemonConfig({
|
|
832
842
|
...existingCfg,
|
|
833
|
-
|
|
843
|
+
services: setEcwebEnabled(existingCfg.services, false),
|
|
834
844
|
});
|
|
835
845
|
}
|
|
836
846
|
catch (e) {
|
|
@@ -866,7 +876,9 @@ export async function cmdInitNonInteractive(opts, dependencies = {}) {
|
|
|
866
876
|
$schema_version: existingCfg.$schema_version ?? 1,
|
|
867
877
|
aid: controlAid,
|
|
868
878
|
owners: [ownerAid],
|
|
869
|
-
...(opts.ecweb === true
|
|
879
|
+
...(opts.ecweb === true
|
|
880
|
+
? { services: setEcwebEnabled(existingCfg.services, true) }
|
|
881
|
+
: {}),
|
|
870
882
|
};
|
|
871
883
|
saveDaemonConfig(next);
|
|
872
884
|
}
|
|
@@ -894,7 +906,7 @@ export async function cmdInitNonInteractive(opts, dependencies = {}) {
|
|
|
894
906
|
controlAid: controlAid,
|
|
895
907
|
ownerAid,
|
|
896
908
|
owners: [ownerAid],
|
|
897
|
-
ecwebEnabled: opts.ecweb === true || existingCfg.
|
|
909
|
+
ecwebEnabled: opts.ecweb === true || ecwebService(existingCfg.services)?.enabled === true,
|
|
898
910
|
baseagent: chosenBaseagent,
|
|
899
911
|
projectsDefaultPath: projectsDefaultPath ?? null,
|
|
900
912
|
defaultsPath: p.defaultsConfig,
|
package/dist/cli/task-context.js
CHANGED
|
@@ -6,6 +6,7 @@ import os from 'node:os';
|
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
export const TASK_RUNTIME_CONTEXT_ENV = 'EVOLCORE_TASK_RUNTIME_CONTEXT';
|
|
8
8
|
export const SESSION_RUNTIME_DIR_ENV = 'EVOLCORE_SESSION_RUNTIME_DIR';
|
|
9
|
+
export const DAEMON_RUNTIME_EPOCH_ENV = 'EVOLCORE_DAEMON_RUNTIME_EPOCH';
|
|
9
10
|
export { RUNTIME_LOCK_DIR_ENV };
|
|
10
11
|
const generatedProcessManagedTempDirs = new Set();
|
|
11
12
|
let processTempCleanupRegistered = false;
|
|
@@ -32,6 +33,13 @@ function normalizeTaskRuntimeContext(value) {
|
|
|
32
33
|
peerName: optionalString(value.peerName),
|
|
33
34
|
peerType: optionalString(value.peerType),
|
|
34
35
|
peerRole: optionalString(value.peerRole),
|
|
36
|
+
permissionMode: optionalString(value.permissionMode),
|
|
37
|
+
processRole: optionalProcessRole(value.processRole),
|
|
38
|
+
dataScope: optionalDataScope(value.dataScope),
|
|
39
|
+
authorizedBy: optionalString(value.authorizedBy),
|
|
40
|
+
executionSource: value.executionSource === 'fullaccess-command' || value.executionSource === 'trigger'
|
|
41
|
+
? value.executionSource : undefined,
|
|
42
|
+
daemonRuntimeEpoch: optionalString(value.daemonRuntimeEpoch),
|
|
35
43
|
threadId: optionalString(value.threadId),
|
|
36
44
|
sessionRuntimeDir: optionalAbsolutePath(value.sessionRuntimeDir),
|
|
37
45
|
runtimeLockDir: optionalAbsolutePath(value.runtimeLockDir),
|
|
@@ -39,6 +47,13 @@ function normalizeTaskRuntimeContext(value) {
|
|
|
39
47
|
causation: normalizeCausation(value.causation),
|
|
40
48
|
};
|
|
41
49
|
}
|
|
50
|
+
function optionalProcessRole(value) {
|
|
51
|
+
return value === 'daemon-owner' || value === 'daemon-service' || value === 'fullaccess-run' || value === 'none'
|
|
52
|
+
? value : undefined;
|
|
53
|
+
}
|
|
54
|
+
function optionalDataScope(value) {
|
|
55
|
+
return value === 'relation' || value === 'agent' || value === 'daemon' ? value : undefined;
|
|
56
|
+
}
|
|
42
57
|
/**
|
|
43
58
|
* Codex's shell carrier can leave one JSON-style escape layer in a message
|
|
44
59
|
* argument (for example, the two characters `\\` and `n`). Decode only that
|
|
@@ -198,6 +213,40 @@ export function isManagedSessionRuntimeDir(directory, managedRoot) {
|
|
|
198
213
|
return false;
|
|
199
214
|
return isPrivateDirectory(root) && isPrivateDirectory(resolved);
|
|
200
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Resolve the session-owned temporary root for a managed child process.
|
|
218
|
+
*
|
|
219
|
+
* A direct runner call without task context is intentionally left alone for
|
|
220
|
+
* backwards-compatible tests and low-level integrations. Once the daemon has
|
|
221
|
+
* injected the task-context marker, however, falling back to the daemon's
|
|
222
|
+
* process-wide TMPDIR would break session isolation. Require the injected
|
|
223
|
+
* value to be present, identical to TMPDIR, and still owned by a trusted
|
|
224
|
+
* managed namespace before any runner-side helper writes a file.
|
|
225
|
+
*/
|
|
226
|
+
export function getManagedTaskTempDir(runtimeEnv) {
|
|
227
|
+
if (typeof runtimeEnv?.[TASK_RUNTIME_CONTEXT_ENV] !== 'string')
|
|
228
|
+
return undefined;
|
|
229
|
+
const configured = runtimeEnv[SESSION_RUNTIME_DIR_ENV]?.trim();
|
|
230
|
+
const inherited = runtimeEnv.TMPDIR?.trim();
|
|
231
|
+
const context = parseTaskRuntimeContext(runtimeEnv[TASK_RUNTIME_CONTEXT_ENV]);
|
|
232
|
+
const contextDir = context?.sessionRuntimeDir;
|
|
233
|
+
const processRoot = process.env.TMPDIR?.trim();
|
|
234
|
+
const trusted = configured
|
|
235
|
+
&& inherited
|
|
236
|
+
&& path.isAbsolute(configured)
|
|
237
|
+
&& path.isAbsolute(inherited)
|
|
238
|
+
&& path.resolve(configured) === path.resolve(inherited)
|
|
239
|
+
// The process root is shared by all sessions. It may contain a session
|
|
240
|
+
// directory, but must never itself become the task's TMPDIR capability.
|
|
241
|
+
&& (!processRoot || !path.isAbsolute(processRoot) || path.resolve(configured) !== path.resolve(processRoot))
|
|
242
|
+
&& contextDir
|
|
243
|
+
&& path.resolve(contextDir) === path.resolve(configured)
|
|
244
|
+
&& (isManagedSessionRuntimeDir(configured) || isRunnerOwnedSessionRuntimeDir(configured));
|
|
245
|
+
if (!trusted) {
|
|
246
|
+
throw new Error('managed session TMPDIR is unavailable or untrusted');
|
|
247
|
+
}
|
|
248
|
+
return path.resolve(configured);
|
|
249
|
+
}
|
|
201
250
|
/**
|
|
202
251
|
* Create a private runtime directory below the process-provided TMPDIR.
|
|
203
252
|
* There is deliberately no os.tmpdir() fallback: managed sessions must not
|
|
@@ -290,6 +339,7 @@ export function buildTaskRuntimeEnv(ctx) {
|
|
|
290
339
|
const clean = normalizeTaskRuntimeContext(ctx);
|
|
291
340
|
return {
|
|
292
341
|
EVOLCORE_SESSION_ID: ctx.sessionId ?? '',
|
|
342
|
+
...(ctx.daemonRuntimeEpoch ? { [DAEMON_RUNTIME_EPOCH_ENV]: ctx.daemonRuntimeEpoch } : {}),
|
|
293
343
|
[TASK_RUNTIME_CONTEXT_ENV]: JSON.stringify(clean),
|
|
294
344
|
// Every managed child receives the session directory as TMPDIR. This keeps
|
|
295
345
|
// ordinary temporary files and runtime-only fallbacks out of shared agent
|
|
@@ -32,7 +32,7 @@ export async function cmdTrigger(args) {
|
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
if (process.env.EVOLCORE_SESSION_ID
|
|
35
|
-
&& (hasOption(rest, '--file') || hasOption(rest, '--prompt-file') || hasOption(rest, '--script-path'))) {
|
|
35
|
+
&& (hasOption(rest, '--file') || hasOption(rest, '--prompt-file') || hasOption(rest, '--script-path') || hasOption(rest, '--script-file'))) {
|
|
36
36
|
throw new Error('Managed tasks cannot read trigger definitions, prompts, or scripts from local files; use inline prompt content');
|
|
37
37
|
}
|
|
38
38
|
try {
|
|
@@ -110,7 +110,7 @@ Create 参数模式支持:
|
|
|
110
110
|
--baseagent <name> (仅 --exec trigger-session)
|
|
111
111
|
--model <模型> --effort <low|medium|high|xhigh|max>
|
|
112
112
|
--max-runs <次数> --max-duration <时长: 30s|15m|2h|1d>
|
|
113
|
-
--permission <readonly|auto|request|bypass
|
|
113
|
+
--permission <readonly|auto|request|bypass|fullaccess>(省略则继承当前身份配置;fullaccess 仅 daemon-owner 且 feature flag 开启时可用)
|
|
114
114
|
--tz <时区> (仅 cron)
|
|
115
115
|
--target-channel <channelKey> --target-channel-id <ID> (AUN 可简写为 aun)
|
|
116
116
|
--target-chat-type <private|group> (AUN 目标必填;channelId 同时作为群聊 ID)
|
|
@@ -123,7 +123,7 @@ Create 参数模式支持:
|
|
|
123
123
|
|
|
124
124
|
Update 仅支持常用字段:
|
|
125
125
|
--once | --delay | --at | --cron | --every | --event [--tz]
|
|
126
|
-
--prompt <文本> | --prompt-file <路径> --name <名称>
|
|
126
|
+
--prompt <文本> | --prompt-file <路径> --script-file <路径> --name <名称>
|
|
127
127
|
--model <模型> --effort <强度> --permission <权限模式|inherit>(inherit 清除覆盖)
|
|
128
128
|
--max-runs <次数> --max-duration <时长>
|
|
129
129
|
--concurrency <forbid|replace|allow> --missed-policy <skip|run-once|run-all>
|
|
@@ -399,19 +399,28 @@ function shellQuoteArg(value) {
|
|
|
399
399
|
}
|
|
400
400
|
async function updateTrigger(args, json) {
|
|
401
401
|
const agentAid = resolveAgentAid(args);
|
|
402
|
-
const triggerId = positional(args, 0, ['--agent', '--format', '--if-revision', '--prompt-file']);
|
|
402
|
+
const triggerId = positional(args, 0, ['--agent', '--format', '--if-revision', '--prompt-file', '--script-file']);
|
|
403
403
|
const usesPromptFile = hasOption(args, '--prompt-file');
|
|
404
|
+
const usesScriptFile = hasOption(args, '--script-file');
|
|
405
|
+
const scriptFilePath = usesScriptFile ? requireFlag(args, '--script-file') : undefined;
|
|
404
406
|
const { parseTriggerUpdateArgv } = await import('../trigger/parser.js');
|
|
405
407
|
const parsed = parseTriggerUpdateArgv(triggerId, withPromptFromFile(triggerUpdateArgs(args)), { allowLongPrompt: usesPromptFile });
|
|
406
408
|
if (!parsed.ok)
|
|
407
409
|
throw new Error(parsed.error);
|
|
410
|
+
const scriptFileRequested = parsed.value.scriptFile !== undefined;
|
|
411
|
+
const { scriptFile: _scriptFile, ...patchFields } = parsed.value;
|
|
412
|
+
const patch = scriptFileRequested ? { ...patchFields, scriptFile: true } : patchFields;
|
|
408
413
|
const expectedRevision = flagValue(args, '--if-revision');
|
|
414
|
+
const scriptFileBase64 = scriptFilePath
|
|
415
|
+
? fs.readFileSync(scriptFilePath).toString('base64')
|
|
416
|
+
: undefined;
|
|
409
417
|
const res = await request({
|
|
410
418
|
type: 'trigger.update',
|
|
411
419
|
agentAid,
|
|
412
420
|
triggerId,
|
|
413
|
-
patch
|
|
421
|
+
patch,
|
|
414
422
|
...(usesPromptFile ? { promptFile: true } : {}),
|
|
423
|
+
...(scriptFileBase64 !== undefined ? { scriptFileBase64 } : {}),
|
|
415
424
|
...(expectedRevision ? { expectedRevision } : {}),
|
|
416
425
|
}, 30_000);
|
|
417
426
|
if (json)
|