evolcore 0.0.31 → 0.0.32
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 +11 -0
- package/dist/agents/codex-runner.js +28 -5
- package/dist/agents/ecagent-runner.js +4 -0
- package/dist/agents/gemini-runner.js +4 -0
- package/dist/aun/aid/store.js +0 -81
- package/dist/aun/group/fs-download.js +1 -10
- package/dist/aun/msg/managed-operation.js +130 -32
- package/dist/aun/service-proxy.js +12 -18
- package/dist/aun/storage/index.js +29 -0
- package/dist/channels/aun.js +10 -135
- package/dist/cli/agent-command.js +6 -7
- package/dist/cli/agent-create.js +43 -24
- package/dist/cli/agent.js +15 -69
- package/dist/cli/aun-commands.js +149 -5
- package/dist/cli/ctl-command.js +1 -2
- package/dist/cli/daemon-commands.js +1 -1
- package/dist/cli/diag.js +2 -2
- package/dist/cli/handoff-command.js +15 -5
- package/dist/cli/memory-command.js +85 -11
- package/dist/cli/model.js +14 -138
- package/dist/cli/queue-command.js +46 -0
- package/dist/cli/response.js +5 -54
- package/dist/cli/skill-command.js +9 -3
- package/dist/cli/stats.js +10 -4
- package/dist/cli/task-command.js +1 -0
- package/dist/cli/task-context.js +15 -0
- package/dist/cli/trigger-command.js +73 -49
- package/dist/config/builtin-roles.js +8 -7
- package/dist/core/agent-ipc-registration.js +65 -22
- package/dist/core/auth/agent-delegation.js +17 -1
- package/dist/core/auth/delegation-authorization.js +1 -0
- package/dist/core/auth/operation-catalog.js +11 -3
- package/dist/core/command/command-handler.js +164 -21
- package/dist/core/command/diag-service.js +5 -1
- package/dist/core/handoff/ipc-registration.js +38 -0
- package/dist/core/ipc-registration.js +71 -7
- package/dist/core/message/aun-ipc-sender.js +48 -4
- package/dist/core/message/message-queue.js +131 -3
- package/dist/core/message/response-engine.js +30 -2
- package/dist/core/permission/sandbox-runtime.js +14 -1
- package/dist/core/task/task-recovery-service.js +2 -0
- package/dist/core/task/task-resume-operation.js +11 -0
- package/dist/index.js +2 -2
- package/dist/ipc.js +146 -8
- package/dist/trigger/authorization.js +2 -1
- package/dist/trigger/ipc-service.js +49 -35
- package/dist/trigger/script-sandbox.js +58 -77
- package/kits/docs/AUTHORING.md +1 -1
- package/kits/docs/channels/aun.md +8 -0
- package/kits/docs/evolcore/INDEX.md +2 -2
- package/kits/docs/evolcore/task.md +2 -0
- package/kits/docs/evolcore/trigger.md +2 -2
- package/kits/rules/01-overview.md +0 -9
- package/kits/rules/06-channel.md +7 -1
- package/kits/templates/system-fragments/commands.md +1 -1
- package/package.json +1 -1
|
@@ -15,6 +15,7 @@ import { resolvePaths } from '../paths.js';
|
|
|
15
15
|
import { ipcQuery } from '../ipc.js';
|
|
16
16
|
import { isHelpFlag, wantsHelp } from './help.js';
|
|
17
17
|
import { readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
18
|
+
import { canonicalizeEvolcoreCommandArgv } from '../core/permission/ec-command-parser.js';
|
|
18
19
|
export const MEMORY_MODES = ['notes', 'generalize', 'promote', 'profile', 'forget'];
|
|
19
20
|
const MEMORY_HELP = `用法: ec memory <command> [选项]
|
|
20
21
|
|
|
@@ -63,6 +64,7 @@ ec memory consolidate [--mode <notes|generalize|promote|profile|forget>]
|
|
|
63
64
|
ec memory update consolidated/commit-convention.md --tags "rule,done"
|
|
64
65
|
ec memory archive consolidated/obsolete.md`;
|
|
65
66
|
export async function cmdMemory(args) {
|
|
67
|
+
args = canonicalizeEvolcoreCommandArgv(['ec', 'memory', ...args]).slice(2);
|
|
66
68
|
if (args.length === 0 || isHelpFlag(args[0]) || wantsHelp(args)) {
|
|
67
69
|
console.log(MEMORY_HELP);
|
|
68
70
|
return;
|
|
@@ -99,13 +101,15 @@ export async function cmdMemory(args) {
|
|
|
99
101
|
* 解析 `--key value` 与位置参数。未识别的 `--xxx` 一律报错,避免静默忽略。
|
|
100
102
|
* `--debug <sessionId>` 是所有子命令的公共参数,不用每处声明。
|
|
101
103
|
*/
|
|
102
|
-
function parseArgs(args, known) {
|
|
104
|
+
function parseArgs(args, known, throwOnUnknown = false) {
|
|
103
105
|
const flags = new Map();
|
|
104
106
|
const positional = [];
|
|
105
107
|
for (let i = 0; i < args.length; i++) {
|
|
106
108
|
const a = args[i];
|
|
107
109
|
if (a.startsWith('--')) {
|
|
108
110
|
if (a !== '--debug' && !known.includes(a)) {
|
|
111
|
+
if (throwOnUnknown)
|
|
112
|
+
throw new Error(`未知参数: ${a}`);
|
|
109
113
|
console.error(`❌ 未知参数: ${a}`);
|
|
110
114
|
process.exit(1);
|
|
111
115
|
}
|
|
@@ -128,6 +132,76 @@ function parseTags(raw) {
|
|
|
128
132
|
const tags = raw.split(',').map(t => t.trim()).filter(Boolean);
|
|
129
133
|
return tags.length > 0 ? tags : undefined;
|
|
130
134
|
}
|
|
135
|
+
export function resolveMemoryCommandArgv(argv) {
|
|
136
|
+
if (argv[0] !== 'memory')
|
|
137
|
+
throw new Error('Expected a memory command');
|
|
138
|
+
const noteSub = argv[1] === 'note' && ['update', 'drop', 'list'].includes(argv[2]) ? argv[2] : undefined;
|
|
139
|
+
const kind = noteSub ? `note.${noteSub}` : argv[1];
|
|
140
|
+
const known = {
|
|
141
|
+
note: ['--slug', '--tags', '--speakers'], 'note.update': ['--slug', '--tags'],
|
|
142
|
+
'note.drop': [], 'note.list': [], create: ['--scope', '--slug', '--desc', '--tags', '--keywords', '--replaces', '--peer'],
|
|
143
|
+
update: ['--tags', '--touch'], archive: [], demote: ['--scope'], consolidate: ['--mode'], feedback: [],
|
|
144
|
+
};
|
|
145
|
+
if (!Object.prototype.hasOwnProperty.call(known, kind))
|
|
146
|
+
throw new Error('Invalid memory command');
|
|
147
|
+
const { flags, positional } = parseArgs(argv.slice(noteSub ? 3 : 2), known[kind], true);
|
|
148
|
+
const required = (value, name) => {
|
|
149
|
+
if (!value)
|
|
150
|
+
throw new Error(`${name} is required`);
|
|
151
|
+
return value;
|
|
152
|
+
};
|
|
153
|
+
const content = positional.join(' ').trim();
|
|
154
|
+
const type = `memory.${kind}`;
|
|
155
|
+
if (kind === 'note')
|
|
156
|
+
return { type, slug: required(flags.get('--slug'), '--slug'), content: required(content, 'content'),
|
|
157
|
+
tags: parseTags(flags.get('--tags')), speakers: parseTags(flags.get('--speakers')) };
|
|
158
|
+
if (kind === 'note.update') {
|
|
159
|
+
const newContent = positional.slice(1).join(' ').trim();
|
|
160
|
+
if (!flags.get('--slug') && !flags.has('--tags') && !newContent)
|
|
161
|
+
throw new Error('No memory note changes supplied');
|
|
162
|
+
return { type, slug: required(positional[0], 'slug'), newSlug: flags.get('--slug'),
|
|
163
|
+
tags: parseTags(flags.get('--tags')), tagsProvided: flags.has('--tags'), content: newContent || undefined };
|
|
164
|
+
}
|
|
165
|
+
if (kind === 'note.drop')
|
|
166
|
+
return { type, slug: required(positional[0], 'slug') };
|
|
167
|
+
if (kind === 'note.list')
|
|
168
|
+
return { type };
|
|
169
|
+
if (kind === 'create') {
|
|
170
|
+
const scope = flags.get('--scope');
|
|
171
|
+
if (!scope || !['relation', 'agent', 'owner'].includes(scope))
|
|
172
|
+
throw new Error('Invalid memory scope');
|
|
173
|
+
if (!flags.has('--tags'))
|
|
174
|
+
throw new Error('--tags is required');
|
|
175
|
+
if (flags.has('--peer') && scope !== 'relation')
|
|
176
|
+
throw new Error('--peer requires relation scope');
|
|
177
|
+
return { type, scope, slug: required(flags.get('--slug'), '--slug'), description: required(flags.get('--desc'), '--desc'),
|
|
178
|
+
content: required(content, 'content'), tags: parseTags(flags.get('--tags')), keywords: parseTags(flags.get('--keywords')),
|
|
179
|
+
replaces: parseTags(flags.get('--replaces')), targetPeerKey: flags.get('--peer') };
|
|
180
|
+
}
|
|
181
|
+
if (kind === 'update') {
|
|
182
|
+
if (!flags.has('--tags') && !flags.has('--touch'))
|
|
183
|
+
throw new Error('No memory changes supplied');
|
|
184
|
+
return { type, filePath: required(positional[0], 'path'), tags: parseTags(flags.get('--tags')), touch: flags.has('--touch') };
|
|
185
|
+
}
|
|
186
|
+
if (kind === 'archive') {
|
|
187
|
+
if (!positional.length)
|
|
188
|
+
throw new Error('Memory paths are required');
|
|
189
|
+
return { type, filePaths: positional };
|
|
190
|
+
}
|
|
191
|
+
if (kind === 'demote') {
|
|
192
|
+
const scope = flags.get('--scope') ?? 'agent';
|
|
193
|
+
if (scope !== 'agent' && scope !== 'owner')
|
|
194
|
+
throw new Error('Invalid demotion scope');
|
|
195
|
+
return { type, slug: required(positional[0], 'slug'), scope };
|
|
196
|
+
}
|
|
197
|
+
if (kind === 'consolidate') {
|
|
198
|
+
const mode = flags.get('--mode') ?? 'notes';
|
|
199
|
+
if (!MEMORY_MODES.includes(mode))
|
|
200
|
+
throw new Error('Invalid consolidation mode');
|
|
201
|
+
return { type, mode };
|
|
202
|
+
}
|
|
203
|
+
return { type, text: required(content, 'feedback') };
|
|
204
|
+
}
|
|
131
205
|
/** 各子命令的一行完整用法:缺参报错时附上,模型照抄即可重试。 */
|
|
132
206
|
const USAGE = {
|
|
133
207
|
note: 'ec memory note --slug <slug> [--tags <tag1,tag2>] [--speakers <aid1,aid2>] "<正文>"',
|
|
@@ -193,7 +267,7 @@ async function cmdMemoryNoteCreate(args) {
|
|
|
193
267
|
failWithUsage('必须提供记忆内容(content)', USAGE.note);
|
|
194
268
|
const { socketPath, ...session } = requireManagedSession('ec memory note', flags);
|
|
195
269
|
const result = await ipcQuery(socketPath, {
|
|
196
|
-
type: 'memory.note', ...session, slug, content, tags,
|
|
270
|
+
type: 'memory.note', argv: ['memory', 'note', ...args], ...session, slug, content, tags,
|
|
197
271
|
speakers: speakers && speakers.length > 0 ? speakers : undefined,
|
|
198
272
|
}, 15_000);
|
|
199
273
|
reportResult(result, (r) => {
|
|
@@ -215,7 +289,7 @@ async function cmdMemoryNoteUpdate(args) {
|
|
|
215
289
|
}
|
|
216
290
|
const { socketPath, ...session } = requireManagedSession('ec memory note update', flags);
|
|
217
291
|
const result = await ipcQuery(socketPath, {
|
|
218
|
-
type: 'memory.note.update', ...session, slug,
|
|
292
|
+
type: 'memory.note.update', argv: ['memory', 'note', 'update', ...args], ...session, slug,
|
|
219
293
|
newSlug, tags, tagsProvided: tagsRaw !== undefined,
|
|
220
294
|
content: content || undefined,
|
|
221
295
|
}, 15_000);
|
|
@@ -231,7 +305,7 @@ async function cmdMemoryNoteDrop(args) {
|
|
|
231
305
|
failWithUsage('必须提供要撤销的 slug', USAGE.noteDrop);
|
|
232
306
|
const { socketPath, ...session } = requireManagedSession('ec memory note drop', flags);
|
|
233
307
|
const result = await ipcQuery(socketPath, {
|
|
234
|
-
type: 'memory.note.drop', ...session, slug,
|
|
308
|
+
type: 'memory.note.drop', argv: ['memory', 'note', 'drop', ...args], ...session, slug,
|
|
235
309
|
}, 15_000);
|
|
236
310
|
reportResult(result, (r) => {
|
|
237
311
|
console.log(`✓ 已撤销: ${r.filePath ?? slug}`);
|
|
@@ -241,7 +315,7 @@ async function cmdMemoryNoteList(args) {
|
|
|
241
315
|
const { flags } = parseArgs(args, []);
|
|
242
316
|
const { socketPath, ...session } = requireManagedSession('ec memory note list', flags);
|
|
243
317
|
const result = await ipcQuery(socketPath, {
|
|
244
|
-
type: 'memory.note.list', ...session,
|
|
318
|
+
type: 'memory.note.list', argv: ['memory', 'note', 'list', ...args], ...session,
|
|
245
319
|
}, 15_000);
|
|
246
320
|
reportResult(result, (r) => {
|
|
247
321
|
const notes = r.notes ?? [];
|
|
@@ -286,7 +360,7 @@ async function cmdMemoryCreate(args) {
|
|
|
286
360
|
}
|
|
287
361
|
const { socketPath, ...session } = requireManagedSession('ec memory create', flags);
|
|
288
362
|
const result = await ipcQuery(socketPath, {
|
|
289
|
-
type: 'memory.create', ...session, scope, slug, description: desc,
|
|
363
|
+
type: 'memory.create', argv: ['memory', 'create', ...args], ...session, scope, slug, description: desc,
|
|
290
364
|
content,
|
|
291
365
|
tags: parseTags(tagsRaw),
|
|
292
366
|
keywords: parseTags(keywordsRaw),
|
|
@@ -312,7 +386,7 @@ async function cmdMemoryConsolidatedUpdate(args) {
|
|
|
312
386
|
failWithUsage('至少提供 --tags 或 --touch', USAGE.update);
|
|
313
387
|
const { socketPath, ...session } = requireManagedSession('ec memory update', flags);
|
|
314
388
|
const result = await ipcQuery(socketPath, {
|
|
315
|
-
type: 'memory.update', ...session, filePath,
|
|
389
|
+
type: 'memory.update', argv: ['memory', 'update', ...args], ...session, filePath,
|
|
316
390
|
tags: parseTags(tagsRaw), touch,
|
|
317
391
|
}, 15_000);
|
|
318
392
|
reportResult(result, () => {
|
|
@@ -325,7 +399,7 @@ async function cmdMemoryArchive(args) {
|
|
|
325
399
|
failWithUsage('必须提供至少一个要归档的文件路径', USAGE.archive);
|
|
326
400
|
const { socketPath, ...session } = requireManagedSession('ec memory archive', flags);
|
|
327
401
|
const result = await ipcQuery(socketPath, {
|
|
328
|
-
type: 'memory.archive', ...session, filePaths: positional,
|
|
402
|
+
type: 'memory.archive', argv: ['memory', 'archive', ...args], ...session, filePaths: positional,
|
|
329
403
|
}, 15_000);
|
|
330
404
|
reportResult(result, (r) => {
|
|
331
405
|
const archived = r.archived ?? positional;
|
|
@@ -353,7 +427,7 @@ async function cmdMemoryDemote(args) {
|
|
|
353
427
|
}
|
|
354
428
|
const { socketPath, ...session } = requireManagedSession('ec memory demote', flags);
|
|
355
429
|
const result = await ipcQuery(socketPath, {
|
|
356
|
-
type: 'memory.demote', ...session, slug, scope,
|
|
430
|
+
type: 'memory.demote', argv: ['memory', 'demote', ...args], ...session, slug, scope,
|
|
357
431
|
}, 15_000);
|
|
358
432
|
reportResult(result, (r) => {
|
|
359
433
|
if (r.conflictArchived) {
|
|
@@ -385,7 +459,7 @@ async function cmdMemoryConsolidate(args) {
|
|
|
385
459
|
const { socketPath, ...session } = requireManagedSession('ec memory consolidate', flags);
|
|
386
460
|
console.log(`正在触发记忆整理(mode=${mode})...`);
|
|
387
461
|
const result = await ipcQuery(socketPath, {
|
|
388
|
-
type: 'memory.consolidate', ...session, mode,
|
|
462
|
+
type: 'memory.consolidate', argv: ['memory', 'consolidate', ...args], ...session, mode,
|
|
389
463
|
}, 30_000);
|
|
390
464
|
reportResult(result, (r) => {
|
|
391
465
|
console.log(`✓ 整理会话已启动(${mode} 模式)`);
|
|
@@ -418,7 +492,7 @@ async function cmdMemoryFeedback(args) {
|
|
|
418
492
|
}
|
|
419
493
|
const { socketPath, ...session } = requireManagedSession('ec memory feedback', flags);
|
|
420
494
|
const result = await ipcQuery(socketPath, {
|
|
421
|
-
type: 'memory.feedback', ...session, text,
|
|
495
|
+
type: 'memory.feedback', argv: ['memory', 'feedback', ...args], ...session, text,
|
|
422
496
|
}, 15_000);
|
|
423
497
|
reportResult(result, () => {
|
|
424
498
|
console.log('✓ 已记录反馈内容');
|
package/dist/cli/model.js
CHANGED
|
@@ -19,10 +19,8 @@ import { resolvePaths } from '../paths.js';
|
|
|
19
19
|
import { ipcQuery } from '../ipc.js';
|
|
20
20
|
import { parsePeerKey } from '../core/relation/peer-identity.js';
|
|
21
21
|
import { resolvePeerRoleDetail } from '../config/peer-role-resolver.js';
|
|
22
|
-
import { getFieldPermission } from '../config/roles.js';
|
|
23
22
|
import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
24
23
|
import { formatModelCheck, runModelCheck } from '../core/model/model-diagnostics.js';
|
|
25
|
-
import { validateRuntimeStringFieldOverride } from '../core/role/runtime-policy.js';
|
|
26
24
|
const ALL_EFFORTS = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'auto'];
|
|
27
25
|
const SCOPE_LABEL = {
|
|
28
26
|
global: '全局', agent: 'agent级', role: '角色级', relation: '关系级',
|
|
@@ -45,29 +43,21 @@ function fail(formatJson, code, message, data) {
|
|
|
45
43
|
}
|
|
46
44
|
process.exit(1);
|
|
47
45
|
}
|
|
48
|
-
function
|
|
49
|
-
void args;
|
|
50
|
-
return !!process.env.EVOLCORE_SESSION_ID;
|
|
51
|
-
}
|
|
52
|
-
function isManagedTargetedWriteEnv(args) {
|
|
53
|
-
return !!process.env.EVOLCORE_SESSION_ID
|
|
54
|
-
&& !isManagedSessionEnv(args);
|
|
55
|
-
}
|
|
56
|
-
async function runCtlCommand(cmd, formatJson, timeoutMs = 10_000) {
|
|
46
|
+
async function runManagedCliOperation(args, formatJson, timeoutMs = 10_000) {
|
|
57
47
|
const sessionId = process.env.EVOLCORE_SESSION_ID;
|
|
58
48
|
if (!sessionId)
|
|
59
49
|
fail(formatJson, 'NO_SESSION', 'EVOLCORE_SESSION_ID 未设置');
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
50
|
+
const delegationToken = readDelegationCredential();
|
|
51
|
+
if (!delegationToken)
|
|
52
|
+
fail(formatJson, 'DELEGATION_REQUIRED', `${AGENT_DELEGATION_TOKEN_ENV} 未设置`);
|
|
53
|
+
const response = await ipcQuery(resolvePaths().socket, {
|
|
54
|
+
type: 'ctl', argv: args, sessionId, delegationToken,
|
|
65
55
|
}, timeoutMs);
|
|
66
|
-
if (!
|
|
56
|
+
if (!response)
|
|
67
57
|
fail(formatJson, 'DAEMON_UNAVAILABLE', '无法连接 evolcore 服务');
|
|
68
|
-
if (!
|
|
69
|
-
fail(formatJson, 'CTL_FAILED',
|
|
70
|
-
|
|
58
|
+
if (!response.ok)
|
|
59
|
+
fail(formatJson, response.code || 'CTL_FAILED', response.error || '命令执行失败');
|
|
60
|
+
printCtlResult({ text: response.result || '', data: response.data }, formatJson);
|
|
71
61
|
}
|
|
72
62
|
function printCtlResult(result, formatJson) {
|
|
73
63
|
if (formatJson) {
|
|
@@ -76,56 +66,6 @@ function printCtlResult(result, formatJson) {
|
|
|
76
66
|
}
|
|
77
67
|
console.log(result.text);
|
|
78
68
|
}
|
|
79
|
-
async function runManagedConfigOperation(args, formatJson) {
|
|
80
|
-
const sessionId = process.env.EVOLCORE_SESSION_ID;
|
|
81
|
-
if (!sessionId)
|
|
82
|
-
fail(formatJson, 'NO_SESSION', 'EVOLCORE_SESSION_ID 未设置');
|
|
83
|
-
const delegationToken = readDelegationCredential();
|
|
84
|
-
if (!delegationToken) {
|
|
85
|
-
fail(formatJson, 'DELEGATION_REQUIRED', `${AGENT_DELEGATION_TOKEN_ENV} 未设置`);
|
|
86
|
-
}
|
|
87
|
-
let response;
|
|
88
|
-
try {
|
|
89
|
-
response = await ipcQuery(resolvePaths().socket, {
|
|
90
|
-
type: 'config.op',
|
|
91
|
-
argv: ['config', ...args],
|
|
92
|
-
sessionId,
|
|
93
|
-
delegationToken,
|
|
94
|
-
}, 10_000);
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
response = null;
|
|
98
|
-
}
|
|
99
|
-
if (!response)
|
|
100
|
-
fail(formatJson, 'DAEMON_UNAVAILABLE', '无法连接 evolcore 服务');
|
|
101
|
-
if (!response.ok || !response.result?.ok) {
|
|
102
|
-
fail(formatJson, response.code || 'CONFIG_AUTH_FAILED', response.error || 'config 操作失败', response.data);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
function configSelectorArgs(sel) {
|
|
106
|
-
const args = ['--self', sel.self];
|
|
107
|
-
if (sel.peerKey)
|
|
108
|
-
args.push('--peer', sel.peerKey);
|
|
109
|
-
return args;
|
|
110
|
-
}
|
|
111
|
-
async function setManagedModelField(sel, field, value, formatJson) {
|
|
112
|
-
const subcommand = value === null ? ['unset', field] : ['set', field, value];
|
|
113
|
-
await runManagedConfigOperation([...subcommand, ...configSelectorArgs(sel)], formatJson);
|
|
114
|
-
}
|
|
115
|
-
function preflightManagedFieldOverride(sel, role, field, value, formatJson) {
|
|
116
|
-
if (!role)
|
|
117
|
-
return;
|
|
118
|
-
const policy = getFieldPermission(role, field, sel.self);
|
|
119
|
-
if (policy?.allowOverride === false) {
|
|
120
|
-
fail(formatJson, 'ROLE_OVERRIDE_DISABLED', `Role ${role} cannot override ${field}`);
|
|
121
|
-
}
|
|
122
|
-
if (value === null)
|
|
123
|
-
return;
|
|
124
|
-
const decision = validateRuntimeStringFieldOverride({ selfAid: sel.self, role, field, value });
|
|
125
|
-
if (!decision.ok) {
|
|
126
|
-
fail(formatJson, decision.code || 'ROLE_VALUE_NOT_ALLOWED', decision.message || `Value ${value} is not allowed for ${field}`);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
69
|
/**
|
|
130
70
|
* 解析 --self / --peer 为作用域选择器。
|
|
131
71
|
*/
|
|
@@ -286,11 +226,6 @@ async function cmdList(args, formatJson) {
|
|
|
286
226
|
console.log(HELP);
|
|
287
227
|
return;
|
|
288
228
|
}
|
|
289
|
-
if (isManagedSessionEnv(args)) {
|
|
290
|
-
const out = await runCtlCommand('/model list', formatJson);
|
|
291
|
-
printCtlResult(out, formatJson);
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
229
|
const sel = parseSelector(args, formatJson);
|
|
295
230
|
const role = explicitOrDerivedRole(args, sel);
|
|
296
231
|
const effectiveSel = selectorWithRole(sel, role);
|
|
@@ -337,11 +272,6 @@ async function cmdCurrent(args, formatJson) {
|
|
|
337
272
|
console.log(HELP);
|
|
338
273
|
return;
|
|
339
274
|
}
|
|
340
|
-
if (isManagedSessionEnv(args)) {
|
|
341
|
-
const out = await runCtlCommand('/model current', formatJson);
|
|
342
|
-
printCtlResult(out, formatJson);
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
275
|
const sel = parseSelector(args, formatJson);
|
|
346
276
|
const ba = activeBaseagent(sel.self);
|
|
347
277
|
const role = explicitOrDerivedRole(args, sel);
|
|
@@ -372,11 +302,6 @@ async function cmdInfo(args, formatJson) {
|
|
|
372
302
|
const modelId = args[1] && !args[1].startsWith('--') ? args[1] : undefined;
|
|
373
303
|
if (!modelId)
|
|
374
304
|
fail(formatJson, 'MISSING_MODEL_ID', 'info 需要 <model-id>');
|
|
375
|
-
if (isManagedSessionEnv(args)) {
|
|
376
|
-
const out = await runCtlCommand(`/model info ${modelId}`, formatJson);
|
|
377
|
-
printCtlResult(out, formatJson);
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
305
|
const sel = parseSelector(args, formatJson);
|
|
381
306
|
const self = getArgValue(args, '--self');
|
|
382
307
|
const info = await getModelInfo(modelId, self);
|
|
@@ -424,12 +349,6 @@ async function cmdUse(args, formatJson) {
|
|
|
424
349
|
const modelId = args[1] && !args[1].startsWith('--') ? args[1] : undefined;
|
|
425
350
|
if (!modelId)
|
|
426
351
|
fail(formatJson, 'MISSING_MODEL_ID', 'use 需要 <model-id>');
|
|
427
|
-
if (isManagedSessionEnv(args)) {
|
|
428
|
-
const effort = getArgValue(args, '--effort');
|
|
429
|
-
const out = await runCtlCommand(`/model ${modelId}${effort ? ` ${effort}` : ''}`, formatJson);
|
|
430
|
-
printCtlResult(out, formatJson);
|
|
431
|
-
return;
|
|
432
|
-
}
|
|
433
352
|
const sel = parseSelector(args, formatJson);
|
|
434
353
|
const role = explicitOrDerivedRole(args, sel);
|
|
435
354
|
const scope = determineWriteScope(sel, formatJson);
|
|
@@ -457,19 +376,6 @@ async function cmdUse(args, formatJson) {
|
|
|
457
376
|
fail(formatJson, 'INVALID_EFFORT', `当前模型目录未声明支持推理强度: ${effort}`);
|
|
458
377
|
}
|
|
459
378
|
const effortVal = effort === 'auto' ? null : (effort ?? undefined);
|
|
460
|
-
if (isManagedTargetedWriteEnv(args)) {
|
|
461
|
-
if (effortVal !== undefined) {
|
|
462
|
-
const effortKey = 'effort';
|
|
463
|
-
preflightManagedFieldOverride(sel, role, `baseagents.${ba}.${effortKey}`, effortVal, formatJson);
|
|
464
|
-
}
|
|
465
|
-
await setManagedModelField(sel, `baseagents.${ba}.model`, modelId, formatJson);
|
|
466
|
-
if (effortVal !== undefined) {
|
|
467
|
-
const effortKey = 'effort';
|
|
468
|
-
await setManagedModelField(sel, `baseagents.${ba}.${effortKey}`, effortVal, formatJson);
|
|
469
|
-
}
|
|
470
|
-
describeWrite(scope, sel, modelId, effort ?? null, formatJson);
|
|
471
|
-
return;
|
|
472
|
-
}
|
|
473
379
|
try {
|
|
474
380
|
writeScope(scope, sel, ba, { model: modelId, effort: effortVal });
|
|
475
381
|
}
|
|
@@ -491,11 +397,6 @@ async function cmdEffort(args, formatJson) {
|
|
|
491
397
|
if (!ALL_EFFORTS.includes(level)) {
|
|
492
398
|
fail(formatJson, 'INVALID_EFFORT', `无效推理强度: ${level}(${ALL_EFFORTS.join('/')})`);
|
|
493
399
|
}
|
|
494
|
-
if (isManagedSessionEnv(args)) {
|
|
495
|
-
const out = await runCtlCommand(`/effort ${level}`, formatJson);
|
|
496
|
-
printCtlResult(out, formatJson);
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
400
|
const sel = parseSelector(args, formatJson);
|
|
500
401
|
const scope = determineWriteScope(sel, formatJson);
|
|
501
402
|
const ba = activeBaseagent(sel.self);
|
|
@@ -507,13 +408,6 @@ async function cmdEffort(args, formatJson) {
|
|
|
507
408
|
if (!model || !catalogEfforts(cat, model, ba).includes(val))
|
|
508
409
|
fail(formatJson, 'INVALID_EFFORT', `当前模型目录未声明支持推理强度: ${val}`);
|
|
509
410
|
}
|
|
510
|
-
if (isManagedTargetedWriteEnv(args)) {
|
|
511
|
-
const effortKey = 'effort';
|
|
512
|
-
preflightManagedFieldOverride(sel, explicitOrDerivedRole(args, sel), `baseagents.${ba}.${effortKey}`, val, formatJson);
|
|
513
|
-
await setManagedModelField(sel, `baseagents.${ba}.${effortKey}`, val, formatJson);
|
|
514
|
-
describeWrite(scope, sel, null, level, formatJson);
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
411
|
try {
|
|
518
412
|
writeScope(scope, sel, ba, { effort: val });
|
|
519
413
|
}
|
|
@@ -529,26 +423,9 @@ async function cmdReset(args, formatJson) {
|
|
|
529
423
|
console.log(HELP);
|
|
530
424
|
return;
|
|
531
425
|
}
|
|
532
|
-
if (isManagedSessionEnv(args)) {
|
|
533
|
-
const out = await runCtlCommand('/model reset', formatJson);
|
|
534
|
-
printCtlResult(out, formatJson);
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
426
|
const sel = parseSelector(args, formatJson);
|
|
538
427
|
const scope = determineWriteScope(sel, formatJson);
|
|
539
428
|
const ba = activeBaseagent(sel.self);
|
|
540
|
-
if (isManagedTargetedWriteEnv(args)) {
|
|
541
|
-
const effortKey = 'effort';
|
|
542
|
-
const role = explicitOrDerivedRole(args, sel);
|
|
543
|
-
preflightManagedFieldOverride(sel, role, `baseagents.${ba}.model`, null, formatJson);
|
|
544
|
-
preflightManagedFieldOverride(sel, role, `baseagents.${ba}.${effortKey}`, null, formatJson);
|
|
545
|
-
await setManagedModelField(sel, `baseagents.${ba}.model`, null, formatJson);
|
|
546
|
-
await setManagedModelField(sel, `baseagents.${ba}.${effortKey}`, null, formatJson);
|
|
547
|
-
emit(formatJson, {
|
|
548
|
-
ok: true, scope, self: sel.self ?? null, peerKey: sel.peerKey ?? null,
|
|
549
|
-
}, () => `✓ 已清除 ${SCOPE_LABEL[scope]} 设置,回落上一级(该范围所有会话下条消息生效)`);
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
429
|
try {
|
|
553
430
|
clearScope(scope, sel, ba);
|
|
554
431
|
}
|
|
@@ -568,11 +445,6 @@ async function cmdCheck(args, formatJson) {
|
|
|
568
445
|
console.log(HELP);
|
|
569
446
|
return;
|
|
570
447
|
}
|
|
571
|
-
if (isManagedSessionEnv(args)) {
|
|
572
|
-
const out = await runCtlCommand('/model check', formatJson, 60_000);
|
|
573
|
-
printCtlResult(out, formatJson);
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
448
|
const sel = parseSelector(args, formatJson);
|
|
577
449
|
const role = explicitOrDerivedRole(args, sel);
|
|
578
450
|
const ba = activeBaseagent(sel.self);
|
|
@@ -609,5 +481,9 @@ export async function cmdModel(args) {
|
|
|
609
481
|
&& (getArgValue(args, '--self') || getArgValue(args, '--peer') || getArgValue(args, '--role'))) {
|
|
610
482
|
fail(formatJson, 'NOT_ALLOWED', 'Managed model commands cannot select --self, --peer, or --role; they always use the authenticated current relation');
|
|
611
483
|
}
|
|
484
|
+
if (process.env.EVOLCORE_SESSION_ID) {
|
|
485
|
+
await runManagedCliOperation(['model', ...args], formatJson, sub === 'check' ? 60_000 : 10_000);
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
612
488
|
await dispatch(sub, args, formatJson);
|
|
613
489
|
}
|
|
@@ -2,7 +2,9 @@ import { resolvePaths } from '../paths.js';
|
|
|
2
2
|
import { ipcQuery } from '../ipc.js';
|
|
3
3
|
import { readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
4
4
|
import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
|
|
5
|
+
import { canonicalizeEvolcoreCommandArgv } from '../core/permission/ec-command-parser.js';
|
|
5
6
|
export async function cmdQueue(args) {
|
|
7
|
+
args = canonicalizeEvolcoreCommandArgv(['ec', 'queue', ...args]).slice(2);
|
|
6
8
|
if (args.length === 0 || isHelpFlag(args[0]) || wantsHelp(args)) {
|
|
7
9
|
console.log(`用法: ec queue --agent <aid> [选项]
|
|
8
10
|
|
|
@@ -91,6 +93,7 @@ JSON 时间字段:
|
|
|
91
93
|
const managed = process.env.EVOLCORE_SESSION_ID;
|
|
92
94
|
const result = await ipcQuery(socketPath, managed ? {
|
|
93
95
|
type: 'queue.op',
|
|
96
|
+
argv: ['queue', ...args],
|
|
94
97
|
agent,
|
|
95
98
|
action,
|
|
96
99
|
messageId: cancelMsgId,
|
|
@@ -147,6 +150,49 @@ function parseQueueTime(value, flag) {
|
|
|
147
150
|
}
|
|
148
151
|
return parsed;
|
|
149
152
|
}
|
|
153
|
+
export function parseQueueOperationArgv(argv) {
|
|
154
|
+
if (argv[0] !== 'queue')
|
|
155
|
+
throw new Error('Expected a queue command');
|
|
156
|
+
const flags = new Map();
|
|
157
|
+
const booleanFlags = new Set(['--clear', '--interrupt', '--showid', '--full']);
|
|
158
|
+
const valueFlags = new Set(['--agent', '--cancel', '--sessionkey', '--after', '--before', '--format']);
|
|
159
|
+
for (let index = 1; index < argv.length; index++) {
|
|
160
|
+
const flag = argv[index];
|
|
161
|
+
if (booleanFlags.has(flag))
|
|
162
|
+
flags.set(flag, 'true');
|
|
163
|
+
else if (valueFlags.has(flag) && argv[index + 1] && !argv[index + 1].startsWith('--'))
|
|
164
|
+
flags.set(flag, argv[++index]);
|
|
165
|
+
else
|
|
166
|
+
throw new Error(`Invalid queue option: ${flag}`);
|
|
167
|
+
}
|
|
168
|
+
const agent = flags.get('--agent');
|
|
169
|
+
if (!agent)
|
|
170
|
+
throw new Error('--agent is required');
|
|
171
|
+
if (flags.has('--format') && flags.get('--format') !== 'json')
|
|
172
|
+
throw new Error('--format only supports json');
|
|
173
|
+
if (['--clear', '--cancel', '--interrupt'].filter(flag => flags.has(flag)).length > 1)
|
|
174
|
+
throw new Error('Queue actions are mutually exclusive');
|
|
175
|
+
const time = (flag) => {
|
|
176
|
+
const value = flags.get(flag);
|
|
177
|
+
if (value === undefined)
|
|
178
|
+
return undefined;
|
|
179
|
+
const parsed = /^\d+$/.test(value) ? Number(value) : Date.parse(value);
|
|
180
|
+
if (!Number.isFinite(parsed))
|
|
181
|
+
throw new Error(`Invalid ${flag}`);
|
|
182
|
+
return parsed;
|
|
183
|
+
};
|
|
184
|
+
const after = time('--after');
|
|
185
|
+
const before = time('--before');
|
|
186
|
+
if (after !== undefined && before !== undefined && after >= before)
|
|
187
|
+
throw new Error('--after must precede --before');
|
|
188
|
+
if (flags.has('--interrupt') && !flags.get('--sessionkey'))
|
|
189
|
+
throw new Error('--interrupt requires --sessionkey');
|
|
190
|
+
return {
|
|
191
|
+
agent,
|
|
192
|
+
action: flags.has('--clear') ? 'clear' : flags.has('--cancel') ? 'cancel' : flags.has('--interrupt') ? 'interrupt' : undefined,
|
|
193
|
+
messageId: flags.get('--cancel'), sessionKey: flags.get('--sessionkey'), after, before,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
150
196
|
function renderQueueItemsCli(items, showId, full, aid) {
|
|
151
197
|
const lines = [`${aid} — 队列 (${items.length} 条)`, ''];
|
|
152
198
|
if (items.length === 0) {
|
package/dist/cli/response.js
CHANGED
|
@@ -57,7 +57,7 @@ function fail(formatJson, code, message) {
|
|
|
57
57
|
}
|
|
58
58
|
process.exit(1);
|
|
59
59
|
}
|
|
60
|
-
async function
|
|
60
|
+
async function runManagedResponse(args, formatJson) {
|
|
61
61
|
const sessionId = process.env.EVOLCORE_SESSION_ID;
|
|
62
62
|
const delegationToken = readDelegationCredential();
|
|
63
63
|
if (!sessionId)
|
|
@@ -65,62 +65,13 @@ async function managedConfig(fieldArgs, formatJson) {
|
|
|
65
65
|
if (!delegationToken)
|
|
66
66
|
fail(formatJson, 'DELEGATION_REQUIRED', `${AGENT_DELEGATION_TOKEN_ENV} is not set`);
|
|
67
67
|
const response = await ipcQuery(resolvePaths().socket, {
|
|
68
|
-
type: '
|
|
69
|
-
argv: ['config', ...fieldArgs],
|
|
70
|
-
sessionId,
|
|
71
|
-
delegationToken,
|
|
68
|
+
type: 'ctl', argv: ['response', ...args], sessionId, delegationToken,
|
|
72
69
|
}, 10_000);
|
|
73
70
|
if (!response)
|
|
74
71
|
fail(formatJson, 'DAEMON_UNAVAILABLE', 'Unable to connect to the evolcore daemon');
|
|
75
|
-
if (!response.ok
|
|
76
|
-
fail(formatJson, response.code || '
|
|
77
|
-
}
|
|
78
|
-
return response.result;
|
|
79
|
-
}
|
|
80
|
-
async function runManagedResponse(args, formatJson) {
|
|
81
|
-
if (getArgValue(args, '--self') || getArgValue(args, '--peer')) {
|
|
82
|
-
fail(formatJson, 'NOT_ALLOWED', 'Managed response commands always use the authenticated current relation');
|
|
83
|
-
}
|
|
84
|
-
const sub = args[0];
|
|
85
|
-
if (sub === 'set') {
|
|
86
|
-
const id = args[1];
|
|
87
|
-
if (!id)
|
|
88
|
-
fail(formatJson, 'MISSING_ID', 'set requires a mode id');
|
|
89
|
-
if (!buildRegistry().has(id))
|
|
90
|
-
fail(formatJson, 'UNKNOWN_MODE', `Unknown mode: ${id}`);
|
|
91
|
-
await managedConfig(['set', RESPONSE_MODE_FIELD, id], formatJson);
|
|
92
|
-
return emit(formatJson, { ok: true, scope: 'relation', mode: id }, () => `✓ 已设置响应模式为 ${id}(作用域: relation)`);
|
|
93
|
-
}
|
|
94
|
-
if (sub === 'reset') {
|
|
95
|
-
await managedConfig(['unset', RESPONSE_MODE_FIELD], formatJson);
|
|
96
|
-
return emit(formatJson, { ok: true, scope: 'relation' }, () => '✓ 已清除当前关系的响应模式设置');
|
|
97
|
-
}
|
|
98
|
-
if (sub === 'current') {
|
|
99
|
-
const modeResult = await managedConfig(['get', RESPONSE_MODE_FIELD], formatJson);
|
|
100
|
-
const paramsResult = await managedConfig(['get', RESPONSE_MODE_PARAMS_FIELD], formatJson);
|
|
101
|
-
const configuredMode = typeof modeResult.value === 'string' ? modeResult.value : undefined;
|
|
102
|
-
const mode = configuredMode ?? buildRegistry().getPreferredId();
|
|
103
|
-
return emit(formatJson, {
|
|
104
|
-
ok: true,
|
|
105
|
-
scope: 'relation',
|
|
106
|
-
responseMode: mode ?? null,
|
|
107
|
-
source: configuredMode ? 'config' : 'preferred',
|
|
108
|
-
sourceTarget: modeResult.source?.target ?? null,
|
|
109
|
-
responseModeParams: paramsResult.value ?? null,
|
|
110
|
-
}, () => `当前响应模式: ${mode ?? '(无)'}`);
|
|
111
|
-
}
|
|
112
|
-
if (sub === 'config') {
|
|
113
|
-
if (args[1] === 'set') {
|
|
114
|
-
fail(formatJson, 'NOT_ALLOWED', 'responseModeParams cannot be modified as an opaque object from a managed task');
|
|
115
|
-
}
|
|
116
|
-
const result = await managedConfig(['get', RESPONSE_MODE_PARAMS_FIELD], formatJson);
|
|
117
|
-
const params = result.value ?? {};
|
|
118
|
-
const modeId = args[1] && !args[1].startsWith('--') ? args[1] : undefined;
|
|
119
|
-
if (modeId)
|
|
120
|
-
return emit(formatJson, { ok: true, mode: modeId, config: params[modeId] ?? {} }, () => `${modeId} 配置: ${JSON.stringify(params[modeId] ?? {}, null, 2)}`);
|
|
121
|
-
return emit(formatJson, { ok: true, responseModeParams: params }, () => `所有模式配置: ${JSON.stringify(params, null, 2)}`);
|
|
122
|
-
}
|
|
123
|
-
fail(formatJson, 'NOT_ALLOWED', `response ${sub} is not available in a managed task`);
|
|
72
|
+
if (!response.ok)
|
|
73
|
+
fail(formatJson, response.code || 'CTL_FAILED', response.error || 'response operation failed');
|
|
74
|
+
emit(formatJson, response.data ?? { ok: true, result: response.result }, () => response.result || 'ok');
|
|
124
75
|
}
|
|
125
76
|
/** 解析 --self / --peer 为作用域选择器 */
|
|
126
77
|
function parseSelector(args, formatJson) {
|
|
@@ -17,21 +17,27 @@
|
|
|
17
17
|
import path from 'path';
|
|
18
18
|
import { spawn } from 'child_process';
|
|
19
19
|
import { getPackageRoot, agentDir } from '../paths.js';
|
|
20
|
-
import { readTaskRuntimeContextFromEnv } from './task-context.js';
|
|
20
|
+
import { authorizeLocalCommand, readTaskRuntimeContextFromEnv, TASK_RUNTIME_CONTEXT_ENV } from './task-context.js';
|
|
21
21
|
export async function cmdSkill(args) {
|
|
22
22
|
const script = path.join(getPackageRoot(), 'kits', 'skills', 'ec-skill', 'scripts', 'cli.mjs');
|
|
23
23
|
// 脚本在包外运行,拿不到主程序的路径工具,这里把 Agent 目录显式传进去,
|
|
24
24
|
// 让它能定位 Agent 级 skills/ 与 .switches.json。
|
|
25
25
|
// selfAid 优先取任务运行时上下文(托管会话的权威来源),其次环境变量。
|
|
26
26
|
const env = { ...process.env };
|
|
27
|
-
const
|
|
28
|
-
|
|
27
|
+
const runtime = process.env.EVOLCORE_SESSION_ID ? await authorizeLocalCommand(['skill', ...args]) : undefined;
|
|
28
|
+
const selfAid = runtime?.selfAid ?? readTaskRuntimeContextFromEnv()?.selfAid ?? process.env.EVOLCORE_SELF_AID;
|
|
29
|
+
if (runtime) {
|
|
30
|
+
env[TASK_RUNTIME_CONTEXT_ENV] = JSON.stringify(runtime);
|
|
31
|
+
env.EVOLCORE_SELF_AID = selfAid;
|
|
32
|
+
}
|
|
33
|
+
if (selfAid && (runtime || !env.EVOLCORE_AGENT_DIR)) {
|
|
29
34
|
env.EVOLCORE_AGENT_DIR = agentDir(selfAid);
|
|
30
35
|
}
|
|
31
36
|
const code = await new Promise((resolve, reject) => {
|
|
32
37
|
const child = spawn(process.execPath, [script, ...args], {
|
|
33
38
|
stdio: 'inherit',
|
|
34
39
|
env,
|
|
40
|
+
cwd: runtime?.projectPath,
|
|
35
41
|
});
|
|
36
42
|
child.on('error', reject);
|
|
37
43
|
child.on('exit', (c) => resolve(c ?? 0));
|
package/dist/cli/stats.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { resolveRoot } from '../paths.js';
|
|
5
5
|
import { wantsHelp } from './help.js';
|
|
6
|
-
import {
|
|
6
|
+
import { authorizeLocalCommand } from './task-context.js';
|
|
7
7
|
import { queryAggregated, querySessionTurns, queryContextBreakdown, queryTopPeers, queryTopModels, queryMessageAggregated, queryPeerList, querySummary, queryPeerDaily, queryTaskModelCalls, querySessionModelCalls } from '../stats/query.js';
|
|
8
8
|
import { getBudgetStatus } from '../stats/budget.js';
|
|
9
9
|
const HELP = `ec stats — Token 用量与费用统计
|
|
@@ -124,10 +124,16 @@ const AGENT_SCOPE_ROLES = new Set(['owner', 'admin']);
|
|
|
124
124
|
* is confined to its own relation and session. Returns undefined outside a
|
|
125
125
|
* managed task, leaving direct terminal usage unchanged.
|
|
126
126
|
*/
|
|
127
|
-
async function resolveManagedStatsScope(flags, isJson) {
|
|
127
|
+
async function resolveManagedStatsScope(flags, isJson, argv) {
|
|
128
128
|
if (!process.env.EVOLCORE_SESSION_ID)
|
|
129
129
|
return undefined;
|
|
130
|
-
|
|
130
|
+
let runtime;
|
|
131
|
+
try {
|
|
132
|
+
runtime = await authorizeLocalCommand(argv);
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
fail(isJson, 'NOT_ALLOWED', error instanceof Error ? error.message : String(error));
|
|
136
|
+
}
|
|
131
137
|
const role = runtime?.peerRole?.trim();
|
|
132
138
|
const selfAid = runtime?.selfAid?.trim();
|
|
133
139
|
// Fail closed: without a resolved identity and role there is no scope to
|
|
@@ -225,7 +231,7 @@ export async function handleStats(args) {
|
|
|
225
231
|
const isJson = flags.format === 'json';
|
|
226
232
|
// Authorize before any branch runs: `--rebuild` writes, and every read view
|
|
227
233
|
// below would otherwise see the whole database.
|
|
228
|
-
const managedScope = await resolveManagedStatsScope(flags, isJson);
|
|
234
|
+
const managedScope = await resolveManagedStatsScope(flags, isJson, ['stats', ...args]);
|
|
229
235
|
if (managedScope)
|
|
230
236
|
enforceManagedSelector(managedScope, flags, isJson);
|
|
231
237
|
// 全量重建日聚合表(运维兜底/排查),不依赖时间范围。
|
package/dist/cli/task-command.js
CHANGED