@sema-agent/client-core 0.77.1 → 0.78.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.
Files changed (382) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/README.md +6 -5
  3. package/dist/abortableSleep.d.ts +0 -28
  4. package/dist/abortableSleep.js +0 -28
  5. package/dist/adapt/arms.d.ts +0 -46
  6. package/dist/adapt/arms.js +9 -544
  7. package/dist/adapt/ids.d.ts +0 -58
  8. package/dist/adapt/ids.js +0 -63
  9. package/dist/adapt/instanceLedger.d.ts +0 -25
  10. package/dist/adapt/instanceLedger.js +0 -20
  11. package/dist/adapt/panelTasks.d.ts +0 -69
  12. package/dist/adapt/panelTasks.js +0 -95
  13. package/dist/adapt/textSegmentAuthority.d.ts +1 -137
  14. package/dist/adapt/textSegmentAuthority.js +0 -54
  15. package/dist/adapt/textStream.d.ts +0 -252
  16. package/dist/adapt/textStream.js +2 -281
  17. package/dist/adapt/toolCards.d.ts +0 -46
  18. package/dist/adapt/toolCards.js +0 -23
  19. package/dist/adapt/turnFlags.d.ts +0 -54
  20. package/dist/adapt/turnFlags.js +1 -17
  21. package/dist/adapt/wireShapes.d.ts +0 -92
  22. package/dist/adapt/wireShapes.js +0 -83
  23. package/dist/adapt.d.ts +0 -55
  24. package/dist/adapt.js +1 -120
  25. package/dist/adapter/activeRunSelfHeal.d.ts +22 -515
  26. package/dist/adapter/activeRunSelfHeal.js +10 -625
  27. package/dist/adapter/downstream/eventToSdkMessage.d.ts +2 -305
  28. package/dist/adapter/downstream/eventToSdkMessage.js +2 -867
  29. package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -314
  30. package/dist/adapter/downstream/terminalToSdkResult.js +13 -560
  31. package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +0 -95
  32. package/dist/adapter/downstream/turnUsageToModelUsage.js +2 -31
  33. package/dist/adapter/runStream.d.ts +0 -206
  34. package/dist/adapter/runStream.js +6 -596
  35. package/dist/adapter/types.d.ts +0 -111
  36. package/dist/adapter/types.js +0 -29
  37. package/dist/agentSession/backgroundView.d.ts +0 -106
  38. package/dist/agentSession/backgroundView.js +3 -49
  39. package/dist/agentSession/contract.d.ts +0 -98
  40. package/dist/agentSession/contract.js +0 -12
  41. package/dist/agentsWireCaps.d.ts +0 -72
  42. package/dist/agentsWireCaps.js +4 -72
  43. package/dist/approvalsStreamLiveCapability.d.ts +0 -25
  44. package/dist/approvalsStreamLiveCapability.js +0 -31
  45. package/dist/argvFlagValue.d.ts +0 -33
  46. package/dist/argvFlagValue.js +3 -35
  47. package/dist/attachmentsWireCaps.d.ts +0 -127
  48. package/dist/attachmentsWireCaps.js +0 -144
  49. package/dist/autoModeUnavailable.d.ts +0 -120
  50. package/dist/autoModeUnavailable.js +0 -144
  51. package/dist/classifierStatus.d.ts +0 -72
  52. package/dist/classifierStatus.js +0 -167
  53. package/dist/classifierVerdictWire.d.ts +0 -54
  54. package/dist/classifierVerdictWire.js +0 -133
  55. package/dist/clientContextWireCaps.d.ts +0 -37
  56. package/dist/clientContextWireCaps.js +0 -36
  57. package/dist/clientSlice.d.ts +0 -63
  58. package/dist/clientSlice.js +0 -45
  59. package/dist/cloudConfigWireCaps.d.ts +0 -86
  60. package/dist/cloudConfigWireCaps.js +2 -65
  61. package/dist/compensations.d.ts +0 -52
  62. package/dist/compensations.js +2 -63
  63. package/dist/controlRouter.d.ts +2 -208
  64. package/dist/controlRouter.js +1 -129
  65. package/dist/coreValuePorts.d.ts +0 -84
  66. package/dist/coreValuePorts.js +0 -29
  67. package/dist/decideReceipt.d.ts +0 -110
  68. package/dist/decideReceipt.js +0 -84
  69. package/dist/detachWire.d.ts +0 -130
  70. package/dist/detachWire.js +1 -130
  71. package/dist/deviceExecutorManagementCapability.d.ts +2 -35
  72. package/dist/deviceExecutorManagementCapability.js +1 -37
  73. package/dist/diagnostics.d.ts +0 -8
  74. package/dist/diagnostics.js +0 -8
  75. package/dist/diff/patch.d.ts +0 -17
  76. package/dist/diff/patch.js +0 -19
  77. package/dist/effectiveFacts.d.ts +0 -40
  78. package/dist/effectiveFacts.js +0 -22
  79. package/dist/effortWire.d.ts +0 -11
  80. package/dist/effortWire.js +0 -12
  81. package/dist/engineAgentPanelStore.d.ts +0 -169
  82. package/dist/engineAgentPanelStore.js +13 -293
  83. package/dist/engineCapReader.d.ts +0 -62
  84. package/dist/engineCapReader.js +1 -43
  85. package/dist/engineCapsCache.d.ts +0 -177
  86. package/dist/engineCapsCache.js +0 -199
  87. package/dist/engineCapsGenerationGuard.d.ts +0 -2
  88. package/dist/engineCapsGenerationGuard.js +0 -11
  89. package/dist/engineErrorCodes.d.ts +1 -316
  90. package/dist/engineErrorCodes.js +0 -427
  91. package/dist/engineHttpTools.d.ts +0 -29
  92. package/dist/engineHttpTools.js +0 -29
  93. package/dist/engineIdentity.d.ts +0 -83
  94. package/dist/engineIdentity.js +0 -88
  95. package/dist/engineInlineTaskStats.d.ts +0 -57
  96. package/dist/engineInlineTaskStats.js +1 -42
  97. package/dist/engineNoticeCodes.d.ts +0 -190
  98. package/dist/engineNoticeCodes.js +0 -182
  99. package/dist/engineSessionParam.d.ts +0 -30
  100. package/dist/engineSessionParam.js +0 -52
  101. package/dist/engineToolLabelStore.d.ts +0 -29
  102. package/dist/engineToolLabelStore.js +0 -31
  103. package/dist/engineWireSdk.d.ts +0 -90
  104. package/dist/engineWireSdk.js +0 -74
  105. package/dist/engineWireTarget.d.ts +0 -14
  106. package/dist/engineWireTarget.js +0 -39
  107. package/dist/env/localeGeo.d.ts +0 -12
  108. package/dist/env/localeGeo.js +2 -77
  109. package/dist/env/localeTag.d.ts +0 -34
  110. package/dist/env/localeTag.js +0 -32
  111. package/dist/env/uiLanguage.d.ts +0 -13
  112. package/dist/env/uiLanguage.js +0 -25
  113. package/dist/envFlag.d.ts +0 -37
  114. package/dist/envFlag.js +0 -40
  115. package/dist/executionLaneCapability.d.ts +0 -48
  116. package/dist/executionLaneCapability.js +0 -54
  117. package/dist/finalVerifyWire.d.ts +0 -67
  118. package/dist/finalVerifyWire.js +3 -43
  119. package/dist/fleet/fleetLedger.d.ts +0 -308
  120. package/dist/fleet/fleetLedger.js +10 -429
  121. package/dist/fleet/fleetProjection.d.ts +0 -240
  122. package/dist/fleet/fleetProjection.js +0 -189
  123. package/dist/fleet/fleetRowAgentType.d.ts +0 -6
  124. package/dist/fleet/fleetRowAgentType.js +1 -32
  125. package/dist/fleet/workflowSizeWarning.d.ts +0 -47
  126. package/dist/fleet/workflowSizeWarning.js +1 -46
  127. package/dist/fleetAgentPanelProjection.d.ts +0 -48
  128. package/dist/fleetAgentPanelProjection.js +8 -173
  129. package/dist/fleetTaskDesc.d.ts +0 -39
  130. package/dist/fleetTaskDesc.js +0 -69
  131. package/dist/forkWireCaps.d.ts +0 -23
  132. package/dist/forkWireCaps.js +1 -24
  133. package/dist/gateOutcome.d.ts +0 -140
  134. package/dist/gateOutcome.js +0 -85
  135. package/dist/gateVocabulary.d.ts +0 -114
  136. package/dist/gateVocabulary.js +3 -161
  137. package/dist/goalStopHook.d.ts +0 -127
  138. package/dist/goalStopHook.js +0 -178
  139. package/dist/headlessPermissionModeWire.d.ts +0 -76
  140. package/dist/headlessPermissionModeWire.js +1 -155
  141. package/dist/headlessReconnectWire.d.ts +0 -84
  142. package/dist/headlessReconnectWire.js +13 -67
  143. package/dist/hitl/approvalDecisionNoteAudit.d.ts +0 -49
  144. package/dist/hitl/approvalDecisionNoteAudit.js +0 -56
  145. package/dist/hitl/approvalOutcomeNote.d.ts +0 -2
  146. package/dist/hitl/approvalOutcomeNote.js +0 -20
  147. package/dist/hitl/approvalResolution.d.ts +0 -113
  148. package/dist/hitl/approvalResolution.js +0 -66
  149. package/dist/hitl/approvalsFeed.d.ts +0 -183
  150. package/dist/hitl/approvalsFeed.js +12 -243
  151. package/dist/hitl/armedGateRegistry.d.ts +0 -55
  152. package/dist/hitl/armedGateRegistry.js +0 -146
  153. package/dist/hitl/askGateWire.d.ts +0 -86
  154. package/dist/hitl/askGateWire.js +1 -95
  155. package/dist/hitl/askParkRowRouting.d.ts +0 -123
  156. package/dist/hitl/askParkRowRouting.js +1 -89
  157. package/dist/hitl/crashConverged.d.ts +0 -148
  158. package/dist/hitl/crashConverged.js +0 -214
  159. package/dist/hitl/editedRuleTextPrecheck.d.ts +0 -109
  160. package/dist/hitl/editedRuleTextPrecheck.js +0 -71
  161. package/dist/hitl/frameRouter.d.ts +0 -134
  162. package/dist/hitl/frameRouter.js +6 -378
  163. package/dist/hitl/gateIdentity.d.ts +0 -39
  164. package/dist/hitl/gateIdentity.js +0 -41
  165. package/dist/hitl/gateLedger.d.ts +0 -267
  166. package/dist/hitl/gateLedger.js +0 -121
  167. package/dist/hitl/hitlBridge.d.ts +7 -431
  168. package/dist/hitl/hitlBridge.js +7 -476
  169. package/dist/hitl/hitlHostSurface.d.ts +0 -150
  170. package/dist/hitl/hitlHostSurface.js +0 -169
  171. package/dist/hitl/livePendingAsk.d.ts +0 -91
  172. package/dist/hitl/livePendingAsk.js +0 -74
  173. package/dist/hitl/localAllowRule.d.ts +0 -62
  174. package/dist/hitl/localAllowRule.js +1 -33
  175. package/dist/hitl/parkOwnership.d.ts +0 -56
  176. package/dist/hitl/parkOwnership.js +0 -22
  177. package/dist/hitl/parkResolver.d.ts +3 -88
  178. package/dist/hitl/parkResolver.js +8 -349
  179. package/dist/hitl/parkRowBirthWait.d.ts +2 -26
  180. package/dist/hitl/parkRowBirthWait.js +3 -93
  181. package/dist/hitl/persistedRulesWire.d.ts +23 -371
  182. package/dist/hitl/persistedRulesWire.js +62 -329
  183. package/dist/hitl/planReviewWire.d.ts +4 -176
  184. package/dist/hitl/planReviewWire.js +9 -312
  185. package/dist/hitl/resumeRunningCard.d.ts +0 -105
  186. package/dist/hitl/resumeRunningCard.js +0 -105
  187. package/dist/hitl/sessionPolicyWire.d.ts +11 -191
  188. package/dist/hitl/sessionPolicyWire.js +0 -149
  189. package/dist/hitl/suspendedReopen.d.ts +3 -24
  190. package/dist/hitl/suspendedReopen.js +0 -14
  191. package/dist/hitl/toolApprovalWire.d.ts +5 -1308
  192. package/dist/hitl/toolApprovalWire.js +5 -945
  193. package/dist/hooksWireCaps.d.ts +0 -38
  194. package/dist/hooksWireCaps.js +0 -190
  195. package/dist/host.d.ts +0 -105
  196. package/dist/host.js +0 -33
  197. package/dist/hostEnv.d.ts +0 -14
  198. package/dist/hostEnv.js +0 -13
  199. package/dist/imagesWireCaps.d.ts +0 -21
  200. package/dist/imagesWireCaps.js +0 -22
  201. package/dist/index.d.ts +0 -134
  202. package/dist/index.js +0 -476
  203. package/dist/interactiveHalt.d.ts +5 -153
  204. package/dist/interactiveHalt.js +0 -111
  205. package/dist/interactiveToolsWire.d.ts +0 -62
  206. package/dist/interactiveToolsWire.js +1 -67
  207. package/dist/leaderConflict.d.ts +0 -59
  208. package/dist/leaderConflict.js +0 -48
  209. package/dist/limitsWire.d.ts +0 -125
  210. package/dist/limitsWire.js +2 -120
  211. package/dist/liveInitToolFace.d.ts +0 -77
  212. package/dist/liveInitToolFace.js +1 -109
  213. package/dist/liveModelCatalog.d.ts +0 -52
  214. package/dist/liveModelCatalog.js +0 -48
  215. package/dist/liveQuestionStore.d.ts +0 -87
  216. package/dist/liveQuestionStore.js +1 -56
  217. package/dist/mcpLiveness.d.ts +0 -151
  218. package/dist/mcpLiveness.js +0 -122
  219. package/dist/mcpPanel.d.ts +0 -104
  220. package/dist/mcpPanel.js +0 -49
  221. package/dist/mcpReconnect.d.ts +0 -58
  222. package/dist/mcpReconnect.js +0 -69
  223. package/dist/mcpWireCaps.d.ts +0 -55
  224. package/dist/mcpWireCaps.js +1 -13
  225. package/dist/memoryComplianceCapability.d.ts +3 -57
  226. package/dist/memoryComplianceCapability.js +0 -57
  227. package/dist/memoryEntriesWire.d.ts +6 -198
  228. package/dist/memoryEntriesWire.js +0 -144
  229. package/dist/memoryOriginCapability.d.ts +3 -53
  230. package/dist/memoryOriginCapability.js +0 -50
  231. package/dist/memorySpecWire.d.ts +0 -116
  232. package/dist/memorySpecWire.js +0 -150
  233. package/dist/model/catalog.d.ts +0 -111
  234. package/dist/model/catalog.js +0 -87
  235. package/dist/model/catalogLoader.d.ts +0 -114
  236. package/dist/model/catalogLoader.js +2 -139
  237. package/dist/model/modelSupplyRules.d.ts +1 -55
  238. package/dist/model/modelSupplyRules.js +0 -62
  239. package/dist/model/providerAuth.d.ts +0 -103
  240. package/dist/model/providerAuth.js +2 -38
  241. package/dist/model/providerCatalog.d.ts +0 -45
  242. package/dist/model/providerCatalog.js +0 -37
  243. package/dist/model/providerPresets.d.ts +0 -33
  244. package/dist/model/providerPresets.js +2 -91
  245. package/dist/model/tierVocabulary.d.ts +0 -31
  246. package/dist/model/tierVocabulary.js +0 -27
  247. package/dist/modelBudgetRule.d.ts +0 -39
  248. package/dist/modelBudgetRule.js +0 -39
  249. package/dist/modelCapabilityProbe.d.ts +0 -175
  250. package/dist/modelCapabilityProbe.js +0 -147
  251. package/dist/modelWireCaps.d.ts +0 -13
  252. package/dist/modelWireCaps.js +0 -13
  253. package/dist/notifications.d.ts +0 -233
  254. package/dist/notifications.js +14 -492
  255. package/dist/oneShotWireCaps.d.ts +0 -34
  256. package/dist/oneShotWireCaps.js +0 -35
  257. package/dist/ownKey.d.ts +0 -33
  258. package/dist/ownKey.js +0 -33
  259. package/dist/panelRunningHistory.d.ts +0 -28
  260. package/dist/panelRunningHistory.js +0 -43
  261. package/dist/peerFrames.d.ts +0 -71
  262. package/dist/peerFrames.js +0 -168
  263. package/dist/peerLaneCapability.d.ts +0 -44
  264. package/dist/peerLaneCapability.js +0 -52
  265. package/dist/permissionRuleIssue.d.ts +0 -30
  266. package/dist/permissionRuleIssue.js +0 -78
  267. package/dist/permissionRulesWriteCapability.d.ts +0 -46
  268. package/dist/permissionRulesWriteCapability.js +0 -54
  269. package/dist/permissionWireCaps.d.ts +0 -37
  270. package/dist/permissionWireCaps.js +0 -37
  271. package/dist/postureKnob.d.ts +0 -71
  272. package/dist/postureKnob.js +0 -86
  273. package/dist/principalWire.d.ts +0 -17
  274. package/dist/principalWire.js +0 -17
  275. package/dist/printToolResultFrame.d.ts +0 -100
  276. package/dist/printToolResultFrame.js +0 -33
  277. package/dist/promptProfileWireCaps.d.ts +0 -13
  278. package/dist/promptProfileWireCaps.js +0 -13
  279. package/dist/readFacePosture.d.ts +0 -43
  280. package/dist/readFacePosture.js +0 -46
  281. package/dist/request/printNotification.d.ts +0 -20
  282. package/dist/request/printNotification.js +0 -55
  283. package/dist/request/taskRequest.d.ts +1 -249
  284. package/dist/request/taskRequest.js +20 -498
  285. package/dist/resumeRefusalCopy.d.ts +0 -136
  286. package/dist/resumeRefusalCopy.js +1 -117
  287. package/dist/retainBackgroundWireCaps.d.ts +0 -48
  288. package/dist/retainBackgroundWireCaps.js +0 -48
  289. package/dist/retryStatus.d.ts +2 -221
  290. package/dist/retryStatus.js +0 -107
  291. package/dist/rewindWireCaps.d.ts +0 -27
  292. package/dist/rewindWireCaps.js +0 -24
  293. package/dist/runCancelContext.d.ts +1 -20
  294. package/dist/runCancelContext.js +0 -34
  295. package/dist/runTerminal.d.ts +0 -273
  296. package/dist/runTerminal.js +0 -177
  297. package/dist/sandboxWire.d.ts +0 -38
  298. package/dist/sandboxWire.js +0 -82
  299. package/dist/scenarioWire.d.ts +0 -60
  300. package/dist/scenarioWire.js +0 -68
  301. package/dist/scratchpadWireCaps.d.ts +0 -11
  302. package/dist/scratchpadWireCaps.js +0 -32
  303. package/dist/sdkWireTransit.d.ts +0 -38
  304. package/dist/sdkWireTransit.js +0 -30
  305. package/dist/seam.d.ts +18 -853
  306. package/dist/seam.js +0 -52
  307. package/dist/seatContract.d.ts +0 -555
  308. package/dist/seatContract.js +5 -304
  309. package/dist/selfOrchestrationDenial.d.ts +0 -189
  310. package/dist/selfOrchestrationDenial.js +0 -162
  311. package/dist/selfOrchestrationWireCaps.d.ts +0 -38
  312. package/dist/selfOrchestrationWireCaps.js +0 -38
  313. package/dist/sessionMap.d.ts +0 -60
  314. package/dist/sessionMap.js +0 -37
  315. package/dist/sessionMemoryStatus.d.ts +11 -114
  316. package/dist/sessionMemoryStatus.js +0 -112
  317. package/dist/sessionModelLatch.d.ts +0 -29
  318. package/dist/sessionModelLatch.js +0 -40
  319. package/dist/sessionPolicyCapability.d.ts +3 -53
  320. package/dist/sessionPolicyCapability.js +0 -52
  321. package/dist/sessionSlot.d.ts +0 -26
  322. package/dist/sessionSlot.js +0 -17
  323. package/dist/skillsWireCaps.d.ts +0 -87
  324. package/dist/skillsWireCaps.js +0 -38
  325. package/dist/sqlEngineCapability.d.ts +0 -118
  326. package/dist/sqlEngineCapability.js +0 -134
  327. package/dist/sseIdleTriage.d.ts +0 -79
  328. package/dist/sseIdleTriage.js +1 -80
  329. package/dist/steering.d.ts +0 -54
  330. package/dist/steering.js +0 -63
  331. package/dist/subagent/engineCompactWire.d.ts +0 -34
  332. package/dist/subagent/engineCompactWire.js +4 -134
  333. package/dist/subagent/engineDelegatedPrompt.d.ts +0 -31
  334. package/dist/subagent/engineDelegatedPrompt.js +1 -103
  335. package/dist/subagent/engineRowStopGate.d.ts +0 -20
  336. package/dist/subagent/engineRowStopGate.js +0 -49
  337. package/dist/subagent/engineSubagentOutput.d.ts +0 -7
  338. package/dist/subagent/engineSubagentOutput.js +1 -51
  339. package/dist/subagent/engineSubagentResume.d.ts +2 -279
  340. package/dist/subagent/engineSubagentResume.js +2 -129
  341. package/dist/subagent/engineSubagentSteer.d.ts +0 -26
  342. package/dist/subagent/engineSubagentSteer.js +0 -63
  343. package/dist/subagent/engineSubagentTail.d.ts +0 -38
  344. package/dist/subagent/engineSubagentTail.js +2 -110
  345. package/dist/subagent/engineTaskHandleWire.d.ts +6 -67
  346. package/dist/subagent/engineTaskHandleWire.js +0 -126
  347. package/dist/subagent/subagentOwnerAbsence.d.ts +0 -2
  348. package/dist/subagent/subagentOwnerAbsence.js +0 -25
  349. package/dist/subagentContentStore.d.ts +3 -260
  350. package/dist/subagentContentStore.js +7 -540
  351. package/dist/systemReminderTag.d.ts +0 -49
  352. package/dist/systemReminderTag.js +0 -61
  353. package/dist/toolResult.d.ts +1 -211
  354. package/dist/toolResult.js +1 -358
  355. package/dist/toolRoster.d.ts +0 -140
  356. package/dist/toolRoster.js +0 -66
  357. package/dist/typePins.d.ts +0 -46
  358. package/dist/types/engineState.d.ts +0 -71
  359. package/dist/types/engineState.js +0 -16
  360. package/dist/ultracodeWireCaps.d.ts +0 -75
  361. package/dist/ultracodeWireCaps.js +0 -92
  362. package/dist/unrefTimer.d.ts +0 -27
  363. package/dist/webSearchBackendCapability.d.ts +0 -72
  364. package/dist/webSearchBackendCapability.js +0 -79
  365. package/dist/webSearchWireCaps.d.ts +0 -37
  366. package/dist/webSearchWireCaps.js +0 -34
  367. package/dist/websearch/searchProviderPresets.d.ts +0 -81
  368. package/dist/websearch/searchProviderPresets.js +0 -27
  369. package/dist/wireErrorTriage.d.ts +4 -160
  370. package/dist/wireErrorTriage.js +0 -171
  371. package/dist/wireRefusalCopy.d.ts +0 -28
  372. package/dist/wireRefusalCopy.js +0 -28
  373. package/dist/workflow.d.ts +0 -40
  374. package/dist/workflow.js +0 -52
  375. package/dist/workflowClient.d.ts +0 -122
  376. package/dist/workflowClient.js +8 -360
  377. package/dist/workflowMonitor.d.ts +2 -72
  378. package/dist/workflowMonitor.js +0 -26
  379. package/dist/writeProtectionCapability.d.ts +0 -112
  380. package/dist/writeProtectionCapability.js +0 -109
  381. package/docs/INTEGRATION-CLIENTS.md +78 -5
  382. package/package.json +3 -3
@@ -1,11 +1,4 @@
1
- /**
2
- * 逐字段对照表(B4 从三个构造器**逐行**读出来的,不是设计出来的)。
3
- *
4
- * 读法:`lanes` 只有一条 = 今天的漂移面;`gap:true` = 我判它是**漏**而不是**设计**。
5
- * 🔴 `gap` 是【判断】不是【事实】——补齐任何一条都要按宪法三问单独立项,别当 B4 的收尾顺手做。
6
- */
7
1
  export const REQUEST_FIELD_MATRIX = [
8
- // ── 两条车道都有 ────────────────────────────────────────────────────────────────────────────
9
2
  { field: 'objective', lanes: ['interactive', 'print'], live: false, why: '本 turn 的真实输入,两条车道都必需' },
10
3
  { field: 'sessionId', lanes: ['interactive', 'print'], live: false, why: '单命名空间(TP-A Step 2):壳 id 即引擎 session id;print 在非 live 下保留 mock 常量' },
11
4
  { field: 'scenario', lanes: ['interactive', 'print'], live: false, why: 'TUI 走 selectScenario(objective) 嗅探,print 走 --scenario/SEMA_HEADLESS_SCENARIO 显式值' },
@@ -13,87 +6,40 @@ export const REQUEST_FIELD_MATRIX = [
13
6
  { field: 'permissionMode', lanes: ['interactive', 'print'], live: true, why: 'TUI 读 AppState.toolPermissionContext(带 stampDefault 门),print 读 flag>env(headlessPermissionModeWire)' },
14
7
  { field: 'selfOrchestration', lanes: ['interactive', 'print'], live: true, why: 'SEMA_SELF_ORCHESTRATION opt-in → core 挂 run_workflow' },
15
8
  { field: 'deferTools', lanes: ['interactive', 'print'], live: true, why: '[1052]① Workflow 延迟披露;selfOrchestration 前置门' },
16
- { field: 'retainBackgroundProcesses', lanes: ['interactive', 'print'], live: true, why: '缺省 ON(clay 2026-07-26 翻转);SEMA_RETAIN_BACKGROUND=0 逃生' },
9
+ { field: 'retainBackgroundProcesses', lanes: ['interactive', 'print'], live: true, why: '缺省 ON(2026-07-26 起翻转);SEMA_RETAIN_BACKGROUND=0 逃生' },
17
10
  { field: 'promptProfile', lanes: ['interactive', 'print'], live: true, why: 'core 1.328 呈现轴 A/B 口,缺省不 stamp = 引擎缺省 simple' },
18
11
  { field: 'enableFork', lanes: ['interactive', 'print'], live: true, why: '显式布尔才 stamp([503]② fail-OPEN 教训:off 必须显式)' },
19
12
  { field: 'attachments', lanes: ['interactive', 'print'], live: true, why: 'design/133 + G1 缺省开的 turn 边界 attachment' },
20
- // ⚠️ 这条 why 原文写的是本地技能目录的**字面路径**,B8 把本模块拉进壳的生产闭包之后,那串
21
- // 字面量随 bundle 进了 `dist/sema.js` 并被壳的品牌门当场逮住(壳的 R11 codemod 只走自己
22
- // 的 src,走不到 node_modules ⇒ 包里的 CC 路径字面 = 品牌面泄漏)。见本文件末的包内纪律。
23
13
  { field: 'skills', lanes: ['interactive', 'print'], live: true, why: '本地技能目录投影(布局取 CC 同款);两条车道都由 launchRepl 载入面注入' },
24
14
  { field: 'mcpServers', lanes: ['interactive', 'print'], live: true, why: '本地 .mcp.json 投影;service 单用户门决定是否兑现' },
25
15
  { field: 'settings.webSearch', lanes: ['interactive', 'print'], live: true, why: 'SEMA_WEBSEARCH_* / settings.json;per-request 配置赢过部署 env' },
26
16
  { field: 'settings.hooks', lanes: ['interactive', 'print'], live: true, why: '[495]① 用户 settings 文件 hooks 逐字上 wire' },
27
- // ⚠️ 这一行 2026-08-17 之前是 `lanes:['interactive'] gap:true`(表内自标「这条差异没有正当理由,
28
- // 是漏的」),#292 P1 把它补齐并搬进本节。补齐的理由不是对称美观,是 [4208] 实测的**权限方向**
29
- // 后果:`-p` 车道上用户 settings 的 `permissions.deny/ask` 整体不被引擎求值(deny 拦不住),
30
- // 而交互 REPL 同一份文件照拦 —— 两条车道对同一份配置给出相反的安全结论。
31
- // 🔴 配对纪律:这一行只管**包内 stamp 门**;端还得把值放进 `input.settings.resolved`
32
- // (壳 print 车道 = `-p` 前置步装一个晚绑定供给器,`seamQueryEngine` 在拼装请求那一刻求值)。
33
- // 任一半单独改都无效 —— 这正是本条修前长期停在 gap 的原因([4285]/[4309] 定谳)。
34
17
  { field: 'settings.<resolved>', lanes: ['interactive', 'print'], live: true, why: 'settings resolver 的 effective 快照(hooks/env/model + 已解析权限投影)。两条车道同源:交互面 replEntry / print 面 printModeEngine 各跑一遍同一个 resolver,产物经同一个 buildWireSettingsStamp 投影。开放集(子键不可枚举)⇒ unregisteredRequestKeys 放行本车道 settings 的**表外**子键,但表内异车道子键仍点名' },
35
- // ── repo 场景五键([C135] 请托,2026-08-08):SDK TaskRequest 成文 passthrough 键(types doc
36
- // 「scenario-specific fields like code-review's repo/council/debate/rounds ride here」),server
37
- // resolve-spec 顶层直读(council/debate 按 `=== true`,rounds 进 clamp [1,3])。lanes 与
38
- // scenario 同款(print 有 --scenario/SEMA_HEADLESS_SCENARIO,scan 场景无 repo 即 501/无意义,
39
- // 值缺席不 stamp,登位为 -p 侧未来入口留座)。今天唯一供给方=web BFF lane 的 repo 字段入口。──
40
18
  { field: 'repo', lanes: ['interactive', 'print'], live: true, why: 'scan/code-review 场景的仓库坐标(passthrough;server 是权威校验方,本层不铸第二判官)' },
41
19
  { field: 'council', lanes: ['interactive', 'print'], live: true, why: 'code-review council 形开关(server 读 `=== true`;非 true 不 stamp=与缺席同义,发小的那个)' },
42
20
  { field: 'debate', lanes: ['interactive', 'print'], live: true, why: 'council 的 debate 变体开关(server 读 `=== true`)' },
43
21
  { field: 'rounds', lanes: ['interactive', 'print'], live: true, why: 'debate 轮数(server clamp [1,3],非有限数被 server 归 undefined——本层原样透传不预 clamp)' },
44
22
  { field: 'lenses', lanes: ['interactive', 'print'], live: true, why: 'code-review 镜头集(passthrough 同 repo;形状由 server 场景定义,本层不闭集)' },
45
- // ── memoryCapture([7226] 包侧缺口 ⑤,0.68.1)──────────────────────────────────────────────
46
- // 🔴 **单成员闭集**:server 契约 §12.4 逐字「`memoryCapture?: "off"`。单成员闭集(**没有**
47
- // `"on"`)」—— 所以本层只在值**恰是** `'off'` 时 stamp;`'on'` / 坏拼写一律不上 wire
48
- // (坏拼写 server 判 400 `request.field_invalid`,本层不预铸第二判官,但也不替它买路)。
49
- // 🔴 与**中途翻转 verb** `POST /v1/runs/:id/memory/capture-optout`(§12.5,能力位
50
- // `runMemoryCaptureOptOut`)是**同一条一次性单向记录的两个口**,不是两个轴:verb 管这一条
51
- // 在飞的 run,本键管「本会话的下一次新提交」。非 live 的 verb(parked / 终态 / 他副本)回
52
- // 409 `steering.not_running` 并**指路本键** —— 端没有本键就接不住那条指路。
53
23
  { field: 'memoryCapture', lanes: ['interactive', 'print'], live: true, why: '本会话永远不进长期记忆的**声明形**(server §12.4 body 键,单成员闭集 "off");两条车道都是提交面 ⇒ 都能声明。与 memoryWrite:false 不是一个轴(那是「本 run 只读平面」)。⚠️ parked 续跑腿结构性拿不到声明(决策/续跑端点从持久 body 重建 spec),那是引擎侧事实,不是本层的漏' },
54
- // ── memory:"off"(CC-39③,0.72.8;server 7.84.0 S-405 / core #863 W3)────────────────────────
55
- // 🔴 契约 §12.7 姊妹键:`memoryCapture` = 「记忆照常用,但别记住我」(会话级采集面关,一次性);`memory` =
56
- // 「这一次别给我记忆」(请求级整面关:不挂 # Memory 段 / 索引 / 三只记忆工具 / 写准入;零记录,可逐请求开关)。
57
- // 同形、不同轴、可并存;两键共用同一只拼写判据(400 `request.field_invalid` 两腿同句)。缺席 = 记忆照常挂。
58
- // 无能力位(7.78.1–7.83.x 只能 trial-by-400)⇒ 本层不预判 server 版本,照发。子代地板(ParentSpecSeat.memoryOff)归 core。
59
24
  { field: 'memory', lanes: ['interactive', 'print'], live: true, why: '这一次运行不挂记忆面的**请求级**开关(server §12.7 body 键,单成员闭集 "off");两条车道都是提交面 ⇒ 都能声明。与 memoryCapture(采集面)不是一个轴、可并存;与 memoryWrite:false(只读平面)也不是一个轴' },
60
- // ── print 独有(§8-5 认定的**有理由**的差异)──────────────────────────────────────────────
61
25
  { field: 'finalVerification', lanes: ['print'], live: true, why: 'P1-1 终验:无人值守车道才需要引擎自证;交互 REPL 由人当场看结果。#106 裁 B(让位+告知)后交互面默认关' },
62
26
  { field: 'limits', lanes: ['print'], live: true, why: 'P2-3-b:`-p` 的预算护栏(--max-* flag 族),交互 REPL 由人随时 Esc' },
63
27
  { field: 'interactiveTools', lanes: ['print'], live: true, why: '[909]B 件3:无人值守 stamp false,从 roster 源头灭掉 AskUserQuestion/plan 门。交互车道 stamp false 等于自废武功' },
64
28
  { field: 'oneShot', lanes: ['print'], live: true, why: 'SDK TaskRequest.oneShot(server ≥7.12.0 消费):`-p` 提交是一次性的——没有后续回合接住异步后台通知,core 据此把「结束回合等通知」指引换成 block-wait;交互车道有后续回合,stamp true 就是谎报。老 worker 静默忽略(开集提交体),故发送侧不设能力位前置门(oneShotWireCaps 头注)' },
65
- // ── 0.77.0(CC-101)print 车道补座两件:无人值守车道才有来源的请求位 ─────────────────────────
66
- // 加座判据三处同时成立才加(缺一处 ⇒ 不加座,登 `upstream_absent`,见 {@link UPSTREAM_ABSENT_REQUEST_INTENTS}):
67
- // ① 装着的 sdk `TaskRequest` 型面上有这一位的**具名**声明(索引签名 `[k: string]: unknown` 不算 ——
68
- // 它对任何键都成立,拿它当证据等于没有证据);② 上游提交体真读这一键;③ 引擎 spec 真消费它。
69
29
  { field: 'outputSchema', lanes: ['print'], live: true, why: '结构化输出约束(sdk `TaskRequest.outputSchema`:最终答案必须匹配的 JSON Schema)。上游只验形状与序列化尺寸(坏形 400 响亮拒)、深层合法性归引擎 ⇒ 本层原样透传、不预铸第二判官。来源只在无人值守车道(`--json-schema` 一类旗);交互面今天没有入口 ⇒ 缺席是**没有来源**,不是漏。⚠️ 本行只管**上行**这一位:结果一侧的结构化产出落不落 CC 形 result 帧是下行投影的事,不在本表' },
70
30
  { field: 'maxCostUsd', lanes: ['print'], live: true, why: '花费上限声明(sdk `TaskRequest.maxCostUsd`,请求体**顶层**位;上游向下夹到部署上限 —— 只许要得更少)。与 `limits` 同一条理由只在无人值守车道:交互面由人随时中断。🔴 坏值(非数 / 非有限 / 非正)在本层**响亮拒**:上游对这一位的坏值是安静忽略并回落部署上限,不是 4xx(见 `refuseBadMaxCostUsd`)' },
71
- // ── interactive 车道独有 ────────────────────────────────────────────────────────────────────
72
- // ⚠️ 「interactive」**不等于**「TUI」:web 的 BFF lane 也报 `interactive`
73
- // (`sema-web-client` `WEB_REQUEST_LANE`)。下面多数条目的理由写的是壳的 TUI 面 —— 它们是
74
- // B4 从壳的三个构造器逐行读出来的,那时这条车道只有壳一个消费者。`attachmentIds` 是**反过来**
75
- // 的第一条:它今天只有 web/desktop 在发,壳反而没有这个入口。别把本节读成「壳独有」。
76
31
  { field: 'attachmentIds', lanes: ['interactive'], live: true, why: '附件**字节通道**(uploadAttachment 回执 id;server ≥1.289 绑定会话并把文件物化进 run 的 attachments/)。有上传入口的端才有 id 可引用:web/desktop 有,壳走 images / 本地文件路径,`-p` 车道连 uploadAttachment 都没有 ⇒ print 缺席是**没有来源**,不是漏。🔴 与上面的 `attachments` 同名不同物(那是 turn 边界的配置键),两条永远不许合并' },
77
32
  { field: 'excludeTools', lanes: ['interactive', 'print'], live: true, why: 'design/161 W3(2026-07-30):真 wire 键(SDK types `excludeTools`)且早在 seatContract `START_SESSION_OPTION_KEYS` 里,却是 desktop 手写 taskReq 的第 9 键、矩阵外——而 stamp 门对未登记键**静默丢弃**,真实危险形=「用户显式排除的工具被静默放回」(权限方向回归,类型层不报)。今天只有 desktop 在发;壳的工具面走 roster/interactiveTools 另一条路。0.77.0 补 print 座(三问:① wire 位与车道无关 —— sdk 具名位、提交体真收 `body.excludeTools`;② 来源 —— print 今天没有排除入口,但这是**收紧方向**的声明,传了只进回执 = 端不读回执就把用户排除的工具放回;③ 口径 —— 仍是 live 门后的位,与交互面同一行)' },
33
+ { field: 'excludeAllTools', lanes: ['interactive', 'print'], live: true, why: '0.78.0(sdk 11.x 具名位 `excludeAllTools`,server ≥7.90.0 请求面):整只工具面卸载 —— 调用方工具 / 脚手架 / 手 / MCP / A2A / skills 一个都不挂,终局必然纯文本(wire 上 `wiring_manifest.tools.count === 0`,整条流零 tool_start / tool_end / tool_disclosure)。与 excludeTools 是两种语义、刻意不折叠(`"*"` 是一个合法的工具名,「卸全部」不能写成 `excludeTools:["*"]`);两键同带各自生效。类型只收字面 `true`(server 只把 literal true 写上任务规格,`false` = 替引擎重申它自己的缺省 ⇒ 不发、与缺席同义、不进回执);坏值响亮拒(收紧方向的声明不许被打字错误安静丢掉)。两条车道都是提交面 ⇒ 都能声明。探测靠键闭集、没有能力位:没接线的 server(≤7.89.x)400 `request.body_shape` 并在 `unknownKeys` 里逐字点名,本层不替它猜;A2A 入站面不承载本键(零工具面走 skill 路由)' },
78
34
  { field: 'settings.ultracode', lanes: ['interactive'], live: true, why: 'design/111:sticky `/effort ultracode` 拨盘 + 当轮关键词嗅探,两个来源都只在交互面存在', gap: true },
79
- // ⚠️ 下面两行 0.77.0(CC-101)之前是 `lanes:['interactive']`。修前的理由句(「print 腿的 params 没有这一位」/
80
- // 「print 无 AppState」)描述的是搬迁当天壳内两个构造器的**形参**,不是 wire 事实:两位在 sdk `TaskRequest`
81
- // 上都是与车道无关的具名顶层位,上游提交体与引擎 spec 两层都真消费。后果 = 无人值守车道传了也整键不上
82
- // 请求体,而调用方拿不到任何信号(下游壳实测:只好把对应的旗判成「未接线」如实告知用户)。
83
- // 行留在本节(而不是搬到「两条车道都有」那一节)只为让 diff 停在一行上;`lanes` 才是事实。
84
35
  { field: 'systemPrompt', lanes: ['interactive', 'print'], live: false, why: '整段替换系统提示(sdk `TaskRequest.systemPrompt`;上游字符数超限 400 响亮拒,本层原样透传)。两条车道都有来源:交互面 = CC QueryParams.systemPrompt,无人值守面 = `--system-prompt[-file]` 一类旗。与追加位 `appendSystemPrompt` 不是一个位(那一位归 live 兜底层,见 `LIVE_DEFAULT_FIELDS`)' },
85
36
  { field: 'reasoningEffort', lanes: ['interactive', 'print'], live: false, why: '思考档位(sdk `TaskRequest.reasoningEffort` 七词闭集;上游对表外词 400 响亮拒 ⇒ 本层不预铸第二判官)。档位是请求级的位、与车道无关:交互面 = `/effort` 拨盘,无人值守面 = 档位旗。🔴 端交的必须是**档位词**:「思考 token 数」今天没有上游对位(见 `UPSTREAM_ABSENT_REQUEST_INTENTS` 的 `maxThinkingTokens`),别把一个数字折成档位词发出去' },
86
37
  { field: 'model', lanes: ['interactive'], live: false, why: '`/model` 中途换模型读 toolUseContext.options.mainLoopModel;print 的模型走 MODEL_ID/--model 另一条路', gap: true },
87
38
  { field: 'images', lanes: ['interactive'], live: false, why: '贴图提交是交互动作,`-p` 的 stdin 没有图片块' },
88
- // ⚠️ 四键一条(0.35.0 补第四键 `resumeAtMode`):它是 `rewindWireCaps` 的 `SeamRewindSpec` 真 wire 键,
89
- // 且 `rewindSpecForMode` 的 `both` / `conversation` 两臂**恒返**它(排他截语义 —— 回到目标消息
90
- // **之前**)。修前合写项只列三键 ⇒ 真 `/rewind` 还原 turn 上 `unregisteredRequestKeys` 会点名
91
- // `resumeAtMode`,而那正是「本层不许有未登记键」这条判据的误报,会教端去白名单化真键。
92
39
  { field: 'resumeAt/resumeAtMode/rewindFiles/rewindFilesTo', lanes: ['interactive'], live: false, why: 'E18 `/rewind` 是交互命令;四键同生同灭(resumeAtMode 是 both/conversation 两臂恒带的排他截语义位)' },
93
40
  { field: 'clientContext', lanes: ['interactive'], live: false, why: 'IANA 时区 + 可选邮箱 → core 本地化 `# Environment` 的 today;print 同样跑在用户机器上,缺席让引擎误标 (UTC)', gap: true },
94
41
  { field: 'scratchpadDir', lanes: ['interactive'], live: true, why: '[816]③ per-session 暂存目录;print 也有 session,缺席让 `-p` 的工具写不进 exemptDir', gap: true },
95
42
  ];
96
- /** live 兜底层(`toLiveRequest`)追加的字段 —— 两条车道**都**经过,故不进上表。 */
97
43
  export const LIVE_DEFAULT_FIELDS = [
98
44
  'cwd',
99
45
  'additionalDirectories',
@@ -106,35 +52,6 @@ export const LIVE_DEFAULT_FIELDS = [
106
52
  'compactionModel',
107
53
  'sessionId(三态解析)',
108
54
  ];
109
- // ══ 逐键去向(0.77.0 / CC-101)════════════════════════════════════════════════════════════════════
110
- //
111
- // 修前的病形:stamp 门 `on()` 有**四种**说「不」的理由(值缺席 / 表里没有这一行 / 本车道不在 lanes 里 /
112
- // live 门没开),四种都折成同一个 `false`;而入参上构造器**压根不读**的键(表外键)连这个 `false` 都轮不到。
113
- // 调用方拿到的只有一份请求体 —— 少了哪个键、为什么少,没有任何位能答。
114
- //
115
- // 修形分两半,**刻意不合并**:
116
- // (甲) 本包**认识**的键这一次没上请求体 ⇒ 不抛,照常装配,逐键给成因({@link TaskRequestOmission})。
117
- // 一个多余但无害的键不该把提交升级成硬失败;该知道的人从回执上知道。
118
- // (乙) 本包**不认识**的键 ⇒ 响亮拒(`TypeError`)。不认识 = 三种可能分不开:打错的在座键名 / 真 wire 位而
119
- // 本包的表还没登记 / 纯垃圾。前两种里都可能是**收紧方向**的声明(排除工具、关记忆、花费上限),
120
- // 安静丢掉 = 这次运行比声明人以为的更宽,而且没有任何人会知道 —— 与 `memoryCapture` 坏拼写同一条
121
- // 纪律,只是错在键名那一轴。🔴 把这一档折成 (甲) 的某个成因词 = 拿「不知道」冒充「明确不带」。
122
- /**
123
- * 「入参里在场、却没上请求体」的**成因词表**(冻结)。🔴 词序就是判定序(先中先得),判定逐词走
124
- * {@link OMISSION_JUDGES} —— 那张判官表的键型就是本词表的成员型:加词不加判官 / 加判官不加词,编译当场红。
125
- *
126
- * · `upstream_absent` —— 本包认识这个意图,但上游没有对位(sdk 型面无具名位,提交体与引擎 spec 也不读)。
127
- * 见 {@link UPSTREAM_ABSENT_REQUEST_INTENTS}。恒不发,与车道 / live 无关。
128
- * · `other_channel` —— 是请求体上的真位,但**不归本构造器**盖:归 live 兜底层({@link LIVE_DEFAULT_FIELDS},
129
- * 端在构造之后经 {@link applyLiveRequestDefaults} 落位)。塞进本构造器的入参 = 没发出去。
130
- * · `off_lane` —— 在车道表里,但本车道不在那一行的 `lanes` 里(理由读那一行的 `why`)。
131
- * · `not_live` —— 本车道有座,但那一行是 live 门后的位,而这一次 `input.live` 为假(mock / fixture 车道)。
132
- *
133
- * 🔴 本词表只答「**本构造器**这一次带没带」。带了 ≠ 引擎兑现了:老版本上游静默忽略新键、部署策略拒、
134
- * 能力位没开,那些只有引擎知道 —— 端不许拿「回执里没有这一键」去渲一句「已生效」。
135
- * ⚠️ **值级等价缺席不入回执**:空数组 / `council:false` / `oneShot` 非 `true` 这类值在 wire 上与缺席同义
136
- * (构造器发小的那个),没有意图被丢,报它们只是噪音。
137
- */
138
55
  export const TASK_REQUEST_OMISSION_CAUSES = Object.freeze([
139
56
  'upstream_absent',
140
57
  'other_channel',
@@ -142,10 +59,6 @@ export const TASK_REQUEST_OMISSION_CAUSES = Object.freeze([
142
59
  'not_live',
143
60
  ]);
144
61
  const row = (field) => ({ via: 'matrix', field });
145
- /**
146
- * 🔴 键型 = `keyof Required<TaskRequestInput>`:入参型加一个键而这里不登记 ⇒ 编译红;这里多一个入参型没有的
147
- * 键 ⇒ 同样编译红。「入参型上声明了、构造器却从不读」的键因此不可能再安静存在(修前 `agents` 正是这一形)。
148
- */
149
62
  const INPUT_KEY_ROUTES = {
150
63
  objective: { via: 'always' },
151
64
  sessionId: { via: 'always' },
@@ -169,6 +82,7 @@ const INPUT_KEY_ROUTES = {
169
82
  attachments: row('attachments'),
170
83
  attachmentIds: row('attachmentIds'),
171
84
  excludeTools: row('excludeTools'),
85
+ excludeAllTools: row('excludeAllTools'),
172
86
  finalVerification: row('finalVerification'),
173
87
  limits: row('limits'),
174
88
  interactiveTools: row('interactiveTools'),
@@ -205,18 +119,11 @@ const SETTINGS_KEY_ROUTES = {
205
119
  webSearch: row('settings.webSearch'),
206
120
  ultracode: row('settings.ultracode'),
207
121
  hooks: row('settings.hooks'),
208
- // 没有车道行:它是 live 兜底层登记的位(`appendSystemPrompt|settings.outputStyle`),构造器无条件原样带。
209
122
  outputStyle: { via: 'always' },
210
123
  };
211
124
  export const UPSTREAM_ABSENT_REQUEST_INTENTS = Object.freeze(Object.entries(INPUT_KEY_ROUTES).flatMap(([key, route]) => route.via === 'fixed' && route.cause === 'upstream_absent' ? [Object.freeze({ key, why: route.why })] : []));
212
125
  const hasOwn = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
213
- /** live 兜底层的裸键名(表项写法含 `|` 备选位与括号说明)。判据面与装配面同读这一只,不各抄一份解析。 */
214
126
  const liveDefaultKeyNames = () => new Set(LIVE_DEFAULT_FIELDS.flatMap(item => item.split('|')).map(name => name.replace(/\(.*\)$/, '').trim()));
215
- /**
216
- * **顶层**入参键 → 路由:入参型上的键 / 入参型之外的 live 兜底**裸**键(按 `other_channel` 认)/ 其余 = 不认识。
217
- * 🔴 点分名在这里**一律不认**:一个字面叫 `settings.ultracode` 的顶层键不是 `settings` 的子键 —— 构造器不读它,
218
- * 认它 = 判官说「带」而请求体上没有。
219
- */
220
127
  const routeOfTopLevelKey = (key) => {
221
128
  if (hasOwn(INPUT_KEY_ROUTES, key))
222
129
  return INPUT_KEY_ROUTES[key];
@@ -224,7 +131,6 @@ const routeOfTopLevelKey = (key) => {
224
131
  return { via: 'fixed', cause: 'other_channel' };
225
132
  return undefined;
226
133
  };
227
- /** 座位读数用的键名 → 路由:`settings.<sub>` 走点分名,其余同顶层。 */
228
134
  const routeOfInputKey = (key) => {
229
135
  if (key.startsWith('settings.')) {
230
136
  const sub = key.slice('settings.'.length);
@@ -232,10 +138,6 @@ const routeOfInputKey = (key) => {
232
138
  }
233
139
  return routeOfTopLevelKey(key);
234
140
  };
235
- /**
236
- * 车道表的一行。🔴 查不到 = **本包自己的表漂了**(装配代码点名了一行、表里却没有),不是调用方的错:
237
- * 修前这里是 `return false` —— 改名一行而漏改装配代码,那个键就此安静地永不上请求体,没有一道门会响。
238
- */
239
141
  const matrixRow = (field) => {
240
142
  const spec = REQUEST_FIELD_MATRIX.find(f => f.field === field);
241
143
  if (spec === undefined) {
@@ -244,21 +146,14 @@ const matrixRow = (field) => {
244
146
  return spec;
245
147
  };
246
148
  const standingOf = (route) => route.via === 'matrix' ? { via: 'matrix', spec: matrixRow(route.field) } : { via: 'fixed', cause: route.cause };
247
- /** 逐词判官 —— 键型就是词表的成员型(与词表的双向耦合在编译期咬死,见词表头注)。 */
248
149
  const OMISSION_JUDGES = {
249
150
  upstream_absent: s => s.via === 'fixed' && s.cause === 'upstream_absent',
250
151
  other_channel: s => s.via === 'fixed' && s.cause === 'other_channel',
251
152
  off_lane: (s, lane) => s.via === 'matrix' && !s.spec.lanes.includes(lane),
252
153
  not_live: (s, _lane, live) => s.via === 'matrix' && s.spec.live && !live,
253
154
  };
254
- /** 唯一的「带不带」判官:`undefined` = 带。stamp 门与回执同读这一只 ⇒ 「回执说带了而请求体上没有」不可能成立。 */
255
155
  const omissionCauseOf = (s, lane, live) => TASK_REQUEST_OMISSION_CAUSES.find(cause => OMISSION_JUDGES[cause](s, lane, live));
256
- /** 车道闭集(`Record<RequestLane, true>`:型上加一条车道而这里不加 ⇒ 编译红)。 */
257
156
  const REQUEST_LANE_SET = { interactive: true, print: true };
258
- /**
259
- * 车道实参的运行期形核。🔴 修前一个表外的车道词(JS 调用方 / 拼写错)让**每一行**的 `lanes.includes` 都答假 ⇒
260
- * 产出只剩 `{objective, sessionId}`,而调用方拿不到任何信号 —— 与表外键同一个病,只是错在控制位上。
261
- */
262
157
  const refuseBadLane = (lane) => {
263
158
  if (typeof lane === 'string' && hasOwn(REQUEST_LANE_SET, lane))
264
159
  return;
@@ -266,17 +161,10 @@ const refuseBadLane = (lane) => {
266
161
  '表外的车道词会让车道表里每一行都判「不属于本车道」,请求体只剩 objective 与 sessionId 而没有任何信号,所以在装配前拒。错误文本只报形状,不回显值。');
267
162
  };
268
163
  const present = (v) => v !== undefined && v !== null;
269
- /** `rewind` 合写项的四个子键(从车道表派生,不手抄;表漂 ⇒ 空集 ⇒ 值级恒缺席,门 A 段当场红)。 */
270
164
  const rewindSubKeys = () => {
271
165
  const r = INPUT_KEY_ROUTES.rewind;
272
166
  return r.via === 'matrix' ? r.field.split('/') : [];
273
167
  };
274
- /**
275
- * 值级等价缺席(**唯一**判据表;stamp 与回执两口共用,不许各写一份):这些键的某些值在 wire 上与「没带」同义
276
- * (上游按 `=== true` / `=== false` / `=== 'off'` / 非空读;空数组 = 「带了 0 个」= 没带),本包发小的那个。
277
- * 🔴 回执口也按它判:一个值级缺席的键既不 stamp、也**不进回执** —— 否则 `oneShot:false` 在无座车道上会生一行
278
- * 「这一次没发出去」,而它本来就没有东西可发。表外的键值级恒在场(`present` 即在场)。
279
- */
280
168
  const VALUE_LEVEL_IN_PLAY = Object.freeze({
281
169
  council: (v) => v === true,
282
170
  debate: (v) => v === true,
@@ -285,30 +173,21 @@ const VALUE_LEVEL_IN_PLAY = Object.freeze({
285
173
  images: (v) => Array.isArray(v) && v.length > 0,
286
174
  attachmentIds: (v) => Array.isArray(v) && v.length > 0,
287
175
  excludeTools: (v) => Array.isArray(v) && v.length > 0,
176
+ excludeAllTools: (v) => v === true,
288
177
  memoryCapture: (v) => v === 'off',
289
178
  memory: (v) => v === 'off',
290
179
  rewind: (v) => typeof v === 'object' && v !== null && rewindSubKeys().some((k) => hasOwn(v, k) && present(v[k])),
291
180
  });
292
- /** 在场 ∧ 值级在场。 */
293
181
  const inPlay = (key, v) => present(v) && (VALUE_LEVEL_IN_PLAY[key]?.(v) ?? true);
294
- /**
295
- * 按名各读一次成一份无原型快照(读法 = 属性读,继承位 / 访问器与修前同一种读法;每键恰一次)。
296
- * `seed` = 调用方**已经读过**的位:照抄进快照,不读第二次(权限面那三位要先于一切别的读取,见装配口读序注)。
297
- */
298
182
  const snapshotByName = (source, keys, seed = {}) => {
299
183
  const out = Object.create(null);
300
184
  for (const k of keys)
301
185
  out[k] = hasOwn(seed, String(k)) ? seed[k] : source[k];
302
186
  return out;
303
187
  };
304
- /** 拒绝文本里单个键名的显示上限与清单上限(键名可能来自不可信入参 ⇒ 转义 + 封长;只进文案,不进判据)。 */
305
188
  const UNKNOWN_KEY_DISPLAY_MAX = 64;
306
189
  const MAX_UNKNOWN_KEYS_SHOWN = 16;
307
190
  const keyForDisplay = (k) => k.length > UNKNOWN_KEY_DISPLAY_MAX ? `${JSON.stringify(k.slice(0, UNKNOWN_KEY_DISPLAY_MAX))}(已截短)` : JSON.stringify(k);
308
- /**
309
- * 座位读数(静态口:不装配请求就能问「这一键在这条车道上有没有座」)。`key` 是**入参键名**
310
- * (`settings` 的子键写点分名 `settings.ultracode`);与装配口同读一张路由表、同一只判官。
311
- */
312
191
  export function taskRequestSeatOf(key, lane) {
313
192
  refuseBadLane(lane);
314
193
  const route = typeof key === 'string' ? routeOfInputKey(key) : undefined;
@@ -317,7 +196,6 @@ export function taskRequestSeatOf(key, lane) {
317
196
  if (route.via === 'always' || route.via === 'control' || route.via === 'settings')
318
197
  return SEATED_UNGATED;
319
198
  const standing = standingOf(route);
320
- // live 取真 = 问的是「车道上有没有座」;`not_live` 的判官要 live 为假才中,故此处永不返回它(型上同样排除)。
321
199
  const cause = omissionCauseOf(standing, lane, true);
322
200
  if (cause !== undefined && cause !== 'not_live')
323
201
  return Object.freeze({ seat: 'none', cause });
@@ -326,44 +204,9 @@ export function taskRequestSeatOf(key, lane) {
326
204
  const SEAT_UNKNOWN = Object.freeze({ seat: 'unknown' });
327
205
  const SEATED_UNGATED = Object.freeze({ seat: 'seated', liveGated: false });
328
206
  const SEATED_LIVE_GATED = Object.freeze({ seat: 'seated', liveGated: true });
329
- /**
330
- * 本车道**不拥有**的具名 settings 子键(= 表里有 `settings.<sub>` 行、而该行的 lanes 不含本车道)。
331
- *
332
- * 用处只有一个:{@link unregisteredRequestKeys} 的判据面。`settings.<resolved>` 是**开放集 spread**
333
- * —— 快照里的子键原样就是 wire 键,所以那条车道的 `settings` 走开放集口径(表外子键放行)。但
334
- * 开放集**不是**整只 `settings` 免检:一个「表里点名了、却不属于本车道」的子键(今天 = print 的
335
- * `settings.ultracode`)是**可枚举的已知量**,放过它等于让那条登记在真 wire 面失效。反过来,本车道
336
- * **自己**那些具名子键合法出现在 wire 上(它们从具名通道来),所以本集合按车道排除,不含它们。
337
- *
338
- * 🔴 构造器侧用的是另一个集合({@link namedSettingsSubKeys},全集)—— 两个集合不是同一件事,别合并:
339
- * 判据问的是「这个键该不该出现在 wire 上」,构造器问的是「这个键该由哪条通道决定」。
340
- */
341
207
  const foreignSettingsSubKeys = (lane) => REQUEST_FIELD_MATRIX.filter(f => f.field.startsWith('settings.') && f.field !== 'settings.<resolved>' && !f.lanes.includes(lane)).map(f => f.field.slice('settings.'.length));
342
- /**
343
- * **具名通道管着的**全部 settings 子键 —— 表里凡有 `settings.<sub>` 行的都算,**不分车道**。
344
- *
345
- * 与 {@link foreignSettingsSubKeys} 的分工(两个集合,两件事):
346
- * · foreign(**异车道**子集)= 判据面用 —— 真 wire 上出现一个「表里点名了、却不属于本车道」的
347
- * 子键要被点名;本车道自己那些具名子键**合法**出现在 wire 上(它们从具名通道来)。
348
- * · named(**全集**)= 构造器面用 —— 快照通道对具名通道管着的键**一律让位**,理由见下。
349
- */
350
208
  const namedSettingsSubKeys = () => REQUEST_FIELD_MATRIX.filter(f => f.field.startsWith('settings.') && f.field !== 'settings.<resolved>').map(f => f.field.slice('settings.'.length));
351
- /** 快照里**权限方向**那一位的键名(唯一享有「摊得全 + 就地重建」强制的位;射程理由见头注 ③)。 */
352
209
  const PERMISSION_FACE_KEY = 'permissions';
353
- /**
354
- * 形状描述(错误文本用):只报**形**,一个字节的内容都不带(快照里有 env / 权限面)。
355
- *
356
- * 载体名(prototype 的 constructor 名)是代码标识符不是用户数据,可以报 —— 它是「你传进来的是个
357
- * 什么东西」这个问题唯一有用的线索。取值整段包在 catch 里:proxy / 带副作用 getter 的载体能让
358
- * `toString` 与 `constructor` 都抛错,而**构造错误文本时抛错**会把「拒」这个判决换成一个面目全非的
359
- * 异常。判决是拒,描述只是线索,取不到就报 unreadable。
360
- */
361
- /**
362
- * 拒绝文本用的**粗分类**(0.72.8 异源复审第二轮 [medium] 真修):只用 `typeof` / null / array 三个固定词,**不**读
363
- * `Symbol.toStringTag`、也不读 prototype 的 constructor 名 —— 那两样都是**调用方可控**的串,对象可以借它们把敏感内容
364
- * 带进错误展示 / 日志。memory 一族(隐私 / 记忆面声明)的拒绝路径一律走它;`shapeTag` 留给 settings.resolved 那类
365
- * 载体形诊断(那里报的是构造器名这一线索,与本族的「只报形状不回显值」纪律不同)。
366
- */
367
210
  const coarseShape = (v) => v === null ? 'typeof=object / null' : Array.isArray(v) ? 'typeof=object / array' : `typeof=${typeof v}`;
368
211
  const shapeTag = (v) => {
369
212
  try {
@@ -374,41 +217,15 @@ const shapeTag = (v) => {
374
217
  return `typeof=${typeof v} / ${Object.prototype.toString.call(v)} / prototype=${carrier}`;
375
218
  }
376
219
  catch {
377
- // 形状取不到 ⇒ 只报 typeof(拒本身已经成立,描述缺一半不影响判决)。
378
220
  return `typeof=${typeof v} / shape=unreadable`;
379
221
  }
380
222
  };
381
- /**
382
- * plain object 判别 —— 按 **prototype** 判,不按 `Object.prototype.toString` 的标签判。
383
- *
384
- * 🔴 标签判法是**假的**(0.35.0 对抗复审 [high] 采纳):`[object Object]` 对**普通类实例**同样
385
- * 成立,而 `Symbol.toStringTag` 还能让任意载体自报这个标签。放它过去之后,下面的摊开用的是
386
- * `Object.entries`(**只取自有可枚举键**)—— 于是一个把 `permissions.deny/ask` 挂在**原型 getter**
387
- * 上的载体会摊出一个**空快照**,请求照发 = 权限静默变宽,正是本节要堵的那个 fail-open 形。
388
- *
389
- * 所以合法载体只有两种:**对象字面量**(原型链只有一层)与 `null` 原型(`Object.create(null)`,常见于
390
- * 「无污染字典」写法)。两者的自有可枚举键集**就是**全部内容,`Object.entries` 不会漏。类实例 /
391
- * `Map` / `Date` / boxed 包装对象 / 数组一律拒 —— 它们要么内容不在自有键上,要么摊开就是垃圾键;
392
- * 「上游产出坏了」比「悄悄发一个更宽的权限面」更该被人看见。
393
- *
394
- * 🔴 判据 **realm 无关**(0.35.0 对抗复审第八轮 [medium] 采纳):不拿「**本** realm 的
395
- * `Object.prototype`」做身份比较 —— iframe / `node:vm` / 另一个渲染进程里的对象字面量各有**自己的**
396
- * `Object.prototype`,身份比较会把这些**完全合法、JSON 忠实**的载体误判成异形,在 web / desktop 宿主
397
- * 上变成提交前的硬失败。
398
- *
399
- * 🔴 但「realm 无关」不等于「按原型链**层数**判」(第九轮 [medium] 采纳):`Object.create(X)`(X 是个
400
- * 自造的**无原型**对象)与 `class … extends null` 的实例都只有一层,却能把 `deny` 挂在那层**继承**位上
401
- * —— 而摊开只看自有键(`JSON.stringify` 也只看自有键),于是规则整条不见。所以判的是「直接原型是不是
402
- * **某个 realm 的**内建 `Object.prototype`」:取那层原型的**自有** `constructor`,要求它是个函数且
403
- * 源码文本与本 realm 的 `Object` 逐字相同(内建函数的源码是 `function Object() { [native code] }`,
404
- * 跨 realm 一致、而 `Map`/自定义类各不相同)。自造原型没有自有 `constructor` ⇒ 拒。
405
- */
406
223
  const isPlainRecord = (v) => {
407
224
  if (typeof v !== 'object' || v === null)
408
225
  return false;
409
226
  const proto = Object.getPrototypeOf(v);
410
227
  if (proto === null)
411
- return true; // Object.create(null) 无污染字典:自有键就是全部内容
228
+ return true;
412
229
  if (typeof proto !== 'object')
413
230
  return false;
414
231
  if (!Object.prototype.hasOwnProperty.call(proto, 'constructor'))
@@ -418,9 +235,6 @@ const isPlainRecord = (v) => {
418
235
  return false;
419
236
  if (Function.prototype.toString.call(ctor) !== Function.prototype.toString.call(Object))
420
237
  return false;
421
- // 🔴 还要求「这个原型**就是**那个构造器的 prototype」(第十轮 [high] 采纳):只比源码文本可以被
422
- // **冒充** —— 自造一个无原型对象、给它塞 `constructor: Object`,源码文本自然对得上,规则却挂在
423
- // 它的继承位上。真 `Object.prototype`(任何 realm)恒满足 `Object.prototype === proto`,冒充者不满足。
424
238
  return ctor.prototype === proto;
425
239
  };
426
240
  const materializeJsonFaithful = (v, path, seen = new Set()) => {
@@ -432,56 +246,31 @@ const materializeJsonFaithful = (v, path, seen = new Set()) => {
432
246
  if (t === 'number') {
433
247
  return Number.isFinite(v) ? { value: v } : { bad: `${path}(非有限数 ⇒ 序列化成 null)` };
434
248
  }
435
- // function / symbol / bigint / undefined(数组元素形)都不是 JSON 值
436
249
  if (t !== 'object')
437
250
  return { bad: `${path}(typeof=${t} 不是 JSON 值)` };
438
251
  const o = v;
439
252
  if (seen.has(o))
440
253
  return { bad: `${path}(循环引用)` };
441
- // 🔴 读的**次序**要跟原生 `JSON.stringify` 一致,而它只在两件事上有定义(第十三轮 [high] 采纳):
442
- // ① 它**先查一次 `toJSON`**、再枚举内容 —— 所以这一查必须排在捕获**之前**,而且只查一次
443
- // (`toJSON` 可以是个带副作用的**访问器**:实测一个「push 一条规则再返回 undefined」的 getter
444
- // 能让原生序列化出 `{"deny":["Write"]}`,我们若晚查一步就会发 `{"deny":[]}` = 比原生更宽);
445
- // ② 它**从不读原型** —— 所以 `isPlainRecord` 那一读只能排在捕获**之后**(见下:那一读可被陷阱化
446
- // 并带副作用,排在前面就是本层自己引入的丢失面)。
447
- // 一句话:**原生会做的读,按它的次序做;原生不做的读,一律推到捕获之后。**
448
254
  const toJSONProp = o.toJSON;
449
255
  if (typeof toJSONProp === 'function')
450
256
  return { bad: `${path}(自报 toJSON ⇒ 字节被改写)` };
451
257
  seen.add(o);
452
258
  try {
453
259
  if (Array.isArray(o)) {
454
- // 🔴 **不调载体自己的实例方法**(第五轮 [high]):`o.entries()` 是可覆盖的 —— 一个 `['Write']`
455
- // 自带一个什么都不产的 `entries` 就能让本函数重建出 `[]`,而原生 `JSON.stringify` 照发
456
- // `["Write"]`:那样**重建自己**成了丢规则的那一环。改按捕获长度 + 数字下标走
457
- // (`Array.isArray` 与 `length` 不经用户方法),与 stringify 读数组的方式一致。
458
- // 🔴 长度**只强制转换一次**,且按真正的 `ToLength` 边界(第十五轮 [high] + 第十六轮 [high]):
459
- // ① 存下来的可能是个**对象**(Proxy 的 get 陷阱能让 `length` 返回带 `valueOf` 的对象),
460
- // 于是 `i < len` 每轮都重新求值 —— 一个「第一次给 3、以后给 1」的 length 能让原生发三条规则、
461
- // 我们只发一条 = 掉规则。原生走 `ToLength(Get(O,'length'))` **一次**,这里也只转一次。
462
- // ② `!isFinite ⇒ 0` 是**错的**:实测原生对 `length: Infinity` 抛 `RangeError`、对 BigInt 抛
463
- // `TypeError`(ToNumber 不接 BigInt),而归 0 会让我们**静默发一个空 deny** = 权限变宽。
464
- // 两形按契约① 响亮拒。`NaN` / 负数 / `-Infinity` 归 0 才是与原生一致的(原生也发 `[]`)。
465
260
  const rawLen = o.length;
466
261
  if (typeof rawLen === 'bigint' || typeof rawLen === 'symbol') {
467
262
  return { bad: `${path}(length 是 ${typeof rawLen} ⇒ 原生序列化直接抛,归 0 会静默发空表)` };
468
263
  }
469
- // 🔴 转换要用**抽象 ToNumber**,而 `Number(x)` 不是它(第十七轮 [high],实测):`Number()` 接受
470
- // **对象强制出来的 BigInt**(`{valueOf(){return 0n}}` / `Object(0n)` / `Symbol.toPrimitive→0n`
471
- // 都得 0),而原生 `JSON.stringify` 在同样输入上抛 `TypeError` ⇒ 归 0 就成了「静默发空 deny」。
472
- // 一元 `+` **就是** ToNumber:BigInt / symbol 一律抛,接住它翻成本层的「拒」。只转一次不变。
473
264
  let lenNum;
474
265
  try {
475
266
  lenNum = +rawLen;
476
267
  }
477
268
  catch {
478
- // ToNumber 抛(BigInt / symbol,含对象强制形)⇒ 原生也抛,拒。
479
269
  return { bad: `${path}(length 按 ToNumber 转换即抛(BigInt/symbol 形)⇒ 原生序列化也抛,归 0 会静默发空表)` };
480
270
  }
481
271
  if (lenNum === Number.POSITIVE_INFINITY) {
482
272
  return { bad: `${path}(length 是 +Infinity ⇒ 原生序列化抛 RangeError,归 0 会静默发空表)` };
483
273
  }
484
- // ToLength 的其余分支:NaN / 负数 / -Infinity ⇒ 0;有限数截断后封顶 2^53-1。
485
274
  const len = Number.isNaN(lenNum)
486
275
  ? 0
487
276
  : Math.min(Math.max(0, Math.trunc(lenNum)), Number.MAX_SAFE_INTEGER);
@@ -492,118 +281,44 @@ const materializeJsonFaithful = (v, path, seen = new Set()) => {
492
281
  return r;
493
282
  items.push(r.value);
494
283
  }
495
- return { value: items }; // 重建:原数组(可能是子类/带访问器/带覆盖方法)不出门
284
+ return { value: items };
496
285
  }
497
- // 🔴 重建成**无原型**记录(0.35.0 对抗复审第七轮 [high] 的可采半场):
498
- // ① 忠实 —— 源本来就允许 `Object.create(null)` 字典,重建成 `{}` 等于把载体形换掉了;
499
- // ② 少一条改写面 —— 无原型记录不会继承任何**事后**装到 `Object.prototype` 上的 `toJSON`。
500
- // ⚠️ 但这只关掉了 record 那一半:重建出来的**数组**必须是真数组(`Array.isArray` / 序列化成
501
- // `[...]` 都依赖 `Array.prototype`),所以「构造之后有人污染内建原型」这条**在数组上无解** ——
502
- // 那种进程里每个对象、每个库都已经不可信了,不是本层能兜的射程。少声称,别装。
503
286
  const rec = Object.create(null);
504
- // 🔴 键先捕获、值**逐个即读即建**(第五轮 [high]):`Object.entries` 会把所有值先读齐再递归拷贝,
505
- // 于是后一个属性的 getter 能在前一个值被拷走**之前**把它清空(拿到的是同一个引用)。
506
- // stringify 也是「先取键、再逐键读值」,按它的次序走才叫忠实。
507
287
  for (const k of Object.keys(o)) {
508
288
  const val = o[k];
509
289
  if (val === undefined)
510
- continue; // record 值缺席 = 该键不存在,序列化丢它是对的
290
+ continue;
511
291
  const r = materializeJsonFaithful(val, `${path}.${k}`, seen);
512
292
  if ('bad' in r)
513
293
  return r;
514
- // 🔴 `defineProperty` 而不是 `rec[k] = …`(第五轮 [high]):`k` 可以是 `__proto__` —— 那是
515
- // `JSON.parse` 出来的**普通数据键**(stringify 照发),而 `rec['__proto__'] = v` 会打到
516
- // `Object.prototype` 的 setter 上:键整个丢掉、还顺手换了目标对象的原型。
517
294
  Object.defineProperty(rec, k, { value: r.value, enumerable: true, writable: true, configurable: true });
518
295
  }
519
- // 🔴 判据的读法**一律排在捕获之后**(0.35.0 对抗复审第十二轮 [high] 采纳):`toJSON` 走属性
520
- // 查找、`isPlainRecord` 走 `getPrototypeOf`/`constructor` —— 这三种读法**都可以带副作用**
521
- // (`getPrototypeOf` 陷阱在被问的那一刻把 `deny` 清空),而**原生 `JSON.stringify` 从不问原型**。
522
- // 校在捕获之前 = 本层自己的读法成了丢内容的那一环(比被动撒谎更糟:那是我们引入的丢失面)。
523
- // 次序改成「先按 stringify 的口径捕获,再校原件,校不过就丢掉捕获物」⇒ 校本身再有副作用也
524
- // 影响不到已经捕获的那份,而拒绝面一字未变。
525
296
  if (!isPlainRecord(o))
526
297
  return { bad: `${path}(${shapeTag(o)})` };
527
- return { value: rec }; // 重建:出门的是无原型纯记录,访问器/原型/隐藏位都留在原对象上
298
+ return { value: rec };
528
299
  }
529
300
  finally {
530
301
  seen.delete(o);
531
302
  }
532
303
  };
533
- /**
534
- * 快照 → 摊开成 `settings` 子键前的两道处理:**具名通道让位** + **畸形响亮拒**。
535
- *
536
- * ## ① 具名通道管着的键一律让位(0.35.0)
537
- *
538
- * 快照是**开放集 spread**(子键原样就是 wire 键),所以它天生是一条**第二通道**。0.34.0 只剥了
539
- * 「车道异名」键(表里那行的 lanes 不含本车道),于是**两条车道都登记**的具名键剥不到 ——
540
- * 而那些键各有自己的治理门:`settings.hooks` 的具名通道在「工作区未受信 / 管理侧明令关停全部
541
- * hooks / 检查本身抛错」时判**不投**(端给的 `settings.hooks` 就是 `undefined`),可快照里那份
542
- * **没过那道门**的 hooks 照样被摊上 wire ⇒ 关停令等于没下。
543
- *
544
- * 所以让位不能靠**合并序**(具名键排在快照之后覆盖它)—— 那只在具名通道**有值**时有效,而
545
- * 治理门否决时的表现恰恰是**没值**。修形 = 结构剥离:凡具名通道管着的子键,快照一概不产。
546
- * 「谁该决定这个键上不上 wire」只有一个答案:那条具名通道(和它的门)。
547
- *
548
- * 🔴 剥得**窄**:只剥表里点名的具名子键。快照**表外**的子键(permissions / env / model / …)
549
- * 原样摊开 —— 那是开放集的全部意义;`outputStyle` 没有车道行(它是 live 兜底层的位)故不受影响。
550
- *
551
- * ## ② 畸形快照响亮拒(0.35.0,fail-closed)
552
- *
553
- * `undefined` / `null` = **合法缺席**(端没解析出快照;老写法拿 null 当空快照传),照旧降空对象。
554
- * 其余非 plain-object 形(数组 / 原始值 / boxed 包装对象 / Map / **类实例**…)= **上游产出坏了**:
555
- * 0.34.0 把它们一律降空,可这一位摊开的正是**已解析权限面** —— 降空 = 请求带着「被剥掉的
556
- * deny/ask」照发出去,引擎侧看到的是一个权限更宽的会话,而且没有任何人会知道。宁可停在提交前:
557
- * `TypeError` 带形状描述(合法载体的判据见 {@link isPlainRecord} —— 「摊得全」是它的全部理由)。
558
- * (本包是发出去的 npm 公开面:JS 调用方与版本偏斜的宿主都到得了这里,型面拦不住。)
559
- *
560
- * ## ③ 权限面**子树**同样要摊得全(0.35.0 对抗复审第二轮 [high] 采纳)
561
- *
562
- * 只校最外层是不够的:`{ permissions: new Map([['deny',['Write']]]) }` 的外层是合法字面量,可
563
- * `JSON.stringify` 把那只 Map 序列化成 `"permissions":{}` —— deny 规则**静默消失**,与 ② 要堵的
564
- * 是同一个权限变宽形,只是深了一层。所以 `permissions` 子树递归过 {@link materializeJsonFaithful}:
565
- * plain record / 数组 / JSON 原始值才算摊得全,`Map`/`Set`/类实例/boxed/环一律拒。
566
- *
567
- * 🔴 **射程刻意只到 `permissions`**,不做整份请求体的深净化:那是「包级 wire 载荷 JSON-safe
568
- * 规范化」独立工单(同一条论证对 `agents`/`hooks`/`attachments` 一样成立),不在本批。这条边界
569
- * 不是随手划的 —— `permissions` 是**权限方向**的那一位:它的内容丢一条 = 会话权限变宽;而
570
- * `env`/`model` 之类配置位的同款畸形是功能缺失,会被人当场看见,不是安全面静默偏移。
571
- * 判据形状**不猜 schema**(不要求「deny 必须是字符串数组」——那会在 server 契约扩形那天误红),
572
- * 只问「序列化后还是不是同一份内容」。
573
- */
574
304
  const resolvedSnapshotForWire = (resolved) => {
575
305
  if (resolved === undefined || resolved === null)
576
306
  return {};
577
- // 原始值 / 函数 / symbol:没有任何可捕获的内容,立刻拒(不必先捕获 —— 拒得早不会丢东西)。
578
307
  if (typeof resolved !== 'object') {
579
308
  throw new TypeError(`buildTaskRequest: settings.resolved 只接受 plain object 或缺席(undefined/null)—— 收到 ${shapeTag(resolved)}。` +
580
309
  '这一位摊开的是已解析权限面(permissions.deny/ask 等子键即 wire 键):把畸形值降成空对象' +
581
310
  '等于让请求带着被剥掉的权限面发出去(deny 静默失效),所以在提交前拒。' +
582
311
  '错误文本只报形状,不回显快照内容。');
583
312
  }
584
- // 🔴 **外层的载体判据也排在捕获之后**(第十二轮 [high],与内层同一条):`isPlainRecord` 要读
585
- // `getPrototypeOf` —— 那是**原生序列化从不做**的一次读,而它可以被陷阱化并带副作用(被问原型的
586
- // 那一刻把 `permissions.deny` 清空)。所以先按 stringify 的口径把内容取走(下面的循环会把权限面
587
- // 当场物化成脱钩副本),原件的形状判据留到最后;校不过就整体拒,拒绝面一字未变。
588
313
  const named = namedSettingsSubKeys();
589
314
  const out = {};
590
- // 🔴 **键先捕获、值逐个即读即处理**(0.35.0 对抗复审第六轮 [high]):`Object.entries(resolved)`
591
- // 会把**所有兄弟键**的值先读齐 —— 于是一个 `env`/`model` 位上的 getter 能在 `permissions` 被
592
- // 重建**之前**把它的 deny 数组清空(拿到的是同一个引用)。这与内层那条(见
593
- // {@link materializeJsonFaithful} 第五条)是同一个病、只是高一层:两层都必须按 stringify 的
594
- // 次序走(先取键、再逐键读值),否则「校的就是发的」在外层又漏了一次。
595
315
  for (const k of Object.keys(resolved)) {
596
316
  if (named.includes(k))
597
317
  continue;
598
318
  const v = resolved[k];
599
319
  if (k === PERMISSION_FACE_KEY) {
600
- // 值缺席 = 该键不存在(与内层 record 同一条口径),整键不出现。
601
320
  if (v === undefined)
602
321
  continue;
603
- // ③ 权限面:**即读即校即建**(射程与理由见头注 ③;报的是**路径**不是值)。
604
- // 🔴 函数载体也必须走这条 —— 修前它先被下面那条「函数值一律不进」吃掉,于是
605
- // `permissions: () => …`(哪怕自带 deny)**整键静默消失** = 请求带着更宽的权限面发出去,
606
- // 正是本节要堵的形。权限面的畸形只有一个诚实终态:拒。
607
322
  const checked = materializeJsonFaithful(v, PERMISSION_FACE_KEY);
608
323
  if ('bad' in checked) {
609
324
  throw new TypeError(`buildTaskRequest: settings.resolved 的权限面子树在 ${checked.bad} 处不是 JSON 可摊全的载体 —— ` +
@@ -612,22 +327,13 @@ const resolvedSnapshotForWire = (resolved) => {
612
327
  '而权限面丢一条 = 会话权限静默变宽。合法载体 = 对象字面量 / 数组 / JSON 原始值(有限数)。' +
613
328
  '错误文本只报路径与形,不回显内容。');
614
329
  }
615
- // 出门的是重建那一份(不是原引用):端此后再动原对象、或原对象上挂着访问器,都影响不到已
616
- // 提交的这份请求体。合法输入的字节与修前逐字相同(重建只丢 stringify 本来就会丢的东西)。
617
330
  out[k] = checked.value;
618
331
  continue;
619
332
  }
620
- // 🔴 函数值一律不进(#292 P1 对抗复审第三轮 [medium] 采纳):JSON wire 上没有函数,而一个
621
- // **自有 `toJSON`** 会在序列化那一刻整只改写 `settings` 的字节 —— 实测
622
- // `resolved={permissions:…, toJSON(){return {ultracode:true}}}` 能让 `JSON.stringify(req)` 出
623
- // `settings:{ultracode:true}`,把上面那道车道剥离(以及一切按对象查的判据)整体绕过。
624
- // 「真上 wire 的那份」= 序列化后的字节,所以过滤必须发生在**值**这一层,而不是只看键名。
625
- // (权限面**不**走这条:静默丢弃在那一位上是权限变宽,见上面那臂。)
626
333
  if (typeof v === 'function')
627
334
  continue;
628
335
  out[k] = v;
629
336
  }
630
- // 内容都取走之后才校外层载体的形(见上面那条红线:这一读可能带副作用,不许排在捕获之前)。
631
337
  if (!isPlainRecord(resolved)) {
632
338
  throw new TypeError(`buildTaskRequest: settings.resolved 只接受 plain object 或缺席(undefined/null)—— 收到 ${shapeTag(resolved)}。` +
633
339
  '这一位摊开的是已解析权限面(permissions.deny/ask 等子键即 wire 键):把畸形值降成空对象' +
@@ -636,86 +342,17 @@ const resolvedSnapshotForWire = (resolved) => {
636
342
  }
637
343
  return out;
638
344
  };
639
- /**
640
- * 合一后的请求构造器 —— **按车道出两形**,字段集差异全部由 `REQUEST_FIELD_MATRIX` 决定。
641
- *
642
- * 🔴 行为纪律:本函数**不做任何统一**。print 没有 `ultracode` 就是没有(表里 `gap:true` 记着账),
643
- * 补齐要另立项 —— 在这里顺手加一行,就是把「合一」偷换成「行为改动」。
644
- */
645
- /**
646
- * ⑤ 的**响亮拒**([7226] 包侧缺口 ⑤;异源对抗复审轮五 finding① 采纳)。
647
- *
648
- * 🔴 修前这里是「不是 `'off'` 就整键不 stamp」——**静默删键**,而删掉的恰是一条**隐私声明**:
649
- * 一个把 `/memory-capture off` 打成 `OFF` 的会话,请求照发、引擎照常采集,**没有任何人会知道**。
650
- * 🔴 上游把这条写死了(装机 core `dist/core/memory.d.ts` 的 `capture?: "off"` 头注**逐字**):
651
- * 「Any other value — `"on"`, `"OFF"`, booleans, garbage — is REFUSED loudly
652
- * (`config.memory_capture_spelling`), never read as either state (**a privacy request must not be
653
- * dropped by a typo**, and capture must not be switched off by one either)」;server 契约 §12.4
654
- * 同样写明坏拼写 400 `request.field_invalid`,并点名「把一条隐私请求按打字错误静默丢掉恰是**禁的方向**」。
655
- * ⇒ 提前删键 = 把上游那道响亮门**绕过去**,方向正好反了。
656
- * 🔴 与本文件 `resolvedSnapshotForWire` 对畸形权限快照的处置**同一条纪律**(那里也是抛,理由逐字
657
- * 是「降空 = 让请求带着被剥掉的权限面发出去」)——两处都是**声明方向**的位:丢了没人看得见。
658
- * ⚠️ `undefined` / `null` = **合法缺席**(端没有这个入口 / 没有声明),照旧不 stamp,不拒。
659
- * ⚠️ **不分车道、不受 live 门**:拒绝不是「stamp 一个键」,不改请求形状;而一条打错字的隐私声明
660
- * 在哪条车道上都不该被默默放行。
661
- * (本包是发出去的 npm 公开面:JS 调用方与版本偏斜的宿主都到得了这里,型面拦不住。)
662
- */
663
- /**
664
- * wire 上那个**单成员闭集**的唯一字面(server §12.4)。导出它是为了让端的断言/门有一个机读锚,
665
- * 🔴 **不是**为了让端拿它去自己拼请求 —— 拼请求走 {@link memoryCaptureDeclarationField}。
666
- */
667
345
  export const MEMORY_CAPTURE_OFF = 'off';
668
- /**
669
- * 「本会话声明过 opt-out 没有」这个**意图位** → 提交腿的 spread-ready 片段(L-316,0.68.2)。
670
- *
671
- * ── 为什么这一只在包里(归层,不是搬家)────────────────────────────────────────────────────
672
- * 端手里只有一个**布尔**:「这条会话敲过 `/memory-capture off` 没有」。而 wire 上那个值是
673
- * **单成员闭集**的一个字面串 —— 谁铸这个串,谁就得同时承担「拼错了会被 400 响亮拒、而且这是
674
- * 一条**隐私**声明、拼错即静默失效」这件事。cli 1.0.x 起这个串在壳里另有一处铸点
675
- * (`memoryCaptureOptOut.memoryCaptureRequestField`),web / desktop 接这条腿时会各铸第三、第四处
676
- * —— 三端各写一个字面量,正是本层存在的理由(与 `taskNotificationToPrintFrame` 同一条先例)。
677
- * ⇒ 端交**意图位**,值由本层唯一铸出;拼写门与 {@link buildTaskRequest} 的响亮拒共用同一个字面。
678
- *
679
- * 🔴 **`false` ⇒ 整键缺席**,不是 `{ memoryCapture: undefined }`、更不是某个「on」值:wire 上
680
- * 压根没有那个值(单成员闭集),**缺席就是「照常采集」的唯一写法**。所以未启用时本片段对
681
- * wire 字节零影响。
682
- * 🔴 **本层只答「下一条提交带不带这一键」,不答「采集关没关」**:后者只有引擎知道(老 worker
683
- * 静默忽略本键 / 部署策略 403 / 控制面写失败),任何端都不许拿这一位去渲一句「已经关了」。
684
- *
685
- * 用法(端逐字照抄,别在外面再包一层字面量):
686
- * ```ts
687
- * buildTaskRequest({ …, ...memoryCaptureDeclarationField(declaredForThisSession) }, 'interactive')
688
- * ```
689
- */
690
346
  export function memoryCaptureDeclarationField(declared) {
691
347
  return declared ? { memoryCapture: MEMORY_CAPTURE_OFF } : {};
692
348
  }
693
- /** `memory: "off"` 的唯一字面(server §12.7;core #863 W3)。 */
694
349
  export const MEMORY_OFF = 'off';
695
- /**
696
- * 「这一次别给我记忆」的**意图位** → 提交腿的 spread-ready 片段(CC-39③,0.72.8;与 {@link memoryCaptureDeclarationField} 同律)。
697
- * 🔴 `false` ⇒ 整键缺席(= 记忆照常挂的唯一写法),不是 `{ memory: undefined }`、更不是某个「on」值。
698
- * 🔴 本层只答「下一条提交带不带这一键」,不答「这次真的没挂记忆面」:后者只有引擎知道(老 server 400 / 更老 worker 静默忽略);
699
- * 终局 memory 状态词 `disabled`(不是 `no-spec`)才是引擎的答案,端别拿这一位去渲「已关」。
700
- * 🔴 两键同发(`memoryCapture:"off"` + `memory:"off"`)时 capture 的单向记录**不落**(core 只在挂引擎时记)—— 契约 §12.7 写真话,
701
- * 不许拿 `memory:"off"` 当隐私声明;要「别记住我」用 memoryCapture 那一键。
702
- */
703
350
  export function memoryOffDeclarationField(declared) {
704
351
  return declared ? { memory: MEMORY_OFF } : {};
705
352
  }
706
- /**
707
- * 端的两个入口 → 「这一次别给我记忆」的**意图位**(cli [7510]:发口投影归包,三端同判、壳零自判)。
708
- * · `flag`:CLI 旗 `--memory <word>` 的原词 —— **只认恰 `'off'`**(单成员闭集;`'on'` / 大小写 / 带空格一律不认,
709
- * 那些拼法上 wire 会被 server 400,而本层不替它买路也不替它编);
710
- * · `settingsMemory`:settings 的 CC 形 `memory` 段 —— **只认严格 `{ enabled: false }`**(`"false"` / `0` / 缺席 = 沉默不是关,
711
- * 与 core `ParentSpecSeat.memoryOff` 只从显式 `enabled: false` 铸同律)。
712
- * 任一成立 ⇒ `true`;其余 / 坏形 / 非对象入参 ⇒ `false`(= 键缺席,记忆照常挂)。喂给 {@link memoryOffDeclarationField}。
713
- */
714
353
  export function memoryOffDeclared(input) {
715
354
  if (typeof input !== 'object' || input === null)
716
355
  return false;
717
- // 🔴 异源对抗复审 [medium] 真修:入口投影**不许**把打错字的收紧声明降级成「缺席」—— 那样片段函数删键、`refuseBadMemoryOff`
718
- // 无从校验,用户以为关了、这次运行照常挂上记忆面。旗在场但不是 'off' ⇒ 响亮拒(与 buildTaskRequest 同律,不回显值)。
719
356
  const flag = input.flag;
720
357
  if (flag !== undefined && flag !== null && flag !== MEMORY_OFF) {
721
358
  throw new TypeError(`memoryOffDeclared: --memory 旗只接受字面量 \'off\' 或缺席 —— 收到 ${coarseShape(flag)}。上游是单成员闭集(没有 "on"),` +
@@ -728,7 +365,6 @@ export function memoryOffDeclared(input) {
728
365
  throw new TypeError(`memoryOffDeclared: settings 的 memory 段必须是对象 —— 收到 ${coarseShape(sm)}。`);
729
366
  }
730
367
  const enabled = sm.enabled;
731
- // CC 形 `memory: { enabled }`:缺席 = 沉默(不是关);在场必须是布尔 —— "false" / 0 是打错字的收紧声明,同样响亮拒。
732
368
  if (enabled !== undefined && typeof enabled !== 'boolean') {
733
369
  throw new TypeError(`memoryOffDeclared: settings memory.enabled 在场时必须是布尔 —— 收到 ${coarseShape(enabled)}。`);
734
370
  }
@@ -746,6 +382,13 @@ const refuseBadMemoryOff = (v) => {
746
382
  '`"on"`,`{ enabled: false }` 对象形也不是 wire 拼法)且对坏拼写**响亮拒**(server 400 `request.field_invalid`)。' +
747
383
  '本层若静默删键,这一次运行会照常挂上记忆面而声明人不会知道 —— 与 memoryCapture 同一条纪律。错误文本只报形状,不回显值。');
748
384
  };
385
+ const refuseBadExcludeAllTools = (v) => {
386
+ if (v === undefined || v === null || v === true || v === false)
387
+ return;
388
+ throw new TypeError('buildTaskRequest: excludeAllTools 只接受字面量 `true`(`false` / 缺席 = 不卸载)—— ' +
389
+ `收到 ${coarseShape(v)}。这一位是**整只工具面卸载**的收紧声明:本层若把坏值静默删键,这一次运行会挂上声明人以为已经卸掉的全部工具。` +
390
+ '错误文本只报形状,不回显值。');
391
+ };
749
392
  const refuseBadMemoryCapture = (v) => {
750
393
  if (v === undefined || v === null)
751
394
  return;
@@ -758,17 +401,6 @@ const refuseBadMemoryCapture = (v) => {
758
401
  '而声明人不会知道自己的 opt-out 丢了 —— 把一条隐私请求按打字错误静默丢掉是**禁的方向**。' +
759
402
  '错误文本只报形状,不回显值。');
760
403
  };
761
- /**
762
- * `maxCostUsd` 的**响亮拒**(0.77.0)。
763
- *
764
- * 🔴 这一位是**收紧方向**的声明(「这一次最多花这么多」),而上游对它的坏值**不是** 4xx:非数 / 非正一律按
765
- * 「调用方没给」处理、回落到部署上限 —— 部署没设上限时 = 这一次运行**没有花费闸**。一个把 `--max-budget-usd 5`
766
- * 原样当字符串 `"5"` 递进来的端,请求照发、运行照跑、上限无声消失,没有任何人会知道。
767
- * ⇒ 本层是这条声明最后一处能响的地方(与 `memoryCapture` 坏拼写同一条纪律:收紧声明不许被打字错误安静丢掉)。
768
- * ⚠️ 判据只有「**有限正数**」这一条,是上游自己的接受域(`typeof === 'number' && > 0`)再去掉序列化不了的
769
- * `Infinity`(JSON 里是 `null`,到上游同样被当成没给)—— 不猜上限、不预夹:向下夹到部署上限是上游的事。
770
- * ⚠️ `undefined` / `null` = 合法缺席。与 `memoryCapture` 同律**不分车道、不受 live 门**:拒绝不是「盖一个键」。
771
- */
772
404
  const refuseBadMaxCostUsd = (v) => {
773
405
  if (v === undefined || v === null)
774
406
  return;
@@ -778,34 +410,8 @@ const refuseBadMaxCostUsd = (v) => {
778
410
  '这一位是花费上限声明(收紧方向),而上游对坏值(非数 / 非正)不是 4xx,是按「没给」处理并回落部署上限:' +
779
411
  '部署没设上限时这一次运行就没有花费闸,而声明人不会知道。数字串请先在端侧解析成数。错误文本只报形状,不回显值。');
780
412
  };
781
- /**
782
- * **装配口**(0.77.0):请求体 + 逐键回执,同一次装配、同一只判官。
783
- *
784
- * 与 {@link buildTaskRequest} 的关系:后者**就是**本函数的 `.request`(一行转调)—— 两个口不可能装出两份
785
- * 不同的请求体。要知道「我给的键这一次到底发没发」的端用本口;只要请求体的端两个口随意。
786
- *
787
- * 🔴 两个口的**拒绝面完全相同**(拒绝发生在装配里,不在回执里):
788
- * · 表外的车道词 ⇒ `TypeError`;
789
- * · 入参(或 `settings`)上**在场**的、本包不认识的键 ⇒ `TypeError`,点名键名(值为 `undefined` / `null` 的键
790
- * = 缺席,不算);
791
- * · `settings` 在场却不是对象 ⇒ `TypeError`;
792
- * · `memoryCapture` / `memory` 坏拼写、`maxCostUsd` 坏值、畸形权限快照 ⇒ `TypeError`(各见其注)。
793
- * 🔴 入参的每个已知键**恰读一次**,装配与回执共用那一份快照:带 getter / proxy 的入参在两次读取之间可以变值,
794
- * 那样回执说的与请求体带的就可以不是同一件事(`memoryCapture` 那条「校验与 stamp 共用同一次读取」的推广)。
795
- */
796
413
  export function assembleTaskRequest(input, lane) {
797
414
  refuseBadLane(lane);
798
- // ── 读序纪律:声明位先读、权限面先物化,然后才碰入参上任何别的键 ────────────────────────────────────
799
- // 🔴 调用方可执行属性(getter / Proxy)之间可以互相改写,而快照存的是**引用**不是内容:
800
- // · 两个记忆声明是**原始值**,读走就改不了 —— 所以它们排在一切之前(修前 0.76.x 就是这个次序);
801
- // · `resolved` 是对象,物化之前跑过的任何一个 getter(`settings.webSearch` / 顶层任意键 / 不在场的 stray 键)都能把
802
- // `resolved.permissions.deny` 就地清空,请求体照发 `deny: []`、回执 `[]` —— 所以它紧随其后物化;
803
- // · `maxCostUsd`(本版新键)排在物化之后、其余键之前:它与权限面不能同时排第一,权限变宽比花费闸丢失更坏,
804
- // 于是只有 settings 容器 / resolved 上的 getter 还能在读到它之前动它 —— 这是**明写的取舍**,不是遗漏;
805
- // · 其余已知键一次性快照(每键恰一次),unknown 键检测与三条值拒绝都在这些读取之后。
806
- // 修前的相对次序(live → 两记忆键 → settings → 物化 → 其余)一条不变,权限面只比修前更早。
807
- // (异源复审 R1 [high] / R2 [high] 各实撞一条:把「其余键」的读取排到物化 / 记忆声明之前,就是本包自己引入的
808
- // 权限放宽 / 隐私声明丢失路径 —— 两条门 F12 / F17 钉着。)
809
415
  const live = input.live;
810
416
  const memoryCaptureIn = input.memoryCapture;
811
417
  const memoryIn = input.memory;
@@ -816,31 +422,26 @@ export function assembleTaskRequest(input, lane) {
816
422
  }
817
423
  const settingsObj = present(settingsIn) ? settingsIn : {};
818
424
  const resolvedIn = settingsObj.resolved;
819
- // resolved 两车道都进表(#292 P1)——它是**开放集 spread**(子键即 wire 键):值缺席时照旧过一遍
820
- // `resolvedSnapshotForWire`(它对 undefined/null 返回空对象),所以这里问的是「车道 + live」而不是「值在场」。
821
425
  const resolvedRoute = SETTINGS_KEY_ROUTES.resolved;
822
426
  const resolvedOpen = resolvedRoute.via === 'matrix' && omissionCauseOf(standingOf(resolvedRoute), lane, live) === undefined;
823
427
  const resolvedWire = resolvedOpen ? resolvedSnapshotForWire(resolvedIn) : {};
824
428
  const maxCostUsdIn = input.maxCostUsd;
825
- // ── 其余已知键一次性快照(已读过的位用种子,不读第二次;按名读 = 与修前同一种读法)────────────────
429
+ const excludeAllToolsIn = input.excludeAllTools;
826
430
  const INPUT_KEYS = Object.keys(INPUT_KEY_ROUTES);
827
431
  const i = snapshotByName(input, INPUT_KEYS, {
828
432
  live,
829
433
  memoryCapture: memoryCaptureIn,
830
434
  memory: memoryIn,
831
435
  maxCostUsd: maxCostUsdIn,
436
+ excludeAllTools: excludeAllToolsIn,
832
437
  settings: settingsIn,
833
438
  });
834
439
  const SETTINGS_KEYS = Object.keys(SETTINGS_KEY_ROUTES);
835
440
  const s = snapshotByName(settingsObj, SETTINGS_KEYS, { resolved: resolvedIn });
836
- // ⑤ 响亮拒:一条打错字的隐私声明绝不许被后面任何一条「不 stamp」路径吞掉。校验与 stamp 用的是上面同一次读取。
837
441
  refuseBadMemoryCapture(memoryCaptureIn);
838
442
  refuseBadMemoryOff(memoryIn);
839
443
  refuseBadMaxCostUsd(maxCostUsdIn);
840
- // ── rewind 合写项:四个具名键按名投影,不整只展开 ──────────────────────────────────────────────────
841
- // 🔴 修前 `...input.rewind` 整只展开:一个 `rewind: { maxCostUsd: 2 }` 能把回执说「没带」的键塞上请求体、
842
- // 还覆盖同名顶层键、绕过该键的坏值门;`rewind: 'abc'` 会把下标键摊上 wire。四个键名取自车道表那一行的
843
- // 合写字段名(`resumeAt/resumeAtMode/rewindFiles/rewindFilesTo`),不另抄一份。
444
+ refuseBadExcludeAllTools(excludeAllToolsIn);
844
445
  const rewindRoute = INPUT_KEY_ROUTES.rewind;
845
446
  const REWIND_KEYS = rewindRoute.via === 'matrix' ? rewindRoute.field.split('/') : [];
846
447
  const rewindIn = i.rewind;
@@ -849,8 +450,6 @@ export function assembleTaskRequest(input, lane) {
849
450
  '它是四个具名请求键(resumeAt / resumeAtMode / rewindFiles / rewindFilesTo)的合写位,不是任意展开口。错误文本只报形状,不回显值。');
850
451
  }
851
452
  const rewindObj = present(rewindIn) ? rewindIn : {};
852
- // 🔴 四子键**在这里恰读一次**(0.77.1 CC-108,外部验收 [7810]):快照之后,值级谓词与 stamp 都只看 `rewindWire`
853
- // 这份普通数据 —— 此前谓词的 `.some` 与投影循环各读一次,非幂等子键访问器两向静默丢且回执不报。
854
453
  const rewindWire = {};
855
454
  for (const k of REWIND_KEYS) {
856
455
  if (!hasOwn(rewindObj, k))
@@ -859,9 +458,7 @@ export function assembleTaskRequest(input, lane) {
859
458
  if (present(v))
860
459
  rewindWire[k] = v;
861
460
  }
862
- /** 喂给 stamp 门的 `rewind` 值:缺席原样(undefined / null),在场则是已快照的四子键副本(不再碰入参访问器)。 */
863
461
  const rewindForGate = present(rewindIn) ? rewindWire : rewindIn;
864
- // ── (乙) 不认识的键:响亮拒(理由见本节头注;只看**在场**的自有可枚举键)──────────────────────────
865
462
  const omitted = [];
866
463
  const omit = (key, cause) => {
867
464
  omitted.push(Object.freeze({ key, cause }));
@@ -879,7 +476,6 @@ export function assembleTaskRequest(input, lane) {
879
476
  unknownKeys.push(key);
880
477
  continue;
881
478
  }
882
- // 入参型之外、但本包认识的键今天只有一类:live 兜底层的位(`cwd` / `appendSystemPrompt` / …)。成因照样问判官,不在这里另写一个词。
883
479
  if (route.via !== 'matrix' && route.via !== 'fixed')
884
480
  continue;
885
481
  const cause = omissionCauseOf(standingOf(route), lane, live);
@@ -912,7 +508,6 @@ export function assembleTaskRequest(input, lane) {
912
508
  '想问某个键有没有座 ⇒ taskRequestSeatOf(key, lane)。`settings` 快照里的开放集子键放进 settings.resolved。' +
913
509
  '错误文本只报键名,不回显值。');
914
510
  }
915
- /** stamp 门:本键在场 ∧ 判官说带。🔴 先问判官再看值 —— 表漂(`matrixRow` 抛)因此每次装配都响,不挑输入。 */
916
511
  const carries = (route, value, key) => {
917
512
  if (route.via === 'always')
918
513
  return present(value);
@@ -926,7 +521,6 @@ export function assembleTaskRequest(input, lane) {
926
521
  omit(key, cause);
927
522
  return false;
928
523
  };
929
- // 每个键的门**只问一次**(问一次记一次回执),装配处只读结果 —— 回执行数 = 被拒的在场键数,不多不少。
930
524
  const gate = Object.create(null);
931
525
  for (const key of INPUT_KEYS) {
932
526
  const route = INPUT_KEY_ROUTES[key];
@@ -939,12 +533,6 @@ export function assembleTaskRequest(input, lane) {
939
533
  }
940
534
  const on = (key) => gate[key] === true;
941
535
  const onSetting = (sub) => gate[`settings.${sub}`] === true;
942
- // settings 四源合并(cli 原式:任一存在则 stamp,全缺则整个 `settings` 键都不出现)。
943
- // ultracode 只在交互车道进表 ⇒ print 传了也不 stamp(表说了算,不是调用方说了算)。
944
- // 🔴 具名通道**赢过快照**这件事不靠下面的合并序(0.35.0):合并序只在具名通道**有值**时管用,
945
- // 而具名门否决时的表现恰恰是**没值**(端不给这个键)。让位改由 `resolvedSnapshotForWire`
946
- // 做**结构剥离** —— 具名通道管着的子键快照一概不产,顺序此后只是可读性,不再是安全依据。
947
- // (那一份快照在本函数开头就物化好了 —— `resolvedWire`,读序理由见那里。)
948
536
  const settingsOut = {
949
537
  ...resolvedWire,
950
538
  ...(onSetting('webSearch') ? { webSearch: s.webSearch } : {}),
@@ -971,49 +559,31 @@ export function assembleTaskRequest(input, lane) {
971
559
  ...(on('promptProfile') ? { promptProfile: i.promptProfile } : {}),
972
560
  ...(on('enableFork') ? { enableFork: i.enableFork } : {}),
973
561
  ...(on('attachments') ? { attachments: i.attachments } : {}),
974
- // repo 场景五键([C135]):值级判据(council/debate 非 true 不 stamp,与 server `=== true` 读法合拍——
975
- // false 与缺席在 wire 上同义,发小的那个)已折进 `VALUE_LEVEL_IN_PLAY`,门 `on()` 一并判过。
976
562
  ...(on('repo') ? { repo: i.repo } : {}),
977
563
  ...(on('council') ? { council: true } : {}),
978
564
  ...(on('debate') ? { debate: true } : {}),
979
565
  ...(on('rounds') ? { rounds: i.rounds } : {}),
980
566
  ...(on('lenses') ? { lenses: i.lenses } : {}),
981
- // 空数组语义(没带附件与「带了 0 个附件」同义,发小的那个)在 `VALUE_LEVEL_IN_PLAY` 里,门一并判过。
982
567
  ...(on('attachmentIds') ? { attachmentIds: [...(i.attachmentIds ?? [])] } : {}),
983
- // 「不排除任何工具」同款空数组语义,同上。
984
568
  ...(on('excludeTools') ? { excludeTools: [...(i.excludeTools ?? [])] } : {}),
569
+ ...(on('excludeAllTools') ? { excludeAllTools: true } : {}),
985
570
  ...(on('clientContext') ? { clientContext: i.clientContext } : {}),
986
571
  ...(on('scratchpadDir') ? { scratchpadDir: i.scratchpadDir } : {}),
987
572
  ...(on('finalVerification') ? { finalVerification: i.finalVerification } : {}),
988
573
  ...(on('limits') ? { limits: i.limits } : {}),
989
574
  ...(on('interactiveTools') ? { interactiveTools: false } : {}),
990
575
  ...(on('oneShot') ? { oneShot: true } : {}),
991
- // 0.77.0 print 补座两件(原样透传;`maxCostUsd` 的坏值已在上面响亮拒)。
992
576
  ...(on('outputSchema') ? { outputSchema: i.outputSchema } : {}),
993
577
  ...(on('maxCostUsd') ? { maxCostUsd: maxCostUsdIn } : {}),
994
- // ⑤ 单成员闭集:值**恰是** `'off'` 才 stamp。表外拼写在上面已经**响亮拒**(见 `refuseBadMemoryCapture`)。
995
578
  ...(on('memoryCapture') ? { memoryCapture: 'off' } : {}),
996
- // CC-39③:姊妹键同律(值恰是 'off' 才 stamp;坏拼写已在上面响亮拒)。
997
579
  ...(on('memory') ? { memory: 'off' } : {}),
998
580
  ...(Object.keys(settingsOut).length > 0 ? { settings: settingsOut } : {}),
999
581
  };
1000
582
  return Object.freeze({ request: out, omitted: Object.freeze([...omitted, ...lateOmitted]) });
1001
583
  }
1002
- /**
1003
- * 只要请求体的口 —— **就是** {@link assembleTaskRequest} 的 `.request`(拒绝面完全相同,见那里的头注)。
1004
- * ⚠️ 本口没有回执通道:认识而没带的键(车道不符 / live 门没开 / 上游无对位)在这里照旧没有信号。要逐键答案
1005
- * 用装配口;要在不装配的情况下问一个键有没有座用 {@link taskRequestSeatOf}。
1006
- */
1007
584
  export function buildTaskRequest(input, lane) {
1008
585
  return assembleTaskRequest(input, lane).request;
1009
586
  }
1010
- /**
1011
- * live 兜底层(cli `liveClient.toLiveRequest` 的**包内半场**)—— 两条车道共用。
1012
- *
1013
- * 🔴 与 cli 的差分记账:cli 版在函数体里直接读 `process.cwd()` / `getAppStateStoreRef()` /
1014
- * `getLiveModelCatalog()` / `engineCapTrue()`。这些是**取值方式**,全部上移到 `LiveDefaultsInput`。
1015
- * 「调用方已带值就不覆盖」的语义(cli 每条都是 `if (out.X === undefined)`)在这里逐条保留。
1016
- */
1017
587
  export function applyLiveRequestDefaults(req, host) {
1018
588
  const out = { ...req };
1019
589
  if (out.cwd == null && host.cwd !== undefined)
@@ -1021,14 +591,9 @@ export function applyLiveRequestDefaults(req, host) {
1021
591
  if (out.additionalDirectories === undefined && (host.additionalDirectories?.length ?? 0) > 0) {
1022
592
  out.additionalDirectories = [...(host.additionalDirectories ?? [])];
1023
593
  }
1024
- // A-028.9:只读面宽根(壳 cli 逐字:`if (roots.length > 0) out.additionalReadDirectories = roots`,
1025
- // 「已带值不覆盖」的守卫同其余各条)。
1026
594
  if (out.additionalReadDirectories === undefined && (host.additionalReadDirectories?.length ?? 0) > 0) {
1027
595
  out.additionalReadDirectories = [...(host.additionalReadDirectories ?? [])];
1028
596
  }
1029
- // C1 / design/144:交互与 headless 都常开 —— 不开则引擎不建 SubagentRetainLedger,
1030
- // 后台子代 SendMessage 唤醒直接 "session was not retained" 拒绝。老引擎按 body→spec 白名单
1031
- // 忽略未知字段,version-safe。
1032
597
  if (out.forwardSubagentEvents === undefined)
1033
598
  out.forwardSubagentEvents = true;
1034
599
  if (out.retainSubagentSessions === undefined)
@@ -1038,8 +603,6 @@ export function applyLiveRequestDefaults(req, host) {
1038
603
  if (typeof out.scenario === 'string' && host.mockScenarioKeys?.has(out.scenario)) {
1039
604
  delete out.scenario;
1040
605
  }
1041
- // 自我认知块双臂([1487]/[1478] R1 终形):caps 判真走一等位,否则借道 outputStyle。
1042
- // 两臂同一合并序(知识块恒前、调用方块恒后)——序由端在 selfKnowledge 里拼好,包只选位。
1043
606
  if (host.selfKnowledge !== undefined) {
1044
607
  if (host.appendSystemPromptCapable) {
1045
608
  out.appendSystemPrompt = host.selfKnowledge.forAppend;
@@ -1049,7 +612,6 @@ export function applyLiveRequestDefaults(req, host) {
1049
612
  out.settings = { ...settings, outputStyle: host.selfKnowledge.forOutputStyle };
1050
613
  }
1051
614
  }
1052
- // E12:与 verify/cascade 互斥(那两个返 result 非 streamed run ⇒ 400)。
1053
615
  if (out.suggestNextPrompts === undefined &&
1054
616
  out.verify === undefined &&
1055
617
  out.cascade === undefined &&
@@ -1059,8 +621,6 @@ export function applyLiveRequestDefaults(req, host) {
1059
621
  if (out.compactionModel === undefined && host.compactionModel !== undefined) {
1060
622
  out.compactionModel = host.compactionModel;
1061
623
  }
1062
- // 单命名空间三态(cli 逐字):① 已捕获的引擎 session 赢(连续性 —— 引擎 session 绝不在
1063
- // 会话中途被换掉);③ 还带着 mock 常量 ⇒ 删掉让引擎新铸;② 其余保留(首 turn 壳 id 直传)。
1064
624
  if (host.capturedSessionId) {
1065
625
  out.sessionId = host.capturedSessionId;
1066
626
  }
@@ -1070,35 +630,9 @@ export function applyLiveRequestDefaults(req, host) {
1070
630
  }
1071
631
  return out;
1072
632
  }
1073
- /**
1074
- * ⇄ B8(§8-5 请求拼装合一的**可执行判据**)—— 一份请求体里出现了**没进车道表**的键就点名它。
1075
- *
1076
- * 为什么要有:B4 把字段集做成了 `REQUEST_FIELD_MATRIX` 这张表,但表当时只管住了
1077
- * `buildTaskRequest` 自己;端上真正上 wire 的那份请求仍可以在构造器之外多塞一个键(print lane
1078
- * 修前正是「自己另拼一份」),于是「表说了算」就退化成一句注释。本函数让**真上 wire 的那份**
1079
- * 也过一遍表:print lane 收编之后,`-p` 的请求体逐键都能报出登记出处,再漏就当场红。
1080
- *
1081
- * 判据口径(三类不点名):
1082
- * ① 车道表里的字段(`lanes` 含本车道);② `LIVE_DEFAULT_FIELDS` —— live 兜底层追加、两条车道
1083
- * 都经过,故本就不进车道表;③ `settings` 的子键按表认(`settings.<sub>`)—— 登记了
1084
- * `settings.<resolved>` 的车道(#292 P1 起 = **两条**)那份 resolver effective 快照是**开放集**,
1085
- * 所以**表外**子键(permissions/env/model/… 不可枚举)放行。
1086
- *
1087
- * 🔴 开放集**不是**整只 `settings` 免检(#292 P1 对抗复审第二轮 [medium] 采纳):表里点名了、
1088
- * 而 lanes 不含本车道的子键(如 print 车道的 `settings.ultracode`)照旧**点名** —— 那些键是
1089
- * **可枚举的已知量**,放过它们等于让「ultracode 仅 interactive」这条登记在真 wire 面失效。
1090
- * `buildTaskRequest` 内的 `resolvedSnapshotForWire` 只管住构造器自己那一份;端在构造之后仍能往请求体上
1091
- * 塞键(print lane 修前正是「自己另拼一份」),而本函数的整个存在理由就是替**真上 wire 的那份**
1092
- * 过表。两道门缺一不可。
1093
- *
1094
- * 🔴 它**不判**「该不该有」——只判「有没有登记」。补齐一条真实差异要改表(带理由),
1095
- * 而不是绕过本函数:改表这个动作本身就会在 diff 里显形,这正是本判据存在的意义。
1096
- */
1097
633
  export function unregisteredRequestKeys(req, lane) {
1098
- /** live 兜底层的键名(表项写法含 `|` 备选位与括号说明,取裸键名;与装配口同读一只解析)。 */
1099
634
  const liveDefaults = liveDefaultKeyNames();
1100
635
  const laneRows = REQUEST_FIELD_MATRIX.filter(f => f.lanes.includes(lane));
1101
- /** 顶层键 → 表项(`resumeAt/resumeAtMode/rewindFiles/rewindFilesTo` 这类斜杠合写项逐键展开)。 */
1102
636
  const laneTopKeys = new Set();
1103
637
  for (const row of laneRows) {
1104
638
  if (row.field.startsWith('settings.'))
@@ -1110,7 +644,6 @@ export function unregisteredRequestKeys(req, lane) {
1110
644
  .filter(f => f.field.startsWith('settings.') && f.field !== 'settings.<resolved>')
1111
645
  .map(f => f.field.slice('settings.'.length)));
1112
646
  const settingsIsOpenSet = laneRows.some(f => f.field === 'settings.<resolved>');
1113
- /** 表里点名了、但 lanes 不含本车道的具名子键 —— 开放集车道也照旧点名(见头注第二条红线)。 */
1114
647
  const foreignSettingsKeys = new Set(foreignSettingsSubKeys(lane));
1115
648
  const out = [];
1116
649
  for (const key of Object.keys(req)) {
@@ -1118,28 +651,17 @@ export function unregisteredRequestKeys(req, lane) {
1118
651
  const settings = req.settings;
1119
652
  if (settings === null || typeof settings !== 'object')
1120
653
  continue;
1121
- // 🔴 自报会改写自己字节的 `settings` 一律点名(#292 P1 复审第四轮的可采部分):`JSON.stringify`
1122
- // 找 `toJSON` 走的是**属性查找**(原型链上的、非枚举的都算),而下面的逐键遍历只看**可枚举自有**
1123
- // 键 ⇒ 一个挂在原型上的 `toJSON` 能让本函数看到一份对象、wire 上却是另一份字节。本函数的承诺
1124
- // 是「替真上 wire 的那份过表」,所以这种「对象与字节不一致」的形必须先被点名,而不是默默通过。
1125
- // (⚠️ 递归深净化整份请求体不在本层的职责里 —— 那是包级 wire 载荷 JSON-safe 规范化的设计题,
1126
- // 今天对 agents/hooks/attachments 等一切对象位一样成立,已登记为独立工单;端是同进程受信调用方,
1127
- // 这里做的是「判据不许被骗」,不是「防御受信宿主」。)
1128
654
  if (typeof settings.toJSON === 'function')
1129
655
  out.push('settings.toJSON');
1130
656
  for (const [sub, value] of Object.entries(settings)) {
1131
657
  if (sub === 'toJSON')
1132
- continue; // 上面那条属性查找已点过名(可枚举自有形不重复报)
1133
- // 🔴 函数值恒点名(复审第三轮 [medium]):wire 上没有函数,而自有 `toJSON` 会在序列化时
1134
- // 整只改写 `settings` 的字节 ⇒ 一切「按对象查键」的判据(含本函数)都会被它骗过。所以它
1135
- // 先于任何登记判断被点名 —— 包括登记在册的子键名上挂了函数值的形。
658
+ continue;
1136
659
  if (typeof value === 'function') {
1137
660
  out.push(`settings.${sub}`);
1138
661
  continue;
1139
662
  }
1140
663
  if (laneSettingsKeys.has(sub) || liveDefaults.has(`settings.${sub}`))
1141
664
  continue;
1142
- // 开放集车道:表外子键放行(快照的键不可枚举),表内异车道子键仍点名。
1143
665
  if (settingsIsOpenSet && !foreignSettingsKeys.has(sub))
1144
666
  continue;
1145
667
  out.push(`settings.${sub}`);