@sema-agent/client-core 0.107.0 → 0.109.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 +239 -0
- package/README.md +54 -36
- package/dist/adapt/arms.js +23 -8
- package/dist/adapt/textStream.d.ts +2 -0
- package/dist/adapt/textStream.js +37 -16
- package/dist/adapter/activeRunSelfHeal.d.ts +2 -0
- package/dist/adapter/activeRunSelfHeal.js +21 -4
- package/dist/adapter/downstream/eventToSdkMessage.js +2 -1
- package/dist/agentSession/engineAgentRegistryRead.js +2 -0
- package/dist/bashExitReading.d.ts +12 -0
- package/dist/bashExitReading.js +44 -0
- package/dist/checkpointRowVerdict.d.ts +6 -1
- package/dist/checkpointRowVerdict.js +30 -2
- package/dist/cloudConfigWireCaps.d.ts +10 -0
- package/dist/cloudConfigWireCaps.js +33 -0
- package/dist/compensations.js +1 -1
- package/dist/coreValuePorts.d.ts +17 -1
- package/dist/coreValuePorts.js +5 -0
- package/dist/decideReceipt.js +2 -1
- package/dist/engineAgentAbsence.d.ts +2 -0
- package/dist/engineAgentAbsence.js +28 -0
- package/dist/engineErrorCodes.d.ts +9 -0
- package/dist/engineErrorCodes.js +9 -0
- package/dist/engineHealthFacts.d.ts +17 -0
- package/dist/engineHealthFacts.js +42 -3
- package/dist/engineNoticeCodes.d.ts +147 -1
- package/dist/engineNoticeCodes.js +694 -57
- package/dist/engineTargetSeat.js +1 -0
- package/dist/errorSupplementRoles.js +6 -1
- package/dist/eventLeg.js +1 -1
- package/dist/executionLaneWords.js +2 -1
- package/dist/fleetTaskDesc.js +3 -3
- package/dist/gateOutcome.d.ts +10 -1
- package/dist/gateOutcome.js +48 -1
- package/dist/generated/engineFactTables.d.ts +2 -0
- package/dist/generated/engineFactTables.js +11 -0
- package/dist/generated/engineNoticeTables.js +6 -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/approvalCardReasons.js +22 -4
- package/dist/hitl/approvalRequestFrameReading.d.ts +14 -0
- package/dist/hitl/approvalRequestFrameReading.js +79 -0
- package/dist/hitl/approvalResolution.d.ts +3 -0
- package/dist/hitl/approvalResolution.js +22 -4
- package/dist/hitl/approvalsFeed.js +4 -13
- package/dist/hitl/askParkRowRouting.js +10 -3
- package/dist/hitl/automaticAnswerVerdict.d.ts +5 -2
- package/dist/hitl/automaticAnswerVerdict.js +16 -2
- package/dist/hitl/decisionConflict.d.ts +2 -1
- package/dist/hitl/decisionConflict.js +4 -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 +37 -7
- package/dist/hitl/gateLedger.d.ts +2 -0
- package/dist/hitl/gateLedger.js +3 -1
- package/dist/hitl/hitlBridge.d.ts +4 -0
- package/dist/hitl/hitlBridge.js +11 -8
- package/dist/hitl/livePendingAsk.js +17 -16
- package/dist/hitl/localAllowRule.js +2 -1
- package/dist/hitl/noAllowCause.d.ts +1 -1
- package/dist/hitl/noAllowCause.js +4 -2
- package/dist/hitl/parkExpiryJudgements.js +26 -1
- package/dist/hitl/parkOwnership.d.ts +2 -0
- package/dist/hitl/parkOwnership.js +48 -8
- package/dist/hitl/parkResolver.js +39 -30
- package/dist/hitl/parkRowBirthWait.d.ts +2 -0
- package/dist/hitl/parkRowBirthWait.js +8 -1
- package/dist/hitl/parkedUnresumable.d.ts +13 -0
- package/dist/hitl/parkedUnresumable.js +80 -0
- package/dist/hitl/permissionRuleScope.d.ts +4 -0
- package/dist/hitl/permissionRuleScope.js +31 -0
- package/dist/hitl/persistedRulesWire.d.ts +7 -1
- package/dist/hitl/persistedRulesWire.js +25 -8
- 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/sessionAllowRoute.js +5 -4
- package/dist/hitl/sessionPolicyDeliverable.js +1 -1
- package/dist/hitl/standingRows.d.ts +1 -5
- package/dist/hitl/standingRows.js +15 -14
- package/dist/hitl/toolApprovalWire.d.ts +16 -4
- package/dist/hitl/toolApprovalWire.js +57 -17
- package/dist/hooksReaderGenerations.d.ts +1 -0
- package/dist/hooksReaderGenerations.js +12 -0
- package/dist/hooksWireCaps.js +12 -7
- package/dist/hostSettingsSource.js +2 -0
- package/dist/i18n/messages.en.d.ts +206 -1
- package/dist/i18n/messages.en.js +209 -4
- package/dist/i18n/messages.zh.js +214 -4
- package/dist/index.d.ts +35 -8
- package/dist/index.js +20 -5
- package/dist/liveModelCatalog.d.ts +4 -2
- package/dist/liveModelCatalog.js +164 -26
- package/dist/localEngineJudge.d.ts +75 -0
- package/dist/localEngineJudge.js +242 -0
- package/dist/localEngineOccupancy.d.ts +88 -0
- package/dist/localEngineOccupancy.js +269 -0
- package/dist/localEngineSeatReading.d.ts +29 -0
- package/dist/localEngineSeatReading.js +294 -0
- package/dist/localEngineSpawn.d.ts +113 -0
- package/dist/localEngineSpawn.js +486 -0
- package/dist/localEngineStep.d.ts +286 -0
- package/dist/localEngineStep.js +1086 -0
- package/dist/localEngineStopLadder.d.ts +29 -0
- package/dist/localEngineStopLadder.js +139 -0
- package/dist/localEngineSwapCard.d.ts +43 -0
- package/dist/localEngineSwapCard.js +205 -0
- package/dist/localEngineTiming.d.ts +8 -0
- package/dist/localEngineTiming.js +8 -0
- package/dist/mcpReconnect.js +12 -5
- package/dist/mcpWireCaps.js +2 -2
- package/dist/memoryEntriesWire.d.ts +1 -1
- package/dist/memoryEntriesWire.js +5 -0
- package/dist/model/catalogDefault.d.ts +25 -0
- package/dist/model/catalogDefault.js +44 -0
- package/dist/noticePresentation.d.ts +2 -0
- package/dist/noticePresentation.js +79 -1
- package/dist/ownKey.d.ts +10 -0
- package/dist/ownKey.js +15 -1
- 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/ruleReadings.js +1 -1
- package/dist/runPermissionModeSwitch.d.ts +2 -1
- package/dist/runPermissionModeSwitch.js +16 -6
- package/dist/seam.d.ts +13 -2
- package/dist/seam.js +8 -1
- package/dist/seatContract.d.ts +103 -12
- package/dist/seatContract.js +344 -14
- package/dist/sessionBackground.js +2 -0
- 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.d.ts +12 -0
- package/dist/subagentContentStore.js +73 -12
- package/dist/supportFloor.js +2 -0
- package/dist/taskNotificationAdmission.d.ts +19 -0
- package/dist/taskNotificationAdmission.js +84 -0
- package/dist/toolResult.js +20 -6
- package/dist/webSearchWireCaps.js +9 -4
- package/dist/wireFailureShape.d.ts +20 -0
- package/dist/wireFailureShape.js +37 -6
- package/dist/wireRefusalCopy.d.ts +23 -2
- package/dist/wireRefusalCopy.js +93 -4
- package/docs/INTEGRATION-CLIENTS.md +1959 -15
- package/package.json +4 -4
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { engineIdentityOf, engineIdentityVerdict } from './engineIdentity.js';
|
|
2
|
+
import { readEngineHealthFacts } from './engineHealthFacts.js';
|
|
3
|
+
import { compareReleaseVersions, engineSupportFloorEffective, engineVersionTier } from './supportFloor.js';
|
|
4
|
+
import { readOwnDataValue } from './ownKey.js';
|
|
5
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
6
|
+
function isRecord(v) {
|
|
7
|
+
if (typeof v !== 'object' || v === null)
|
|
8
|
+
return false;
|
|
9
|
+
try {
|
|
10
|
+
return !Array.isArray(v);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function isArray(v) {
|
|
17
|
+
try {
|
|
18
|
+
return Array.isArray(v);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function nonEmpty(v) {
|
|
25
|
+
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
26
|
+
}
|
|
27
|
+
function isPid(v) {
|
|
28
|
+
return typeof v === 'number' && Number.isSafeInteger(v) && v > 0;
|
|
29
|
+
}
|
|
30
|
+
function isPort(v) {
|
|
31
|
+
return typeof v === 'number' && Number.isInteger(v) && v >= 1 && v <= 65535;
|
|
32
|
+
}
|
|
33
|
+
function own(v, key) {
|
|
34
|
+
if (!isRecord(v) && !isArray(v))
|
|
35
|
+
return undefined;
|
|
36
|
+
try {
|
|
37
|
+
return readOwnDataValue(v, key);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function freezeIdentity(id) {
|
|
44
|
+
return Object.freeze({ ...id });
|
|
45
|
+
}
|
|
46
|
+
function planFingerprintsOf(raw) {
|
|
47
|
+
if (!isArray(raw))
|
|
48
|
+
return undefined;
|
|
49
|
+
const out = [];
|
|
50
|
+
for (let i = 0; i < raw.length; i++) {
|
|
51
|
+
const e = own(raw, String(i));
|
|
52
|
+
const group = nonEmpty(own(e, 'group'));
|
|
53
|
+
const fingerprint = nonEmpty(own(e, 'fingerprint'));
|
|
54
|
+
if (group !== undefined && fingerprint !== undefined)
|
|
55
|
+
out.push(Object.freeze({ group, fingerprint }));
|
|
56
|
+
}
|
|
57
|
+
return Object.freeze(out);
|
|
58
|
+
}
|
|
59
|
+
function anchorOf(raw) {
|
|
60
|
+
if (!isRecord(raw))
|
|
61
|
+
return null;
|
|
62
|
+
const pid = readOwnDataValue(raw, 'pid');
|
|
63
|
+
const port = readOwnDataValue(raw, 'port');
|
|
64
|
+
if (!isPid(pid) || !isPort(port))
|
|
65
|
+
return null;
|
|
66
|
+
const identity = freezeIdentity(engineIdentityOf({ pid, instanceId: readOwnDataValue(raw, 'instanceId'), startedAt: readOwnDataValue(raw, 'engineStartedAt') }));
|
|
67
|
+
const planFingerprints = planFingerprintsOf(readOwnDataValue(raw, 'planFingerprints'));
|
|
68
|
+
const logPath = nonEmpty(readOwnDataValue(raw, 'logPath'));
|
|
69
|
+
return Object.freeze({
|
|
70
|
+
pid,
|
|
71
|
+
port,
|
|
72
|
+
identity,
|
|
73
|
+
...(planFingerprints !== undefined ? { planFingerprints } : {}),
|
|
74
|
+
...(logPath !== undefined ? { logPath } : {}),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
export function localEngineAnchorOf(raw) {
|
|
78
|
+
try {
|
|
79
|
+
return anchorOf(raw);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export function localEnginePlanDriftOf(anchor, ownPlan) {
|
|
86
|
+
try {
|
|
87
|
+
const a = localEngineAnchorOf(anchor);
|
|
88
|
+
const AMBIGUOUS = Symbol('ambiguous');
|
|
89
|
+
const theirs = new Map();
|
|
90
|
+
for (const e of a?.planFingerprints ?? []) {
|
|
91
|
+
const prior = theirs.get(e.group);
|
|
92
|
+
theirs.set(e.group, prior === undefined || prior === e.fingerprint ? e.fingerprint : AMBIGUOUS);
|
|
93
|
+
}
|
|
94
|
+
if (!isArray(ownPlan))
|
|
95
|
+
return Object.freeze([]);
|
|
96
|
+
const mine = new Map();
|
|
97
|
+
for (let i = 0; i < ownPlan.length; i++) {
|
|
98
|
+
const e = own(ownPlan, String(i));
|
|
99
|
+
const group = nonEmpty(own(e, 'group'));
|
|
100
|
+
if (group === undefined)
|
|
101
|
+
continue;
|
|
102
|
+
const fp = nonEmpty(own(e, 'fingerprint')) ?? AMBIGUOUS;
|
|
103
|
+
const prior = mine.get(group);
|
|
104
|
+
mine.set(group, prior === undefined ? fp : prior === fp ? fp : AMBIGUOUS);
|
|
105
|
+
}
|
|
106
|
+
const out = [];
|
|
107
|
+
for (const [group, fp] of mine) {
|
|
108
|
+
const t = theirs.get(group);
|
|
109
|
+
const drift = fp === AMBIGUOUS || t === undefined || t === AMBIGUOUS ? 'unknown' : t === fp ? 'same' : 'different';
|
|
110
|
+
out.push(Object.freeze({ group, drift }));
|
|
111
|
+
}
|
|
112
|
+
return Object.freeze(out);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return Object.freeze([]);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const NONE = Object.freeze({ kind: 'none' });
|
|
119
|
+
function pidStateOf(v) {
|
|
120
|
+
return v === 'gone' || v === 'alive' || v === 'recycled' ? v : 'unknown';
|
|
121
|
+
}
|
|
122
|
+
function relationOf(v) {
|
|
123
|
+
return v === 'same' || v === 'different' ? v : 'unknown';
|
|
124
|
+
}
|
|
125
|
+
function anchoredOf(a) {
|
|
126
|
+
return Object.freeze({ pid: a.pid, ...(a.identity.startedAt !== undefined ? { startedAt: a.identity.startedAt } : {}) });
|
|
127
|
+
}
|
|
128
|
+
function unanswered(a, reason) {
|
|
129
|
+
return Object.freeze({ kind: 'unanswered', pid: a.pid, ...(a.identity.startedAt !== undefined ? { startedAt: a.identity.startedAt } : {}), reason });
|
|
130
|
+
}
|
|
131
|
+
function stranger(mismatch, anchored) {
|
|
132
|
+
return Object.freeze({ kind: 'stranger', mismatch, anchored });
|
|
133
|
+
}
|
|
134
|
+
function comparableBeyondPid(x, y) {
|
|
135
|
+
return (x.instanceId !== undefined && y.instanceId !== undefined) || (x.startedAt !== undefined && y.startedAt !== undefined);
|
|
136
|
+
}
|
|
137
|
+
export function sameLocalEngineInstance(x, y, anchorPidAlive) {
|
|
138
|
+
if (engineIdentityVerdict(x, y) !== 'same')
|
|
139
|
+
return false;
|
|
140
|
+
return comparableBeyondPid(engineIdentityOf(x), engineIdentityOf(y)) || anchorPidAlive === true;
|
|
141
|
+
}
|
|
142
|
+
function judgeAnchored(input, a) {
|
|
143
|
+
const pidState = pidStateOf(own(input, 'anchorPid'));
|
|
144
|
+
const health = own(input, 'health');
|
|
145
|
+
if (!isRecord(health)) {
|
|
146
|
+
if (pidState === 'gone' || pidState === 'recycled')
|
|
147
|
+
return NONE;
|
|
148
|
+
return unanswered(a, pidState === 'alive' ? 'no-answer' : 'unverifiable');
|
|
149
|
+
}
|
|
150
|
+
const hid = engineIdentityOf({ pid: own(health, 'pid'), instanceId: own(health, 'instanceId'), startedAt: own(health, 'startedAt') });
|
|
151
|
+
const facts = readEngineHealthFacts(health);
|
|
152
|
+
if (hid.pid === undefined)
|
|
153
|
+
return unanswered(a, 'unverifiable');
|
|
154
|
+
if (hid.pid !== a.pid) {
|
|
155
|
+
if (pidState === 'alive')
|
|
156
|
+
return unanswered(a, 'no-answer');
|
|
157
|
+
if (pidState === 'unknown')
|
|
158
|
+
return unanswered(a, 'unverifiable');
|
|
159
|
+
return facts.dataRoot !== undefined ? stranger('pid', null) : unanswered(a, 'unverifiable');
|
|
160
|
+
}
|
|
161
|
+
if (facts.dataRoot === undefined)
|
|
162
|
+
return unanswered(a, 'unverifiable');
|
|
163
|
+
if (a.identity.startedAt !== undefined && hid.startedAt === undefined)
|
|
164
|
+
return unanswered(a, 'unverifiable');
|
|
165
|
+
const idv = engineIdentityVerdict(a.identity, hid);
|
|
166
|
+
if (idv === 'changed')
|
|
167
|
+
return stranger('generation', null);
|
|
168
|
+
if (idv !== 'same' || !sameLocalEngineInstance(a.identity, hid, pidState === 'alive'))
|
|
169
|
+
return unanswered(a, 'unverifiable');
|
|
170
|
+
const relation = relationOf(own(input, 'dataRootRelation'));
|
|
171
|
+
if (relation === 'unknown')
|
|
172
|
+
return unanswered(a, 'unverifiable');
|
|
173
|
+
if (relation === 'different')
|
|
174
|
+
return stranger('data-root', pidState === 'alive' ? anchoredOf(a) : null);
|
|
175
|
+
const engine = Object.freeze({ pid: a.pid, port: a.port, identity: freezeIdentity(hid), ...(facts.version !== undefined ? { version: facts.version } : {}) });
|
|
176
|
+
if (facts.draining !== undefined)
|
|
177
|
+
return Object.freeze({ kind: 'draining', engine, deadlineAt: facts.draining.deadlineAt });
|
|
178
|
+
const running = facts.version;
|
|
179
|
+
const ownRaw = own(input, 'ownVersion');
|
|
180
|
+
const mine = typeof ownRaw === 'string' ? ownRaw : undefined;
|
|
181
|
+
const cmp = running !== undefined && mine !== undefined ? compareReleaseVersions(running, mine) : undefined;
|
|
182
|
+
if (running !== undefined && mine !== undefined) {
|
|
183
|
+
if (cmp === 0)
|
|
184
|
+
return Object.freeze({ kind: 'attach', engine });
|
|
185
|
+
if (cmp === -1)
|
|
186
|
+
return Object.freeze({ kind: 'ahead', engine, running, own: mine, servesWhileWaiting: engineVersionTier(running) === 'engine' });
|
|
187
|
+
if (cmp === 1)
|
|
188
|
+
return Object.freeze({ kind: 'behind', engine, running, own: mine, source: 'running' });
|
|
189
|
+
}
|
|
190
|
+
return Object.freeze({ kind: 'version-unknown', engine });
|
|
191
|
+
}
|
|
192
|
+
export function judgeLocalEngine(input) {
|
|
193
|
+
const a = localEngineAnchorOf(own(input, 'anchor'));
|
|
194
|
+
if (a === null || !isRecord(input))
|
|
195
|
+
return NONE;
|
|
196
|
+
try {
|
|
197
|
+
return judgeAnchored(input, a);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
return unanswered(a, 'unverifiable');
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
export function localEngineLaneOf(verdict) {
|
|
204
|
+
try {
|
|
205
|
+
const kind = own(verdict, 'kind');
|
|
206
|
+
const engine = own(verdict, 'engine');
|
|
207
|
+
if (kind === 'attach' || kind === 'ahead' || kind === 'version-unknown')
|
|
208
|
+
return isRecord(engine) ? 'self-spawned' : undefined;
|
|
209
|
+
if (kind === 'behind')
|
|
210
|
+
return isRecord(engine) || (engine === null && Object.hasOwn(verdict, 'engine')) ? 'self-spawned' : undefined;
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
export function localEngineVerdictSentence(verdict, upgrade, lang) {
|
|
218
|
+
try {
|
|
219
|
+
const kind = own(verdict, 'kind');
|
|
220
|
+
if (kind === 'version-unknown')
|
|
221
|
+
return renderMessage(msg('localEngine.versionUnknown'), lang);
|
|
222
|
+
const running = own(verdict, 'running');
|
|
223
|
+
const mine = own(verdict, 'own');
|
|
224
|
+
if (typeof running !== 'string' || typeof mine !== 'string')
|
|
225
|
+
return undefined;
|
|
226
|
+
const cmp = compareReleaseVersions(running, mine);
|
|
227
|
+
if (kind === 'behind' && cmp === 1) {
|
|
228
|
+
if (upgrade === 'cli-update')
|
|
229
|
+
return renderMessage(msg('localEngine.behind.cliUpdate', { running, own: mine }), lang);
|
|
230
|
+
if (upgrade === 'app-update')
|
|
231
|
+
return renderMessage(msg('localEngine.behind.appUpdate', { running, own: mine }), lang);
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
if (kind === 'ahead' && cmp === -1 && own(verdict, 'servesWhileWaiting') === false) {
|
|
235
|
+
return renderMessage(msg('localEngine.legacyBelowFloor', { running, floor: engineSupportFloorEffective() }), lang);
|
|
236
|
+
}
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { FleetMeta, FleetTaskRow, FleetWorkflowRow } from '@sema-agent/sdk';
|
|
2
|
+
import { type LocalEngineRef } from './localEngineJudge.js';
|
|
3
|
+
import type { SessionEngineReading } from './sessionEngine.js';
|
|
4
|
+
import type { LocalEnginePrincipal } from './localEngineSpawn.js';
|
|
5
|
+
import type { UiLanguage } from './env/uiLanguage.js';
|
|
6
|
+
export type ClientRegistryDirectory = 'ok' | 'absent' | 'unreadable';
|
|
7
|
+
export interface ClientRegistryRecordReading {
|
|
8
|
+
readonly pid: number;
|
|
9
|
+
readonly alive: boolean;
|
|
10
|
+
readonly readable: boolean;
|
|
11
|
+
readonly kind?: string;
|
|
12
|
+
readonly status?: string;
|
|
13
|
+
readonly recycled?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface ClientRegistryCount {
|
|
16
|
+
readonly total: number;
|
|
17
|
+
readonly midTurn: number;
|
|
18
|
+
readonly known: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function countClientRegistry(records: readonly ClientRegistryRecordReading[], selfPid: number, directory: ClientRegistryDirectory): ClientRegistryCount;
|
|
21
|
+
export interface LocalEngineFleetReading {
|
|
22
|
+
readonly connected: boolean;
|
|
23
|
+
readonly meta: FleetMeta | null;
|
|
24
|
+
readonly snapshotSeen: boolean;
|
|
25
|
+
readonly boundTo: LocalEngineRef | null;
|
|
26
|
+
readonly target: LocalEngineRef | null;
|
|
27
|
+
readonly tasks: readonly FleetTaskRow[];
|
|
28
|
+
readonly workflows: readonly FleetWorkflowRow[];
|
|
29
|
+
}
|
|
30
|
+
export interface FleetBackgroundLive {
|
|
31
|
+
readonly live: number;
|
|
32
|
+
readonly ids: readonly string[];
|
|
33
|
+
}
|
|
34
|
+
export declare function fleetBackgroundLiveOf(r: LocalEngineFleetReading): FleetBackgroundLive | 'unknown';
|
|
35
|
+
export type LocalEngineSelfItem = 'turn' | 'cards' | 'workflow' | 'queued' | 'rowWrites' | 'shells';
|
|
36
|
+
export type LocalEngineSelfReading = boolean | number | 'unknown';
|
|
37
|
+
export interface LocalEngineSelfInput {
|
|
38
|
+
readonly turnInflight: LocalEngineSelfReading;
|
|
39
|
+
readonly cardsOnScreen: LocalEngineSelfReading;
|
|
40
|
+
readonly workflowsInflight: LocalEngineSelfReading;
|
|
41
|
+
readonly queuedMessages: LocalEngineSelfReading;
|
|
42
|
+
readonly rowWritesInflight: LocalEngineSelfReading;
|
|
43
|
+
readonly sessionShells: LocalEngineSelfReading | 'covered';
|
|
44
|
+
}
|
|
45
|
+
export interface LocalEngineSelf {
|
|
46
|
+
readonly verdict: 'idle' | 'busy' | 'unknown';
|
|
47
|
+
readonly busy: readonly LocalEngineSelfItem[];
|
|
48
|
+
readonly unknown: readonly LocalEngineSelfItem[];
|
|
49
|
+
}
|
|
50
|
+
export declare function localEngineSelfOf(r: LocalEngineSelfInput): LocalEngineSelf;
|
|
51
|
+
export type LocalEngineRegistryStatus = 'busy' | 'waiting' | 'idle';
|
|
52
|
+
export declare function localEngineRegistryStatusOf(self: LocalEngineSelf): LocalEngineRegistryStatus;
|
|
53
|
+
export interface LocalEngineOccupancy {
|
|
54
|
+
readonly others: ClientRegistryCount;
|
|
55
|
+
readonly inflight: number | 'unknown';
|
|
56
|
+
readonly bgLive: number | 'unknown';
|
|
57
|
+
readonly self: LocalEngineSelf['verdict'];
|
|
58
|
+
}
|
|
59
|
+
export declare function localEngineIdle(o: LocalEngineOccupancy): boolean;
|
|
60
|
+
export type LocalEngineDefaultLane = 'local' | 'cloud' | 'unknown';
|
|
61
|
+
export interface LocalEngineDemandSession {
|
|
62
|
+
readonly reading: SessionEngineReading | null | undefined;
|
|
63
|
+
readonly legacyLandsLocal?: boolean;
|
|
64
|
+
readonly running: boolean;
|
|
65
|
+
readonly parked: boolean | 'unknown';
|
|
66
|
+
readonly queued: boolean;
|
|
67
|
+
readonly focused: boolean;
|
|
68
|
+
}
|
|
69
|
+
export interface LocalEngineDemandInput {
|
|
70
|
+
readonly principal: LocalEnginePrincipal | undefined;
|
|
71
|
+
readonly defaultLane: LocalEngineDefaultLane;
|
|
72
|
+
readonly sessions: readonly LocalEngineDemandSession[];
|
|
73
|
+
readonly printLocal: boolean;
|
|
74
|
+
readonly userStartAction: boolean;
|
|
75
|
+
readonly attachOnlyUse: boolean;
|
|
76
|
+
}
|
|
77
|
+
export type LocalEngineDemandSource = 'default-lane' | 'session' | 'print' | 'user-action' | 'attach-only';
|
|
78
|
+
export interface LocalEngineDemand {
|
|
79
|
+
readonly demand: 'spawn' | 'attach-only' | 'none';
|
|
80
|
+
readonly because: readonly LocalEngineDemandSource[];
|
|
81
|
+
}
|
|
82
|
+
export declare function localEngineDemandOf(r: LocalEngineDemandInput): LocalEngineDemand;
|
|
83
|
+
export interface LocalEngineExitFate {
|
|
84
|
+
readonly kind: 'stays';
|
|
85
|
+
readonly why: 'peers' | 'lease' | 'unknown';
|
|
86
|
+
}
|
|
87
|
+
export declare function localEngineExitFate(others: ClientRegistryCount): LocalEngineExitFate;
|
|
88
|
+
export declare function localEngineExitFateSentence(fate: LocalEngineExitFate, lang?: UiLanguage): string | undefined;
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { isCoreWorkflowRunTerminal, isSdkFleetTaskTerminal } from './terminalStatuses.js';
|
|
2
|
+
import { appendOwnElement, readOwnDataValue } from './ownKey.js';
|
|
3
|
+
import { sameLocalEngineInstance } from './localEngineJudge.js';
|
|
4
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
5
|
+
function isRecord(v) {
|
|
6
|
+
if (typeof v !== 'object' || v === null)
|
|
7
|
+
return false;
|
|
8
|
+
try {
|
|
9
|
+
return !Array.isArray(v);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function isArray(v) {
|
|
16
|
+
try {
|
|
17
|
+
return Array.isArray(v);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function own(v, key) {
|
|
24
|
+
if (!isRecord(v) && !isArray(v))
|
|
25
|
+
return undefined;
|
|
26
|
+
try {
|
|
27
|
+
return readOwnDataValue(v, key);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function isCount(v) {
|
|
34
|
+
return typeof v === 'number' && Number.isSafeInteger(v) && v >= 0;
|
|
35
|
+
}
|
|
36
|
+
function elementsOf(v) {
|
|
37
|
+
try {
|
|
38
|
+
if (!Array.isArray(v))
|
|
39
|
+
return undefined;
|
|
40
|
+
const out = [];
|
|
41
|
+
for (let i = 0; i < v.length; i++) {
|
|
42
|
+
if (!Object.hasOwn(v, i))
|
|
43
|
+
return undefined;
|
|
44
|
+
appendOwnElement(out, readOwnDataValue(v, String(i)));
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const REGISTRY_STATUS_WORDS = new Set(Object.keys({ busy: true, waiting: true, idle: true }));
|
|
53
|
+
function registryStatusOf(r) {
|
|
54
|
+
try {
|
|
55
|
+
const d = Object.getOwnPropertyDescriptor(r, 'status');
|
|
56
|
+
if (d === undefined)
|
|
57
|
+
return 'status' in r ? 'unreadable' : 'absent';
|
|
58
|
+
if (!Object.hasOwn(d, 'value'))
|
|
59
|
+
return 'unreadable';
|
|
60
|
+
const v = d.value;
|
|
61
|
+
if (v === undefined)
|
|
62
|
+
return 'absent';
|
|
63
|
+
return REGISTRY_STATUS_WORDS.has(v) ? v : 'unreadable';
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return 'unreadable';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export function countClientRegistry(records, selfPid, directory) {
|
|
70
|
+
if (directory === 'absent')
|
|
71
|
+
return Object.freeze({ total: 0, midTurn: 0, known: true });
|
|
72
|
+
if (directory !== 'ok')
|
|
73
|
+
return Object.freeze({ total: 0, midTurn: 0, known: false });
|
|
74
|
+
const list = elementsOf(records);
|
|
75
|
+
if (list === undefined)
|
|
76
|
+
return Object.freeze({ total: 0, midTurn: 0, known: false });
|
|
77
|
+
let total = 0;
|
|
78
|
+
let midTurn = 0;
|
|
79
|
+
let known = true;
|
|
80
|
+
for (const r of list) {
|
|
81
|
+
const pid = own(r, 'pid');
|
|
82
|
+
const alive = own(r, 'alive');
|
|
83
|
+
const readable = own(r, 'readable');
|
|
84
|
+
if (typeof pid !== 'number' || typeof alive !== 'boolean' || typeof readable !== 'boolean') {
|
|
85
|
+
known = false;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (pid === selfPid || !alive)
|
|
89
|
+
continue;
|
|
90
|
+
if (!readable) {
|
|
91
|
+
known = false;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (own(r, 'kind') === 'daemon')
|
|
95
|
+
continue;
|
|
96
|
+
total++;
|
|
97
|
+
const status = registryStatusOf(r);
|
|
98
|
+
if (status === 'unreadable') {
|
|
99
|
+
known = false;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if ((status === 'busy' || status === 'waiting') && own(r, 'recycled') !== true)
|
|
103
|
+
midTurn++;
|
|
104
|
+
}
|
|
105
|
+
return Object.freeze({ total, midTurn, known });
|
|
106
|
+
}
|
|
107
|
+
function taskCounts(status) {
|
|
108
|
+
if (isSdkFleetTaskTerminal(status))
|
|
109
|
+
return false;
|
|
110
|
+
const s = status;
|
|
111
|
+
switch (s) {
|
|
112
|
+
case 'queued':
|
|
113
|
+
case 'running':
|
|
114
|
+
case 'stopping':
|
|
115
|
+
case 'idle':
|
|
116
|
+
return true;
|
|
117
|
+
case 'waiting':
|
|
118
|
+
case 'awaiting approval':
|
|
119
|
+
return false;
|
|
120
|
+
default: {
|
|
121
|
+
const unhandled = s;
|
|
122
|
+
void unhandled;
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function workflowCounts(status) {
|
|
128
|
+
if (isCoreWorkflowRunTerminal(status))
|
|
129
|
+
return false;
|
|
130
|
+
return status === 'running' ? true : undefined;
|
|
131
|
+
}
|
|
132
|
+
export function fleetBackgroundLiveOf(r) {
|
|
133
|
+
try {
|
|
134
|
+
if (own(r, 'connected') !== true || own(r, 'snapshotSeen') !== true)
|
|
135
|
+
return 'unknown';
|
|
136
|
+
const meta = own(r, 'meta');
|
|
137
|
+
if (own(meta, 'scoped') !== false || own(meta, 'sessionScoped') !== false)
|
|
138
|
+
return 'unknown';
|
|
139
|
+
const boundTo = own(r, 'boundTo');
|
|
140
|
+
const target = own(r, 'target');
|
|
141
|
+
const bi = own(boundTo, 'identity');
|
|
142
|
+
const ti = own(target, 'identity');
|
|
143
|
+
if (!isRecord(bi) || !isRecord(ti) || !sameLocalEngineInstance(bi, ti, false))
|
|
144
|
+
return 'unknown';
|
|
145
|
+
const tasks = elementsOf(own(r, 'tasks'));
|
|
146
|
+
const workflows = elementsOf(own(r, 'workflows'));
|
|
147
|
+
if (tasks === undefined || workflows === undefined)
|
|
148
|
+
return 'unknown';
|
|
149
|
+
const ids = [];
|
|
150
|
+
for (const [rows, counts] of [[tasks, taskCounts], [workflows, workflowCounts]]) {
|
|
151
|
+
for (const row of rows) {
|
|
152
|
+
const id = own(row, 'id');
|
|
153
|
+
const status = own(row, 'status');
|
|
154
|
+
if (typeof id !== 'string' || id.length === 0 || typeof status !== 'string')
|
|
155
|
+
return 'unknown';
|
|
156
|
+
const c = counts(status);
|
|
157
|
+
if (c === undefined)
|
|
158
|
+
return 'unknown';
|
|
159
|
+
if (c)
|
|
160
|
+
ids.push(id);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
ids.sort();
|
|
164
|
+
return Object.freeze({ live: ids.length, ids: Object.freeze(ids) });
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return 'unknown';
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const SELF_ITEMS = Object.freeze([
|
|
171
|
+
['turn', 'turnInflight'],
|
|
172
|
+
['cards', 'cardsOnScreen'],
|
|
173
|
+
['workflow', 'workflowsInflight'],
|
|
174
|
+
['queued', 'queuedMessages'],
|
|
175
|
+
['rowWrites', 'rowWritesInflight'],
|
|
176
|
+
['shells', 'sessionShells'],
|
|
177
|
+
]);
|
|
178
|
+
export function localEngineSelfOf(r) {
|
|
179
|
+
const busy = [];
|
|
180
|
+
const unknown = [];
|
|
181
|
+
for (const [item, key] of SELF_ITEMS) {
|
|
182
|
+
const v = own(r, key);
|
|
183
|
+
if (v === 'covered' && item === 'shells')
|
|
184
|
+
continue;
|
|
185
|
+
if (v === true || (isCount(v) && v > 0))
|
|
186
|
+
busy.push(item);
|
|
187
|
+
else if (v === false || v === 0)
|
|
188
|
+
continue;
|
|
189
|
+
else
|
|
190
|
+
unknown.push(item);
|
|
191
|
+
}
|
|
192
|
+
const verdict = busy.length > 0 ? 'busy' : unknown.length > 0 ? 'unknown' : 'idle';
|
|
193
|
+
return Object.freeze({ verdict, busy: Object.freeze(busy), unknown: Object.freeze(unknown) });
|
|
194
|
+
}
|
|
195
|
+
const SELF_ITEM_SET = new Set(SELF_ITEMS.map(([item]) => item));
|
|
196
|
+
export function localEngineRegistryStatusOf(self) {
|
|
197
|
+
try {
|
|
198
|
+
const verdict = own(self, 'verdict');
|
|
199
|
+
const busy = elementsOf(own(self, 'busy'));
|
|
200
|
+
const unknown = elementsOf(own(self, 'unknown'));
|
|
201
|
+
if (busy === undefined || unknown === undefined || ![...busy, ...unknown].every((x) => SELF_ITEM_SET.has(x)))
|
|
202
|
+
return 'busy';
|
|
203
|
+
if (verdict === 'idle')
|
|
204
|
+
return busy.length === 0 && unknown.length === 0 ? 'idle' : 'busy';
|
|
205
|
+
if (verdict === 'busy')
|
|
206
|
+
return busy.length > 0 && busy.every((x) => x === 'cards') ? 'waiting' : 'busy';
|
|
207
|
+
return 'busy';
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return 'busy';
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
export function localEngineIdle(o) {
|
|
214
|
+
const others = own(o, 'others');
|
|
215
|
+
return own(others, 'known') === true && own(others, 'midTurn') === 0 && own(o, 'inflight') === 0 && own(o, 'bgLive') === 0 && own(o, 'self') === 'idle';
|
|
216
|
+
}
|
|
217
|
+
function sessionLandsLocal(s) {
|
|
218
|
+
const reading = own(s, 'reading');
|
|
219
|
+
const kind = own(reading, 'kind');
|
|
220
|
+
if (kind === 'bound')
|
|
221
|
+
return own(own(reading, 'engine'), 'identityKind') === 'self';
|
|
222
|
+
if (kind === 'legacy')
|
|
223
|
+
return own(s, 'legacyLandsLocal') === true;
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
function sessionActive(s) {
|
|
227
|
+
const parked = own(s, 'parked');
|
|
228
|
+
return own(s, 'running') === true || parked === true || parked === 'unknown' || own(s, 'queued') === true || own(s, 'focused') === true;
|
|
229
|
+
}
|
|
230
|
+
export function localEngineDemandOf(r) {
|
|
231
|
+
if (own(own(r, 'principal'), 'kind') !== 'principal')
|
|
232
|
+
return Object.freeze({ demand: 'none', because: Object.freeze([]) });
|
|
233
|
+
const because = [];
|
|
234
|
+
if (own(r, 'defaultLane') === 'local')
|
|
235
|
+
because.push('default-lane');
|
|
236
|
+
const sessions = elementsOf(own(r, 'sessions')) ?? [];
|
|
237
|
+
if (sessions.some((s) => sessionLandsLocal(s) && sessionActive(s)))
|
|
238
|
+
because.push('session');
|
|
239
|
+
if (own(r, 'printLocal') === true)
|
|
240
|
+
because.push('print');
|
|
241
|
+
if (own(r, 'userStartAction') === true)
|
|
242
|
+
because.push('user-action');
|
|
243
|
+
if (because.length > 0)
|
|
244
|
+
return Object.freeze({ demand: 'spawn', because: Object.freeze(because) });
|
|
245
|
+
if (own(r, 'attachOnlyUse') === true)
|
|
246
|
+
return Object.freeze({ demand: 'attach-only', because: Object.freeze(['attach-only']) });
|
|
247
|
+
return Object.freeze({ demand: 'none', because: Object.freeze([]) });
|
|
248
|
+
}
|
|
249
|
+
export function localEngineExitFate(others) {
|
|
250
|
+
const total = own(others, 'total');
|
|
251
|
+
const why = own(others, 'known') === true && isCount(total) ? (total > 0 ? 'peers' : 'lease') : 'unknown';
|
|
252
|
+
return Object.freeze({ kind: 'stays', why });
|
|
253
|
+
}
|
|
254
|
+
const EXIT_FATE_KEYS = Object.freeze({
|
|
255
|
+
peers: 'localEngine.exitFate.peers',
|
|
256
|
+
lease: 'localEngine.exitFate.lease',
|
|
257
|
+
unknown: 'localEngine.exitFate.unknown',
|
|
258
|
+
});
|
|
259
|
+
export function localEngineExitFateSentence(fate, lang) {
|
|
260
|
+
try {
|
|
261
|
+
const why = own(fate, 'why');
|
|
262
|
+
if (own(fate, 'kind') !== 'stays' || (why !== 'peers' && why !== 'lease' && why !== 'unknown'))
|
|
263
|
+
return undefined;
|
|
264
|
+
return renderMessage(msg(EXIT_FATE_KEYS[why]), lang);
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
return undefined;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { EngineRestartOutcome, EngineTargetLocal, LocalEngineSeatReading, SeatLocalMcpReading } from './seatContract.js';
|
|
2
|
+
import { type LocalEngineEffect, type LocalEngineFailCode, type LocalEngineNotice, type LocalEngineState } from './localEngineStep.js';
|
|
3
|
+
import type { LocalEngineSwapCause } from './localEngineSwapCard.js';
|
|
4
|
+
import type { LocalEngineUpgradePath } from './localEngineJudge.js';
|
|
5
|
+
import type { UiLanguage } from './env/uiLanguage.js';
|
|
6
|
+
export interface LocalEngineSeatHostFacts {
|
|
7
|
+
readonly upgrade: 'available' | 'unavailable';
|
|
8
|
+
readonly principal?: {
|
|
9
|
+
readonly kind: string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export declare function localEngineSeatReadingOf(state: LocalEngineState, host: LocalEngineSeatHostFacts): LocalEngineSeatReading | undefined;
|
|
13
|
+
export declare function localEngineSeatSentence(reading: LocalEngineSeatReading, upgrade: LocalEngineUpgradePath | undefined, lang?: UiLanguage): string | undefined;
|
|
14
|
+
export declare function localEngineNoticeText(notice: LocalEngineNotice, lang?: UiLanguage): string | undefined;
|
|
15
|
+
export declare function localEngineFailText(code: LocalEngineFailCode, lang?: UiLanguage): string | undefined;
|
|
16
|
+
export declare function engineTargetLocalOf(input: {
|
|
17
|
+
readonly lifecycle: LocalEngineSeatReading;
|
|
18
|
+
readonly mcp?: SeatLocalMcpReading;
|
|
19
|
+
}, lang?: UiLanguage): EngineTargetLocal;
|
|
20
|
+
export interface EngineRestartOperation {
|
|
21
|
+
readonly before: LocalEngineState;
|
|
22
|
+
readonly after: LocalEngineState;
|
|
23
|
+
readonly effects: readonly LocalEngineEffect[];
|
|
24
|
+
readonly cause: LocalEngineSwapCause;
|
|
25
|
+
readonly demand: 'spawn' | 'attach-only' | 'none';
|
|
26
|
+
readonly model?: string;
|
|
27
|
+
readonly lang?: UiLanguage;
|
|
28
|
+
}
|
|
29
|
+
export declare function engineRestartOutcomeOf(r: EngineRestartOperation): EngineRestartOutcome;
|