evolcore 0.0.29 → 0.0.30

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 (68) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/agents/codex-runner.js +61 -14
  3. package/dist/aun/aid/agentmd.js +224 -19
  4. package/dist/aun/aid/index.js +2 -1
  5. package/dist/aun/aid/managed-operation.js +70 -4
  6. package/dist/aun/group/index.js +1 -0
  7. package/dist/{core → aun}/group/invite-service.js +4 -4
  8. package/dist/channels/daemon.js +1 -1
  9. package/dist/cli/agent-command.js +7 -7
  10. package/dist/cli/aun-commands.js +97 -37
  11. package/dist/cli/data-command.js +2 -1
  12. package/dist/cli/managed-command-guard.js +2 -2
  13. package/dist/cli/model.js +1 -1
  14. package/dist/cli/response.js +1 -1
  15. package/dist/cli/trigger-command.js +52 -29
  16. package/dist/config/boot-log.js +95 -1
  17. package/dist/config/builtin-roles.js +1 -0
  18. package/dist/config/peer-role-resolver.js +21 -0
  19. package/dist/core/agent-ipc-registration.js +409 -0
  20. package/dist/core/agent-runtime.js +435 -0
  21. package/dist/core/auth/delegation-authorization.js +58 -0
  22. package/dist/core/auth/operation-catalog.js +8 -0
  23. package/dist/core/bootstrap-service.js +65 -1
  24. package/dist/core/channel-runtime.js +435 -0
  25. package/dist/core/command/command-handler.js +4 -1
  26. package/dist/core/daemon-bootstrap.js +151 -0
  27. package/dist/core/daemon-control.js +205 -0
  28. package/dist/core/daemon-lifecycle.js +225 -0
  29. package/dist/core/data-migration.js +4 -1
  30. package/dist/core/handoff/ipc-registration.js +156 -0
  31. package/dist/core/ipc-registration.js +457 -0
  32. package/dist/core/memory/consolidation-trigger.js +8 -0
  33. package/dist/core/memory/consolidation.js +838 -0
  34. package/dist/core/message/aun-ipc-sender.js +226 -0
  35. package/dist/core/message/outbound.js +165 -0
  36. package/dist/core/permission/approval-gateway.js +13 -0
  37. package/dist/core/permission/ec-command-parser.js +80 -35
  38. package/dist/core/permission/sandbox-runtime.js +23 -2
  39. package/dist/core/permission/tool-error-code.js +1 -0
  40. package/dist/core/permission/tool-policy.js +61 -24
  41. package/dist/core/session/session-idle-monitor.js +17 -0
  42. package/dist/index.js +352 -4841
  43. package/dist/ipc.js +2 -1
  44. package/dist/stats/db.js +24 -0
  45. package/dist/stats/index.js +1 -1
  46. package/dist/stats/writer.js +25 -1
  47. package/dist/trigger/application-service.js +157 -0
  48. package/dist/trigger/authorization.js +371 -0
  49. package/dist/trigger/ipc-service.js +406 -0
  50. package/dist/trigger/local-files.js +133 -0
  51. package/dist/trigger/manager.js +235 -22
  52. package/dist/trigger/scheduler.js +30 -5
  53. package/dist/trigger/script-executor.js +176 -39
  54. package/dist/trigger/script-sandbox.js +458 -0
  55. package/dist/trigger/system-definitions.js +188 -0
  56. package/dist/trigger/validation.js +0 -3
  57. package/dist/utils/aid-bind.js +1 -1
  58. package/dist/utils/evolcore-version.js +74 -0
  59. package/dist/utils/logger.js +16 -0
  60. package/kits/docs/evolcore/INDEX.md +1 -1
  61. package/kits/docs/evolcore/aid.md +9 -1
  62. package/kits/docs/evolcore/model.md +3 -2
  63. package/kits/docs/evolcore/rpc.md +4 -0
  64. package/kits/docs/evolcore/trigger.md +15 -1
  65. package/kits/schemas/relation-config.schema.9.json +1 -1
  66. package/kits/templates/system-fragments/commands.md +0 -1
  67. package/package.json +1 -1
  68. package/dist/core/memory/launch-consolidation.js +0 -395
@@ -1,5 +1,7 @@
1
1
  import { spawn } from 'child_process';
2
+ import { buildTriggerScriptLaunch } from './script-sandbox.js';
2
3
  import { previewText, resolveScriptPath, sha256, } from './validation.js';
4
+ const MAX_SCRIPT_OUTPUT_BYTES = 1 * 1024 * 1024;
3
5
  export class TriggerScriptExecutor {
4
6
  async execute(input) {
5
7
  const script = input.trigger.execution.type === 'script'
@@ -19,6 +21,9 @@ export class TriggerScriptExecutor {
19
21
  },
20
22
  };
21
23
  }
24
+ if (input.signal?.aborted) {
25
+ return this.errorResult(Date.now(), Buffer.alloc(0), Buffer.alloc(0), 'SCRIPT_ABORTED', 'script was aborted', 130);
26
+ }
22
27
  const scriptAbs = resolveScriptPath(input.triggerDir, script.path);
23
28
  const timeoutMs = script.timeoutMs ?? 30_000;
24
29
  const scriptArgs = Array.isArray(script.args) ? script.args.map(arg => String(arg)) : [];
@@ -38,72 +43,157 @@ export class TriggerScriptExecutor {
38
43
  },
39
44
  args: script.args ?? {},
40
45
  };
41
- return await this.spawnProcess(script.runtime, [scriptAbs, ...scriptArgs], JSON.stringify(payload), timeoutMs, input.signal);
46
+ let launch;
47
+ try {
48
+ launch = buildTriggerScriptLaunch({
49
+ trigger: input.trigger,
50
+ triggerDir: input.triggerDir,
51
+ scriptPath: scriptAbs,
52
+ scriptArgs,
53
+ projectPath: input.projectPath,
54
+ executionAuthorization: input.executionAuthorization,
55
+ });
56
+ await launch.prepare?.(input.signal);
57
+ }
58
+ catch (error) {
59
+ try {
60
+ launch?.cleanup?.();
61
+ }
62
+ catch { }
63
+ if (input.signal?.aborted) {
64
+ return this.errorResult(Date.now(), Buffer.alloc(0), Buffer.alloc(0), 'SCRIPT_ABORTED', 'script was aborted', 130);
65
+ }
66
+ return this.errorResult(Date.now(), Buffer.alloc(0), Buffer.alloc(0), 'SCRIPT_SANDBOX_UNAVAILABLE', error?.message || String(error), 126);
67
+ }
68
+ return await this.spawnProcess(launch, JSON.stringify(payload), timeoutMs, input.signal);
42
69
  }
43
- spawnProcess(command, args, stdin, timeoutMs, signal) {
70
+ spawnProcess(launch, stdin, timeoutMs, signal) {
44
71
  const startedAt = Date.now();
72
+ if (signal?.aborted) {
73
+ try {
74
+ launch.cleanup?.();
75
+ }
76
+ catch { }
77
+ return Promise.resolve(this.errorResult(startedAt, Buffer.alloc(0), Buffer.alloc(0), 'SCRIPT_ABORTED', 'script was aborted', 130));
78
+ }
45
79
  return new Promise((resolve) => {
46
80
  let stdout = Buffer.alloc(0);
47
81
  let stderr = Buffer.alloc(0);
48
82
  let settled = false;
49
83
  let timedOut = false;
50
84
  let aborted = false;
51
- const cmd = command === 'node' ? process.execPath : command;
52
- const child = spawn(cmd, args, {
53
- stdio: ['pipe', 'pipe', 'pipe'],
54
- shell: false,
55
- windowsHide: process.platform === 'win32',
56
- env: process.env,
57
- });
85
+ let outputLimitReached = false;
86
+ let terminationTimer;
87
+ let child;
88
+ let timer;
89
+ const finish = (result) => {
90
+ if (settled)
91
+ return;
92
+ settled = true;
93
+ clearTimeout(timer);
94
+ if (terminationTimer)
95
+ clearTimeout(terminationTimer);
96
+ signal?.removeEventListener('abort', abortHandler);
97
+ try {
98
+ launch.cleanup?.();
99
+ }
100
+ catch { }
101
+ resolve(result);
102
+ };
58
103
  const abortHandler = () => {
59
104
  aborted = true;
60
- child.kill('SIGTERM');
61
- setTimeout(() => {
62
- if (!settled)
63
- child.kill('SIGKILL');
64
- }, 2_000).unref();
105
+ terminateProcessTree(child, true);
65
106
  };
107
+ try {
108
+ child = spawn(launch.command, launch.args, {
109
+ stdio: ['pipe', 'pipe', 'pipe'],
110
+ shell: false,
111
+ windowsHide: process.platform === 'win32',
112
+ windowsVerbatimArguments: launch.windowsVerbatimArguments,
113
+ cwd: launch.cwd,
114
+ env: launch.env,
115
+ detached: process.platform !== 'win32',
116
+ });
117
+ }
118
+ catch (error) {
119
+ try {
120
+ launch.cleanup?.();
121
+ }
122
+ catch { }
123
+ resolve(this.errorResult(startedAt, stdout, stderr, 'SCRIPT_SPAWN_ERROR', error?.message || String(error), 127));
124
+ return;
125
+ }
126
+ if (!child.stdout || !child.stderr || !child.stdin) {
127
+ terminateProcessTree(child, true);
128
+ try {
129
+ launch.cleanup?.();
130
+ }
131
+ catch { }
132
+ resolve(this.errorResult(startedAt, stdout, stderr, 'SCRIPT_SPAWN_ERROR', 'script process pipes are unavailable', 127));
133
+ return;
134
+ }
135
+ const childStdout = child.stdout;
136
+ const childStderr = child.stderr;
137
+ const childStdin = child.stdin;
66
138
  if (signal) {
67
139
  if (signal.aborted)
68
140
  abortHandler();
69
141
  else
70
142
  signal.addEventListener('abort', abortHandler, { once: true });
71
143
  }
72
- const timer = setTimeout(() => {
73
- timedOut = true;
74
- child.kill('SIGTERM');
75
- setTimeout(() => {
144
+ const requestTermination = (reason) => {
145
+ if (timedOut || outputLimitReached || aborted)
146
+ return;
147
+ if (reason === 'timeout')
148
+ timedOut = true;
149
+ if (reason === 'output')
150
+ outputLimitReached = true;
151
+ terminateProcessTree(child, false);
152
+ terminationTimer = setTimeout(() => {
76
153
  if (!settled)
77
- child.kill('SIGKILL');
78
- }, 2_000).unref();
79
- }, timeoutMs);
154
+ terminateProcessTree(child, true);
155
+ }, 1_000);
156
+ terminationTimer.unref();
157
+ };
158
+ timer = setTimeout(() => requestTermination('timeout'), timeoutMs);
80
159
  timer.unref();
81
- child.stdout.on('data', (chunk) => { stdout = Buffer.concat([stdout, Buffer.from(chunk)]); });
82
- child.stderr.on('data', (chunk) => { stderr = Buffer.concat([stderr, Buffer.from(chunk)]); });
83
- child.on('error', (err) => {
84
- if (settled)
160
+ const appendOutput = (target, chunk) => {
161
+ const remaining = MAX_SCRIPT_OUTPUT_BYTES - stdout.length - stderr.length;
162
+ if (remaining <= 0) {
163
+ requestTermination('output');
85
164
  return;
86
- settled = true;
87
- clearTimeout(timer);
88
- signal?.removeEventListener('abort', abortHandler);
89
- resolve(this.errorResult(startedAt, stdout, stderr, 'SCRIPT_SPAWN_ERROR', err.message, 127));
165
+ }
166
+ const accepted = chunk.subarray(0, remaining);
167
+ if (target === 'stdout')
168
+ stdout = Buffer.concat([stdout, accepted]);
169
+ else
170
+ stderr = Buffer.concat([stderr, accepted]);
171
+ if (accepted.length < chunk.length) {
172
+ requestTermination('output');
173
+ }
174
+ };
175
+ childStdout.on('data', (chunk) => appendOutput('stdout', Buffer.from(chunk)));
176
+ childStderr.on('data', (chunk) => appendOutput('stderr', Buffer.from(chunk)));
177
+ child.on('error', (err) => {
178
+ finish(this.errorResult(startedAt, stdout, stderr, 'SCRIPT_SPAWN_ERROR', err.message, 127));
90
179
  });
91
180
  child.on('close', (code, closeSignal) => {
92
181
  if (settled)
93
182
  return;
94
- settled = true;
95
- clearTimeout(timer);
96
- signal?.removeEventListener('abort', abortHandler);
97
183
  if (aborted) {
98
- resolve(this.errorResult(startedAt, stdout, stderr, 'SCRIPT_ABORTED', 'script was aborted', code ?? 130));
184
+ finish(this.errorResult(startedAt, stdout, stderr, 'SCRIPT_ABORTED', 'script was aborted', code ?? 130));
99
185
  return;
100
186
  }
101
187
  if (timedOut) {
102
- resolve(this.errorResult(startedAt, stdout, stderr, 'SCRIPT_TIMEOUT', `script timed out after ${timeoutMs}ms`, code ?? 124));
188
+ finish(this.errorResult(startedAt, stdout, stderr, 'SCRIPT_TIMEOUT', `script timed out after ${timeoutMs}ms`, code ?? 124));
189
+ return;
190
+ }
191
+ if (outputLimitReached) {
192
+ finish(this.errorResult(startedAt, stdout, stderr, 'SCRIPT_OUTPUT_LIMIT', `script output exceeded ${MAX_SCRIPT_OUTPUT_BYTES} bytes`, code ?? 1));
103
193
  return;
104
194
  }
105
- if ((code ?? 0) !== 0) {
106
- resolve(this.errorResult(startedAt, stdout, stderr, 'SCRIPT_EXIT_NON_ZERO', `script exited with code ${code ?? `signal ${closeSignal}`}`, code ?? 1));
195
+ if (code !== 0) {
196
+ finish(this.errorResult(startedAt, stdout, stderr, 'SCRIPT_EXIT_NON_ZERO', `script exited with code ${code ?? `signal ${closeSignal}`}`, code ?? 1));
107
197
  return;
108
198
  }
109
199
  const text = stdout.toString('utf-8').trim();
@@ -115,10 +205,10 @@ export class TriggerScriptExecutor {
115
205
  }
116
206
  }
117
207
  catch (err) {
118
- resolve(this.errorResult(startedAt, stdout, stderr, 'SCRIPT_RESULT_PARSE_ERROR', err?.message || String(err), 1));
208
+ finish(this.errorResult(startedAt, stdout, stderr, 'SCRIPT_RESULT_PARSE_ERROR', err?.message || String(err), 1));
119
209
  return;
120
210
  }
121
- resolve({
211
+ finish({
122
212
  exitCode: 0,
123
213
  durationMs: Date.now() - startedAt,
124
214
  stdoutBytes: stdout.length,
@@ -130,7 +220,8 @@ export class TriggerScriptExecutor {
130
220
  result,
131
221
  });
132
222
  });
133
- child.stdin.end(stdin);
223
+ childStdin.on('error', () => { });
224
+ childStdin.end(stdin);
134
225
  });
135
226
  }
136
227
  errorResult(startedAt, stdout, stderr, code, message, exitCode) {
@@ -154,3 +245,49 @@ export class TriggerScriptExecutor {
154
245
  };
155
246
  }
156
247
  }
248
+ function terminateProcessTree(child, force) {
249
+ if (!child.pid)
250
+ return;
251
+ if (process.platform === 'win32') {
252
+ const taskkill = process.env.SystemRoot
253
+ ? `${process.env.SystemRoot}\\System32\\taskkill.exe`
254
+ : 'taskkill.exe';
255
+ const args = ['/pid', String(child.pid), '/t', ...(force ? ['/f'] : [])];
256
+ const killer = spawn(taskkill, args, {
257
+ stdio: 'ignore',
258
+ windowsHide: true,
259
+ });
260
+ killer.on('error', () => {
261
+ try {
262
+ child.kill('SIGKILL');
263
+ }
264
+ catch { }
265
+ });
266
+ killer.on('close', code => {
267
+ if (force || code === 0)
268
+ return;
269
+ const forceKiller = spawn(taskkill, ['/pid', String(child.pid), '/t', '/f'], {
270
+ stdio: 'ignore',
271
+ windowsHide: true,
272
+ });
273
+ forceKiller.on('error', () => {
274
+ try {
275
+ child.kill('SIGKILL');
276
+ }
277
+ catch { }
278
+ });
279
+ forceKiller.unref();
280
+ });
281
+ killer.unref();
282
+ return;
283
+ }
284
+ try {
285
+ process.kill(-(child.pid), force ? 'SIGKILL' : 'SIGTERM');
286
+ }
287
+ catch {
288
+ try {
289
+ child.kill(force ? 'SIGKILL' : 'SIGTERM');
290
+ }
291
+ catch { }
292
+ }
293
+ }