@sema-agent/client-core 0.108.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 +121 -0
- package/README.md +37 -24
- 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.js +1 -1
- 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 +1 -1
- package/dist/checkpointRowVerdict.js +4 -2
- package/dist/compensations.js +1 -1
- package/dist/engineAgentAbsence.d.ts +2 -0
- package/dist/engineAgentAbsence.js +28 -0
- package/dist/engineErrorCodes.d.ts +4 -0
- package/dist/engineErrorCodes.js +4 -0
- package/dist/engineHealthFacts.d.ts +17 -0
- package/dist/engineHealthFacts.js +42 -3
- package/dist/engineNoticeCodes.d.ts +128 -0
- package/dist/engineNoticeCodes.js +630 -55
- package/dist/errorSupplementRoles.js +4 -1
- package/dist/fleetTaskDesc.js +3 -3
- package/dist/generated/engineFactTables.d.ts +1 -0
- package/dist/generated/engineFactTables.js +6 -0
- package/dist/generated/engineNoticeTables.js +3 -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/approvalsFeed.js +1 -1
- package/dist/hitl/askParkRowRouting.js +5 -2
- 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/frameRouter.js +9 -1
- package/dist/hitl/hitlBridge.d.ts +4 -0
- package/dist/hitl/hitlBridge.js +9 -5
- 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 +7 -7
- 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 +2 -0
- package/dist/hitl/persistedRulesWire.js +11 -10
- package/dist/hitl/sessionAllowRoute.js +5 -4
- package/dist/hitl/standingRows.d.ts +1 -5
- package/dist/hitl/standingRows.js +15 -14
- package/dist/hitl/toolApprovalWire.d.ts +8 -2
- package/dist/hitl/toolApprovalWire.js +35 -14
- package/dist/hooksWireCaps.js +4 -3
- package/dist/hostSettingsSource.js +2 -0
- package/dist/i18n/messages.en.d.ts +168 -0
- package/dist/i18n/messages.en.js +169 -1
- package/dist/i18n/messages.zh.js +169 -1
- package/dist/index.d.ts +29 -7
- package/dist/index.js +16 -4
- 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/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/ruleReadings.js +1 -1
- package/dist/seam.d.ts +13 -2
- package/dist/seam.js +8 -1
- package/dist/seatContract.d.ts +42 -4
- package/dist/seatContract.js +180 -3
- package/dist/sessionBackground.js +2 -0
- package/dist/subagentContentStore.d.ts +12 -0
- package/dist/subagentContentStore.js +72 -11
- package/dist/toolResult.js +18 -5
- package/dist/wireFailureShape.d.ts +20 -0
- package/dist/wireFailureShape.js +37 -6
- package/dist/wireRefusalCopy.d.ts +21 -1
- package/dist/wireRefusalCopy.js +91 -2
- package/docs/INTEGRATION-CLIENTS.md +1152 -10
- package/package.json +3 -3
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
import { readOwnDataValue } from './ownKey.js';
|
|
2
|
+
import { inSlotReadOf } from './wireFailureShape.js';
|
|
3
|
+
import { normalizeWirePrincipal } from './principalWire.js';
|
|
4
|
+
import { LOCAL_ENGINE_STOP_LADDER } from './localEngineStopLadder.js';
|
|
5
|
+
import { LOCAL_ENGINE_TIMING } from './localEngineTiming.js';
|
|
6
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
7
|
+
function isRecord(v) {
|
|
8
|
+
if (typeof v !== 'object' || v === null)
|
|
9
|
+
return false;
|
|
10
|
+
try {
|
|
11
|
+
return !Array.isArray(v);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function own(v, key) {
|
|
18
|
+
if (!isRecord(v))
|
|
19
|
+
return undefined;
|
|
20
|
+
try {
|
|
21
|
+
return readOwnDataValue(v, key);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function envEntriesOf(v) {
|
|
28
|
+
const keys = envBlockKeysOf(v);
|
|
29
|
+
if (keys === undefined)
|
|
30
|
+
return undefined;
|
|
31
|
+
if (keys === null)
|
|
32
|
+
return [];
|
|
33
|
+
const out = [];
|
|
34
|
+
for (const k of keys) {
|
|
35
|
+
const x = own(v, k);
|
|
36
|
+
const str = x === undefined ? undefined : stringOf(x);
|
|
37
|
+
if (str !== undefined)
|
|
38
|
+
out.push([k, str]);
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
function envBlockKeysOf(v) {
|
|
43
|
+
if (typeof v !== 'object' || v === null)
|
|
44
|
+
return null;
|
|
45
|
+
try {
|
|
46
|
+
if (Array.isArray(v))
|
|
47
|
+
return null;
|
|
48
|
+
return Object.keys(v);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function stringOf(x) {
|
|
55
|
+
if (typeof x === 'string')
|
|
56
|
+
return x;
|
|
57
|
+
try {
|
|
58
|
+
return String(x);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function parseJsonLine(t) {
|
|
65
|
+
try {
|
|
66
|
+
return JSON.parse(t);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function freezeRecord(rows) {
|
|
73
|
+
const out = {};
|
|
74
|
+
for (const [k, v] of rows)
|
|
75
|
+
Object.defineProperty(out, k, { value: v, enumerable: true, writable: true, configurable: true });
|
|
76
|
+
return Object.freeze(out);
|
|
77
|
+
}
|
|
78
|
+
const lit = (value) => Object.freeze({ kind: 'literal', value });
|
|
79
|
+
const del = Object.freeze({ kind: 'delete' });
|
|
80
|
+
const slot = (s) => Object.freeze({ kind: 'path', slot: s });
|
|
81
|
+
const derived = (from) => Object.freeze({ kind: 'derived', from });
|
|
82
|
+
const row = (key, value, userOverridable) => Object.freeze({ key, value, userOverridable });
|
|
83
|
+
export const LOCAL_ENGINE_SPAWN_ENV = Object.freeze([
|
|
84
|
+
row('DRAIN_GRACE_MS', lit('60000'), true),
|
|
85
|
+
row('STORE_LOCK_WAIT_MS', derived('drainPlusH'), true),
|
|
86
|
+
row('ENGINE_AUTO_EXIT', lit('true'), true),
|
|
87
|
+
row('SEMA_PARENT_PID', del, false),
|
|
88
|
+
row('SEMA_ENGINE_PARENT_PID', del, false),
|
|
89
|
+
row('BIND_HOST', lit('127.0.0.1'), true),
|
|
90
|
+
row('DB_BACKEND', lit('local'), false),
|
|
91
|
+
row('CONFIG_PROVIDER', lit('local'), false),
|
|
92
|
+
row('REMOTE_EXEC', lit('host'), true),
|
|
93
|
+
row('LOCAL_DATA_ROOT', slot('dataRoot'), false),
|
|
94
|
+
row('AGENT_DATA_DIR', slot('dataRoot'), true),
|
|
95
|
+
row('MEMORY_ENGINE_DIR', derived('agentDataDir'), true),
|
|
96
|
+
row('CONFIG_LOCAL_DIR', slot('configLocalDir'), false),
|
|
97
|
+
row('SEMA_CONFIG_DIR', slot('configHome'), false),
|
|
98
|
+
row('ALLOW_UNAUTHED_WRITES', lit('false'), false),
|
|
99
|
+
row('OPERATOR_SINGLE_USER', derived('operatorSingleUser'), true),
|
|
100
|
+
row('LEADER_ENABLED', del, false),
|
|
101
|
+
row('REGISTRY_ADMIN_TOKEN', del, false),
|
|
102
|
+
]);
|
|
103
|
+
export const LOCAL_ENGINE_HOST_BITS = Object.freeze(['PORT', 'SERVICE_AUTH_TOKENS', 'ELECTRON_RUN_AS_NODE', 'NODE_ENV', 'HOST_SHELL_PATH']);
|
|
104
|
+
export const LOCAL_ENGINE_SPAWN_SHAPE = Object.freeze({ detachedSession: true, stdio: 'engine-log-file' });
|
|
105
|
+
const BOOL_TRUE = new Set(['true', '1', 'yes', 'on']);
|
|
106
|
+
const OPERATOR_DECLARATION_KEYS = Object.freeze({ requirePrincipal: 'REQUIRE_PRINCIPAL', principals: 'OPERATOR_PRINCIPALS', singleUser: 'OPERATOR_SINGLE_USER' });
|
|
107
|
+
export function localEngineOperatorSingleUserOf(inherited) {
|
|
108
|
+
try {
|
|
109
|
+
const requirePrincipal = own(inherited, OPERATOR_DECLARATION_KEYS.requirePrincipal);
|
|
110
|
+
if (typeof requirePrincipal === 'string' && requirePrincipal !== '' && BOOL_TRUE.has(requirePrincipal.toLowerCase()))
|
|
111
|
+
return undefined;
|
|
112
|
+
const principals = own(inherited, OPERATOR_DECLARATION_KEYS.principals);
|
|
113
|
+
if (typeof principals === 'string' && principals.split(',').some((s) => s.trim() !== ''))
|
|
114
|
+
return undefined;
|
|
115
|
+
const declared = own(inherited, OPERATOR_DECLARATION_KEYS.singleUser);
|
|
116
|
+
if (typeof declared === 'string' && declared !== '')
|
|
117
|
+
return undefined;
|
|
118
|
+
return 'true';
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const BOOT_ALLOWANCE_MS = 180_000;
|
|
125
|
+
const DRAIN_GRACE_FLOOR_MS = 10_000;
|
|
126
|
+
const DRAIN_GRACE_TABLE_MS = 60_000;
|
|
127
|
+
function finiteNumber(s) {
|
|
128
|
+
if (s === undefined || s === '')
|
|
129
|
+
return undefined;
|
|
130
|
+
const n = Number(s);
|
|
131
|
+
return Number.isFinite(n) ? n : undefined;
|
|
132
|
+
}
|
|
133
|
+
const HOST_BIT_SET = new Set(LOCAL_ENGINE_HOST_BITS);
|
|
134
|
+
const TABLE_KEY_SET = new Set(LOCAL_ENGINE_SPAWN_ENV.map((r) => r.key));
|
|
135
|
+
const DERIVE = Object.freeze({
|
|
136
|
+
agentDataDir: (env) => env.get('AGENT_DATA_DIR'),
|
|
137
|
+
drainPlusH: (env) => String(drainGraceOf(env.get('DRAIN_GRACE_MS')) + LOCAL_ENGINE_STOP_LADDER.H),
|
|
138
|
+
operatorSingleUser: (env) => localEngineOperatorSingleUserOf(Object.fromEntries(env)),
|
|
139
|
+
});
|
|
140
|
+
function drainGraceOf(v) {
|
|
141
|
+
const n = finiteNumber(v);
|
|
142
|
+
return n === undefined ? DRAIN_GRACE_TABLE_MS : Math.max(DRAIN_GRACE_FLOOR_MS, n);
|
|
143
|
+
}
|
|
144
|
+
function budgetsOf(env, storeLockFromUser) {
|
|
145
|
+
const H = LOCAL_ENGINE_STOP_LADDER.H;
|
|
146
|
+
const D = drainGraceOf(env.get('DRAIN_GRACE_MS'));
|
|
147
|
+
const userStore = storeLockFromUser ? finiteNumber(env.get('STORE_LOCK_WAIT_MS')) : undefined;
|
|
148
|
+
const storeLockWaitMs = userStore !== undefined ? Math.max(0, userStore) : D + H;
|
|
149
|
+
const healthWaitBudgetMs = storeLockWaitMs + BOOT_ALLOWANCE_MS;
|
|
150
|
+
const stopBoundMs = D + 3 * H;
|
|
151
|
+
const lockWaitMs = 2 * LOCAL_ENGINE_TIMING.prepareTimeoutMs + stopBoundMs + healthWaitBudgetMs + H;
|
|
152
|
+
return Object.freeze({ storeLockWaitMs, healthWaitBudgetMs, stopBoundMs, lockWaitMs });
|
|
153
|
+
}
|
|
154
|
+
export function localEngineSpawnEnv(input) {
|
|
155
|
+
const env = new Map();
|
|
156
|
+
const applied = [];
|
|
157
|
+
const refusedHostBits = [];
|
|
158
|
+
let storeLockFromUser = false;
|
|
159
|
+
{
|
|
160
|
+
for (const [k, v] of envEntriesOf(own(input, 'inherited')) ?? [])
|
|
161
|
+
env.set(k, v);
|
|
162
|
+
const paths = own(input, 'paths');
|
|
163
|
+
for (const r of LOCAL_ENGINE_SPAWN_ENV) {
|
|
164
|
+
const inheritedValue = env.get(r.key);
|
|
165
|
+
if (r.value.kind === 'delete') {
|
|
166
|
+
env.delete(r.key);
|
|
167
|
+
applied.push(Object.freeze({ key: r.key, from: 'table' }));
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (r.userOverridable && inheritedValue !== undefined && inheritedValue !== '') {
|
|
171
|
+
applied.push(Object.freeze({ key: r.key, from: 'user' }));
|
|
172
|
+
if (r.key === 'STORE_LOCK_WAIT_MS')
|
|
173
|
+
storeLockFromUser = true;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
let value;
|
|
177
|
+
let from = 'table';
|
|
178
|
+
if (r.value.kind === 'literal')
|
|
179
|
+
value = r.value.value;
|
|
180
|
+
else if (r.value.kind === 'path') {
|
|
181
|
+
const p = own(paths, r.value.slot);
|
|
182
|
+
value = typeof p === 'string' && p !== '' ? p : undefined;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
value = DERIVE[r.value.from](env);
|
|
186
|
+
from = 'derived';
|
|
187
|
+
}
|
|
188
|
+
if (value === undefined) {
|
|
189
|
+
if (!r.userOverridable)
|
|
190
|
+
env.delete(r.key);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
env.set(r.key, value);
|
|
194
|
+
applied.push(Object.freeze({ key: r.key, from }));
|
|
195
|
+
}
|
|
196
|
+
for (const [k, v] of envEntriesOf(own(input, 'hostBits')) ?? []) {
|
|
197
|
+
if (!HOST_BIT_SET.has(k) || TABLE_KEY_SET.has(k)) {
|
|
198
|
+
refusedHostBits.push(k);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
env.set(k, v);
|
|
202
|
+
applied.push(Object.freeze({ key: k, from: 'host' }));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return Object.freeze({
|
|
206
|
+
env: freezeRecord([...env.entries()]),
|
|
207
|
+
applied: Object.freeze(applied),
|
|
208
|
+
refusedHostBits: Object.freeze(refusedHostBits),
|
|
209
|
+
budgets: budgetsOf(env, storeLockFromUser),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
const SEED_LAYER_ORDER = Object.freeze(['userSettings', 'flagSettings', 'policySettings']);
|
|
213
|
+
const SPAWN_SPELLED = new Set([...LOCAL_ENGINE_SPAWN_ENV.map((r) => r.key), ...LOCAL_ENGINE_HOST_BITS, ...Object.values(OPERATOR_DECLARATION_KEYS)]);
|
|
214
|
+
const PINNED_AT_ENTRY = new Set(['SEMA_CONFIG_DIR', 'HOME', 'USERPROFILE']);
|
|
215
|
+
const READ_FACE_VALUES = new Set(['open', 'roots']);
|
|
216
|
+
const WORKFLOW_SIZE_GUIDELINE_VALUES = new Set(['unrestricted', 'small', 'medium', 'large']);
|
|
217
|
+
function layerReadsOf(layers) {
|
|
218
|
+
const out = new Map();
|
|
219
|
+
let list = [];
|
|
220
|
+
try {
|
|
221
|
+
if (Array.isArray(layers))
|
|
222
|
+
list = [...layers];
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
list = [];
|
|
226
|
+
}
|
|
227
|
+
for (const entry of list) {
|
|
228
|
+
const layer = own(entry, 'layer');
|
|
229
|
+
if (layer !== 'userSettings' && layer !== 'flagSettings' && layer !== 'policySettings')
|
|
230
|
+
continue;
|
|
231
|
+
if (out.has(layer))
|
|
232
|
+
continue;
|
|
233
|
+
const read = own(entry, 'read');
|
|
234
|
+
const state = own(read, 'state');
|
|
235
|
+
if (state === 'ok')
|
|
236
|
+
out.set(layer, { kind: 'ok', env: own(read, 'env') });
|
|
237
|
+
else if (state === 'absent')
|
|
238
|
+
out.set(layer, { kind: 'absent' });
|
|
239
|
+
else
|
|
240
|
+
out.set(layer, { kind: 'unreadable', lastHealthy: state === 'unreadable' ? own(read, 'lastHealthy') : undefined });
|
|
241
|
+
}
|
|
242
|
+
return out;
|
|
243
|
+
}
|
|
244
|
+
export function localEngineSeedEnv(input) {
|
|
245
|
+
const ci = own(input, 'platform') === 'win32';
|
|
246
|
+
const canon = (k) => (ci ? k.toUpperCase() : k);
|
|
247
|
+
const merged = new Map();
|
|
248
|
+
const dropped = [];
|
|
249
|
+
let refuse;
|
|
250
|
+
const spell = (k) => (ci && SPAWN_SPELLED.has(k.toUpperCase()) ? k.toUpperCase() : k);
|
|
251
|
+
const put = (key, value, source) => {
|
|
252
|
+
merged.set(canon(key), { key: spell(key), value, source });
|
|
253
|
+
};
|
|
254
|
+
{
|
|
255
|
+
for (const source of ['baseline', 'external']) {
|
|
256
|
+
const entries = envEntriesOf(own(input, source));
|
|
257
|
+
if (entries === undefined)
|
|
258
|
+
dropped.push(Object.freeze({ key: source, why: 'layer-unreadable' }));
|
|
259
|
+
else
|
|
260
|
+
for (const [k, v] of entries)
|
|
261
|
+
put(k, v, source);
|
|
262
|
+
}
|
|
263
|
+
const reads = layerReadsOf(own(input, 'layers'));
|
|
264
|
+
for (const layer of SEED_LAYER_ORDER) {
|
|
265
|
+
const read = reads.get(layer);
|
|
266
|
+
if (read === undefined || read.kind === 'absent')
|
|
267
|
+
continue;
|
|
268
|
+
let entries;
|
|
269
|
+
if (read.kind === 'ok') {
|
|
270
|
+
entries = envEntriesOf(read.env);
|
|
271
|
+
if (entries === undefined)
|
|
272
|
+
dropped.push(Object.freeze({ key: layer, why: 'layer-unreadable' }));
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
dropped.push(Object.freeze({ key: layer, why: 'layer-unreadable' }));
|
|
276
|
+
if (layer === 'policySettings' && isRecord(read.lastHealthy))
|
|
277
|
+
entries = envEntriesOf(read.lastHealthy);
|
|
278
|
+
}
|
|
279
|
+
if (entries === undefined) {
|
|
280
|
+
if (layer === 'policySettings')
|
|
281
|
+
refuse = 'policy-unreadable';
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
for (const [k, v] of entries) {
|
|
285
|
+
if (PINNED_AT_ENTRY.has(k.toUpperCase())) {
|
|
286
|
+
dropped.push(Object.freeze({ key: k, why: 'pinned-at-entry' }));
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
put(k, v, layer);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const topLevel = own(input, 'topLevel');
|
|
293
|
+
const rf = merged.get(canon('READ_FACE'));
|
|
294
|
+
if (rf !== undefined) {
|
|
295
|
+
const t = rf.value.trim();
|
|
296
|
+
if (READ_FACE_VALUES.has(t))
|
|
297
|
+
merged.set(canon('READ_FACE'), { ...rf, value: t });
|
|
298
|
+
else {
|
|
299
|
+
merged.delete(canon('READ_FACE'));
|
|
300
|
+
if (t !== '')
|
|
301
|
+
dropped.push(Object.freeze({ key: 'READ_FACE', why: 'top-level-invalid' }));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (!merged.has(canon('READ_FACE'))) {
|
|
305
|
+
const s = own(topLevel, 'engineReadFace');
|
|
306
|
+
if (s !== undefined) {
|
|
307
|
+
const t = typeof s === 'string' ? s.trim() : undefined;
|
|
308
|
+
if (t !== undefined && READ_FACE_VALUES.has(t))
|
|
309
|
+
put('READ_FACE', t, 'top-level');
|
|
310
|
+
else if (t !== '')
|
|
311
|
+
dropped.push(Object.freeze({ key: 'READ_FACE', why: 'top-level-invalid' }));
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (!merged.has(canon('WORKFLOW_SIZE_GUIDELINE'))) {
|
|
315
|
+
const s = own(topLevel, 'workflowSizeGuideline');
|
|
316
|
+
if (typeof s === 'string' && WORKFLOW_SIZE_GUIDELINE_VALUES.has(s))
|
|
317
|
+
put('WORKFLOW_SIZE_GUIDELINE', s, 'top-level');
|
|
318
|
+
else if (s !== undefined)
|
|
319
|
+
dropped.push(Object.freeze({ key: 'WORKFLOW_SIZE_GUIDELINE', why: 'top-level-invalid' }));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
const rows = [...merged.values()];
|
|
323
|
+
return Object.freeze({
|
|
324
|
+
env: freezeRecord(rows.map((r) => [r.key, r.value])),
|
|
325
|
+
from: Object.freeze(rows.map((r) => Object.freeze({ key: r.key, source: r.source }))),
|
|
326
|
+
dropped: Object.freeze(dropped),
|
|
327
|
+
...(refuse !== undefined ? { refuse } : {}),
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
const PRINCIPAL_KEY = 'SEMA_LIVE_PRINCIPAL';
|
|
331
|
+
const PROCESS_PRINCIPAL_KEYS = Object.freeze(['SEMA_LIVE_PRINCIPAL', 'SEMA_FLEET_PRINCIPAL', 'SEMA_WORKFLOW_PRINCIPAL']);
|
|
332
|
+
const DEFAULT_PRINCIPAL = 'default';
|
|
333
|
+
const PRINCIPAL_LAYER_ORDER = Object.freeze(['policySettings', 'flagSettings', 'userSettings']);
|
|
334
|
+
function principalIn(block) {
|
|
335
|
+
const keys = envBlockKeysOf(block);
|
|
336
|
+
if (keys === undefined)
|
|
337
|
+
return { kind: 'unreadable' };
|
|
338
|
+
if (keys === null)
|
|
339
|
+
return { kind: 'unset' };
|
|
340
|
+
const slot = inSlotReadOf(block, PRINCIPAL_KEY);
|
|
341
|
+
if (slot.state === 'unproven' || slot.state === 'present_unreadable')
|
|
342
|
+
return { kind: 'unreadable' };
|
|
343
|
+
const v = slot.state === 'present' ? slot.value : undefined;
|
|
344
|
+
const p = typeof v === 'string' ? normalizeWirePrincipal(v) : undefined;
|
|
345
|
+
return p !== undefined ? { kind: 'value', principal: p } : { kind: 'unset' };
|
|
346
|
+
}
|
|
347
|
+
export function localEnginePrincipalOf(view) {
|
|
348
|
+
try {
|
|
349
|
+
const reads = layerReadsOf(own(view, 'layers'));
|
|
350
|
+
let resolved;
|
|
351
|
+
for (const layer of PRINCIPAL_LAYER_ORDER) {
|
|
352
|
+
const read = reads.get(layer);
|
|
353
|
+
if (read === undefined || read.kind === 'absent')
|
|
354
|
+
continue;
|
|
355
|
+
if (read.kind === 'unreadable')
|
|
356
|
+
return Object.freeze({ kind: 'unknown', layer });
|
|
357
|
+
const p = principalIn(read.env);
|
|
358
|
+
if (p.kind === 'unreadable')
|
|
359
|
+
return Object.freeze({ kind: 'unknown', layer });
|
|
360
|
+
if (p.kind === 'value') {
|
|
361
|
+
resolved = { principal: p.principal, source: 'settings' };
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
const result = resolved ?? { principal: DEFAULT_PRINCIPAL, source: 'default' };
|
|
366
|
+
const processEnv = own(view, 'processEnv');
|
|
367
|
+
const overridden = PROCESS_PRINCIPAL_KEYS.some((k) => {
|
|
368
|
+
const v = own(processEnv, k);
|
|
369
|
+
const p = typeof v === 'string' ? normalizeWirePrincipal(v) : undefined;
|
|
370
|
+
return p !== undefined && p !== result.principal;
|
|
371
|
+
});
|
|
372
|
+
return Object.freeze({ kind: 'principal', principal: result.principal, source: result.source, ...(overridden ? { ignoredProcessOverride: true } : {}) });
|
|
373
|
+
}
|
|
374
|
+
catch {
|
|
375
|
+
return Object.freeze({ kind: 'unknown', layer: 'userSettings' });
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
const LAYER_LABEL_KEYS = Object.freeze({
|
|
379
|
+
userSettings: 'localEngine.settingsLayer.userSettings',
|
|
380
|
+
flagSettings: 'localEngine.settingsLayer.flagSettings',
|
|
381
|
+
policySettings: 'localEngine.settingsLayer.policySettings',
|
|
382
|
+
});
|
|
383
|
+
export function localEnginePrincipalSentence(p, lang) {
|
|
384
|
+
try {
|
|
385
|
+
const kind = own(p, 'kind');
|
|
386
|
+
if (kind === 'unknown') {
|
|
387
|
+
const layer = own(p, 'layer');
|
|
388
|
+
if (layer !== 'userSettings' && layer !== 'flagSettings' && layer !== 'policySettings')
|
|
389
|
+
return undefined;
|
|
390
|
+
return renderMessage(msg('localEngine.principalUnknown', { layer: msg(LAYER_LABEL_KEYS[layer]) }), lang);
|
|
391
|
+
}
|
|
392
|
+
if (kind === 'principal' && own(p, 'ignoredProcessOverride') === true)
|
|
393
|
+
return renderMessage(msg('localEngine.principalOverrideIgnored'), lang);
|
|
394
|
+
return undefined;
|
|
395
|
+
}
|
|
396
|
+
catch {
|
|
397
|
+
return undefined;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
const BOOT_REFUSAL_MAX_CHARS = 800;
|
|
401
|
+
const BOOT_REFUSAL_MAX_HINTS = 2;
|
|
402
|
+
const CONFIG_CODE = /^config\.[A-Za-z0-9_.-]+$/;
|
|
403
|
+
function capSentence(s) {
|
|
404
|
+
const t = s.trim();
|
|
405
|
+
return t.length > BOOT_REFUSAL_MAX_CHARS ? `${t.slice(0, BOOT_REFUSAL_MAX_CHARS)}…` : t;
|
|
406
|
+
}
|
|
407
|
+
export function engineBootRefusalOf(lines, scrub) {
|
|
408
|
+
try {
|
|
409
|
+
const clean = (s) => {
|
|
410
|
+
try {
|
|
411
|
+
const out = scrub(s);
|
|
412
|
+
return typeof out === 'string' ? out : undefined;
|
|
413
|
+
}
|
|
414
|
+
catch {
|
|
415
|
+
return undefined;
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
const hints = [];
|
|
419
|
+
let code;
|
|
420
|
+
let hint;
|
|
421
|
+
let fatal;
|
|
422
|
+
const list = Array.isArray(lines) ? [...lines] : [];
|
|
423
|
+
for (const raw of list) {
|
|
424
|
+
if (typeof raw !== 'string')
|
|
425
|
+
continue;
|
|
426
|
+
const line = clean(raw);
|
|
427
|
+
if (line === undefined)
|
|
428
|
+
continue;
|
|
429
|
+
const t = line.trim();
|
|
430
|
+
if (!t.startsWith('{'))
|
|
431
|
+
continue;
|
|
432
|
+
const o = parseJsonLine(t);
|
|
433
|
+
if (!isRecord(o))
|
|
434
|
+
continue;
|
|
435
|
+
const m = own(o, 'msg');
|
|
436
|
+
const err = own(o, 'err');
|
|
437
|
+
if (m === 'fatal' && typeof err === 'string' && err.trim() !== '') {
|
|
438
|
+
const full = clean(err);
|
|
439
|
+
const s = full === undefined ? undefined : full.replace(/^\s*Error:\s*/, '');
|
|
440
|
+
if (s !== undefined && s.trim() !== '')
|
|
441
|
+
fatal = capSentence(s);
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
const c = own(o, 'code');
|
|
445
|
+
const h = own(o, 'hint');
|
|
446
|
+
if (typeof c === 'string' && CONFIG_CODE.test(c) && typeof h === 'string' && h.trim() !== '') {
|
|
447
|
+
const model = own(o, 'model');
|
|
448
|
+
const who = typeof model === 'string' && model !== '' ? `"${model}": ` : '';
|
|
449
|
+
const s = clean(`${who}${h}`);
|
|
450
|
+
const cc = clean(c);
|
|
451
|
+
if (s === undefined || cc === undefined || !CONFIG_CODE.test(cc))
|
|
452
|
+
continue;
|
|
453
|
+
const sentence = capSentence(s);
|
|
454
|
+
code = cc;
|
|
455
|
+
const ch = clean(h);
|
|
456
|
+
hint = ch === undefined ? undefined : capSentence(ch);
|
|
457
|
+
if (hints.includes(sentence))
|
|
458
|
+
continue;
|
|
459
|
+
hints.push(sentence);
|
|
460
|
+
if (hints.length > BOOT_REFUSAL_MAX_HINTS)
|
|
461
|
+
hints.shift();
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
const parts = [...hints, ...(fatal !== undefined ? [fatal] : [])];
|
|
465
|
+
if (parts.length === 0)
|
|
466
|
+
return undefined;
|
|
467
|
+
return Object.freeze({ ...(code !== undefined ? { code } : {}), ...(hint !== undefined ? { hint } : {}), text: parts.join('\n') });
|
|
468
|
+
}
|
|
469
|
+
catch {
|
|
470
|
+
return undefined;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
export function engineBootRefusalSentence(refusal, lang) {
|
|
474
|
+
try {
|
|
475
|
+
const text = own(refusal, 'text');
|
|
476
|
+
if (typeof text !== 'string' || text.trim() === '')
|
|
477
|
+
return undefined;
|
|
478
|
+
return renderMessage(msg('localEngine.bootRefusal', { reason: text }), lang);
|
|
479
|
+
}
|
|
480
|
+
catch {
|
|
481
|
+
return undefined;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
export function localEngineFirstShareSentence(lang) {
|
|
485
|
+
return renderMessage(msg('localEngine.firstShare'), lang);
|
|
486
|
+
}
|