@sema-agent/server 7.89.0 → 7.91.1
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/dist/adoption/plan.js +11 -0
- package/dist/boot/fatal-exit.d.ts +3 -0
- package/dist/boot/fatal-exit.js +5 -0
- package/dist/boot/resolve-spec.js +2 -0
- package/dist/boot/runner-deps.d.ts +6 -0
- package/dist/boot/runner-deps.js +11 -0
- package/dist/boot/session-faces.d.ts +6 -0
- package/dist/boot/session-faces.js +10 -2
- package/dist/boot/stage-03-store-backend.d.ts +1 -0
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -0
- package/dist/boot/stage-05-execution-env.d.ts +1 -0
- package/dist/boot/stage-06-runners.d.ts +1 -0
- package/dist/boot/stage-06-runners.js +2 -2
- package/dist/boot/stage-07-capability-layer.d.ts +1 -0
- package/dist/boot/stage-08-reapers.d.ts +1 -0
- package/dist/boot/stage-09-leader.d.ts +1 -0
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +1 -0
- package/dist/boot/stage-10-http-server.js +1 -0
- package/dist/boot/stores.d.ts +2 -0
- package/dist/boot/stores.js +11 -3
- package/dist/brain.js +32 -19
- package/dist/capabilities/memory-notice.d.ts +7 -1
- package/dist/capabilities/memory-notice.js +6 -6
- package/dist/capabilities/team.d.ts +37 -0
- package/dist/config-catalog.js +6 -18
- package/dist/config.d.ts +1 -1
- package/dist/config.js +5 -5
- package/dist/cross-session-settings.d.ts +6 -2
- package/dist/hooks/hook-llm.js +10 -6
- package/dist/hooks/hook-runner.js +19 -2
- package/dist/http/admission.js +9 -5
- package/dist/http/routes/capabilities.js +6 -3
- package/dist/http/routes/rules.d.ts +11 -0
- package/dist/http/routes/rules.js +54 -5
- package/dist/http/routes/session-sync.js +8 -2
- package/dist/http/routes/sessions-list.js +6 -1
- package/dist/http/routes/sessions.js +16 -14
- package/dist/http/server.d.ts +12 -0
- package/dist/http/wire-types.d.ts +12 -0
- package/dist/main.js +2 -1
- package/dist/model-route-url.d.ts +8 -0
- package/dist/model-route-url.js +17 -8
- package/dist/peer-directory.d.ts +114 -0
- package/dist/peer-directory.js +136 -0
- package/dist/permission-rule-vocab.d.ts +27 -1
- package/dist/permission-rule-vocab.js +8 -0
- package/dist/plugins/mailbox-recipient-lifecycle.d.ts +86 -0
- package/dist/plugins/mailbox-recipient-lifecycle.js +10 -0
- package/dist/plugins/mailbox-store-sql.d.ts +18 -2
- package/dist/plugins/mailbox-store-sql.js +77 -1
- package/dist/plugins/memory-embedder.d.ts +0 -6
- package/dist/plugins/memory-embedder.js +10 -16
- package/dist/plugins/store-contracts.d.ts +36 -1
- package/dist/plugins/store-contracts.js +10 -0
- package/dist/request-key-closure.js +2 -1
- package/dist/rules-consent.d.ts +74 -1
- package/dist/rules-consent.js +81 -1
- package/dist/runtime-governance.d.ts +16 -7
- package/dist/runtime-governance.js +27 -7
- package/dist/session-policy-wire.d.ts +103 -0
- package/dist/session-policy-wire.js +66 -0
- package/dist/task-settings.d.ts +12 -2
- package/dist/task-settings.js +7 -5
- package/dist/trace/core-keyset-guard.d.ts +2 -2
- package/dist/trace/project.d.ts +7 -0
- package/dist/trace/project.js +1 -0
- package/dist/trace/redact.d.ts +96 -11
- package/dist/trace/redact.js +155 -11
- package/dist/trace/sema-provenance.d.ts +7 -6
- package/package.json +3 -3
package/dist/task-settings.d.ts
CHANGED
|
@@ -48,7 +48,16 @@ import { type KeyClosureIssue } from "./request-key-closure.js";
|
|
|
48
48
|
* deployment approval/governance baseline is composed OUTSIDE this derive and is untouchable from a settings stamp),
|
|
49
49
|
* and `auto` adds the same ask gate as `default` with core's auto-mode classifier screening the asks upstream
|
|
50
50
|
* (entitlement-gated in core, [ref]②). */
|
|
51
|
-
export
|
|
51
|
+
export declare const SETTINGS_PERMISSION_MODES: readonly ["default", "acceptEdits", "plan", "bypassPermissions", "auto"];
|
|
52
|
+
/** 五模式闭集的型形 —— **从值表派生**(S-496 / [ref]):改前本仓有 **4 份**同一张五词表(本处的手写联合 /
|
|
53
|
+
* 下面 `coercePermissionModeStrict` 的运行期字面量链 / `http/admission.ts` 顶层 `permissionMode` 的比较链 /
|
|
54
|
+
* 同文件 `settings.permissions.defaultMode` 的比较链),外加两句错误文案里各抄一遍词。现在值表一份、
|
|
55
|
+
* 型与文案都从它派生,比较链改调 {@link isSettingsPermissionMode}。 */
|
|
56
|
+
export type SettingsPermissionMode = (typeof SETTINGS_PERMISSION_MODES)[number];
|
|
57
|
+
/** 五词表的 wire 文案形(`"a" | "b" | …`)—— 两条 400 的句子从这里取词,不再各抄一份。 */
|
|
58
|
+
export declare const SETTINGS_PERMISSION_MODE_WORDS: string;
|
|
59
|
+
/** 闭集成员判定(`unknown` 入口用)—— 词表的**唯一**运行期读者:wire 门与 coerce 两族同调。 */
|
|
60
|
+
export declare function isSettingsPermissionMode(raw: unknown): raw is SettingsPermissionMode;
|
|
52
61
|
/**
|
|
53
62
|
* R4: coerce a raw top-level `body.permissionMode` (the LIGHT per-turn wire — the shell sends the
|
|
54
63
|
* CC permission mode RAW, axis-agnostic; the service interprets) to a service-honored mode, or undefined.
|
|
@@ -68,7 +77,8 @@ export type SettingsPermissionMode = "default" | "acceptEdits" | "plan" | "bypas
|
|
|
68
77
|
*/
|
|
69
78
|
export declare function coercePermissionMode(raw: unknown): SettingsPermissionMode | undefined;
|
|
70
79
|
/** 五模式闭集的**严格**读法([ref] ④:`/v1/capabilities?permissionMode=` 查询串用它 —— 读面对词表外的值 400,
|
|
71
|
-
* 不走上面那条给 resume 重放留的 `default` 宽臂)
|
|
80
|
+
* 不走上面那条给 resume 重放留的 `default` 宽臂)。上面的宽读只是本函数外再包一层折叠。
|
|
81
|
+
* S-496:词表单点已上移到 {@link SETTINGS_PERMISSION_MODES},本函数只是它的 `undefined` 形读者。 */
|
|
72
82
|
export declare function coercePermissionModeStrict(raw: unknown): SettingsPermissionMode | undefined;
|
|
73
83
|
/**
|
|
74
84
|
* S-433 —— 一份**被批准的计划**之后,这条会话继续用的 permission mode(`plan_review` 决裁体的
|
package/dist/task-settings.js
CHANGED
|
@@ -3,6 +3,11 @@ import { findUnmatchableToolNames, formatUnmatchableToolNames } from "./config.j
|
|
|
3
3
|
import { CONTROL_AND_BIDI_STRIP_RE } from "./text-bidi.js";
|
|
4
4
|
import { MAX_KEY_ECHO, keyClosureClause, scanKeyClosure } from "./request-key-closure.js";
|
|
5
5
|
import { parseHooksConfig } from "./hooks/hook-runner.js";
|
|
6
|
+
export const SETTINGS_PERMISSION_MODES = ["default", "acceptEdits", "plan", "bypassPermissions", "auto"];
|
|
7
|
+
export const SETTINGS_PERMISSION_MODE_WORDS = SETTINGS_PERMISSION_MODES.map((m) => `"${m}"`).join(" | ");
|
|
8
|
+
export function isSettingsPermissionMode(raw) {
|
|
9
|
+
return typeof raw === "string" && SETTINGS_PERMISSION_MODES.includes(raw);
|
|
10
|
+
}
|
|
6
11
|
export function coercePermissionMode(raw) {
|
|
7
12
|
const strict = coercePermissionModeStrict(raw);
|
|
8
13
|
if (strict !== undefined)
|
|
@@ -12,9 +17,7 @@ export function coercePermissionMode(raw) {
|
|
|
12
17
|
return undefined;
|
|
13
18
|
}
|
|
14
19
|
export function coercePermissionModeStrict(raw) {
|
|
15
|
-
|
|
16
|
-
return raw;
|
|
17
|
-
return undefined;
|
|
20
|
+
return isSettingsPermissionMode(raw) ? raw : undefined;
|
|
18
21
|
}
|
|
19
22
|
export const PLAN_APPROVE_PERMISSION_MODES_AFTER = ["default", "acceptEdits"];
|
|
20
23
|
export function isPlanApprovePermissionModeAfter(raw) {
|
|
@@ -154,8 +157,7 @@ export function parseTaskSettings(raw) {
|
|
|
154
157
|
const allow = cleanStringArray(p.allow);
|
|
155
158
|
const deny = cleanStringArray(p.deny);
|
|
156
159
|
const ask = cleanStringArray(p.ask);
|
|
157
|
-
const
|
|
158
|
-
const defaultMode = mode === "default" || mode === "acceptEdits" || mode === "plan" || mode === "bypassPermissions" || mode === "auto" ? mode : undefined;
|
|
160
|
+
const defaultMode = coercePermissionModeStrict(p.defaultMode);
|
|
159
161
|
const rawKill = p.disableAutoMode;
|
|
160
162
|
const disableAutoMode = rawKill === "disable" || rawKill === true || rawKill === false ? rawKill : undefined;
|
|
161
163
|
if (allow || deny || ask || defaultMode || disableAutoMode !== undefined) {
|
|
@@ -130,8 +130,8 @@ type SummaryProjected = "sessionId" | "scope" | "createdAt" | "gateKind" | "seve
|
|
|
130
130
|
type SummaryExcluded = "token" | "toolInput" | "toolName" | "toolCallId" | "preview" | "principal" | "sourceTaskId" | "contentKind" | "restoreMode" | "checkpointId" | "previewWithheld";
|
|
131
131
|
type _GuardInboxSummary = AssertAllKeysHandled<Exclude<keyof CheckpointSummary, SummaryProjected | SummaryExcluded>>;
|
|
132
132
|
type _GuardInboxSummaryReverse = AssertAllKeysHandled<Exclude<SummaryProjected | SummaryExcluded, keyof CheckpointSummary>>;
|
|
133
|
-
type TaskSpecWired = "objective" | "principal" | "images" | "sessionId" | "requireExistingSession" | "oneShot" | "clientContext" | "resumeAt" | "resumeAtMode" | "model" | "compactionModel" | "thinking" | "systemPrompt" | "appendSystemPrompt" | "promptProvider" | "memory" | "suggestNextPrompts" | "restoreFiles" | "acceptPartialRestore" | "rewindFilesTo" | "tools" | "excludeTools" | "deferTools" | "toolMaterializeStrategy" | "promptProfile" | "toolPolicy" | "onAsk" | "onQuestion" | "hooks" | "durableApproval" | "resourceSuspend" | "resilience" | "finalVerification" | "checkpointStore" | "handsReadOnly" | "memoryPersistenceCapable" | "additionalDirectories" | "additionalReadDirectories" | "enablePlanMode" | "interactiveTools" | "enableFork" | "shellGate" | "writeFace" | "mcp" | "a2a" | "skills" | "backgroundScope" | "envFacts" | "limits" | "configOverrides" | "forwardSubagentEvents" | "retainSubagentSessions" | "retainBackgroundProcesses" | "outputSchema" | "outputRetries" | "compaction" | "attachments" | "selfOrchestration" | "getApiKeyAndHeaders" | "interactionPosture" | "agents" | "taskId" | "signal" | "preemptSignal" | "modelRole" | "enableBlockedReport" | "maxSuspends" | "autoModeRequested" | "skillListingBudgetFraction" | "skillListingMaxDescChars";
|
|
134
|
-
type TaskSpecUnwired = "
|
|
133
|
+
type TaskSpecWired = "objective" | "principal" | "images" | "sessionId" | "requireExistingSession" | "oneShot" | "clientContext" | "resumeAt" | "resumeAtMode" | "model" | "compactionModel" | "thinking" | "systemPrompt" | "appendSystemPrompt" | "promptProvider" | "memory" | "suggestNextPrompts" | "restoreFiles" | "acceptPartialRestore" | "rewindFilesTo" | "tools" | "excludeTools" | "deferTools" | "toolMaterializeStrategy" | "promptProfile" | "toolPolicy" | "onAsk" | "onQuestion" | "hooks" | "durableApproval" | "resourceSuspend" | "resilience" | "finalVerification" | "checkpointStore" | "handsReadOnly" | "memoryPersistenceCapable" | "additionalDirectories" | "additionalReadDirectories" | "enablePlanMode" | "interactiveTools" | "enableFork" | "shellGate" | "writeFace" | "mcp" | "a2a" | "skills" | "backgroundScope" | "envFacts" | "limits" | "configOverrides" | "forwardSubagentEvents" | "retainSubagentSessions" | "retainBackgroundProcesses" | "outputSchema" | "outputRetries" | "compaction" | "attachments" | "selfOrchestration" | "getApiKeyAndHeaders" | "interactionPosture" | "agents" | "taskId" | "signal" | "preemptSignal" | "modelRole" | "enableBlockedReport" | "maxSuspends" | "autoModeRequested" | "skillListingBudgetFraction" | "skillListingMaxDescChars" | "excludeAllTools";
|
|
134
|
+
type TaskSpecUnwired = "actor" | "roles" | "lspManager" | "tracer" | "readFace" | "readDenyPatterns" | "interactiveQuestionFallback" | "alwaysLoadTools" | "restoreGatedTools" | "deferSelfResolve" | "basePolicyForResumeEdit" | "lspDiagnostics" | "streamingToolExecution" | "toolResultThresholdChars";
|
|
135
135
|
type _GuardTaskSpec = AssertAllKeysHandled<Exclude<keyof TaskSpec, TaskSpecWired | TaskSpecUnwired>>;
|
|
136
136
|
type _GuardTaskSpecReverse = AssertAllKeysHandled<Exclude<TaskSpecWired | TaskSpecUnwired, keyof TaskSpec>>;
|
|
137
137
|
type TaskResultForwarded = "taskId" | "runId" | "sessionId" | "terminal" | "model" | "effectiveReasoning" | "result" | "salvagedOutput" | "remoteEnvFailures" | "apiFailure" | "retryAfterMs" | "degraded" | "structuredOutput" | "rewindNotes" | "haltedOnUserRejection" | "haltedByUser" | "strandedHumanAnswers" | "pendingApproval" | "approvalWaitedMs" | "effectiveReadFace" | "effectiveReadDenyPatterns" | "effectiveWriteFace" | "effectiveMemoryScopes" | "stats" | "editedFiles";
|
package/dist/trace/project.d.ts
CHANGED
|
@@ -769,6 +769,13 @@ export declare function compactedEventData(ev: {
|
|
|
769
769
|
clampReason?: "budget" | "tolerance";
|
|
770
770
|
tokensAfter?: number;
|
|
771
771
|
triggerTokensBefore?: number;
|
|
772
|
+
/** core 7.24.0 [ref]:引擎**自己**算的结构性净减(pre-messages 的结构和 减去 post-messages 的同一个和,
|
|
773
|
+
* 铸点处 clamp ≥0),三条压缩车道(turn 边界 / prompt-too-long 恢复 / 任务末 settle)同一只
|
|
774
|
+
* `mintCompactedEvent` 出。🔴 **缺席 = post 测量失败,不是 0**:上面那两个旧键(`tokensAfter` /
|
|
775
|
+
* `triggerTokensBefore`)自本版起在 core 的类型上写明是**诊断位、不可相减**(触发闸读的是 usage 锚定
|
|
776
|
+
* 的数、post 恒是结构和 + 固定提示词开销,两者的差混坐标,实测在普通 run 上是负数)。本仓的处置因此
|
|
777
|
+
* 是**三条都逐字透传、一条都不合成**:谁要画上下文表就读 `freedTokens`,读不到就渲染 unknown。 */
|
|
778
|
+
freedTokens?: number;
|
|
772
779
|
durationMs?: number;
|
|
773
780
|
phaseDurations?: {
|
|
774
781
|
prepareMs?: number;
|
package/dist/trace/project.js
CHANGED
|
@@ -656,6 +656,7 @@ export function compactedEventData(ev) {
|
|
|
656
656
|
...(ev.clampReason !== undefined ? { clampReason: ev.clampReason } : {}),
|
|
657
657
|
...(num(ev.tokensAfter) !== undefined ? { tokensAfter: num(ev.tokensAfter) } : {}),
|
|
658
658
|
...(num(ev.triggerTokensBefore) !== undefined ? { triggerTokensBefore: num(ev.triggerTokensBefore) } : {}),
|
|
659
|
+
...(num(ev.freedTokens) !== undefined ? { freedTokens: num(ev.freedTokens) } : {}),
|
|
659
660
|
...(num(ev.durationMs) !== undefined ? { durationMs: num(ev.durationMs) } : {}),
|
|
660
661
|
...(phaseDurations !== undefined ? { phaseDurations } : {}),
|
|
661
662
|
};
|
package/dist/trace/redact.d.ts
CHANGED
|
@@ -141,12 +141,13 @@ export declare function redactedPreview(value: unknown, cap?: number): string |
|
|
|
141
141
|
* (`model-route-url.ts` 第一臂)共用的**同一只**判据:两处曾各判各的,而 `URL.canParse` 单独为真的
|
|
142
142
|
* **不透明** URL 恰好是「凭据位看不见」的那一形。
|
|
143
143
|
*
|
|
144
|
-
* ⚠️ **射程如实**(车JC 复审去幻觉轮:此处原文写的是「本仓唯一判据」,亲读证伪)——
|
|
145
|
-
* 裸 `URL.canParse`
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
144
|
+
* ⚠️ **射程如实**(车JC 复审去幻觉轮:此处原文写的是「本仓唯一判据」,亲读证伪)—— 仓里**另有一处**仍用
|
|
145
|
+
* 裸 `URL.canParse` 回答同一个问题,且**刻意不在射程内**(改它是一次新的行为面拒启,按三问另开车):
|
|
146
|
+
* `config.ts` 的 `GIT_API_BASEURL`(`parseGitApiKind`):无协议闸 ⇒ 不透明形今天过门(拒因经本铸点,
|
|
147
|
+
* 所以不回显凭据;可用性由 `fetch` 那侧决定)。
|
|
148
|
+
* ✅ 原先列在这里的第二处(`config-catalog.ts` 的 `stripUrlUserinfo`:不透明形 `href === 原串` ⇒ 原样回显)
|
|
149
|
+
* 已在 7.90.0 随 core `displayUrlOf` 到货**闭环** —— 那只函数整只退役,url 型行的回显改走本铸点,
|
|
150
|
+
* 于是这道闸对它自动成立(catalog wire 行为面变更,CHANGELOG 已对外写明并点名 @web-admin)。
|
|
150
151
|
*
|
|
151
152
|
* 🔴 谓词写成 `URL.canParse` 而不是 try/catch:这一臂**不是兜底**(兜底才归静默降级那张表管),它是判据本身 ——
|
|
152
153
|
* 「不是一个层级式 URL」是一个可判的状态,用异常当控制流只会让它看起来像一次意外。
|
|
@@ -164,16 +165,100 @@ export declare function isHierarchicalUrl(raw: string): boolean;
|
|
|
164
165
|
* 网关 URL 的 userinfo / query 里,密码明文落 `engine-*.log`(日志的读者面比 run 错误文本更宽:它落盘、
|
|
165
166
|
* 被采集、进工单)。同类出口不止这两处,类级机器门在 `test/config-url-display-safe.test.ts`。
|
|
166
167
|
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
168
|
+
* 🔴 **S-483 展示半场(7.90.0 / core 7.24.0):两条正交的律合成一次,名表的射程缩到不可约的那一半**。
|
|
169
|
+
* 改前内部只有一条:`redactSecrets(new URL(raw).href)` —— 自由文本那条**名单制**的律,query 的值只在键名
|
|
170
|
+
* 落在 `CREDENTIAL_NAME_WORDS`(或值本身像个密钥)时才遮,于是**没人列过的那个键名**就是它的盲点
|
|
171
|
+
* (`?sig=…` / `?auth=…` / 部署自定义的网关参数名)。现在前面先跑 core 的 `displayUrlOf`,它是**位置制**的:
|
|
172
|
+
* · userinfo **落地**(不是遮成记号 —— 它从**解析**组合 `scheme://host + path + query`,userinfo 结构上
|
|
173
|
+
* 进不了产物);凭据在 userinfo 这件事本身仍然响亮,只不过是在**声明关口**响
|
|
174
|
+
* (`modelRouteUrlRefusal` / `parseA2aServe` / core 的 `assertServableRequestRoot`),不靠展示串暗示;
|
|
175
|
+
* · query 的**每一个值**成记号、**键名留着**(键名必须留:两条只在 query 上不同的根若都渲染成同一个串,
|
|
176
|
+
* 「A 配给了 B」这句拒因会写成「targets X … paired with X」);
|
|
177
|
+
* · 无 `=` 的**裸段**整片成一枚记号、连名字都不给(`URLSearchParams` 把它读成「空值的键」,那个读法
|
|
178
|
+
* 正好把 payload 本身放上了屏);
|
|
179
|
+
* · fragment 丢掉(implicit-OAuth 把 bearer 放那儿),尾斜杠与默认端口按配对键的同一把尺折。
|
|
180
|
+
* 位置律跑完**再跑一次形状律**({@link redactSecrets}):它管的是「一段字面量**长得像**凭据」,而位置律
|
|
181
|
+
* 对这件事结构性失明 —— `pathname` 被逐字保留,「这个路径段是不是一枚令牌」只能按形认。两条律正交、
|
|
182
|
+
* 各有一个属主、在铸点里合成一次;因为位置律先跑,名表在 query 上无事可做,它的射程被**缩小**到
|
|
183
|
+
* host + path 这一不可约的半边。
|
|
184
|
+
* 换尺的**代价成文、不是意外**:非凭据参数的值(`?model=x`)现在也成记号 —— 排障读不到它了。方向一致:
|
|
185
|
+
* 一个没人列过的凭据参数名泄出去是不可逆的,少读一个模型名不是。本仓原先**三份**各判各的 URL 脱敏实现
|
|
186
|
+
* (本铸点 / catalog 的 `stripUrlUserinfo` / embedder 的 `redactEndpointForLog`)合成这一只,记号闭形仍归
|
|
187
|
+
* 本模块({@link REDACTION_TOKENS};委托边界的闭集校验在下面的加载期检查)。
|
|
188
|
+
*
|
|
189
|
+
* 本函数自己只剩两件事,两件都是**配置型 URL 特有**的(core 的渲染器对这两形有自己的答案,而配置面要更严):
|
|
169
190
|
* ① **有效性闸**:配置里的那一位应当是一个**绝对 URL**。`new URL(raw)` 解析不动 ⇒ 这一位根本不是 URL
|
|
170
191
|
* (裸 `host:port`、相对路径、手滑的散文),自由文本的 URL 律对它没有定界依据 ⇒ 返回**占位**
|
|
171
192
|
* {@link DISPLAY_SAFE_URL_TOKEN},**不回落原值**([ref]:安全轴上的兜底必须 fail-closed 或响亮)。
|
|
172
193
|
* 成文代价:`MODEL_GATEWAY_BASEURL=127.0.0.1:8000` 这种缺 scheme 的配置在日志上变成 `«redacted:url»`
|
|
173
194
|
* —— 而它在 `fetch` 那一侧本来就是必然失败的形(WHATWG 要求绝对 URL),日志上响亮一点方向一致。
|
|
174
195
|
* ② **空串 = 未设**:里面没有凭据,原样回空串(不铸占位 —— 占位会让「没配」读成「配了但看不见」)。
|
|
175
|
-
*
|
|
176
|
-
*
|
|
196
|
+
* ⚠️ **保形只到 host / port / path 这一层**(S-483 起如实改口;`test/config-url-display-safe.test.ts`
|
|
197
|
+
* 的 S-483-o 是这句话的机器读数,别在散文里再抄一遍):scheme / host / port / path 的字节逐字(模 WHATWG
|
|
198
|
+
* 的 HTTP 等价归一:默认端口省、host 小写、IDN→punycode、点段折叠,再加**整串末尾**的斜杠去掉 ——
|
|
199
|
+
* 是**整串末尾**不是「路径末尾」:`…/p/` ⇒ `…/p`,而 `…/p/?k=v` 的 `/p/` 保留),query 只留**键名**。
|
|
200
|
+
*/
|
|
201
|
+
/** 位置律的**形** —— 生产路径恒是 core 的 {@link displayUrlOf}。参数化是**为可测性开的唯一一个缝**
|
|
202
|
+
* (S-497 的「违反格」要造一个「位置律漏了一段」的世界,而拿上游的现成缺陷当触发器会在它修好那天失效);
|
|
203
|
+
* 生产调用方**不传**这个参数。 */
|
|
204
|
+
export type PositionalUrlLaw = (url: string) => string;
|
|
205
|
+
/** 测试口(与 `observability/fail-open.ts` 的 `resetFailOpenRecorderForTest` 同姿势):一次性 warn 的闸是
|
|
206
|
+
* 模块级的,而「只 warn 一次」本身要被钉,所以给测试一个复位口。生产零调用。 */
|
|
207
|
+
export declare function resetDisplaySafeFailClosedWarnForTest(): void;
|
|
208
|
+
/**
|
|
209
|
+
* 🔴 **S-497 的不变量 —— 形状律在 query / fragment 区间上有一条凭据跨度 ⇒ 那一整段不出门**。
|
|
210
|
+
*
|
|
211
|
+
* 为什么需要它(差分实测 650 形里 26 个反例,本车亲跑复现):两条律**串起来**的时候,前一条会把后一条
|
|
212
|
+
* 赖以认字的**结构**改掉。实测的病形是 `https://h/?next=https://u:&pw@h=` —— 位置律先按 `&` 切段、把
|
|
213
|
+
* `next=https://u:` 整段换成记号,于是 `&` 之后那半截密码落到了**下一段的键名位**上被保留,而形状律
|
|
214
|
+
* 此刻已经看不到 `://<userinfo>@` 这个结构、无从下手(`redactSecrets(原串)` 是对的,可它拿不到原串)。
|
|
215
|
+
*
|
|
216
|
+
* 🔴 **判据落在「切分之前」,而不是在产物文本里找证据**(这一条是本不变量的全部)。三次尝试都被同一件事
|
|
217
|
+
* 击穿:①凭据**整段**不得是产物的子串 —— 位置律把它切开了,整段自然不是子串;②切成**片** + 长度下限 ——
|
|
218
|
+
* 材料能被切成全是单字符(`&a!b!c!d@`)甚至纯标点(`&!$()*+,;@`),任何下限都漏;③**字符集**包含 ——
|
|
219
|
+
* 密码的每个字符都能在同一条 URL 的 path / host / 别的键名里另外出现一次,包含关系成立而明文骑在产物上
|
|
220
|
+
* (`https://h/abcdefghijklmnopqrstuvwxyz0123456789?ok=1&next=https://u:&secret123=x@h`,S-497-k)。
|
|
221
|
+
* 共同的根:**切开之后,「这个字节来自凭据」在文本上不可判**。⇒ 判据搬到切分之前,用形状律自己报的
|
|
222
|
+
* **跨度坐标**当出处证明({@link shapeLawCredentialInQueryOrFragment})—— 不需要长度下限、字符类白名单
|
|
223
|
+
* 或任何集合运算,**规则比前三版都少**,而且对「将来出现的新形」天然封闭(新形状照样落在跨度里)。
|
|
224
|
+
*
|
|
225
|
+
* 两步(一条规则,不按形状分臂):
|
|
226
|
+
* ① 形状律在**归一化视图**上取跨度;凡有一条跨度落进 `?`(或 `#`)之后的区间 ⇒ 整段 query + fragment
|
|
227
|
+
* 换一枚 {@link REDACTION_TOKENS} 内的占位,`scheme://host[:port]/path` 留着并照旧过一遍形状律;
|
|
228
|
+
* ② 否则照旧合成:位置律 → 形状律。
|
|
229
|
+
* **过度遮的射程如实**:一条 query 里**真的**带凭据的配置型 URL,自本版起读不到它的**其它**参数名了
|
|
230
|
+
* (改前是逐参数遮)。方向一致,而且干净的根**零影响** —— Azure 式 `?api-version=…&deployment=…` 上
|
|
231
|
+
* 形状律一条跨度都没有,结构上走不到这一步(S-497-e 单独钉住)。path 区间的凭据**不**走这条路:位置律
|
|
232
|
+
* 逐字保留 `pathname`,形状律在产物上照常认得它(S-497-f 的并集格)。
|
|
233
|
+
* 🔴 这是 fail-**closed**(扣下信息),**不**登记 `recordFailOpen` —— 那张表记的是「放行了本该拒的」。
|
|
234
|
+
* 只打一条一次性 warn(**不含原文**:原文就是那段凭据)。
|
|
235
|
+
*/
|
|
236
|
+
export declare function buildDisplaySafeUrl(raw: string, positionalLaw?: PositionalUrlLaw): string;
|
|
237
|
+
/**
|
|
238
|
+
* {@link buildDisplaySafeUrl} 的**带判据**出口:除了展示串,还说这一次有没有落到 fail-closed
|
|
239
|
+
* (= 「query / fragment 因为里面有一条凭据跨度而整段被扣下」)。
|
|
240
|
+
*
|
|
241
|
+
* 🔴 **为什么要这个出口**(发前复审):core 的**路由拒因**是一句**自由文本**,里面嵌着 core **已经用
|
|
242
|
+
* 位置律改写过**的那条 URL —— 到我们手上时 `://<userinfo>@` 的结构早没了,形状律无从下手,于是那条出口
|
|
243
|
+
* 整个在不变量之外(实测:降级拒因把密码写进 `listening` 行)。这里不去猜怎么把上游那句话重新脱敏
|
|
244
|
+
* (那会变成第二个写者),而是用**同一条判决**:铸点对这条 URL 都已经守不住了,任何**引用它**的自由文本
|
|
245
|
+
* 一律扣下(见 {@link buildDisplaySafeRefusal})。判决属主还是这一只函数。
|
|
246
|
+
*/
|
|
247
|
+
export declare function buildDisplaySafeUrlChecked(raw: string, positionalLaw?: PositionalUrlLaw): {
|
|
248
|
+
text: string;
|
|
249
|
+
failedClosed: boolean;
|
|
250
|
+
};
|
|
251
|
+
/**
|
|
252
|
+
* 🔴 **引用了一条「铸点都守不住」的 URL 的自由文本,一律扣下**(S-497 的第二个出口;codex 第三轮 [high] 二)。
|
|
253
|
+
*
|
|
254
|
+
* 料 = 上游(core)的路由拒因:一句自由文本,里面嵌着 core **已经用位置律改写过**的那条 URL。到本仓手上时
|
|
255
|
+
* `://<userinfo>@` 的结构已经没了 ⇒ 形状律认不出那一段 ⇒ 光过一遍 `redactSecrets` 兜不住(实测:降级拒因
|
|
256
|
+
* 把密码写进 `listening` 行)。
|
|
257
|
+
*
|
|
258
|
+
* 判据**不新造**:问 {@link buildDisplaySafeUrlChecked} —— 如果铸点对这几条源 URL 里的任何一条都已经落到
|
|
259
|
+
* fail-closed,那么**任何引用它的句子**都不许出门,换一句固定文案(零原文)。机器可读的那一半不丢:调用方
|
|
260
|
+
* 手里有 `verdict.code`(拒因的码),它本来就在同一个投影的**另一个字段**上。
|
|
261
|
+
* 都守得住 ⇒ 照旧只过一遍形状律(上游的位置律已经把 URL 的凭据位处理过,这一层管的是**形状**那一半)。
|
|
177
262
|
*/
|
|
178
|
-
export declare function
|
|
263
|
+
export declare function buildDisplaySafeRefusal(text: string, sourceUrls: readonly string[]): string;
|
|
179
264
|
//# sourceMappingURL=redact.d.ts.map
|
package/dist/trace/redact.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { stripFormatCharacters } from "@sema-agent/core";
|
|
1
|
+
import { displayUrlOf, stripFormatCharacters } from "@sema-agent/core";
|
|
2
2
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
3
3
|
export const normalizeForRedaction = stripFormatCharacters;
|
|
4
4
|
const REDACTION_TOKEN_RE_SRC = String.raw `«redacted(?::[a-z-]{1,16}){0,2}»`;
|
|
5
|
-
const
|
|
5
|
+
const ARM_VALUE_CLASSES = [];
|
|
6
|
+
const atLeast = (cls, min) => {
|
|
7
|
+
ARM_VALUE_CLASSES.push(cls);
|
|
8
|
+
return `${cls}{${min}}${cls}*`;
|
|
9
|
+
};
|
|
6
10
|
const ENTROPY_SCAN_MAX = 96;
|
|
7
11
|
const twoStrongAhead = (valueClass) => String.raw `(?=${valueClass}{0,${ENTROPY_SCAN_MAX}}[0-9A-Z]${valueClass}{0,${ENTROPY_SCAN_MAX}}[0-9A-Z])`;
|
|
8
12
|
const IDENT_CONNECTORS = "[_./-]";
|
|
@@ -1085,6 +1089,7 @@ const FRAGMENT_SECRET_PATTERNS = [
|
|
|
1085
1089
|
[valueArm("xapp-\\d-", "[A-Za-z0-9-]", 4, "needs-left-boundary"), "«redacted:slack-token:partial»"],
|
|
1086
1090
|
];
|
|
1087
1091
|
const DISPLAY_SAFE_URL_TOKEN = "«redacted:url»";
|
|
1092
|
+
const WITHHELD_VALUE_TOKEN = "«redacted»";
|
|
1088
1093
|
const REDACTION_TOKENS = new Set([...FULL_ARM_PATTERNS.map(([, r]) => r), PEM_FRAGMENT_TOKEN, DISPLAY_SAFE_URL_TOKEN, ...FRAGMENT_SECRET_PATTERNS.map(([, r]) => r)]
|
|
1089
1094
|
.flatMap((r) => r.match(/«[^»]*»/g) ?? []));
|
|
1090
1095
|
{
|
|
@@ -1092,6 +1097,22 @@ const REDACTION_TOKENS = new Set([...FULL_ARM_PATTERNS.map(([, r]) => r), PEM_FR
|
|
|
1092
1097
|
for (const t of REDACTION_TOKENS)
|
|
1093
1098
|
if (!closed.test(t))
|
|
1094
1099
|
throw new Error(`redact: token ${t} is outside the closed form ${REDACTION_TOKEN_RE_SRC}`);
|
|
1100
|
+
if (!REDACTION_TOKENS.has(WITHHELD_VALUE_TOKEN)) {
|
|
1101
|
+
throw new Error(`redact: ${WITHHELD_VALUE_TOKEN} is no longer produced by the arm tables — the fail-closed filler must stay a closed-set member`);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
{
|
|
1105
|
+
for (const probe of ["https://probe.invalid/p?k=v", "https://probe.invalid/p?bare"]) {
|
|
1106
|
+
const toks = displayUrlOf(probe).match(/«[^»]*»/g) ?? [];
|
|
1107
|
+
if (toks.length === 0) {
|
|
1108
|
+
throw new Error(`redact: core displayUrlOf(${probe}) minted no «…» token at all — upstream changed the placeholder spelling; map it at the delegation boundary (never add a second token table)`);
|
|
1109
|
+
}
|
|
1110
|
+
for (const tok of toks) {
|
|
1111
|
+
if (!REDACTION_TOKENS.has(tok)) {
|
|
1112
|
+
throw new Error(`redact: core displayUrlOf minted ${tok}, which is outside this module's token closed set — map it at the delegation boundary (never add a second token table)`);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1095
1116
|
}
|
|
1096
1117
|
const labelOfToken = (token) => token.replace(/[«»]/g, "").replace(/^redacted:/, "");
|
|
1097
1118
|
const FRAGMENT_ARM_TOKENS = new Set(FRAGMENT_SECRET_PATTERNS.map(([, repl]) => repl));
|
|
@@ -1598,7 +1619,7 @@ const armPool = (() => {
|
|
|
1598
1619
|
const kept = resolveSpanOverlaps(spans);
|
|
1599
1620
|
const out = applySpans(text, kept).out;
|
|
1600
1621
|
if (!wantCount || kept.length === 0)
|
|
1601
|
-
return { out, hits: NO_HITS };
|
|
1622
|
+
return { out, hits: NO_HITS, kept };
|
|
1602
1623
|
const tokenOf = (sp) => members[sp.order].token;
|
|
1603
1624
|
const strong = spans.filter((sp) => armOfToken(tokenOf(sp)) === "full").sort((a, b) => a.start - b.start);
|
|
1604
1625
|
const byArmedToken = new Map();
|
|
@@ -1618,7 +1639,7 @@ const armPool = (() => {
|
|
|
1618
1639
|
else
|
|
1619
1640
|
cur.count += 1;
|
|
1620
1641
|
}
|
|
1621
|
-
return { out, hits: [...byArmedToken.values()].map(({ token, arm, count }) => ({ label: labelOfToken(token), count, arm })) };
|
|
1642
|
+
return { out, hits: [...byArmedToken.values()].map(({ token, arm, count }) => ({ label: labelOfToken(token), count, arm })), kept };
|
|
1622
1643
|
};
|
|
1623
1644
|
})();
|
|
1624
1645
|
let onRedaction;
|
|
@@ -1641,11 +1662,12 @@ function reportHits(hits) {
|
|
|
1641
1662
|
}
|
|
1642
1663
|
function runRedaction(text, observe, json, wantHits) {
|
|
1643
1664
|
const wantCount = wantHits || (onRedaction !== undefined && observe);
|
|
1644
|
-
const
|
|
1665
|
+
const normalized = normalizeForRedaction(text);
|
|
1666
|
+
const r = applyRules(normalized, wantCount, json, observe);
|
|
1645
1667
|
forgetEscapedSeparatorTails();
|
|
1646
1668
|
if (observe)
|
|
1647
1669
|
reportHits(r.hits);
|
|
1648
|
-
return { text: r.out, hits: r.hits };
|
|
1670
|
+
return { text: r.out, hits: r.hits, spans: r.kept };
|
|
1649
1671
|
}
|
|
1650
1672
|
export function redactSecrets(text, opts) {
|
|
1651
1673
|
return runRedaction(text, opts?.observe ?? true, opts?.json === true, false).text;
|
|
@@ -1718,12 +1740,134 @@ export function isHierarchicalUrl(raw) {
|
|
|
1718
1740
|
const u = new URL(raw);
|
|
1719
1741
|
return u.href.startsWith(`${u.protocol}//`);
|
|
1720
1742
|
}
|
|
1721
|
-
|
|
1743
|
+
function decodeToFixedPoint(s, maxRounds = 3) {
|
|
1744
|
+
let cur = s;
|
|
1745
|
+
for (let round = 0; round < maxRounds; round += 1) {
|
|
1746
|
+
if (!cur.includes("%"))
|
|
1747
|
+
return { text: cur, residue: false };
|
|
1748
|
+
const next = cur.replace(/%([0-9A-Fa-f]{2})/g, (_whole, hex) => String.fromCharCode(Number.parseInt(hex, 16)));
|
|
1749
|
+
if (next === cur)
|
|
1750
|
+
break;
|
|
1751
|
+
cur = next;
|
|
1752
|
+
}
|
|
1753
|
+
return { text: cur, residue: cur.includes("%") };
|
|
1754
|
+
}
|
|
1755
|
+
const VIEW_FILLER_PREFERENCE = ["a", "z", "_", "-", "0"];
|
|
1756
|
+
let armValueClassViewsCache;
|
|
1757
|
+
function armValueClassViews() {
|
|
1758
|
+
armValueClassViewsCache ??= [...new Set(ARM_VALUE_CLASSES)].map((cls) => {
|
|
1759
|
+
const inClass = new RegExp(`^(?:${cls})$`, "u");
|
|
1760
|
+
const filler = VIEW_FILLER_PREFERENCE.find((c) => inClass.test(c));
|
|
1761
|
+
if (filler === undefined)
|
|
1762
|
+
throw new Error(`redact: arm value class ${cls} admits none of the view fillers — add one that it accepts`);
|
|
1763
|
+
return { inClass, filler };
|
|
1764
|
+
});
|
|
1765
|
+
return armValueClassViewsCache;
|
|
1766
|
+
}
|
|
1767
|
+
function boundedUnitView(unit, inClass, filler) {
|
|
1768
|
+
let out = "";
|
|
1769
|
+
for (const ch of unit)
|
|
1770
|
+
out += inClass.test(ch) ? ch : filler;
|
|
1771
|
+
return out;
|
|
1772
|
+
}
|
|
1773
|
+
function unitCarriesCredential(unit) {
|
|
1774
|
+
const decoded = decodeToFixedPoint(unit);
|
|
1775
|
+
const views = new Set();
|
|
1776
|
+
for (const spelling of [unit, decoded.text])
|
|
1777
|
+
for (const v of armValueClassViews())
|
|
1778
|
+
views.add(boundedUnitView(spelling, v.inClass, v.filler));
|
|
1779
|
+
views.delete("");
|
|
1780
|
+
const hit = [...views].some((view) => redactSecrets(view) !== view);
|
|
1781
|
+
return { hit, residue: decoded.residue };
|
|
1782
|
+
}
|
|
1783
|
+
function displaySafePathname(pathname) {
|
|
1784
|
+
const parts = pathname.split("/");
|
|
1785
|
+
let withheld = false;
|
|
1786
|
+
for (let i = 0; i < parts.length; i += 1) {
|
|
1787
|
+
const seg = parts[i];
|
|
1788
|
+
if (seg === "")
|
|
1789
|
+
continue;
|
|
1790
|
+
const verdict = unitCarriesCredential(seg);
|
|
1791
|
+
if (!verdict.hit && !verdict.residue)
|
|
1792
|
+
continue;
|
|
1793
|
+
if (isAllRedactionTokens(redactSecrets(seg)))
|
|
1794
|
+
continue;
|
|
1795
|
+
parts[i] = WITHHELD_PATH_SEGMENT_TOKEN;
|
|
1796
|
+
withheld = true;
|
|
1797
|
+
}
|
|
1798
|
+
return { text: withheld ? parts.join("/") : pathname, withheld };
|
|
1799
|
+
}
|
|
1800
|
+
const ALL_REDACTION_TOKENS_RE = new RegExp(`^(?:${REDACTION_TOKEN_RE_SRC})+$`);
|
|
1801
|
+
const isAllRedactionTokens = (text) => ALL_REDACTION_TOKENS_RE.test(text);
|
|
1802
|
+
const WITHHELD_PATH_SEGMENT_TOKEN = "«redacted:key»";
|
|
1803
|
+
if (!REDACTION_TOKENS.has(WITHHELD_PATH_SEGMENT_TOKEN)) {
|
|
1804
|
+
throw new Error(`redact: ${WITHHELD_PATH_SEGMENT_TOKEN} is no longer produced by the arm tables — the path-segment filler must stay a closed-set member`);
|
|
1805
|
+
}
|
|
1806
|
+
function shapeLawCredentialInQueryOrFragment(canonical) {
|
|
1807
|
+
const normalized = normalizeForRedaction(canonical);
|
|
1808
|
+
const boundary = normalized.indexOf("?");
|
|
1809
|
+
if (boundary < 0)
|
|
1810
|
+
return false;
|
|
1811
|
+
if (runRedaction(canonical, false, false, false).spans.some((sp) => sp.end > boundary))
|
|
1812
|
+
return true;
|
|
1813
|
+
for (const unit of normalized.slice(boundary + 1).split("&").flatMap((sg) => {
|
|
1814
|
+
const eq = sg.indexOf("=");
|
|
1815
|
+
return eq === -1 ? [sg] : [sg.slice(0, eq), sg.slice(eq + 1)];
|
|
1816
|
+
})) {
|
|
1817
|
+
if (unit === "")
|
|
1818
|
+
continue;
|
|
1819
|
+
const verdict = unitCarriesCredential(unit);
|
|
1820
|
+
if (verdict.hit || verdict.residue)
|
|
1821
|
+
return true;
|
|
1822
|
+
const decoded = decodeToFixedPoint(unit).text;
|
|
1823
|
+
if (decoded.includes("://") || decoded.includes("@"))
|
|
1824
|
+
return true;
|
|
1825
|
+
}
|
|
1826
|
+
return false;
|
|
1827
|
+
}
|
|
1828
|
+
let displaySafeFailClosedWarned = false;
|
|
1829
|
+
export function resetDisplaySafeFailClosedWarnForTest() {
|
|
1830
|
+
displaySafeFailClosedWarned = false;
|
|
1831
|
+
}
|
|
1832
|
+
export function buildDisplaySafeUrl(raw, positionalLaw = displayUrlOf) {
|
|
1833
|
+
return buildDisplaySafeUrlChecked(raw, positionalLaw).text;
|
|
1834
|
+
}
|
|
1835
|
+
export function buildDisplaySafeUrlChecked(raw, positionalLaw = displayUrlOf) {
|
|
1722
1836
|
if (raw === "")
|
|
1723
|
-
return "";
|
|
1837
|
+
return { text: "", failedClosed: false };
|
|
1724
1838
|
if (!isHierarchicalUrl(raw))
|
|
1725
|
-
return DISPLAY_SAFE_URL_TOKEN;
|
|
1726
|
-
const
|
|
1727
|
-
|
|
1839
|
+
return { text: DISPLAY_SAFE_URL_TOKEN, failedClosed: false };
|
|
1840
|
+
const parsed = new URL(raw);
|
|
1841
|
+
const safePath = displaySafePathname(parsed.pathname);
|
|
1842
|
+
if (shapeLawCredentialInQueryOrFragment(parsed.href)) {
|
|
1843
|
+
noteDisplaySafeFailClosed("query-and-fragment-withheld");
|
|
1844
|
+
const root = redactSecrets(`${parsed.protocol}//${parsed.host}${safePath.text}`);
|
|
1845
|
+
return { text: `${root}?${WITHHELD_VALUE_TOKEN}`, failedClosed: true };
|
|
1846
|
+
}
|
|
1847
|
+
if (!safePath.withheld)
|
|
1848
|
+
return { text: redactSecrets(positionalLaw(raw)), failedClosed: false };
|
|
1849
|
+
noteDisplaySafeFailClosed("path-segment-withheld");
|
|
1850
|
+
const positional = positionalLaw(raw);
|
|
1851
|
+
const cut = positional.indexOf("?");
|
|
1852
|
+
const root = redactSecrets(`${parsed.protocol}//${parsed.host}${safePath.text}`);
|
|
1853
|
+
return { text: cut < 0 ? root.replace(/\/+$/, "") : `${root}${positional.slice(cut)}`, failedClosed: true };
|
|
1854
|
+
}
|
|
1855
|
+
export function buildDisplaySafeRefusal(text, sourceUrls) {
|
|
1856
|
+
if (text === "")
|
|
1857
|
+
return text;
|
|
1858
|
+
if (sourceUrls.some((url) => url !== "" && buildDisplaySafeUrlChecked(url).failedClosed)) {
|
|
1859
|
+
noteDisplaySafeFailClosed("refusal-text-withheld");
|
|
1860
|
+
return REFUSAL_WITHHELD_TEXT;
|
|
1861
|
+
}
|
|
1862
|
+
return redactSecrets(text);
|
|
1863
|
+
}
|
|
1864
|
+
const REFUSAL_WITHHELD_TEXT = "[route refusal text withheld: it quotes a configured URL that carries a credential, and the upstream wording cannot be re-redacted safely once the URL has been rewritten for display. " +
|
|
1865
|
+
"The machine-readable verdict is on the pairing field beside this one; fix the configuration so the credential is not in the URL.]";
|
|
1866
|
+
function noteDisplaySafeFailClosed(level) {
|
|
1867
|
+
if (displaySafeFailClosedWarned)
|
|
1868
|
+
return;
|
|
1869
|
+
displaySafeFailClosedWarned = true;
|
|
1870
|
+
process.emitWarning(`display-safe URL composition fell back to fail-closed (${level}): a part of the configured URL was judged to carry a credential that the composition cannot redact at byte granularity, so that whole part is withheld. ` +
|
|
1871
|
+
`The product is safe, but this deployment has an input hitting the composition seam — report it upstream. No original bytes are logged.`, "SemaRedactionFailClosed");
|
|
1728
1872
|
}
|
|
1729
1873
|
//# sourceMappingURL=redact.js.map
|
|
@@ -17,14 +17,15 @@ export declare const SEMA_PROVENANCE_KINDS: readonly ["agent_message"];
|
|
|
17
17
|
* 有意**不**放行的 lane 词(EXCLUDED,逐词记账;运行期落到「丢整键」臂 —— 与闭集外的未知词同臂,但这里的词是
|
|
18
18
|
* core 词表**内**的、经人裁定不上 wire 的):
|
|
19
19
|
* · `cross_session_message` —— core fc52b4d4 [ref] §4.1(session-box drain 铸;`from` 是对端**地址**、`peerMeta`
|
|
20
|
-
* 携 typed peer 记录)
|
|
21
|
-
*
|
|
20
|
+
* 携 typed peer 记录)。🔴 **7.91.0 订正**:`RunnerDeps.peerDirectory` 座已接线([ref])⇒ 「本仓不可达」那半句作废,
|
|
21
|
+
* 有席的部署上这个 lane 词真的会被铸出来;仍不放行的理由只剩**注入帧渲染形候 [ref] @server③ 表态**。
|
|
22
|
+
* 与 core-keyset-guard.ts ① 的 `crossSessionMessage` / ①-nested 的 `peerMeta` 同批同判,表态之后三处同翻。
|
|
22
23
|
* · `cross_session_notice` —— core 7.4.0 [ref] §4.4/§5.2(片4;本闭集 2026-09-05 真红出它)。**同一条车道的
|
|
23
24
|
* 第二个载体**,不是新判据:同一个 session-box drain 铸(`agents/peer-session-drain.js` 的 notice 臂),同一个
|
|
24
|
-
* `RunnerDeps.peerDirectory` 座前提
|
|
25
|
-
* ① 的同名排除键)一同候 [ref] 表态。放进 EXCLUDED 而不是 PROJECTED
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* `RunnerDeps.peerDirectory` 座前提(同样自 7.91.0 起在场);渲染形与它的载体 `crossSessionNotice`
|
|
26
|
+
* (core-keyset-guard.ts ① 的同名排除键)一同候 [ref] 表态。放进 EXCLUDED 而不是 PROJECTED,是**沿用**上一行的
|
|
27
|
+
* 裁定而不是新增特判:表态未出前放行一个 lane 词,等于替它预先声明一种 cli 渲染形。表态落定那天三处(本簿、
|
|
28
|
+
* 载体键、①-nested 的 `peerMeta`)同批翻。
|
|
28
29
|
*/
|
|
29
30
|
export declare const SEMA_PROVENANCE_KINDS_EXCLUDED: readonly ["cross_session_message", "cross_session_notice"];
|
|
30
31
|
/** 本仓两条腿入参的**形**(不是 core 类型:入参是运行期载荷,`kind` 先当 string 收、经闭集才成 typed)。 */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.91.1",
|
|
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",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"build:binary:run-local:darwin-arm64": "bun build --compile --target=bun-darwin-arm64 src/run-local.ts --outfile dist/run-local-darwin-arm64"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@sema-agent/core": "7.
|
|
62
|
+
"@sema-agent/core": "7.24.2",
|
|
63
63
|
"@sema-agent/settings-schema": "3.0.0",
|
|
64
64
|
"e2b": "^2.28.0",
|
|
65
65
|
"libsodium-wrappers": "^0.8.4",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"sharp": "^0.35.3"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
|
-
"@sema-agent/sdk": "9.
|
|
77
|
+
"@sema-agent/sdk": "9.10.0",
|
|
78
78
|
"@types/libsodium-wrappers": "^0.7.14",
|
|
79
79
|
"@types/node": "22.10.2",
|
|
80
80
|
"@types/pg": "^8.20.0",
|