evolcore 0.0.33 → 0.0.35-test.0
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 +59 -0
- package/bin/ec.js +3 -2
- package/bin/install-codex-managed-hooks.mjs +38 -4
- package/dist/agents/baseagent-availability.js +20 -36
- package/dist/agents/claude-runner.js +93 -14
- package/dist/agents/codex/diagnostics.js +79 -22
- package/dist/agents/codex-runner.js +245 -47
- package/dist/agents/ecagent-runner.js +90 -27
- package/dist/agents/runner-types.js +5 -6
- package/dist/aun/aid/agentmd.js +13 -2
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/identity.js +1 -1
- package/dist/aun/msg/managed-operation.js +16 -0
- package/dist/aun/msg/p2p.js +18 -2
- package/dist/channels/aun.js +123 -7
- package/dist/channels/daemon.js +6 -3
- package/dist/cli/aun-commands.js +39 -14
- package/dist/cli/ctl-command.js +3 -1
- package/dist/cli/daemon-commands.js +130 -23
- package/dist/cli/fs-command.js +2 -1
- package/dist/cli/getmeta-command.js +211 -0
- package/dist/cli/index.js +26 -6
- package/dist/cli/integrity-command.js +196 -0
- package/dist/cli/managed-command-guard.js +3 -0
- package/dist/cli/memory-command.js +200 -156
- package/dist/cli/thread-command.js +17 -7
- package/dist/cli/trigger-command.js +6 -1
- package/dist/config/config-field-policy.js +4 -0
- package/dist/config/config-manager.js +19 -0
- package/dist/config/contact-book-store.js +5 -0
- package/dist/config/resolved-config-op.js +25 -8
- package/dist/config/role-service.js +13 -0
- package/dist/config/runtime-env.js +16 -0
- package/dist/config-store.js +30 -0
- package/dist/core/audit/log-integrity.js +3 -1
- package/dist/core/auth/agent-delegation.js +108 -35
- package/dist/core/auth/delegation-diagnostics.js +414 -0
- package/dist/core/auth/operation-authorizer.js +22 -3
- package/dist/core/auth/operation-catalog.js +16 -0
- package/dist/core/channel-runtime.js +1 -1
- package/dist/core/command/agent-control.js +18 -26
- package/dist/core/command/command-handler.js +145 -5
- package/dist/core/command/daemon-diagnostics.js +1 -0
- package/dist/core/command/menu-catalog.js +3 -0
- package/dist/core/command/menu-handler.js +24 -7
- package/dist/core/command/menu-protocol.js +1 -0
- package/dist/core/command/slash-handler.js +2 -0
- package/dist/core/command/topic-slash.js +4 -7
- package/dist/core/daemon-bootstrap.js +4 -7
- package/dist/core/event-catalog.js +14 -0
- package/dist/core/file-integrity/read.js +61 -0
- package/dist/core/file-integrity/store.js +262 -0
- package/dist/core/ipc-registration.js +47 -2
- package/dist/core/memory/batch-meta.js +133 -0
- package/dist/core/memory/consolidation-context.js +132 -28
- package/dist/core/memory/consolidation-ops-records.js +14 -16
- package/dist/core/memory/consolidation-trigger.js +15 -7
- package/dist/core/memory/consolidation.js +146 -26
- package/dist/core/memory/index-manager.js +19 -28
- package/dist/core/memory/memory-admin.js +19 -14
- package/dist/core/memory/memory-document.js +53 -9
- package/dist/core/memory/memory-writer.js +50 -19
- package/dist/core/message/aun-ipc-sender.js +19 -1
- package/dist/core/message/im-renderer.js +20 -4
- package/dist/core/message/message-bridge.js +5 -4
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/peer-mode.js +17 -0
- package/dist/core/message/response-engine.js +598 -50
- package/dist/core/permission/ec-command-parser.js +169 -44
- package/dist/core/permission/protected-paths.js +5 -1
- package/dist/core/permission/readonly-shell-query.js +43 -5
- package/dist/core/permission/session-path-grants.js +334 -0
- package/dist/core/permission/tool-canonical.js +226 -0
- package/dist/core/permission/tool-policy.js +60 -62
- package/dist/core/relation/peer-identity.js +87 -12
- package/dist/core/role/runtime-policy.js +21 -10
- package/dist/core/session/session-fs-store.js +123 -8
- package/dist/core/session/session-manager.js +131 -6
- package/dist/core/session/session-title.js +26 -1
- package/dist/core/skill/index-generator.js +17 -3
- package/dist/core/system-session/grants.js +40 -0
- package/dist/core/system-session/memory.js +289 -0
- package/dist/core/system-session/registry.js +74 -0
- package/dist/core/system-session/types.js +14 -0
- package/dist/core/thread/command-parser.js +6 -1
- package/dist/core/thread/ipc-operation.js +33 -16
- package/dist/core/thread/thread-operation.js +62 -24
- package/dist/core/thread/thread-service.js +258 -51
- package/dist/eck/kit-renderer.js +7 -2
- package/dist/eck/manifest-engine.js +24 -4
- package/dist/index.js +11 -2
- package/dist/ipc.js +51 -40
- package/dist/paths.js +70 -0
- package/dist/stats/billing.js +20 -8
- package/dist/trigger/feedback.js +6 -1
- package/dist/trigger/parser.js +8 -1
- package/dist/trigger/system-definitions.js +3 -3
- package/dist/utils/cross-platform.js +17 -5
- package/dist/utils/error-dict.json +18 -4
- package/dist/utils/error-utils.js +121 -0
- package/dist/utils/instance-registry.js +13 -8
- package/dist/utils/log-writer.js +12 -0
- package/dist/utils/process-introspect.js +11 -0
- package/kits/docs/context-assembly.md +0 -1
- package/kits/docs/evolcore/agent-create.md +5 -4
- package/kits/docs/evolcore/agent.md +2 -2
- package/kits/docs/evolcore/config.md +2 -2
- package/kits/docs/evolcore/ctl.md +2 -2
- package/kits/docs/evolcore/ec-capabilities.md +1 -1
- package/kits/docs/evolcore/fs-architecture.md +9 -10
- package/kits/docs/evolcore/fs.md +2 -2
- package/kits/docs/evolcore/group-collaboration.md +3 -3
- package/kits/docs/evolcore/group.md +14 -12
- package/kits/docs/evolcore/memory-architecture.md +4 -5
- package/kits/docs/evolcore/memory-consolidation.md +19 -16
- package/kits/docs/evolcore/memory-tags.md +3 -1
- package/kits/docs/evolcore/memory.md +24 -12
- package/kits/docs/evolcore/model.md +16 -0
- package/kits/docs/evolcore/msg.md +7 -7
- package/kits/docs/evolcore/stats.md +1 -1
- package/kits/docs/evolcore/thread-chain.md +30 -14
- package/kits/docs/prompt-loading-architecture.md +0 -1
- package/kits/eck_manifest.auxiliary.json +9 -0
- package/kits/eck_manifest.json +20 -20
- package/kits/eck_manifest.memory.json +20 -12
- package/kits/rules/01-overview.md +11 -0
- package/kits/rules/03-identity.md +6 -3
- package/kits/rules/06-channel.md +1 -1
- package/kits/rules/07-memory-and-thread.md +13 -16
- package/kits/schemas/_meta.json +7 -1
- package/kits/schemas/agent-config.schema.13.json +1 -1
- package/kits/schemas/daemon.schema.7.json +140 -0
- package/kits/skills/ec-group/SKILL.md +8 -5
- package/kits/skills/ec-skill/scripts/cli.mjs +1 -1
- package/kits/skills/ec-skill/scripts/skill.mjs +1 -1
- package/kits/skills/thread-ops/SKILL.md +18 -18
- package/kits/templates/memory-consolidation/forget.md +2 -2
- package/kits/templates/memory-consolidation/generalize.md +4 -4
- package/kits/templates/memory-consolidation/notes.md +12 -12
- package/kits/templates/memory-consolidation/profile.md +3 -3
- package/kits/templates/memory-consolidation/promote.md +3 -3
- package/kits/templates/memory-consolidation/workflow.md +42 -7
- package/kits/templates/message-fragments/handoff-request-to-target.md +1 -1
- package/kits/templates/system-fragments/bash-description.md +9 -0
- package/kits/templates/system-fragments/bootstrap.md +4 -3
- package/kits/templates/system-fragments/channel.md +2 -2
- package/kits/templates/system-fragments/memory.md +16 -9
- package/kits/templates/system-fragments/reply.md +6 -6
- package/kits/templates/system-fragments/session.md +1 -1
- package/package.json +4 -3
- package/dist/core/memory/memory-session-policy.js +0 -41
- package/dist/core/memory/memory-signature.js +0 -257
|
@@ -619,6 +619,10 @@ function isLiteralArgBoundary(value) {
|
|
|
619
619
|
* 判为 `shell-composition`,拦截力度不变,只让错误归因准确。
|
|
620
620
|
*/
|
|
621
621
|
function isPosixQuotedTokenBoundary(value) {
|
|
622
|
+
// 相邻引号段直接拼接(`'a''b'`、`$'a''b'`、`'a'"b"`)与 bash 一致:
|
|
623
|
+
// 闭合引号后紧跟另一个开引号不是错误,两个段拼进同一个 token。
|
|
624
|
+
if (value === "'" || value === '"')
|
|
625
|
+
return true;
|
|
622
626
|
return value === undefined || isShellSpacing(value) || SHELL_UNQUOTED_META.has(value);
|
|
623
627
|
}
|
|
624
628
|
function isShellParameterExpansionStart(value) {
|
|
@@ -714,6 +718,77 @@ function decodePositionalText(argv, start, optionFlags) {
|
|
|
714
718
|
argv[index] = decodeEvolcoreInlineText(value);
|
|
715
719
|
}
|
|
716
720
|
}
|
|
721
|
+
// 取值为「逗号分隔、单项不含空格」的列表参数。aid、标签值、角色名里都不会有
|
|
722
|
+
// 空格,所以按空格拆分是安全的。
|
|
723
|
+
const MEMORY_LIST_FLAGS = new Set(['--tags', '--speakers']);
|
|
724
|
+
const SEND_LIST_FLAGS = new Set(['--mention']);
|
|
725
|
+
const FS_LIST_FLAGS = new Set(['--allow-roles']);
|
|
726
|
+
// 取值可能含空格的列表参数,只能按逗号拆:关键词是自由文本,记忆路径是 config
|
|
727
|
+
// 相对路径,两者都可能有空格。
|
|
728
|
+
const MEMORY_COMMA_ONLY_FLAGS = new Set(['--keywords', '--replaces']);
|
|
729
|
+
/** 逗号分隔项:去空、去首尾空白,重新用逗号连接。 */
|
|
730
|
+
function joinCommaList(value) {
|
|
731
|
+
return value.split(',').map(item => item.trim()).filter(Boolean).join(',');
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* 把列表参数统一成逗号分隔。PowerShell 把未加引号的 `a,b` 当数组,经 npm 的
|
|
735
|
+
* ec.ps1 用 `$args` 转发给 node 时逗号消失:`a,b` 变成 `a b`,`a, b` 和
|
|
736
|
+
* `a,b, c` 也变成 `a b` / `a b c`(实测 PS 5.1)。审批侧按命令串解析时看到的
|
|
737
|
+
* 是 `a,` 和 `b` 两个 token。两边在这里收敛到同一表示,委托哈希才能对上。
|
|
738
|
+
*
|
|
739
|
+
* 值以逗号结尾说明逗号数组还没结束:把后续 token 并进同一个值里再拆。值里本来
|
|
740
|
+
* 带逗号却没有空格的写法(bash 下 `--tags "a, b"`)也会被拆成两个标签,这是刻
|
|
741
|
+
* 意取舍——标签都是不含空格的单词,而 ec.ps1 已经把 `a, b` 和 `a,b` 归成了一
|
|
742
|
+
* 个值,无法再区分。
|
|
743
|
+
*/
|
|
744
|
+
function canonicalizeListFlags(argv, flags) {
|
|
745
|
+
for (let index = 0; index < argv.length; index++) {
|
|
746
|
+
const value = argv[index];
|
|
747
|
+
if (value === '--')
|
|
748
|
+
break;
|
|
749
|
+
if (!flags.has(value))
|
|
750
|
+
continue;
|
|
751
|
+
if (argv[index + 1] === undefined || argv[index + 1].startsWith('--'))
|
|
752
|
+
continue;
|
|
753
|
+
// `--tags a, b` 在 PowerShell 里是同一个值,审批侧却解析成 `a,` 加 `b`,
|
|
754
|
+
// 这里按逗号是否收尾把后续 token 续接回来
|
|
755
|
+
let end = index + 1;
|
|
756
|
+
while (argv[end].endsWith(',') && argv[end + 1] !== undefined
|
|
757
|
+
&& !argv[end + 1].startsWith('--')) {
|
|
758
|
+
end++;
|
|
759
|
+
}
|
|
760
|
+
argv[index + 1] = argv.slice(index + 1, end + 1)
|
|
761
|
+
.join(' ')
|
|
762
|
+
.split(/[,\s]+/u)
|
|
763
|
+
.filter(Boolean)
|
|
764
|
+
.join(',');
|
|
765
|
+
if (end > index + 1)
|
|
766
|
+
argv.splice(index + 2, end - index - 1);
|
|
767
|
+
index++;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* 只按逗号归一化,不动值里的空格。
|
|
772
|
+
*
|
|
773
|
+
* 与 canonicalizeListFlags 的区别:`--keywords 'a b'` 是一个含空格的关键词,
|
|
774
|
+
* 不能被拆成两个。所以只在值本身带逗号时整理(顺带去掉逗号周围的空白),
|
|
775
|
+
* `--keywords a,b` 这种未加引号的写法在 PowerShell 下会先被折成 `a b`,此处
|
|
776
|
+
* 认不出来——那属于被拒绝的写法,靠规范要求单引号避免。
|
|
777
|
+
*/
|
|
778
|
+
function canonicalizeCommaOnlyFlags(argv, flags) {
|
|
779
|
+
for (let index = 0; index < argv.length; index++) {
|
|
780
|
+
const value = argv[index];
|
|
781
|
+
if (value === '--')
|
|
782
|
+
break;
|
|
783
|
+
if (!flags.has(value))
|
|
784
|
+
continue;
|
|
785
|
+
const next = argv[index + 1];
|
|
786
|
+
if (next === undefined || next.startsWith('--') || !next.includes(','))
|
|
787
|
+
continue;
|
|
788
|
+
argv[index + 1] = joinCommaList(next);
|
|
789
|
+
index++;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
717
792
|
function canonicalizeHandoffText(argv) {
|
|
718
793
|
const action = argv[2];
|
|
719
794
|
if (action !== 'return' && action !== 'recover-return')
|
|
@@ -739,7 +814,8 @@ function canonicalizeHandoffText(argv) {
|
|
|
739
814
|
* Convert an EC invocation to the one argv representation shared by approval,
|
|
740
815
|
* delegation hashing, IPC, and command execution. Shell syntax is already
|
|
741
816
|
* resolved before this function is called; this function only normalizes the
|
|
742
|
-
* EC entrypoint
|
|
817
|
+
* EC entrypoint, applies the command-specific inline text contract, and joins
|
|
818
|
+
* memory list flags with commas.
|
|
743
819
|
*/
|
|
744
820
|
export function canonicalizeEvolcoreCommandArgv(argv) {
|
|
745
821
|
const canonical = normalizeEvolcoreCommandArgv(argv);
|
|
@@ -759,11 +835,13 @@ export function canonicalizeEvolcoreCommandArgv(argv) {
|
|
|
759
835
|
else if (command === 'msg' && subcommand === 'send') {
|
|
760
836
|
decodeInlineFlags(result, INLINE_TEXT_FLAGS.msgSend);
|
|
761
837
|
decodePositionalText(result, 5, MESSAGE_POSITIONAL_FLAGS);
|
|
838
|
+
canonicalizeListFlags(result, SEND_LIST_FLAGS);
|
|
762
839
|
}
|
|
763
840
|
else if (command === 'group') {
|
|
764
841
|
if (subcommand === 'send') {
|
|
765
842
|
decodeInlineFlags(result, INLINE_TEXT_FLAGS.groupSend);
|
|
766
843
|
decodePositionalText(result, 5, MESSAGE_POSITIONAL_FLAGS);
|
|
844
|
+
canonicalizeListFlags(result, SEND_LIST_FLAGS);
|
|
767
845
|
}
|
|
768
846
|
else if (subcommand === 'create')
|
|
769
847
|
decodeInlineFlags(result, INLINE_TEXT_FLAGS.groupCreate);
|
|
@@ -785,6 +863,13 @@ export function canonicalizeEvolcoreCommandArgv(argv) {
|
|
|
785
863
|
else if (command === 'handoff') {
|
|
786
864
|
canonicalizeHandoffText(result);
|
|
787
865
|
}
|
|
866
|
+
else if (command === 'memory') {
|
|
867
|
+
canonicalizeListFlags(result, MEMORY_LIST_FLAGS);
|
|
868
|
+
canonicalizeCommaOnlyFlags(result, MEMORY_COMMA_ONLY_FLAGS);
|
|
869
|
+
}
|
|
870
|
+
else if (command === 'fs' && subcommand === 'chmod') {
|
|
871
|
+
canonicalizeListFlags(result, FS_LIST_FLAGS);
|
|
872
|
+
}
|
|
788
873
|
return result;
|
|
789
874
|
}
|
|
790
875
|
const POWERSHELL_CREDENTIAL_ENV_RE = /^(EVOLCORE_CODEX_SESSION_TOKEN|EVOLCORE_DELEGATION_TOKEN)$/i;
|
|
@@ -1496,6 +1581,8 @@ export function parseLiteralShellCommand(command, options = {}) {
|
|
|
1496
1581
|
let token = '';
|
|
1497
1582
|
let tokenStarted = false;
|
|
1498
1583
|
let quote = null;
|
|
1584
|
+
// EC 命令的自由文本有额外的写法约束(见双引号分支的反引号/$ 转义处理)。
|
|
1585
|
+
const isEcCommand = hasEcCommandPrefix(input);
|
|
1499
1586
|
const finishToken = () => {
|
|
1500
1587
|
if (!tokenStarted)
|
|
1501
1588
|
return;
|
|
@@ -1527,6 +1614,12 @@ export function parseLiteralShellCommand(command, options = {}) {
|
|
|
1527
1614
|
return parseFailure(issue, input, index, argv.length, 'posix');
|
|
1528
1615
|
if (char === '\\') {
|
|
1529
1616
|
const next = input[++index];
|
|
1617
|
+
// EC 自由文本只接受单引号一种写法。双引号里用反斜杠转义 ` 或 $ 虽然
|
|
1618
|
+
// 能得到字面量,但同一条规则下要记两套写法,所以对 ec 命令显式拒绝,
|
|
1619
|
+
// 把正文一律导向单引号。非 ec 命令保持原行为。
|
|
1620
|
+
if (isEcCommand && (next === '`' || next === '$')) {
|
|
1621
|
+
return parseFailure('unsupported-escape', input, index, argv.length, 'posix');
|
|
1622
|
+
}
|
|
1530
1623
|
token += ['"', '\\', '$', '`'].includes(next) ? next : `\\${next}`;
|
|
1531
1624
|
continue;
|
|
1532
1625
|
}
|
|
@@ -1568,6 +1661,54 @@ export function parseLiteralShellCommand(command, options = {}) {
|
|
|
1568
1661
|
token += next;
|
|
1569
1662
|
continue;
|
|
1570
1663
|
}
|
|
1664
|
+
// ANSI-C quoting: $'...' allows \n \t \r \\ \' escapes, same as bash $'...'.
|
|
1665
|
+
// Must be checked before SHELL_UNQUOTED_META because $ is in that set.
|
|
1666
|
+
if (char === '$' && input[index + 1] === "'") {
|
|
1667
|
+
tokenStarted = true;
|
|
1668
|
+
index += 2; // skip $ and opening '
|
|
1669
|
+
let ansiClosed = false;
|
|
1670
|
+
while (index < input.length) {
|
|
1671
|
+
const c = input[index];
|
|
1672
|
+
if (c === "'") {
|
|
1673
|
+
ansiClosed = true;
|
|
1674
|
+
break; // leave index at closing '; for-loop increment moves past it
|
|
1675
|
+
}
|
|
1676
|
+
if (c === '\\') {
|
|
1677
|
+
const esc = input[++index];
|
|
1678
|
+
if (esc === undefined)
|
|
1679
|
+
break;
|
|
1680
|
+
switch (esc) {
|
|
1681
|
+
case 'n':
|
|
1682
|
+
token += '\n';
|
|
1683
|
+
break;
|
|
1684
|
+
case 't':
|
|
1685
|
+
token += '\t';
|
|
1686
|
+
break;
|
|
1687
|
+
case 'r':
|
|
1688
|
+
token += '\r';
|
|
1689
|
+
break;
|
|
1690
|
+
case '\\':
|
|
1691
|
+
token += '\\';
|
|
1692
|
+
break;
|
|
1693
|
+
case "'":
|
|
1694
|
+
token += "'";
|
|
1695
|
+
break;
|
|
1696
|
+
default:
|
|
1697
|
+
token += `\\${esc}`;
|
|
1698
|
+
break;
|
|
1699
|
+
}
|
|
1700
|
+
index++;
|
|
1701
|
+
continue;
|
|
1702
|
+
}
|
|
1703
|
+
token += c;
|
|
1704
|
+
index++;
|
|
1705
|
+
}
|
|
1706
|
+
if (!ansiClosed)
|
|
1707
|
+
return parseFailure('invalid-quote', input, index, argv.length, 'posix');
|
|
1708
|
+
if (!isPosixQuotedTokenBoundary(input[index + 1]))
|
|
1709
|
+
return parseFailure('invalid-quote', input, index, argv.length, 'posix');
|
|
1710
|
+
continue;
|
|
1711
|
+
}
|
|
1571
1712
|
// `#` starts a shell comment only at the beginning of a word. Channel
|
|
1572
1713
|
// peer keys such as `aun#alice` are ordinary literal arguments.
|
|
1573
1714
|
if ((SHELL_UNQUOTED_META.has(char) && (char !== '#' || !tokenStarted))
|
|
@@ -1623,6 +1764,11 @@ export function parseCodexShellCommandArgv(command, options = {}) {
|
|
|
1623
1764
|
});
|
|
1624
1765
|
return parsed.ok ? canonicalizeEvolcoreCommandArgv(parsed.argv) : null;
|
|
1625
1766
|
}
|
|
1767
|
+
const stringCarrier = resolveCodexShellCarrierString(command);
|
|
1768
|
+
if (stringCarrier) {
|
|
1769
|
+
const parsed = parseCodexCarrierCommand(stringCarrier, options);
|
|
1770
|
+
return parsed.ok ? normalizeEvolcoreCommandArgv(parsed.argv) : null;
|
|
1771
|
+
}
|
|
1626
1772
|
const outer = parseLiteralShellArgv(command, options);
|
|
1627
1773
|
if (outer) {
|
|
1628
1774
|
const carrier = resolveCodexShellCarrierArgv(outer);
|
|
@@ -1630,20 +1776,11 @@ export function parseCodexShellCommandArgv(command, options = {}) {
|
|
|
1630
1776
|
const parsed = parseCodexCarrierCommand(carrier, options);
|
|
1631
1777
|
return parsed.ok ? parsed.argv : null;
|
|
1632
1778
|
}
|
|
1633
|
-
const stringCarrier = resolveCodexShellCarrierString(command);
|
|
1634
|
-
if (stringCarrier) {
|
|
1635
|
-
const parsed = parseCodexCarrierCommand(stringCarrier, options);
|
|
1636
|
-
return parsed.ok ? parsed.argv : null;
|
|
1637
|
-
}
|
|
1638
1779
|
if (parseCodexCmdCarrierStringFailure(command, options))
|
|
1639
1780
|
return null;
|
|
1640
1781
|
return normalizeEvolcoreCommandArgv(outer);
|
|
1641
1782
|
}
|
|
1642
|
-
|
|
1643
|
-
if (!stringCarrier)
|
|
1644
|
-
return null;
|
|
1645
|
-
const parsed = parseCodexCarrierCommand(stringCarrier, options);
|
|
1646
|
-
return parsed.ok ? normalizeEvolcoreCommandArgv(parsed.argv) : null;
|
|
1783
|
+
return null;
|
|
1647
1784
|
}
|
|
1648
1785
|
/** Parse a Codex tool input while preserving safe syntax failure metadata. */
|
|
1649
1786
|
export function parseCodexToolCommand(input, options = {}) {
|
|
@@ -1687,22 +1824,20 @@ export function parseCodexToolCommand(input, options = {}) {
|
|
|
1687
1824
|
? { ...parsed, argv: normalizeEvolcoreCommandArgv(parsed.argv) }
|
|
1688
1825
|
: parsed;
|
|
1689
1826
|
}
|
|
1827
|
+
const stringCarrier = resolveCodexShellCarrierString(command);
|
|
1828
|
+
if (stringCarrier) {
|
|
1829
|
+
return parseCodexCarrierCommand(stringCarrier, { allowManagedTmpDir: true, ...options });
|
|
1830
|
+
}
|
|
1690
1831
|
const outer = parseLiteralShellCommand(command, { allowManagedTmpDir: true });
|
|
1691
1832
|
if (outer.ok) {
|
|
1692
1833
|
const carrier = resolveCodexShellCarrierArgv(outer.argv);
|
|
1693
1834
|
if (carrier !== undefined) {
|
|
1694
1835
|
return parseCodexCarrierCommand(carrier, { allowManagedTmpDir: true, ...options });
|
|
1695
1836
|
}
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
? parseCodexCarrierCommand(stringCarrier, { allowManagedTmpDir: true, ...options })
|
|
1699
|
-
: parseCodexCmdCarrierStringFailure(command, { allowManagedTmpDir: true })
|
|
1700
|
-
?? { ...outer, argv: normalizeEvolcoreCommandArgv(outer.argv) };
|
|
1837
|
+
return parseCodexCmdCarrierStringFailure(command, { allowManagedTmpDir: true })
|
|
1838
|
+
?? { ...outer, argv: normalizeEvolcoreCommandArgv(outer.argv) };
|
|
1701
1839
|
}
|
|
1702
|
-
|
|
1703
|
-
return stringCarrier
|
|
1704
|
-
? parseCodexCarrierCommand(stringCarrier, { allowManagedTmpDir: true, ...options })
|
|
1705
|
-
: parseCodexCmdCarrierStringFailure(command, { allowManagedTmpDir: true }) ?? outer;
|
|
1840
|
+
return parseCodexCmdCarrierStringFailure(command, { allowManagedTmpDir: true }) ?? outer;
|
|
1706
1841
|
}
|
|
1707
1842
|
function isApplyPatchExecutable(value) {
|
|
1708
1843
|
const normalized = value.replaceAll('\\', '/').replace(/\/+$/u, '');
|
|
@@ -1715,7 +1850,7 @@ function normalizeApplyPatchPath(value) {
|
|
|
1715
1850
|
return undefined;
|
|
1716
1851
|
return normalized;
|
|
1717
1852
|
}
|
|
1718
|
-
function parseApplyPatchDocument(source) {
|
|
1853
|
+
export function parseApplyPatchDocument(source) {
|
|
1719
1854
|
const lines = source.replace(/\r\n?/gu, '\n').split('\n');
|
|
1720
1855
|
while (lines.at(-1) === '')
|
|
1721
1856
|
lines.pop();
|
|
@@ -2658,6 +2793,17 @@ export function classifyEvolcoreShellCommand(command, options = {}) {
|
|
|
2658
2793
|
});
|
|
2659
2794
|
return { kind: 'composite', issue: parsed.ok ? 'shell-composition' : parsed.issue };
|
|
2660
2795
|
}
|
|
2796
|
+
const stringCarrier = resolveCodexShellCarrierString(stripped);
|
|
2797
|
+
if (stringCarrier) {
|
|
2798
|
+
const nested = parseCodexCarrierCommand(stringCarrier, parseOptions);
|
|
2799
|
+
if (nested.ok && nested.argv[0] === 'ec')
|
|
2800
|
+
return { kind: 'literal' };
|
|
2801
|
+
if (!nested.ok && (hasCarrierEcCommandPrefix(stringCarrier.command, stringCarrier.dialect)
|
|
2802
|
+
|| (stringCarrier.dialect === 'powershell' && hasPowerShellCredentialAssignment(stringCarrier.command)))) {
|
|
2803
|
+
return { kind: 'composite', issue: nested.issue };
|
|
2804
|
+
}
|
|
2805
|
+
return { kind: 'none' };
|
|
2806
|
+
}
|
|
2661
2807
|
const literal = parseLiteralShellCommand(stripped, parseOptions);
|
|
2662
2808
|
if (literal.ok) {
|
|
2663
2809
|
if (normalizeEvolcoreCommandArgv(literal.argv)[0] === 'ec')
|
|
@@ -2672,16 +2818,6 @@ export function classifyEvolcoreShellCommand(command, options = {}) {
|
|
|
2672
2818
|
return { kind: 'composite', issue: nested.issue };
|
|
2673
2819
|
}
|
|
2674
2820
|
}
|
|
2675
|
-
const stringCarrier = resolveCodexShellCarrierString(stripped);
|
|
2676
|
-
if (stringCarrier) {
|
|
2677
|
-
const nested = parseCodexCarrierCommand(stringCarrier, parseOptions);
|
|
2678
|
-
if (nested.ok && nested.argv[0] === 'ec')
|
|
2679
|
-
return { kind: 'literal' };
|
|
2680
|
-
if (!nested.ok && (hasCarrierEcCommandPrefix(stringCarrier.command, stringCarrier.dialect)
|
|
2681
|
-
|| (stringCarrier.dialect === 'powershell' && hasPowerShellCredentialAssignment(stringCarrier.command)))) {
|
|
2682
|
-
return { kind: 'composite', issue: nested.issue };
|
|
2683
|
-
}
|
|
2684
|
-
}
|
|
2685
2821
|
const malformedCmdBody = extractCodexCmdCarrierBody(stripped);
|
|
2686
2822
|
if (malformedCmdBody && looksLikeEcCommandBody(malformedCmdBody)) {
|
|
2687
2823
|
const nested = parseLiteralShellCommand(malformedCmdBody, {
|
|
@@ -2694,17 +2830,6 @@ export function classifyEvolcoreShellCommand(command, options = {}) {
|
|
|
2694
2830
|
}
|
|
2695
2831
|
return { kind: 'none' };
|
|
2696
2832
|
}
|
|
2697
|
-
const stringCarrier = resolveCodexShellCarrierString(stripped);
|
|
2698
|
-
if (stringCarrier) {
|
|
2699
|
-
const nested = parseCodexCarrierCommand(stringCarrier, parseOptions);
|
|
2700
|
-
if (nested.ok && nested.argv[0] === 'ec')
|
|
2701
|
-
return { kind: 'literal' };
|
|
2702
|
-
if (!nested.ok && (hasCarrierEcCommandPrefix(stringCarrier.command, stringCarrier.dialect)
|
|
2703
|
-
|| (stringCarrier.dialect === 'powershell' && hasPowerShellCredentialAssignment(stringCarrier.command)))) {
|
|
2704
|
-
return { kind: 'composite', issue: nested.issue };
|
|
2705
|
-
}
|
|
2706
|
-
return { kind: 'none' };
|
|
2707
|
-
}
|
|
2708
2833
|
const malformedCmdBody = extractCodexCmdCarrierBody(stripped);
|
|
2709
2834
|
if (malformedCmdBody && looksLikeEcCommandBody(malformedCmdBody)) {
|
|
2710
2835
|
const nested = parseLiteralShellCommand(malformedCmdBody, {
|
|
@@ -3022,7 +3147,7 @@ export function describeProactiveSendCommandFailure(toolName, input, session) {
|
|
|
3022
3147
|
const from = argv[3];
|
|
3023
3148
|
const to = argv[4];
|
|
3024
3149
|
const fullFormHint = `${prefix}缺少发送者与目标。完整形式为 ${expectedForm};`
|
|
3025
|
-
+
|
|
3150
|
+
+ `省略 from/to 仅在带 --thread 的跨话题发送中允许,普通回复也可用 ec ctl send '<正文>' 继承当前会话。`;
|
|
3026
3151
|
if (!from || from.startsWith('--')) {
|
|
3027
3152
|
return fullFormHint;
|
|
3028
3153
|
}
|
|
@@ -3030,7 +3155,7 @@ export function describeProactiveSendCommandFailure(toolName, input, session) {
|
|
|
3030
3155
|
return looksLikeAid(from)
|
|
3031
3156
|
? fullFormHint
|
|
3032
3157
|
: `${prefix}缺少发送者与目标("${from}" 是正文而非 AID)。完整形式为 ${expectedForm};`
|
|
3033
|
-
+
|
|
3158
|
+
+ `省略 from/to 仅在带 --thread 的跨话题发送中允许,普通回复也可用 ec ctl send '<正文>' 继承当前会话。`;
|
|
3034
3159
|
}
|
|
3035
3160
|
if (!looksLikeAid(from) || !looksLikeAid(to)) {
|
|
3036
3161
|
return `${prefix}发送者/目标不是合法 AID(收到 from="${from}" to="${to}")。完整形式为 ${expectedForm}。`;
|
|
@@ -938,7 +938,11 @@ export function lClassGrantIncludesProtectedPath(value, options = {}) {
|
|
|
938
938
|
// A grant covering an Agent root also covers its L-class configuration.
|
|
939
939
|
if (segments.length <= 2)
|
|
940
940
|
return true;
|
|
941
|
-
|
|
941
|
+
// relations/ 下的 L 类只有 relations/<peer>/config.json:只有范围是 relations/ 或
|
|
942
|
+
// relations/<peer> 本身时才覆盖它,更深的路径(如 relations/<peer>/memory/…)不会。
|
|
943
|
+
if (segments[2] === 'relations')
|
|
944
|
+
return segments.length <= 4;
|
|
945
|
+
return ['config.json', 'contact.json', 'contact-operations.jsonl', 'roles', 'triggers']
|
|
942
946
|
.includes(segments[2]);
|
|
943
947
|
}
|
|
944
948
|
return false;
|
|
@@ -3,7 +3,7 @@ import { parseLiteralShellArgv } from './ec-command-parser.js';
|
|
|
3
3
|
const MAX_QUERY_LISTS = 8;
|
|
4
4
|
const MAX_PIPELINE_STAGES = 3;
|
|
5
5
|
const SUPPORTED_EXECUTABLES = new Set([
|
|
6
|
-
'echo', 'pwd', 'ls', 'cat', 'grep', 'rg', 'find', 'sed', 'head', 'sort', 'git', 'wc', 'stat', 'lstat', 'awk',
|
|
6
|
+
'echo', 'pwd', 'ls', 'cat', 'grep', 'rg', 'find', 'sed', 'head', 'tail', 'sort', 'git', 'wc', 'stat', 'lstat', 'awk',
|
|
7
7
|
'bash', 'sh',
|
|
8
8
|
]);
|
|
9
9
|
const FIND_MUTATING_PRIMARY_RE = /^-(?:delete|exec|execdir|ok|okdir|fprint|fprint0|fprintf|fls)$/;
|
|
@@ -447,6 +447,13 @@ function analyzeHead(args) {
|
|
|
447
447
|
const parsed = parseOptionsAndPaths(args, new Set(['-c', '-n', '--bytes', '--lines']));
|
|
448
448
|
return parsed?.paths.map(exact) ?? null;
|
|
449
449
|
}
|
|
450
|
+
function analyzeTail(args) {
|
|
451
|
+
// -f/--follow opens an indefinite watch loop — not a bounded read query.
|
|
452
|
+
if (args.some(a => a === '-f' || a === '--follow' || /^-[^-]*f/.test(a)))
|
|
453
|
+
return null;
|
|
454
|
+
const parsed = parseOptionsAndPaths(args, new Set(['-c', '-n', '--bytes', '--lines']));
|
|
455
|
+
return parsed?.paths.map(exact) ?? null;
|
|
456
|
+
}
|
|
450
457
|
function analyzeSort(args) {
|
|
451
458
|
if (args.some(argument => /^(?:-o|-T)(?:.+|$)|^(?:--output|--compress-program|--temporary-directory|--files0-from)(?:=|$)/.test(argument))) {
|
|
452
459
|
return null;
|
|
@@ -828,68 +835,95 @@ function analyzeCommand(argv) {
|
|
|
828
835
|
const args = argv.slice(1);
|
|
829
836
|
let pathOperands = null;
|
|
830
837
|
let accessKind = 'content';
|
|
838
|
+
let purpose = 'unknown';
|
|
831
839
|
switch (executable) {
|
|
832
840
|
case 'echo':
|
|
833
841
|
pathOperands = [];
|
|
842
|
+
purpose = 'passthrough';
|
|
834
843
|
break;
|
|
835
844
|
case 'pwd':
|
|
836
845
|
pathOperands = args.every(argument => ['-L', '-P', '--help', '--version'].includes(argument)) ? [] : null;
|
|
846
|
+
purpose = 'passthrough';
|
|
837
847
|
break;
|
|
838
848
|
case 'ls':
|
|
839
849
|
pathOperands = analyzeLs(args);
|
|
850
|
+
purpose = 'enumerate';
|
|
840
851
|
break;
|
|
841
852
|
case 'cat':
|
|
842
853
|
pathOperands = analyzeCat(args);
|
|
854
|
+
purpose = 'content-read';
|
|
843
855
|
break;
|
|
844
856
|
case 'grep':
|
|
845
857
|
pathOperands = analyzeGrep(args);
|
|
858
|
+
purpose = 'search';
|
|
846
859
|
break;
|
|
847
860
|
case 'rg':
|
|
848
861
|
pathOperands = analyzeRg(args);
|
|
862
|
+
purpose = 'search';
|
|
849
863
|
break;
|
|
850
864
|
case 'find':
|
|
851
865
|
pathOperands = analyzeFind(args);
|
|
866
|
+
purpose = 'enumerate';
|
|
852
867
|
break;
|
|
853
868
|
case 'sed':
|
|
854
869
|
pathOperands = analyzeSed(args);
|
|
870
|
+
purpose = 'content-read';
|
|
855
871
|
break;
|
|
856
872
|
case 'head':
|
|
857
873
|
pathOperands = analyzeHead(args);
|
|
874
|
+
purpose = 'content-read';
|
|
875
|
+
break;
|
|
876
|
+
case 'tail':
|
|
877
|
+
pathOperands = analyzeTail(args);
|
|
878
|
+
purpose = 'content-read';
|
|
858
879
|
break;
|
|
859
880
|
case 'sort':
|
|
860
881
|
pathOperands = analyzeSort(args);
|
|
882
|
+
// sort 有路径参数时是文件读取,无路径参数时是纯 stdin 排序
|
|
883
|
+
purpose = 'stdin-transform';
|
|
861
884
|
break;
|
|
862
885
|
case 'git':
|
|
863
886
|
pathOperands = analyzeGit(args);
|
|
887
|
+
purpose = 'vcs-query';
|
|
864
888
|
break;
|
|
865
889
|
case 'wc':
|
|
866
890
|
pathOperands = analyzeWc(args);
|
|
891
|
+
// wc 有路径参数时是元数据读取,无路径参数时是纯 stdin 统计
|
|
892
|
+
purpose = 'metadata-read';
|
|
867
893
|
break;
|
|
868
894
|
case 'stat':
|
|
869
895
|
case 'lstat':
|
|
870
896
|
pathOperands = analyzeStat(args);
|
|
871
897
|
accessKind = 'metadata';
|
|
898
|
+
purpose = 'metadata-read';
|
|
872
899
|
break;
|
|
873
900
|
case 'awk':
|
|
874
901
|
pathOperands = analyzeAwk(args);
|
|
902
|
+
purpose = 'content-read';
|
|
875
903
|
break;
|
|
876
904
|
case 'bash':
|
|
877
905
|
case 'sh':
|
|
878
906
|
pathOperands = analyzeShellSyntaxCheck(args);
|
|
907
|
+
purpose = 'syntax-check';
|
|
879
908
|
break;
|
|
880
909
|
}
|
|
881
910
|
if (!pathOperands)
|
|
882
911
|
return null;
|
|
883
912
|
if (['ls', 'find'].includes(executable))
|
|
884
913
|
accessKind = 'enumerate';
|
|
914
|
+
// 无路径操作数的命令是纯 stdin→stdout 变换,可安全出现在管道任意位置。
|
|
915
|
+
// 对于 sort/wc/awk/grep/head/tail/sed:有路径参数时读文件,无路径参数时为 stdin 变换。
|
|
916
|
+
const stdinTransform = pathOperands.length === 0
|
|
917
|
+
&& ['sort', 'wc', 'awk', 'grep', 'rg', 'head', 'tail', 'sed'].includes(executable);
|
|
918
|
+
// 修正 purpose:stdin 变换时统一标记,避免 'metadata-read'/'content-read' 歧义
|
|
919
|
+
const resolvedPurpose = stdinTransform ? 'stdin-transform' : purpose;
|
|
885
920
|
return {
|
|
886
921
|
command: {
|
|
887
922
|
executable,
|
|
888
923
|
argv,
|
|
889
924
|
pathOperands,
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
// derived from their operands by policy consumers.
|
|
925
|
+
stdinTransform,
|
|
926
|
+
purpose: resolvedPurpose,
|
|
893
927
|
...(accessKind === 'metadata' ? { accessKind } : {}),
|
|
894
928
|
},
|
|
895
929
|
};
|
|
@@ -910,7 +944,11 @@ export function analyzeReadonlyShellQuery(command, options = {}) {
|
|
|
910
944
|
if (!analyzed)
|
|
911
945
|
return { kind: 'unproven', reason: 'unsupported-command-or-option' };
|
|
912
946
|
if (index > 0) {
|
|
913
|
-
|
|
947
|
+
// 管道后续段必须是纯 stdin→stdout 变换(stdinTransform=true 由 analyzeCommand 打标,
|
|
948
|
+
// 表示命令无 FS 路径操作数、只处理 stdin 流)。
|
|
949
|
+
// 黑名单规则已在 analyzeCommand 内部拦截(如 sort -o、tail -f 等),到这里的都是
|
|
950
|
+
// 白名单规则捞回后的安全命令,用标签判断而非硬编码可执行文件列表。
|
|
951
|
+
if (!analyzed.command.stdinTransform) {
|
|
914
952
|
return { kind: 'unproven', reason: 'unsupported-pipeline-filter' };
|
|
915
953
|
}
|
|
916
954
|
if (analyzed.command.pathOperands.length > 0) {
|