evolcore 0.0.35 → 0.0.37

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.
Files changed (224) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +6 -0
  3. package/bin/install-codex-managed-hooks.mjs +20 -3
  4. package/dist/agents/baseagent-availability.js +1 -1
  5. package/dist/agents/baseagent.js +88 -0
  6. package/dist/agents/claude-runner.js +59 -12
  7. package/dist/agents/codex/app-server-client.js +18 -1
  8. package/dist/agents/codex-runner.js +262 -21
  9. package/dist/agents/ecagent-runner.js +47 -11
  10. package/dist/agents/gemini-runner.js +36 -12
  11. package/dist/aun/aid/client.js +4 -3
  12. package/dist/aun/aid/control-aid.js +270 -8
  13. package/dist/aun/aid/identity.js +6 -3
  14. package/dist/aun/aid/ownership-operation.js +58 -0
  15. package/dist/aun/aid/store.js +1 -0
  16. package/dist/aun/group/fs-download.js +67 -2
  17. package/dist/aun/group/history.js +20 -5
  18. package/dist/aun/group/operations.js +8 -2
  19. package/dist/aun/menu/client.js +39 -2
  20. package/dist/aun/menu/transport.js +1 -1
  21. package/dist/aun/msg/history.js +43 -4
  22. package/dist/aun/msg/managed-operation.js +30 -53
  23. package/dist/aun/msg/p2p.js +51 -15
  24. package/dist/aun/outbox.js +4 -0
  25. package/dist/channels/aun.js +260 -73
  26. package/dist/channels/daemon.js +6 -4
  27. package/dist/channels/feishu.js +3 -0
  28. package/dist/cli/agent-command.js +161 -223
  29. package/dist/cli/agent-create.js +190 -223
  30. package/dist/cli/agent.js +3 -1
  31. package/dist/cli/aid-bind-command.js +53 -0
  32. package/dist/cli/aun-commands.js +384 -91
  33. package/dist/cli/bench.js +1 -1
  34. package/dist/cli/cli-argv.js +74 -0
  35. package/dist/cli/daemon-commands.js +105 -74
  36. package/dist/cli/diag.js +1 -1
  37. package/dist/cli/fs-command.js +18 -19
  38. package/dist/cli/getmeta-command.js +159 -6
  39. package/dist/cli/index.js +6 -12
  40. package/dist/cli/init-channel.js +8 -55
  41. package/dist/cli/init.js +125 -218
  42. package/dist/cli/queue-command.js +11 -8
  43. package/dist/cli/restart-monitor.js +177 -85
  44. package/dist/cli/session-command.js +1 -1
  45. package/dist/cli/stats.js +7 -5
  46. package/dist/cli/thread-command.js +103 -30
  47. package/dist/cli/trigger-command.js +1 -1
  48. package/dist/cli/watch-msg-diag.js +1 -0
  49. package/dist/config/access-policy.js +2 -2
  50. package/dist/config/boot-log.js +14 -11
  51. package/dist/config/config-field-policy.js +9 -1
  52. package/dist/config/config-manager.js +176 -90
  53. package/dist/config/config-operation-service.js +7 -14
  54. package/dist/config/contact-book-store.js +142 -26
  55. package/dist/config/contact-book.js +4 -2
  56. package/dist/config/lifecycle.js +1 -1
  57. package/dist/config/owner-config.js +96 -0
  58. package/dist/config/peer-role-resolver.js +12 -18
  59. package/dist/config/providers-config.js +382 -0
  60. package/dist/config/providers-import.js +74 -0
  61. package/dist/config/providers-management.js +328 -0
  62. package/dist/config/providers.js +22 -0
  63. package/dist/config/resolved-config-op.js +17 -14
  64. package/dist/config/snapshot.js +28 -16
  65. package/dist/config-store.js +18 -14
  66. package/dist/core/agent-ipc-registration.js +21 -63
  67. package/dist/core/agent-runtime.js +16 -5
  68. package/dist/core/auth/agent-delegation.js +199 -25
  69. package/dist/core/auth/auth-gateway.js +44 -2
  70. package/dist/core/auth/authorization-denial.js +1 -1
  71. package/dist/core/auth/debug-context.js +2 -1
  72. package/dist/core/auth/delegation-authorization.js +2 -2
  73. package/dist/core/auth/delegation-diagnostics.js +4 -1
  74. package/dist/core/auth/operation-authorizer.js +10 -1
  75. package/dist/core/auth/operation-catalog.js +19 -1
  76. package/dist/core/bootstrap-service.js +43 -20
  77. package/dist/core/channel-loader.js +0 -1
  78. package/dist/core/channel-runtime.js +30 -4
  79. package/dist/core/command/agent-control.js +196 -37
  80. package/dist/core/command/cli-intent-parser.js +60 -4
  81. package/dist/core/command/command-handler.js +212 -60
  82. package/dist/core/command/connect-menu.js +1 -0
  83. package/dist/core/command/diag-service.js +5 -4
  84. package/dist/core/command/file-search.js +368 -0
  85. package/dist/core/command/menu-catalog.js +2 -1
  86. package/dist/core/command/menu-handler.js +292 -107
  87. package/dist/core/command/menu-protocol.js +23 -0
  88. package/dist/core/command/role-menu.js +7 -19
  89. package/dist/core/command/skill-slash.js +130 -25
  90. package/dist/core/command/slash-handler.js +101 -53
  91. package/dist/core/command/topic-slash.js +16 -5
  92. package/dist/core/daemon-bootstrap.js +7 -1
  93. package/dist/core/daemon-control.js +19 -1
  94. package/dist/core/daemon-lifecycle.js +2 -1
  95. package/dist/core/event-catalog.js +2 -0
  96. package/dist/core/evolagent-registry.js +13 -2
  97. package/dist/core/evolagent.js +3 -6
  98. package/dist/core/handoff/ipc-registration.js +2 -2
  99. package/dist/core/handoff/runtime.js +40 -6
  100. package/dist/core/handoff/store.js +1 -0
  101. package/dist/core/inference/text-inference.js +95 -6
  102. package/dist/core/ipc-registration.js +43 -24
  103. package/dist/core/memory/consolidation-context.js +4 -1
  104. package/dist/core/memory/consolidation.js +25 -14
  105. package/dist/core/message/aun-ipc-sender.js +296 -88
  106. package/dist/core/message/aun-request-registry.js +226 -0
  107. package/dist/core/message/create-status.js +33 -4
  108. package/dist/core/message/message-bridge.js +62 -13
  109. package/dist/core/message/message-log.js +0 -1
  110. package/dist/core/message/message-queue.js +4 -1
  111. package/dist/core/message/message-utils.js +8 -1
  112. package/dist/core/message/peer-mode.js +17 -9
  113. package/dist/core/message/response-engine.js +266 -124
  114. package/dist/core/message/retry-scheduler.js +11 -8
  115. package/dist/core/model/catalog-service.js +60 -18
  116. package/dist/core/model/model-catalog.js +112 -9
  117. package/dist/core/model/model-fallback.js +94 -26
  118. package/dist/core/ownership/owner-resolver.js +687 -0
  119. package/dist/core/permission/approval-gateway.js +196 -62
  120. package/dist/core/permission/ec-command-parser.js +138 -25
  121. package/dist/core/permission/filesystem-approval-scope.js +141 -0
  122. package/dist/core/permission/protected-paths.js +14 -1
  123. package/dist/core/permission/sandbox-runtime.js +171 -18
  124. package/dist/core/permission/tool-policy.js +13 -2
  125. package/dist/core/role/runtime-policy.js +3 -4
  126. package/dist/core/session/session-idle-monitor.js +10 -8
  127. package/dist/core/session/session-manager.js +72 -45
  128. package/dist/core/session/session-mapper.js +18 -7
  129. package/dist/core/session/session-renew.js +5 -4
  130. package/dist/core/session/session-title.js +2 -1
  131. package/dist/core/session/session-turn-coordinator.js +4 -2
  132. package/dist/core/skill/index-generator.js +2 -16
  133. package/dist/core/task/task-recovery-service.js +15 -2
  134. package/dist/core/thread/command-parser.js +28 -13
  135. package/dist/core/thread/index.js +1 -0
  136. package/dist/core/thread/ipc-operation.js +11 -8
  137. package/dist/core/thread/thread-operation.js +79 -44
  138. package/dist/core/thread/thread-route.js +54 -6
  139. package/dist/core/thread/thread-service.js +236 -45
  140. package/dist/core/thread/topic-id.js +248 -0
  141. package/dist/eck/kit-renderer.js +1 -1
  142. package/dist/eck/message-renderer.js +12 -2
  143. package/dist/index.js +50 -27
  144. package/dist/ipc.js +59 -6
  145. package/dist/paths.js +1 -0
  146. package/dist/product.js +1 -0
  147. package/dist/response-system/engines/v1/proactive-flow.js +10 -3
  148. package/dist/stats/db.js +8 -0
  149. package/dist/stats/writer.js +26 -4
  150. package/dist/trigger/authorization.js +48 -3
  151. package/dist/trigger/feedback.js +28 -10
  152. package/dist/trigger/ipc-service.js +86 -10
  153. package/dist/trigger/local-files.js +55 -23
  154. package/dist/trigger/scheduler.js +57 -11
  155. package/dist/trigger/system-definitions.js +1 -0
  156. package/dist/trigger/validation.js +44 -15
  157. package/dist/utils/aid-bind.js +17 -297
  158. package/dist/utils/avatar-upload.js +16 -4
  159. package/dist/utils/cross-platform.js +115 -36
  160. package/dist/utils/ecweb-supervisor.js +1 -1
  161. package/dist/utils/ecweb-utils.js +8 -1
  162. package/dist/utils/error-utils.js +44 -6
  163. package/dist/utils/instance-registry.js +12 -2
  164. package/dist/utils/npm-ops.js +102 -27
  165. package/dist/utils/package-version-info.js +72 -27
  166. package/dist/utils/restart-safety.js +50 -0
  167. package/dist/utils/upgrade-jobs.js +304 -0
  168. package/dist/utils/windows-autostart.js +17 -10
  169. package/kits/docs/INDEX.md +5 -0
  170. package/kits/docs/aun/ABILITY_CALLING.md +239 -0
  171. package/kits/docs/evolcore/INDEX.md +14 -3
  172. package/kits/docs/evolcore/agent-create.md +55 -141
  173. package/kits/docs/evolcore/agent.md +38 -16
  174. package/kits/docs/evolcore/aid.md +34 -0
  175. package/kits/docs/evolcore/config.md +20 -1
  176. package/kits/docs/evolcore/event.md +2 -2
  177. package/kits/docs/evolcore/fs.md +18 -2
  178. package/kits/docs/evolcore/group-collaboration.md +13 -246
  179. package/kits/docs/evolcore/group.md +2 -1
  180. package/kits/docs/evolcore/memory-consolidation-batches.md +1 -1
  181. package/kits/docs/evolcore/menu-protocol.md +65 -1
  182. package/kits/docs/evolcore/msg.md +64 -2
  183. package/kits/docs/evolcore/skill.md +86 -0
  184. package/kits/docs/evolcore/stats.md +6 -0
  185. package/kits/docs/evolcore/task.md +2 -0
  186. package/kits/docs/evolcore/thread-chain.md +145 -51
  187. package/kits/docs/evolcore/trigger.md +48 -3
  188. package/kits/eck_manifest.json +21 -0
  189. package/kits/eck_message_manifest.json +4 -4
  190. package/kits/migrations/migrate-role-config-v5.mjs +20 -7
  191. package/kits/rules/01-overview.md +2 -1
  192. package/kits/rules/03-identity.md +3 -1
  193. package/kits/rules/04-relation.md +1 -1
  194. package/kits/rules/07-memory-and-thread.md +1 -1
  195. package/kits/schemas/_meta.json +16 -1
  196. package/kits/schemas/agent-config.schema.13.json +44 -2
  197. package/kits/schemas/contact-book.schema.3.json +5 -0
  198. package/kits/schemas/daemon.schema.6.json +3 -1
  199. package/kits/schemas/daemon.schema.8.json +329 -0
  200. package/kits/schemas/defaults.schema.5.json +39 -3
  201. package/kits/schemas/providers.schema.1.json +76 -0
  202. package/kits/schemas/relation-config.schema.9.json +5 -1
  203. package/kits/skills/.switches.json +28 -0
  204. package/kits/skills/aid-ability/SKILL.md +214 -0
  205. package/kits/skills/ec-agent-create/SKILL.md +162 -0
  206. package/kits/skills/ec-group/SKILL.md +2 -1
  207. package/kits/skills/ec-group-collaboration/SKILL.md +228 -0
  208. package/kits/skills/ec-identity/SKILL.md +143 -0
  209. package/kits/skills/ec-skill/scripts/cli.mjs +36 -3
  210. package/kits/skills/ec-skill/scripts/skill.mjs +202 -15
  211. package/kits/skills/ec-trigger/SKILL.md +167 -0
  212. package/kits/skills/ec-trigger/references/examples.md +153 -0
  213. package/kits/skills/thread-ops/SKILL.md +108 -420
  214. package/kits/templates/message-fragments/thread-context.md +1 -2
  215. package/kits/templates/message-fragments/trigger-thread-check.md +1 -1
  216. package/kits/templates/roles/member.json +1 -1
  217. package/kits/templates/roles/visitor.json +1 -0
  218. package/kits/templates/system-fragments/bootstrap.md +1 -0
  219. package/kits/templates/system-fragments/channel.md +2 -1
  220. package/kits/templates/system-fragments/commands.md +5 -4
  221. package/kits/templates/system-fragments/identity.md +2 -0
  222. package/kits/templates/system-fragments/session.md +1 -1
  223. package/kits/templates/system-fragments/venue.md +1 -1
  224. package/package.json +4 -3
@@ -1,4 +1,54 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { atomicWriteJson } from './atomic-write.js';
1
4
  const REAL_RESTART_TEST_OVERRIDE = 'EVOLCORE_ALLOW_REAL_RESTART_IN_TEST';
5
+ export function readRestartRequest(filePath, requestId) {
6
+ try {
7
+ const request = JSON.parse(fs.readFileSync(filePath, 'utf8'));
8
+ return request?.requestId === requestId ? request : null;
9
+ }
10
+ catch {
11
+ return null;
12
+ }
13
+ }
14
+ export function createRestartRequest(filePath, request, isProcessAlive) {
15
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
16
+ try {
17
+ const previous = JSON.parse(fs.readFileSync(filePath, 'utf8'));
18
+ if ([previous.launcherPid, previous.monitorPid]
19
+ .some(pid => typeof pid === 'number' && isProcessAlive(pid))
20
+ || Date.now() - Number(previous.updatedAt ?? previous.timestamp ?? 0) < 30_000)
21
+ return false;
22
+ fs.rmSync(filePath, { force: true });
23
+ }
24
+ catch (error) {
25
+ if (error.code !== 'ENOENT')
26
+ return false;
27
+ }
28
+ try {
29
+ fs.writeFileSync(filePath, JSON.stringify(request), { flag: 'wx' });
30
+ return true;
31
+ }
32
+ catch (error) {
33
+ if (error.code === 'EEXIST')
34
+ return false;
35
+ throw error;
36
+ }
37
+ }
38
+ export function updateRestartRequest(filePath, requestId, update) {
39
+ const request = readRestartRequest(filePath, requestId);
40
+ if (!request)
41
+ return false;
42
+ atomicWriteJson(filePath, { ...request, ...update, updatedAt: Date.now() });
43
+ return true;
44
+ }
45
+ export function removeRestartRequest(filePath, requestId) {
46
+ if (!readRestartRequest(filePath, requestId))
47
+ return;
48
+ fs.rmSync(filePath, { force: true });
49
+ fs.rmSync(`${filePath}_`, { force: true });
50
+ fs.rmSync(`${filePath}__`, { force: true });
51
+ }
2
52
  export function isRestartTestRuntime(env = process.env) {
3
53
  return env.VITEST === 'true'
4
54
  || env.EVOLCORE_TEST === '1';
@@ -0,0 +1,304 @@
1
+ import crypto from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { daemonControlDir, getPackageRoot, resolvePaths } from '../paths.js';
5
+ import { MAIN_PACKAGE_NAME, RESTART_REQUEST_ID_ENV, RUNTIME_HOME_ENV, SESSION_ID_ENV } from '../product.js';
6
+ import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
7
+ import { atomicWriteJson, withFileLock } from './atomic-write.js';
8
+ import { isLinkedInstall, preparePackageCache } from './npm-ops.js';
9
+ import { isProcessRunning, launchMonitorAndConfirm, resolveCliEntry } from './cross-platform.js';
10
+ import { scanInstances } from './instance-registry.js';
11
+ import { createRestartRequest, readRestartRequest, removeRestartRequest, shouldSuppressRealRestart, updateRestartRequest } from './restart-safety.js';
12
+ import { refreshManagedPackageVersions, resolveUpgradeDistTag, VERSION_INFO_PACKAGES } from './package-version-info.js';
13
+ const directory = () => path.join(resolvePaths().dataDir, 'upgrade-jobs');
14
+ const jobPath = (jobId) => {
15
+ if (!/^job_[a-f0-9-]{36}$/.test(jobId))
16
+ throw new Error('Invalid upgrade jobId');
17
+ return path.join(directory(), `${jobId}.json`);
18
+ };
19
+ const terminal = (status) => !['accepted', 'running'].includes(status);
20
+ const subscriptions = new Map();
21
+ const blankCheck = (distTag) => ({
22
+ operation: 'version-check', devMode: isLinkedInstall(), distTag, hasUpdate: null,
23
+ packages: Object.fromEntries(VERSION_INFO_PACKAGES.map(name => [name, { currentVersion: null, targetVersion: null, checkedAt: null }])),
24
+ });
25
+ export function structuredUpgradeCheck(results, distTag) {
26
+ const check = blankCheck(distTag);
27
+ for (const result of results) {
28
+ check.packages[result.packageName] = {
29
+ currentVersion: result.entry.currentVersion,
30
+ targetVersion: result.status === 'ok' ? result.entry.latestVersion ?? null : null,
31
+ checkedAt: result.status === 'ok' ? result.entry.checkedAt ?? null : null,
32
+ ...(result.status !== 'ok' && result.entry.checkedAt ? { lastCheckedVersion: result.entry.latestVersion, lastCheckedAt: result.entry.checkedAt } : {}),
33
+ ...(result.error ? { error: result.error } : {}),
34
+ };
35
+ }
36
+ const core = results.find(result => result.packageName === MAIN_PACKAGE_NAME);
37
+ check.hasUpdate = core?.status === 'ok' && core.entry.currentVersion ? core.hasUpdate : null;
38
+ return check;
39
+ }
40
+ export function readUpgradeJob(jobId) {
41
+ const file = jobPath(jobId);
42
+ try {
43
+ const job = JSON.parse(fs.readFileSync(file, 'utf8'));
44
+ return job.jobId === jobId && Array.isArray(job.events) ? job : null;
45
+ }
46
+ catch {
47
+ return null;
48
+ }
49
+ }
50
+ function save(job) {
51
+ atomicWriteJson(jobPath(job.jobId), job);
52
+ }
53
+ export function updateUpgradeJob(jobId, patch, message) {
54
+ const lock = `${jobPath(jobId)}.lock`;
55
+ const deadline = Date.now() + 3_000;
56
+ let descriptor;
57
+ for (;;) {
58
+ try {
59
+ descriptor = fs.openSync(lock, 'wx', 0o600);
60
+ fs.writeFileSync(descriptor, JSON.stringify({ pid: process.pid }));
61
+ break;
62
+ }
63
+ catch (error) {
64
+ if (error.code !== 'EEXIST')
65
+ throw error;
66
+ try {
67
+ const owner = JSON.parse(fs.readFileSync(lock, 'utf8'));
68
+ if (Number.isSafeInteger(owner.pid) && !isProcessRunning(owner.pid)) {
69
+ fs.rmSync(lock, { force: true });
70
+ continue;
71
+ }
72
+ }
73
+ catch { }
74
+ if (Date.now() >= deadline)
75
+ throw new Error('Upgrade job state is busy');
76
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10);
77
+ }
78
+ }
79
+ try {
80
+ return writeUpgradeJob(jobId, patch, message);
81
+ }
82
+ finally {
83
+ fs.closeSync(descriptor);
84
+ fs.rmSync(lock, { force: true });
85
+ }
86
+ }
87
+ function writeUpgradeJob(jobId, patch, message) {
88
+ const job = readUpgradeJob(jobId);
89
+ if (!job)
90
+ return null;
91
+ if (terminal(job.status) && patch.status && patch.status !== job.status)
92
+ return job;
93
+ Object.assign(job, patch, { updatedAt: Date.now() });
94
+ if (message) {
95
+ job.seq++;
96
+ const event = {
97
+ operation: 'version-check', devMode: job.devMode, distTag: job.distTag, hasUpdate: job.hasUpdate, packages: job.packages,
98
+ type: 'menu.event', event: terminal(job.status) ? 'upgrade.result' : 'upgrade.progress',
99
+ requestId: job.requestId, jobId, seq: job.seq, phase: job.phase, at: new Date(job.updatedAt).toISOString(),
100
+ elapsedMs: job.updatedAt - job.createdAt, message, status: job.status,
101
+ ...(job.success !== undefined ? { success: job.success } : {}),
102
+ ...(job.code ? { code: job.code, reason: job.reason } : {}),
103
+ };
104
+ job.events = [...job.events.slice(-255), event];
105
+ }
106
+ save(job);
107
+ return job;
108
+ }
109
+ export function upgradeJobView(job) {
110
+ const { target: _target, npmConfig: _npmConfig, requestKey: _requestKey, scopeKey: _scopeKey, ownerPid: _ownerPid, monitorPid: _monitorPid, launcherPid: _launcherPid, ...view } = job;
111
+ return view;
112
+ }
113
+ export function subscribeUpgradeJob(jobId, send, key) {
114
+ if (key)
115
+ subscriptions.get(key)?.();
116
+ let seq = 0;
117
+ let busy = false;
118
+ const deadline = Date.now() + 6 * 60_000;
119
+ const stop = () => { clearInterval(timer); if (key && subscriptions.get(key) === stop)
120
+ subscriptions.delete(key); };
121
+ const timer = setInterval(() => {
122
+ if (Date.now() >= deadline) {
123
+ stop();
124
+ return;
125
+ }
126
+ if (busy)
127
+ return;
128
+ busy = true;
129
+ void (async () => {
130
+ const job = readUpgradeJob(jobId);
131
+ if (!job) {
132
+ stop();
133
+ return;
134
+ }
135
+ for (const event of job.events.filter(item => item.seq > seq)) {
136
+ await send(event);
137
+ seq = event.seq;
138
+ if (event.event === 'upgrade.result')
139
+ atomicWriteJson(`${jobPath(jobId)}.ack`, { seq });
140
+ }
141
+ if (terminal(job.status))
142
+ stop();
143
+ })().catch(() => { stop(); }).finally(() => { busy = false; });
144
+ }, 200);
145
+ timer.unref();
146
+ if (key)
147
+ subscriptions.set(key, stop);
148
+ return stop;
149
+ }
150
+ export async function acknowledgeUpgradeRestart(jobId) {
151
+ const deadline = Date.now() + 2_000;
152
+ while (Date.now() < deadline) {
153
+ try {
154
+ if (JSON.parse(fs.readFileSync(`${jobPath(jobId)}.ack`, 'utf8')).seq >= (readUpgradeJob(jobId)?.seq ?? Infinity))
155
+ return;
156
+ }
157
+ catch { }
158
+ await new Promise(resolve => setTimeout(resolve, 50));
159
+ }
160
+ }
161
+ function jobs() {
162
+ try {
163
+ return fs.readdirSync(directory()).filter(file => /^job_[a-f0-9-]{36}\.json$/.test(file)).map(file => readUpgradeJob(file.slice(0, -5))).filter((job) => !!job);
164
+ }
165
+ catch {
166
+ return [];
167
+ }
168
+ }
169
+ export async function startUpgradeJob(requestId, scope) {
170
+ fs.mkdirSync(directory(), { recursive: true });
171
+ return withFileLock(path.join(directory(), 'active.lock'), async () => {
172
+ const existing = jobs();
173
+ const requestKey = crypto.createHash('sha256').update(JSON.stringify([scope, requestId])).digest('hex');
174
+ const scopeKey = crypto.createHash('sha256').update(scope).digest('hex');
175
+ const replay = existing.find(job => job.requestKey === requestKey);
176
+ if (replay)
177
+ return { job: replay, reused: true };
178
+ const monitors = scanInstances().restartMonitors.filter(item => item.alive);
179
+ for (const job of existing) {
180
+ const liveMonitor = !!job.monitorPid && isProcessRunning(job.monitorPid);
181
+ const liveLauncher = !!job.launcherPid && isProcessRunning(job.launcherPid);
182
+ if (!job.released || liveMonitor || liveLauncher) {
183
+ if (liveMonitor || liveLauncher || (!job.released && !job.restartRequestId && isProcessRunning(job.ownerPid)) || monitors.length) {
184
+ if (job.scopeKey !== scopeKey)
185
+ throw Object.assign(new Error('An update is already running for another requester'), { code: 'CONFLICT' });
186
+ return { job, reused: true };
187
+ }
188
+ updateUpgradeJob(job.jobId, { status: 'failed', success: false, released: true, code: 'UPGRADE_INTERRUPTED', reason: 'Update worker exited before completing the transaction' }, '更新进程已退出,可重新发起');
189
+ }
190
+ }
191
+ if (monitors.length)
192
+ throw Object.assign(new Error('A restart transaction is still running'), { code: 'CONFLICT' });
193
+ const now = Date.now();
194
+ const job = {
195
+ ...blankCheck(resolveUpgradeDistTag()), jobId: `job_${crypto.randomUUID()}`, requestId, requestKey, scopeKey,
196
+ status: 'accepted', phase: 'upgrade-check', seq: 0, createdAt: now, updatedAt: now,
197
+ deadline: now + 5 * 60_000, ownerPid: process.pid, released: false, events: [],
198
+ };
199
+ save(job);
200
+ for (const expired of existing.filter(item => item.released).sort((left, right) => right.updatedAt - left.updatedAt).slice(49)) {
201
+ for (const suffix of ['', '_', '__', '.ack', '.ack_'])
202
+ fs.rmSync(`${jobPath(expired.jobId)}${suffix}`, { force: true });
203
+ }
204
+ setTimeout(() => { void runUpgradeJob(job).catch(() => { }); }, 50);
205
+ return { job, reused: false };
206
+ });
207
+ }
208
+ async function runUpgradeJob(job) {
209
+ const controller = new AbortController();
210
+ const timeout = setTimeout(() => controller.abort(), Math.max(1, job.deadline - Date.now()));
211
+ let heartbeat;
212
+ let handedOff = false;
213
+ try {
214
+ updateUpgradeJob(job.jobId, { status: 'running' }, '正在检查版本');
215
+ const results = await refreshManagedPackageVersions(VERSION_INFO_PACKAGES, { distTag: job.distTag, source: 'menu-update', signal: controller.signal, includeUninstalled: true });
216
+ const check = structuredUpgradeCheck(results, job.distTag);
217
+ updateUpgradeJob(job.jobId, check, '版本检查完成');
218
+ if (controller.signal.aborted)
219
+ throw new Error('Update timed out');
220
+ if (check.hasUpdate === false) {
221
+ updateUpgradeJob(job.jobId, { status: 'no-update', success: true, released: true }, '当前 EvolCore 无可升级版本');
222
+ return;
223
+ }
224
+ if (check.hasUpdate === null)
225
+ throw new Error(check.packages[MAIN_PACKAGE_NAME].error ?? 'Cannot determine the EvolCore target version');
226
+ if (check.devMode)
227
+ throw new Error('Linked development installations cannot be updated with npm');
228
+ const coreResult = results.find(result => result.packageName === MAIN_PACKAGE_NAME);
229
+ const target = coreResult.entry;
230
+ updateUpgradeJob(job.jobId, { target, npmConfig: coreResult.npmConfig, phase: 'downloading' }, '正在准备更新包,优先读取 npm 缓存');
231
+ heartbeat = setInterval(() => {
232
+ try {
233
+ updateUpgradeJob(job.jobId, {}, '正在准备更新包,等待 npm 完成');
234
+ }
235
+ catch {
236
+ controller.abort();
237
+ }
238
+ }, 1_000);
239
+ await preparePackageCache(target.latestVersion, target.registry, {
240
+ signal: controller.signal,
241
+ npmConfig: coreResult.npmConfig,
242
+ onPhase: phase => { updateUpgradeJob(job.jobId, { phase }, phase === 'tarball-check' ? '正在校验 npm 缓存包' : '正在下载或复用缓存'); },
243
+ });
244
+ clearInterval(heartbeat);
245
+ heartbeat = undefined;
246
+ if (controller.signal.aborted)
247
+ throw new Error('Update timed out');
248
+ if (shouldSuppressRealRestart())
249
+ throw new Error('Real restart is disabled in this test runtime');
250
+ const pending = path.join(daemonControlDir(), 'restart-pending.json');
251
+ const requestId = crypto.randomUUID();
252
+ if (!createRestartRequest(pending, {
253
+ requestId, requesterPid: process.pid, status: 'requested', timestamp: Date.now(), upgradeJobId: job.jobId,
254
+ }, isProcessRunning))
255
+ throw new Error('Another restart request is pending');
256
+ updateUpgradeJob(job.jobId, { restartRequestId: requestId }, '缓存校验通过,正在交由重启监控器处理');
257
+ const entry = resolveCliEntry(getPackageRoot());
258
+ const launch = await launchMonitorAndConfirm([...entry.args, 'restart'], {
259
+ [RUNTIME_HOME_ENV]: resolvePaths().root, [RESTART_REQUEST_ID_ENV]: requestId,
260
+ [SESSION_ID_ENV]: '', [AGENT_DELEGATION_TOKEN_ENV]: '',
261
+ }, () => {
262
+ const request = readRestartRequest(pending, requestId);
263
+ return request?.status === 'accepted' || request?.status === 'ready';
264
+ }, () => false, {
265
+ requestId, timeoutMs: 8_000, logFilePath: path.join(resolvePaths().logs, `restart-launch-${requestId}.log`),
266
+ onSpawn: pid => { updateRestartRequest(pending, requestId, { launcherPid: pid }); updateUpgradeJob(job.jobId, { launcherPid: pid }); },
267
+ isPendingInRegistry: () => scanInstances().restartMonitors.some(item => item.alive && item.record.requestId === requestId),
268
+ });
269
+ handedOff = launch.ok || launch.pending === true;
270
+ if (!handedOff) {
271
+ removeRestartRequest(pending, requestId);
272
+ throw new Error('Restart monitor did not accept the update; inspect restart launch diagnostics');
273
+ }
274
+ while (!terminal(readUpgradeJob(job.jobId)?.status ?? 'failed')) {
275
+ if (controller.signal.aborted) {
276
+ removeRestartRequest(pending, requestId);
277
+ throw new Error('Update timed out before restart acceptance');
278
+ }
279
+ await new Promise(resolve => setTimeout(resolve, 200));
280
+ }
281
+ }
282
+ catch (error) {
283
+ const current = readUpgradeJob(job.jobId);
284
+ if (current && !terminal(current.status))
285
+ updateUpgradeJob(job.jobId, {
286
+ status: controller.signal.aborted ? 'timeout' : 'failed', success: false, released: true,
287
+ code: controller.signal.aborted ? 'UPGRADE_TIMEOUT' : 'UPGRADE_FAILED',
288
+ reason: error instanceof SyntaxError ? 'npm returned invalid package metadata' : sanitizeUpgradeReason(error instanceof Error ? error.message : 'Update failed'),
289
+ }, '更新未完成,可重新发起');
290
+ }
291
+ finally {
292
+ clearTimeout(timeout);
293
+ if (heartbeat)
294
+ clearInterval(heartbeat);
295
+ if (!handedOff) {
296
+ const current = readUpgradeJob(job.jobId);
297
+ if (current?.released === false && terminal(current.status))
298
+ updateUpgradeJob(job.jobId, { released: true });
299
+ }
300
+ }
301
+ }
302
+ export function sanitizeUpgradeReason(reason) {
303
+ return reason.replace(/https?:\/\/\S+/gi, '[registry]').replace(/(?:token|password|authorization)\s*[:=]\s*\S+/gi, '[redacted]').slice(0, 1_000);
304
+ }
@@ -48,7 +48,7 @@ function accessDeniedError(action, result) {
48
48
  + '若自启动已由管理员配置且只需确认服务,请执行:ec status。';
49
49
  }
50
50
  function isTaskNotFoundMessage(message) {
51
- return /cannot find the file specified|系统找不到指定的文件|找不到指定的文件|指定的任务不存在|任务不存在/i.test(message);
51
+ return /cannot find the (?:file|path) specified|系统找不到指定的(?:文件|路径)|找不到指定的(?:文件|路径)|指定的任务不存在|任务不存在/i.test(message);
52
52
  }
53
53
  function isRegistryValueNotFoundMessage(message) {
54
54
  return /unable to find|cannot find|系统找不到|找不到指定的注册表项|找不到指定的文件/i.test(message);
@@ -232,9 +232,9 @@ function taskOwnership(xml, runtimeRoot) {
232
232
  : undefined;
233
233
  const principalCurrent = principalBlocks.length === 1
234
234
  && /<LogonType>\s*InteractiveToken\s*<\/LogonType>/i.test(principalBlocks[0])
235
- // schtasks /RL LIMITED can omit RunLevel entirely because
236
- // LeastPrivilege is the schema default.
237
- && (runLevel === undefined || /^LeastPrivilege$/i.test(runLevel));
235
+ // The task is intentionally created with /RL HIGHEST so startup can
236
+ // provision the managed Codex hook and other machine-level requirements.
237
+ && /^HighestAvailable$/i.test(runLevel ?? '');
238
238
  const triggerCurrent = triggerTypes.length === 1 && triggerTypes[0] === 'logontrigger';
239
239
  const current = managed
240
240
  && normalizeCommandLine(args) === normalizeCommandLine(expectedArgs)
@@ -698,14 +698,23 @@ export function configureWindowsAutostart(enabled, runtimeRoot) {
698
698
  ];
699
699
  const result = runSchtasks(args);
700
700
  if (result.status !== 0) {
701
- if (isAccessDenied(result) && taskBeforeCreate.state === 'not-found') {
701
+ const taskError = isAccessDenied(result)
702
+ ? accessDeniedError('启用', result)
703
+ : commandError(result, '创建 Windows 登录自启任务失败');
704
+ // Some Windows installations can query tasks but cannot create one
705
+ // because Task Scheduler's backing path is unavailable. HKCU Run does
706
+ // not depend on that path. Only fall back when no existing task is owned.
707
+ const canUseUserRun = isAccessDenied(result) || isTaskNotFoundMessage(resultOutput(result));
708
+ if (canUseUserRun && taskBeforeCreate.state === 'not-found') {
702
709
  const fallback = createUserRunAutostart(absoluteRoot, scriptPath, wrapperCurrent);
703
710
  const fallbackMayBeInstalled = fallback.enabled && fallback.backend === 'user-run';
704
711
  const restoreError = restoreWrapperUnlessNeeded(scriptPath, previousWrapper, fallback.ok || fallbackMayBeInstalled || (existingRun.state === 'installed' && existingRun.managed));
705
712
  if (fallback.ok) {
706
713
  return {
707
714
  ...fallback,
708
- warning: '任务计划程序拒绝访问,已回退到当前用户 HKCU Run 自启动(无需管理员权限)。如需改用计划任务,请以管理员身份再次运行 ec init --auto-start。',
715
+ warning: isAccessDenied(result)
716
+ ? '任务计划程序拒绝访问,已回退到当前用户 HKCU Run 自启动(无需管理员权限)。如需改用计划任务,请以管理员身份再次运行 ec init --auto-start。'
717
+ : `任务计划程序创建失败:${commandError(result, '找不到指定的文件或路径')};已回退到当前用户 HKCU Run 自启动(无需管理员权限)。`,
709
718
  };
710
719
  }
711
720
  const fallbackError = fallback.error ? `;用户级 Run 回退失败:${fallback.error}` : '';
@@ -714,7 +723,7 @@ export function configureWindowsAutostart(enabled, runtimeRoot) {
714
723
  ok: false,
715
724
  enabled: fallback.enabled,
716
725
  ...(fallback.backend ? { backend: fallback.backend } : {}),
717
- error: `${accessDeniedError('启用', result)}${fallbackError}${rollbackSuffix}`,
726
+ error: `${taskError}${fallbackError}${rollbackSuffix}`,
718
727
  };
719
728
  }
720
729
  const restoreError = restoreWrapperUnlessNeeded(scriptPath, previousWrapper, taskBeforeCreate.state === 'installed' || (existingRun.state === 'installed' && existingRun.managed));
@@ -728,9 +737,7 @@ export function configureWindowsAutostart(enabled, runtimeRoot) {
728
737
  ok: false,
729
738
  enabled: previousBackend !== undefined,
730
739
  ...(previousBackend ? { backend: previousBackend } : {}),
731
- error: `${isAccessDenied(result)
732
- ? accessDeniedError('启用', result)
733
- : commandError(result, '创建 Windows 登录自启任务失败')}${rollbackSuffix}`,
740
+ error: `${taskError}${rollbackSuffix}`,
734
741
  };
735
742
  }
736
743
  const verified = probeWindowsTask(absoluteRoot);
@@ -18,6 +18,9 @@
18
18
  | 速查表 | `aun/CHEATSHEET.md` | AUN 协议命名空间与常用操作速查 |
19
19
  | SDK 文档指引 | `aun/SDK.md` | AUN SDK 文档位置(`$AUN_SDK_DOCS`)、结构与常用入口;四语言版本共用同一份协议文档 |
20
20
  | 同步协议 | `aun/SYNC_PROTOCOL.md` | 上游协议同步 SOP |
21
+ | Ability 调用 | `aun/ABILITY_CALLING.md` | AID 能力发现、原始 JSON 调用、ACK/等待、超时和 request 查询 |
22
+
23
+ EvolCore 能力插件体系的实施设计位于源码仓库 `$PACKAGE_ROOT/docs/ability/plugin-system/README.md`。该设计尚未实现,不是当前可用的 Ability 插件命令手册。
21
24
 
22
25
  ## EvolCore 命令
23
26
 
@@ -28,6 +31,8 @@
28
31
  |------|------|------|
29
32
  | 命令集目录 | `evolcore/INDEX.md` | msg/group/agent/aid/storage/ctl/rpc/bench 全集索引 |
30
33
  | 联系人命令 | `evolcore/contact.md` | Contact Book 添加申请、拉黑与托管会话权限边界 |
34
+ | Agent 生命周期与 Bootstrap | `evolcore/agent-create.md` | 生命周期与新 Agent 首次设定参考;创建者操作已迁移到 `ec-agent-create` 技能 |
35
+ | 群聊协作入口 | `evolcore/group-collaboration.md` | 旧文档入口;完整任务流程已迁移到 `ec-group-collaboration` 技能 |
31
36
 
32
37
  ## 身份
33
38