@sema-agent/server 7.133.0 → 7.134.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/MIGRATION.md +87 -0
- package/README.md +2 -2
- package/README.zh-CN.md +2 -2
- package/USAGE.md +129 -11
- package/deploy/sema-up/README.md +16 -0
- package/deploy/sema-up/chart/Chart.yaml +1 -1
- package/deploy/sema-up/chart/templates/NOTES.txt +15 -0
- package/deploy/sema-up/chart/templates/_helpers.tpl +129 -0
- package/deploy/sema-up/chart/templates/sealed-key.yaml +24 -0
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +14 -0
- package/deploy/sema-up/chart/templates/server.yaml +14 -0
- package/deploy/sema-up/chart/values-full-single.yaml +5 -1
- package/deploy/sema-up/chart/values.yaml +34 -0
- package/dist/approval-ask-audit-store.d.ts +1 -1
- package/dist/approval-card.d.ts +4 -4
- package/dist/approval-card.js +1 -2
- package/dist/approval-content-kind.d.ts +5 -2
- package/dist/approval-content-kind.js +16 -3
- package/dist/approval-gate-currency.d.ts +72 -0
- package/dist/approval-gate-currency.js +94 -0
- package/dist/approval.d.ts +6 -0
- package/dist/approval.js +31 -14
- package/dist/boot/coordinators.d.ts +6 -1
- package/dist/boot/coordinators.js +6 -3
- package/dist/boot/leader.d.ts +2 -0
- package/dist/boot/leader.js +2 -1
- package/dist/boot/read-deny-anchor-audit.js +2 -2
- package/dist/boot/runner-deps.d.ts +18 -5
- package/dist/boot/runner-deps.js +9 -0
- package/dist/boot/stage-06-runners.d.ts +4 -3
- package/dist/boot/stage-06-runners.js +15 -2
- package/dist/boot/stage-07-capability-layer.d.ts +2 -1
- package/dist/boot/stage-08-reapers.d.ts +2 -1
- package/dist/boot/stage-09-leader.d.ts +2 -1
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +2 -1
- package/dist/boot/stage-10-http-server.js +2 -1
- package/dist/boot/stores.d.ts +8 -0
- package/dist/boot/stores.js +8 -12
- package/dist/boot/web-admin.d.ts +6 -0
- package/dist/boot/web-admin.js +11 -2
- package/dist/budget.js +5 -1
- package/dist/caller-text-echo.d.ts +2 -0
- package/dist/caller-text-echo.js +2 -1
- package/dist/canonical-json.d.ts +2 -41
- package/dist/canonical-json.js +2 -13
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/mcp-probe.js +2 -2
- package/dist/capability-facts.d.ts +2 -0
- package/dist/capability-facts.js +4 -4
- package/dist/checkpoint-ctx-seal-m28.d.ts +42 -0
- package/dist/checkpoint-ctx-seal-m28.js +19 -0
- package/dist/field-conflict.d.ts +2 -1
- package/dist/field-conflict.js +1 -0
- package/dist/file-history-disclosure.d.ts +34 -5
- package/dist/file-history-disclosure.js +2 -2
- package/dist/fleet/fleet-bus.d.ts +4 -0
- package/dist/fleet/fleet-bus.js +1 -0
- package/dist/hooks/hook-runner.js +2 -2
- package/dist/http/admission.js +8 -0
- package/dist/http/approval-sweeps.js +3 -1
- package/dist/http/checkpoint-ctx.d.ts +157 -2
- package/dist/http/checkpoint-ctx.js +158 -2
- package/dist/http/dispatch.js +3 -3
- package/dist/http/durable-run-leg.js +3 -2
- package/dist/http/idempotency.d.ts +2 -2
- package/dist/http/idempotency.js +2 -2
- package/dist/http/principal-gate.d.ts +32 -6
- package/dist/http/principal-gate.js +27 -4
- package/dist/http/refusal-body.d.ts +12 -0
- package/dist/http/refusal-body.js +11 -0
- package/dist/http/request-guards.d.ts +0 -9
- package/dist/http/request-guards.js +2 -16
- package/dist/http/resume-ctx-read.d.ts +48 -1
- package/dist/http/resume-ctx-read.js +26 -3
- package/dist/http/resume-legs.d.ts +2 -1
- package/dist/http/resume-legs.js +37 -22
- package/dist/http/route-ctx.d.ts +0 -9
- package/dist/http/routes/agents-roster.js +2 -3
- package/dist/http/routes/approvals-assistant.js +43 -9
- package/dist/http/routes/capabilities.js +1 -1
- package/dist/http/routes/diagnostics.d.ts +3 -3
- package/dist/http/routes/diagnostics.js +1 -1
- package/dist/http/routes/fleet.js +4 -4
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/rules.js +4 -4
- package/dist/http/routes/runs.js +30 -9
- package/dist/http/routes/session-sync.d.ts +3 -2
- package/dist/http/routes/session-sync.js +38 -20
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/sessions-list.js +3 -4
- package/dist/http/routes/sessions.js +4 -4
- package/dist/http/routes/tasks.js +21 -16
- package/dist/http/routes/trace-usage.js +7 -9
- package/dist/http/run-declared-families.d.ts +16 -0
- package/dist/http/run-declared-families.js +12 -0
- package/dist/http/server.d.ts +6 -0
- package/dist/http/server.js +5 -2
- package/dist/http/submit-ctx.d.ts +4 -3
- package/dist/http/submit-ctx.js +19 -3
- package/dist/http/wire-types.d.ts +7 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/leader/wire.d.ts +4 -0
- package/dist/leader/wire.js +8 -7
- package/dist/main.js +1 -1
- package/dist/memory-origin-fence.js +2 -2
- package/dist/model-compat.d.ts +1 -1
- package/dist/observability/prompt-manifest.d.ts +19 -8
- package/dist/observability/prompt-manifest.js +9 -8
- package/dist/observability/tool-trace.js +8 -9
- package/dist/orchestration/workflow-park-decision.d.ts +1 -1
- package/dist/orchestration/workflow-park-decision.js +1 -0
- package/dist/parked-decide.d.ts +4 -5
- package/dist/parked-decide.js +3 -1
- package/dist/permission-rule-vocab.d.ts +1 -23
- package/dist/permission-rule-vocab.js +0 -13
- package/dist/plugins/approval-payload-fingerprint.d.ts +14 -6
- package/dist/plugins/approval-payload-fingerprint.js +1 -1
- package/dist/plugins/caching-session-store.d.ts +1 -1
- package/dist/plugins/caching-session-store.js +4 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +22 -1
- package/dist/plugins/checkpoint-store-sql.js +45 -1
- package/dist/plugins/local-checkpoint-store.d.ts +13 -2
- package/dist/plugins/local-checkpoint-store.js +26 -0
- package/dist/plugins/local-session-store.d.ts +12 -9
- package/dist/plugins/local-session-store.js +23 -14
- package/dist/plugins/local-session-window.d.ts +12 -6
- package/dist/plugins/local-session-window.js +1 -17
- package/dist/plugins/one-time-migrations.d.ts +11 -0
- package/dist/plugins/one-time-migrations.js +12 -0
- package/dist/plugins/permission-rule-store-file.js +10 -6
- package/dist/plugins/permission-rule-store-sql.js +8 -8
- package/dist/plugins/pg-session-storage.d.ts +1 -1
- package/dist/plugins/pg-session-storage.js +39 -17
- package/dist/plugins/remote-env-device.d.ts +14 -7
- package/dist/plugins/remote-env-device.js +23 -15
- package/dist/plugins/session-ownership.d.ts +11 -0
- package/dist/plugins/session-ownership.js +11 -0
- package/dist/plugins/session-placement.d.ts +12 -14
- package/dist/plugins/session-placement.js +2 -15
- package/dist/plugins/tidb-session-store.d.ts +1 -1
- package/dist/plugins/tidb-session-store.js +39 -17
- package/dist/request-tool-axes.d.ts +12 -0
- package/dist/request-tool-axes.js +20 -0
- package/dist/run-local.js +1 -0
- package/dist/runs.d.ts +2 -1
- package/dist/runs.js +4 -3
- package/dist/sealed-key.d.ts +32 -0
- package/dist/sealed-key.js +55 -1
- package/dist/security.d.ts +9 -7
- package/dist/session-error-wire.d.ts +12 -5
- package/dist/session-error-wire.js +4 -1
- package/dist/session-sync-kernel.d.ts +37 -10
- package/dist/session-sync-kernel.js +10 -0
- package/dist/task-a2a.js +4 -3
- package/dist/task-mcp.d.ts +2 -2
- package/dist/task-mcp.js +20 -8
- package/dist/task-settings.d.ts +5 -1
- package/dist/task-settings.js +1 -1
- package/dist/tool-approval.d.ts +151 -52
- package/dist/tool-approval.js +113 -20
- package/dist/tool-rule-names.d.ts +6 -0
- package/dist/trace/core-keyset-guard.d.ts +4 -3
- package/dist/trace/exit-seat.d.ts +13 -1
- package/dist/trace/exit-seat.js +55 -1
- package/dist/trace/ledger-events.d.ts +3 -1
- package/dist/trace/project.d.ts +18 -1
- package/dist/trace/project.js +16 -4
- package/dist/trace/redact.d.ts +6 -3
- package/dist/trace/redact.js +191 -23
- package/dist/trace/self-minted-wire.d.ts +4 -0
- package/dist/trace/self-minted-wire.js +1 -0
- package/dist/trace/wire-projection-faces.d.ts +6 -0
- package/dist/trace/wire-projection-faces.js +6 -0
- package/dist/web-admin-client/skills-mcp.d.ts +1 -1
- package/dist/web-admin-client/skills-mcp.js +2 -3
- package/dist/web-admin-client/types.d.ts +1 -1
- package/package.json +2 -2
- package/scripts/drain-check-local.mjs +34 -2
- package/scripts/drain-check.mysql.sql +20 -2
- package/scripts/drain-check.pg.sql +20 -2
- package/dist/mcp-tool-faces.d.ts +0 -69
- package/dist/mcp-tool-faces.js +0 -104
package/dist/trace/redact.js
CHANGED
|
@@ -28,6 +28,137 @@ export function mapNormalizedToOriginal(text, normalized) {
|
|
|
28
28
|
map[normalized.length] = text.length;
|
|
29
29
|
return map;
|
|
30
30
|
}
|
|
31
|
+
function deleteSpelledFormatCharacters(s) {
|
|
32
|
+
let i = s.indexOf("\\");
|
|
33
|
+
if (i < 0)
|
|
34
|
+
return { text: s, at: undefined, cum: undefined };
|
|
35
|
+
const n = s.length;
|
|
36
|
+
const read = { end: 0 };
|
|
37
|
+
let cuts;
|
|
38
|
+
while (i >= 0) {
|
|
39
|
+
let body = i + 1;
|
|
40
|
+
while (body < n && s.charCodeAt(body) === CH_BACKSLASH)
|
|
41
|
+
body += 1;
|
|
42
|
+
const cp = readSpelledCodePoint(s, body, read);
|
|
43
|
+
if (cp >= 0 && isFormatCodePoint(cp)) {
|
|
44
|
+
(cuts ??= []).push(i, read.end);
|
|
45
|
+
body = read.end;
|
|
46
|
+
}
|
|
47
|
+
i = s.indexOf("\\", body);
|
|
48
|
+
}
|
|
49
|
+
if (cuts === undefined)
|
|
50
|
+
return { text: s, at: undefined, cum: undefined };
|
|
51
|
+
const count = cuts.length / 2;
|
|
52
|
+
const at = new Int32Array(count);
|
|
53
|
+
const cum = new Int32Array(count);
|
|
54
|
+
const parts = [];
|
|
55
|
+
let from = 0;
|
|
56
|
+
let removed = 0;
|
|
57
|
+
for (let k = 0; k < count; k++) {
|
|
58
|
+
const a = cuts[2 * k];
|
|
59
|
+
const b = cuts[2 * k + 1];
|
|
60
|
+
parts.push(s.slice(from, a));
|
|
61
|
+
at[k] = a - removed;
|
|
62
|
+
removed += b - a;
|
|
63
|
+
cum[k] = removed;
|
|
64
|
+
from = b;
|
|
65
|
+
}
|
|
66
|
+
parts.push(s.slice(from));
|
|
67
|
+
return { text: parts.join(""), at, cum };
|
|
68
|
+
}
|
|
69
|
+
function viewIndexInInput(fold, v) {
|
|
70
|
+
const at = fold.at;
|
|
71
|
+
let lo = 0;
|
|
72
|
+
let hi = at.length;
|
|
73
|
+
while (lo < hi) {
|
|
74
|
+
const mid = (lo + hi) >>> 1;
|
|
75
|
+
if (at[mid] <= v)
|
|
76
|
+
lo = mid + 1;
|
|
77
|
+
else
|
|
78
|
+
hi = mid;
|
|
79
|
+
}
|
|
80
|
+
return lo === 0 ? v : v + fold.cum[lo - 1];
|
|
81
|
+
}
|
|
82
|
+
function readHexRun(s, at, count) {
|
|
83
|
+
let v = 0;
|
|
84
|
+
for (let k = at; k < at + count; k++) {
|
|
85
|
+
const d = hexDigitValue(s.charCodeAt(k));
|
|
86
|
+
if (d < 0)
|
|
87
|
+
return -1;
|
|
88
|
+
v = v * 16 + d;
|
|
89
|
+
}
|
|
90
|
+
return v;
|
|
91
|
+
}
|
|
92
|
+
function readEscapeElement(s, at, out) {
|
|
93
|
+
const kind = s.charCodeAt(at);
|
|
94
|
+
if (kind === CH_x) {
|
|
95
|
+
out.end = at + 3;
|
|
96
|
+
return readHexRun(s, at + 1, 2);
|
|
97
|
+
}
|
|
98
|
+
if (kind !== CH_u)
|
|
99
|
+
return -1;
|
|
100
|
+
if (s.charCodeAt(at + 1) === CH_LBRACE) {
|
|
101
|
+
let v = 0;
|
|
102
|
+
let k = at + 2;
|
|
103
|
+
for (; k < s.length; k++) {
|
|
104
|
+
const d = hexDigitValue(s.charCodeAt(k));
|
|
105
|
+
if (d < 0)
|
|
106
|
+
break;
|
|
107
|
+
v = v * 16 + d;
|
|
108
|
+
if (v > 0x10ffff)
|
|
109
|
+
return -1;
|
|
110
|
+
}
|
|
111
|
+
if (k === at + 2 || s.charCodeAt(k) !== CH_RBRACE)
|
|
112
|
+
return -1;
|
|
113
|
+
out.end = k + 1;
|
|
114
|
+
return v;
|
|
115
|
+
}
|
|
116
|
+
out.end = at + 5;
|
|
117
|
+
return readHexRun(s, at + 1, 4);
|
|
118
|
+
}
|
|
119
|
+
function readSpelledCodePoint(s, at, out) {
|
|
120
|
+
const v = readEscapeElement(s, at, out);
|
|
121
|
+
if (v < 0xd800 || v > 0xdfff)
|
|
122
|
+
return v;
|
|
123
|
+
if (v > 0xdbff)
|
|
124
|
+
return -1;
|
|
125
|
+
let k = out.end;
|
|
126
|
+
if (s.charCodeAt(k) !== CH_BACKSLASH)
|
|
127
|
+
return -1;
|
|
128
|
+
while (s.charCodeAt(k) === CH_BACKSLASH)
|
|
129
|
+
k += 1;
|
|
130
|
+
const lo = readEscapeElement(s, k, out);
|
|
131
|
+
return lo >= 0xdc00 && lo <= 0xdfff ? 0x10000 + ((v - 0xd800) << 10) + (lo - 0xdc00) : -1;
|
|
132
|
+
}
|
|
133
|
+
const FORMAT_CODEPOINT_TABLE = (() => {
|
|
134
|
+
const table = new Uint8Array(0x10000);
|
|
135
|
+
const units = [];
|
|
136
|
+
const codes = [];
|
|
137
|
+
for (let c = 0; c < 0x10000; c++) {
|
|
138
|
+
if (c >= 0xd800 && c <= 0xdfff)
|
|
139
|
+
continue;
|
|
140
|
+
units.push(String.fromCharCode(c));
|
|
141
|
+
codes.push(c);
|
|
142
|
+
}
|
|
143
|
+
const kept = normalizeForRedaction(units.join(""));
|
|
144
|
+
let j = 0;
|
|
145
|
+
for (let i = 0; i < codes.length; i++) {
|
|
146
|
+
if (j < kept.length && kept.charCodeAt(j) === codes[i])
|
|
147
|
+
j += 1;
|
|
148
|
+
else
|
|
149
|
+
table[codes[i]] = 1;
|
|
150
|
+
}
|
|
151
|
+
if (j !== kept.length)
|
|
152
|
+
throw new Error("redact: format-character stripping is not a code-unit deletion over the BMP — refusing to derive the escape-spelled format-character table");
|
|
153
|
+
return table;
|
|
154
|
+
})();
|
|
155
|
+
function isFormatCodePoint(cp) {
|
|
156
|
+
if (cp > 0x10ffff || (cp >= 0xd800 && cp <= 0xdfff))
|
|
157
|
+
return false;
|
|
158
|
+
if (cp >= 0x10000)
|
|
159
|
+
return normalizeForRedaction(String.fromCodePoint(cp)) === "";
|
|
160
|
+
return FORMAT_CODEPOINT_TABLE[cp] === 1;
|
|
161
|
+
}
|
|
31
162
|
export const REDACTION_TOKEN_RE_SRC = String.raw `«redacted(?::[a-z-]{1,16}){0,2}»`;
|
|
32
163
|
const ARM_VALUE_CLASSES = [];
|
|
33
164
|
const atLeast = (cls, min) => {
|
|
@@ -42,7 +173,7 @@ const WORD_INTERIOR_CLASS = "[A-Za-z0-9]";
|
|
|
42
173
|
const CH_TAB = 9, CH_LF = 10, CH_CR = 13, CH_ESC = 27, CH_SPACE = 32, CH_PLUS = 43, CH_MINUS = 45, CH_SLASH = 47;
|
|
43
174
|
const CH_0 = 48, CH_9 = 57, CH_COLON = 58, CH_EQ = 61, CH_AT = 64, CH_A = 65, CH_Z = 90;
|
|
44
175
|
const CH_LBRACKET = 91, CH_BACKSLASH = 92, CH_UNDERSCORE = 95;
|
|
45
|
-
const CH_a = 97, CH_b = 98, CH_f = 102, CH_n = 110, CH_r = 114, CH_t = 116, CH_u = 117, CH_z = 122, CH_TILDE = 126;
|
|
176
|
+
const CH_a = 97, CH_b = 98, CH_f = 102, CH_n = 110, CH_r = 114, CH_t = 116, CH_u = 117, CH_x = 120, CH_z = 122, CH_TILDE = 126;
|
|
46
177
|
const CH_QUOTE = 34;
|
|
47
178
|
const CH_CSI8 = 155;
|
|
48
179
|
const CH_LAQUO = 171;
|
|
@@ -632,9 +763,15 @@ function collectStickySpans(a, text, at, out) {
|
|
|
632
763
|
}
|
|
633
764
|
}
|
|
634
765
|
const WORD_SEGMENT_CLASS = "[A-Za-z0-9._~+/-]";
|
|
766
|
+
const SCHEME_DELIMITER_CHARS = "\\\"'`“”|";
|
|
767
|
+
if (/[\]^-]/.test(SCHEME_DELIMITER_CHARS))
|
|
768
|
+
throw new Error("redact: scheme delimiter table holds a character-class metacharacter — the class source is built without escaping it");
|
|
769
|
+
const SCHEME_DELIMITER_CODES = new Set([...SCHEME_DELIMITER_CHARS].map((c) => c.charCodeAt(0)));
|
|
770
|
+
const isSchemeDelimiterCode = (c) => SCHEME_DELIMITER_CODES.has(c);
|
|
771
|
+
const SCHEME_SEPARATOR_CLASS = `[\\s${SCHEME_DELIMITER_CHARS.replace(/\\/g, "\\\\")}]`;
|
|
635
772
|
const LEXICAL_KEYWORD_ARMS = new Set();
|
|
636
|
-
const keywordArm = (keywordSrc, valueClass, min, tailSrc = "") => {
|
|
637
|
-
const re = new RegExp(`(?:${keywordSrc}
|
|
773
|
+
const keywordArm = (keywordSrc, valueClass, min, tailSrc = "", separatorClass = "\\s") => {
|
|
774
|
+
const re = new RegExp(`(?:${keywordSrc}${separatorClass}+${atLeast(valueClass, min)}${tailSrc}` +
|
|
638
775
|
`|(?<!${WORD_SEGMENT_CLASS})${keywordSrc}(?:${twoStrongAhead(valueClass)}|${noConnectorAhead(valueClass)})${atLeast(valueClass, min)}${tailSrc})`, "g");
|
|
639
776
|
LEXICAL_KEYWORD_ARMS.add(re);
|
|
640
777
|
return re;
|
|
@@ -668,8 +805,8 @@ const PEM_FRAGMENT_TOKEN = "«redacted:private-key:partial»";
|
|
|
668
805
|
const HEADLESS_PPK_TOKEN = "«redacted:private-key:partial»";
|
|
669
806
|
const ANCHORED_VALUE_TOKEN = "«redacted»";
|
|
670
807
|
const KEYWORD_SECRET_PATTERNS = [
|
|
671
|
-
[keywordArm("[Bb]earer", "[A-Za-z0-9._~+/-]", 20, "=*"), "Bearer «redacted»"],
|
|
672
|
-
[keywordArm("Basic", "[A-Za-z0-9+/]", 16, "={0,2}"), "Basic «redacted»"],
|
|
808
|
+
[keywordArm("[Bb]earer", "[A-Za-z0-9._~+/-]", 20, "=*", SCHEME_SEPARATOR_CLASS), "Bearer «redacted»"],
|
|
809
|
+
[keywordArm("Basic", "[A-Za-z0-9+/]", 16, "={0,2}", SCHEME_SEPARATOR_CLASS), "Basic «redacted»"],
|
|
673
810
|
[keywordArm("[Tt]oken", "[A-Za-z0-9._~+/-]", 20), "token «redacted»"],
|
|
674
811
|
];
|
|
675
812
|
const SK_FULL_ARM_MIN = 20;
|
|
@@ -1772,7 +1909,7 @@ const isValueCloser = (ch) => ch === CH_DOT || ch === CH_COMMA || ch === CH_SEMI
|
|
|
1772
1909
|
const isInlineSpaceUnit = (ch) => ch === CH_SPACE || ch === CH_TAB;
|
|
1773
1910
|
const isToken68Code = (c) => isAsciiAlnumCode(c) || c === CH_DOT || c === CH_MINUS || c === CH_UNDERSCORE || c === CH_TILDE || c === CH_PLUS || c === CH_SLASH;
|
|
1774
1911
|
const endsValueUnit = (ch) => ch === JSON_STRING_END || isRegexSpace(ch) || isQuoteUnit(ch) || isValueCloser(ch);
|
|
1775
|
-
const endsHeaderValueUnit = (ch) => ch === JSON_STRING_END || isLineTerminator(ch) ||
|
|
1912
|
+
const endsHeaderValueUnit = (ch) => ch === JSON_STRING_END || isLineTerminator(ch) || isSchemeDelimiterCode(ch) || ch === CH_COMMA || ch === CH_SEMI || ch === CH_RPAREN || ch === CH_RBRACKET || ch === CH_RBRACE || ch === CH_GT;
|
|
1776
1913
|
const bracketOf = (c) => c === CH_LPAREN ? 1 : c === CH_RPAREN ? -1 : c === CH_LBRACKET ? 2 : c === CH_RBRACKET ? -2 : c === CH_LBRACE ? 3 : c === CH_RBRACE ? -3 : c === CH_LT ? 4 : c === CH_GT ? -4 : 0;
|
|
1777
1914
|
let anchoredScanUnits = 0;
|
|
1778
1915
|
export function anchoredScanUnitsForTest() {
|
|
@@ -2016,15 +2153,16 @@ function schemeValueAt(text, s, json) {
|
|
|
2016
2153
|
anchoredScanUnits += i - w;
|
|
2017
2154
|
if (i - w > STRONG_AUTH_SCHEME_MAX || !STRONG_AUTH_SCHEMES.has(text.slice(w, i).toLowerCase()))
|
|
2018
2155
|
return undefined;
|
|
2019
|
-
let
|
|
2156
|
+
let separated = false;
|
|
2020
2157
|
while (i < n) {
|
|
2021
2158
|
const unit = readAnchorUnit(text, i, json);
|
|
2022
|
-
|
|
2159
|
+
const ch = unitChOf(unit);
|
|
2160
|
+
if (!isInlineSpaceUnit(ch) && !isSchemeDelimiterCode(ch))
|
|
2023
2161
|
break;
|
|
2024
2162
|
i += unitLenOf(unit);
|
|
2025
|
-
|
|
2163
|
+
separated = true;
|
|
2026
2164
|
}
|
|
2027
|
-
if (!
|
|
2165
|
+
if (!separated)
|
|
2028
2166
|
return undefined;
|
|
2029
2167
|
const vs = i;
|
|
2030
2168
|
if (i >= n || !isAsciiAlnumCode(text.charCodeAt(i)))
|
|
@@ -2396,6 +2534,7 @@ const armPool = (() => {
|
|
|
2396
2534
|
const tokenOf = (sp) => members[sp.order].token;
|
|
2397
2535
|
const strong = spans.filter((sp) => armOfToken(tokenOf(sp)) === "full").sort((a, b) => a.start - b.start);
|
|
2398
2536
|
const byArmedToken = new Map();
|
|
2537
|
+
const stamped = [];
|
|
2399
2538
|
let si = 0;
|
|
2400
2539
|
let strongMaxEnd = -1;
|
|
2401
2540
|
for (const sp of kept) {
|
|
@@ -2411,8 +2550,9 @@ const armPool = (() => {
|
|
|
2411
2550
|
byArmedToken.set(key, { token, arm, count: 1 });
|
|
2412
2551
|
else
|
|
2413
2552
|
cur.count += 1;
|
|
2553
|
+
stamped.push({ ...sp, hit: { token, arm } });
|
|
2414
2554
|
}
|
|
2415
|
-
return { hits: [...byArmedToken.values()].map(({ token, arm, count }) => ({ label: labelOfToken(token), count, arm })), kept };
|
|
2555
|
+
return { hits: [...byArmedToken.values()].map(({ token, arm, count }) => ({ label: labelOfToken(token), count, arm })), kept: stamped };
|
|
2416
2556
|
};
|
|
2417
2557
|
})();
|
|
2418
2558
|
let onRedaction;
|
|
@@ -2433,21 +2573,49 @@ function reportHits(hits) {
|
|
|
2433
2573
|
}
|
|
2434
2574
|
}
|
|
2435
2575
|
}
|
|
2436
|
-
function runRedaction(text, observe, json, wantHits, scope) {
|
|
2437
|
-
const wantCount = wantHits || (onRedaction !== undefined && observe);
|
|
2576
|
+
function runRedaction(text, observe, json, wantHits, scope, muteCount = false) {
|
|
2577
|
+
const wantCount = wantHits || (onRedaction !== undefined && observe && !muteCount);
|
|
2438
2578
|
const normalized = normalizeForRedaction(text);
|
|
2439
|
-
const
|
|
2579
|
+
const first = applyRules(normalized, wantCount, json, observe, scope);
|
|
2440
2580
|
forgetEscapedSeparatorTails();
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
const
|
|
2444
|
-
|
|
2581
|
+
let spans = spansInOriginal(text, normalized, undefined, first.kept);
|
|
2582
|
+
let hits = first.hits;
|
|
2583
|
+
const second = deleteSpelledFormatCharacters(normalized);
|
|
2584
|
+
if (second.at !== undefined) {
|
|
2585
|
+
const r2 = applyRules(second.text, wantCount, json, false, scope);
|
|
2586
|
+
forgetEscapedSeparatorTails();
|
|
2587
|
+
const extra = spansInOriginal(text, normalized, second, r2.kept);
|
|
2588
|
+
if (extra.length > 0) {
|
|
2589
|
+
spans = resolveSpanOverlaps([...spans, ...extra]);
|
|
2590
|
+
hits = wantCount ? hitsOfSpans(spans) : NO_HITS;
|
|
2591
|
+
}
|
|
2592
|
+
}
|
|
2593
|
+
if (observe && !muteCount)
|
|
2594
|
+
reportHits(hits);
|
|
2595
|
+
return { text: applySpans(text, spans).out, hits, spans };
|
|
2596
|
+
}
|
|
2597
|
+
function hitsOfSpans(spans) {
|
|
2598
|
+
const by = new Map();
|
|
2599
|
+
for (const sp of spans) {
|
|
2600
|
+
if (sp.hit === undefined)
|
|
2601
|
+
continue;
|
|
2602
|
+
const key = `${sp.hit.token}\u0000${sp.hit.arm}`;
|
|
2603
|
+
const cur = by.get(key);
|
|
2604
|
+
if (cur === undefined)
|
|
2605
|
+
by.set(key, { token: sp.hit.token, arm: sp.hit.arm, count: 1 });
|
|
2606
|
+
else
|
|
2607
|
+
cur.count += 1;
|
|
2608
|
+
}
|
|
2609
|
+
return [...by.values()].map(({ token, arm, count }) => ({ label: labelOfToken(token), count, arm }));
|
|
2445
2610
|
}
|
|
2446
|
-
function spansInOriginal(text, normalized, kept) {
|
|
2447
|
-
if (kept.length === 0
|
|
2611
|
+
function spansInOriginal(text, normalized, fold, kept) {
|
|
2612
|
+
if (kept.length === 0)
|
|
2448
2613
|
return kept;
|
|
2614
|
+
const inNormalized = fold?.at === undefined ? kept : kept.map((s) => ({ ...s, start: viewIndexInInput(fold, s.start), end: viewIndexInInput(fold, s.end - 1) + 1 }));
|
|
2615
|
+
if (normalized === text)
|
|
2616
|
+
return inNormalized;
|
|
2449
2617
|
const map = mapNormalizedToOriginal(text, normalized);
|
|
2450
|
-
return
|
|
2618
|
+
return inNormalized.map((s) => ({ ...s, start: map[s.start], end: map[s.end - 1] + 1 }));
|
|
2451
2619
|
}
|
|
2452
2620
|
export function redactSecrets(text, opts) {
|
|
2453
2621
|
return runRedaction(text, opts?.observe ?? true, opts?.json === true, false, "free-text").text;
|
|
@@ -2460,8 +2628,8 @@ export function redactionSpansForTest(text, opts) {
|
|
|
2460
2628
|
const r = runRedaction(text, false, opts?.json === true, false, "free-text");
|
|
2461
2629
|
return { text: r.text, spans: r.spans.map((sp) => ({ start: sp.start, end: sp.end })) };
|
|
2462
2630
|
}
|
|
2463
|
-
export function proposeRedactionSpans(text, scope) {
|
|
2464
|
-
return runRedaction(text, true, false, false, scope).spans.map((sp) => ({ start: sp.start, end: sp.end, repl: sp.repl }));
|
|
2631
|
+
export function proposeRedactionSpans(text, scope, opts) {
|
|
2632
|
+
return runRedaction(text, true, false, false, scope, opts?.countHits === false).spans.map((sp) => ({ start: sp.start, end: sp.end, repl: sp.repl }));
|
|
2465
2633
|
}
|
|
2466
2634
|
const REDACT_MAX_DEPTH = 64;
|
|
2467
2635
|
export function redactDeep(value) {
|
|
@@ -210,6 +210,7 @@ export const SELF_MINTED_WIRE = {
|
|
|
210
210
|
plan_mode_after: { attr: "-", since: "7.133.0" },
|
|
211
211
|
bound_call_door: { attr: "-", since: "7.133.0" },
|
|
212
212
|
remember_decision: { attr: "-", since: "7.133.0" },
|
|
213
|
+
approval_feedback: { attr: "-", since: "7.134.0" },
|
|
213
214
|
},
|
|
214
215
|
},
|
|
215
216
|
limitRefusalReason: {
|
|
@@ -268,6 +268,12 @@ export declare const WIRE_PROJECTION_FACES: {
|
|
|
268
268
|
readonly excluded: readonly [];
|
|
269
269
|
readonly minted: readonly [];
|
|
270
270
|
};
|
|
271
|
+
readonly cross_boundary_taint: {
|
|
272
|
+
readonly projector: "crossBoundaryTaintEventData";
|
|
273
|
+
readonly coreType: "Extract<TraceEvent, { kind: \"permission.cross_boundary_taint\" }>";
|
|
274
|
+
readonly excluded: readonly ["kind", "version", "taskId", "ts"];
|
|
275
|
+
readonly minted: readonly [];
|
|
276
|
+
};
|
|
271
277
|
readonly prompt_manifest: {
|
|
272
278
|
readonly projector: "promptManifestRecordOf";
|
|
273
279
|
readonly coreType: "Extract<TraceEvent, { kind: \"prompt.assembled\" }>";
|
|
@@ -77,6 +77,12 @@ export const WIRE_PROJECTION_FACES = {
|
|
|
77
77
|
},
|
|
78
78
|
origin_clearance_origin: { projector: "buildClearanceRowWire", coreType: "MemoryEntryOrigin", excluded: [], minted: [] },
|
|
79
79
|
origin_clearance_event: { projector: "buildClearanceRowWire", coreType: "OriginClearanceEvent", excluded: [], minted: [] },
|
|
80
|
+
cross_boundary_taint: {
|
|
81
|
+
projector: "crossBoundaryTaintEventData",
|
|
82
|
+
coreType: `Extract<TraceEvent, { kind: "permission.cross_boundary_taint" }>`,
|
|
83
|
+
excluded: ["kind", "version", "taskId", "ts"],
|
|
84
|
+
minted: [],
|
|
85
|
+
},
|
|
80
86
|
prompt_manifest: {
|
|
81
87
|
projector: "promptManifestRecordOf",
|
|
82
88
|
coreType: MANIFEST_FRAME,
|
|
@@ -30,7 +30,7 @@ export declare function applySkillsManifest(baseline: LoadedSkill[], manifest: {
|
|
|
30
30
|
* Resolve center MCP servers (`/effective.mcp`) into core `McpServerSpec`s + the scenarios each applies to.
|
|
31
31
|
* env-NAME refs → real values from THIS service's env (secret boundary unchanged); a server with any missing
|
|
32
32
|
* ref is skipped (`resolveRefs` → null). `enabled:false` skipped. A server whose `toolFaces` / `toolAxes` declaration is
|
|
33
|
-
* malformed is skipped whole (both are trust-root declarations —
|
|
33
|
+
* malformed is skipped whole (both are trust-root declarations — the engine's `readToolFaces` / `readMcpToolAxes` judge them). Restart-to-apply
|
|
34
34
|
* (filtered per scenario in `resolveSpec` via `mcpForScenario`).
|
|
35
35
|
*/
|
|
36
36
|
export declare function resolveMcpServers(mcp: {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { readMcpSourceLabel } from "../mcp-source-label.js";
|
|
2
|
-
import { readMcpToolFaces } from "../mcp-tool-faces.js";
|
|
3
2
|
import { skillContentHash } from "@sema-agent/settings-schema";
|
|
4
|
-
import { readMcpToolAxes } from "@sema-agent/core";
|
|
3
|
+
import { readMcpToolAxes, readToolFaces } from "@sema-agent/core";
|
|
5
4
|
import { MCP_CONTENT_ORIGINS, describeBadContentOrigin, describeBadWireName, isContentOriginWord, isUsableWireName } from "@sema-agent/settings-schema";
|
|
6
5
|
import { noteMcpAssertionHeaderNotSent, sentMcpAssertionHeaderMember, withholdsMcpAssertionHeader } from "../mcp-assertion-header.js";
|
|
7
6
|
import { SHA256_HEX_RE } from "../digest-form.js";
|
|
@@ -116,7 +115,7 @@ export function resolveMcpServers(mcp, logger) {
|
|
|
116
115
|
});
|
|
117
116
|
}
|
|
118
117
|
const source = readMcpSourceLabel(s.name, s.source);
|
|
119
|
-
const facesRead =
|
|
118
|
+
const facesRead = readToolFaces(s.toolFaces);
|
|
120
119
|
if (!facesRead.ok) {
|
|
121
120
|
logger?.warn("web_admin_mcp_tool_faces_invalid", {
|
|
122
121
|
server: s.name,
|
|
@@ -147,7 +147,7 @@ export interface CenterMcpServer {
|
|
|
147
147
|
*
|
|
148
148
|
* 🔴 类型是 `unknown` 而不是那个结构,**刻意的**:本类型是两条 center 腿的**承载形**(本地 config.d 经
|
|
149
149
|
* settings-schema 的 `z.unknown()` 解析透明地过来、远端 /effective 是直读 JSON),判据与坏形处置的单一
|
|
150
|
-
*
|
|
150
|
+
* 属主是引擎根导出的 `readToolFaces`(`resolveMcpServers` 在铸 spec 那一刻调它)。在承载
|
|
151
151
|
* 形上先写一个结构,等于把同一张判据表抄成两份(而其中一份没有执行力)。
|
|
152
152
|
*/
|
|
153
153
|
toolFaces?: unknown;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.134.0",
|
|
4
4
|
"description": "Sema Server — the server/API implementation layer for Sema, wiring core, registry, model providers, and cloud agent execution. Built on @sema-agent/core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"build:binary:run-local:darwin-arm64": "bun build --compile --target=bun-darwin-arm64 src/run-local.ts --outfile dist/run-local-darwin-arm64"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"@sema-agent/core": "7.
|
|
71
|
+
"@sema-agent/core": "7.54.1",
|
|
72
72
|
"@sema-agent/settings-schema": "14.2.0",
|
|
73
73
|
"e2b": "^2.28.0",
|
|
74
74
|
"libsodium-wrappers": "^0.8.4",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* 换钉前的**排空检查 —— `DB_BACKEND=local`(File 店)车道**,只读。随 npm 包出(`scripts/drain-check-local.mjs`)。
|
|
4
|
-
*
|
|
4
|
+
* 一次跑**九条判据**(判据表 {@link DRAIN_CRITERIA},每条一行末行、各自的命中行;SQL 车道的同一判据是同目录随包的 `drain-check.mysql.sql` / `drain-check.pg.sql`,
|
|
5
5
|
* 每条判据一段、段首标记 `-- drain-check:<判据名>:<后端>`,判据名与本表的 `name` 同一个词):
|
|
6
6
|
* · `skill-grants-rollback`(**回滚**到 7.115.x 前,即引擎从 7.41 退回 7.40):四样任一 ——
|
|
7
7
|
* ① pending 行带 `state.skillGrants`(本次 run 冻结在行上的技能授予行:模型激活 / 子代捕获写下的放行与禁止);
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
* `dist/orchestration/workflow-agent-session-index.js` 取 —— 本脚本只按 runId 折叠;读不出的行计入 `corrupt`(rc 2:读不出的那一行可能正是点名某张待批卡的那一份);
|
|
32
32
|
* 窗与删码:本判据是一次性迁移 M9 的读侧半场 —— 窗口与删码清单见引擎启动期一次性迁移登记表(one-time-migrations)M9 一行,随 M9 一起删;这里不写第二份窗。
|
|
33
33
|
* · `parked-tool-lists`(升级到 7.132.0 前)/ `own-tool-lists-rollback`(从 7.132.0 回滚前):停驻行记下的工具名清单 / 7.52 写下的 `ownToolLists`(判据与出路见判据表那两条的注);
|
|
34
|
+
* · `sealed-credentials-rollback`(从 7.134.0 回滚前):续跑上下文的凭据位上带封签的 pending 行(7.133.x 读不懂封签,续跑时把这些位当没有;判据与出路见判据表那一条的注);
|
|
34
35
|
* · `retired-mode-seed`(换钉 7.113.0 前,core 7.39.0 删掉退役 mode-seed 的一次性迁移):pending 行的 `state.inheritedGate` 仍带退役成员;
|
|
35
36
|
* · `permissions-allow-list`(换钉 7.117.0 前,本服务把 `settings.permissions.allow` 整份交给引擎的 allow 层):pending 行所在会话的续跑上下文
|
|
36
37
|
* (`checkpoint-ctx/*.json` 的信封 `{ sessionId, updatedAt, ctx }`)里,`ctx.body.settings.permissions.allow` 是非空数组,且 `ctx.permissionsAllowReading` 不是 `"allow_layer"`
|
|
@@ -74,6 +75,7 @@
|
|
|
74
75
|
* `SKILL-DENY-INERT-ROW token=<token> sessionId=<id> createdAt=<ms> member=<skills|agents.skills>` /
|
|
75
76
|
* `WORKFLOW-PARK-ROW token=<token> sessionId=<id> createdAt=<ms> runId=<点名它的 run,逗号连接>` /
|
|
76
77
|
* `PARKED-TOOL-LISTS-ROW token=<token> sessionId=<id> createdAt=<ms> member=<toolCeiling|constraintChain|boundGrantDigest>` / `OWN-TOOL-LISTS-ROW token=<token> sessionId=<id> createdAt=<ms>` /
|
|
78
|
+
* `SEALED-CREDENTIALS-ROW token=<token> sessionId=<id> createdAt=<ms> field=<第一处带封签的凭据位>|runId=<workflow 子代卡:点它的 run>` /
|
|
77
79
|
* `ALLOW-LIST-ROW token=<token> sessionId=<id> createdAt=<ms>` / `RETIRED-ROW token=<token> sessionId=<id> createdAt=<ms> member=<成员>`;
|
|
78
80
|
* · 每条判据一行末行(表序;`RETIRED-MODE-SEED` 那一行恒在最后,7.113.0 起读「最后一行」的下游不受影响;`PERMISSIONS-ALLOW-LIST` 仍是倒数第二行):
|
|
79
81
|
* `SKILL-GRANTS rows=<命中数> pending=<pending 行数> total=<行数> unknownEvents=<n> corrupt=<n> root=<实际读的数据根>`,
|
|
@@ -82,6 +84,7 @@
|
|
|
82
84
|
* `WORKFLOW-PARK-HOLDER rows=<命中数> pending=<pending 行数> total=<行数> unknownEvents=<n> corrupt=<n> root=<实际读的数据根>`,
|
|
83
85
|
* `PARKED-TOOL-LISTS rows=<命中数> pending=<pending 行数> total=<行数> unknownEvents=<n> corrupt=<n> root=<实际读的数据根>`,
|
|
84
86
|
* `OWN-TOOL-LISTS-ROLLBACK rows=<命中数> pending=<pending 行数> total=<行数> unknownEvents=<n> corrupt=<n> root=<实际读的数据根>`,
|
|
87
|
+
* `SEALED-CREDENTIALS-ROLLBACK rows=<命中数> pending=<pending 行数> total=<行数> unknownEvents=<n> corrupt=<n> root=<实际读的数据根>`,
|
|
85
88
|
* `PERMISSIONS-ALLOW-LIST rows=<命中数> pending=<pending 行数> total=<行数> unknownEvents=<n> corrupt=<n> root=<实际读的数据根>`,
|
|
86
89
|
* `RETIRED-MODE-SEED rows=<命中数> pending=<pending 行数> total=<行数> unknownEvents=<n> corrupt=<n> root=<实际读的数据根>`;
|
|
87
90
|
* `corrupt` = 共用扫描的坏记录 + 这条判据自己读不懂的旁路输入(`permissions-allow-list`:读不懂的 ctx 档,文件名进 stderr —— 一份读不懂的 ctx 可能正是某条 pending 行带 `allow` 的那一份;
|
|
@@ -97,7 +100,7 @@ import { join } from "node:path";
|
|
|
97
100
|
import { fileURLToPath } from "node:url";
|
|
98
101
|
|
|
99
102
|
/** 从脚本隔壁的编译产物取来的服务判据(脚本不持第二份实现)。
|
|
100
|
-
* @typedef {{ allowListReadingUnstated: (ctx: Record<string, unknown>) => boolean, retiredSkillManifestLayerOf: (body: unknown) => "skills" | "agents.skills" | undefined, skillDenyInertEntryOf: (body: unknown) => { layer: "skills" | "agents.skills", message: string } | undefined, readAgentSessionLedgerLine: (v: unknown) => { runId: string, rows: Array<{ sessionId: string }> } | undefined }} ServiceCriteria */
|
|
103
|
+
* @typedef {{ allowListReadingUnstated: (ctx: Record<string, unknown>) => boolean, sealedCredentialFieldOf: (ctx: unknown) => string | undefined, retiredSkillManifestLayerOf: (body: unknown) => "skills" | "agents.skills" | undefined, skillDenyInertEntryOf: (body: unknown) => { layer: "skills" | "agents.skills", message: string } | undefined, readAgentSessionLedgerLine: (v: unknown) => { runId: string, rows: Array<{ sessionId: string }> } | undefined }} ServiceCriteria */
|
|
101
104
|
|
|
102
105
|
/** 读期间文件在变时的有界重读次数(含第一次)。 */
|
|
103
106
|
const STABLE_READ_ATTEMPTS = 3;
|
|
@@ -460,6 +463,34 @@ export const DRAIN_CRITERIA = [
|
|
|
460
463
|
load: () => ({ input: undefined, corrupt: 0, unreadable: [] }),
|
|
461
464
|
judge: (row) => (isObject(row.state) && Object.hasOwn(/** @type {Record<string, unknown>} */ (row.state), "ownToolLists") ? "" : undefined),
|
|
462
465
|
},
|
|
466
|
+
{
|
|
467
|
+
// 从 7.134.0 回滚到 7.133.x 之前:pending 行所在会话的续跑上下文里,提交体的凭据位(MCP / A2A 请求头与 env、settings.env、settings.webSearch.apiKey、http hook 请求头)
|
|
468
|
+
// 上带封签 —— 7.134.0 封好才落盘,7.133.x 读不懂封签、续跑时把这些位当作没有(无凭据照跑、不报错)。出路:回滚前把它们决掉或取消(随包 `MIGRATION.md` 7.134.0 节)。
|
|
469
|
+
// 判据函数是服务里那一只(`sealedCredentialFieldOf`,经编译产物 `dist/http/checkpoint-ctx.js` 取;走法与封口 / 开口 / 一次性迁移同一只),本脚本不写第二份;
|
|
470
|
+
// 命中行点名第一处凭据位(`field=`,键名;值从不出来);读不懂的 ctx 档 / 索引账本行计入 `corrupt`(rc 2)。
|
|
471
|
+
// 读哪一份续跑上下文与续跑腿同:workflow 子代卡(子会话被 park 索引点名)续跑读**发起会话**那一份,而发起会话记在引擎的 run 账里(引擎自己的账本格式,本脚本不重抄)
|
|
472
|
+
// ⇒ 子代卡数的是真超集:自己那一份带封签,或数据根里任一份 ctx 带封签,即记为候选并点名点它的 run(`runId=`)—— 与随包 SQL 孪生同为超集,不漏。
|
|
473
|
+
// 表序在 `permissions-allow-list` 之前 —— 那一条仍倒数第二、`RETIRED-MODE-SEED` 仍最后。
|
|
474
|
+
name: "sealed-credentials-rollback",
|
|
475
|
+
tail: "SEALED-CREDENTIALS-ROLLBACK",
|
|
476
|
+
hit: "SEALED-CREDENTIALS-ROW",
|
|
477
|
+
load: (root, service) => {
|
|
478
|
+
const idx = readCtxIndex(root);
|
|
479
|
+
const parks = readParkIndex(root, service.readAgentSessionLedgerLine);
|
|
480
|
+
const fieldOf = service.sealedCredentialFieldOf;
|
|
481
|
+
const anySealed = [...idx.bySession.values()].some((ctx) => fieldOf(ctx) !== undefined);
|
|
482
|
+
return { input: { bySession: idx.bySession, fieldOf, parkedBy: parks.bySession, anySealed }, corrupt: idx.corrupt + parks.corrupt, unreadable: [...idx.unreadable, ...parks.unreadable] };
|
|
483
|
+
},
|
|
484
|
+
judge: (row, input) => {
|
|
485
|
+
const { bySession, fieldOf, parkedBy, anySealed } = /** @type {{ bySession: Map<string, Record<string, unknown>>, fieldOf: ServiceCriteria["sealedCredentialFieldOf"], parkedBy: Map<string, string[]>, anySealed: boolean }} */ (input);
|
|
486
|
+
if (typeof row.sessionId !== "string") return undefined;
|
|
487
|
+
const ctx = bySession.get(row.sessionId);
|
|
488
|
+
const field = ctx === undefined ? undefined : fieldOf(ctx);
|
|
489
|
+
if (field !== undefined) return ` field=${field}`;
|
|
490
|
+
const runs = parkedBy.get(row.sessionId);
|
|
491
|
+
return runs !== undefined && anySealed ? ` runId=${runs.join(",")}` : undefined;
|
|
492
|
+
},
|
|
493
|
+
},
|
|
463
494
|
{
|
|
464
495
|
name: "permissions-allow-list",
|
|
465
496
|
tail: "PERMISSIONS-ALLOW-LIST",
|
|
@@ -503,6 +534,7 @@ async function loadServiceCriteria(rootEcho) {
|
|
|
503
534
|
/** @type {Array<[string, () => Promise<Record<string, unknown>>, string]>} 〔产物相对路径(报告用), 取模块, 导出名〕 */
|
|
504
535
|
const wanted = [
|
|
505
536
|
["dist/http/checkpoint-ctx.js", () => import("../dist/http/checkpoint-ctx.js"), "allowListReadingUnstated"],
|
|
537
|
+
["dist/http/checkpoint-ctx.js", () => import("../dist/http/checkpoint-ctx.js"), "sealedCredentialFieldOf"],
|
|
506
538
|
["dist/http/retired-skill-manifest.js", () => import("../dist/http/retired-skill-manifest.js"), "retiredSkillManifestLayerOf"],
|
|
507
539
|
["dist/rule-entry-list.js", () => import("../dist/rule-entry-list.js"), "skillDenyInertEntryOf"],
|
|
508
540
|
["dist/orchestration/workflow-agent-session-index.js", () => import("../dist/orchestration/workflow-agent-session-index.js"), "readAgentSessionLedgerLine"],
|
|
@@ -8,15 +8,16 @@
|
|
|
8
8
|
-- sessions 命中行所在的会话 id,逗号连接,新的在前。以 hit_rows 为准:这一列被会话变量 group_concat_max_len(缺省 1024 字节)截断时,列出的会话数会少于 hit_rows ——
|
|
9
9
|
-- 先处理列出的再跑一次,或先在同一个会话里 SET SESSION group_concat_max_len = 1048576; 再跑本文件(本文件自己只含 SELECT)。
|
|
10
10
|
-- 每段只数 pending 行(已决 / 已过期的行不数);判据只看**键在不在 / 值形**,不读行的其余内容。
|
|
11
|
-
-- DB_BACKEND=local(File 店)没有 SQL:用同目录的 drain-check-local.mjs
|
|
11
|
+
-- DB_BACKEND=local(File 店)没有 SQL:用同目录的 drain-check-local.mjs,九条判据同名。
|
|
12
12
|
--
|
|
13
|
-
--
|
|
13
|
+
-- 九条判据(顺序同 drain-check-local.mjs 的判据表):
|
|
14
14
|
-- skill-grants-rollback 回滚到 7.115.x(引擎 7.40)之前:7.116.0 停驻的行带 7.40 不读的技能授予节 / 卡绑定 / 会话上下文里的人点名技能 / 还没被激活的技能声明的禁止清单。
|
|
15
15
|
-- retired-skill-manifest 升级到 7.116.0 之前:停驻、持久化提交体里技能(顶层 skills[] 或子代 agents[].skills[])还带已退役的 manifest 键。
|
|
16
16
|
-- skill-deny-inert 换钉 7.117.0 之前:停驻、提交体里技能(顶层 skills[] 或子代 agents[].skills[])的 disallowedTools 有引擎会读成空的条目的**候选**(见该段注)。
|
|
17
17
|
-- workflow-park-holder 换钉 7.118.0 之前 / 从 7.118.0 回滚到 7.117.x 之前:此刻待批、且子会话被 workflow park 索引点名的卡(workflow 子代卡;见该段注)。
|
|
18
18
|
-- parked-tool-lists 升级到 7.132.0 之前:停驻行记着子代工具天花板 / 冻结的父约束链 / Skill 卡的清单绑定(7.52 在认领前按规范拼写读它们)的**候选**(见该段注)。
|
|
19
19
|
-- own-tool-lists-rollback 从 7.132.0 回滚到 7.131.x 之前:7.132.0 停驻、带 state.ownToolLists 的行(7.131.x 读不了)。
|
|
20
|
+
-- sealed-credentials-rollback 从 7.134.0 回滚到 7.133.x 之前:停驻、续跑上下文里提交体的凭据位上带封签的行(7.133.x 读不懂封签,续跑时把这些位当没有)的**候选**(见该段注)。
|
|
20
21
|
-- permissions-allow-list 换钉 7.117.0 之前:停驻、提交体 settings.permissions.allow 是非空数组且读法记号不是当前的 "allow_layer"(无记号 = 名单时代;"statement" = 表态时代)。
|
|
21
22
|
-- retired-mode-seed 换钉 7.113.0 之前:检查点的 inheritedGate 里仍带退役 mode-seed 成员。
|
|
22
23
|
|
|
@@ -115,6 +116,23 @@ FROM checkpoint k
|
|
|
115
116
|
WHERE k.status = 'pending'
|
|
116
117
|
AND JSON_CONTAINS_PATH(k.checkpoint, 'one', '$.state.ownToolLists');
|
|
117
118
|
|
|
119
|
+
-- drain-check:sealed-credentials-rollback:mysql —— 期望 hit_rows = 0;每一行 = 一条**候选**:从 7.134.0 回滚到 7.133.x 后续跑会丢掉请求凭据的停驻行。
|
|
120
|
+
-- 在**回滚之前**、对 7.134.0 的数据跑:7.134.0 把续跑上下文里提交体的凭据位(MCP / A2A 请求头与 env、settings.env、settings.webSearch.apiKey、http hook 请求头)
|
|
121
|
+
-- 封成封签(对象,格式词 "checkpoint-ctx-sealedbox-v1")才落盘;7.133.x 读不懂封签,续跑时把这些位当作没有(无凭据照跑、不报错)。出路:回滚前把它们决掉或取消(见随包 MIGRATION.md 7.134.0 节)。
|
|
122
|
+
-- 读哪一份续跑上下文:与续跑腿同(连接形与 permissions-allow-list 段逐字同,理由见该段注)。SQL 不走凭据位闭集 ⇒ 数的是**真超集**:提交体里任何一处有一个
|
|
123
|
+
-- JSON 串值恰为这个格式词即数(封签只落在凭据位上;体里别处恰好写着这个词的串值也会被数到 —— 多数,不漏)。本地脚本同名判据走服务里那一只凭据位走法(精确)。
|
|
124
|
+
SELECT 'sealed-credentials-rollback' AS criterion, COUNT(*) AS hit_rows,
|
|
125
|
+
COALESCE(GROUP_CONCAT(k.session_id ORDER BY k.created_at_ms DESC SEPARATOR ','), '') AS sessions
|
|
126
|
+
FROM checkpoint k
|
|
127
|
+
WHERE k.status = 'pending'
|
|
128
|
+
AND EXISTS (SELECT 1
|
|
129
|
+
FROM checkpoint kk
|
|
130
|
+
LEFT JOIN workflow_agent_session w ON w.session_id = kk.session_id
|
|
131
|
+
LEFT JOIN workflow_run r ON r.id = w.run_id
|
|
132
|
+
JOIN checkpoint_ctx c ON c.session_id = COALESCE(JSON_UNQUOTE(JSON_EXTRACT(r.run, '$.originatingSessionId')), kk.session_id)
|
|
133
|
+
WHERE kk.token = k.token
|
|
134
|
+
AND LOCATE('"checkpoint-ctx-sealedbox-v1"', CAST(JSON_EXTRACT(c.ctx, '$.body') AS CHAR)) > 0);
|
|
135
|
+
|
|
118
136
|
-- drain-check:permissions-allow-list:mysql —— 期望 hit_rows = 0;每一行 = 一条升级后续跑会被拒的停驻行。
|
|
119
137
|
-- 读哪一份续跑上下文:与续跑腿同 —— workflow 子代的停驻行(在 workflow_agent_session 里登记过)续跑时读的是**发起这条 workflow 的会话**那一份
|
|
120
138
|
-- (workflow_run.run 的 originatingSessionId);其余行读自己会话那一份。一个子会话可以被好几条 workflow 记录点名(续跑链 / 分叉;7.118.0 起索引主键是
|
|
@@ -7,15 +7,16 @@
|
|
|
7
7
|
-- hit_rows 命中的停驻行数(pending 行里算命中的那些);**全部为 0 才算排空**,非 0 ⇒ 逐条答完或取消(各判据对应的升级 / 回滚说明见随包 MIGRATION.md);
|
|
8
8
|
-- sessions 命中行所在的会话 id,逗号连接,新的在前。
|
|
9
9
|
-- 每段只数 pending 行(已决 / 已过期的行不数);判据只看**键在不在 / 值形**,不读行的其余内容。
|
|
10
|
-
-- DB_BACKEND=local(File 店)没有 SQL:用同目录的 drain-check-local.mjs
|
|
10
|
+
-- DB_BACKEND=local(File 店)没有 SQL:用同目录的 drain-check-local.mjs,九条判据同名。
|
|
11
11
|
--
|
|
12
|
-
--
|
|
12
|
+
-- 九条判据(顺序同 drain-check-local.mjs 的判据表):
|
|
13
13
|
-- skill-grants-rollback 回滚到 7.115.x(引擎 7.40)之前:7.116.0 停驻的行带 7.40 不读的技能授予节 / 卡绑定 / 会话上下文里的人点名技能 / 还没被激活的技能声明的禁止清单。
|
|
14
14
|
-- retired-skill-manifest 升级到 7.116.0 之前:停驻、持久化提交体里技能(顶层 skills[] 或子代 agents[].skills[])还带已退役的 manifest 键。
|
|
15
15
|
-- skill-deny-inert 换钉 7.117.0 之前:停驻、提交体里技能(顶层 skills[] 或子代 agents[].skills[])的 disallowedTools 有引擎会读成空的条目的**候选**(见该段注)。
|
|
16
16
|
-- workflow-park-holder 换钉 7.118.0 之前 / 从 7.118.0 回滚到 7.117.x 之前:此刻待批、且子会话被 workflow park 索引点名的卡(workflow 子代卡;见该段注)。
|
|
17
17
|
-- parked-tool-lists 升级到 7.132.0 之前:停驻行记着子代工具天花板 / 冻结的父约束链 / Skill 卡的清单绑定(7.52 在认领前按规范拼写读它们)的**候选**(见该段注)。
|
|
18
18
|
-- own-tool-lists-rollback 从 7.132.0 回滚到 7.131.x 之前:7.132.0 停驻、带 state.ownToolLists 的行(7.131.x 读不了)。
|
|
19
|
+
-- sealed-credentials-rollback 从 7.134.0 回滚到 7.133.x 之前:停驻、续跑上下文里提交体的凭据位上带封签的行(7.133.x 读不懂封签,续跑时把这些位当没有)的**候选**(见该段注)。
|
|
19
20
|
-- permissions-allow-list 换钉 7.117.0 之前:停驻、提交体 settings.permissions.allow 是非空数组且读法记号不是当前的 "allow_layer"(无记号 = 名单时代;"statement" = 表态时代)。
|
|
20
21
|
-- retired-mode-seed 换钉 7.113.0 之前:检查点的 inheritedGate 里仍带退役 mode-seed 成员。
|
|
21
22
|
|
|
@@ -123,6 +124,23 @@ FROM checkpoint k
|
|
|
123
124
|
WHERE k.status = 'pending'
|
|
124
125
|
AND (k.checkpoint -> 'state') ? 'ownToolLists';
|
|
125
126
|
|
|
127
|
+
-- drain-check:sealed-credentials-rollback:pg —— 期望 hit_rows = 0;每一行 = 一条**候选**:从 7.134.0 回滚到 7.133.x 后续跑会丢掉请求凭据的停驻行。
|
|
128
|
+
-- 在**回滚之前**、对 7.134.0 的数据跑:7.134.0 把续跑上下文里提交体的凭据位(MCP / A2A 请求头与 env、settings.env、settings.webSearch.apiKey、http hook 请求头)
|
|
129
|
+
-- 封成封签(对象,格式词 "checkpoint-ctx-sealedbox-v1")才落盘;7.133.x 读不懂封签,续跑时把这些位当作没有(无凭据照跑、不报错)。出路:回滚前把它们决掉或取消(见随包 MIGRATION.md 7.134.0 节)。
|
|
130
|
+
-- 读哪一份续跑上下文:与续跑腿同(连接形与 permissions-allow-list 段逐字同,理由见该段注)。SQL 不走凭据位闭集 ⇒ 数的是**真超集**:提交体里任何一处有一个
|
|
131
|
+
-- JSON 串值恰为这个格式词即数(封签只落在凭据位上;体里别处恰好写着这个词的串值也会被数到 —— 多数,不漏)。本地脚本同名判据走服务里那一只凭据位走法(精确)。
|
|
132
|
+
SELECT 'sealed-credentials-rollback' AS criterion, count(*) AS hit_rows,
|
|
133
|
+
coalesce(string_agg(k.session_id, ',' ORDER BY k.created_at_ms DESC), '') AS sessions
|
|
134
|
+
FROM checkpoint k
|
|
135
|
+
WHERE k.status = 'pending'
|
|
136
|
+
AND EXISTS (SELECT 1
|
|
137
|
+
FROM checkpoint kk
|
|
138
|
+
LEFT JOIN workflow_agent_session w ON w.session_id = kk.session_id
|
|
139
|
+
LEFT JOIN workflow_run r ON r.id = w.run_id
|
|
140
|
+
JOIN checkpoint_ctx c ON c.session_id = COALESCE(r.run::json->>'originatingSessionId', kk.session_id)
|
|
141
|
+
WHERE kk.token = k.token
|
|
142
|
+
AND strpos((c.ctx -> 'body')::text, '"checkpoint-ctx-sealedbox-v1"') > 0);
|
|
143
|
+
|
|
126
144
|
-- drain-check:permissions-allow-list:pg —— 期望 hit_rows = 0;每一行 = 一条升级后续跑会被拒的停驻行。
|
|
127
145
|
-- 读哪一份续跑上下文:与续跑腿同 —— workflow 子代的停驻行(在 workflow_agent_session 里登记过)续跑时读的是**发起这条 workflow 的会话**那一份
|
|
128
146
|
-- (workflow_run.run 的 originatingSessionId);其余行读自己会话那一份。一个子会话可以被好几条 workflow 记录点名(续跑链 / 分叉;7.118.0 起索引主键是
|