@sema-agent/client-core 0.95.0 → 0.97.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 +269 -0
- package/README.md +61 -31
- package/dist/adapt/arms.js +7 -1
- package/dist/adapt/toolCards.d.ts +1 -0
- package/dist/adapt/toolCards.js +16 -3
- package/dist/adapt/wireShapes.js +2 -16
- package/dist/adapter/activeRunSelfHeal.d.ts +4 -2
- package/dist/adapter/activeRunSelfHeal.js +32 -6
- package/dist/adapter/downstream/eventToSdkMessage.js +11 -3
- package/dist/adapter/downstream/terminalToSdkResult.js +14 -11
- package/dist/adapter/runStream.js +30 -47
- package/dist/agentSession/backgroundView.js +2 -15
- package/dist/agentSession/engineAgentRegistryRead.js +5 -4
- package/dist/agentSession/engineSessionBackgroundStop.js +22 -15
- package/dist/agentsWireCaps.d.ts +1 -1
- package/dist/agentsWireCaps.js +29 -12
- package/dist/approvalDecidedByCapability.d.ts +2 -0
- package/dist/approvalDecidedByCapability.js +0 -1
- package/dist/approvalsStreamLiveCapability.d.ts +2 -0
- package/dist/approvalsStreamLiveCapability.js +3 -2
- package/dist/attachmentSeatCapability.d.ts +2 -0
- package/dist/attachmentSeatCapability.js +0 -1
- package/dist/callerCwdCapability.d.ts +2 -4
- package/dist/callerCwdCapability.js +0 -7
- package/dist/centerWiringCapability.d.ts +2 -4
- package/dist/centerWiringCapability.js +4 -9
- package/dist/classifierVerdictWire.js +4 -16
- package/dist/clientSlice.js +1 -1
- package/dist/cloudConfigWireCaps.d.ts +4 -4
- package/dist/cloudConfigWireCaps.js +241 -85
- package/dist/coreValuePorts.d.ts +11 -7
- package/dist/coreValuePorts.js +5 -8
- package/dist/credentialProvenance.d.ts +28 -0
- package/dist/credentialProvenance.js +76 -0
- package/dist/decideFailureNote.js +3 -1
- package/dist/decideReceipt.js +7 -10
- package/dist/declared/supportFloorDeclared.js +3 -3
- package/dist/deviceExecutorManagementCapability.d.ts +2 -0
- package/dist/deviceExecutorManagementCapability.js +3 -2
- package/dist/displayUntrusted.d.ts +10 -3
- package/dist/displayUntrusted.js +371 -60
- package/dist/engineCapReader.d.ts +8 -2
- package/dist/engineCapReader.js +15 -7
- package/dist/engineCapsCache.d.ts +17 -3
- package/dist/engineCapsCache.js +268 -43
- package/dist/engineDirectory.d.ts +79 -0
- package/dist/engineDirectory.js +186 -0
- package/dist/engineErrorCodes.d.ts +17 -1
- package/dist/engineErrorCodes.js +46 -16
- package/dist/engineNoticeCodes.d.ts +17 -0
- package/dist/engineNoticeCodes.js +54 -1
- package/dist/executionLaneCapability.d.ts +2 -0
- package/dist/executionLaneCapability.js +3 -2
- package/dist/fileHistoryCaptureCapability.d.ts +16 -0
- package/dist/fileHistoryCaptureCapability.js +98 -2
- package/dist/fileHistoryLegNotice.js +4 -0
- package/dist/fleet/bgSubagentRow.d.ts +15 -0
- package/dist/fleet/bgSubagentRow.js +67 -0
- package/dist/fleet/fleetLedger.d.ts +1 -0
- package/dist/fleet/fleetLedger.js +164 -126
- package/dist/fleet/fleetProjection.d.ts +1 -0
- package/dist/fleet/fleetProjection.js +10 -3
- package/dist/fleetTaskDesc.js +4 -17
- package/dist/gateOutcome.d.ts +12 -1
- package/dist/gateOutcome.js +56 -1
- package/dist/gateVocabulary.d.ts +2 -2
- package/dist/gateVocabulary.js +4 -3
- package/dist/generated/engineAskFaceTables.js +1 -1
- package/dist/generated/engineFactTables.d.ts +5 -3
- package/dist/generated/engineFactTables.js +17 -4
- package/dist/generated/engineNoticeTables.js +12 -3
- package/dist/generated/sdkFactTables.d.ts +2 -0
- package/dist/generated/sdkFactTables.js +7 -0
- package/dist/generated/settingsSchemaFns.d.ts +3 -0
- package/dist/generated/settingsSchemaFns.js +53 -0
- package/dist/generated/toolNameTables.d.ts +1 -1
- package/dist/generated/toolNameTables.js +1 -42
- package/dist/hitl/approvalDecisionNoteAudit.js +2 -2
- package/dist/hitl/approvalEndingCause.d.ts +2 -0
- package/dist/hitl/approvalEndingCause.js +26 -21
- package/dist/hitl/approvalHolds.d.ts +16 -1
- package/dist/hitl/approvalHolds.js +52 -12
- package/dist/hitl/askGateWire.js +1 -0
- package/dist/hitl/askParkRowRouting.js +1 -1
- package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
- package/dist/hitl/automaticAnswerVerdict.js +13 -10
- package/dist/hitl/decisionConflict.js +4 -5
- package/dist/hitl/decisionRefusal.d.ts +8 -0
- package/dist/hitl/decisionRefusal.js +55 -14
- package/dist/hitl/frameRouter.d.ts +3 -1
- package/dist/hitl/frameRouter.js +58 -39
- package/dist/hitl/gateLedger.d.ts +0 -5
- package/dist/hitl/gateLedger.js +0 -21
- package/dist/hitl/hitlBridge.d.ts +6 -2
- package/dist/hitl/hitlBridge.js +46 -11
- package/dist/hitl/localAllowRule.d.ts +1 -0
- package/dist/hitl/localAllowRule.js +2 -2
- package/dist/hitl/noAllowCause.d.ts +2 -1
- package/dist/hitl/noAllowCause.js +3 -2
- package/dist/hitl/parkResolver.d.ts +1 -0
- package/dist/hitl/parkResolver.js +14 -56
- package/dist/hitl/parkRowBirthWait.d.ts +1 -0
- package/dist/hitl/parkRowBirthWait.js +2 -2
- package/dist/hitl/planReviewWire.d.ts +1 -0
- package/dist/hitl/planReviewWire.js +98 -20
- package/dist/hitl/replayedApproval.d.ts +3 -3
- package/dist/hitl/replayedApproval.js +21 -16
- package/dist/hitl/sessionPolicyDeliverable.d.ts +0 -1
- package/dist/hitl/sessionPolicyDeliverable.js +17 -17
- package/dist/hitl/sessionPolicyWire.d.ts +2 -0
- package/dist/hitl/sessionPolicyWire.js +15 -3
- package/dist/hitl/standingRows.d.ts +19 -0
- package/dist/hitl/standingRows.js +148 -0
- package/dist/hitl/suspendedReopen.js +2 -1
- package/dist/hitl/toolApprovalWire.d.ts +22 -10
- package/dist/hitl/toolApprovalWire.js +286 -47
- package/dist/hookMatcherVerdict.d.ts +1 -9
- package/dist/hookMatcherVerdict.js +21 -61
- package/dist/hooksWireCaps.js +2 -2
- package/dist/hostCallbackGuard.d.ts +1 -0
- package/dist/hostCallbackGuard.js +6 -0
- package/dist/index.d.ts +26 -12
- package/dist/index.js +20 -10
- package/dist/liveModelCatalog.d.ts +13 -0
- package/dist/liveModelCatalog.js +56 -0
- package/dist/mcpProbeCapability.d.ts +2 -4
- package/dist/mcpProbeCapability.js +3 -8
- package/dist/mcpWireCaps.d.ts +1 -0
- package/dist/mcpWireCaps.js +4 -1
- package/dist/memoryComplianceCapability.d.ts +2 -4
- package/dist/memoryComplianceCapability.js +3 -8
- package/dist/memoryOriginCapability.d.ts +2 -4
- package/dist/memoryOriginCapability.js +3 -8
- package/dist/memorySpecWire.js +2 -2
- package/dist/modelIdentityResolvability.d.ts +2 -2
- package/dist/modelIdentityResolvability.js +14 -5
- package/dist/noticePresentation.d.ts +68 -0
- package/dist/noticePresentation.js +247 -0
- package/dist/outputStyleSeatCapability.d.ts +2 -1
- package/dist/outputStyleSeatCapability.js +0 -4
- package/dist/ownKey.d.ts +2 -0
- package/dist/ownKey.js +18 -0
- package/dist/peerFrames.js +13 -9
- package/dist/peerLaneCapability.d.ts +2 -0
- package/dist/peerLaneCapability.js +3 -2
- package/dist/permissionModesCapability.d.ts +2 -4
- package/dist/permissionModesCapability.js +0 -7
- package/dist/permissionRuleIssue.js +0 -3
- package/dist/permissionRulesWriteCapability.d.ts +2 -0
- package/dist/permissionRulesWriteCapability.js +3 -2
- package/dist/permissionsAllowGrantCapability.d.ts +2 -0
- package/dist/permissionsAllowGrantCapability.js +4 -2
- package/dist/permissionsDeclaration.d.ts +2 -0
- package/dist/permissionsDeclaration.js +72 -59
- package/dist/printPermissionOutcome.d.ts +12 -0
- package/dist/printPermissionOutcome.js +50 -0
- package/dist/printToolResultFrame.d.ts +1 -0
- package/dist/printToolResultFrame.js +5 -9
- package/dist/promptBlockedCopy.d.ts +5 -0
- package/dist/promptBlockedCopy.js +35 -0
- package/dist/protocolSegment.d.ts +9 -6
- package/dist/protocolSegment.js +31 -21
- package/dist/providerRejection.d.ts +4 -0
- package/dist/providerRejection.js +75 -14
- package/dist/replayBody.d.ts +12 -0
- package/dist/replayBody.js +25 -0
- package/dist/request/taskRequest.d.ts +1 -4
- package/dist/request/taskRequest.js +74 -19
- package/dist/resumeRefusalCopy.js +9 -25
- package/dist/retryStatus.d.ts +9 -1
- package/dist/retryStatus.js +9 -2
- package/dist/rewindArchiveCapability.d.ts +3 -13
- package/dist/rewindArchiveCapability.js +12 -58
- package/dist/rewindArchiveReading.d.ts +17 -0
- package/dist/rewindArchiveReading.js +55 -0
- package/dist/ruleCompileVerdict.d.ts +9 -1
- package/dist/ruleCompileVerdict.js +29 -4
- package/dist/runTerminal.d.ts +48 -5
- package/dist/runTerminal.js +215 -12
- package/dist/sandboxWire.js +13 -0
- package/dist/sdkWireTransit.d.ts +2 -1
- package/dist/sdkWireTransit.js +1 -0
- package/dist/sealedKeyCapability.d.ts +2 -4
- package/dist/sealedKeyCapability.js +0 -7
- package/dist/seam.js +4 -2
- package/dist/seatContract.d.ts +76 -11
- package/dist/seatContract.js +222 -27
- package/dist/sessionPolicyCapability.d.ts +2 -0
- package/dist/sessionPolicyCapability.js +3 -2
- package/dist/sessionReadRedactionCapability.d.ts +2 -4
- package/dist/sessionReadRedactionCapability.js +0 -7
- package/dist/sessionSyncFileHistory.d.ts +4 -0
- package/dist/sessionSyncFileHistory.js +66 -0
- package/dist/sessionSyncFileHistoryCapability.d.ts +2 -1
- package/dist/sessionSyncFileHistoryCapability.js +3 -5
- package/dist/skillToolListsCapability.d.ts +2 -1
- package/dist/skillToolListsCapability.js +3 -5
- package/dist/sqlEngineCapability.d.ts +2 -0
- package/dist/sqlEngineCapability.js +4 -3
- package/dist/steerPriorityCapability.d.ts +2 -1
- package/dist/steerPriorityCapability.js +3 -5
- package/dist/storePostureCapability.d.ts +2 -4
- package/dist/storePostureCapability.js +4 -9
- package/dist/subagent/engineSubagentSteer.js +7 -5
- package/dist/subagentContentStore.js +4 -15
- package/dist/supportFloor.d.ts +1 -0
- package/dist/supportFloor.js +13 -9
- package/dist/systemReminderTag.d.ts +1 -0
- package/dist/systemReminderTag.js +8 -0
- package/dist/toolHistoryBadTurn.js +3 -2
- package/dist/toolHistoryMismatch.d.ts +0 -3
- package/dist/toolHistoryMismatch.js +3 -7
- package/dist/toolResult.d.ts +12 -1
- package/dist/toolResult.js +55 -1
- package/dist/toolResultContent.d.ts +2 -0
- package/dist/toolResultContent.js +63 -0
- package/dist/usageAnalytics.js +40 -16
- package/dist/userInvokedSkillsCapability.d.ts +2 -1
- package/dist/userInvokedSkillsCapability.js +3 -5
- package/dist/webSearchBackendCapability.d.ts +2 -0
- package/dist/webSearchBackendCapability.js +3 -2
- package/dist/wireErrorTriage.d.ts +2 -0
- package/dist/wireErrorTriage.js +91 -38
- package/dist/wireFailureShape.d.ts +20 -3
- package/dist/wireFailureShape.js +128 -72
- package/dist/workflowsJournalCapability.d.ts +2 -0
- package/dist/workflowsJournalCapability.js +3 -2
- package/dist/writeProtectionCapability.d.ts +2 -0
- package/dist/writeProtectionCapability.js +3 -2
- package/docs/INTEGRATION-CLIENTS.md +1784 -20
- package/package.json +5 -5
- package/dist/engineRefusedToolName.d.ts +0 -1
- package/dist/engineRefusedToolName.js +0 -8
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
interface EngineCapReaderSpec<R> {
|
|
2
2
|
name: string;
|
|
3
3
|
project: (caps: unknown) => R | undefined;
|
|
4
|
-
makeUnobserved: () => R;
|
|
5
4
|
}
|
|
5
|
+
type ReaderUnobserved = {
|
|
6
|
+
kind: 'unobserved';
|
|
7
|
+
};
|
|
8
|
+
type ReaderUnreadable = {
|
|
9
|
+
kind: 'unreadable';
|
|
10
|
+
};
|
|
6
11
|
interface EngineCapReader<R> {
|
|
7
12
|
note(baseUrl: string, caps: unknown, opts?: {
|
|
8
13
|
generation?: number;
|
|
9
14
|
}): void;
|
|
10
|
-
observed(baseUrl: string | undefined): R;
|
|
15
|
+
observed(baseUrl: string | undefined): R | ReaderUnobserved | ReaderUnreadable;
|
|
11
16
|
__resetForTests(): void;
|
|
12
17
|
}
|
|
13
18
|
export declare function createEngineCapReader<R>(spec: EngineCapReaderSpec<R>): EngineCapReader<R>;
|
|
19
|
+
export declare function unreadableReadingDetail(subject?: string): string;
|
|
14
20
|
export type StoreSeat = {
|
|
15
21
|
kind: 'object';
|
|
16
22
|
store: object;
|
package/dist/engineCapReader.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { engineCapsLandingOf } from './engineCapsCache.js';
|
|
2
2
|
import { ownDataField } from './ownKey.js';
|
|
3
|
+
const unobserved = () => ({ kind: 'unobserved' });
|
|
4
|
+
const unreadable = () => ({ kind: 'unreadable' });
|
|
3
5
|
function freezeReading(reading, seen = new Set()) {
|
|
4
6
|
if (reading === null || typeof reading !== 'object' || seen.has(reading))
|
|
5
7
|
return reading;
|
|
@@ -18,15 +20,17 @@ export function createEngineCapReader(spec) {
|
|
|
18
20
|
note(_baseUrl, _caps, _opts) { },
|
|
19
21
|
observed(baseUrl) {
|
|
20
22
|
if (typeof baseUrl !== 'string' || baseUrl === '')
|
|
21
|
-
return
|
|
23
|
+
return unobserved();
|
|
22
24
|
const landing = engineCapsLandingOf(baseUrl);
|
|
23
|
-
if (landing ===
|
|
24
|
-
return
|
|
25
|
+
if (landing.kind === 'not_landed')
|
|
26
|
+
return unobserved();
|
|
27
|
+
if (landing.kind === 'unreadable')
|
|
28
|
+
return unreadable();
|
|
25
29
|
const hit = memo.get(landing);
|
|
26
30
|
if (hit === PROJECTING)
|
|
27
|
-
return
|
|
31
|
+
return unobserved();
|
|
28
32
|
if (hit !== undefined)
|
|
29
|
-
return hit.reading === undefined ?
|
|
33
|
+
return hit.reading === undefined ? unreadable() : hit.reading;
|
|
30
34
|
const mine = memo;
|
|
31
35
|
mine.set(landing, PROJECTING);
|
|
32
36
|
let reading;
|
|
@@ -38,17 +42,21 @@ export function createEngineCapReader(spec) {
|
|
|
38
42
|
}
|
|
39
43
|
if (engineCapsLandingOf(baseUrl) !== landing) {
|
|
40
44
|
mine.delete(landing);
|
|
41
|
-
return
|
|
45
|
+
return unobserved();
|
|
42
46
|
}
|
|
43
47
|
const done = { reading: reading === undefined ? undefined : freezeReading(reading) };
|
|
44
48
|
mine.set(landing, done);
|
|
45
|
-
return done.reading === undefined ?
|
|
49
|
+
return done.reading === undefined ? unreadable() : done.reading;
|
|
46
50
|
},
|
|
47
51
|
__resetForTests() {
|
|
48
52
|
memo = new WeakMap();
|
|
49
53
|
},
|
|
50
54
|
};
|
|
51
55
|
}
|
|
56
|
+
export function unreadableReadingDetail(subject) {
|
|
57
|
+
const head = typeof subject === 'string' && subject.length > 0 ? `${subject} could not be read` : 'could not be read';
|
|
58
|
+
return `${head} — the engine's /v1/capabilities report arrived, but this entry is not in a form this client reads, so it is shown as unknown, not as absent; probing the same engine again will not change it while the engine reports it this way`;
|
|
59
|
+
}
|
|
52
60
|
export function storeSeatOf(caps) {
|
|
53
61
|
try {
|
|
54
62
|
const store = ownDataField(caps, 'store');
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
export type EngineCapsLanding = {
|
|
2
|
+
readonly kind: 'landed';
|
|
3
|
+
readonly caps: Readonly<Record<string, unknown>>;
|
|
4
|
+
} | {
|
|
5
|
+
readonly kind: 'not_landed';
|
|
6
|
+
} | {
|
|
7
|
+
readonly kind: 'unreadable';
|
|
8
|
+
};
|
|
1
9
|
export declare function engineCapsGeneration(baseUrl: string): number;
|
|
2
|
-
export declare function engineCapsLandingOf(baseUrl: string):
|
|
3
|
-
readonly caps: object;
|
|
4
|
-
} | undefined;
|
|
10
|
+
export declare function engineCapsLandingOf(baseUrl: string | undefined): EngineCapsLanding;
|
|
5
11
|
export declare function kickEngineCapsProbe(baseUrl: string, probe: () => Promise<unknown>): void;
|
|
6
12
|
export declare function engineCapsSettled(baseUrl: string | undefined, opts?: {
|
|
7
13
|
withinMs?: number;
|
|
@@ -14,10 +20,13 @@ export declare function engineCapStateVia(baseUrl: string | undefined, key: stri
|
|
|
14
20
|
}): Promise<EngineCapState>;
|
|
15
21
|
export declare function engineCapTrue(baseUrl: string | undefined, key: string): boolean;
|
|
16
22
|
export declare function engineCapNestedTrue(baseUrl: string | undefined, parentKey: string, key: string): boolean;
|
|
23
|
+
export declare function engineCapNestedValue(baseUrl: string | undefined, parentKey: string, key: string): EngineCapValueState;
|
|
17
24
|
export type EngineCapValueState = {
|
|
18
25
|
kind: 'unobserved';
|
|
19
26
|
} | {
|
|
20
27
|
kind: 'not_reported';
|
|
28
|
+
} | {
|
|
29
|
+
kind: 'unreadable';
|
|
21
30
|
} | {
|
|
22
31
|
kind: 'null';
|
|
23
32
|
} | {
|
|
@@ -27,4 +36,9 @@ export type EngineCapValueState = {
|
|
|
27
36
|
export declare function engineCapValue(baseUrl: string | undefined, key: string): EngineCapValueState;
|
|
28
37
|
export declare function engineCapString(baseUrl: string | undefined, key: string): string | undefined;
|
|
29
38
|
export declare function invalidateEngineCaps(baseUrl: string | undefined, probe?: () => Promise<unknown>): void;
|
|
39
|
+
export type EngineCapsProbeRotation = 'started' | 'registered' | 'ignored';
|
|
40
|
+
export declare function rotateEngineCapsProbe(baseUrl: string | undefined, probe: () => Promise<unknown>): EngineCapsProbeRotation;
|
|
41
|
+
export declare function refreshEngineCapsOnce(baseUrl: string | undefined, opts?: {
|
|
42
|
+
withinMs?: number;
|
|
43
|
+
}): Promise<'settled' | 'timed_out' | 'no_probe'>;
|
|
30
44
|
export declare function __resetEngineCapsCacheForTests(): void;
|
package/dist/engineCapsCache.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import { settleWithinDeadline } from './abortableSleep.js';
|
|
2
|
+
import { ownDataField } from './ownKey.js';
|
|
3
|
+
const NOT_LANDED = Object.freeze({ kind: 'not_landed' });
|
|
1
4
|
const capsByBase = new Map();
|
|
2
5
|
const inFlight = new Set();
|
|
3
6
|
const settleByBase = new Map();
|
|
4
7
|
const genByBase = new Map();
|
|
8
|
+
const probeByBase = new Map();
|
|
9
|
+
const refreshByBase = new Map();
|
|
5
10
|
function capsGeneration(baseUrl) {
|
|
6
11
|
return genByBase.get(baseUrl) ?? 0;
|
|
7
12
|
}
|
|
@@ -9,11 +14,17 @@ export function engineCapsGeneration(baseUrl) {
|
|
|
9
14
|
return capsGeneration(baseUrl);
|
|
10
15
|
}
|
|
11
16
|
export function engineCapsLandingOf(baseUrl) {
|
|
12
|
-
|
|
17
|
+
if (typeof baseUrl !== 'string' || baseUrl === '')
|
|
18
|
+
return NOT_LANDED;
|
|
19
|
+
return capsByBase.get(baseUrl) ?? NOT_LANDED;
|
|
13
20
|
}
|
|
14
21
|
export function kickEngineCapsProbe(baseUrl, probe) {
|
|
22
|
+
startEngineCapsProbe(baseUrl, probe);
|
|
23
|
+
}
|
|
24
|
+
function startEngineCapsProbe(baseUrl, probe) {
|
|
15
25
|
if (!baseUrl || capsByBase.has(baseUrl) || inFlight.has(baseUrl))
|
|
16
|
-
return;
|
|
26
|
+
return false;
|
|
27
|
+
probeByBase.set(baseUrl, probe);
|
|
17
28
|
const gen = capsGeneration(baseUrl);
|
|
18
29
|
inFlight.add(baseUrl);
|
|
19
30
|
let wake = () => { };
|
|
@@ -30,9 +41,7 @@ export function kickEngineCapsProbe(baseUrl, probe) {
|
|
|
30
41
|
const caps = await probe();
|
|
31
42
|
if (gen !== capsGeneration(baseUrl))
|
|
32
43
|
return;
|
|
33
|
-
|
|
34
|
-
capsByBase.set(baseUrl, Object.freeze({ caps: caps }));
|
|
35
|
-
}
|
|
44
|
+
landCapsSnapshot(baseUrl, gen, caps);
|
|
36
45
|
}
|
|
37
46
|
catch {
|
|
38
47
|
}
|
|
@@ -45,6 +54,7 @@ export function kickEngineCapsProbe(baseUrl, probe) {
|
|
|
45
54
|
markSettled();
|
|
46
55
|
}
|
|
47
56
|
})();
|
|
57
|
+
return true;
|
|
48
58
|
}
|
|
49
59
|
const MAX_WITHIN_MS = 2_147_483_647;
|
|
50
60
|
function waitBudgetOf(opts) {
|
|
@@ -114,25 +124,152 @@ export async function engineCapsSettled(baseUrl, opts) {
|
|
|
114
124
|
}
|
|
115
125
|
}
|
|
116
126
|
export function engineCapState(baseUrl, key) {
|
|
117
|
-
|
|
118
|
-
return 'unprobed';
|
|
119
|
-
return capStateIn(capsByBase.get(baseUrl)?.caps, key);
|
|
127
|
+
return stateOfSlot(slotInLanding(engineCapsLandingOf(baseUrl), key));
|
|
120
128
|
}
|
|
121
|
-
|
|
129
|
+
const SNAPSHOT_MAX_DEPTH = 64;
|
|
130
|
+
const SNAPSHOT_MAX_NODES = 100_000;
|
|
131
|
+
const SNAPSHOT_PROBE_KEY = '\u0000capabilities-snapshot-probe\u0000';
|
|
132
|
+
const FOREIGN_PROTOTYPE = Object.freeze(Object.create(null));
|
|
133
|
+
function unreadableError() {
|
|
134
|
+
return new TypeError('capabilities body position is not readable (accessor or throwing proxy)');
|
|
135
|
+
}
|
|
136
|
+
const UNREADABLE_NODE = new Proxy(Object.freeze({}), {
|
|
137
|
+
getOwnPropertyDescriptor: () => {
|
|
138
|
+
throw unreadableError();
|
|
139
|
+
},
|
|
140
|
+
ownKeys: () => {
|
|
141
|
+
throw unreadableError();
|
|
142
|
+
},
|
|
143
|
+
has: () => {
|
|
144
|
+
throw unreadableError();
|
|
145
|
+
},
|
|
146
|
+
get: () => {
|
|
147
|
+
throw unreadableError();
|
|
148
|
+
},
|
|
149
|
+
getPrototypeOf: () => {
|
|
150
|
+
throw unreadableError();
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
function throwingAccessor() {
|
|
154
|
+
return {
|
|
155
|
+
get: () => {
|
|
156
|
+
throw unreadableError();
|
|
157
|
+
},
|
|
158
|
+
enumerable: true,
|
|
159
|
+
configurable: false,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function landCapsSnapshot(baseUrl, gen, caps) {
|
|
163
|
+
if (!isPlainCapsBody(caps))
|
|
164
|
+
return 'not_a_record';
|
|
165
|
+
const snapshot = snapshotCapsBody(caps);
|
|
166
|
+
if (gen !== capsGeneration(baseUrl))
|
|
167
|
+
return 'superseded';
|
|
168
|
+
const record = snapshot === UNREADABLE_NODE
|
|
169
|
+
? Object.freeze({ kind: 'unreadable' })
|
|
170
|
+
: Object.freeze({ kind: 'landed', caps: snapshot });
|
|
171
|
+
capsByBase.set(baseUrl, record);
|
|
172
|
+
return 'landed';
|
|
173
|
+
}
|
|
174
|
+
function snapshotCapsBody(body) {
|
|
175
|
+
if (body === null || typeof body !== 'object')
|
|
176
|
+
return body;
|
|
177
|
+
const seen = new WeakMap();
|
|
178
|
+
let nodes = 0;
|
|
179
|
+
const copy = (src, depth) => {
|
|
180
|
+
const known = seen.get(src);
|
|
181
|
+
if (known !== undefined)
|
|
182
|
+
return known;
|
|
183
|
+
if (depth > SNAPSHOT_MAX_DEPTH || ++nodes > SNAPSHOT_MAX_NODES)
|
|
184
|
+
return UNREADABLE_NODE;
|
|
185
|
+
let keys;
|
|
186
|
+
let out;
|
|
187
|
+
let isArray;
|
|
188
|
+
try {
|
|
189
|
+
isArray = Array.isArray(src);
|
|
190
|
+
keys = Object.getOwnPropertyNames(src);
|
|
191
|
+
Object.getOwnPropertyDescriptor(src, SNAPSHOT_PROBE_KEY);
|
|
192
|
+
let length = 0;
|
|
193
|
+
if (isArray) {
|
|
194
|
+
const ld = Object.getOwnPropertyDescriptor(src, 'length');
|
|
195
|
+
if (ld === undefined || !Object.hasOwn(ld, 'value') || typeof ld.value !== 'number')
|
|
196
|
+
return UNREADABLE_NODE;
|
|
197
|
+
length = ld.value;
|
|
198
|
+
}
|
|
199
|
+
const proto = isArray ? null : Object.getPrototypeOf(src);
|
|
200
|
+
out = isArray ? new Array(length) : proto === Object.prototype || proto === null ? {} : Object.create(FOREIGN_PROTOTYPE);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return UNREADABLE_NODE;
|
|
204
|
+
}
|
|
205
|
+
seen.set(src, out);
|
|
206
|
+
for (const k of keys) {
|
|
207
|
+
if (isArray && k === 'length')
|
|
208
|
+
continue;
|
|
209
|
+
let d;
|
|
210
|
+
try {
|
|
211
|
+
d = Object.getOwnPropertyDescriptor(src, k);
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
Object.defineProperty(out, k, throwingAccessor());
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (d === undefined)
|
|
218
|
+
continue;
|
|
219
|
+
if (!Object.hasOwn(d, 'value')) {
|
|
220
|
+
Object.defineProperty(out, k, throwingAccessor());
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
const v = d.value;
|
|
224
|
+
Object.defineProperty(out, k, {
|
|
225
|
+
value: v !== null && typeof v === 'object' ? copy(v, depth + 1) : v,
|
|
226
|
+
enumerable: d.enumerable === true,
|
|
227
|
+
writable: false,
|
|
228
|
+
configurable: false,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
Object.freeze(out);
|
|
232
|
+
return out;
|
|
233
|
+
};
|
|
234
|
+
return copy(body, 0);
|
|
235
|
+
}
|
|
236
|
+
const SLOT_UNOBSERVED = Object.freeze({ kind: 'unobserved' });
|
|
237
|
+
const SLOT_ABSENT = Object.freeze({ kind: 'absent' });
|
|
238
|
+
const SLOT_UNREADABLE = Object.freeze({ kind: 'unreadable' });
|
|
239
|
+
function capSlotIn(caps, key) {
|
|
122
240
|
if (caps === undefined || caps === null || typeof caps !== 'object')
|
|
123
|
-
return
|
|
241
|
+
return SLOT_UNOBSERVED;
|
|
124
242
|
try {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const v = caps[key];
|
|
128
|
-
if (v === true)
|
|
129
|
-
return 'true';
|
|
130
|
-
if (v === false)
|
|
131
|
-
return 'false';
|
|
132
|
-
return 'non_boolean';
|
|
243
|
+
const v = ownDataField(caps, key);
|
|
244
|
+
return v === undefined ? SLOT_ABSENT : { kind: 'present', value: v };
|
|
133
245
|
}
|
|
134
246
|
catch {
|
|
135
|
-
return
|
|
247
|
+
return SLOT_UNREADABLE;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function slotInLanding(landing, key) {
|
|
251
|
+
switch (landing.kind) {
|
|
252
|
+
case 'not_landed':
|
|
253
|
+
return SLOT_UNOBSERVED;
|
|
254
|
+
case 'unreadable':
|
|
255
|
+
return SLOT_UNREADABLE;
|
|
256
|
+
case 'landed':
|
|
257
|
+
return capSlotIn(landing.caps, key);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function capStateIn(caps, key) {
|
|
261
|
+
return stateOfSlot(capSlotIn(caps, key));
|
|
262
|
+
}
|
|
263
|
+
function stateOfSlot(slot) {
|
|
264
|
+
switch (slot.kind) {
|
|
265
|
+
case 'unobserved':
|
|
266
|
+
return 'unprobed';
|
|
267
|
+
case 'absent':
|
|
268
|
+
return 'absent';
|
|
269
|
+
case 'unreadable':
|
|
270
|
+
return 'non_boolean';
|
|
271
|
+
case 'present':
|
|
272
|
+
return slot.value === true ? 'true' : slot.value === false ? 'false' : 'non_boolean';
|
|
136
273
|
}
|
|
137
274
|
}
|
|
138
275
|
async function untilSettledOrAborted(p, signal) {
|
|
@@ -161,7 +298,8 @@ export async function engineCapStateVia(baseUrl, key, probe, opts) {
|
|
|
161
298
|
try {
|
|
162
299
|
if (signal?.aborted)
|
|
163
300
|
return 'unprobed';
|
|
164
|
-
|
|
301
|
+
const body = await probe(signal);
|
|
302
|
+
return isPlainCapsBody(body) ? capStateIn(body, key) : 'unprobed';
|
|
165
303
|
}
|
|
166
304
|
catch {
|
|
167
305
|
return 'unprobed';
|
|
@@ -178,37 +316,42 @@ export function engineCapTrue(baseUrl, key) {
|
|
|
178
316
|
return engineCapState(baseUrl, key) === 'true';
|
|
179
317
|
}
|
|
180
318
|
export function engineCapNestedTrue(baseUrl, parentKey, key) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const parent = capsByBase.get(baseUrl)?.caps[parentKey];
|
|
184
|
-
if (parent === null || typeof parent !== 'object')
|
|
185
|
-
return false;
|
|
186
|
-
return parent[key] === true;
|
|
319
|
+
const state = engineCapNestedValue(baseUrl, parentKey, key);
|
|
320
|
+
return state.kind === 'value' && state.value === true;
|
|
187
321
|
}
|
|
188
|
-
export function
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (!(key in caps))
|
|
322
|
+
export function engineCapNestedValue(baseUrl, parentKey, key) {
|
|
323
|
+
const parent = slotInLanding(engineCapsLandingOf(baseUrl), parentKey);
|
|
324
|
+
if (parent.kind !== 'present')
|
|
325
|
+
return valueStateOfSlot(parent);
|
|
326
|
+
const group = parent.value;
|
|
327
|
+
if (group === null || typeof group !== 'object')
|
|
195
328
|
return { kind: 'not_reported' };
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
329
|
+
return valueStateOfSlot(capSlotIn(group, key));
|
|
330
|
+
}
|
|
331
|
+
export function engineCapValue(baseUrl, key) {
|
|
332
|
+
return valueStateOfSlot(slotInLanding(engineCapsLandingOf(baseUrl), key));
|
|
333
|
+
}
|
|
334
|
+
function valueStateOfSlot(slot) {
|
|
335
|
+
switch (slot.kind) {
|
|
336
|
+
case 'unobserved':
|
|
337
|
+
return { kind: 'unobserved' };
|
|
338
|
+
case 'absent':
|
|
339
|
+
return { kind: 'not_reported' };
|
|
340
|
+
case 'unreadable':
|
|
341
|
+
return { kind: 'unreadable' };
|
|
342
|
+
case 'present':
|
|
343
|
+
return slot.value === null ? { kind: 'null' } : { kind: 'value', value: slot.value };
|
|
344
|
+
}
|
|
202
345
|
}
|
|
203
346
|
export function engineCapString(baseUrl, key) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const v = capsByBase.get(baseUrl)?.caps[key];
|
|
207
|
-
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
347
|
+
const slot = slotInLanding(engineCapsLandingOf(baseUrl), key);
|
|
348
|
+
return slot.kind === 'present' && typeof slot.value === 'string' && slot.value.length > 0 ? slot.value : undefined;
|
|
208
349
|
}
|
|
209
350
|
export function invalidateEngineCaps(baseUrl, probe) {
|
|
210
351
|
if (!baseUrl)
|
|
211
352
|
return;
|
|
353
|
+
if (probe === undefined)
|
|
354
|
+
probeByBase.delete(baseUrl);
|
|
212
355
|
const hadState = capsByBase.has(baseUrl) ||
|
|
213
356
|
inFlight.has(baseUrl) ||
|
|
214
357
|
settleByBase.has(baseUrl) ||
|
|
@@ -222,9 +365,91 @@ export function invalidateEngineCaps(baseUrl, probe) {
|
|
|
222
365
|
if (probe !== undefined)
|
|
223
366
|
kickEngineCapsProbe(baseUrl, probe);
|
|
224
367
|
}
|
|
368
|
+
export function rotateEngineCapsProbe(baseUrl, probe) {
|
|
369
|
+
try {
|
|
370
|
+
if (typeof baseUrl !== 'string' || baseUrl === '' || typeof probe !== 'function')
|
|
371
|
+
return 'ignored';
|
|
372
|
+
if (startEngineCapsProbe(baseUrl, probe))
|
|
373
|
+
return 'started';
|
|
374
|
+
probeByBase.set(baseUrl, probe);
|
|
375
|
+
return 'registered';
|
|
376
|
+
}
|
|
377
|
+
catch {
|
|
378
|
+
return 'ignored';
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
export async function refreshEngineCapsOnce(baseUrl, opts) {
|
|
382
|
+
try {
|
|
383
|
+
if (typeof baseUrl !== 'string' || baseUrl === '')
|
|
384
|
+
return 'no_probe';
|
|
385
|
+
const budget = waitBudgetOf(opts);
|
|
386
|
+
const probe = probeByBase.get(baseUrl);
|
|
387
|
+
if (probe === undefined)
|
|
388
|
+
return 'no_probe';
|
|
389
|
+
const flying = refreshByBase.get(baseUrl);
|
|
390
|
+
if (flying !== undefined && flying.gen === capsGeneration(baseUrl))
|
|
391
|
+
return await awaitRefreshWithin(flying, budget);
|
|
392
|
+
if (!capsByBase.has(baseUrl)) {
|
|
393
|
+
kickEngineCapsProbe(baseUrl, probe);
|
|
394
|
+
return await engineCapsSettled(baseUrl, budget === undefined ? undefined : { withinMs: budget });
|
|
395
|
+
}
|
|
396
|
+
const gen = capsGeneration(baseUrl);
|
|
397
|
+
let finish = () => { };
|
|
398
|
+
const entry = { gen, promise: new Promise((resolve) => { finish = resolve; }) };
|
|
399
|
+
refreshByBase.set(baseUrl, entry);
|
|
400
|
+
void (async () => {
|
|
401
|
+
try {
|
|
402
|
+
const caps = await probe();
|
|
403
|
+
if (gen !== capsGeneration(baseUrl) || !capsByBase.has(baseUrl))
|
|
404
|
+
return false;
|
|
405
|
+
return landCapsSnapshot(baseUrl, gen, caps) === 'landed';
|
|
406
|
+
}
|
|
407
|
+
catch {
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
finally {
|
|
411
|
+
if (refreshByBase.get(baseUrl) === entry)
|
|
412
|
+
refreshByBase.delete(baseUrl);
|
|
413
|
+
}
|
|
414
|
+
})().then(finish);
|
|
415
|
+
return await awaitRefreshWithin(entry, budget);
|
|
416
|
+
}
|
|
417
|
+
catch {
|
|
418
|
+
return 'timed_out';
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
function isPlainCapsBody(caps) {
|
|
422
|
+
try {
|
|
423
|
+
if (typeof caps !== 'object' || caps === null)
|
|
424
|
+
return false;
|
|
425
|
+
if (Array.isArray(caps))
|
|
426
|
+
return false;
|
|
427
|
+
const proto = Object.getPrototypeOf(caps);
|
|
428
|
+
if (proto !== null && Object.getPrototypeOf(proto) !== null)
|
|
429
|
+
return false;
|
|
430
|
+
for (const key of Reflect.ownKeys(caps))
|
|
431
|
+
Object.getOwnPropertyDescriptor(caps, key);
|
|
432
|
+
return true;
|
|
433
|
+
}
|
|
434
|
+
catch {
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
async function awaitRefreshWithin(entry, budget) {
|
|
439
|
+
if (budget === undefined) {
|
|
440
|
+
await entry.promise;
|
|
441
|
+
return 'settled';
|
|
442
|
+
}
|
|
443
|
+
if (budget === 0)
|
|
444
|
+
return 'timed_out';
|
|
445
|
+
const out = await settleWithinDeadline(budget, () => entry.promise);
|
|
446
|
+
return out.kind === 'deadline' ? 'timed_out' : 'settled';
|
|
447
|
+
}
|
|
225
448
|
export function __resetEngineCapsCacheForTests() {
|
|
226
449
|
capsByBase.clear();
|
|
227
450
|
inFlight.clear();
|
|
228
451
|
settleByBase.clear();
|
|
229
452
|
genByBase.clear();
|
|
453
|
+
probeByBase.clear();
|
|
454
|
+
refreshByBase.clear();
|
|
230
455
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
declare const KIND_WORDS: readonly ["managed"];
|
|
2
|
+
declare const POSTURE_WORDS: readonly ["single", "multi"];
|
|
3
|
+
declare const RULE_WORDS: readonly ["only-one", "none", "ambiguous"];
|
|
4
|
+
export type EngineKindWord = (typeof KIND_WORDS)[number];
|
|
5
|
+
export type EnginePostureWord = (typeof POSTURE_WORDS)[number];
|
|
6
|
+
export type MeEngineRuleWord = (typeof RULE_WORDS)[number];
|
|
7
|
+
export type OpenWordReading<K extends string> = {
|
|
8
|
+
readonly kind: 'listed';
|
|
9
|
+
readonly word: K;
|
|
10
|
+
} | {
|
|
11
|
+
readonly kind: 'unlisted';
|
|
12
|
+
readonly word: string;
|
|
13
|
+
} | {
|
|
14
|
+
readonly kind: 'unreadable';
|
|
15
|
+
};
|
|
16
|
+
export interface EngineRowReading {
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly kind: OpenWordReading<EngineKindWord>;
|
|
19
|
+
readonly scope: string | undefined;
|
|
20
|
+
readonly online: boolean | undefined;
|
|
21
|
+
readonly posture: OpenWordReading<EnginePostureWord>;
|
|
22
|
+
readonly viaCenter: string;
|
|
23
|
+
}
|
|
24
|
+
export interface EngineRowSet {
|
|
25
|
+
readonly rows: readonly EngineRowReading[];
|
|
26
|
+
readonly unreadableRows: number;
|
|
27
|
+
readonly unreadableNames: readonly string[];
|
|
28
|
+
}
|
|
29
|
+
export type MeEngineTargetReading = {
|
|
30
|
+
readonly kind: 'row';
|
|
31
|
+
readonly row: EngineRowReading;
|
|
32
|
+
} | {
|
|
33
|
+
readonly kind: 'null';
|
|
34
|
+
} | {
|
|
35
|
+
readonly kind: 'unreadable';
|
|
36
|
+
};
|
|
37
|
+
export interface MeEngineReading {
|
|
38
|
+
readonly rule: OpenWordReading<MeEngineRuleWord>;
|
|
39
|
+
readonly target: MeEngineTargetReading;
|
|
40
|
+
readonly candidates: EngineRowSet | undefined;
|
|
41
|
+
}
|
|
42
|
+
export type MeEngineUnresolvedReason = 'body' | 'rule' | 'rule-unlisted' | 'target' | 'candidates' | 'conflict';
|
|
43
|
+
export type MeEngineDecision = {
|
|
44
|
+
readonly kind: 'connect';
|
|
45
|
+
readonly engine: EngineRowReading;
|
|
46
|
+
readonly rule: OpenWordReading<MeEngineRuleWord>;
|
|
47
|
+
} | {
|
|
48
|
+
readonly kind: 'no-engine';
|
|
49
|
+
} | {
|
|
50
|
+
readonly kind: 'choose';
|
|
51
|
+
readonly candidates: EngineRowSet;
|
|
52
|
+
} | {
|
|
53
|
+
readonly kind: 'unresolved';
|
|
54
|
+
readonly reason: MeEngineUnresolvedReason;
|
|
55
|
+
readonly rule: OpenWordReading<MeEngineRuleWord>;
|
|
56
|
+
readonly candidates: EngineRowSet | undefined;
|
|
57
|
+
};
|
|
58
|
+
export type EngineOverrideDecision = {
|
|
59
|
+
readonly kind: 'select';
|
|
60
|
+
readonly engine: EngineRowReading;
|
|
61
|
+
} | {
|
|
62
|
+
readonly kind: 'not-listed';
|
|
63
|
+
readonly candidates: EngineRowSet;
|
|
64
|
+
} | {
|
|
65
|
+
readonly kind: 'duplicate';
|
|
66
|
+
readonly name: string;
|
|
67
|
+
} | {
|
|
68
|
+
readonly kind: 'row-unreadable';
|
|
69
|
+
readonly name: string;
|
|
70
|
+
} | {
|
|
71
|
+
readonly kind: 'unreadable';
|
|
72
|
+
} | {
|
|
73
|
+
readonly kind: 'invalid';
|
|
74
|
+
};
|
|
75
|
+
export declare function projectEngineDirectory(body: unknown): EngineRowSet | undefined;
|
|
76
|
+
export declare function projectMeEngine(body: unknown): MeEngineReading | undefined;
|
|
77
|
+
export declare function decideMeEngine(reading: MeEngineReading | undefined): MeEngineDecision;
|
|
78
|
+
export declare function engineOverrideOf(set: EngineRowSet | undefined, requested: unknown): EngineOverrideDecision;
|
|
79
|
+
export {};
|