@sema-agent/server 7.135.0 → 7.136.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 +64 -2
- package/USAGE.md +62 -25
- package/deploy/sema-up/README.md +1 -1
- package/deploy/sema-up/chart/templates/NOTES.txt +1 -1
- package/deploy/sema-up/chart/values.yaml +1 -1
- package/dist/approval-card.d.ts +60 -4
- package/dist/approval-card.js +18 -1
- package/dist/approval-content-kind.d.ts +1 -0
- package/dist/approval-content-kind.js +1 -1
- package/dist/auth-bridge.d.ts +34 -5
- package/dist/auth-bridge.js +20 -3
- package/dist/boot/budget-tracing.d.ts +1 -2
- package/dist/boot/budget-tracing.js +2 -2
- package/dist/boot/org-memory.js +1 -1
- package/dist/boot/resolve-spec.js +10 -7
- package/dist/boot/runner-deps.js +4 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-06-runners.d.ts +1 -1
- package/dist/boot/stage-07-capability-layer.d.ts +1 -1
- package/dist/boot/stage-08-reapers.d.ts +1 -1
- package/dist/boot/stage-09-leader.d.ts +1 -1
- package/dist/boot/stage-10-http-server.d.ts +1 -1
- package/dist/boot/stores.js +2 -3
- package/dist/boot/web-admin.js +10 -17
- package/dist/brain.js +12 -3
- package/dist/budget.d.ts +3 -3
- package/dist/budget.js +4 -0
- package/dist/capabilities/mcp-probe.d.ts +5 -4
- package/dist/capability-facts.d.ts +3 -7
- package/dist/capability-facts.js +3 -5
- package/dist/center-credential.d.ts +18 -4
- package/dist/center-credential.js +18 -3
- package/dist/config-catalog.js +12 -10
- package/dist/config-d-migration.js +1 -1
- package/dist/config-invariants.d.ts +1 -1
- package/dist/config-invariants.js +8 -0
- package/dist/config-lkg.d.ts +0 -38
- package/dist/config-lkg.js +1 -83
- package/dist/config-types.d.ts +12 -4
- package/dist/config.js +26 -8
- package/dist/deployment-shape.d.ts +1 -1
- package/dist/elicitation.d.ts +8 -7
- package/dist/elicitation.js +9 -8
- package/dist/file-history-disclosure.d.ts +6 -4
- package/dist/file-history-disclosure.js +22 -6
- package/dist/fleet-client.d.ts +32 -1
- package/dist/fleet-client.js +24 -4
- package/dist/fleet-lease.d.ts +7 -3
- package/dist/fleet-lease.js +31 -23
- package/dist/hooks/hook-llm.js +14 -8
- package/dist/hooks/hook-runner.d.ts +4 -4
- package/dist/hooks/hook-runner.js +2 -2
- package/dist/http/checkpoint-ctx.d.ts +28 -9
- package/dist/http/checkpoint-ctx.js +5 -1
- package/dist/http/dispatch.js +9 -9
- package/dist/http/resume-ctx-read.d.ts +2 -16
- package/dist/http/resume-ctx-read.js +2 -3
- package/dist/http/routes/approvals-assistant.d.ts +0 -2
- package/dist/http/routes/approvals-assistant.js +47 -12
- package/dist/http/routes/runs.js +2 -2
- package/dist/http/routes/session-sync.js +31 -9
- package/dist/http/routes/sessions.js +18 -14
- package/dist/http/submit-ctx.js +1 -1
- package/dist/http/wire-types.d.ts +5 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/model-route-gap.d.ts +49 -4
- package/dist/model-route-gap.js +34 -1
- package/dist/object-store-buckets.d.ts +13 -0
- package/dist/object-store-buckets.js +3 -0
- package/dist/observability/fail-open.d.ts +6 -6
- package/dist/observability/fail-open.js +6 -6
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/principal-context.d.ts +4 -1
- package/dist/observability/principal-context.js +6 -1
- package/dist/parked-decide.d.ts +4 -3
- package/dist/parked-decide.js +26 -7
- package/dist/peer-directory.d.ts +2 -1
- package/dist/peer-directory.js +5 -5
- package/dist/plugins/approval-ask-store-sql.d.ts +8 -0
- package/dist/plugins/approval-ask-store-sql.js +3 -0
- package/dist/plugins/blob-backend.js +2 -1
- package/dist/plugins/checkpoint-index-columns.d.ts +50 -1
- package/dist/plugins/checkpoint-index-columns.js +28 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +27 -3
- package/dist/plugins/checkpoint-store-sql.js +58 -29
- package/dist/plugins/file-history-store-sql.d.ts +6 -0
- package/dist/plugins/file-history-store-sql.js +30 -23
- package/dist/plugins/local-checkpoint-store.js +4 -3
- package/dist/plugins/one-time-migrations.d.ts +21 -28
- package/dist/plugins/one-time-migrations.js +39 -123
- package/dist/plugins/remote-env-k8s.d.ts +18 -5
- package/dist/plugins/remote-env-k8s.js +24 -7
- package/dist/plugins/s3-answer.d.ts +15 -0
- package/dist/plugins/s3-answer.js +5 -0
- package/dist/plugins/snapshot-bucket-presence.d.ts +39 -4
- package/dist/plugins/snapshot-bucket-presence.js +35 -7
- package/dist/plugins/sql-errors.d.ts +39 -0
- package/dist/plugins/sql-errors.js +49 -1
- package/dist/plugins/store-fault.d.ts +4 -0
- package/dist/plugins/store-fault.js +8 -0
- package/dist/plugins/tidb-pool.js +1 -1
- package/dist/plugins/web-search.d.ts +1 -1
- package/dist/plugins/web-search.js +2 -2
- package/dist/request-declaration-refusal.d.ts +94 -0
- package/dist/request-declaration-refusal.js +78 -0
- package/dist/request-image-urls.d.ts +6 -0
- package/dist/request-image-urls.js +27 -0
- package/dist/request-key-closure.d.ts +5 -0
- package/dist/request-key-closure.js +4 -1
- package/dist/runtime-caps-resolver.js +1 -1
- package/dist/sandbox-pkg-source.d.ts +28 -1
- package/dist/sandbox-pkg-source.js +1 -2
- package/dist/sealed-key.d.ts +19 -0
- package/dist/sealed-key.js +47 -4
- package/dist/session-incarnation.d.ts +16 -5
- package/dist/session-incarnation.js +7 -4
- package/dist/session-row.d.ts +3 -17
- package/dist/session-row.js +4 -0
- package/dist/session-sync.d.ts +15 -3
- package/dist/session-sync.js +5 -2
- package/dist/task-a2a.d.ts +52 -81
- package/dist/task-a2a.js +219 -89
- package/dist/task-mcp.d.ts +6 -14
- package/dist/task-mcp.js +16 -51
- package/dist/tool-approval.d.ts +23 -10
- package/dist/tool-approval.js +51 -36
- package/dist/trace/core-keyset-guard.d.ts +2 -2
- package/dist/trace/exit-seat.js +37 -13
- package/dist/trace/redact.d.ts +28 -12
- package/dist/trace/redact.js +233 -94
- package/dist/trace/self-minted-wire.d.ts +267 -0
- package/dist/trace/self-minted-wire.js +79 -0
- package/dist/url-credential-refusal.d.ts +52 -0
- package/dist/url-credential-refusal.js +14 -0
- package/dist/url-refusal.d.ts +13 -4
- package/dist/url-refusal.js +8 -2
- package/dist/workspace-space.d.ts +27 -0
- package/dist/workspace-space.js +26 -0
- package/package.json +3 -2
- package/scripts/drain-check-local.mjs +2 -1
- package/scripts/drain-check.mysql.sql +3 -1
- package/scripts/drain-check.pg.sql +3 -1
- package/skills/schedule.md +1 -1
- package/wire-changes/server@7.104.0.json +134 -0
- package/wire-changes/server@7.105.0.json +53 -0
- package/wire-changes/server@7.106.0.json +475 -0
- package/wire-changes/server@7.107.0.json +64 -0
- package/wire-changes/server@7.108.0.json +153 -0
- package/wire-changes/server@7.109.0.json +46 -0
- package/wire-changes/server@7.110.0.json +90 -0
- package/wire-changes/server@7.111.0.json +86 -0
- package/wire-changes/server@7.112.0.json +60 -0
- package/wire-changes/server@7.113.0.json +26 -0
- package/wire-changes/server@7.114.0.json +26 -0
- package/wire-changes/server@7.115.0.json +97 -0
- package/wire-changes/server@7.116.0.json +218 -0
- package/wire-changes/server@7.116.1.json +26 -0
- package/wire-changes/server@7.117.0.json +65 -0
- package/wire-changes/server@7.118.0.json +129 -0
- package/wire-changes/server@7.119.0.json +65 -0
- package/wire-changes/server@7.120.0.json +89 -0
- package/wire-changes/server@7.121.0.json +219 -0
- package/wire-changes/server@7.122.0.json +54 -0
- package/wire-changes/server@7.123.0.json +26 -0
- package/wire-changes/server@7.124.0.json +336 -0
- package/wire-changes/server@7.124.1.json +26 -0
- package/wire-changes/server@7.125.0.json +111 -0
- package/wire-changes/server@7.126.0.json +285 -0
- package/wire-changes/server@7.127.0.json +77 -0
- package/wire-changes/server@7.127.1.json +26 -0
- package/wire-changes/server@7.127.2.json +53 -0
- package/wire-changes/server@7.128.0.json +26 -0
- package/wire-changes/server@7.129.0.json +106 -0
- package/wire-changes/server@7.129.1.json +26 -0
- package/wire-changes/server@7.130.0.json +26 -0
- package/wire-changes/server@7.131.0.json +118 -0
- package/wire-changes/server@7.132.0.json +226 -0
- package/wire-changes/server@7.133.0.json +1155 -0
- package/wire-changes/server@7.134.0.json +107 -0
- package/wire-changes/server@7.135.0.json +174 -0
- package/wire-changes/server@7.136.0.json +448 -0
- package/dist/url-credential.d.ts +0 -52
- package/dist/url-credential.js +0 -49
package/dist/tool-approval.js
CHANGED
|
@@ -13,7 +13,7 @@ import { recordFailOpen } from "./observability/fail-open.js";
|
|
|
13
13
|
import { ownerOfCheckpointScope } from "./security.js";
|
|
14
14
|
import { deriveAskId, deriveAskScopedBatchId, deriveBatchId, MAX_DECISION_NOTE_CHARS, noteLandedOnRow, noteRecordedReceipt } from "./approval-ask-machine.js";
|
|
15
15
|
import { currentParkArm, MAX_RULE_OFFERS, buildApprovalCard, buildApprovalCardEnvelope, buildApprovalRequestFrame, buildReplayFrame, buildRevokeFrame, readDenialLimitFallback, readProbeCause, readProbeReason, readReadRootCandidate, readStoredCardEnvelope, readRuleEvidence, readAllowRuleShadowed, readRuleOffersAbsence, readRuleOffersAbsenceSeat, readParkRowTrueSeat, readAskClassPair, readClosedWordSeat, buildApprovalCompleteFrame, readRuleOfferList, } from "./approval-card.js";
|
|
16
|
-
import { askRowCarriesOwner, POLICY_REFUSAL_DECISION, projectAskTerminalClaimTruth } from "./plugins/approval-ask-store-sql.js";
|
|
16
|
+
import { askOwnerAdmits, askRowCarriesOwner, POLICY_REFUSAL_DECISION, projectAskTerminalClaimTruth } from "./plugins/approval-ask-store-sql.js";
|
|
17
17
|
import { APPROVAL_ENDING_CAUSES, SETTLE_OUTCOME, causeOfAskRow } from "./approval-deny-reasons.js";
|
|
18
18
|
import { settleByPolicy } from "./approval-policy-settlement.js";
|
|
19
19
|
import { governanceAskMarksFor, runWithGovernanceAskScope } from "./governance-ask-marks.js";
|
|
@@ -195,8 +195,11 @@ function mandatedFromSeat(seat) {
|
|
|
195
195
|
return false;
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
|
+
function rowOrUnknown(read) {
|
|
199
|
+
return read.kind === "row" ? read.row : null;
|
|
200
|
+
}
|
|
198
201
|
function askRowVisibleTo(row, principal) {
|
|
199
|
-
return row !== null && (row.owner
|
|
202
|
+
return row !== null && askOwnerAdmits(row.owner, principal);
|
|
200
203
|
}
|
|
201
204
|
function waitingLegsReached(entry, othersReached) {
|
|
202
205
|
return (entry.adopted === true ? 0 : 1) + othersReached;
|
|
@@ -206,7 +209,7 @@ function withConsumerDisclosure(result, waitingLegs) {
|
|
|
206
209
|
}
|
|
207
210
|
function livePendingRowOf(e) {
|
|
208
211
|
const listFrame = e.adopted === true ? e.cardFrame : (e.cardFrame ?? e.frame);
|
|
209
|
-
const approvalCard = e.adopted === true ? e.cardFrame.approvalCard : e.frame.approvalCard;
|
|
212
|
+
const approvalCard = e.adopted === true ? e.cardFrame.card.approvalCard : e.frame.approvalCard;
|
|
210
213
|
return {
|
|
211
214
|
approvalId: e.approvalId,
|
|
212
215
|
toolName: e.toolName,
|
|
@@ -2049,17 +2052,21 @@ export class ToolApprovalCoordinator {
|
|
|
2049
2052
|
}
|
|
2050
2053
|
const entry = this.liveEntryFor(id);
|
|
2051
2054
|
if (entry?.adopted === true)
|
|
2052
|
-
return this.
|
|
2053
|
-
if (
|
|
2054
|
-
return this.
|
|
2055
|
-
|
|
2056
|
-
|
|
2055
|
+
return this.respondByRow(entry, id, principal, parsed, httpReq);
|
|
2056
|
+
if (entry !== undefined && askOwnerAdmits(entry.owner, principal))
|
|
2057
|
+
return this.answerRegistration(entry, entry.owner, id, principal, parsed, httpReq);
|
|
2058
|
+
if (entry !== undefined && this.registrationHasRow(entry))
|
|
2059
|
+
return this.respondByRow(entry, id, principal, parsed, httpReq);
|
|
2060
|
+
return this.respondLate(id, principal, parsed, httpReq);
|
|
2057
2061
|
}
|
|
2058
|
-
|
|
2062
|
+
registrationHasRow(entry) {
|
|
2063
|
+
return this.askStore !== undefined && entry.askId !== undefined;
|
|
2064
|
+
}
|
|
2065
|
+
async respondByRow(entry, id, principal, parsed, httpReq) {
|
|
2059
2066
|
const store = this.askStore;
|
|
2060
2067
|
if (!store)
|
|
2061
2068
|
return this.notPending();
|
|
2062
|
-
const row = await this.askRowFor(store, id, "getAsk(respond-
|
|
2069
|
+
const row = rowOrUnknown(await this.askRowFor(store, id, "getAsk(respond-by-row)"));
|
|
2063
2070
|
if (!askRowVisibleTo(row, principal))
|
|
2064
2071
|
return this.notPending(NOT_PENDING_UNKNOWN_CAUSE);
|
|
2065
2072
|
if (row.state !== "STREAM_PENDING")
|
|
@@ -2067,7 +2074,7 @@ export class ToolApprovalCoordinator {
|
|
|
2067
2074
|
return this.answerRegistration(entry, row.owner, id, principal, parsed, httpReq);
|
|
2068
2075
|
}
|
|
2069
2076
|
answerRegistration(entry, judgedOwner, id, principal, parsed, httpReq) {
|
|
2070
|
-
const preRule = this.precheckEditedRuleBeforeDecision(entry, parsed);
|
|
2077
|
+
const preRule = this.precheckEditedRuleBeforeDecision(entry, judgedOwner, parsed);
|
|
2071
2078
|
if (preRule !== undefined)
|
|
2072
2079
|
return preRule;
|
|
2073
2080
|
if (parsed.value !== "deny" && policyCannotAnswer(heldAskOf(entry.requiresRealApproval === true), parsed.decidedBy)) {
|
|
@@ -2076,17 +2083,17 @@ export class ToolApprovalCoordinator {
|
|
|
2076
2083
|
const ruleEligibility = { eligible: true };
|
|
2077
2084
|
const store = this.askStore;
|
|
2078
2085
|
if (store && entry.askId !== undefined && entry.batchId !== undefined) {
|
|
2079
|
-
return this.respondWithCas(store, entry.askId, entry.batchId, judgedOwner, entry, parsed, ruleEligibility).then((cas) => cas.lost ? this.dispatchRowTruth(cas.row, id, parsed, httpReq, principal) : this.afterLiveDecision(cas.result, entry, parsed, principal, ruleEligibility));
|
|
2086
|
+
return this.respondWithCas(store, entry.askId, entry.batchId, judgedOwner, entry, parsed, ruleEligibility).then((cas) => cas.lost ? this.dispatchRowTruth(cas.row, id, parsed, httpReq, principal) : this.afterLiveDecision(cas.result, entry, judgedOwner, parsed, principal, ruleEligibility));
|
|
2080
2087
|
}
|
|
2081
|
-
return this.afterLiveDecision(this.finishRespond(entry, parsed), entry, parsed, principal, ruleEligibility);
|
|
2088
|
+
return this.afterLiveDecision(this.finishRespond(entry, judgedOwner, parsed), entry, judgedOwner, parsed, principal, ruleEligibility);
|
|
2082
2089
|
}
|
|
2083
|
-
afterLiveDecision(decided, entry, parsed, principal, ruleEligibility) {
|
|
2084
|
-
const settled = this.recordDeploymentListAnswer(decided, entry, parsed, principal, ruleEligibility);
|
|
2090
|
+
afterLiveDecision(decided, entry, judgedOwner, parsed, principal, ruleEligibility) {
|
|
2091
|
+
const settled = this.recordDeploymentListAnswer(decided, entry, judgedOwner, parsed, principal, ruleEligibility);
|
|
2085
2092
|
if (parsed.persistRule === undefined)
|
|
2086
2093
|
return settled;
|
|
2087
|
-
return this.persistRuleAfterDecision(settled, entry, parsed.persistRule, parsed.updatedInput !== undefined, ruleEligibility);
|
|
2094
|
+
return this.persistRuleAfterDecision(settled, entry, judgedOwner, parsed.persistRule, parsed.updatedInput !== undefined, ruleEligibility);
|
|
2088
2095
|
}
|
|
2089
|
-
recordDeploymentListAnswer(decided, entry, parsed, principal, eligibility) {
|
|
2096
|
+
recordDeploymentListAnswer(decided, entry, judgedOwner, parsed, principal, eligibility) {
|
|
2090
2097
|
const store = this.sessionGrants;
|
|
2091
2098
|
const sessionId = entry.sessionId;
|
|
2092
2099
|
if (parsed.value !== "allow_session" || !sessionId || store === undefined)
|
|
@@ -2101,9 +2108,9 @@ export class ToolApprovalCoordinator {
|
|
|
2101
2108
|
return { ...result, body: { ...result.body, rememberApplied: false } };
|
|
2102
2109
|
let rememberApplied = false;
|
|
2103
2110
|
try {
|
|
2104
|
-
await this.withStoreDeadline(store.grant(sessionId, entry.toolName, principal ??
|
|
2111
|
+
await this.withStoreDeadline(store.grant(sessionId, entry.toolName, principal ?? judgedOwner), "sessionGrants.grant(deployment-list)", DURABLE_CALL_TIMEOUT_MS);
|
|
2105
2112
|
rememberApplied = true;
|
|
2106
|
-
defaultLogger.info("approval_exemption_granted", { sessionId, toolName: entry.toolName, grantedBy: principal ??
|
|
2113
|
+
defaultLogger.info("approval_exemption_granted", { sessionId, toolName: entry.toolName, grantedBy: principal ?? judgedOwner });
|
|
2107
2114
|
}
|
|
2108
2115
|
catch (err) {
|
|
2109
2116
|
defaultLogger.warn("approval_exemption_grant_failed", { sessionId, toolName: entry.toolName, error: String(err).slice(0, 200) });
|
|
@@ -2111,7 +2118,7 @@ export class ToolApprovalCoordinator {
|
|
|
2111
2118
|
return { ...result, body: { ...result.body, rememberApplied } };
|
|
2112
2119
|
})();
|
|
2113
2120
|
}
|
|
2114
|
-
precheckEditedRuleBeforeDecision(entry, parsed) {
|
|
2121
|
+
precheckEditedRuleBeforeDecision(entry, judgedOwner, parsed) {
|
|
2115
2122
|
const persistRule = parsed.persistRule;
|
|
2116
2123
|
if (persistRule === undefined || persistRule.kind !== "text" || !persistRule.edited)
|
|
2117
2124
|
return undefined;
|
|
@@ -2120,7 +2127,7 @@ export class ToolApprovalCoordinator {
|
|
|
2120
2127
|
if (entry.governanceForced === true)
|
|
2121
2128
|
return undefined;
|
|
2122
2129
|
const command = entry.ruleLane?.command;
|
|
2123
|
-
if (this.ruleConsent === undefined || command === undefined ||
|
|
2130
|
+
if (this.ruleConsent === undefined || command === undefined || judgedOwner === null)
|
|
2124
2131
|
return undefined;
|
|
2125
2132
|
const verdict = precheckCardRuleText(persistRule.rule, command);
|
|
2126
2133
|
if (verdict === undefined || verdict.ok)
|
|
@@ -2155,9 +2162,9 @@ export class ToolApprovalCoordinator {
|
|
|
2155
2162
|
}
|
|
2156
2163
|
readApproval(id, principal) {
|
|
2157
2164
|
const entry = this.liveEntryFor(id);
|
|
2158
|
-
if (entry
|
|
2159
|
-
return this.
|
|
2160
|
-
if (entry !== undefined && (entry.owner
|
|
2165
|
+
if (entry !== undefined && this.registrationHasRow(entry))
|
|
2166
|
+
return this.readByRow(entry, id, principal);
|
|
2167
|
+
if (entry !== undefined && askOwnerAdmits(entry.owner, principal)) {
|
|
2161
2168
|
const body = { state: "pending", ...livePendingRowOf(entry) };
|
|
2162
2169
|
return { status: 200, body };
|
|
2163
2170
|
}
|
|
@@ -2166,11 +2173,18 @@ export class ToolApprovalCoordinator {
|
|
|
2166
2173
|
return this.notPending();
|
|
2167
2174
|
return this.readAskRowState(store, id, principal);
|
|
2168
2175
|
}
|
|
2169
|
-
async
|
|
2176
|
+
async readByRow(entry, id, principal) {
|
|
2170
2177
|
const store = this.askStore;
|
|
2171
2178
|
if (!store)
|
|
2172
2179
|
return this.notPending();
|
|
2173
|
-
const
|
|
2180
|
+
const read = await this.askRowFor(store, id, "getAsk(read-by-row)");
|
|
2181
|
+
if (read.kind === "unreadable") {
|
|
2182
|
+
if (entry.adopted === true || !askOwnerAdmits(entry.owner, principal))
|
|
2183
|
+
return this.notPending(NOT_PENDING_UNKNOWN_CAUSE);
|
|
2184
|
+
const body = { state: "pending", ...livePendingRowOf(entry) };
|
|
2185
|
+
return { status: 200, body };
|
|
2186
|
+
}
|
|
2187
|
+
const row = rowOrUnknown(read);
|
|
2174
2188
|
if (askRowVisibleTo(row, principal) && row.state === "STREAM_PENDING") {
|
|
2175
2189
|
const body = { state: "pending", ...livePendingRowOf(entry) };
|
|
2176
2190
|
return { status: 200, body };
|
|
@@ -2178,7 +2192,7 @@ export class ToolApprovalCoordinator {
|
|
|
2178
2192
|
return this.readStateOfRow(row, principal);
|
|
2179
2193
|
}
|
|
2180
2194
|
async readAskRowState(store, id, principal) {
|
|
2181
|
-
return this.readStateOfRow(await this.askRowFor(store, id, "getAsk(read)"), principal);
|
|
2195
|
+
return this.readStateOfRow(rowOrUnknown(await this.askRowFor(store, id, "getAsk(read)")), principal);
|
|
2182
2196
|
}
|
|
2183
2197
|
async readParkedGate(row) {
|
|
2184
2198
|
const gate = this.parkedGate;
|
|
@@ -2310,15 +2324,16 @@ export class ToolApprovalCoordinator {
|
|
|
2310
2324
|
return undefined;
|
|
2311
2325
|
}
|
|
2312
2326
|
async dispatchLateByRow(store, id, parsed, httpReq, principal) {
|
|
2313
|
-
return this.dispatchRowTruth(await this.askRowFor(store, id, "getAsk(respond-late)"), id, parsed, httpReq, principal);
|
|
2327
|
+
return this.dispatchRowTruth(rowOrUnknown(await this.askRowFor(store, id, "getAsk(respond-late)")), id, parsed, httpReq, principal);
|
|
2314
2328
|
}
|
|
2315
2329
|
async askRowFor(store, id, label) {
|
|
2316
2330
|
try {
|
|
2317
|
-
|
|
2331
|
+
const row = await this.withStoreDeadline(store.getAsk(id), label, DURABLE_CONVERGE_READ_TIMEOUT_MS);
|
|
2332
|
+
return row === null ? { kind: "absent" } : { kind: "row", row };
|
|
2318
2333
|
}
|
|
2319
2334
|
catch (err) {
|
|
2320
2335
|
this.noteStoreError(err, label);
|
|
2321
|
-
return
|
|
2336
|
+
return { kind: "unreadable" };
|
|
2322
2337
|
}
|
|
2323
2338
|
}
|
|
2324
2339
|
async dispatchRowTruth(row, id, parsed, httpReq, principal) {
|
|
@@ -2580,13 +2595,13 @@ export class ToolApprovalCoordinator {
|
|
|
2580
2595
|
},
|
|
2581
2596
|
};
|
|
2582
2597
|
}
|
|
2583
|
-
async persistRuleAfterDecision(settled, entry, persistRule, inputWasEdited, ruleEligibility) {
|
|
2598
|
+
async persistRuleAfterDecision(settled, entry, judgedOwner, persistRule, inputWasEdited, ruleEligibility) {
|
|
2584
2599
|
const result = await settled;
|
|
2585
2600
|
if (result.status !== 200)
|
|
2586
2601
|
return result;
|
|
2587
2602
|
const lane = this.ruleConsent;
|
|
2588
2603
|
const material = entry.ruleLane;
|
|
2589
|
-
const owner =
|
|
2604
|
+
const owner = judgedOwner;
|
|
2590
2605
|
const withFlag = (rulePersisted, ruleRefusal, echo) => ({
|
|
2591
2606
|
status: result.status,
|
|
2592
2607
|
body: { ...result.body, rulePersisted, ...(ruleRefusal !== undefined ? { ruleRefusal } : {}), ...(echo ?? {}) },
|
|
@@ -2708,11 +2723,11 @@ export class ToolApprovalCoordinator {
|
|
|
2708
2723
|
if (!converged) {
|
|
2709
2724
|
return { lost: false, result: this.notPending() };
|
|
2710
2725
|
}
|
|
2711
|
-
return { lost: false, result: withConsumerDisclosure(this.finishRespond(entry, parsed, { updatedInputDelivered: false, noteRecorded: noteLanded }), waitingLegsReached(entry, othersReached)) };
|
|
2726
|
+
return { lost: false, result: withConsumerDisclosure(this.finishRespond(entry, owner, parsed, { updatedInputDelivered: false, noteRecorded: noteLanded }), waitingLegsReached(entry, othersReached)) };
|
|
2712
2727
|
}
|
|
2713
2728
|
const payloadIsMine = ambiguousConfirmedRow === undefined ||
|
|
2714
2729
|
approvalPayloadFingerprint({ updatedInput: ambiguousConfirmedRow.updatedInput }) === approvalPayloadFingerprint({ updatedInput: parsed.updatedInput });
|
|
2715
|
-
const result = this.finishRespond(entry, parsed, {
|
|
2730
|
+
const result = this.finishRespond(entry, owner, parsed, {
|
|
2716
2731
|
noteRecorded: noteLanded,
|
|
2717
2732
|
...(winnerRow !== undefined ? { settleOutcome: outcomeOfDecidedRow(winnerRow), settleOutcomeIsThisRequest: ambiguousConfirmedRow === undefined } : {}),
|
|
2718
2733
|
...(entry.adopted === true ? { updatedInputDelivered: false } : ambiguousConfirmedRow !== undefined ? { updatedInputDelivered: payloadIsMine } : {}),
|
|
@@ -2720,7 +2735,7 @@ export class ToolApprovalCoordinator {
|
|
|
2720
2735
|
const othersReached = winnerRow !== undefined ? this.notifyExternalDecision(askId, outcomeOfDecidedRow(winnerRow)).settled : 0;
|
|
2721
2736
|
return { lost: false, result: withConsumerDisclosure(result, waitingLegsReached(entry, othersReached)) };
|
|
2722
2737
|
}
|
|
2723
|
-
finishRespond(entry, parsed, opts) {
|
|
2738
|
+
finishRespond(entry, judgedOwner, parsed, opts) {
|
|
2724
2739
|
let rememberApplied;
|
|
2725
2740
|
const home = standingAnswerHome(pendingEntryStandingAnswerFacts(entry));
|
|
2726
2741
|
let grantable;
|
|
@@ -2745,7 +2760,7 @@ export class ToolApprovalCoordinator {
|
|
|
2745
2760
|
if (oldest !== undefined)
|
|
2746
2761
|
this.allowAllSessions.delete(oldest);
|
|
2747
2762
|
}
|
|
2748
|
-
this.allowAllSessions.add(sessionAllowKey(
|
|
2763
|
+
this.allowAllSessions.add(sessionAllowKey(judgedOwner, entry.sessionId, sessionAllowCategory(entry.toolName), entry.grantBinding));
|
|
2749
2764
|
}
|
|
2750
2765
|
const allowed = parsed.value !== "deny";
|
|
2751
2766
|
const settleArgs = opts?.settleOutcome !== undefined ? settleArgsOfDecided(opts.settleOutcome) : { allowed, updatedInput: parsed.updatedInput, settledBy: liveSettledBy(parsed.decidedBy) };
|
|
@@ -218,8 +218,8 @@ type _GuardInboxSummaryReverse = AssertAllKeysHandled<Exclude<SummaryProjected |
|
|
|
218
218
|
type ParkArmKeys = keyof Extract<PendingAction, {
|
|
219
219
|
kind: "tool_approval";
|
|
220
220
|
}>;
|
|
221
|
-
type ParkArmQueueProjected = "toolName" | "toolCallId" | "boundInputHash" | "ruleOffers" | "hasBidiControls" | keyof import("../approval-card.js").ParkRowFacts;
|
|
222
|
-
type ParkArmQueueExcluded = "kind" | "args" | "batchToolCallIds" | "completedCallIds" | "capabilityId" | "contractId" | "shapeDigest" | "implementationRevision" | "family" | "pathTarget" | "hostTarget" | "targets" | "names" | "preview" | "previewWithheld" | "execCwd" | "denialLimitFallback" | "authoredBy"
|
|
221
|
+
type ParkArmQueueProjected = "toolName" | "toolCallId" | "boundInputHash" | "ruleOffers" | "hasBidiControls" | keyof import("../approval-card.js").ParkRowFacts | keyof import("../approval-card.js").SkillCardFacts;
|
|
222
|
+
type ParkArmQueueExcluded = "kind" | "args" | "batchToolCallIds" | "completedCallIds" | "capabilityId" | "contractId" | "shapeDigest" | "implementationRevision" | "family" | "pathTarget" | "hostTarget" | "targets" | "names" | "preview" | "previewWithheld" | "execCwd" | "denialLimitFallback" | "authoredBy";
|
|
223
223
|
type _GuardParkArmQueue = AssertAllKeysHandled<Exclude<ParkArmKeys, ParkArmQueueProjected | ParkArmQueueExcluded>>;
|
|
224
224
|
type _GuardParkArmQueueReverse = AssertAllKeysHandled<Exclude<ParkArmQueueProjected | ParkArmQueueExcluded, ParkArmKeys>>;
|
|
225
225
|
type _NoDoubleBookParkArmQueue = AssertAllKeysHandled<Extract<ParkArmQueueProjected, ParkArmQueueExcluded>>;
|
package/dist/trace/exit-seat.js
CHANGED
|
@@ -3,7 +3,7 @@ import { CALLER_TEXT_CUT_MARK } from "../caller-text-echo.js";
|
|
|
3
3
|
import { errorKindOf } from "../observability/err-text.js";
|
|
4
4
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
5
5
|
import { OVERSIZED_REDACTION_PLACEHOLDER } from "../observability/run-terminal.js";
|
|
6
|
-
import { proposeRedactionSpans, REDACTION_TOKEN_RE_SRC } from "./redact.js";
|
|
6
|
+
import { proposeRedactionSpans, readingHeadEnd, REDACTION_TOKEN_RE_SRC } from "./redact.js";
|
|
7
7
|
const EXIT_SEATS = {
|
|
8
8
|
"trace-frame-text": { scope: "free-text" },
|
|
9
9
|
"trace-frame-line": { scope: "free-text", maxChars: 300 },
|
|
@@ -38,8 +38,7 @@ function mergeSpans(spans) {
|
|
|
38
38
|
return out;
|
|
39
39
|
}
|
|
40
40
|
const TOKEN_AT = new RegExp(REDACTION_TOKEN_RE_SRC, "y");
|
|
41
|
-
function
|
|
42
|
-
let cut = room;
|
|
41
|
+
function safeCutPoint(gap, cut) {
|
|
43
42
|
const hi = gap.charCodeAt(cut - 1);
|
|
44
43
|
if (cut > 0 && hi >= 0xd800 && hi <= 0xdbff && (gap.charCodeAt(cut) & 0xfc00) === 0xdc00)
|
|
45
44
|
cut -= 1;
|
|
@@ -50,16 +49,19 @@ function cutPlain(gap, room) {
|
|
|
50
49
|
if (m !== null && open + m[0].length > cut)
|
|
51
50
|
cut = open;
|
|
52
51
|
}
|
|
53
|
-
return
|
|
52
|
+
return cut;
|
|
54
53
|
}
|
|
55
|
-
|
|
54
|
+
const cutPlain = (gap, room) => gap.slice(0, safeCutPoint(gap, room));
|
|
55
|
+
function renderOnce(text, groups, until = Number.POSITIVE_INFINITY) {
|
|
56
56
|
const parts = [];
|
|
57
57
|
let at = 0;
|
|
58
58
|
for (const g of groups) {
|
|
59
|
+
if (g.start >= until)
|
|
60
|
+
break;
|
|
59
61
|
parts.push(text.slice(at, g.start), g.repl);
|
|
60
62
|
at = g.end;
|
|
61
63
|
}
|
|
62
|
-
parts.push(text.slice(at));
|
|
64
|
+
parts.push(text.slice(at, until));
|
|
63
65
|
return parts.join("");
|
|
64
66
|
}
|
|
65
67
|
function emitAs(form, text) {
|
|
@@ -79,12 +81,18 @@ function emitAs(form, text) {
|
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
83
|
const layoutOf = (row) => (row.emit === undefined ? "multi-line" : "single-line");
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
const SCAN_WINDOW_FLOOR = 4096;
|
|
85
|
+
const SCAN_WINDOW_PER_BOUND = 8;
|
|
86
|
+
const scanWindowOf = (maxChars) => Math.max(SCAN_WINDOW_FLOOR, maxChars * SCAN_WINDOW_PER_BOUND);
|
|
87
|
+
function boundRow(out, row, cutUpstream) {
|
|
88
|
+
if (row.maxChars === undefined)
|
|
84
89
|
return out;
|
|
85
90
|
if (row.emit === undefined)
|
|
86
|
-
return cutPlain(out, row.maxChars);
|
|
87
|
-
|
|
91
|
+
return out.length <= row.maxChars ? out : cutPlain(out, row.maxChars);
|
|
92
|
+
if (out.length <= row.maxChars && !cutUpstream)
|
|
93
|
+
return out;
|
|
94
|
+
const room = row.maxChars - CALLER_TEXT_CUT_MARK.length;
|
|
95
|
+
return (out.length <= room ? out : cutPlain(out, room)) + CALLER_TEXT_CUT_MARK;
|
|
88
96
|
}
|
|
89
97
|
export function seatText(seat, text) {
|
|
90
98
|
const row = SEAT_ROWS.get(seat);
|
|
@@ -92,11 +100,27 @@ export function seatText(seat, text) {
|
|
|
92
100
|
throw new Error(`exit seat: ${JSON.stringify(seat)} is not a row of the seat table`);
|
|
93
101
|
let out;
|
|
94
102
|
try {
|
|
95
|
-
|
|
103
|
+
const layout = layoutOf(row);
|
|
104
|
+
const scanWindow = row.maxChars === undefined ? undefined : scanWindowOf(row.maxChars);
|
|
105
|
+
let windowEnd;
|
|
106
|
+
let regionEnd;
|
|
107
|
+
if (scanWindow !== undefined && text.length > scanWindow) {
|
|
108
|
+
const half = scanWindow >>> 1;
|
|
109
|
+
const region = safeCutPoint(text, readingHeadEnd(text, layout, half));
|
|
110
|
+
const end = safeCutPoint(text, readingHeadEnd(text, layout, scanWindow - half, region));
|
|
111
|
+
if (end < text.length) {
|
|
112
|
+
windowEnd = end;
|
|
113
|
+
regionEnd = region;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const head = windowEnd === undefined ? text : text.slice(0, windowEnd);
|
|
117
|
+
if (row.emit !== undefined && emitAs(row.emit, head) === "")
|
|
96
118
|
out = "";
|
|
97
119
|
else {
|
|
98
|
-
const
|
|
99
|
-
|
|
120
|
+
const emitUntil = regionEnd;
|
|
121
|
+
const extent = windowEnd === undefined ? "whole" : "head";
|
|
122
|
+
const rendered = renderOnce(head, mergeSpans(proposeRedactionSpans(head, row.scope, layout, extent)), emitUntil);
|
|
123
|
+
out = boundRow(row.emit === undefined ? rendered : emitAs(row.emit, rendered), row, windowEnd !== undefined);
|
|
100
124
|
}
|
|
101
125
|
}
|
|
102
126
|
catch (err) {
|
package/dist/trace/redact.d.ts
CHANGED
|
@@ -65,16 +65,6 @@ declare const DISPLAY_SAFE_URL_TOKEN = "\u00ABredacted:url\u00BB";
|
|
|
65
65
|
/** [ref]:出网代理 URL 的回显尺(`outbound-dispatcher.ts` `displayProxyUrl`)形不干净时整只用**同一枚**占位 —— 单独一行导出,
|
|
66
66
|
* 上面那行字面量保持 `const NAME = "…";` 形(`test/api-notice-text-freeze.test.ts` §6 的冻结扫描按这一形认替换 token)。 */
|
|
67
67
|
export { DISPLAY_SAFE_URL_TOKEN };
|
|
68
|
-
/**
|
|
69
|
-
* 名表的**只读导出**([ref]:第四处消费 —— 受理口的 URL 凭据判官 `url-credential.ts`;文档同步钉按它对表)。
|
|
70
|
-
* 表的属主仍是本模块的 {@link CREDENTIAL_NAME_ANCHORS};加一个名字只改那一处,本数组与下面的谓词随之现算。
|
|
71
|
-
*/
|
|
72
|
-
export declare const CREDENTIAL_PARAM_NAMES: readonly string[];
|
|
73
|
-
/**
|
|
74
|
-
* 「这个**已解码**的参数名是不是凭据名」([ref] 第四处消费)。入参是收方读到的那一形(`URLSearchParams` 解过一次码的名字),
|
|
75
|
-
* 判法与本模块 URL 参数臂同读 —— 同一只判定 {@link credentialNameAnchor}:整名在表里(ASCII 大小写不敏感,不做 Unicode 折叠)。
|
|
76
|
-
*/
|
|
77
|
-
export declare function isCredentialParamName(decodedName: string): boolean;
|
|
78
68
|
/**
|
|
79
69
|
* 🔴 **取证相的重扫模式(测试座,[ref])** —— 生产恒 `"incremental"`;`"full"` 是**参照语义** = 「没有可复用的上一次执行」:
|
|
80
70
|
* 每级五条取证臂整段重跑、URL 臂每段重扫,既不读足迹也不回放(池把每一级的脏区间当作「未知」交下去,与级 0 同一个读法)。
|
|
@@ -135,6 +125,32 @@ export declare function setRedactionObserver(fn: ((patternLabel: string, count:
|
|
|
135
125
|
* · `single-line`:出口在读者看见之前把文本压成一行(出口座的日志字段行 / 标题行:空白控制字符被删或折成空格)⇒ ①②③④。
|
|
136
126
|
*/
|
|
137
127
|
export type RedactionLayout = "multi-line" | "single-line";
|
|
128
|
+
/**
|
|
129
|
+
* 一段文本相对「它所在的那一整段」的**范围**(闭集两词;调用方对自己交来的文本的陈述,不是旋钮):
|
|
130
|
+
* · `whole`:这就是全部。所有「见收尾才认」的结构臂走到末尾仍没见收尾 ⇒ 这一起点不成 —— 判据 = 声明正则(`test/trace-redact.test.ts` 的真值表钉着扫描器与声明正则逐跨度等价);
|
|
131
|
+
* · `head`:这只是更长文本的头一段(出口座对有界行只扫一段头,见 `trace/exit-seat.ts` 的扫描窗)。**一条律:结构的判定走到这一段末尾还没走完 ⇒ 判定在更远处(未决)⇒ 从结构起点遮到这一段的末尾**
|
|
132
|
+
* (fail-closed:起点在、判定要看窗外,明文不许出门)。未决只有两种,同读一条臂:
|
|
133
|
+
* ① **收尾没见到** —— JSON 串值(要收尾引号)· URL authority(要 `@`;authority 一路走到末尾没有 `/` / 空白,里面有没有 `@` 都读成还在 userinfo 里)·
|
|
134
|
+
* SSH2 / PEM 栅栏(要收尾栅栏)· 带引号的强锚值(要收尾引号)· PuTTY 容器(终止符之后到末尾没见下一个版本头);
|
|
135
|
+
* ② **起头没读完**(起头本身不设长度上界,起点可以离末尾很远)—— PEM 起始栅栏行(标签之后到末尾一枚 `-----` 都没有,已读到的部分也还可能是合法栅栏行的前缀)· PuTTY 版本头(`<数字串>: ` 没写完)·
|
|
136
|
+
* 无头 .ppk 字段(`Private-Lines: <数字串>` 之后下一个体行的判定没走完)。
|
|
137
|
+
* PuTTY 容器臂的「无合格终止 ⇒ 吃到输入末尾」本来就是这一律在整段文本上的形,两种范围都吃到末尾;区别只在留痕 —— 整段读法上它是兜底(记 `server.redact.ppk-eat-to-end`),
|
|
138
|
+
* head 读法上终止可能在更远处,是未决(不记)。**未决一律不记 fail-open**:它是这一律的正常读数,不是回退;
|
|
139
|
+
* 由裸形 / 关键字 / 查询参数 / 环境变量赋值等**不靠收尾**的臂认出的凭据(值到字符类的自然右界)两种范围读法逐字相同。
|
|
140
|
+
*/
|
|
141
|
+
export type RedactionExtent = "whole" | "head";
|
|
142
|
+
/**
|
|
143
|
+
* 🔴 **出口座扫描窗的单位 = 读法单元,不是原始码元**(修复验证腿 high ①):从 `from`(缺省 0)起数 `units` 个**读法单元**(各读法里最少的那一读 —— 删得最多的 —— 剩下的码元),
|
|
144
|
+
* 返回原文里的终点(含 `≥ units` 个读法单元的前缀,至多是最短那一个的两倍;文本不够长 ⇒ `text.length`)。格式字符 / 控制字符 / 转义写法的不可见字符不计数:它们在读法格里被删,
|
|
145
|
+
* 整段读法认得出的凭据(`sk-` + 18 位 + 五千个零宽空格 + 余下 12 位)靠它们之后的字节凑够最短长度 —— 窗若按原始码元计,填充一撑就把证据推到窗外,窗读法只见前缀而漏。
|
|
146
|
+
* `from`:出门区与余量**各自从自己的起点数**(窗 = 出门区〔从头数半窗〕+ 余量〔从出门区终点起再数半窗〕),不是各自从头数「第一个 ≥ units 的终点」—— 后者遇到不可见填充会按翻倍
|
|
147
|
+
* 跳到同一个终点,余量塌成 0,被窗尾切开的凭据在出门区里露出半截(修复验证 r3 high)。
|
|
148
|
+
* 取舍:不可见填充很大的文本,窗随之延伸(最坏延伸到整段 = 整段读法的代价),换来「窗里的读法单元数恒 ≥ `units`」这一个不变量 —— 窗里每一读的视图都不短于 `units`。
|
|
149
|
+
* 终点不落在转义写法中间:前缀末尾还没写完的转义写法({@link trailingPartialEscapeStart},在读法后文本上判,{@link shortestReading})不计数、窗延伸到它写完 —— 出门区终点与窗尾都因此落在转义的边上,余量从干净的边起数。
|
|
150
|
+
* 复杂度:**第一趟**若可见占比 ≥ 一半(少量换行 / 色码)按占比补足缺口,均匀的文本一两趟落在终点附近;补不足(或占比低)的趟一律至少翻倍 —— 总趟数 O(log 终点)、总功 O(终点),
|
|
151
|
+
* 不存在逐趟只前进几个码元的爬行(4095 个可见 + 4000 个控制字符曾因此平方,K=4000 约 0.2–0.3 s)。判据与读法格同源(同一批切除点收集器,零第二份「什么算不可见」)。
|
|
152
|
+
*/
|
|
153
|
+
export declare function readingHeadEnd(text: string, layout: RedactionLayout, units: number, from?: number): number;
|
|
138
154
|
export declare function redactSecrets(text: string, opts?: {
|
|
139
155
|
observe?: boolean;
|
|
140
156
|
json?: boolean;
|
|
@@ -195,7 +211,7 @@ export type RedactionSpan = {
|
|
|
195
211
|
readonly repl: string;
|
|
196
212
|
};
|
|
197
213
|
export type { RedactionScope };
|
|
198
|
-
export declare function proposeRedactionSpans(text: string, scope: RedactionScope, layout: RedactionLayout): readonly RedactionSpan[];
|
|
214
|
+
export declare function proposeRedactionSpans(text: string, scope: RedactionScope, layout: RedactionLayout, extent: RedactionExtent): readonly RedactionSpan[];
|
|
199
215
|
/**
|
|
200
216
|
* 🔴 环 + 深度预算(2026-07-25 补)。原实现是纯递归、**既不记已访问节点也不限深度**,而它的调用位置是
|
|
201
217
|
* **最不可信的边界**:`toolStart`/`toolEnd` 把工具的 `args`/`output`/`structured` 直接喂进来。后果两条:
|
|
@@ -232,7 +248,7 @@ export declare function redactedPreview(value: unknown, cap?: number): string |
|
|
|
232
248
|
*
|
|
233
249
|
* 🔴 **[ref] 展示半场(7.90.0 / core 7.24.0):两条正交的律合成一次,名表的射程缩到不可约的那一半**。
|
|
234
250
|
* 改前内部只有一条:`redactSecrets(new URL(raw).href)` —— 自由文本那条**名单制**的律,query 的值只在键名
|
|
235
|
-
*
|
|
251
|
+
* 落在凭据名表 `CREDENTIAL_PARAM_NAMES`(或值本身像个密钥)时才遮,于是**没人列过的那个键名**就是它的盲点
|
|
236
252
|
* (`?sig=…` / `?auth=…` / 部署自定义的网关参数名)。现在前面先跑 core 的 `displayUrlOf`,它是**位置制**的:
|
|
237
253
|
* · userinfo **落地**(不是遮成记号 —— 它从**解析**组合 `scheme://host + path + query`,userinfo 结构上
|
|
238
254
|
* 进不了产物);凭据在 userinfo 这件事本身仍然响亮,只不过是在**声明关口**响
|