@sema-agent/client-core 0.107.0 → 0.108.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 +118 -0
- package/README.md +19 -14
- package/dist/adapter/activeRunSelfHeal.d.ts +2 -0
- package/dist/adapter/activeRunSelfHeal.js +20 -3
- package/dist/checkpointRowVerdict.d.ts +5 -0
- package/dist/checkpointRowVerdict.js +26 -0
- package/dist/cloudConfigWireCaps.d.ts +10 -0
- package/dist/cloudConfigWireCaps.js +33 -0
- package/dist/coreValuePorts.d.ts +17 -1
- package/dist/coreValuePorts.js +5 -0
- package/dist/decideReceipt.js +2 -1
- package/dist/engineErrorCodes.d.ts +5 -0
- package/dist/engineErrorCodes.js +5 -0
- package/dist/engineNoticeCodes.d.ts +19 -1
- package/dist/engineNoticeCodes.js +65 -3
- package/dist/engineTargetSeat.js +1 -0
- package/dist/errorSupplementRoles.js +2 -0
- package/dist/eventLeg.js +1 -1
- package/dist/executionLaneWords.js +2 -1
- package/dist/gateOutcome.d.ts +10 -1
- package/dist/gateOutcome.js +48 -1
- package/dist/generated/engineFactTables.d.ts +1 -0
- package/dist/generated/engineFactTables.js +5 -0
- package/dist/generated/engineNoticeTables.js +3 -0
- package/dist/generated/settingsSchemaFns.d.ts +4 -2
- package/dist/generated/settingsSchemaFns.js +9 -3
- package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -1
- package/dist/generated/settingsSchemaMcpRequestEntry.js +9 -18
- package/dist/generated/settingsSchemaReservedMemberName.d.ts +1 -0
- package/dist/generated/settingsSchemaReservedMemberName.js +7 -0
- package/dist/generated/settingsSchemaTables.d.ts +2 -0
- package/dist/generated/settingsSchemaTables.js +10 -0
- package/dist/generated/settingsSchemaWireName.d.ts +1 -0
- package/dist/generated/settingsSchemaWireName.js +8 -0
- package/dist/headlessReconnectWire.js +12 -7
- package/dist/hitl/approvalAskers.d.ts +13 -0
- package/dist/hitl/approvalAskers.js +79 -0
- package/dist/hitl/approvalResolution.d.ts +3 -0
- package/dist/hitl/approvalResolution.js +22 -4
- package/dist/hitl/approvalsFeed.js +3 -12
- package/dist/hitl/askParkRowRouting.js +5 -1
- package/dist/hitl/decisionRefusal.d.ts +1 -0
- package/dist/hitl/decisionRefusal.js +5 -2
- package/dist/hitl/decisionSend.js +2 -6
- package/dist/hitl/frameRouter.d.ts +3 -2
- package/dist/hitl/frameRouter.js +28 -6
- package/dist/hitl/gateLedger.d.ts +2 -0
- package/dist/hitl/gateLedger.js +3 -1
- package/dist/hitl/hitlBridge.js +2 -3
- package/dist/hitl/parkResolver.js +32 -23
- package/dist/hitl/parkRowBirthWait.d.ts +2 -0
- package/dist/hitl/parkRowBirthWait.js +8 -1
- package/dist/hitl/persistedRulesWire.d.ts +5 -1
- package/dist/hitl/persistedRulesWire.js +20 -4
- package/dist/hitl/planReviewWire.js +12 -16
- package/dist/hitl/policyDenyCause.d.ts +3 -0
- package/dist/hitl/policyDenyCause.js +16 -0
- package/dist/hitl/sessionPolicyDeliverable.js +1 -1
- package/dist/hitl/toolApprovalWire.d.ts +8 -2
- package/dist/hitl/toolApprovalWire.js +22 -3
- package/dist/hooksReaderGenerations.d.ts +1 -0
- package/dist/hooksReaderGenerations.js +12 -0
- package/dist/hooksWireCaps.js +8 -4
- package/dist/i18n/messages.en.d.ts +38 -1
- package/dist/i18n/messages.en.js +40 -3
- package/dist/i18n/messages.zh.js +45 -3
- package/dist/index.d.ts +6 -1
- package/dist/index.js +4 -1
- package/dist/liveModelCatalog.d.ts +4 -2
- package/dist/liveModelCatalog.js +164 -26
- package/dist/model/catalogDefault.d.ts +25 -0
- package/dist/model/catalogDefault.js +44 -0
- package/dist/permissionWireCaps.d.ts +1 -0
- package/dist/permissionWireCaps.js +11 -0
- package/dist/pluginHooksWire.d.ts +5 -3
- package/dist/pluginHooksWire.js +116 -7
- package/dist/queuedDelivery.d.ts +1 -0
- package/dist/queuedDelivery.js +12 -0
- package/dist/resultFrameKeys.js +4 -2
- package/dist/resumeRefusalCopy.js +15 -8
- package/dist/runPermissionModeSwitch.d.ts +2 -1
- package/dist/runPermissionModeSwitch.js +16 -6
- package/dist/seatContract.d.ts +63 -10
- package/dist/seatContract.js +164 -11
- package/dist/sessionEngine.d.ts +2 -1
- package/dist/sessionEngine.js +5 -0
- package/dist/settingsHooksSalvage.d.ts +5 -0
- package/dist/settingsHooksSalvage.js +54 -0
- package/dist/subagentContentStore.js +1 -1
- package/dist/supportFloor.js +2 -0
- package/dist/taskNotificationAdmission.d.ts +19 -0
- package/dist/taskNotificationAdmission.js +84 -0
- package/dist/toolResult.js +2 -1
- package/dist/webSearchWireCaps.js +9 -4
- package/dist/wireRefusalCopy.d.ts +2 -1
- package/dist/wireRefusalCopy.js +2 -2
- package/docs/INTEGRATION-CLIENTS.md +816 -14
- package/package.json +4 -4
package/dist/liveModelCatalog.js
CHANGED
|
@@ -189,6 +189,45 @@ function rowIdentityUnreadable(row) {
|
|
|
189
189
|
return true;
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
|
+
function aliasesOf(cat) {
|
|
193
|
+
const ALIASES_ABSENT = Object.freeze({ kind: 'absent' });
|
|
194
|
+
const ALIASES_UNREADABLE = Object.freeze({ kind: 'unreadable' });
|
|
195
|
+
try {
|
|
196
|
+
const d = Object.getOwnPropertyDescriptor(cat, 'aliases');
|
|
197
|
+
if (d === undefined)
|
|
198
|
+
return ALIASES_ABSENT;
|
|
199
|
+
if (!Object.hasOwn(d, 'value'))
|
|
200
|
+
return ALIASES_UNREADABLE;
|
|
201
|
+
const raw = d.value;
|
|
202
|
+
if (raw === undefined)
|
|
203
|
+
return ALIASES_ABSENT;
|
|
204
|
+
if (!Array.isArray(raw))
|
|
205
|
+
return ALIASES_UNREADABLE;
|
|
206
|
+
const n = ownDataOf(raw, 'length');
|
|
207
|
+
if (typeof n !== 'number' || !Number.isSafeInteger(n) || n < 0)
|
|
208
|
+
return ALIASES_UNREADABLE;
|
|
209
|
+
const entries = [];
|
|
210
|
+
for (let i = 0; i < n; i += 1) {
|
|
211
|
+
const ed = Object.getOwnPropertyDescriptor(raw, String(i));
|
|
212
|
+
if (ed === undefined || !Object.hasOwn(ed, 'value'))
|
|
213
|
+
return ALIASES_UNREADABLE;
|
|
214
|
+
const e = ed.value;
|
|
215
|
+
if (e === null || typeof e !== 'object' || !isPlainRecord(e))
|
|
216
|
+
return ALIASES_UNREADABLE;
|
|
217
|
+
const nd = Object.getOwnPropertyDescriptor(e, 'name');
|
|
218
|
+
if (nd === undefined || !Object.hasOwn(nd, 'value') || typeof nd.value !== 'string' || nd.value.length === 0)
|
|
219
|
+
return ALIASES_UNREADABLE;
|
|
220
|
+
const bit = atMentionBitOf(e);
|
|
221
|
+
if (bit === 'malformed' || bit === 'unreadable')
|
|
222
|
+
return ALIASES_UNREADABLE;
|
|
223
|
+
appendOwnElement(entries, Object.freeze({ name: nd.value, bit }));
|
|
224
|
+
}
|
|
225
|
+
return Object.freeze({ kind: 'listed', entries: Object.freeze(entries) });
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return ALIASES_UNREADABLE;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
192
231
|
export function modelAcceptanceOf(model, catalog = getLiveModelCatalog()) {
|
|
193
232
|
const name = typeof model === 'string' && model.length > 0 ? model : undefined;
|
|
194
233
|
try {
|
|
@@ -211,22 +250,45 @@ export function modelAcceptanceOf(model, catalog = getLiveModelCatalog()) {
|
|
|
211
250
|
defaultModel = undefined;
|
|
212
251
|
}
|
|
213
252
|
const withDefault = defaultModel === undefined ? {} : { defaultModel };
|
|
253
|
+
const cannotSay = () => Object.freeze({ verdict: 'unknown', why: 'catalog_unreadable', model: name });
|
|
214
254
|
const reservedReading = () => Object.freeze({ verdict: 'unknown', why: 'reserved_word', model: name, ...withDefault });
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const
|
|
220
|
-
if (
|
|
221
|
-
return
|
|
222
|
-
if (
|
|
255
|
+
const notMentionable = () => Object.freeze({ verdict: 'refused', why: 'not_at_mentionable', model: name, ...withDefault });
|
|
256
|
+
const byRow = (row) => {
|
|
257
|
+
if (ownDataOf(row, 'enabled') === false)
|
|
258
|
+
return Object.freeze({ verdict: 'refused', why: 'disabled', model: name, ...withDefault });
|
|
259
|
+
const bit = atMentionBitOf(row);
|
|
260
|
+
if (bit === 'refused')
|
|
261
|
+
return notMentionable();
|
|
262
|
+
if (bit === 'malformed' || bit === 'unreadable')
|
|
263
|
+
return cannotSay();
|
|
264
|
+
return Object.freeze({ verdict: 'accepted', why: 'listed', model: name, ...withDefault });
|
|
265
|
+
};
|
|
266
|
+
const aliases = aliasesOf(catalog);
|
|
267
|
+
if (aliases.kind === 'absent') {
|
|
268
|
+
if (reserved)
|
|
223
269
|
return reservedReading();
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
270
|
+
const row = liveModelRowOf(catalog, name);
|
|
271
|
+
if (row !== undefined) {
|
|
272
|
+
const normalized = ownDataOf(row, 'name');
|
|
273
|
+
if (typeof normalized !== 'string' || normalized.length === 0)
|
|
274
|
+
return cannotSay();
|
|
275
|
+
if (isReservedModelWord(normalized))
|
|
276
|
+
return reservedReading();
|
|
277
|
+
return byRow(row);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
const row = rows.find((r) => ownDataOf(r, 'name') === name);
|
|
282
|
+
if (row !== undefined)
|
|
283
|
+
return byRow(row);
|
|
284
|
+
if (aliases.kind === 'unreadable')
|
|
285
|
+
return cannotSay();
|
|
286
|
+
const alias = aliases.entries.find((a) => a.name === name);
|
|
287
|
+
if (alias !== undefined)
|
|
288
|
+
return alias.bit === 'refused' ? notMentionable() : Object.freeze({ verdict: 'accepted', why: 'aliased', model: name, ...withDefault });
|
|
227
289
|
}
|
|
228
290
|
if (rows.some(rowIdentityUnreadable))
|
|
229
|
-
return
|
|
291
|
+
return cannotSay();
|
|
230
292
|
const dropped = droppedModelEntriesOf(catalog);
|
|
231
293
|
if (droppedDisabledNamed(dropped, name))
|
|
232
294
|
return Object.freeze({ verdict: 'refused', why: 'disabled', model: name, ...withDefault });
|
|
@@ -246,7 +308,7 @@ export function modelNotServedNotice(reading, lang) {
|
|
|
246
308
|
if (ownDataOf(reading, 'verdict') !== 'refused')
|
|
247
309
|
return undefined;
|
|
248
310
|
const why = ownDataOf(reading, 'why');
|
|
249
|
-
if (why !== 'not_listed' && why !== 'disabled')
|
|
311
|
+
if (why !== 'not_listed' && why !== 'disabled' && why !== 'not_at_mentionable')
|
|
250
312
|
return undefined;
|
|
251
313
|
const model = ownDataOf(reading, 'model');
|
|
252
314
|
const shown = typeof model === 'string' && model.length > 0 ? quoteUntrustedForSentence(model, NOT_SERVED_NAME_MAX) : undefined;
|
|
@@ -254,6 +316,11 @@ export function modelNotServedNotice(reading, lang) {
|
|
|
254
316
|
return undefined;
|
|
255
317
|
const dm = ownDataOf(reading, 'defaultModel');
|
|
256
318
|
const fallback = typeof dm === 'string' && dm.length > 0 ? quoteUntrustedForSentence(dm, NOT_SERVED_NAME_MAX) : undefined;
|
|
319
|
+
if (why === 'not_at_mentionable') {
|
|
320
|
+
return fallback === undefined
|
|
321
|
+
? renderMessage(msg('model.notMentionable.noDefault', { model: shown }), lang)
|
|
322
|
+
: renderMessage(msg('model.notMentionable.withDefault', { model: shown, default: fallback }), lang);
|
|
323
|
+
}
|
|
257
324
|
return fallback === undefined
|
|
258
325
|
? renderMessage(msg('model.notServed.noDefault', { model: shown }), lang)
|
|
259
326
|
: renderMessage(msg('model.notServed.withDefault', { model: shown, default: fallback }), lang);
|
|
@@ -420,6 +487,24 @@ export function modelPlaneOf(catalog = getLiveModelCatalog()) {
|
|
|
420
487
|
return unreadable;
|
|
421
488
|
}
|
|
422
489
|
}
|
|
490
|
+
export function modelPlaneSentence(reading, lang) {
|
|
491
|
+
try {
|
|
492
|
+
if (reading === null || typeof reading !== 'object' || Array.isArray(reading))
|
|
493
|
+
return undefined;
|
|
494
|
+
if (ownDataOf(reading, 'kind') !== 'read')
|
|
495
|
+
return undefined;
|
|
496
|
+
const served = ownDataOf(reading, 'servedTable');
|
|
497
|
+
const stance = ownDataOf(reading, 'catalog');
|
|
498
|
+
if (served !== 'env')
|
|
499
|
+
return undefined;
|
|
500
|
+
if (stance !== 'absent' && stance !== 'refused')
|
|
501
|
+
return undefined;
|
|
502
|
+
return renderMessage(msg('model.catalog.envServed', { stance }), lang);
|
|
503
|
+
}
|
|
504
|
+
catch {
|
|
505
|
+
return undefined;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
423
508
|
const CONFIG_DOMAIN_WORD = /^[a-z][a-z0-9_.-]{0,63}$/;
|
|
424
509
|
export function modelCandidateRejectedContent(reading, lang) {
|
|
425
510
|
try {
|
|
@@ -467,6 +552,7 @@ export function readLiveModelCatalog(body) {
|
|
|
467
552
|
const droppedKey = envelopeKey(body, 'droppedEntries');
|
|
468
553
|
const candidateKey = envelopeKey(body, 'candidateRejected');
|
|
469
554
|
const planeKey = envelopeKey(body, 'modelPlane');
|
|
555
|
+
const aliasesKey = envelopeKey(body, 'aliases');
|
|
470
556
|
const raw = modelsKey.present ? modelsKey.value : undefined;
|
|
471
557
|
if (!Array.isArray(raw))
|
|
472
558
|
return unreadableCatalog('models_not_array');
|
|
@@ -479,7 +565,7 @@ export function readLiveModelCatalog(body) {
|
|
|
479
565
|
let unreadableRows = 0;
|
|
480
566
|
for (let i = 0; i < len; i += 1) {
|
|
481
567
|
const d = Object.getOwnPropertyDescriptor(raw, String(i));
|
|
482
|
-
const row = d !== undefined && Object.hasOwn(d, 'value') ?
|
|
568
|
+
const row = d !== undefined && Object.hasOwn(d, 'value') ? modelRowTransitCopy(d.value) : undefined;
|
|
483
569
|
if (row === undefined || names.has(row.name)) {
|
|
484
570
|
unreadableRows += 1;
|
|
485
571
|
continue;
|
|
@@ -504,12 +590,60 @@ export function readLiveModelCatalog(body) {
|
|
|
504
590
|
out.candidateRejected = frozenJsonCopyOf(candidateKey.value) ?? null;
|
|
505
591
|
if (planeKey.present && planeKey.value !== undefined)
|
|
506
592
|
out.modelPlane = frozenJsonCopyOf(planeKey.value) ?? null;
|
|
593
|
+
if (aliasesKey.present && aliasesKey.value !== undefined)
|
|
594
|
+
out.aliases = aliasesTransitCopy(aliasesKey.value);
|
|
507
595
|
return Object.freeze({ kind: 'read', catalog: Object.freeze(out), unreadableRows, ...(defaultModelMalformed ? { defaultModelMalformed: true } : {}) });
|
|
508
596
|
}
|
|
509
597
|
catch {
|
|
510
598
|
return unreadableCatalog('unreadable');
|
|
511
599
|
}
|
|
512
600
|
}
|
|
601
|
+
function aliasesTransitCopy(v) {
|
|
602
|
+
const copy = frozenJsonCopyOf(v);
|
|
603
|
+
if (copy === undefined)
|
|
604
|
+
return null;
|
|
605
|
+
const before = aliasesOf({ aliases: v });
|
|
606
|
+
const after = aliasesOf({ aliases: copy });
|
|
607
|
+
if (before.kind !== after.kind)
|
|
608
|
+
return null;
|
|
609
|
+
if (before.kind === 'listed' && after.kind === 'listed') {
|
|
610
|
+
if (before.entries.length !== after.entries.length)
|
|
611
|
+
return null;
|
|
612
|
+
for (let i = 0; i < before.entries.length; i += 1) {
|
|
613
|
+
const b = before.entries[i];
|
|
614
|
+
const a = after.entries[i];
|
|
615
|
+
if (b === undefined || a === undefined || b.name !== a.name || b.bit !== a.bit)
|
|
616
|
+
return null;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
return copy;
|
|
620
|
+
}
|
|
621
|
+
const ACCEPTANCE_ROW_KEYS = Object.freeze(['id', 'enabled', 'atMentionable']);
|
|
622
|
+
function modelRowTransitCopy(row) {
|
|
623
|
+
const copy = liveModelRowCopy(row);
|
|
624
|
+
if (copy === undefined || row === null || typeof row !== 'object')
|
|
625
|
+
return copy;
|
|
626
|
+
let restated;
|
|
627
|
+
for (const key of ACCEPTANCE_ROW_KEYS) {
|
|
628
|
+
if (Object.hasOwn(copy, key))
|
|
629
|
+
continue;
|
|
630
|
+
let value;
|
|
631
|
+
try {
|
|
632
|
+
const d = Object.getOwnPropertyDescriptor(row, key);
|
|
633
|
+
if (d === undefined)
|
|
634
|
+
continue;
|
|
635
|
+
value = Object.hasOwn(d, 'value') ? (d.value === undefined ? undefined : (frozenJsonCopyOf(d.value) ?? null)) : null;
|
|
636
|
+
}
|
|
637
|
+
catch {
|
|
638
|
+
value = null;
|
|
639
|
+
}
|
|
640
|
+
if (value === undefined)
|
|
641
|
+
continue;
|
|
642
|
+
restated ??= { ...copy };
|
|
643
|
+
Object.defineProperty(restated, key, { value, enumerable: true, writable: true, configurable: true });
|
|
644
|
+
}
|
|
645
|
+
return restated === undefined ? copy : Object.freeze(restated);
|
|
646
|
+
}
|
|
513
647
|
function droppedEntriesCopy(v) {
|
|
514
648
|
if (!Array.isArray(v))
|
|
515
649
|
return frozenJsonCopyOf(v) ?? null;
|
|
@@ -544,23 +678,27 @@ export function liveDefaultModelOf(catalog = getLiveModelCatalog()) {
|
|
|
544
678
|
return Object.freeze({ kind: 'unknown', why: 'unreadable' });
|
|
545
679
|
}
|
|
546
680
|
}
|
|
681
|
+
function atMentionBitOf(o) {
|
|
682
|
+
const d = Object.getOwnPropertyDescriptor(o, 'atMentionable');
|
|
683
|
+
if (d === undefined)
|
|
684
|
+
return 'not_governed';
|
|
685
|
+
if (!(Object.hasOwn(d, 'value')))
|
|
686
|
+
return 'unreadable';
|
|
687
|
+
if (d.value === undefined)
|
|
688
|
+
return 'not_governed';
|
|
689
|
+
if (d.value === true)
|
|
690
|
+
return 'allowed';
|
|
691
|
+
if (d.value === false)
|
|
692
|
+
return 'refused';
|
|
693
|
+
return 'malformed';
|
|
694
|
+
}
|
|
547
695
|
export function atMentionOf(model, catalog = getLiveModelCatalog()) {
|
|
548
696
|
try {
|
|
549
697
|
const target = targetRowOf(model, catalog);
|
|
550
698
|
if (target.kind !== 'row')
|
|
551
699
|
return Object.freeze({ kind: 'unknown', why: target.why });
|
|
552
|
-
const
|
|
553
|
-
|
|
554
|
-
return Object.freeze({ kind: 'not_governed' });
|
|
555
|
-
if (!(Object.hasOwn(d, 'value')))
|
|
556
|
-
return Object.freeze({ kind: 'unknown', why: 'unreadable' });
|
|
557
|
-
if (d.value === undefined)
|
|
558
|
-
return Object.freeze({ kind: 'not_governed' });
|
|
559
|
-
if (d.value === true)
|
|
560
|
-
return Object.freeze({ kind: 'allowed' });
|
|
561
|
-
if (d.value === false)
|
|
562
|
-
return Object.freeze({ kind: 'refused' });
|
|
563
|
-
return Object.freeze({ kind: 'unknown', why: 'malformed' });
|
|
700
|
+
const bit = atMentionBitOf(target.row);
|
|
701
|
+
return bit === 'malformed' || bit === 'unreadable' ? Object.freeze({ kind: 'unknown', why: bit }) : Object.freeze({ kind: bit });
|
|
564
702
|
}
|
|
565
703
|
catch {
|
|
566
704
|
return Object.freeze({ kind: 'unknown', why: 'unreadable' });
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { SETTINGS_RESOLVE_CATALOG_DEFAULT_MODEL, type SETTINGS_DEFAULT_ROLE_TIER_LADDER } from '../generated/settingsSchemaFns.js';
|
|
2
|
+
import { SETTINGS_MODEL_PLANE_REFUSAL_CODES } from '../generated/settingsSchemaTables.js';
|
|
3
|
+
import type { UiLanguage } from '../env/uiLanguage.js';
|
|
2
4
|
export type CatalogDefaultModelsInput = Parameters<typeof SETTINGS_RESOLVE_CATALOG_DEFAULT_MODEL>[0];
|
|
3
5
|
export type CatalogDefaultSource = 'roles.default' | 'fallback' | `tierGroup.${(typeof SETTINGS_DEFAULT_ROLE_TIER_LADDER)[number]}`;
|
|
4
6
|
export interface CatalogDefaultDangling {
|
|
@@ -22,3 +24,26 @@ export interface CatalogDefaultSelect {
|
|
|
22
24
|
}
|
|
23
25
|
export type CatalogDefaultModel = CatalogDefaultNamed | CatalogDefaultSelect;
|
|
24
26
|
export declare function resolveCatalogDefaultModel(models: CatalogDefaultModelsInput, has: (name: string) => boolean, fallback: string): CatalogDefaultModel;
|
|
27
|
+
export type CatalogDefaultRefusalCode = Extract<(typeof SETTINGS_MODEL_PLANE_REFUSAL_CODES)[number], 'config.default_model_missing'>;
|
|
28
|
+
export interface CatalogDefaultModelVerdictInput {
|
|
29
|
+
readonly models: CatalogDefaultModelsInput;
|
|
30
|
+
readonly has: (name: string) => boolean;
|
|
31
|
+
readonly fallback: string;
|
|
32
|
+
readonly face: object;
|
|
33
|
+
}
|
|
34
|
+
export interface CatalogDefaultResolvable {
|
|
35
|
+
readonly ok: true;
|
|
36
|
+
readonly default: CatalogDefaultModel;
|
|
37
|
+
}
|
|
38
|
+
export interface CatalogDefaultRefused {
|
|
39
|
+
readonly ok: false;
|
|
40
|
+
readonly code: CatalogDefaultRefusalCode;
|
|
41
|
+
readonly default: CatalogDefaultModel;
|
|
42
|
+
readonly detail: {
|
|
43
|
+
readonly cause: string;
|
|
44
|
+
readonly role: string;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export type CatalogDefaultModelVerdict = CatalogDefaultResolvable | CatalogDefaultRefused;
|
|
48
|
+
export declare function catalogDefaultModelVerdict(input: CatalogDefaultModelVerdictInput): CatalogDefaultModelVerdict | undefined;
|
|
49
|
+
export declare function catalogDefaultRefusalContent(verdict: CatalogDefaultModelVerdict, lang?: UiLanguage): string | undefined;
|
|
@@ -1,4 +1,48 @@
|
|
|
1
1
|
import { SETTINGS_RESOLVE_CATALOG_DEFAULT_MODEL } from '../generated/settingsSchemaFns.js';
|
|
2
|
+
import { modelFaceResolvable } from '../coreValuePorts.js';
|
|
3
|
+
import { slotReadOf } from '../wireFailureShape.js';
|
|
4
|
+
import { displayUntrusted } from '../displayUntrusted.js';
|
|
5
|
+
import { msg, renderMessage } from '../i18n/translate.js';
|
|
2
6
|
export function resolveCatalogDefaultModel(models, has, fallback) {
|
|
3
7
|
return SETTINGS_RESOLVE_CATALOG_DEFAULT_MODEL(models, has, fallback);
|
|
4
8
|
}
|
|
9
|
+
const CATALOG_DEFAULT_REFUSAL_CODE = 'config.default_model_missing';
|
|
10
|
+
export function catalogDefaultModelVerdict(input) {
|
|
11
|
+
const { models, has, fallback, face } = input;
|
|
12
|
+
const chain = resolveCatalogDefaultModel(models, has, fallback);
|
|
13
|
+
const verdict = modelFaceResolvable(face, { spec: { modelRole: 'default' } });
|
|
14
|
+
if (verdict === undefined || typeof verdict !== 'object' || verdict === null)
|
|
15
|
+
return undefined;
|
|
16
|
+
const okSlot = slotReadOf(verdict, 'ok');
|
|
17
|
+
if (okSlot.presence !== 'present')
|
|
18
|
+
return undefined;
|
|
19
|
+
if (okSlot.value === true)
|
|
20
|
+
return Object.freeze({ ok: true, default: chain });
|
|
21
|
+
if (okSlot.value !== false)
|
|
22
|
+
return undefined;
|
|
23
|
+
const codeSlot = slotReadOf(verdict, 'code');
|
|
24
|
+
const roleSlot = slotReadOf(verdict, 'role');
|
|
25
|
+
const code = codeSlot.presence === 'present' ? codeSlot.value : undefined;
|
|
26
|
+
const role = roleSlot.presence === 'present' ? roleSlot.value : undefined;
|
|
27
|
+
if (typeof code !== 'string' || code.length === 0 || typeof role !== 'string' || role.length === 0)
|
|
28
|
+
return undefined;
|
|
29
|
+
return Object.freeze({
|
|
30
|
+
ok: false,
|
|
31
|
+
code: CATALOG_DEFAULT_REFUSAL_CODE,
|
|
32
|
+
default: chain,
|
|
33
|
+
detail: Object.freeze({ cause: code, role }),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export function catalogDefaultRefusalContent(verdict, lang) {
|
|
37
|
+
if (typeof verdict !== 'object' || verdict === null || verdict.ok !== false)
|
|
38
|
+
return undefined;
|
|
39
|
+
const d = verdict.default;
|
|
40
|
+
if (typeof d !== 'object' || d === null)
|
|
41
|
+
return undefined;
|
|
42
|
+
if (d.kind === 'named' && typeof d.name === 'string') {
|
|
43
|
+
return renderMessage(msg('model.catalogDefault.refused.named', { name: displayUntrusted(d.name, { max: 64 }) }), lang);
|
|
44
|
+
}
|
|
45
|
+
if (d.kind === 'select')
|
|
46
|
+
return renderMessage(msg('model.catalogDefault.refused.select'), lang);
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
@@ -4,6 +4,7 @@ export type { PermissionMode };
|
|
|
4
4
|
export interface PermissionModeField {
|
|
5
5
|
permissionMode?: PermissionMode;
|
|
6
6
|
}
|
|
7
|
+
export declare function permissionModeTitle(word: string): string | undefined;
|
|
7
8
|
export declare function permissionModeField(mode: string | undefined, opts?: {
|
|
8
9
|
stampDefault?: boolean;
|
|
9
10
|
permissionModes?: PermissionModesReading | undefined;
|
|
@@ -2,6 +2,17 @@ import { PERMISSION_MODE_WORDS } from './taskRequestWords.js';
|
|
|
2
2
|
import { permissionModeAdmitted } from './permissionModesCapability.js';
|
|
3
3
|
const _permissionModePin = true;
|
|
4
4
|
void _permissionModePin;
|
|
5
|
+
const PERMISSION_MODE_TITLES = {
|
|
6
|
+
default: 'Manual',
|
|
7
|
+
acceptEdits: 'Accept edits',
|
|
8
|
+
plan: 'Plan',
|
|
9
|
+
auto: 'Auto',
|
|
10
|
+
bypassPermissions: 'Bypass Permissions',
|
|
11
|
+
dontAsk: "Don't Ask",
|
|
12
|
+
};
|
|
13
|
+
export function permissionModeTitle(word) {
|
|
14
|
+
return typeof word === 'string' && Object.hasOwn(PERMISSION_MODE_TITLES, word) ? PERMISSION_MODE_TITLES[word] : undefined;
|
|
15
|
+
}
|
|
5
16
|
const BIT_GATED_MODE = 'dontAsk';
|
|
6
17
|
const KNOWN = new Set(PERMISSION_MODE_WORDS.filter((w) => w !== BIT_GATED_MODE));
|
|
7
18
|
export function permissionModeField(mode, opts) {
|
|
@@ -8,11 +8,11 @@ export declare const ENGINE_FIRED_HOOK_EVENTS: readonly ["PreToolUse", "PostTool
|
|
|
8
8
|
export type EngineFiredHookEvent = (typeof ENGINE_FIRED_HOOK_EVENTS)[number];
|
|
9
9
|
export declare const PLUGIN_HOOK_DISPOSITIONS: readonly ["engine", "shell", "not_run"];
|
|
10
10
|
export type PluginHookDisposition = (typeof PLUGIN_HOOK_DISPOSITIONS)[number];
|
|
11
|
-
export declare const PLUGIN_HOOK_REASONS: readonly ["projected", "shell_event", "no_executor", "engine_not_local", "engine_locality_unknown", "engine_capability_absent", "engine_capability_unknown", "not_command", "sensitive_options", "engine_limit", "shell_form_user_config", "user_config_unset", "malformed_entry", "engine_hooks_off", "engine_hooks_unknown", "engine_type_skipped", "engine_llm_limit", "engine_unconfirmed", "engine_elsewhere", "hooks_module", "scope_unsupported", "source_incomplete", "compaction_local_fallback"];
|
|
11
|
+
export declare const PLUGIN_HOOK_REASONS: readonly ["projected", "shell_event", "no_executor", "engine_not_local", "engine_locality_unknown", "engine_capability_absent", "engine_capability_unknown", "not_command", "sensitive_options", "engine_limit", "shell_form_user_config", "user_config_unset", "malformed_entry", "engine_hooks_off", "engine_hooks_unknown", "engine_type_skipped", "engine_llm_limit", "engine_unconfirmed", "engine_elsewhere", "hooks_module", "scope_unsupported", "source_incomplete", "compaction_local_fallback", "key_not_read", "source_not_authored"];
|
|
12
12
|
export type PluginHookReason = (typeof PLUGIN_HOOK_REASONS)[number];
|
|
13
13
|
export declare const PLUGIN_HOOK_EXCLUSION_REASONS: readonly ["workspace_untrusted", "governance_unreadable", "policy_disable_all", "startup_mode", "managed_plugins_only", "prompt_not_user_authored"];
|
|
14
14
|
export type PluginHookExclusionReason = (typeof PLUGIN_HOOK_EXCLUSION_REASONS)[number];
|
|
15
|
-
export declare const SETTINGS_HOOK_DROP_REASONS: readonly ["exec_form_unsupported", "mcp_tool_unsupported"];
|
|
15
|
+
export declare const SETTINGS_HOOK_DROP_REASONS: readonly ["exec_form_unsupported", "mcp_tool_unsupported", "key_not_read", "source_not_authored"];
|
|
16
16
|
export type SettingsHookDropReason = (typeof SETTINGS_HOOK_DROP_REASONS)[number];
|
|
17
17
|
export type HookSettingsSource = 'policySettings' | 'userSettings' | 'projectSettings' | 'localSettings' | 'flagSettings';
|
|
18
18
|
export interface PluginHookKey {
|
|
@@ -36,6 +36,7 @@ export interface SettingsHookDrop {
|
|
|
36
36
|
readonly hookIndex: number;
|
|
37
37
|
readonly reason: SettingsHookDropReason;
|
|
38
38
|
readonly notRun: boolean;
|
|
39
|
+
readonly unreadKeys?: readonly (readonly (string | number)[])[];
|
|
39
40
|
}
|
|
40
41
|
export interface SettingsHookVerdict {
|
|
41
42
|
readonly source: HookSettingsSource;
|
|
@@ -147,6 +148,7 @@ export interface PluginHookDecisionInput {
|
|
|
147
148
|
readonly promptAuthoredByUser: boolean;
|
|
148
149
|
readonly occupied: ReadonlyMap<string, EventOccupancy>;
|
|
149
150
|
readonly suppressedLocally?: ReadonlySet<string>;
|
|
151
|
+
readonly readerNotRead: readonly string[];
|
|
150
152
|
}
|
|
151
153
|
export interface PluginHookDecision {
|
|
152
154
|
readonly verdicts: readonly PluginHookVerdict[];
|
|
@@ -166,7 +168,7 @@ export declare function decideSessionHooks(input: SessionHookDecisionInput): {
|
|
|
166
168
|
readonly verdicts: readonly SessionHookVerdict[];
|
|
167
169
|
readonly unreadable: number;
|
|
168
170
|
};
|
|
169
|
-
export declare function filterSettingsHookGroups(source: HookSettingsSource, event: string, groups: readonly WireHookGroup[], execFormCapable: boolean, shellRunsType: (type: string | undefined) => boolean, judge: SettingsHookJudge, mask?: HooksSalvageMask): SettingsHookFilterResult;
|
|
171
|
+
export declare function filterSettingsHookGroups(source: HookSettingsSource, event: string, groups: readonly WireHookGroup[], execFormCapable: boolean, shellRunsType: (type: string | undefined) => boolean, judge: SettingsHookJudge, readerNotRead: readonly string[], mask?: HooksSalvageMask): SettingsHookFilterResult;
|
|
170
172
|
export interface SettingsHookFilterResult {
|
|
171
173
|
readonly groups: WireHookGroup[];
|
|
172
174
|
readonly drops: SettingsHookDrop[];
|
package/dist/pluginHooksWire.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { displayUntrusted } from './displayUntrusted.js';
|
|
2
|
-
import { appendOwnElement } from './ownKey.js';
|
|
2
|
+
import { appendOwnElement, readOwnDataValue } from './ownKey.js';
|
|
3
3
|
import { msg, renderMessage } from './i18n/translate.js';
|
|
4
4
|
import { SETTINGS_ENGINE_OWNED_HOOK_EVENTS } from './generated/settingsSchemaTables.js';
|
|
5
|
-
import { HOOK_SETTINGS_SOURCE_TEXT, hooksSalvageMaskOf, salvageSettingsHooksEntries, } from './settingsHooksSalvage.js';
|
|
5
|
+
import { HOOK_SETTINGS_SOURCE_TEXT, hooksEntryUnreadKeys, hooksGroupAuthoredSource, hooksGroupUnreadKeys, hooksKeyCoordinateText, hooksSalvageMaskOf, salvageSettingsHooksEntries, } from './settingsHooksSalvage.js';
|
|
6
6
|
export const ENGINE_FIRED_HOOK_EVENTS = SETTINGS_ENGINE_OWNED_HOOK_EVENTS;
|
|
7
7
|
export const PLUGIN_HOOK_DISPOSITIONS = ['engine', 'shell', 'not_run'];
|
|
8
8
|
export const PLUGIN_HOOK_REASONS = [
|
|
@@ -29,6 +29,8 @@ export const PLUGIN_HOOK_REASONS = [
|
|
|
29
29
|
'scope_unsupported',
|
|
30
30
|
'source_incomplete',
|
|
31
31
|
'compaction_local_fallback',
|
|
32
|
+
'key_not_read',
|
|
33
|
+
'source_not_authored',
|
|
32
34
|
];
|
|
33
35
|
export const PLUGIN_HOOK_EXCLUSION_REASONS = [
|
|
34
36
|
'workspace_untrusted',
|
|
@@ -38,7 +40,7 @@ export const PLUGIN_HOOK_EXCLUSION_REASONS = [
|
|
|
38
40
|
'managed_plugins_only',
|
|
39
41
|
'prompt_not_user_authored',
|
|
40
42
|
];
|
|
41
|
-
export const SETTINGS_HOOK_DROP_REASONS = ['exec_form_unsupported', 'mcp_tool_unsupported'];
|
|
43
|
+
export const SETTINGS_HOOK_DROP_REASONS = ['exec_form_unsupported', 'mcp_tool_unsupported', 'key_not_read', 'source_not_authored'];
|
|
42
44
|
export function hooksWirePlanShapeOf(v) {
|
|
43
45
|
try {
|
|
44
46
|
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
@@ -257,7 +259,9 @@ export function decidePluginHooks(input) {
|
|
|
257
259
|
unreadable++;
|
|
258
260
|
return;
|
|
259
261
|
}
|
|
260
|
-
;
|
|
262
|
+
const authored = hooksGroupAuthoredSource(group);
|
|
263
|
+
const groupUnread = authored === 'unreadable' ? undefined : hooksGroupUnreadKeys(event, group);
|
|
264
|
+
const groupSourceAuthored = authored === 'unreadable' || (authored === 'present' && groupUnread !== undefined);
|
|
261
265
|
group.hooks.forEach((entry, hookIndex) => {
|
|
262
266
|
const key = { pluginId, pluginName, event, groupIndex, hookIndex };
|
|
263
267
|
if (input.exclusion !== undefined) {
|
|
@@ -317,6 +321,15 @@ export function decidePluginHooks(input) {
|
|
|
317
321
|
appendOwnElement(verdicts, { ...key, disposition: ex.disposition, reason: ex.reason });
|
|
318
322
|
return;
|
|
319
323
|
}
|
|
324
|
+
const entryUnread = isRecord(entry) ? hooksEntryUnreadKeys(event, entry, input.readerNotRead) : undefined;
|
|
325
|
+
if (groupSourceAuthored && (authored === 'unreadable' || entryUnread !== undefined)) {
|
|
326
|
+
appendOwnElement(verdicts, { ...key, ...fallback(event, entryType, 'source_not_authored') });
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
if (entryUnread !== undefined && ((groupUnread?.length ?? 0) > 0 || entryUnread.length > 0)) {
|
|
330
|
+
appendOwnElement(verdicts, { ...key, ...fallback(event, entryType, 'key_not_read') });
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
320
333
|
const plugin = { name: src.name, root: src.root, dataDir: src.dataDir };
|
|
321
334
|
const options = projectedOptions(src.options);
|
|
322
335
|
if (options !== undefined)
|
|
@@ -454,7 +467,18 @@ function carriesArgs(entry) {
|
|
|
454
467
|
}
|
|
455
468
|
return true;
|
|
456
469
|
}
|
|
457
|
-
|
|
470
|
+
function unreadKeyPathsOf(event, groupIndex, hookIndex, groupUnread, entryUnread) {
|
|
471
|
+
if (entryUnread === undefined)
|
|
472
|
+
return Object.freeze([]);
|
|
473
|
+
const out = [];
|
|
474
|
+
for (const k of groupUnread)
|
|
475
|
+
appendOwnElement(out, Object.freeze(['hooks', event, groupIndex, k]));
|
|
476
|
+
for (const k of entryUnread)
|
|
477
|
+
if (k !== 'plugin')
|
|
478
|
+
appendOwnElement(out, Object.freeze(['hooks', event, groupIndex, 'hooks', hookIndex, k]));
|
|
479
|
+
return Object.freeze(out);
|
|
480
|
+
}
|
|
481
|
+
export function filterSettingsHookGroups(source, event, groups, execFormCapable, shellRunsType, judge, readerNotRead, mask) {
|
|
458
482
|
const drops = [];
|
|
459
483
|
const verdicts = [];
|
|
460
484
|
const excluded = [];
|
|
@@ -470,20 +494,35 @@ export function filterSettingsHookGroups(source, event, groups, execFormCapable,
|
|
|
470
494
|
}
|
|
471
495
|
const kept = [];
|
|
472
496
|
let changed = false;
|
|
497
|
+
const authored = hooksGroupAuthoredSource(group);
|
|
498
|
+
const groupUnread = authored === 'unreadable' ? undefined : hooksGroupUnreadKeys(event, group);
|
|
499
|
+
const groupSourceAuthored = authored === 'unreadable' || (authored === 'present' && groupUnread !== undefined);
|
|
473
500
|
group.hooks.forEach((entry, hookIndex) => {
|
|
474
501
|
if (mask !== undefined && mask.entryDropped(event, groupIndex, hookIndex)) {
|
|
475
502
|
changed = true;
|
|
476
503
|
return;
|
|
477
504
|
}
|
|
478
|
-
const
|
|
505
|
+
const earlier = !isRecord(entry)
|
|
479
506
|
? undefined
|
|
480
507
|
: entry.type === 'mcp_tool'
|
|
481
508
|
? 'mcp_tool_unsupported'
|
|
482
509
|
: entry.type === 'command' && carriesArgs(entry) && !execFormCapable
|
|
483
510
|
? 'exec_form_unsupported'
|
|
484
511
|
: undefined;
|
|
512
|
+
const entryUnread = earlier === undefined && isRecord(entry) ? hooksEntryUnreadKeys(event, entry, readerNotRead) : undefined;
|
|
513
|
+
const sourceNotAuthored = earlier === undefined && groupSourceAuthored && (authored === 'unreadable' || entryUnread !== undefined);
|
|
514
|
+
const unreadKeys = earlier === undefined && !sourceNotAuthored ? unreadKeyPathsOf(event, groupIndex, hookIndex, groupUnread ?? [], entryUnread) : [];
|
|
515
|
+
const reason = earlier ?? (sourceNotAuthored ? 'source_not_authored' : unreadKeys.length > 0 ? 'key_not_read' : undefined);
|
|
485
516
|
if (reason !== undefined) {
|
|
486
|
-
appendOwnElement(drops, {
|
|
517
|
+
appendOwnElement(drops, {
|
|
518
|
+
source,
|
|
519
|
+
event,
|
|
520
|
+
groupIndex,
|
|
521
|
+
hookIndex,
|
|
522
|
+
reason,
|
|
523
|
+
notRun: engineEvent && !shellRunsType(isRecord(entry) && typeof entry.type === 'string' ? entry.type : undefined),
|
|
524
|
+
...(reason === 'key_not_read' ? { unreadKeys } : {}),
|
|
525
|
+
});
|
|
487
526
|
changed = true;
|
|
488
527
|
return;
|
|
489
528
|
}
|
|
@@ -510,6 +549,8 @@ export function filterSettingsHookGroups(source, event, groups, execFormCapable,
|
|
|
510
549
|
}
|
|
511
550
|
appendOwnElement(kept, entry);
|
|
512
551
|
});
|
|
552
|
+
if (((groupUnread?.length ?? 0) > 0 || groupSourceAuthored) && kept.length === 0)
|
|
553
|
+
changed = true;
|
|
513
554
|
if (!changed)
|
|
514
555
|
appendOwnElement(out, group);
|
|
515
556
|
else if (kept.length > 0)
|
|
@@ -832,10 +873,14 @@ const REASON_TEXT = {
|
|
|
832
873
|
scope_unsupported: 'hooks registered for a skill, an agent or by the host application are not sent to the engine, and this client does not run this event',
|
|
833
874
|
source_incomplete: 'the plugin was reported without its id, name, root folder or data folder',
|
|
834
875
|
compaction_local_fallback: renderMessage(msg('config.hooks.plan.reason.compactionLocalFallback')),
|
|
876
|
+
key_not_read: renderMessage(msg('config.hooks.plan.reason.keyNotRead')),
|
|
877
|
+
source_not_authored: renderMessage(msg('config.hooks.plan.reason.sourceNotAuthored')),
|
|
835
878
|
};
|
|
836
879
|
const DROP_TEXT = {
|
|
837
880
|
exec_form_unsupported: 'exec-form hooks (with "args") are sent to the engine only once it reports support for them',
|
|
838
881
|
mcp_tool_unsupported: 'MCP tool hooks are not supported by the engine',
|
|
882
|
+
key_not_read: REASON_TEXT.key_not_read,
|
|
883
|
+
source_not_authored: REASON_TEXT.source_not_authored,
|
|
839
884
|
};
|
|
840
885
|
const SOURCE_TEXT = HOOK_SETTINGS_SOURCE_TEXT;
|
|
841
886
|
export function pluginHookReasonText(reason) {
|
|
@@ -898,8 +943,52 @@ function capNoticeLabel(s) {
|
|
|
898
943
|
}
|
|
899
944
|
return `${s.slice(0, end)}…`;
|
|
900
945
|
}
|
|
946
|
+
const KEY_NOT_READ_SHOWN = 3;
|
|
947
|
+
function unreadPathsOfRow(d) {
|
|
948
|
+
const raw = d.unreadKeys;
|
|
949
|
+
if (!Array.isArray(raw))
|
|
950
|
+
return [];
|
|
951
|
+
return raw.filter((p) => Array.isArray(p) && p.length > 0 && p.every((x) => typeof x === 'string' || typeof x === 'number'));
|
|
952
|
+
}
|
|
953
|
+
function namedPathsOfRow(d) {
|
|
954
|
+
switch (d.reason) {
|
|
955
|
+
case 'key_not_read':
|
|
956
|
+
return unreadPathsOfRow(d);
|
|
957
|
+
case 'source_not_authored':
|
|
958
|
+
return typeof d.event === 'string' && Number.isInteger(d.groupIndex) && d.groupIndex >= 0 ? [['hooks', d.event, d.groupIndex, 'source']] : [];
|
|
959
|
+
case 'exec_form_unsupported':
|
|
960
|
+
case 'mcp_tool_unsupported':
|
|
961
|
+
return [];
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
function namedCoordinatesText(coordinates) {
|
|
965
|
+
const shown = coordinates.slice(0, KEY_NOT_READ_SHOWN).join(', ');
|
|
966
|
+
return coordinates.length > KEY_NOT_READ_SHOWN ? renderMessage(msg('config.hooks.plan.keyNotRead.more', { shown, rest: coordinates.length - KEY_NOT_READ_SHOWN })) : shown;
|
|
967
|
+
}
|
|
968
|
+
function keyNotReadLine(source, row) {
|
|
969
|
+
const events = row.events.map((e) => noticeLabel(e)).join(', ');
|
|
970
|
+
const hooks = `${row.count} ${events} ${row.count === 1 ? 'hook' : 'hooks'}`;
|
|
971
|
+
const coordinates = namedCoordinatesText(row.coordinates);
|
|
972
|
+
const line = renderMessage(msg(row.coordinates.length === 1 ? 'config.hooks.plan.keyNotRead.oneKey' : 'config.hooks.plan.keyNotRead.manyKeys', { layer: SOURCE_TEXT[source], hooks, coordinates }));
|
|
973
|
+
return row.onFailure ? renderMessage(msg('config.hooks.plan.keyNotRead.withOnFailure', { line })) : line;
|
|
974
|
+
}
|
|
975
|
+
function sourceNotAuthoredLine(source, row) {
|
|
976
|
+
const events = row.events.map((e) => noticeLabel(e)).join(', ');
|
|
977
|
+
const hooks = `${row.count} ${events} ${row.count === 1 ? 'hook' : 'hooks'}`;
|
|
978
|
+
const coordinates = namedCoordinatesText(row.coordinates);
|
|
979
|
+
return renderMessage(msg(row.coordinates.length === 1 ? 'config.hooks.plan.sourceNotAuthored.oneKey' : 'config.hooks.plan.sourceNotAuthored.manyKeys', { layer: SOURCE_TEXT[source], hooks, coordinates }));
|
|
980
|
+
}
|
|
901
981
|
export function hooksNotRunNotice(plan) {
|
|
902
982
|
const lines = [];
|
|
983
|
+
let closedBy;
|
|
984
|
+
try {
|
|
985
|
+
closedBy = isRecord(plan) ? readOwnDataValue(plan, 'closedBy') : undefined;
|
|
986
|
+
}
|
|
987
|
+
catch {
|
|
988
|
+
closedBy = undefined;
|
|
989
|
+
}
|
|
990
|
+
if (closedBy === 'policy_disable_all')
|
|
991
|
+
appendOwnElement(lines, renderMessage(msg('config.hooks.plan.disableAllHooks')));
|
|
903
992
|
const byPlugin = new Map();
|
|
904
993
|
for (const v of plan.verdicts) {
|
|
905
994
|
if (v.disposition !== 'not_run')
|
|
@@ -916,9 +1005,27 @@ export function hooksNotRunNotice(plan) {
|
|
|
916
1005
|
appendOwnElement(lines, `Plugin "${noticeLabel(row.name) || '(unnamed)'}": ${events} ${row.count === 1 ? 'hook' : 'hooks'} will not run — ${pluginHookReasonText(row.reason)}.`);
|
|
917
1006
|
}
|
|
918
1007
|
const bySource = new Map();
|
|
1008
|
+
const namedBySource = new Map();
|
|
919
1009
|
for (const d of plan.settingsDropped) {
|
|
920
1010
|
if (!d.notRun)
|
|
921
1011
|
continue;
|
|
1012
|
+
const named = d.reason === 'key_not_read' || d.reason === 'source_not_authored' ? namedPathsOfRow(d) : [];
|
|
1013
|
+
if (named.length > 0 && (d.reason === 'key_not_read' || d.reason === 'source_not_authored')) {
|
|
1014
|
+
const nk = `${d.source}\u0000${d.reason}`;
|
|
1015
|
+
const row = namedBySource.get(nk) ?? { source: d.source, reason: d.reason, events: [], count: 0, coordinates: [], onFailure: false };
|
|
1016
|
+
if (!row.events.includes(d.event))
|
|
1017
|
+
appendOwnElement(row.events, d.event);
|
|
1018
|
+
row.count++;
|
|
1019
|
+
for (const path of named) {
|
|
1020
|
+
const c = hooksKeyCoordinateText(path);
|
|
1021
|
+
if (!row.coordinates.includes(c))
|
|
1022
|
+
appendOwnElement(row.coordinates, c);
|
|
1023
|
+
if (d.reason === 'key_not_read' && path[path.length - 1] === 'onFailure')
|
|
1024
|
+
row.onFailure = true;
|
|
1025
|
+
}
|
|
1026
|
+
namedBySource.set(nk, row);
|
|
1027
|
+
continue;
|
|
1028
|
+
}
|
|
922
1029
|
const k = `${d.source}\u0000${d.reason}`;
|
|
923
1030
|
const row = bySource.get(k) ?? { source: d.source, reason: d.reason, events: [], count: 0 };
|
|
924
1031
|
if (!row.events.includes(d.event))
|
|
@@ -930,6 +1037,8 @@ export function hooksNotRunNotice(plan) {
|
|
|
930
1037
|
const events = row.events.map((e) => noticeLabel(e)).join(', ');
|
|
931
1038
|
appendOwnElement(lines, `${SOURCE_TEXT[row.source]}: ${events} ${row.count === 1 ? 'hook' : 'hooks'} will not run — ${settingsHookDropText(row.reason)}.`);
|
|
932
1039
|
}
|
|
1040
|
+
for (const row of namedBySource.values())
|
|
1041
|
+
appendOwnElement(lines, row.reason === 'key_not_read' ? keyNotReadLine(row.source, row) : sourceNotAuthoredLine(row.source, row));
|
|
933
1042
|
const settingsVerdicts = plan.settingsVerdicts;
|
|
934
1043
|
const byVerdict = new Map();
|
|
935
1044
|
for (const raw of Array.isArray(settingsVerdicts) ? settingsVerdicts : []) {
|
package/dist/queuedDelivery.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export interface QueueEntry {
|
|
|
15
15
|
readonly intentKey?: string;
|
|
16
16
|
readonly screening?: 'pending' | 'result';
|
|
17
17
|
readonly upsExecutor?: 'shell' | 'engine' | 'unknown' | 'none';
|
|
18
|
+
readonly _sema_task_notification?: {} | null | undefined;
|
|
18
19
|
}
|
|
19
20
|
export type QueuedHoldReason = 'barrier' | 'share_incomplete' | 'not_steerable' | 'in_flight' | 'attempted' | 'no_run';
|
|
20
21
|
export interface QueuedDeliveryPlan {
|