@sema-agent/client-core 0.97.0 → 0.98.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 +429 -0
- package/README.md +74 -36
- package/dist/adapt/arms.d.ts +1 -0
- package/dist/adapt/arms.js +128 -34
- package/dist/adapt/ids.d.ts +12 -1
- package/dist/adapt/ids.js +59 -8
- package/dist/adapt/instanceLedger.d.ts +50 -0
- package/dist/adapt/instanceLedger.js +147 -0
- package/dist/adapt/textStream.d.ts +1 -0
- package/dist/adapt/textStream.js +24 -7
- package/dist/adapt/toolCards.d.ts +27 -5
- package/dist/adapt/toolCards.js +39 -6
- package/dist/adapt/wireShapes.js +6 -2
- package/dist/adapt.d.ts +2 -0
- package/dist/adapt.js +8 -3
- package/dist/adapter/activeRunSelfHeal.d.ts +5 -0
- package/dist/adapter/activeRunSelfHeal.js +51 -28
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +2 -5
- package/dist/adapter/downstream/eventToSdkMessage.js +27 -34
- package/dist/adapter/downstream/terminalToSdkResult.js +11 -4
- package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +5 -2
- package/dist/adapter/downstream/turnUsageToModelUsage.js +2 -0
- package/dist/adapter/runStream.js +29 -13
- package/dist/adapter/types.d.ts +4 -4
- package/dist/agentSession/backgroundView.js +2 -1
- package/dist/agentSession/engineAgentRegistryRead.d.ts +2 -2
- package/dist/agentSession/engineAgentRegistryRead.js +12 -13
- package/dist/agentsWireCaps.d.ts +8 -6
- package/dist/agentsWireCaps.js +177 -162
- package/dist/approvalDecidedByCapability.d.ts +0 -4
- package/dist/approvalDecidedByCapability.js +0 -6
- package/dist/approvalsStreamLiveCapability.d.ts +0 -4
- package/dist/approvalsStreamLiveCapability.js +0 -6
- package/dist/assistantInbox.d.ts +34 -0
- package/dist/assistantInbox.js +118 -0
- package/dist/centerWiringCapability.js +9 -1
- package/dist/clientSlice.d.ts +0 -9
- package/dist/clientSlice.js +0 -3
- package/dist/cloudConfigWireCaps.d.ts +4 -2
- package/dist/cloudConfigWireCaps.js +81 -61
- package/dist/compensations.js +1 -1
- package/dist/connectorStatus.d.ts +21 -0
- package/dist/connectorStatus.js +112 -0
- package/dist/controlRouter.d.ts +14 -1
- package/dist/controlRouter.js +68 -17
- package/dist/coreValuePorts.d.ts +3 -3
- package/dist/decideReceipt.d.ts +2 -2
- package/dist/decideReceipt.js +5 -2
- package/dist/declared/supportFloorDeclared.js +3 -3
- package/dist/deviceExecutorManagementCapability.d.ts +0 -4
- package/dist/deviceExecutorManagementCapability.js +0 -6
- package/dist/deviceRebind.d.ts +49 -1
- package/dist/deviceRebind.js +221 -3
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +250 -76
- package/dist/engineAgentAbsence.d.ts +1 -1
- package/dist/engineAgentPanelStore.d.ts +5 -4
- package/dist/engineAgentPanelStore.js +3 -12
- package/dist/engineCapReader.d.ts +0 -4
- package/dist/engineCapReader.js +1 -5
- package/dist/engineCapsCache.d.ts +4 -0
- package/dist/engineCapsCache.js +17 -12
- package/dist/engineClosedSets.d.ts +1 -0
- package/dist/engineClosedSets.js +4 -1
- package/dist/engineErrorCodes.d.ts +9 -2
- package/dist/engineErrorCodes.js +9 -1
- package/dist/engineIdentity.d.ts +1 -0
- package/dist/engineIdentity.js +8 -0
- package/dist/engineRowRef.d.ts +28 -0
- package/dist/engineRowRef.js +111 -0
- package/dist/engineSessionMessages.d.ts +67 -0
- package/dist/engineSessionMessages.js +364 -0
- package/dist/engineToolDirectory.d.ts +18 -0
- package/dist/engineToolDirectory.js +85 -0
- package/dist/engineUrl.d.ts +18 -0
- package/dist/engineUrl.js +52 -0
- package/dist/env/uiLanguage.d.ts +9 -0
- package/dist/env/uiLanguage.js +35 -0
- package/dist/eventLeg.d.ts +92 -0
- package/dist/eventLeg.js +285 -0
- package/dist/executionLaneCapability.d.ts +0 -4
- package/dist/executionLaneCapability.js +3 -16
- package/dist/fileHistoryCaptureCapability.d.ts +0 -4
- package/dist/fileHistoryCaptureCapability.js +5 -7
- package/dist/fleet/fleetLedger.d.ts +0 -3
- package/dist/fleet/fleetLedger.js +21 -36
- package/dist/fleet/fleetProjection.d.ts +2 -2
- package/dist/fleet/fleetProjection.js +10 -8
- package/dist/frameBinding.d.ts +5 -0
- package/dist/frameBinding.js +23 -0
- package/dist/gateFailureCodes.d.ts +2 -0
- package/dist/gateFailureCodes.js +15 -0
- package/dist/gateOutcome.d.ts +3 -1
- package/dist/gateOutcome.js +25 -6
- package/dist/gateVocabulary.d.ts +5 -0
- package/dist/gateVocabulary.js +64 -2
- package/dist/generated/engineAskFaceTables.js +2 -2
- package/dist/generated/engineFactTables.d.ts +6 -3
- package/dist/generated/engineFactTables.js +22 -4
- package/dist/generated/engineNoticeTables.js +9 -0
- package/dist/generated/toolNameTables.d.ts +1 -0
- package/dist/generated/toolNameTables.js +1 -0
- package/dist/hitl/allowRuleShadow.d.ts +6 -1
- package/dist/hitl/allowRuleShadow.js +21 -17
- package/dist/hitl/approvalCardReading.d.ts +15 -0
- package/dist/hitl/approvalCardReading.js +154 -0
- package/dist/hitl/approvalCardReasons.d.ts +13 -0
- package/dist/hitl/approvalCardReasons.js +120 -0
- package/dist/hitl/approvalHolds.d.ts +47 -15
- package/dist/hitl/approvalHolds.js +134 -28
- package/dist/hitl/approvalResolution.d.ts +51 -26
- package/dist/hitl/approvalResolution.js +86 -122
- package/dist/hitl/approvalsFeed.js +6 -18
- package/dist/hitl/askClassPair.d.ts +2 -0
- package/dist/hitl/askClassPair.js +1 -0
- package/dist/hitl/askGateWire.d.ts +20 -2
- package/dist/hitl/askGateWire.js +49 -1
- package/dist/hitl/askParkRowRouting.d.ts +5 -0
- package/dist/hitl/askParkRowRouting.js +32 -1
- package/dist/hitl/askSettlementLine.d.ts +18 -0
- package/dist/hitl/askSettlementLine.js +79 -0
- package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
- package/dist/hitl/automaticAnswerVerdict.js +21 -5
- package/dist/hitl/crashConverged.d.ts +11 -20
- package/dist/hitl/crashConverged.js +56 -0
- package/dist/hitl/crashConvergedNotice.d.ts +3 -1
- package/dist/hitl/crashConvergedNotice.js +48 -11
- package/dist/hitl/decisionConflict.js +3 -10
- package/dist/hitl/decisionRefusal.d.ts +40 -1
- package/dist/hitl/decisionRefusal.js +199 -42
- package/dist/hitl/frameRouter.d.ts +5 -2
- package/dist/hitl/frameRouter.js +20 -16
- package/dist/hitl/gateLedger.d.ts +2 -0
- package/dist/hitl/gateLedger.js +50 -13
- package/dist/hitl/hitlBridge.d.ts +1 -2
- package/dist/hitl/hitlBridge.js +10 -7
- package/dist/hitl/livePendingAsk.d.ts +3 -3
- package/dist/hitl/livePendingAsk.js +7 -18
- package/dist/hitl/parkResolver.d.ts +2 -24
- package/dist/hitl/parkResolver.js +61 -97
- package/dist/hitl/persistedRulesWire.d.ts +24 -0
- package/dist/hitl/persistedRulesWire.js +122 -2
- package/dist/hitl/planReviewWire.d.ts +26 -13
- package/dist/hitl/planReviewWire.js +112 -78
- package/dist/hitl/refusedToolNameProse.d.ts +0 -1
- package/dist/hitl/refusedToolNameProse.js +0 -3
- package/dist/hitl/replayedApproval.d.ts +4 -3
- package/dist/hitl/replayedApproval.js +7 -4
- package/dist/hitl/sessionPolicyDeliverable.js +2 -4
- package/dist/hitl/sessionPolicyWire.d.ts +32 -20
- package/dist/hitl/sessionPolicyWire.js +162 -52
- package/dist/hitl/standingRows.d.ts +20 -2
- package/dist/hitl/standingRows.js +69 -8
- package/dist/hitl/toolApprovalWire.d.ts +87 -152
- package/dist/hitl/toolApprovalWire.js +591 -380
- package/dist/hookMatcherVerdict.d.ts +6 -1
- package/dist/hookMatcherVerdict.js +14 -7
- package/dist/hooksWireCaps.d.ts +2 -2
- package/dist/hooksWireCaps.js +59 -55
- package/dist/i18n/messages.en.d.ts +121 -0
- package/dist/i18n/messages.en.js +119 -0
- package/dist/i18n/messages.zh.d.ts +3 -0
- package/dist/i18n/messages.zh.js +120 -0
- package/dist/i18n/translate.d.ts +25 -0
- package/dist/i18n/translate.js +127 -0
- package/dist/index.d.ts +53 -18
- package/dist/index.js +38 -10
- package/dist/inheritEnvCapability.d.ts +31 -0
- package/dist/inheritEnvCapability.js +104 -0
- package/dist/liveModelCatalog.d.ts +1 -2
- package/dist/liveModelCatalog.js +2 -6
- package/dist/liveQuestionStore.d.ts +2 -21
- package/dist/mcpLiveness.d.ts +2 -1
- package/dist/mcpProbeWire.d.ts +6 -1
- package/dist/mcpProbeWire.js +1 -1
- package/dist/mcpWireCaps.d.ts +13 -2
- package/dist/mcpWireCaps.js +48 -0
- package/dist/memoryEntriesWire.d.ts +4 -9
- package/dist/model/modelSupplyRules.d.ts +0 -2
- package/dist/model/modelSupplyRules.js +3 -12
- package/dist/model/modelsPolicy.d.ts +0 -5
- package/dist/model/modelsPolicy.js +6 -36
- package/dist/model/subagentModelWord.d.ts +31 -0
- package/dist/model/subagentModelWord.js +261 -0
- package/dist/notifications.d.ts +6 -0
- package/dist/notifications.js +71 -23
- package/dist/outputStyleSeatCapability.d.ts +0 -3
- package/dist/outputStyleSeatCapability.js +0 -3
- package/dist/ownKey.d.ts +15 -0
- package/dist/ownKey.js +60 -3
- package/dist/panelReduce.d.ts +15 -9
- package/dist/panelReduce.js +680 -549
- package/dist/panelStateHolder.d.ts +3 -7
- package/dist/panelStateHolder.js +14 -130
- package/dist/peerLaneCapability.d.ts +0 -4
- package/dist/peerLaneCapability.js +0 -6
- package/dist/permissionRulesWriteCapability.d.ts +0 -4
- package/dist/permissionRulesWriteCapability.js +0 -6
- package/dist/permissionWireCaps.d.ts +2 -2
- package/dist/permissionWireCaps.js +2 -0
- package/dist/permissionsAllowGrantCapability.d.ts +0 -4
- package/dist/permissionsAllowGrantCapability.js +0 -6
- package/dist/permissionsDeclaration.d.ts +0 -11
- package/dist/permissionsDeclaration.js +60 -53
- package/dist/pluginHooksWire.d.ts +1 -1
- package/dist/pluginHooksWire.js +3 -6
- package/dist/preemptWire.d.ts +44 -0
- package/dist/preemptWire.js +83 -0
- package/dist/printToolResultFrame.js +15 -4
- package/dist/replayBody.d.ts +3 -0
- package/dist/replayBody.js +14 -0
- package/dist/request/taskRequest.d.ts +0 -1
- package/dist/request/taskRequest.js +0 -3
- package/dist/resumeRefusalCopy.d.ts +2 -1
- package/dist/resumeRefusalCopy.js +38 -2
- package/dist/retryStatus.d.ts +8 -0
- package/dist/retryStatus.js +106 -1
- package/dist/rewindArchiveCapability.d.ts +0 -4
- package/dist/rewindArchiveCapability.js +2 -10
- package/dist/rewindArchiveReading.d.ts +0 -1
- package/dist/rewindArchiveReading.js +0 -3
- package/dist/runCancelContext.d.ts +2 -1
- package/dist/runCancelContext.js +4 -2
- package/dist/runReattachPolicy.d.ts +31 -0
- package/dist/runReattachPolicy.js +46 -0
- package/dist/runTerminal.d.ts +3 -6
- package/dist/runTerminal.js +8 -9
- package/dist/sandboxWire.d.ts +3 -1
- package/dist/sandboxWire.js +76 -27
- package/dist/scenarioWire.js +1 -1
- package/dist/seam.d.ts +24 -2
- package/dist/seam.js +15 -3
- package/dist/seatContract.d.ts +53 -10
- package/dist/seatContract.js +132 -81
- package/dist/sessionPolicyCapability.d.ts +0 -4
- package/dist/sessionPolicyCapability.js +0 -6
- package/dist/sessionSyncFileHistoryCapability.d.ts +0 -3
- package/dist/sessionSyncFileHistoryCapability.js +0 -3
- package/dist/skillToolListsCapability.d.ts +0 -3
- package/dist/skillToolListsCapability.js +0 -3
- package/dist/sqlEngineCapability.d.ts +0 -4
- package/dist/sqlEngineCapability.js +0 -6
- package/dist/steerPriorityCapability.d.ts +0 -3
- package/dist/steerPriorityCapability.js +0 -3
- package/dist/streamDrainingLegs.d.ts +4 -0
- package/dist/streamDrainingLegs.js +6 -1
- package/dist/subagent/engineCompactWire.d.ts +0 -1
- package/dist/subagent/engineCompactWire.js +7 -5
- package/dist/subagent/engineTaskHandleWire.js +4 -7
- package/dist/subagentContentStore.js +1 -11
- package/dist/submitReopen.d.ts +24 -0
- package/dist/submitReopen.js +75 -0
- package/dist/terminalStatuses.d.ts +3 -0
- package/dist/terminalStatuses.js +10 -2
- package/dist/toolResult.d.ts +10 -1
- package/dist/toolResult.js +34 -6
- package/dist/toolRoster.d.ts +0 -2
- package/dist/toolRoster.js +0 -2
- package/dist/turnFailurePresentation.d.ts +28 -0
- package/dist/turnFailurePresentation.js +205 -0
- package/dist/userInvokedSkillsCapability.d.ts +0 -3
- package/dist/userInvokedSkillsCapability.js +0 -3
- package/dist/webSearchBackendCapability.d.ts +0 -4
- package/dist/webSearchBackendCapability.js +0 -6
- package/dist/wireErrorTriage.js +5 -24
- package/dist/wireFailureShape.d.ts +62 -5
- package/dist/wireFailureShape.js +105 -5
- package/dist/wireRefusalCopy.d.ts +12 -2
- package/dist/wireRefusalCopy.js +50 -52
- package/dist/workflowsJournalCapability.d.ts +0 -4
- package/dist/workflowsJournalCapability.js +0 -6
- package/dist/writeProtectionCapability.d.ts +0 -4
- package/dist/writeProtectionCapability.js +0 -6
- package/docs/INTEGRATION-CLIENTS.md +1305 -46
- package/package.json +5 -4
- package/dist/attachmentSeatCapability.d.ts +0 -12
- package/dist/attachmentSeatCapability.js +0 -23
- package/dist/hitl/approvalOutcomeNote.d.ts +0 -10
- package/dist/hitl/approvalOutcomeNote.js +0 -29
- package/dist/sessionReadRedactionCapability.d.ts +0 -13
- package/dist/sessionReadRedactionCapability.js +0 -35
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { displayUntrusted, quoteUntrustedForSentence } from '../displayUntrusted.js';
|
|
1
2
|
import { engineCapTrue } from '../engineCapsCache.js';
|
|
2
3
|
import { CORE_RULE_BEHAVIORS } from '../generated/engineFactTables.js';
|
|
3
4
|
import { wireFailureShapeOf } from '../wireFailureShape.js';
|
|
4
5
|
import { CAPABILITY_OPERATOR_PRINCIPALS_REQUIRED } from '../engineErrorCodes.js';
|
|
5
6
|
import { hostLog } from '../host.js';
|
|
7
|
+
import { guardedRead, readOwnDataValue } from '../ownKey.js';
|
|
6
8
|
import { observedPermissionRulesWrite, permissionRulesWriteAvailable } from '../permissionRulesWriteCapability.js';
|
|
7
|
-
import { readToolApprovalRespondAck } from './toolApprovalWire.js';
|
|
9
|
+
import { isToolApprovalRespondReplayed, readToolApprovalRespondAck } from './toolApprovalWire.js';
|
|
8
10
|
export function persistedRulesLaneAvailable(baseUrl) {
|
|
9
11
|
return engineCapTrue(baseUrl, 'permissionRules');
|
|
10
12
|
}
|
|
@@ -112,6 +114,124 @@ export const PERSISTED_RULE_BEHAVIOR_UNKNOWN = '(unknown)';
|
|
|
112
114
|
export function persistedRuleBehaviorLabel(rule) {
|
|
113
115
|
return rowStr(rule, 'behavior') ?? PERSISTED_RULE_BEHAVIOR_UNKNOWN;
|
|
114
116
|
}
|
|
117
|
+
const PERSISTED_RULE_ORIGIN_PHRASES = Object.freeze({
|
|
118
|
+
user: 'added by you',
|
|
119
|
+
'imported-cc': 'imported',
|
|
120
|
+
starter: 'preset',
|
|
121
|
+
});
|
|
122
|
+
const UNKNOWN_ORIGIN_PHRASE = 'an origin this build does not know';
|
|
123
|
+
const NO_ORIGIN_PHRASE = 'unknown origin';
|
|
124
|
+
function ownSlot(o, key) {
|
|
125
|
+
if (typeof o !== 'object' || o === null)
|
|
126
|
+
return undefined;
|
|
127
|
+
return guardedRead(() => readOwnDataValue(o, key));
|
|
128
|
+
}
|
|
129
|
+
const ORIGINS_READ_MAX = 256;
|
|
130
|
+
export function persistedRuleAddOriginLabel(origin) {
|
|
131
|
+
return typeof origin === 'string' && Object.hasOwn(PERSISTED_RULE_ORIGIN_PHRASES, origin)
|
|
132
|
+
? PERSISTED_RULE_ORIGIN_PHRASES[origin]
|
|
133
|
+
: UNKNOWN_ORIGIN_PHRASE;
|
|
134
|
+
}
|
|
135
|
+
export function persistedRuleOriginsLabel(rule) {
|
|
136
|
+
const adds = ownSlot(rule, 'adds');
|
|
137
|
+
const isArr = guardedRead(() => (Array.isArray(adds) ? true : undefined));
|
|
138
|
+
if (isArr !== true)
|
|
139
|
+
return NO_ORIGIN_PHRASE;
|
|
140
|
+
const lenRaw = ownSlot(adds, 'length');
|
|
141
|
+
const len = typeof lenRaw === 'number' && Number.isSafeInteger(lenRaw) && lenRaw > 0 ? Math.min(lenRaw, ORIGINS_READ_MAX) : 0;
|
|
142
|
+
const seen = [];
|
|
143
|
+
for (let i = 0; i < len; i++) {
|
|
144
|
+
const origin = ownSlot(ownSlot(adds, String(i)), 'origin');
|
|
145
|
+
const phrase = persistedRuleAddOriginLabel(typeof origin === 'string' ? origin : undefined);
|
|
146
|
+
if (!seen.includes(phrase))
|
|
147
|
+
seen.push(phrase);
|
|
148
|
+
}
|
|
149
|
+
return seen.length === 0 ? NO_ORIGIN_PHRASE : seen.join(' + ');
|
|
150
|
+
}
|
|
151
|
+
const UNKNOWN_SCOPE_PHRASE = 'a scope this build does not know';
|
|
152
|
+
export function persistedRuleScopeLabel(scope) {
|
|
153
|
+
if (scope === 'global')
|
|
154
|
+
return 'all projects';
|
|
155
|
+
if (typeof scope === 'string' && scope.startsWith('project:') && scope.length > 'project:'.length) {
|
|
156
|
+
const shown = displayUntrusted(scope.slice('project:'.length), { max: 400, blanks: true });
|
|
157
|
+
return shown === '' ? UNKNOWN_SCOPE_PHRASE : shown;
|
|
158
|
+
}
|
|
159
|
+
return UNKNOWN_SCOPE_PHRASE;
|
|
160
|
+
}
|
|
161
|
+
const PERSISTED_RULE_REVOKE_LINES = Object.freeze({
|
|
162
|
+
removed: {
|
|
163
|
+
yes: {
|
|
164
|
+
notice: '{rule}: a tombstone was written, but the rule is still live — it was approved again during the call.',
|
|
165
|
+
change: 'Revoked saved rule {rule} (still live — approved again meanwhile)',
|
|
166
|
+
},
|
|
167
|
+
unknown: {
|
|
168
|
+
notice: '{rule}: a tombstone was written, but whether the rule is still live could not be confirmed — treat it as still in effect and check the list.',
|
|
169
|
+
change: 'Revoked saved rule {rule} (liveness could not be confirmed — treated as still in effect)',
|
|
170
|
+
},
|
|
171
|
+
no: { notice: 'Removed {rule}.', change: 'Revoked saved rule {rule}' },
|
|
172
|
+
},
|
|
173
|
+
'nothing-written': {
|
|
174
|
+
yes: {
|
|
175
|
+
notice: '{rule}: nothing was written, and the rule is still live — it was not removed; check the list.',
|
|
176
|
+
change: 'Removing saved rule {rule} wrote nothing — the rule is still live',
|
|
177
|
+
},
|
|
178
|
+
unknown: {
|
|
179
|
+
notice: '{rule}: nothing was written, and whether the rule is still live could not be confirmed — treat it as still in effect and check the list.',
|
|
180
|
+
change: 'Removing saved rule {rule} wrote nothing — liveness could not be confirmed',
|
|
181
|
+
},
|
|
182
|
+
no: { notice: '{rule}: nothing to remove.', change: 'Removing saved rule {rule} wrote nothing (nothing to remove)' },
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
const REVOKE_UNKNOWN_STATUS = Object.freeze({
|
|
186
|
+
absent: {
|
|
187
|
+
notice: '{rule}: the engine did not say what this removal did, so whether anything was removed is unclear — check the list.',
|
|
188
|
+
change: 'Removing saved rule {rule} came back without saying what it did',
|
|
189
|
+
},
|
|
190
|
+
unrecognised: {
|
|
191
|
+
notice: '{rule}: the engine answered with a status this build does not know, so whether anything was removed is unclear — check the list.',
|
|
192
|
+
change: 'Removing saved rule {rule} returned a status this build does not know',
|
|
193
|
+
},
|
|
194
|
+
liveness: { yes: ' It also reports the rule is still live.', unknown: ' Whether the rule is still live could not be confirmed either.', no: '' },
|
|
195
|
+
});
|
|
196
|
+
const fillRule = (template, rule) => template.split('{rule}').join(rule);
|
|
197
|
+
export function persistedRuleRevokeOutcome(ruleText, result) {
|
|
198
|
+
const quoted = typeof ruleText === 'string' ? quoteUntrustedForSentence(ruleText, 120) : undefined;
|
|
199
|
+
const rule = quoted ?? 'this rule';
|
|
200
|
+
const status = ownSlot(result, 'status');
|
|
201
|
+
const rawLive = ownSlot(result, 'stillLive');
|
|
202
|
+
const liveness = rawLive === 'yes' || rawLive === 'no' || rawLive === 'unknown' ? rawLive : 'unknown';
|
|
203
|
+
if (status === 'removed' || status === 'no-op') {
|
|
204
|
+
const outcome = status === 'removed' ? 'removed' : 'nothing-written';
|
|
205
|
+
const line = PERSISTED_RULE_REVOKE_LINES[outcome][liveness];
|
|
206
|
+
return Object.freeze({ outcome, liveness, notice: fillRule(line.notice, rule), change: fillRule(line.change, rule) });
|
|
207
|
+
}
|
|
208
|
+
const head = typeof status === 'string' && status !== '' ? REVOKE_UNKNOWN_STATUS.unrecognised : REVOKE_UNKNOWN_STATUS.absent;
|
|
209
|
+
return Object.freeze({
|
|
210
|
+
outcome: 'unknown-status',
|
|
211
|
+
liveness,
|
|
212
|
+
notice: `${fillRule(head.notice, rule)}${REVOKE_UNKNOWN_STATUS.liveness[liveness]}`,
|
|
213
|
+
change: fillRule(head.change, rule),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
const PERSISTED_RULE_MATCH_LABELS = Object.freeze({
|
|
217
|
+
exact: 'exact match',
|
|
218
|
+
prefix: 'prefix match',
|
|
219
|
+
wildcard: 'wildcard match',
|
|
220
|
+
subpath: 'subpath match',
|
|
221
|
+
path: 'path match',
|
|
222
|
+
name: 'skill name match',
|
|
223
|
+
name_prefix: 'skill name prefix match',
|
|
224
|
+
host: 'web domain match (one host)',
|
|
225
|
+
subdomain: 'web domain match (every host under the domain)',
|
|
226
|
+
});
|
|
227
|
+
export function persistedRuleMatchLabel(ruleOrMatch) {
|
|
228
|
+
const word = typeof ruleOrMatch === 'string' ? ruleOrMatch : ownSlot(ruleOrMatch, 'match');
|
|
229
|
+
if (typeof word !== 'string' || word === '')
|
|
230
|
+
return 'an unreported match form';
|
|
231
|
+
return Object.hasOwn(PERSISTED_RULE_MATCH_LABELS, word)
|
|
232
|
+
? PERSISTED_RULE_MATCH_LABELS[word]
|
|
233
|
+
: 'a match form this build does not know';
|
|
234
|
+
}
|
|
115
235
|
export function revokeTargetFromPersistedRule(rule, opts) {
|
|
116
236
|
const behavior = persistedRuleBehaviorOf(rule);
|
|
117
237
|
if (behavior === undefined)
|
|
@@ -434,7 +554,7 @@ export function classifySkippedReason(reason) {
|
|
|
434
554
|
}
|
|
435
555
|
export function readRulePersistOutcome(ack) {
|
|
436
556
|
const parsed = readToolApprovalRespondAck(ack);
|
|
437
|
-
if (parsed === undefined)
|
|
557
|
+
if (parsed === undefined || isToolApprovalRespondReplayed(parsed))
|
|
438
558
|
return { state: 'unknown' };
|
|
439
559
|
if (parsed.rulePersisted === true)
|
|
440
560
|
return { state: 'persisted' };
|
|
@@ -28,6 +28,16 @@ export declare function _resetArmedPlanReviewsForTest(): void;
|
|
|
28
28
|
export type PlanReviewReopenTrigger = 'user' | 'automatic';
|
|
29
29
|
export type PlanReviewGateInstanceReader = (taskId: string) => Promise<ReadonlySet<string> | null>;
|
|
30
30
|
export declare function clearPlanReviewUserDismissals(sessionKey?: string): void;
|
|
31
|
+
export type PlanReviewOfferedMode = 'three_choice' | 'two_choice' | 'unknown';
|
|
32
|
+
export interface PlanReviewCardLike {
|
|
33
|
+
readonly questionId?: string;
|
|
34
|
+
readonly questions?: ReadonlyArray<{
|
|
35
|
+
readonly options?: ReadonlyArray<{
|
|
36
|
+
readonly label?: string;
|
|
37
|
+
}>;
|
|
38
|
+
}>;
|
|
39
|
+
}
|
|
40
|
+
export declare function planReviewOfferedModeOf(card: string | PlanReviewCardLike): PlanReviewOfferedMode;
|
|
31
41
|
export interface ArmPlanReviewOptions {
|
|
32
42
|
submittedInPlanMode?: boolean;
|
|
33
43
|
readGateInstanceKeys?: PlanReviewGateInstanceReader;
|
|
@@ -76,22 +86,25 @@ export declare function notePlanReviewGateLeft(taskId: string): void;
|
|
|
76
86
|
export declare function latestPlanReviewDecisionMark(taskId: string): number | null;
|
|
77
87
|
export declare function __resetPlanReviewDecisionLatchForTests(): void;
|
|
78
88
|
export declare function decidePlanReview(taskId: string, decision: 'approve' | 'reject', permissionModeAfter?: string, opts?: DecidePlanReviewOptions): Promise<void>;
|
|
79
|
-
export interface
|
|
80
|
-
mintFreshQuestionId?: boolean;
|
|
81
|
-
deliverDecision?: (taskId: string, decision: 'approve' | 'reject', reason?: string) => void | Promise<void>;
|
|
89
|
+
export interface ReopenPlanReviewSharedOpts {
|
|
82
90
|
sessionKey?: string;
|
|
83
|
-
|
|
84
|
-
onOutcome?: PlanReviewDeliveryOptions['onOutcome'];
|
|
85
|
-
presentationReceiptMs?: number;
|
|
91
|
+
presentationReceiptMs: number;
|
|
86
92
|
trigger?: PlanReviewReopenTrigger;
|
|
87
93
|
readGateInstanceKeys?: PlanReviewGateInstanceReader;
|
|
88
94
|
pendingReadStartedAt?: number;
|
|
89
95
|
}
|
|
96
|
+
export interface ReopenPlanReviewFreshOpts extends ReopenPlanReviewSharedOpts {
|
|
97
|
+
mintFreshQuestionId?: true;
|
|
98
|
+
deliverDecision?: (taskId: string, decision: 'approve' | 'reject', reason?: string) => void | Promise<void>;
|
|
99
|
+
wire?: PlanReviewWire;
|
|
100
|
+
onOutcome?: PlanReviewDeliveryOptions['onOutcome'];
|
|
101
|
+
}
|
|
102
|
+
export interface ReopenPlanReviewReuseOpts extends ReopenPlanReviewSharedOpts {
|
|
103
|
+
mintFreshQuestionId: false;
|
|
104
|
+
deliverDecision?: never;
|
|
105
|
+
wire?: never;
|
|
106
|
+
onOutcome?: never;
|
|
107
|
+
}
|
|
108
|
+
export type ReopenPlanReviewOpts = ReopenPlanReviewFreshOpts | ReopenPlanReviewReuseOpts;
|
|
90
109
|
export declare function _resetActiveReopenRespondersForTest(): void;
|
|
91
|
-
export declare function reopenPlanReviewCard(taskId: string, opts: ReopenPlanReviewOpts
|
|
92
|
-
presentationReceiptMs: number;
|
|
93
|
-
}): Promise<ReopenCardVerdict>;
|
|
94
|
-
export declare function reopenPlanReviewCard(taskId: string, opts?: ReopenPlanReviewOpts & {
|
|
95
|
-
presentationReceiptMs?: undefined;
|
|
96
|
-
}): ReopenCardVerdict;
|
|
97
|
-
export declare function reopenPlanReviewCard(taskId: string, opts?: ReopenPlanReviewOpts): ReopenCardVerdict | Promise<ReopenCardVerdict>;
|
|
110
|
+
export declare function reopenPlanReviewCard(taskId: string, opts: ReopenPlanReviewOpts): Promise<ReopenCardVerdict>;
|
|
@@ -7,11 +7,13 @@ import { enqueuePlanReviewOutcome } from '../notifications.js';
|
|
|
7
7
|
import { corruptStoredRowContent, corruptStoredRowWhere } from '../wireErrorTriage.js';
|
|
8
8
|
import { decideFailureNote } from '../decideFailureNote.js';
|
|
9
9
|
import { wireFailureTextsOf } from '../wireFailureShape.js';
|
|
10
|
+
import { readOwnDataNonEmptyString, readOwnDataValue } from '../ownKey.js';
|
|
10
11
|
import { checkpointUnsupportedVersionContent, checkpointUnsupportedVersionFromError, resumeContextUnavailableContent, resumeContextUnavailableFromError } from '../resumeRefusalCopy.js';
|
|
11
|
-
import { REQUEST_FIELD_CONFLICT
|
|
12
|
+
import { REQUEST_FIELD_CONFLICT } from '../engineErrorCodes.js';
|
|
13
|
+
import { refusalDeliveryOf } from './decisionRefusal.js';
|
|
12
14
|
import { denyReasonForWire, isPlanReviewModeAfter } from './hitlBridge.js';
|
|
13
15
|
import { planReviewQuestionId, REOPEN_ID_TAIL, taskIdFromPlanReviewQuestionId } from './gateIdentity.js';
|
|
14
|
-
import { notePlanReviewAnswered, notePlanReviewAnsweredFor, planReviewArmedKeyFor,
|
|
16
|
+
import { notePlanReviewAnswered, notePlanReviewAnsweredFor, planReviewArmedKeyFor, waitForGateArmedFor, wasGateArmedFor, } from './armedGateRegistry.js';
|
|
15
17
|
import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
|
|
16
18
|
import { PLAN_REVIEW_GATE_KIND, durableDecideLegOf } from '../adapter/activeRunSelfHeal.js';
|
|
17
19
|
import { readRunTerminal, runTerminalGateKind } from '../runTerminal.js';
|
|
@@ -144,9 +146,12 @@ function pausedGateKindOf(carrier) {
|
|
|
144
146
|
}
|
|
145
147
|
const armedPlanReviewTaskIds = new Set();
|
|
146
148
|
const offerModeAfterByTask = new Map();
|
|
149
|
+
const offeredModeByQuestionId = new Map();
|
|
150
|
+
const OFFERED_MODE_LEDGER_MAX = 64;
|
|
147
151
|
export function _resetArmedPlanReviewsForTest() {
|
|
148
152
|
armedPlanReviewTaskIds.clear();
|
|
149
153
|
offerModeAfterByTask.clear();
|
|
154
|
+
offeredModeByQuestionId.clear();
|
|
150
155
|
planReviewDismissalsByKey.clear();
|
|
151
156
|
}
|
|
152
157
|
const ON_SCREEN = Promise.resolve(true);
|
|
@@ -247,12 +252,77 @@ function planReviewQuestions(question, offerModeAfter = false) {
|
|
|
247
252
|
},
|
|
248
253
|
];
|
|
249
254
|
}
|
|
255
|
+
function planReviewQuestionFrame(questionId, question, offerModeAfter, reopened = false) {
|
|
256
|
+
if (!reopened) {
|
|
257
|
+
offeredModeByQuestionId.delete(questionId);
|
|
258
|
+
offeredModeByQuestionId.set(questionId, offerModeAfter);
|
|
259
|
+
while (offeredModeByQuestionId.size > OFFERED_MODE_LEDGER_MAX) {
|
|
260
|
+
const oldest = offeredModeByQuestionId.keys().next();
|
|
261
|
+
if (oldest.done === true)
|
|
262
|
+
break;
|
|
263
|
+
offeredModeByQuestionId.delete(oldest.value);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return { type: 'question', questionId, questions: planReviewQuestions(question, offerModeAfter) };
|
|
267
|
+
}
|
|
250
268
|
function publishPlanReviewCard(taskId) {
|
|
251
|
-
publishQuestionFrame(
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
269
|
+
publishQuestionFrame(planReviewQuestionFrame(planReviewQuestionId(taskId), ARM_QUESTION, offerModeAfterByTask.get(taskId) === true));
|
|
270
|
+
}
|
|
271
|
+
const OFFERED_MODE_SCAN_MAX = 32;
|
|
272
|
+
function ownElementsOf(v, max) {
|
|
273
|
+
if (!Array.isArray(v))
|
|
274
|
+
return [];
|
|
275
|
+
const n = Math.min(v.length, max);
|
|
276
|
+
const out = [];
|
|
277
|
+
for (let i = 0; i < n; i++)
|
|
278
|
+
out.push(readOwnDataValue(v, String(i)));
|
|
279
|
+
return out;
|
|
280
|
+
}
|
|
281
|
+
function offeredModeFromLabels(card) {
|
|
282
|
+
let modeAfter = false;
|
|
283
|
+
let plain = false;
|
|
284
|
+
for (const q of ownElementsOf(readOwnDataValue(card, 'questions'), OFFERED_MODE_SCAN_MAX)) {
|
|
285
|
+
if (typeof q !== 'object' || q === null)
|
|
286
|
+
continue;
|
|
287
|
+
for (const o of ownElementsOf(readOwnDataValue(q, 'options'), OFFERED_MODE_SCAN_MAX)) {
|
|
288
|
+
if (typeof o !== 'object' || o === null)
|
|
289
|
+
continue;
|
|
290
|
+
const label = readOwnDataNonEmptyString(o, 'label');
|
|
291
|
+
if (label === PLAN_REVIEW_APPROVE_AUTO_LABEL || label === PLAN_REVIEW_APPROVE_MANUAL_LABEL)
|
|
292
|
+
modeAfter = true;
|
|
293
|
+
else if (label === APPROVE_LABEL)
|
|
294
|
+
plain = true;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (modeAfter && !plain)
|
|
298
|
+
return 'three_choice';
|
|
299
|
+
if (plain && !modeAfter)
|
|
300
|
+
return 'two_choice';
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
function offeredModeFromQuestionId(questionId) {
|
|
304
|
+
if (taskIdFromPlanReviewQuestionId(questionId) === undefined)
|
|
305
|
+
return 'unknown';
|
|
306
|
+
const recorded = offeredModeByQuestionId.get(questionId);
|
|
307
|
+
if (recorded !== undefined)
|
|
308
|
+
return recorded ? 'three_choice' : 'two_choice';
|
|
309
|
+
return questionId.includes(REOPEN_ID_TAIL) ? 'two_choice' : 'unknown';
|
|
310
|
+
}
|
|
311
|
+
export function planReviewOfferedModeOf(card) {
|
|
312
|
+
try {
|
|
313
|
+
if (typeof card === 'string')
|
|
314
|
+
return offeredModeFromQuestionId(card);
|
|
315
|
+
if (typeof card !== 'object' || card === null)
|
|
316
|
+
return 'unknown';
|
|
317
|
+
const fromLabels = offeredModeFromLabels(card);
|
|
318
|
+
if (fromLabels !== undefined)
|
|
319
|
+
return fromLabels;
|
|
320
|
+
const questionId = readOwnDataNonEmptyString(card, 'questionId');
|
|
321
|
+
return questionId === undefined ? 'unknown' : offeredModeFromQuestionId(questionId);
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
return 'unknown';
|
|
325
|
+
}
|
|
256
326
|
}
|
|
257
327
|
export function armPlanReviewApproval(result, sessionKey, opts) {
|
|
258
328
|
let armedTaskId;
|
|
@@ -752,13 +822,13 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
|
|
|
752
822
|
else if (typeof status === 'number' && corruptStoredRowWhere(e) !== undefined) {
|
|
753
823
|
const where = corruptStoredRowWhere(e);
|
|
754
824
|
hostLog('debug', `planReviewWire: ${decision} → ${String(status)} corrupt (stored resume context unreadable)`);
|
|
755
|
-
effect = 'not_applied';
|
|
825
|
+
effect = refusalDeliveryOf(e, { route: 'plan_review' }).delivery === 'refused' ? 'not_applied' : 'unconfirmed';
|
|
756
826
|
outcome = `This ${decision} was not applied. ${corruptStoredRowContent(where)}`;
|
|
757
827
|
}
|
|
758
828
|
else if (typeof status === 'number') {
|
|
759
829
|
const failureTexts = wireFailureTextsOf(e);
|
|
760
830
|
hostLog('debug', `planReviewWire: ${decision} → ${status} ${failureTexts.log.slice(0, 200)}`);
|
|
761
|
-
effect = (
|
|
831
|
+
effect = refusalDeliveryOf(e, { route: 'plan_review' }).delivery === 'refused' ? 'not_applied' : 'unconfirmed';
|
|
762
832
|
outcome = `${`The plan_review decision failed: HTTP ${status} ${failureTexts.reason}`.trim()}${decideFailureNote(e)}`;
|
|
763
833
|
}
|
|
764
834
|
else if (noAnswer === 'time-limit' || noAnswer === 'deadline') {
|
|
@@ -828,8 +898,6 @@ export function _resetActiveReopenRespondersForTest() {
|
|
|
828
898
|
const reopenFlights = new Map();
|
|
829
899
|
function joinReopenFlight(flight, taskId, receiptMs) {
|
|
830
900
|
hostLog('debug', `planReviewWire: reopen for task ${taskId} joined the card already on its way (no second card, its answer path kept)`);
|
|
831
|
-
if (receiptMs === undefined)
|
|
832
|
-
return { reopened: true, firstSight: false };
|
|
833
901
|
const ac = new AbortController();
|
|
834
902
|
return Promise.race([
|
|
835
903
|
flight.presented.then((v) => v === true, () => false),
|
|
@@ -867,17 +935,13 @@ function mintPlanReviewReopen(taskId, opts, sessionKey, receiptMs) {
|
|
|
867
935
|
settle(false);
|
|
868
936
|
throw e;
|
|
869
937
|
}
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
});
|
|
878
|
-
}
|
|
879
|
-
settle(verdict.reopened === true);
|
|
880
|
-
return verdict;
|
|
938
|
+
return verdict.then((v) => {
|
|
939
|
+
settle(v.reopened === true);
|
|
940
|
+
return v;
|
|
941
|
+
}, (e) => {
|
|
942
|
+
settle(false);
|
|
943
|
+
throw e;
|
|
944
|
+
});
|
|
881
945
|
}
|
|
882
946
|
function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
|
|
883
947
|
const markBefore = dismissalEntryFor(sessionKey, taskId);
|
|
@@ -893,30 +957,10 @@ function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
|
|
|
893
957
|
const mintFresh = opts?.mintFreshQuestionId !== false;
|
|
894
958
|
if (!mintFresh && hasLocalQuestionResponder(canonicalId)) {
|
|
895
959
|
hostLog('debug', `planReviewWire: reopen for task ${taskId} reusing the canonical responder (path=reopen-canonical)`);
|
|
896
|
-
if (opts?.deliverDecision !== undefined) {
|
|
897
|
-
hostLog('debug', `planReviewWire: reopen canonical-reuse branch for task ${taskId} ignores opts.deliverDecision (answers route through the existing arm responder — documented exception)`);
|
|
898
|
-
}
|
|
899
|
-
if (opts?.wire !== undefined || opts?.onOutcome !== undefined) {
|
|
900
|
-
hostLog('debug', `planReviewWire: reopen canonical-reuse branch for task ${taskId} ignores opts.wire / opts.onOutcome (answers route through the existing arm responder and the wire it was armed with — documented exception)`);
|
|
901
|
-
}
|
|
902
960
|
retireActiveReopen(sessionKey, canonicalId);
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
type: 'question',
|
|
907
|
-
questionId: canonicalId,
|
|
908
|
-
questions: planReviewQuestions(ARM_QUESTION, offerModeAfterByTask.get(taskId) === true),
|
|
909
|
-
});
|
|
910
|
-
return settleOnReceipt(receipt, firstSight);
|
|
911
|
-
}
|
|
912
|
-
publishQuestionFrameFor(sessionKey, {
|
|
913
|
-
type: 'question',
|
|
914
|
-
questionId: canonicalId,
|
|
915
|
-
questions: planReviewQuestions(ARM_QUESTION, offerModeAfterByTask.get(taskId) === true),
|
|
916
|
-
});
|
|
917
|
-
registerArmedGateFor(sessionKey, armedKey);
|
|
918
|
-
revokePlanReviewUserDismissal(sessionKey, taskId, markBefore);
|
|
919
|
-
return { reopened: true, firstSight };
|
|
961
|
+
const receipt = waitForGateArmedFor(sessionKey, [canonicalId], receiptMs);
|
|
962
|
+
publishQuestionFrameFor(sessionKey, planReviewQuestionFrame(canonicalId, ARM_QUESTION, offerModeAfterByTask.get(taskId) === true));
|
|
963
|
+
return settleOnReceipt(receipt, firstSight);
|
|
920
964
|
}
|
|
921
965
|
retireActiveReopen(sessionKey, canonicalId);
|
|
922
966
|
if (unregisterLocalQuestionResponder(canonicalId)) {
|
|
@@ -961,23 +1005,9 @@ function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
|
|
|
961
1005
|
return { ok: true };
|
|
962
1006
|
});
|
|
963
1007
|
activeReopenResponders.set(activeKey, { questionId, unregister });
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
type: 'question',
|
|
968
|
-
questionId,
|
|
969
|
-
questions: planReviewQuestions(REOPEN_QUESTION),
|
|
970
|
-
});
|
|
971
|
-
return settleOnReceipt(receipt, firstSight);
|
|
972
|
-
}
|
|
973
|
-
registerArmedGateFor(sessionKey, armedKey);
|
|
974
|
-
publishQuestionFrameFor(sessionKey, {
|
|
975
|
-
type: 'question',
|
|
976
|
-
questionId,
|
|
977
|
-
questions: planReviewQuestions(REOPEN_QUESTION),
|
|
978
|
-
});
|
|
979
|
-
revokePlanReviewUserDismissal(sessionKey, taskId, markBefore);
|
|
980
|
-
return { reopened: true, firstSight };
|
|
1008
|
+
const receipt = waitForGateArmedFor(sessionKey, [questionId], receiptMs);
|
|
1009
|
+
publishQuestionFrameFor(sessionKey, planReviewQuestionFrame(questionId, REOPEN_QUESTION, false, true));
|
|
1010
|
+
return settleOnReceipt(receipt, firstSight);
|
|
981
1011
|
}
|
|
982
1012
|
function noPresentationSurfaceVerdict(taskId, sessionKey) {
|
|
983
1013
|
const verdict = { reopened: false, _sema_noPresentationSurface: true };
|
|
@@ -1075,44 +1105,48 @@ async function staleDismissalVerdict(current, sessionKey, taskId, receiptMs) {
|
|
|
1075
1105
|
}
|
|
1076
1106
|
export function reopenPlanReviewCard(taskId, opts) {
|
|
1077
1107
|
const receiptMs = opts?.presentationReceiptMs;
|
|
1108
|
+
if (typeof receiptMs !== 'number' || Number.isNaN(receiptMs)) {
|
|
1109
|
+
hostLog('debug', `planReviewWire: reopen for task ${String(taskId)} refused — presentationReceiptMs is required (a number of milliseconds); the synchronous form was retired in 0.98.0`);
|
|
1110
|
+
return Promise.resolve({ reopened: false });
|
|
1111
|
+
}
|
|
1078
1112
|
try {
|
|
1079
1113
|
if (typeof taskId !== 'string' || taskId.length === 0) {
|
|
1080
|
-
return
|
|
1114
|
+
return Promise.resolve({ reopened: false });
|
|
1115
|
+
}
|
|
1116
|
+
const injected = opts;
|
|
1117
|
+
if (opts?.mintFreshQuestionId === false && (injected?.deliverDecision !== undefined || injected?.wire !== undefined || injected?.onOutcome !== undefined)) {
|
|
1118
|
+
hostLog('error', `planReviewWire: plan_review reopen for task ${taskId} refused — mintFreshQuestionId:false reuses the armed card's responder and its delivery, ` +
|
|
1119
|
+
'so deliverDecision / wire / onOutcome cannot be given with it; drop mintFreshQuestionId:false to deliver through the injected path');
|
|
1120
|
+
return Promise.resolve({ reopened: false });
|
|
1081
1121
|
}
|
|
1082
|
-
const readStart = typeof opts
|
|
1122
|
+
const readStart = typeof opts.pendingReadStartedAt === 'number' && Number.isFinite(opts.pendingReadStartedAt) ? opts.pendingReadStartedAt : undefined;
|
|
1083
1123
|
if (planReviewDecisionInFlight(taskId, readStart)) {
|
|
1084
1124
|
hostLog('debug', `planReviewWire: reopen for task ${taskId} refused — a decision for this task is in flight (its answer is still being delivered)`);
|
|
1085
1125
|
const refused = { reopened: false, _sema_decisionInFlight: true };
|
|
1086
|
-
return
|
|
1126
|
+
return Promise.resolve(refused);
|
|
1087
1127
|
}
|
|
1088
1128
|
const guardStartedAt = planReviewPendingReadMark();
|
|
1089
1129
|
const recheckReadStart = readStart === undefined ? guardStartedAt : Math.min(readStart, guardStartedAt);
|
|
1090
|
-
const sessionKey = opts
|
|
1130
|
+
const sessionKey = opts.sessionKey ?? DEFAULT_SESSION_KEY;
|
|
1091
1131
|
if (!hasQuestionOverlayFor(sessionKey)) {
|
|
1092
|
-
|
|
1093
|
-
return receiptMs === undefined ? noSurface : Promise.resolve(noSurface);
|
|
1132
|
+
return Promise.resolve(noPresentationSurfaceVerdict(taskId, sessionKey));
|
|
1094
1133
|
}
|
|
1095
|
-
if (sessionKey !== DEFAULT_SESSION_KEY && opts
|
|
1134
|
+
if (sessionKey !== DEFAULT_SESSION_KEY && opts.deliverDecision === undefined && opts.wire === undefined) {
|
|
1096
1135
|
hostLog('error', `planReviewWire: plan_review 卡未重开 —— sessionKey=${JSON.stringify(sessionKey)} 是非默认槽,` +
|
|
1097
1136
|
'而缺省决断投递口(decidePlanReview)今天固定打默认槽的 baseUrl/token/principal。' +
|
|
1098
1137
|
'整条链转 keyed 之前,非默认槽要重开请自带 deliverDecision(按本槽投递);' +
|
|
1099
1138
|
'此处拒绝而不是照发 —— 照发会把这条会话的决断发到另一个槽上。');
|
|
1100
|
-
return
|
|
1139
|
+
return Promise.resolve({ reopened: false });
|
|
1101
1140
|
}
|
|
1102
|
-
const trigger = opts
|
|
1141
|
+
const trigger = opts.trigger === undefined ? undefined : opts.trigger === 'user' ? 'user' : 'automatic';
|
|
1103
1142
|
if (trigger === 'automatic') {
|
|
1104
1143
|
const mark = planReviewUserDismissalMarkFor(sessionKey, taskId);
|
|
1105
|
-
if (mark !== undefined)
|
|
1106
|
-
if (receiptMs === undefined || opts === undefined) {
|
|
1107
|
-
hostLog('debug', `planReviewWire: automatic reopen for task ${taskId} refused — the user closed this gate's card`);
|
|
1108
|
-
return { reopened: false, dismissedByUser: true };
|
|
1109
|
-
}
|
|
1144
|
+
if (mark !== undefined)
|
|
1110
1145
|
return reopenAfterDismissalCheck(taskId, opts, sessionKey, receiptMs, mark, recheckReadStart);
|
|
1111
|
-
}
|
|
1112
1146
|
}
|
|
1113
1147
|
return mintPlanReviewReopen(taskId, opts, sessionKey, receiptMs);
|
|
1114
1148
|
}
|
|
1115
1149
|
catch {
|
|
1116
|
-
return
|
|
1150
|
+
return Promise.resolve({ reopened: false });
|
|
1117
1151
|
}
|
|
1118
1152
|
}
|
|
@@ -2,6 +2,3 @@ import { CORE_PROTOCOL_PREFIXES } from '../generated/toolNameTables.js';
|
|
|
2
2
|
export const PREFIXES_IN_PROSE = CORE_PROTOCOL_PREFIXES.map((prefix) => `"${prefix}"`).join(' or ');
|
|
3
3
|
export const REFUSED_NAME_CLASSES = `a retired tool name, or a name that contains "__" but does not start with ${PREFIXES_IN_PROSE}`;
|
|
4
4
|
export const REFUSED_NAME_FIX = `If the tool still exists, use its current name; a server or agent-peer tool name starts with ${PREFIXES_IN_PROSE}.`;
|
|
5
|
-
export const RULES_LEGACY_TOOL_NAME_WRITE_NOTE = `The engine refused to write these session rules, and the stored record was not changed at all: they name a tool the engine refuses — ${REFUSED_NAME_CLASSES} (the engine's own error text names the entry). ` +
|
|
6
|
-
`${REFUSED_NAME_FIX} Then write the rules again. ` +
|
|
7
|
-
'If that entry was already in this session’s rule record, it has to be removed from the record before the record can be written again.';
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { type ApprovalSettledHow } from './approvalHolds.js';
|
|
2
|
-
import { type ApprovalsListEnvelope, type
|
|
2
|
+
import { type ApprovalsListEnvelope, type CrashConvergedRowReading } from './crashConverged.js';
|
|
3
3
|
export type ReplayedApprovalDisposition = {
|
|
4
4
|
readonly kind: 'live';
|
|
5
5
|
readonly basis: 'live_leg' | 'preamble' | 'pending_list';
|
|
6
6
|
} | {
|
|
7
7
|
readonly kind: 'decided';
|
|
8
|
-
readonly cause?:
|
|
9
|
-
readonly needsHumanReason?: NonNullable<
|
|
8
|
+
readonly cause?: CrashConvergedRowReading['cause'];
|
|
9
|
+
readonly needsHumanReason?: NonNullable<CrashConvergedRowReading['needsHumanReason']>;
|
|
10
10
|
readonly settled?: ApprovalSettledHow;
|
|
11
|
+
readonly parked?: true;
|
|
11
12
|
} | {
|
|
12
13
|
readonly kind: 'unknown';
|
|
13
14
|
readonly why: 'unreadable_frame' | 'no_approval_id' | 'not_read' | 'list_unreadable' | 'list_not_reported' | 'list_incomplete';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { hasLedgerPositionKey } from './gateLedger.js';
|
|
2
|
-
import { anyApprovalSettled, settledApprovalOf } from './approvalHolds.js';
|
|
2
|
+
import { anyApprovalSettled, APPROVAL_SETTLED_HOWS, settledApprovalOf } from './approvalHolds.js';
|
|
3
3
|
import { readLivePendingRows } from './livePendingAsk.js';
|
|
4
4
|
import { projectCrashConverged } from './crashConverged.js';
|
|
5
5
|
import { quoteUntrustedForSentence } from '../displayUntrusted.js';
|
|
@@ -9,7 +9,7 @@ const unknown = (why) => Object.freeze({ kind: 'unknown', why });
|
|
|
9
9
|
const decided = (row) => Object.freeze(row === undefined
|
|
10
10
|
? { kind: 'decided' }
|
|
11
11
|
: { kind: 'decided', cause: row.cause, ...(row.needsHumanReason !== undefined ? { needsHumanReason: row.needsHumanReason } : {}) });
|
|
12
|
-
const decidedSettled = (how) => Object.freeze({ kind: 'decided', settled: how });
|
|
12
|
+
const decidedSettled = (how, parked) => Object.freeze(parked && how === 'closed_by_engine' ? { kind: 'decided', settled: how, parked: true } : { kind: 'decided', settled: how });
|
|
13
13
|
function approvalIdOf(frame) {
|
|
14
14
|
const v = frame.approvalId;
|
|
15
15
|
return typeof v === 'string' && v !== '' ? v : undefined;
|
|
@@ -29,7 +29,7 @@ export function settledApprovalDisposition(frame) {
|
|
|
29
29
|
if (!anyApprovalSettled())
|
|
30
30
|
return undefined;
|
|
31
31
|
const entry = settledApprovalOf(approvalIdOf(frame));
|
|
32
|
-
return entry === undefined ? undefined : decidedSettled(entry.how);
|
|
32
|
+
return entry === undefined ? undefined : decidedSettled(entry.how, entry.parked);
|
|
33
33
|
}
|
|
34
34
|
catch {
|
|
35
35
|
return undefined;
|
|
@@ -161,7 +161,10 @@ export function replayedApprovalClosesCardFrame(disposition) {
|
|
|
161
161
|
if (readOwnDataValue(disposition, 'kind') !== 'decided')
|
|
162
162
|
return false;
|
|
163
163
|
const cause = readOwnDataValue(disposition, 'cause');
|
|
164
|
-
|
|
164
|
+
if (typeof cause === 'string' && Object.hasOwn(STOPPED_BY_CAUSE, cause))
|
|
165
|
+
return true;
|
|
166
|
+
const settled = readOwnDataValue(disposition, 'settled');
|
|
167
|
+
return typeof settled === 'string' && APPROVAL_SETTLED_HOWS.includes(settled) && !('parked' in disposition);
|
|
165
168
|
}
|
|
166
169
|
catch {
|
|
167
170
|
return false;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { CONFIG_LEGACY_TOOL_NAME
|
|
1
|
+
import { CONFIG_LEGACY_TOOL_NAME } from '../engineErrorCodes.js';
|
|
2
2
|
import { rosterMountedNames } from '../rosterMountedNames.js';
|
|
3
3
|
import { ruleCompileVerdict } from '../ruleCompileVerdict.js';
|
|
4
4
|
import { ruleToolNameVerdictOf } from '../protocolSegment.js';
|
|
5
|
-
import { PREFIXES_IN_PROSE, REFUSED_NAME_CLASSES, REFUSED_NAME_FIX
|
|
5
|
+
import { PREFIXES_IN_PROSE, REFUSED_NAME_CLASSES, REFUSED_NAME_FIX } from './refusedToolNameProse.js';
|
|
6
6
|
import { CORE_PROTOCOL_PREFIXES } from '../generated/toolNameTables.js';
|
|
7
7
|
const COVERING_NAMESPACE_PREFIXES = CORE_PROTOCOL_PREFIXES;
|
|
8
8
|
const WITHHELD_NOTICE = {
|
|
@@ -132,7 +132,5 @@ const LEGACY_TOOL_NAME_FAILURE_NOTE = `This run did not start: a tool rule appli
|
|
|
132
132
|
export function legacyToolNameFailureNoteOf(code) {
|
|
133
133
|
if (code === CONFIG_LEGACY_TOOL_NAME)
|
|
134
134
|
return LEGACY_TOOL_NAME_FAILURE_NOTE;
|
|
135
|
-
if (code === RULES_LEGACY_TOOL_NAME)
|
|
136
|
-
return RULES_LEGACY_TOOL_NAME_WRITE_NOTE;
|
|
137
135
|
return undefined;
|
|
138
136
|
}
|