@sema-agent/client-core 0.109.0 → 0.111.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +342 -0
- package/README.md +88 -32
- package/dist/abortableSleep.d.ts +7 -0
- package/dist/abortableSleep.js +37 -0
- package/dist/adapt/arms.js +45 -11
- package/dist/adapt/toolCards.d.ts +3 -1
- package/dist/adapt/toolCards.js +4 -2
- package/dist/adapter/activeRunSelfHeal.d.ts +39 -0
- package/dist/adapter/activeRunSelfHeal.js +171 -3
- package/dist/adapter/downstream/eventToSdkMessage.js +20 -15
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -0
- package/dist/adapter/downstream/terminalToSdkResult.js +11 -0
- package/dist/adapter/runStream.d.ts +5 -0
- package/dist/adapter/runStream.js +15 -3
- package/dist/attachmentRoute.d.ts +20 -0
- package/dist/attachmentRoute.js +39 -0
- package/dist/attachmentsWireCaps.js +1 -1
- package/dist/builtinOutputStyles.d.ts +12 -0
- package/dist/builtinOutputStyles.js +147 -0
- package/dist/compactionStatus.d.ts +9 -0
- package/dist/compactionStatus.js +29 -5
- package/dist/controlRouter.js +2 -1
- package/dist/coreValuePorts.d.ts +39 -1
- package/dist/coreValuePorts.js +10 -0
- package/dist/declared/supportFloorDeclared.js +1 -1
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +138 -14
- package/dist/engineErrorCodes.d.ts +3 -0
- package/dist/engineErrorCodes.js +3 -0
- package/dist/engineHealthFacts.d.ts +20 -0
- package/dist/engineHealthFacts.js +42 -1
- package/dist/engineHealthProbeVerdict.d.ts +23 -0
- package/dist/engineHealthProbeVerdict.js +115 -0
- package/dist/engineInlineTaskStats.d.ts +4 -3
- package/dist/engineInlineTaskStats.js +18 -2
- package/dist/engineNoticeCodes.d.ts +10 -0
- package/dist/engineNoticeCodes.js +36 -6
- package/dist/engineRepoint.d.ts +147 -0
- package/dist/engineRepoint.js +310 -0
- package/dist/engineRowRef.d.ts +3 -0
- package/dist/engineRowRef.js +13 -1
- package/dist/engineSessionMessages.d.ts +2 -1
- package/dist/engineSessionMessages.js +5 -0
- package/dist/engineSwapCrossing.d.ts +57 -0
- package/dist/engineSwapCrossing.js +297 -0
- package/dist/engineUnavailable.d.ts +44 -0
- package/dist/engineUnavailable.js +492 -0
- package/dist/errorSupplementRoles.js +2 -1
- package/dist/eventLeg.js +3 -3
- package/dist/fleet/fleetProjection.js +3 -2
- package/dist/generated/engineFactTables.d.ts +2 -0
- package/dist/generated/engineFactTables.js +12 -0
- package/dist/generated/sdkFactTables.d.ts +2 -1
- package/dist/generated/sdkFactTables.js +5 -0
- package/dist/generated/settingsSchemaTables.d.ts +4 -0
- package/dist/generated/settingsSchemaTables.js +1 -0
- package/dist/hitl/approvalAskers.d.ts +6 -0
- package/dist/hitl/approvalAskers.js +30 -0
- package/dist/hitl/approvalCardReasons.js +6 -3
- package/dist/hitl/approvalDelivery.d.ts +1 -0
- package/dist/hitl/approvalDelivery.js +1 -1
- package/dist/hitl/approvalRequestFrameReading.d.ts +7 -0
- package/dist/hitl/approvalRequestFrameReading.js +11 -0
- package/dist/hitl/approvalResolution.d.ts +9 -2
- package/dist/hitl/approvalResolution.js +6 -1
- package/dist/hitl/askGateWire.js +5 -8
- package/dist/hitl/automaticAnswerVerdict.js +2 -2
- package/dist/hitl/decisionConflict.js +6 -3
- package/dist/hitl/decisionRefusal.d.ts +2 -0
- package/dist/hitl/decisionRefusal.js +8 -8
- package/dist/hitl/decisionRefusalCarrier.d.ts +3 -0
- package/dist/hitl/decisionRefusalCarrier.js +348 -0
- package/dist/hitl/decisionSend.d.ts +10 -0
- package/dist/hitl/decisionSend.js +57 -17
- package/dist/hitl/editedApprovalAcceptance.d.ts +25 -0
- package/dist/hitl/editedApprovalAcceptance.js +26 -0
- package/dist/hitl/elicitationRefusal.d.ts +4 -0
- package/dist/hitl/elicitationRefusal.js +23 -0
- package/dist/hitl/frameRouter.d.ts +2 -2
- package/dist/hitl/frameRouter.js +12 -33
- package/dist/hitl/gateIdentity.d.ts +5 -0
- package/dist/hitl/gateIdentity.js +23 -0
- package/dist/hitl/gateLedger.d.ts +0 -4
- package/dist/hitl/gateLedger.js +0 -19
- package/dist/hitl/hitlBridge.d.ts +7 -0
- package/dist/hitl/hitlBridge.js +14 -8
- package/dist/hitl/hitlHostSurface.d.ts +3 -1
- package/dist/hitl/hitlHostSurface.js +14 -4
- package/dist/hitl/hostWithdrawal.d.ts +15 -0
- package/dist/hitl/hostWithdrawal.js +38 -0
- package/dist/hitl/localAllowRedemption.d.ts +67 -0
- package/dist/hitl/localAllowRedemption.js +256 -0
- package/dist/hitl/parkResolver.js +32 -13
- package/dist/hitl/persistedRulesWire.d.ts +16 -0
- package/dist/hitl/persistedRulesWire.js +72 -2
- package/dist/hitl/planReviewWire.d.ts +3 -0
- package/dist/hitl/planReviewWire.js +37 -10
- package/dist/hitl/policyDenyCause.d.ts +1 -1
- package/dist/hitl/policyDenyCause.js +1 -1
- package/dist/hitl/resumeRunningCard.d.ts +1 -0
- package/dist/hitl/resumeRunningCard.js +1 -0
- package/dist/hitl/screenCardCarriers.d.ts +15 -0
- package/dist/hitl/screenCardCarriers.js +41 -0
- package/dist/hitl/screenDecisionCards.d.ts +98 -0
- package/dist/hitl/screenDecisionCards.js +362 -0
- package/dist/hitl/sessionPolicyWire.js +6 -4
- package/dist/hitl/standingRows.d.ts +4 -1
- package/dist/hitl/standingRows.js +33 -1
- package/dist/hitl/toolApprovalWire.d.ts +64 -15
- package/dist/hitl/toolApprovalWire.js +470 -125
- package/dist/hooksWireCaps.js +31 -1
- package/dist/hostSettingNoticeArm.d.ts +3 -0
- package/dist/hostSettingNoticeArm.js +12 -0
- package/dist/hostTurnSettings.d.ts +13 -4
- package/dist/hostTurnSettings.js +150 -10
- package/dist/humanTurnRead.js +11 -1
- package/dist/i18n/messages.en.d.ts +212 -0
- package/dist/i18n/messages.en.js +217 -5
- package/dist/i18n/messages.zh.js +235 -5
- package/dist/i18n/translate.d.ts +3 -0
- package/dist/i18n/translate.js +78 -10
- package/dist/i18n/zh.d.ts +1 -0
- package/dist/i18n/zh.js +1 -0
- package/dist/index.d.ts +56 -16
- package/dist/index.js +40 -12
- package/dist/inheritEnvCapability.js +2 -0
- package/dist/inputAuthor.d.ts +16 -0
- package/dist/inputAuthor.js +44 -0
- package/dist/interactiveHalt.js +2 -1
- package/dist/interactiveInterrupt.js +20 -2
- package/dist/interruptRefusalNote.d.ts +2 -0
- package/dist/interruptRefusalNote.js +17 -0
- package/dist/liveModelCatalog.d.ts +2 -0
- package/dist/liveModelCatalog.js +23 -9
- package/dist/liveQuestionStore.d.ts +4 -1
- package/dist/liveQuestionStore.js +12 -3
- package/dist/localEngineSeatReading.d.ts +2 -2
- package/dist/localEngineSeatReading.js +5 -3
- package/dist/localEngineSpawn.d.ts +0 -7
- package/dist/localEngineSpawn.js +0 -92
- package/dist/localEngineStep.d.ts +2 -2
- package/dist/localEngineStep.js +2 -0
- package/dist/mcpEngineLeg.d.ts +3 -0
- package/dist/mcpEngineLeg.js +38 -1
- package/dist/mcpPanel.js +2 -0
- package/dist/mcpReconnect.d.ts +9 -1
- package/dist/mcpReconnect.js +124 -19
- package/dist/mcpWireCaps.js +1 -1
- package/dist/model/engineModelWords.d.ts +3 -0
- package/dist/model/engineModelWords.js +13 -0
- package/dist/model/subagentModelWord.d.ts +21 -2
- package/dist/model/subagentModelWord.js +100 -29
- package/dist/modelCapabilityProbe.js +7 -43
- package/dist/modsFace.d.ts +8 -1
- package/dist/modsFace.js +27 -0
- package/dist/notifications.d.ts +36 -6
- package/dist/notifications.js +170 -20
- package/dist/ownKey.d.ts +6 -5
- package/dist/ownKey.js +31 -7
- package/dist/peerFrames.d.ts +40 -2
- package/dist/peerFrames.js +158 -3
- package/dist/pendingUserRow.d.ts +4 -0
- package/dist/pendingUserRow.js +16 -0
- package/dist/permissionsDeclaration.d.ts +1 -0
- package/dist/permissionsDeclaration.js +11 -1
- package/dist/planReviewCardFacts.d.ts +3 -0
- package/dist/planReviewCardFacts.js +52 -2
- package/dist/pluginHooksWire.d.ts +10 -1
- package/dist/pluginHooksWire.js +96 -7
- package/dist/printToolResultFrame.js +4 -2
- package/dist/promptBlockedCopy.js +11 -6
- package/dist/promptSuggestionBatch.d.ts +7 -0
- package/dist/promptSuggestionBatch.js +9 -0
- package/dist/promptSuggestionsTail.d.ts +39 -0
- package/dist/promptSuggestionsTail.js +116 -0
- package/dist/replayBody.js +10 -2
- package/dist/request/taskRequest.d.ts +5 -0
- package/dist/request/taskRequest.js +142 -21
- package/dist/requestCoordinate.d.ts +1 -0
- package/dist/requestCoordinate.js +13 -0
- package/dist/resumeRefusalCopy.d.ts +1 -3
- package/dist/resumeRefusalCopy.js +2 -1
- package/dist/retryStatus.d.ts +2 -2
- package/dist/retryStatus.js +2 -0
- package/dist/rewindArchiveReading.js +4 -4
- package/dist/runCancelContext.d.ts +2 -1
- package/dist/runCancelContext.js +1 -0
- package/dist/runPermissionModeSwitch.js +2 -2
- package/dist/scenarioRefusal.js +11 -13
- package/dist/scenarioSkills.js +11 -6
- package/dist/seam.d.ts +27 -2
- package/dist/seam.js +17 -1
- package/dist/seatContract.d.ts +189 -12
- package/dist/seatContract.js +401 -9
- package/dist/sessionBackground.js +2 -1
- package/dist/sessionBackgroundHandoff.js +2 -1
- package/dist/sessionCostReading.d.ts +70 -0
- package/dist/sessionCostReading.js +150 -0
- package/dist/sessionEngine.d.ts +2 -0
- package/dist/sessionEngine.js +111 -0
- package/dist/sessionHooksRoster.d.ts +4 -0
- package/dist/sessionHooksRoster.js +158 -0
- package/dist/sessionMemoryStatus.d.ts +2 -1
- package/dist/sessionMemoryStatus.js +2 -2
- package/dist/sessionReadRedaction.d.ts +7 -0
- package/dist/sessionReadRedaction.js +26 -0
- package/dist/sessionSyncFileHistory.d.ts +4 -0
- package/dist/sessionSyncFileHistory.js +27 -0
- package/dist/settingsHooksSalvage.js +2 -1
- package/dist/sseIdleTriage.d.ts +13 -1
- package/dist/sseIdleTriage.js +25 -6
- package/dist/storeDurabilityWord.d.ts +15 -0
- package/dist/storeDurabilityWord.js +18 -0
- package/dist/storePostureCapability.d.ts +7 -3
- package/dist/storePostureCapability.js +69 -39
- package/dist/subagent/engineSubagentResume.js +2 -2
- package/dist/subagent/engineSubagentTail.js +8 -1
- package/dist/subagentContentStore.d.ts +11 -0
- package/dist/subagentContentStore.js +28 -2
- package/dist/terminalStatuses.d.ts +1 -0
- package/dist/terminalStatuses.js +4 -1
- package/dist/toolResult.d.ts +1 -0
- package/dist/toolResult.js +2 -0
- package/dist/turnFailurePresentation.js +9 -2
- package/dist/typePins.d.ts +11 -0
- package/dist/usageAnalytics.d.ts +17 -0
- package/dist/usageAnalytics.js +44 -2
- package/dist/userAttachmentEnvelope.d.ts +2 -1
- package/dist/userAttachmentEnvelope.js +10 -0
- package/dist/wireErrorTriage.js +2 -1
- package/dist/wireFailureShape.d.ts +6 -5
- package/dist/wireFailureShape.js +150 -38
- package/dist/wireRefusalCopy.d.ts +16 -5
- package/dist/wireRefusalCopy.js +119 -86
- package/docs/INTEGRATION-CLIENTS.md +4228 -21
- package/package.json +7 -3
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { displayUntrusted } from '../displayUntrusted.js';
|
|
2
|
+
import { readOwnDataValue } from '../ownKey.js';
|
|
3
|
+
import { layerAdmissionWord } from '../settingsLayerAdmission.js';
|
|
4
|
+
import { parseLocalAllowRule } from './localAllowRule.js';
|
|
5
|
+
import { classifyRulesFailure, classifySkippedReason, readCcImportRedeemCounts, } from './persistedRulesWire.js';
|
|
6
|
+
export const LOCAL_ALLOW_NOT_REDEEMABLE_REASONS = Object.freeze(['managed_only', 'tighten_only', 'no_scope_root', 'no_consent', 'road_closed']);
|
|
7
|
+
export const LOCAL_ALLOW_UNKNOWN_CAUSES = Object.freeze(['input_unreadable', 'policy_unreadable', 'consent_unreadable', 'road_unknown']);
|
|
8
|
+
function verdict(v) {
|
|
9
|
+
return Object.freeze({ ...v });
|
|
10
|
+
}
|
|
11
|
+
const notRedeemable = (reason) => verdict({ kind: 'not_redeemable', reason });
|
|
12
|
+
const unknownBecause = (cause) => verdict({ kind: 'unknown', cause });
|
|
13
|
+
const PROJECT_SCOPE_PREFIX = 'project:';
|
|
14
|
+
const ALLOW_BEHAVIOR = 'allow';
|
|
15
|
+
const MANAGED_LAYER = 'policySettings';
|
|
16
|
+
const DETAIL_SHOWN_MAX = 400;
|
|
17
|
+
function policyStep(v) {
|
|
18
|
+
if (v === true)
|
|
19
|
+
return notRedeemable('managed_only');
|
|
20
|
+
if (v === false)
|
|
21
|
+
return undefined;
|
|
22
|
+
return unknownBecause('policy_unreadable');
|
|
23
|
+
}
|
|
24
|
+
function scopeRootOf(v) {
|
|
25
|
+
return typeof v === 'string' && v !== '' ? v : undefined;
|
|
26
|
+
}
|
|
27
|
+
function storeRowConsents(row, rule, scopeRoot) {
|
|
28
|
+
if (typeof row !== 'object' || row === null)
|
|
29
|
+
return false;
|
|
30
|
+
const behavior = readOwnDataValue(row, 'behavior');
|
|
31
|
+
const text = readOwnDataValue(row, 'rule');
|
|
32
|
+
const scope = readOwnDataValue(row, 'scope');
|
|
33
|
+
return behavior === ALLOW_BEHAVIOR && text === rule && (scope === 'global' || scope === PROJECT_SCOPE_PREFIX + scopeRoot);
|
|
34
|
+
}
|
|
35
|
+
function consentRecorded(store, rule, scopeRoot) {
|
|
36
|
+
if (typeof store !== 'object' || store === null)
|
|
37
|
+
return undefined;
|
|
38
|
+
const ok = readOwnDataValue(store, 'ok');
|
|
39
|
+
if (ok !== true)
|
|
40
|
+
return undefined;
|
|
41
|
+
const rows = readOwnDataValue(store, 'rules');
|
|
42
|
+
if (!Array.isArray(rows))
|
|
43
|
+
return undefined;
|
|
44
|
+
for (let i = 0; i < rows.length; i++) {
|
|
45
|
+
if (storeRowConsents(readOwnDataValue(rows, String(i)), rule, scopeRoot))
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
function roadStep(road) {
|
|
51
|
+
if (road === 'true')
|
|
52
|
+
return verdict({ kind: 'redeemable', via: 'consent' });
|
|
53
|
+
if (road === 'false' || road === 'absent')
|
|
54
|
+
return notRedeemable('road_closed');
|
|
55
|
+
return unknownBecause('road_unknown');
|
|
56
|
+
}
|
|
57
|
+
export function localAllowRedeemability(input) {
|
|
58
|
+
try {
|
|
59
|
+
if (typeof input !== 'object' || input === null)
|
|
60
|
+
return unknownBecause('input_unreadable');
|
|
61
|
+
const subject = readOwnDataValue(input, 'subject');
|
|
62
|
+
if (subject !== 'offered' && subject !== 'declared')
|
|
63
|
+
return unknownBecause('input_unreadable');
|
|
64
|
+
const source = readOwnDataValue(input, 'source');
|
|
65
|
+
if (!(subject === 'declared' && source === MANAGED_LAYER)) {
|
|
66
|
+
const policy = policyStep(readOwnDataValue(input, 'managedRulesOnly'));
|
|
67
|
+
if (policy !== undefined)
|
|
68
|
+
return policy;
|
|
69
|
+
}
|
|
70
|
+
const scopeRoot = scopeRootOf(readOwnDataValue(input, 'scopeRoot'));
|
|
71
|
+
if (subject === 'offered') {
|
|
72
|
+
if (scopeRoot === undefined)
|
|
73
|
+
return notRedeemable('no_scope_root');
|
|
74
|
+
return roadStep(readOwnDataValue(input, 'road'));
|
|
75
|
+
}
|
|
76
|
+
const workspace = readOwnDataValue(input, 'workspace');
|
|
77
|
+
let word;
|
|
78
|
+
try {
|
|
79
|
+
word = layerAdmissionWord(source, workspace, 'permissions', ALLOW_BEHAVIOR);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return unknownBecause('input_unreadable');
|
|
83
|
+
}
|
|
84
|
+
if (word === 'admitted')
|
|
85
|
+
return verdict({ kind: 'redeemable', via: 'layer' });
|
|
86
|
+
if (word === 'tighten_only')
|
|
87
|
+
return notRedeemable('tighten_only');
|
|
88
|
+
if (scopeRoot === undefined)
|
|
89
|
+
return notRedeemable('no_scope_root');
|
|
90
|
+
const rule = readOwnDataValue(input, 'rule');
|
|
91
|
+
if (typeof rule !== 'string' || rule === '')
|
|
92
|
+
return unknownBecause('input_unreadable');
|
|
93
|
+
const consent = consentRecorded(readOwnDataValue(input, 'store'), rule, scopeRoot);
|
|
94
|
+
if (consent === undefined)
|
|
95
|
+
return unknownBecause('consent_unreadable');
|
|
96
|
+
return consent ? verdict({ kind: 'redeemable', via: 'consent' }) : notRedeemable('no_consent');
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return unknownBecause('input_unreadable');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export const LOCAL_ALLOW_REDEMPTION_REFUSALS = Object.freeze([
|
|
103
|
+
'managed_only',
|
|
104
|
+
'no_scope_root',
|
|
105
|
+
'rule_shape',
|
|
106
|
+
'request_refused',
|
|
107
|
+
'preview_mismatch',
|
|
108
|
+
'engine_refused',
|
|
109
|
+
'ticket_dead',
|
|
110
|
+
]);
|
|
111
|
+
export const LOCAL_ALLOW_REDEMPTION_UNAVAILABLE_CAUSES = Object.freeze(['road_closed', 'road_unknown', 'policy_unreadable', 'input_unreadable', 'prepare_failed']);
|
|
112
|
+
export const LOCAL_ALLOW_REDEMPTION_UNKNOWN_CAUSES = Object.freeze(['redeem_unsettled', 'receipt_unreadable']);
|
|
113
|
+
function singleRuleLayerContent(canonical) {
|
|
114
|
+
return JSON.stringify({ permissions: { allow: [canonical] } });
|
|
115
|
+
}
|
|
116
|
+
function receipt(r) {
|
|
117
|
+
return Object.freeze({ ...r });
|
|
118
|
+
}
|
|
119
|
+
function detailOf(text) {
|
|
120
|
+
if (typeof text !== 'string')
|
|
121
|
+
return {};
|
|
122
|
+
const shown = displayUntrusted(text, { max: DETAIL_SHOWN_MAX });
|
|
123
|
+
return shown.trim() !== '' ? { detail: shown } : {};
|
|
124
|
+
}
|
|
125
|
+
const JUDGED_RECEIPT = {
|
|
126
|
+
managed_only: { kind: 'refused', reason: 'managed_only' },
|
|
127
|
+
no_scope_root: { kind: 'refused', reason: 'no_scope_root' },
|
|
128
|
+
road_closed: { kind: 'unavailable', cause: 'road_closed' },
|
|
129
|
+
road_unknown: { kind: 'unavailable', cause: 'road_unknown' },
|
|
130
|
+
policy_unreadable: { kind: 'unavailable', cause: 'policy_unreadable' },
|
|
131
|
+
input_unreadable: { kind: 'unavailable', cause: 'input_unreadable' },
|
|
132
|
+
tighten_only: { kind: 'unavailable', cause: 'input_unreadable' },
|
|
133
|
+
no_consent: { kind: 'unavailable', cause: 'input_unreadable' },
|
|
134
|
+
consent_unreadable: { kind: 'unavailable', cause: 'input_unreadable' },
|
|
135
|
+
};
|
|
136
|
+
function previewSingle(prep, scopeRoot) {
|
|
137
|
+
const preview = typeof prep === 'object' && prep !== null ? readOwnDataValue(prep, 'preview') : undefined;
|
|
138
|
+
if (typeof preview !== 'object' || preview === null)
|
|
139
|
+
return { mismatch: true };
|
|
140
|
+
const skipped = readOwnDataValue(preview, 'skipped');
|
|
141
|
+
if (Array.isArray(skipped) && skipped.length > 0) {
|
|
142
|
+
const first = readOwnDataValue(skipped, '0');
|
|
143
|
+
const reason = typeof first === 'object' && first !== null ? readOwnDataValue(first, 'reason') : undefined;
|
|
144
|
+
return { mismatch: true, skipped: typeof reason === 'string' ? classifySkippedReason(reason).text : '' };
|
|
145
|
+
}
|
|
146
|
+
if (!Array.isArray(skipped))
|
|
147
|
+
return { mismatch: true };
|
|
148
|
+
const candidates = readOwnDataValue(preview, 'candidates');
|
|
149
|
+
if (!Array.isArray(candidates) || candidates.length !== 1)
|
|
150
|
+
return { mismatch: true };
|
|
151
|
+
const c = readOwnDataValue(candidates, '0');
|
|
152
|
+
if (typeof c !== 'object' || c === null)
|
|
153
|
+
return { mismatch: true };
|
|
154
|
+
const behavior = readOwnDataValue(c, 'behavior');
|
|
155
|
+
const rule = readOwnDataValue(c, 'rule');
|
|
156
|
+
const scope = readOwnDataValue(c, 'scope');
|
|
157
|
+
const kind = typeof scope === 'object' && scope !== null ? readOwnDataValue(scope, 'kind') : undefined;
|
|
158
|
+
const root = typeof scope === 'object' && scope !== null ? readOwnDataValue(scope, 'root') : undefined;
|
|
159
|
+
if (behavior !== ALLOW_BEHAVIOR || typeof rule !== 'string' || kind !== 'project' || root !== scopeRoot)
|
|
160
|
+
return { mismatch: true };
|
|
161
|
+
return { rule };
|
|
162
|
+
}
|
|
163
|
+
export async function redeemReadOnlyRuleOffer(facade, input, opts) {
|
|
164
|
+
let canonical;
|
|
165
|
+
let offered;
|
|
166
|
+
let scopeRoot;
|
|
167
|
+
let settingsPath;
|
|
168
|
+
try {
|
|
169
|
+
if (typeof input !== 'object' || input === null)
|
|
170
|
+
return receipt({ kind: 'unavailable', cause: 'input_unreadable' });
|
|
171
|
+
const judged = localAllowRedeemability({
|
|
172
|
+
subject: 'offered',
|
|
173
|
+
managedRulesOnly: readOwnDataValue(input, 'managedRulesOnly'),
|
|
174
|
+
scopeRoot: readOwnDataValue(input, 'scopeRoot'),
|
|
175
|
+
road: readOwnDataValue(input, 'road'),
|
|
176
|
+
});
|
|
177
|
+
if (judged.kind !== 'redeemable')
|
|
178
|
+
return receipt(JUDGED_RECEIPT[judged.kind === 'not_redeemable' ? judged.reason : judged.cause]);
|
|
179
|
+
scopeRoot = readOwnDataValue(input, 'scopeRoot');
|
|
180
|
+
const path = readOwnDataValue(input, 'settingsPath');
|
|
181
|
+
if (typeof path !== 'string' || path === '')
|
|
182
|
+
return receipt({ kind: 'unavailable', cause: 'input_unreadable' });
|
|
183
|
+
settingsPath = path;
|
|
184
|
+
const rule = readOwnDataValue(input, 'rule');
|
|
185
|
+
const expected = readOwnDataValue(input, 'expectedToolName');
|
|
186
|
+
const deps = readOwnDataValue(input, 'deps');
|
|
187
|
+
if (typeof rule !== 'string' || deps === undefined || (expected !== undefined && typeof expected !== 'string'))
|
|
188
|
+
return receipt({ kind: 'unavailable', cause: 'input_unreadable' });
|
|
189
|
+
const parsed = parseLocalAllowRule(rule, expected, deps);
|
|
190
|
+
if (!parsed.ok)
|
|
191
|
+
return receipt({ kind: 'refused', reason: 'rule_shape', ...detailOf(parsed.error) });
|
|
192
|
+
canonical = parsed.canonical;
|
|
193
|
+
offered = rule;
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return receipt({ kind: 'unavailable', cause: 'input_unreadable' });
|
|
197
|
+
}
|
|
198
|
+
const signal = opts?.signal;
|
|
199
|
+
let prep;
|
|
200
|
+
try {
|
|
201
|
+
prep = await facade.ccImportPrepare([{ layer: 'localSettings', path: settingsPath, root: scopeRoot, content: singleRuleLayerContent(canonical) }], signal !== undefined ? { signal } : undefined);
|
|
202
|
+
}
|
|
203
|
+
catch (e) {
|
|
204
|
+
const f = classifyRulesFailure(e);
|
|
205
|
+
if (f.kind === 'lane-unavailable' || f.kind === 'route-missing')
|
|
206
|
+
return receipt({ kind: 'unavailable', cause: 'road_closed' });
|
|
207
|
+
if (f.kind === 'body-shape' || f.kind === 'field-refused' || f.kind === 'too-many-candidates' || f.kind === 'forbidden' || f.kind === 'operators-unconfigured') {
|
|
208
|
+
return receipt({ kind: 'refused', reason: 'request_refused' });
|
|
209
|
+
}
|
|
210
|
+
return receipt({ kind: 'unavailable', cause: 'prepare_failed' });
|
|
211
|
+
}
|
|
212
|
+
let ticket;
|
|
213
|
+
let storedRule;
|
|
214
|
+
try {
|
|
215
|
+
const single = previewSingle(prep, scopeRoot);
|
|
216
|
+
if ('mismatch' in single) {
|
|
217
|
+
return receipt(single.skipped !== undefined ? { kind: 'refused', reason: 'engine_refused', ...detailOf(single.skipped) } : { kind: 'refused', reason: 'preview_mismatch' });
|
|
218
|
+
}
|
|
219
|
+
if (single.rule !== canonical && single.rule !== offered)
|
|
220
|
+
return receipt({ kind: 'refused', reason: 'preview_mismatch' });
|
|
221
|
+
storedRule = single.rule;
|
|
222
|
+
const t = readOwnDataValue(prep, 'ticket');
|
|
223
|
+
if (typeof t !== 'string' || t === '')
|
|
224
|
+
return receipt({ kind: 'refused', reason: 'preview_mismatch' });
|
|
225
|
+
ticket = t;
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return receipt({ kind: 'refused', reason: 'preview_mismatch' });
|
|
229
|
+
}
|
|
230
|
+
let body;
|
|
231
|
+
try {
|
|
232
|
+
body = await facade.ccImportRedeem(ticket, signal !== undefined ? { signal } : undefined);
|
|
233
|
+
}
|
|
234
|
+
catch (e) {
|
|
235
|
+
const f = classifyRulesFailure(e);
|
|
236
|
+
if (f.kind === 'ticket-dead')
|
|
237
|
+
return receipt({ kind: 'refused', reason: 'ticket_dead' });
|
|
238
|
+
if (f.kind === 'lane-unavailable')
|
|
239
|
+
return receipt({ kind: 'unavailable', cause: 'road_closed' });
|
|
240
|
+
return receipt({ kind: 'unknown', cause: 'redeem_unsettled' });
|
|
241
|
+
}
|
|
242
|
+
const counts = readCcImportRedeemCounts(body);
|
|
243
|
+
if (counts === null)
|
|
244
|
+
return receipt({ kind: 'unknown', cause: 'receipt_unreadable' });
|
|
245
|
+
const refusedRow = counts.refused?.[0];
|
|
246
|
+
if (refusedRow !== undefined)
|
|
247
|
+
return receipt({ kind: 'refused', reason: 'engine_refused', ...detailOf(refusedRow.detail) });
|
|
248
|
+
if (counts.indeterminate.length > 0)
|
|
249
|
+
return receipt({ kind: 'unknown', cause: 'redeem_unsettled' });
|
|
250
|
+
const scope = PROJECT_SCOPE_PREFIX + scopeRoot;
|
|
251
|
+
if (counts.persisted === 1 && counts.deduped === 0)
|
|
252
|
+
return receipt({ kind: 'applied', outcome: 'persisted', rule: storedRule, scope });
|
|
253
|
+
if (counts.deduped === 1 && counts.persisted === 0)
|
|
254
|
+
return receipt({ kind: 'applied', outcome: 'already_live', rule: storedRule, scope });
|
|
255
|
+
return receipt({ kind: 'unknown', cause: 'receipt_unreadable' });
|
|
256
|
+
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { putOwnKey, readOwnDataValue } from '../ownKey.js';
|
|
1
|
+
import { guardedRead, putOwnKey, readOwnDataValue } from '../ownKey.js';
|
|
2
2
|
import { HitlBridge, NO_QUESTION_OVERLAY_REASON, findPendingForTask, isNoDecisionSurfaceReason, } from './hitlBridge.js';
|
|
3
3
|
import { approvalResolutionDetail, approvalResolutionStatusTag, directSafetyStopOf, resolutionOfDecisionFailure } from './approvalResolution.js';
|
|
4
4
|
import { readDecisionRefusalAsk } from './decisionRefusal.js';
|
|
5
5
|
import { publishQuestionFrame, registerLocalQuestionResponder, hasQuestionOverlay, } from '../liveQuestionStore.js';
|
|
6
6
|
import { hostLog } from '../host.js';
|
|
7
7
|
import { surfaceFsApprovalAndDecide } from './toolApprovalWire.js';
|
|
8
|
-
import { INTERRUPT_DENY_REASON, observeCancelByDeny } from './hitlHostSurface.js';
|
|
8
|
+
import { INTERRUPT_DENY_REASON, interruptDenyLifetime, observeCancelByDeny } from './hitlHostSurface.js';
|
|
9
9
|
import { denyAttributionOf, flushHeldWithInterruptRewrite, isAskTool } from './frameRouter.js';
|
|
10
10
|
import { invokeHostCallbackIsolated } from '../hostCallbackGuard.js';
|
|
11
11
|
import { inheritFrameBinding } from '../frameBinding.js';
|
|
12
12
|
import { approvalCallKey, askGateQuestionId } from './gateIdentity.js';
|
|
13
|
+
import { parkQuestionFrameBits, sourceGenerationNow } from './screenCardCarriers.js';
|
|
13
14
|
import { usableAskQuestions } from './parkOwnership.js';
|
|
14
15
|
import { readDecideReceipt } from '../decideReceipt.js';
|
|
15
16
|
import { decideFailureNote } from '../decideFailureNote.js';
|
|
@@ -65,6 +66,7 @@ async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGat
|
|
|
65
66
|
if (!hasQuestionOverlay()) {
|
|
66
67
|
return { kind: 'not_sent', lane: 'ask', cause: 'card_unavailable', detail: NO_QUESTION_OVERLAY_REASON };
|
|
67
68
|
}
|
|
69
|
+
const sourceGeneration = sourceGenerationNow(deps);
|
|
68
70
|
const found = await findPendingForTask(deps.client, taskId, isAskTool, signal ? { signal } : undefined, parkGatedCallId, (row) => isAskTool(typeof row.toolName === 'string' ? row.toolName : undefined));
|
|
69
71
|
if (!found.ok)
|
|
70
72
|
return { kind: 'not_sent', lane: 'ask', cause: found.code ?? 'fetch_failed', ...(found.reason !== '' ? { detail: found.reason } : {}), ...(found.rowVerdict !== undefined ? { rowVerdict: found.rowVerdict } : {}) };
|
|
@@ -86,11 +88,17 @@ async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGat
|
|
|
86
88
|
};
|
|
87
89
|
}
|
|
88
90
|
const questionId = askGateQuestionId(approvalCallKey(gatedCallId, taskId));
|
|
91
|
+
let withdrawn;
|
|
89
92
|
const answer = await new Promise(resolve => {
|
|
90
93
|
const unregister = registerLocalQuestionResponder(questionId, async (_id, a) => {
|
|
91
94
|
cleanup();
|
|
92
95
|
resolve(a);
|
|
93
96
|
return { ok: true };
|
|
97
|
+
}, (w) => {
|
|
98
|
+
withdrawn = w;
|
|
99
|
+
cleanup();
|
|
100
|
+
publishQuestionFrame({ type: 'question_complete', questionId });
|
|
101
|
+
resolve(null);
|
|
94
102
|
});
|
|
95
103
|
const onAbort = () => {
|
|
96
104
|
cleanup();
|
|
@@ -107,11 +115,15 @@ async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGat
|
|
|
107
115
|
}
|
|
108
116
|
signal?.addEventListener('abort', onAbort, { once: true });
|
|
109
117
|
onPresented?.();
|
|
110
|
-
publishQuestionFrame({ type: 'question', questionId, questions, ...(questionsFromModelCall ? { _sema_questionsFromModelCall: true } : {}) });
|
|
118
|
+
publishQuestionFrame({ type: 'question', questionId, questions, ...(questionsFromModelCall ? { _sema_questionsFromModelCall: true } : {}), ...parkQuestionFrameBits(taskId, gatedCallId, sourceGeneration) });
|
|
111
119
|
});
|
|
120
|
+
if (withdrawn !== undefined) {
|
|
121
|
+
hostLog('debug', `liveHitlAskWire: question-withdrawn-by-host card=${questionId} verdict=${withdrawn.rowVerdict.kind}`);
|
|
122
|
+
return { kind: 'not_sent', ...at, cause: 'withdrawn', toldBy: withdrawn.toldBy, rowVerdict: withdrawn.rowVerdict };
|
|
123
|
+
}
|
|
112
124
|
const bridge = new HitlBridge(deps.client, taskId, deps.onDecideOperation ? { onDecideOperation: deps.onDecideOperation } : undefined);
|
|
113
125
|
if (answer === null) {
|
|
114
|
-
observeCancelByDeny(bridge.decideTool({ decision: 'deny', reason: INTERRUPT_DENY_REASON }, gatedCallId,
|
|
126
|
+
observeCancelByDeny(bridge.decideTool({ decision: 'deny', reason: INTERRUPT_DENY_REASON }, gatedCallId, { signal: interruptDenyLifetime() }, pending), taskId);
|
|
115
127
|
return { kind: 'unsettled', ...at, cause: 'interrupted' };
|
|
116
128
|
}
|
|
117
129
|
let declinedReceipt;
|
|
@@ -155,7 +167,7 @@ function isFetchStepNoPending(outcome) {
|
|
|
155
167
|
return outcome.kind === 'not_sent' && outcome.cause === 'no_pending' && outcome.gatedCallId === undefined;
|
|
156
168
|
}
|
|
157
169
|
function isHumanDisposition(r) {
|
|
158
|
-
return r.kind === 'decided' || (r.kind === 'unsettled' && r.cause === 'interrupted') || (r.kind === 'not_sent' && r.cause === 'retracted');
|
|
170
|
+
return r.kind === 'decided' || (r.kind === 'unsettled' && r.cause === 'interrupted') || (r.kind === 'not_sent' && (r.cause === 'retracted' || r.cause === 'withdrawn'));
|
|
159
171
|
}
|
|
160
172
|
function failureReasonOf(r) {
|
|
161
173
|
if (r.kind === 'decided')
|
|
@@ -184,6 +196,7 @@ async function surfaceParkGate(park, ctx, gatedCallId, onPresented) {
|
|
|
184
196
|
...(onPresented ? { onPresented } : {}),
|
|
185
197
|
...(deps.onDecideOperation ? { onDecideOperation: deps.onDecideOperation } : {}),
|
|
186
198
|
...(decidedByReading !== undefined ? { approvalDecidedBy: decidedByReading } : {}),
|
|
199
|
+
...((read) => (typeof read === 'function' ? { engineGeneration: () => read.call(deps) } : {}))(guardedRead(() => deps.engineGeneration)),
|
|
187
200
|
}, taskId, argsByCallOf(led), ctx.signal, gatedCallId, park.toolName);
|
|
188
201
|
if (outcome.kind === 'decided' && outcome.decision === 'deny' && outcome.gatedCallId) {
|
|
189
202
|
led.markDenied(outcome.gatedCallId, denyAttributionOf(outcome.deny));
|
|
@@ -282,7 +295,8 @@ export async function resolvePark(park, ctx) {
|
|
|
282
295
|
if (outcome.kind !== 'decided') {
|
|
283
296
|
hostLog('debug', `liveHitlAskWire: gate not decided (${outcome.kind}/${outcome.cause}: ${failureReasonOf(outcome)}) — fail-soft to suspended terminal`);
|
|
284
297
|
const interrupted = outcome.kind === 'unsettled' && outcome.cause === 'interrupted';
|
|
285
|
-
const
|
|
298
|
+
const toldByHost = outcome.kind === 'not_sent' && outcome.cause === 'withdrawn';
|
|
299
|
+
const failedReason = interrupted || toldByHost
|
|
286
300
|
? undefined
|
|
287
301
|
: outcome.kind === 'not_sent' && outcome.cause === 'retracted'
|
|
288
302
|
? 'the approval card was retracted by the host without a decision (nothing was sent; the run stays parked and remains decidable elsewhere)'
|
|
@@ -312,13 +326,19 @@ export async function resolvePark(park, ctx) {
|
|
|
312
326
|
};
|
|
313
327
|
}
|
|
314
328
|
function failsoftWayOutOf(outcome) {
|
|
329
|
+
if (outcome === undefined)
|
|
330
|
+
return 'card';
|
|
331
|
+
if (typeof outcome !== 'object' || outcome === null)
|
|
332
|
+
return 'speak';
|
|
315
333
|
if (outcome.kind === 'not_sent' && (outcome.cause === 'row_unresumable' || (outcome.cause === 'safety_stop' && outcome.safetyCode === 'binding_missing')))
|
|
316
334
|
return 'reason';
|
|
317
|
-
if (outcome.kind === 'unsettled' && outcome.cause === 'engine_refused' && refusedParkFromError(outcome.refusal) !== null)
|
|
335
|
+
if (outcome.kind === 'unsettled' && outcome.cause === 'engine_refused' && (refusedParkFromError(outcome.refusal) !== null || outcome.refusal?.conflict === 'row_integrity'))
|
|
318
336
|
return 'cancel';
|
|
337
|
+
if (outcome.kind === 'unsettled' && outcome.cause === 'engine_refused')
|
|
338
|
+
return 'speak';
|
|
319
339
|
return 'card';
|
|
320
340
|
}
|
|
321
|
-
function failsoftReasonSentence(park, failedReason, terminal, wayOut
|
|
341
|
+
function failsoftReasonSentence(park, failedReason, terminal, wayOut) {
|
|
322
342
|
if (terminal !== undefined)
|
|
323
343
|
return terminal.errorMessage;
|
|
324
344
|
if (failedReason === undefined)
|
|
@@ -328,10 +348,9 @@ function failsoftReasonSentence(park, failedReason, terminal, wayOut = 'card') {
|
|
|
328
348
|
return renderMessage(msg('approval.park.stillParked', { gate, reason: failedReason }));
|
|
329
349
|
if (wayOut === 'cancel')
|
|
330
350
|
return renderMessage(msg('approval.park.refusedNotResumable', { gate, reason: failedReason }));
|
|
331
|
-
return (
|
|
332
|
-
' — the run is still parked on this approval: decide it on the card when it is shown again, or cancel the run.');
|
|
351
|
+
return renderMessage(msg(wayOut === 'speak' ? 'approval.park.resume.speak' : 'approval.park.resume.card', { gate, reason: failedReason }));
|
|
333
352
|
}
|
|
334
|
-
function failsoftEvents(park, ctx, gateAbortedByUser, failedReason, terminal, noDecisionSurface
|
|
353
|
+
function failsoftEvents(park, ctx, gateAbortedByUser, failedReason, terminal, noDecisionSurface, wayOut) {
|
|
335
354
|
const events = [
|
|
336
355
|
...flushHeldWithInterruptRewrite(ctx.led, {
|
|
337
356
|
terminal: park.pendingDone,
|
|
@@ -360,12 +379,12 @@ export function stalledTerminal(park, ctx, stalledRounds, lastStallReason, decid
|
|
|
360
379
|
`stopped re-attaching. Your last decision was accepted; sema did not observe the run move on after it — check the ` +
|
|
361
380
|
`transcript, decide the call again if the card comes back, or cancel the run.`;
|
|
362
381
|
hostLog('debug', `liveHitlAskWire: ${errorMessage}`);
|
|
363
|
-
return { kind: 'failsoft', events: failsoftEvents(park, ctx, false, undefined, { errorCode: 'hitl_stalled', errorMessage }) };
|
|
382
|
+
return { kind: 'failsoft', events: failsoftEvents(park, ctx, false, undefined, { errorCode: 'hitl_stalled', errorMessage }, false, failsoftWayOutOf(undefined)) };
|
|
364
383
|
}
|
|
365
384
|
const reason = `the run stayed parked across ${stalledRounds} consecutive re-attach rounds without any host progress ` +
|
|
366
385
|
`(last: ${lastStallReason ?? 'the engine kept parking'})`;
|
|
367
386
|
hostLog('debug', `liveHitlAskWire: ${reason} — fail-soft after the round committed`);
|
|
368
|
-
return { kind: 'failsoft', events: failsoftEvents(park, ctx, false, reason) };
|
|
387
|
+
return { kind: 'failsoft', events: failsoftEvents(park, ctx, false, reason, undefined, false, failsoftWayOutOf(undefined)) };
|
|
369
388
|
}
|
|
370
389
|
function notifyParkReattach(ctx, attempt, max, reason) {
|
|
371
390
|
invokeHostCallbackIsolated('liveHitlAskWire: onParkReattach', () => {
|
|
@@ -44,6 +44,11 @@ export interface CcImportRedeemCounts {
|
|
|
44
44
|
}
|
|
45
45
|
export type CcImportReceiptOutcome = 'persisted' | 'no-op' | 'refused' | 'indeterminate';
|
|
46
46
|
export declare function readCcImportRedeemCounts(body: unknown): CcImportRedeemCounts | null;
|
|
47
|
+
export interface CcImportRefusedReading {
|
|
48
|
+
readonly count: number;
|
|
49
|
+
readonly rows: readonly CcImportRedeemRefused[];
|
|
50
|
+
}
|
|
51
|
+
export declare function refusedRowOf(counts: CcImportRedeemCounts | null | undefined): CcImportRefusedReading | null;
|
|
47
52
|
export type RulesFailure = {
|
|
48
53
|
kind: 'lane-unavailable';
|
|
49
54
|
message: string;
|
|
@@ -189,6 +194,17 @@ export declare function classifySkippedReason(reason: string): {
|
|
|
189
194
|
code?: string;
|
|
190
195
|
text: string;
|
|
191
196
|
};
|
|
197
|
+
export interface CcImportSkippedGroup {
|
|
198
|
+
readonly entries: readonly string[];
|
|
199
|
+
readonly reason: string;
|
|
200
|
+
readonly code?: string;
|
|
201
|
+
}
|
|
202
|
+
export interface CcImportSkippedReading {
|
|
203
|
+
readonly shape: 'absent' | 'malformed' | 'read';
|
|
204
|
+
readonly groups: readonly CcImportSkippedGroup[];
|
|
205
|
+
readonly unreadable: number;
|
|
206
|
+
}
|
|
207
|
+
export declare function ccImportSkippedRowsOf(skipped: {} | null | undefined): CcImportSkippedReading;
|
|
192
208
|
export type RulePersistOutcome = {
|
|
193
209
|
state: 'unknown';
|
|
194
210
|
} | {
|
|
@@ -7,7 +7,7 @@ import { hostLog } from '../host.js';
|
|
|
7
7
|
import { msg, renderMessage } from '../i18n/translate.js';
|
|
8
8
|
import { appendOwnElement, guardedRead, readOwnDataValue } from '../ownKey.js';
|
|
9
9
|
import { observedPermissionRulesWrite, permissionRulesWriteAvailable } from '../permissionRulesWriteCapability.js';
|
|
10
|
-
import { isToolApprovalRespondReplayed, readToolApprovalRespondAck } from './toolApprovalWire.js';
|
|
10
|
+
import { isToolApprovalRespondParkedRedeemed, isToolApprovalRespondReplayed, readToolApprovalRespondAck } from './toolApprovalWire.js';
|
|
11
11
|
export function persistedRulesLaneAvailable(baseUrl) {
|
|
12
12
|
return engineCapTrue(baseUrl, 'permissionRules');
|
|
13
13
|
}
|
|
@@ -133,6 +133,35 @@ export function readCcImportRedeemCounts(body) {
|
|
|
133
133
|
return null;
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
|
+
const isCount = (r) => r.presence === 'present' && typeof r.value === 'number' && Number.isSafeInteger(r.value) && r.value >= 0;
|
|
137
|
+
const NO_REFUSED_ROWS = Object.freeze([]);
|
|
138
|
+
const NO_REFUSED = Object.freeze({ count: 0, rows: NO_REFUSED_ROWS });
|
|
139
|
+
export function refusedRowOf(counts) {
|
|
140
|
+
try {
|
|
141
|
+
if (typeof counts !== 'object' || counts === null)
|
|
142
|
+
return null;
|
|
143
|
+
if (!isCount(slotReadOf(counts, 'persisted')) || !isCount(slotReadOf(counts, 'deduped')))
|
|
144
|
+
return null;
|
|
145
|
+
const slot = slotReadOf(counts, 'refused');
|
|
146
|
+
if (slot.presence === 'absent')
|
|
147
|
+
return NO_REFUSED;
|
|
148
|
+
if (slot.presence !== 'present')
|
|
149
|
+
return null;
|
|
150
|
+
const rows = ownArrayItems(slot.value);
|
|
151
|
+
if (rows === undefined)
|
|
152
|
+
return null;
|
|
153
|
+
const kept = [];
|
|
154
|
+
for (const row of rows) {
|
|
155
|
+
if (typeof row !== 'object' || row === null)
|
|
156
|
+
return null;
|
|
157
|
+
kept.push(row);
|
|
158
|
+
}
|
|
159
|
+
return kept.length === 0 ? NO_REFUSED : Object.freeze({ count: kept.length, rows: Object.freeze(kept) });
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
136
165
|
export function classifyRulesFailure(e, context) {
|
|
137
166
|
const { status, errorCode, message, retryAfterSec, committed } = wireFailureShapeOf(e);
|
|
138
167
|
if (errorCode === 'capability.rule_store_required') {
|
|
@@ -635,9 +664,50 @@ export function classifySkippedReason(reason) {
|
|
|
635
664
|
return { text };
|
|
636
665
|
return { code: head, text };
|
|
637
666
|
}
|
|
667
|
+
const CC_IMPORT_SKIPPED_READ_BUDGET = 20_000;
|
|
668
|
+
const CC_IMPORT_SKIPPED_SHOWN_MAX = 2000;
|
|
669
|
+
function ccImportSkippedReading(shape, groups, unreadable) {
|
|
670
|
+
return Object.freeze({ shape, groups: Object.freeze([...groups]), unreadable });
|
|
671
|
+
}
|
|
672
|
+
export function ccImportSkippedRowsOf(skipped) {
|
|
673
|
+
if (skipped === undefined)
|
|
674
|
+
return ccImportSkippedReading('absent', [], 0);
|
|
675
|
+
const grouped = new Map();
|
|
676
|
+
let unreadable = 0;
|
|
677
|
+
try {
|
|
678
|
+
if (!Array.isArray(skipped))
|
|
679
|
+
return ccImportSkippedReading('malformed', [], 0);
|
|
680
|
+
const length = readOwnDataValue(skipped, 'length');
|
|
681
|
+
if (typeof length !== 'number' || !Number.isSafeInteger(length) || length < 0 || length > CC_IMPORT_SKIPPED_READ_BUDGET)
|
|
682
|
+
return ccImportSkippedReading('malformed', [], 0);
|
|
683
|
+
for (let i = 0; i < length; i++) {
|
|
684
|
+
const row = guardedRead(() => readOwnDataValue(skipped, String(i)));
|
|
685
|
+
const rule = typeof row === 'object' && row !== null ? guardedRead(() => readOwnDataValue(row, 'rule')) : undefined;
|
|
686
|
+
const reason = typeof row === 'object' && row !== null ? guardedRead(() => readOwnDataValue(row, 'reason')) : undefined;
|
|
687
|
+
if (typeof rule !== 'string' || typeof reason !== 'string') {
|
|
688
|
+
unreadable += 1;
|
|
689
|
+
continue;
|
|
690
|
+
}
|
|
691
|
+
const entries = grouped.get(reason);
|
|
692
|
+
if (entries === undefined)
|
|
693
|
+
grouped.set(reason, [displayUntrusted(rule, { max: CC_IMPORT_SKIPPED_SHOWN_MAX })]);
|
|
694
|
+
else
|
|
695
|
+
entries.push(displayUntrusted(rule, { max: CC_IMPORT_SKIPPED_SHOWN_MAX }));
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
catch {
|
|
699
|
+
return ccImportSkippedReading('malformed', [], 0);
|
|
700
|
+
}
|
|
701
|
+
const groups = [];
|
|
702
|
+
for (const [raw, entries] of grouped) {
|
|
703
|
+
const code = classifySkippedReason(raw).code;
|
|
704
|
+
groups.push(Object.freeze({ entries: Object.freeze(entries), reason: displayUntrusted(raw, { max: CC_IMPORT_SKIPPED_SHOWN_MAX }), ...(code !== undefined ? { code } : {}) }));
|
|
705
|
+
}
|
|
706
|
+
return ccImportSkippedReading('read', groups, unreadable);
|
|
707
|
+
}
|
|
638
708
|
export function readRulePersistOutcome(ack) {
|
|
639
709
|
const parsed = readToolApprovalRespondAck(ack);
|
|
640
|
-
if (parsed === undefined || isToolApprovalRespondReplayed(parsed))
|
|
710
|
+
if (parsed === undefined || isToolApprovalRespondReplayed(parsed) || isToolApprovalRespondParkedRedeemed(parsed))
|
|
641
711
|
return { state: 'unknown' };
|
|
642
712
|
if (parsed.rulePersisted === true)
|
|
643
713
|
return { state: 'persisted' };
|
|
@@ -41,6 +41,8 @@ export interface PlanReviewCardView {
|
|
|
41
41
|
readonly note?: string;
|
|
42
42
|
}
|
|
43
43
|
export declare function planReviewCardViewOf(frame: object | null | undefined, lang?: UiLanguage): PlanReviewCardView | undefined;
|
|
44
|
+
export type PlanReviewEvidenceMove = 'same' | 'moved' | 'unknown';
|
|
45
|
+
export declare function planReviewEvidenceMovedOf(shown: object | null | undefined, latest: object | null | undefined): PlanReviewEvidenceMove;
|
|
44
46
|
export declare function notePlanReviewAnsweredIfDecisive(questionId: unknown, answer: QuestionAnswer | null | undefined): void;
|
|
45
47
|
export { isPlanReviewPark };
|
|
46
48
|
export declare function _resetArmedPlanReviewsForTest(): void;
|
|
@@ -79,6 +81,7 @@ export interface PlanReviewOutcomeMeta {
|
|
|
79
81
|
decision: 'approve' | 'reject' | 'ask_again';
|
|
80
82
|
effect: PlanReviewDecisionEffect;
|
|
81
83
|
cause?: 'stored_form_unsupported';
|
|
84
|
+
questionId?: string;
|
|
82
85
|
}
|
|
83
86
|
export declare function planReviewOutcomeTail(taskId: string, decision: 'approve' | 'reject', effect: PlanReviewDecisionEffect, cause?: 'stored_form_unsupported'): string;
|
|
84
87
|
export type PlanReviewWireClient = {
|