entroly-wasm 1.0.78 → 1.0.80
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/data/tuning_defaults.json +5 -5
- package/index.d.ts +8 -0
- package/index.js +90 -1
- package/js/continuity_contracts.d.ts +86 -0
- package/js/continuity_contracts.js +81 -0
- package/js/trust_engine.d.ts +18 -0
- package/js/trust_engine.js +31 -0
- package/js/work_context_snapshot_store.d.ts +43 -0
- package/js/work_context_snapshot_store.js +280 -0
- package/js/work_graph.d.ts +225 -0
- package/js/work_graph.js +191 -0
- package/js/work_graph_content_digest.js +151 -0
- package/js/work_graph_continuity.d.ts +54 -0
- package/js/work_graph_continuity.js +128 -0
- package/js/work_graph_repo.d.ts +26 -0
- package/js/work_graph_repo.js +364 -0
- package/js/work_graph_store.d.ts +85 -0
- package/js/work_graph_store.js +364 -0
- package/package.json +18 -3
- package/pkg/entroly_wasm.d.ts +208 -0
- package/pkg/entroly_wasm.js +1710 -2
- package/pkg/entroly_wasm_bg.wasm +0 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Persistence mechanics only. Work-state semantics remain in shared Rust.
|
|
4
|
+
const crypto = require('crypto');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { WorkGraph } = require('./work_graph');
|
|
9
|
+
const { enrichWorktreeContentDigests } = require('./work_graph_content_digest');
|
|
10
|
+
const { discoverRepositoryIdentity, discoverRepositoryObservation } = require('./work_graph_repo');
|
|
11
|
+
|
|
12
|
+
const DEFAULT_LOCK_TIMEOUT_MS = 5000;
|
|
13
|
+
const DEFAULT_STALE_LOCK_MS = 120000;
|
|
14
|
+
const DEFAULT_LOCK_SETTLE_MS = 1000;
|
|
15
|
+
const DEFAULT_MAX_STATE_BYTES = 64 * 1024 * 1024;
|
|
16
|
+
|
|
17
|
+
class WorkGraphStoreError extends Error {
|
|
18
|
+
constructor(message) { super(message); this.name = 'WorkGraphStoreError'; }
|
|
19
|
+
}
|
|
20
|
+
class WorkGraphLockTimeout extends WorkGraphStoreError {
|
|
21
|
+
constructor(message) { super(message); this.name = 'WorkGraphLockTimeout'; }
|
|
22
|
+
}
|
|
23
|
+
class WorkGraphStateError extends WorkGraphStoreError {
|
|
24
|
+
constructor(message) { super(message); this.name = 'WorkGraphStateError'; }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function finiteNonnegative(value, name) {
|
|
28
|
+
const number = Number(value);
|
|
29
|
+
if (!Number.isFinite(number) || number < 0) {
|
|
30
|
+
throw new WorkGraphStateError(`${name} must be a finite non-negative number`);
|
|
31
|
+
}
|
|
32
|
+
return number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function positiveSafeInteger(value, name) {
|
|
36
|
+
const number = Number(value);
|
|
37
|
+
if (!Number.isSafeInteger(number) || number < 1) {
|
|
38
|
+
throw new WorkGraphStateError(`${name} must be a positive safe integer`);
|
|
39
|
+
}
|
|
40
|
+
return number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function defaultStoreRoot() {
|
|
44
|
+
const base = process.env.ENTROLY_DIR
|
|
45
|
+
? path.resolve(process.env.ENTROLY_DIR)
|
|
46
|
+
: path.join(os.homedir(), '.entroly');
|
|
47
|
+
return path.join(base, 'work-graphs');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function repoKey(repoId) {
|
|
51
|
+
if (!repoId) throw new WorkGraphStateError('repo_id must not be empty');
|
|
52
|
+
return crypto.createHash('sha256').update(String(repoId), 'utf8').digest('hex').slice(0, 32);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function secureDirectory(dir) {
|
|
56
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
57
|
+
const stat = fs.lstatSync(dir);
|
|
58
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
59
|
+
throw new WorkGraphStateError(`unsafe Work Graph directory: ${dir}`);
|
|
60
|
+
}
|
|
61
|
+
if (process.platform !== 'win32') fs.chmodSync(dir, 0o700);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function sleepMs(ms) {
|
|
65
|
+
const wait = new Int32Array(new SharedArrayBuffer(4));
|
|
66
|
+
Atomics.wait(wait, 0, 0, Math.max(0, ms));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function fsyncDirectory(dir) {
|
|
70
|
+
if (process.platform === 'win32') return;
|
|
71
|
+
let fd;
|
|
72
|
+
try {
|
|
73
|
+
fd = fs.openSync(dir, fs.constants.O_RDONLY);
|
|
74
|
+
fs.fsyncSync(fd);
|
|
75
|
+
} catch (_) {
|
|
76
|
+
// File fsync + atomic rename remain the primary durability guarantee.
|
|
77
|
+
} finally {
|
|
78
|
+
if (fd !== undefined) fs.closeSync(fd);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
class WorkGraphStore {
|
|
83
|
+
constructor(repoId, options = {}) {
|
|
84
|
+
this.repoId = String(repoId || '');
|
|
85
|
+
this.root = options.root ? path.resolve(String(options.root)) : defaultStoreRoot();
|
|
86
|
+
this.repoDir = path.join(this.root, repoKey(this.repoId));
|
|
87
|
+
this.statePath = path.join(this.repoDir, 'state.json');
|
|
88
|
+
this.lockPath = path.join(this.repoDir, '.lock');
|
|
89
|
+
this.lockTimeoutMs = finiteNonnegative(
|
|
90
|
+
options.lockTimeoutMs ?? DEFAULT_LOCK_TIMEOUT_MS, 'lockTimeoutMs',
|
|
91
|
+
);
|
|
92
|
+
this.staleLockMs = Math.max(1000, finiteNonnegative(
|
|
93
|
+
options.staleLockMs ?? DEFAULT_STALE_LOCK_MS, 'staleLockMs',
|
|
94
|
+
));
|
|
95
|
+
this.maxStateBytes = Math.max(1024, positiveSafeInteger(
|
|
96
|
+
options.maxStateBytes ?? DEFAULT_MAX_STATE_BYTES, 'maxStateBytes',
|
|
97
|
+
));
|
|
98
|
+
secureDirectory(this.root);
|
|
99
|
+
secureDirectory(this.repoDir);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static forRepository(repoPath = '.', options = {}) {
|
|
103
|
+
const identity = discoverRepositoryIdentity(repoPath);
|
|
104
|
+
return new WorkGraphStore(identity.repo_id, options);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
readLockToken() {
|
|
108
|
+
try {
|
|
109
|
+
const stat = fs.lstatSync(this.lockPath);
|
|
110
|
+
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
111
|
+
throw new WorkGraphStateError(`unsafe Work Graph lock path: ${this.lockPath}`);
|
|
112
|
+
}
|
|
113
|
+
return fs.readFileSync(this.lockPath, 'utf8').split('\n', 1)[0];
|
|
114
|
+
} catch (error) {
|
|
115
|
+
if (error instanceof WorkGraphStateError) throw error;
|
|
116
|
+
return '';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
filesystemNowMs() {
|
|
121
|
+
const probe = path.join(this.repoDir, `.clock-${crypto.randomUUID().replace(/-/g, '')}`);
|
|
122
|
+
let fd;
|
|
123
|
+
try {
|
|
124
|
+
fd = fs.openSync(probe, 'wx', 0o600);
|
|
125
|
+
fs.closeSync(fd);
|
|
126
|
+
fd = undefined;
|
|
127
|
+
return fs.statSync(probe).mtimeMs;
|
|
128
|
+
} catch (error) {
|
|
129
|
+
throw new WorkGraphStoreError(`cannot sample Work Graph filesystem clock: ${error.message}`);
|
|
130
|
+
} finally {
|
|
131
|
+
if (fd !== undefined) { try { fs.closeSync(fd); } catch (_) {} }
|
|
132
|
+
try { fs.unlinkSync(probe); } catch (_) {}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
lockIsStale() {
|
|
137
|
+
let stat;
|
|
138
|
+
try { stat = fs.lstatSync(this.lockPath); }
|
|
139
|
+
catch (_) { return false; }
|
|
140
|
+
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
141
|
+
throw new WorkGraphStateError(`unsafe Work Graph lock path: ${this.lockPath}`);
|
|
142
|
+
}
|
|
143
|
+
const first = stat.mtimeMs;
|
|
144
|
+
if (this.filesystemNowMs() - first < this.staleLockMs) return false;
|
|
145
|
+
sleepMs(DEFAULT_LOCK_SETTLE_MS);
|
|
146
|
+
let second;
|
|
147
|
+
try { second = fs.statSync(this.lockPath).mtimeMs; }
|
|
148
|
+
catch (_) { return false; }
|
|
149
|
+
return second === first && this.filesystemNowMs() - second >= this.staleLockMs;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
breakStaleLock() {
|
|
153
|
+
if (!this.lockIsStale()) return false;
|
|
154
|
+
try { fs.unlinkSync(this.lockPath); return true; }
|
|
155
|
+
catch (error) { return error && error.code === 'ENOENT'; }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
tryAcquireLock(token) {
|
|
159
|
+
let fd;
|
|
160
|
+
try {
|
|
161
|
+
fd = fs.openSync(this.lockPath, 'wx', 0o600);
|
|
162
|
+
fs.writeFileSync(fd, `${token}\n${(Date.now() / 1000).toFixed(6)}\n`, 'utf8');
|
|
163
|
+
fs.fsyncSync(fd);
|
|
164
|
+
fs.closeSync(fd);
|
|
165
|
+
return true;
|
|
166
|
+
} catch (error) {
|
|
167
|
+
if (fd !== undefined) { try { fs.closeSync(fd); } catch (_) {} }
|
|
168
|
+
if (error && error.code === 'EEXIST') return false;
|
|
169
|
+
throw new WorkGraphStoreError(`cannot acquire Work Graph lock: ${error.message}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
acquireLock() {
|
|
174
|
+
const started = process.hrtime.bigint();
|
|
175
|
+
const timeoutNs = BigInt(Math.trunc(this.lockTimeoutMs * 1e6));
|
|
176
|
+
const token = `${os.hostname()}:${process.pid}:${crypto.randomUUID().replace(/-/g, '')}`;
|
|
177
|
+
let delay = 1;
|
|
178
|
+
for (;;) {
|
|
179
|
+
if (this.tryAcquireLock(token)) return token;
|
|
180
|
+
if (this.breakStaleLock()) continue;
|
|
181
|
+
if (process.hrtime.bigint() - started >= timeoutNs) {
|
|
182
|
+
throw new WorkGraphLockTimeout(`timed out acquiring Work Graph lock for ${this.repoId}`);
|
|
183
|
+
}
|
|
184
|
+
const jitter = 0.5 + crypto.randomInt(0, 65536) / 65535;
|
|
185
|
+
sleepMs(Math.max(1, Math.floor(delay * jitter)));
|
|
186
|
+
delay = Math.min(delay * 2, 50);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
releaseLock(token) {
|
|
191
|
+
if (this.readLockToken() !== token) return;
|
|
192
|
+
try { fs.unlinkSync(this.lockPath); } catch (_) {}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
withLock(fn) {
|
|
196
|
+
const token = this.acquireLock();
|
|
197
|
+
try { return fn(); }
|
|
198
|
+
finally { this.releaseLock(token); }
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
loadUnlocked() {
|
|
202
|
+
if (!fs.existsSync(this.statePath)) return new WorkGraph(this.repoId);
|
|
203
|
+
const stat = fs.lstatSync(this.statePath);
|
|
204
|
+
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
205
|
+
throw new WorkGraphStateError(`unsafe Work Graph state: ${this.statePath}`);
|
|
206
|
+
}
|
|
207
|
+
if (stat.size > this.maxStateBytes) {
|
|
208
|
+
throw new WorkGraphStateError(`Work Graph state is ${stat.size} bytes; limit is ${this.maxStateBytes}`);
|
|
209
|
+
}
|
|
210
|
+
let graph;
|
|
211
|
+
try { graph = WorkGraph.fromJSON(fs.readFileSync(this.statePath, 'utf8')); }
|
|
212
|
+
catch (error) { throw new WorkGraphStateError(`cannot load Work Graph state: ${error.message}`); }
|
|
213
|
+
if (graph.repoId !== this.repoId) {
|
|
214
|
+
throw new WorkGraphStateError(
|
|
215
|
+
`stored Work Graph repo mismatch: expected ${this.repoId}, got ${graph.repoId}`,
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
return graph;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
saveUnlocked(graph) {
|
|
222
|
+
if (graph.repoId !== this.repoId) {
|
|
223
|
+
throw new WorkGraphStateError(
|
|
224
|
+
`cannot persist foreign Work Graph: expected ${this.repoId}, got ${graph.repoId}`,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
const payload = Buffer.from(graph.exportJSON(false), 'utf8');
|
|
228
|
+
if (payload.length > this.maxStateBytes) {
|
|
229
|
+
throw new WorkGraphStateError(`Work Graph state is ${payload.length} bytes; limit is ${this.maxStateBytes}`);
|
|
230
|
+
}
|
|
231
|
+
secureDirectory(this.repoDir);
|
|
232
|
+
const temp = path.join(this.repoDir, `.state-${process.pid}-${crypto.randomUUID().replace(/-/g, '')}.tmp`);
|
|
233
|
+
let fd;
|
|
234
|
+
try {
|
|
235
|
+
fd = fs.openSync(temp, 'wx', 0o600);
|
|
236
|
+
fs.writeFileSync(fd, payload);
|
|
237
|
+
fs.fsyncSync(fd);
|
|
238
|
+
fs.closeSync(fd);
|
|
239
|
+
fd = undefined;
|
|
240
|
+
fs.renameSync(temp, this.statePath);
|
|
241
|
+
if (process.platform !== 'win32') fs.chmodSync(this.statePath, 0o600);
|
|
242
|
+
fsyncDirectory(this.repoDir);
|
|
243
|
+
} finally {
|
|
244
|
+
if (fd !== undefined) { try { fs.closeSync(fd); } catch (_) {} }
|
|
245
|
+
try { fs.unlinkSync(temp); } catch (_) {}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
load() { return this.withLock(() => this.loadUnlocked()); }
|
|
250
|
+
|
|
251
|
+
save(graph) {
|
|
252
|
+
return this.withLock(() => {
|
|
253
|
+
const current = this.loadUnlocked();
|
|
254
|
+
current.merge(graph);
|
|
255
|
+
this.saveUnlocked(current);
|
|
256
|
+
return current;
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
submitObservation(observation) {
|
|
261
|
+
if (!observation || observation.repo_id !== this.repoId) {
|
|
262
|
+
throw new WorkGraphStateError(
|
|
263
|
+
`repository identity changed: expected ${this.repoId}, got ${observation && observation.repo_id}`,
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
return this.withLock(() => {
|
|
267
|
+
const graph = this.loadUnlocked();
|
|
268
|
+
graph.observeRepository(observation);
|
|
269
|
+
this.saveUnlocked(graph);
|
|
270
|
+
return graph;
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
mutate(operation) {
|
|
275
|
+
return this.withLock(() => {
|
|
276
|
+
const graph = this.loadUnlocked();
|
|
277
|
+
const result = operation(graph);
|
|
278
|
+
this.saveUnlocked(graph);
|
|
279
|
+
return { graph, result };
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
updateRepository(repoPath = '.', options = {}) {
|
|
284
|
+
const observation = discoverRepositoryObservation(repoPath, options);
|
|
285
|
+
enrichWorktreeContentDigests(repoPath, observation);
|
|
286
|
+
return this.submitObservation(observation);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
claimWork(repoPath, options = {}) {
|
|
290
|
+
const agentId = String(options.agentId || '').trim();
|
|
291
|
+
const taskTitle = String(options.taskTitle || '').trim();
|
|
292
|
+
if (!agentId || !taskTitle) {
|
|
293
|
+
throw new WorkGraphStateError('agentId and taskTitle must not be empty');
|
|
294
|
+
}
|
|
295
|
+
const nowMs = options.observedAtMs == null ? Date.now() : Number(options.observedAtMs);
|
|
296
|
+
if (!Number.isSafeInteger(nowMs)) {
|
|
297
|
+
throw new WorkGraphStateError('observedAtMs must be a JavaScript-safe integer');
|
|
298
|
+
}
|
|
299
|
+
const ttlMs = positiveSafeInteger(options.ttlMs ?? 900000, 'ttlMs');
|
|
300
|
+
const leaseId = String(options.leaseId || crypto.randomUUID().replace(/-/g, ''));
|
|
301
|
+
const taskId = String(options.taskId || '');
|
|
302
|
+
const sourceKind = String(options.sourceKind || 'agent_statement');
|
|
303
|
+
if (!['agent_statement', 'user_statement'].includes(sourceKind)) {
|
|
304
|
+
throw new WorkGraphStateError("sourceKind must be 'agent_statement' or 'user_statement'");
|
|
305
|
+
}
|
|
306
|
+
const observation = discoverRepositoryObservation(repoPath, {
|
|
307
|
+
agentId,
|
|
308
|
+
sessionId: String(options.sessionId || ''),
|
|
309
|
+
observedAtMs: nowMs,
|
|
310
|
+
taskHint: {
|
|
311
|
+
task_id: taskId,
|
|
312
|
+
title: taskTitle,
|
|
313
|
+
trust: 'observed',
|
|
314
|
+
explicit_status: 'in_progress',
|
|
315
|
+
remaining_work: [],
|
|
316
|
+
source_kind: sourceKind,
|
|
317
|
+
source_ref: `work-claim:${leaseId}`,
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
observation.leases = [{
|
|
321
|
+
lease_id: leaseId,
|
|
322
|
+
agent_id: agentId,
|
|
323
|
+
task_id: taskId,
|
|
324
|
+
scope_paths: [...new Set(options.scopePaths || [])].map(String).sort(),
|
|
325
|
+
scope_symbols: [...new Set(options.scopeSymbols || [])].map(String).sort(),
|
|
326
|
+
expires_at_ms: nowMs + ttlMs,
|
|
327
|
+
source_ref: `work-lease:${leaseId}`,
|
|
328
|
+
}];
|
|
329
|
+
enrichWorktreeContentDigests(repoPath, observation);
|
|
330
|
+
return { graph: this.submitObservation(observation), leaseId };
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
coordination(nowMs = Date.now()) { return this.load().coordination(nowMs); }
|
|
334
|
+
resume(workstreamId = null, maxEvidence = 128) {
|
|
335
|
+
return this.load().resume(workstreamId, maxEvidence);
|
|
336
|
+
}
|
|
337
|
+
recordContextReceipt(receipt, options = {}) {
|
|
338
|
+
return this.mutate((graph) => graph.recordContextReceipt(receipt, options));
|
|
339
|
+
}
|
|
340
|
+
recordMemory(memory, nowMs, supersededIds = []) {
|
|
341
|
+
return this.mutate((graph) => graph.recordMemory(memory, nowMs, supersededIds));
|
|
342
|
+
}
|
|
343
|
+
recordExecutionChain(route, outcome, verification, invalidatedCommitments = []) {
|
|
344
|
+
return this.mutate((graph) => graph.recordExecutionChain(
|
|
345
|
+
route, outcome, verification, invalidatedCommitments,
|
|
346
|
+
));
|
|
347
|
+
}
|
|
348
|
+
continuationProof(handoff, manifest) {
|
|
349
|
+
return this.load().continuationProof(handoff, manifest);
|
|
350
|
+
}
|
|
351
|
+
reconstructedContinuationProof(workstreamId, toAgent, manifest) {
|
|
352
|
+
return this.load().reconstructedContinuationProof(workstreamId, toAgent, manifest);
|
|
353
|
+
}
|
|
354
|
+
handoff(workstreamId, fromAgent, toAgent, generatedAtMs = Date.now()) {
|
|
355
|
+
return this.load().handoff(workstreamId, fromAgent, toAgent, generatedAtMs);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
module.exports = {
|
|
360
|
+
WorkGraphLockTimeout,
|
|
361
|
+
WorkGraphStateError,
|
|
362
|
+
WorkGraphStore,
|
|
363
|
+
WorkGraphStoreError,
|
|
364
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "entroly-wasm",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.80",
|
|
4
4
|
"description": "WebAssembly Context Assurance for AI agents: reduce avoidable token usage with local evidence selection, receipts, exact recovery, and verification.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -32,12 +32,27 @@
|
|
|
32
32
|
"js/value_tracker.js",
|
|
33
33
|
"js/app_sdk.js",
|
|
34
34
|
"js/context_receipts.js",
|
|
35
|
+
"js/continuity_contracts.js",
|
|
36
|
+
"js/continuity_contracts.d.ts",
|
|
35
37
|
"js/agentskills_export.js",
|
|
36
38
|
"js/gateways.js",
|
|
37
39
|
"js/vault_observer.js",
|
|
38
40
|
"js/distill.js",
|
|
39
41
|
"js/federation.js",
|
|
40
|
-
"js/evolution_daemon.js"
|
|
42
|
+
"js/evolution_daemon.js",
|
|
43
|
+
"js/trust_engine.js",
|
|
44
|
+
"js/trust_engine.d.ts",
|
|
45
|
+
"js/work_graph.js",
|
|
46
|
+
"js/work_graph.d.ts",
|
|
47
|
+
"js/work_graph_repo.js",
|
|
48
|
+
"js/work_graph_repo.d.ts",
|
|
49
|
+
"js/work_graph_store.js",
|
|
50
|
+
"js/work_graph_store.d.ts",
|
|
51
|
+
"js/work_context_snapshot_store.js",
|
|
52
|
+
"js/work_context_snapshot_store.d.ts",
|
|
53
|
+
"js/work_graph_content_digest.js",
|
|
54
|
+
"js/work_graph_continuity.js",
|
|
55
|
+
"js/work_graph_continuity.d.ts"
|
|
41
56
|
],
|
|
42
57
|
"scripts": {
|
|
43
58
|
"build": "wasm-pack build --target nodejs --out-dir pkg",
|
|
@@ -48,7 +63,7 @@
|
|
|
48
63
|
"health": "node js/cli.js health",
|
|
49
64
|
"demo": "node js/cli.js demo",
|
|
50
65
|
"autotune": "node js/cli.js autotune",
|
|
51
|
-
"test": "node test_wasm_e2e.js"
|
|
66
|
+
"test": "node test_wasm_e2e.js && node test_work_graph.js && node test_work_graph_repo.js && node test_work_graph_store.js && node test_work_graph_content_digest.js && node test_work_graph_continuity.js && node test_context_trust_delivery.js && node test_work_graph_performance.js && node test_work_graph_root_exports.js && node test_context_receipt_parity.js"
|
|
52
67
|
},
|
|
53
68
|
"keywords": [
|
|
54
69
|
"entroly",
|
package/pkg/entroly_wasm.d.ts
CHANGED
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
/* tslint:disable */
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
|
|
4
|
+
export class WasmCognitiveBus {
|
|
5
|
+
free(): void;
|
|
6
|
+
[Symbol.dispose](): void;
|
|
7
|
+
/**
|
|
8
|
+
* Full event shape: `id`, `source_agent`, `event_type`, `content`,
|
|
9
|
+
* `timestamp`, `emotional_tag`, `salience`, `is_spike`.
|
|
10
|
+
*/
|
|
11
|
+
drainJSON(agent_id: string, limit?: number | null): string;
|
|
12
|
+
/**
|
|
13
|
+
* Hippocampus bridge shape: `content`, `source`, `salience`,
|
|
14
|
+
* `emotional_tag`, `event_type`. Deliberately narrower than `drainJSON`.
|
|
15
|
+
*/
|
|
16
|
+
drainMemoryBridgeJSON(): string;
|
|
17
|
+
/**
|
|
18
|
+
* `memorySalienceThreshold` matches the PyO3 default of 50.0.
|
|
19
|
+
*/
|
|
20
|
+
constructor(memory_salience_threshold?: number | null);
|
|
21
|
+
/**
|
|
22
|
+
* Returns the number of subscribers the event was routed to, exactly as
|
|
23
|
+
* the PyO3 `publish` does.
|
|
24
|
+
*/
|
|
25
|
+
publish(source_agent: string, event_type: string, content: string, emotional_tag?: number | null, salience?: number | null): number;
|
|
26
|
+
queueDepth(agent_id: string): number;
|
|
27
|
+
setTaskContext(agent_id: string, task_text: string): void;
|
|
28
|
+
setTick(tick: number): void;
|
|
29
|
+
statsJSON(): string;
|
|
30
|
+
/**
|
|
31
|
+
* `eventTypesJSON` is a JSON array of event-type strings. Passing them as
|
|
32
|
+
* JSON rather than a `Box<[JsString]>` keeps one decoding path shared with
|
|
33
|
+
* every other binding here.
|
|
34
|
+
*/
|
|
35
|
+
subscribe(agent_id: string, event_types_json: string): void;
|
|
36
|
+
tick(): void;
|
|
37
|
+
unsubscribe(agent_id: string): void;
|
|
38
|
+
}
|
|
39
|
+
|
|
4
40
|
export class WasmEntrolyEngine {
|
|
5
41
|
free(): void;
|
|
6
42
|
[Symbol.dispose](): void;
|
|
@@ -201,10 +237,129 @@ export class WasmEntrolyEngine {
|
|
|
201
237
|
stats(): any;
|
|
202
238
|
}
|
|
203
239
|
|
|
240
|
+
export class WasmNkbeAllocator {
|
|
241
|
+
free(): void;
|
|
242
|
+
[Symbol.dispose](): void;
|
|
243
|
+
/**
|
|
244
|
+
* Returns false when the agent is unknown, matching PyO3.
|
|
245
|
+
*/
|
|
246
|
+
addFragment(agent_name: string, fragment_id: string, relevance: number, token_cost: number): boolean;
|
|
247
|
+
/**
|
|
248
|
+
* `{agent_name: {budget, weight, utility}}`, as the engine builds it.
|
|
249
|
+
*/
|
|
250
|
+
allocateJSON(): string;
|
|
251
|
+
/**
|
|
252
|
+
* Defaults mirror the PyO3 constructor exactly: 128000 / 0.1 / 1e-4 / 30 /
|
|
253
|
+
* 5 / 0.01. Divergent defaults would be a parity break that no test on
|
|
254
|
+
* either side would notice.
|
|
255
|
+
*/
|
|
256
|
+
constructor(global_budget?: number | null, tau?: number | null, epsilon?: number | null, max_iter?: number | null, nash_iterations?: number | null, learning_rate?: number | null);
|
|
257
|
+
registerAgent(name: string, weight: number, min_budget: number): void;
|
|
258
|
+
reinforce(outcomes_json: string): boolean;
|
|
259
|
+
statsJSON(): string;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export class WasmTrustEngine {
|
|
263
|
+
free(): void;
|
|
264
|
+
[Symbol.dispose](): void;
|
|
265
|
+
assessClaimJSON(evidence: string, claim: string): string;
|
|
266
|
+
fileCriticality(path: string): string;
|
|
267
|
+
hasSafetySignal(content: string): boolean;
|
|
268
|
+
constructor(profile: string);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export class WasmWorkGraph {
|
|
272
|
+
free(): void;
|
|
273
|
+
[Symbol.dispose](): void;
|
|
274
|
+
applyEventJSON(json_text: string): string;
|
|
275
|
+
contextScopeJSON(workstream_id: string | null | undefined, max_evidence: number, pretty: boolean): string;
|
|
276
|
+
continuationProofJSON(handoff_json: string, manifest_json: string): string;
|
|
277
|
+
coordinationJSON(now_ms: number, pretty: boolean): string;
|
|
278
|
+
exportJSON(pretty: boolean): string;
|
|
279
|
+
static fromJSON(json_text: string): WasmWorkGraph;
|
|
280
|
+
handoffJSON(workstream_id: string, from_agent: string, to_agent: string, generated_at_ms: number, pretty: boolean): string;
|
|
281
|
+
mergeJSON(json_text: string): number;
|
|
282
|
+
constructor(repo_id: string);
|
|
283
|
+
observeRepositoryJSON(json_text: string): string;
|
|
284
|
+
reconstructedContinuationProofJSON(workstream_id: string, to_agent: string, manifest_json: string): string;
|
|
285
|
+
recordContextReceiptJSON(receipt_json: string, agent_id: string, session_id: string): string;
|
|
286
|
+
recordExecutionChainJSON(route_json: string, outcome_json: string, verification_json: string, invalidated_commitments_json?: string | null): string;
|
|
287
|
+
recordMemoryJSON(memory_json: string, now_ms: number, superseded_ids_json?: string | null): string;
|
|
288
|
+
resumeJSON(workstream_id: string | null | undefined, max_evidence: number, pretty: boolean): string;
|
|
289
|
+
snapshotJSON(pretty: boolean): string;
|
|
290
|
+
summaryJSON(): string;
|
|
291
|
+
unfinishedJSON(pretty: boolean): string;
|
|
292
|
+
static verifyHandoffIntegrityJSON(receipt_json: string): boolean;
|
|
293
|
+
verifyHandoffJSON(receipt_json: string): boolean;
|
|
294
|
+
readonly eventCount: number;
|
|
295
|
+
readonly graphCommitment: string;
|
|
296
|
+
readonly repoId: string;
|
|
297
|
+
readonly revision: bigint;
|
|
298
|
+
}
|
|
299
|
+
|
|
204
300
|
export function classify_learning_query(query: string): string;
|
|
205
301
|
|
|
206
302
|
export function classify_query_transition(prev_hash: bigint, current_query: string, elapsed_s: number, time_window_s: number, rephrase_threshold: number, topic_change_threshold: number): any;
|
|
207
303
|
|
|
304
|
+
/**
|
|
305
|
+
* Build a canonical receipt envelope and return it as canonical JSON.
|
|
306
|
+
*
|
|
307
|
+
* Reference lists arrive as JSON arrays rather than `Box<[JsString]>` so there
|
|
308
|
+
* is one decoding path shared with the other bindings here, and so an empty
|
|
309
|
+
* list is expressed the same way in both runtimes.
|
|
310
|
+
*/
|
|
311
|
+
export function contextReceiptBuildJSON(repository_id: string, repository_commitment: string, graph_commitment: string, work_scope_id: string, source_commitment?: string | null, selected_refs_json?: string | null, omitted_refs_json?: string | null, pinned_refs_json?: string | null, recoverable_refs_json?: string | null, recovery_handles_json?: string | null, evidence_ids_json?: string | null, budget_tokens?: number | null, selection_policy?: string | null, execution_id?: string | null, created_at_ms?: number | null): string;
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* The commitment carried by a verified envelope.
|
|
315
|
+
*/
|
|
316
|
+
export function contextReceiptCommitment(receipt_json: string): string;
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Project a verified envelope into the Work Graph reference form, as JSON.
|
|
320
|
+
*/
|
|
321
|
+
export function contextReceiptGraphRefJSON(receipt_json: string, workstream_id: string, agent_id: string, session_id: string): string;
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Schema version this build implements.
|
|
325
|
+
*/
|
|
326
|
+
export function contextReceiptSchemaVersion(): number;
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Parse and verify an envelope, returning its canonical JSON.
|
|
330
|
+
*
|
|
331
|
+
* Fails closed on a commitment that does not recompute and on an unrecognised
|
|
332
|
+
* schema version — a caller cannot obtain an unverified envelope here.
|
|
333
|
+
*/
|
|
334
|
+
export function contextReceiptVerifyJSON(receipt_json: string): string;
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* May this memory be injected, and why.
|
|
338
|
+
*
|
|
339
|
+
* No score parameter, by design — section 10's "do not let similarity score
|
|
340
|
+
* imply truth" is enforced by the signature in both runtimes alike.
|
|
341
|
+
*/
|
|
342
|
+
export function memoryRecordAdmissibility(record_json: string, now_ms: number, superseded_ids_json?: string | null): string;
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Build a memory record and return it as canonical JSON.
|
|
346
|
+
*/
|
|
347
|
+
export function memoryRecordBuildJSON(repository_id: string, content_reference: string, trust_state: string, task_id?: string | null, workstream_id?: string | null, source_agent?: string | null, source_session?: string | null, source_execution?: string | null, content_commitment?: string | null, evidence_ids_json?: string | null, created_at_ms?: number | null, observed_at_ms?: number | null, valid_until_ms?: number | null, supersedes_json?: string | null, contradicted_by_json?: string | null, recovery_handle?: string | null): string;
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Schema version this build implements for memory records.
|
|
351
|
+
*/
|
|
352
|
+
export function memoryRecordSchemaVersion(): number;
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Parse and check a memory record, returning its canonical JSON.
|
|
356
|
+
*/
|
|
357
|
+
export function memoryRecordVerifyJSON(record_json: string): string;
|
|
358
|
+
|
|
359
|
+
export function modelExecutionOutcomeBuildJSON(input_json: string): string;
|
|
360
|
+
|
|
361
|
+
export function modelExecutionOutcomeVerifyJSON(value_json: string): string;
|
|
362
|
+
|
|
208
363
|
export function optimize_task_profiles(episodes_json: string): any;
|
|
209
364
|
|
|
210
365
|
export function qccr_expand_query(query: string): string;
|
|
@@ -213,4 +368,57 @@ export function qccr_rank_files(sources: string[], texts: string[], query: strin
|
|
|
213
368
|
|
|
214
369
|
export function qccr_select(fragments_json: string, token_budget: number, query: string, overrides_json: string, preferred_json: string): string;
|
|
215
370
|
|
|
371
|
+
/**
|
|
372
|
+
* Build a recovery handle and return it as canonical JSON.
|
|
373
|
+
*
|
|
374
|
+
* Throws when a disposition promises recovery without the means to honour it.
|
|
375
|
+
*/
|
|
376
|
+
export function recoveryHandleBuildJSON(repository_id: string, receipt_id: string, disposition: string, source_ref?: string | null, source_commitment?: string | null, fragment_commitment?: string | null, byte_start?: number | null, byte_end?: number | null, version?: string | null, storage_locator?: string | null, observed_at_ms?: number | null): string;
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Schema version this build implements for recovery handles.
|
|
380
|
+
*/
|
|
381
|
+
export function recoveryHandleSchemaVersion(): number;
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Check recovered bytes against the handle's commitment.
|
|
385
|
+
*
|
|
386
|
+
* Returns `verified`, `commitment_mismatch` or `not_recoverable`.
|
|
387
|
+
*/
|
|
388
|
+
export function recoveryHandleVerifyBytes(handle_json: string, payload: Uint8Array): string;
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Parse and check a handle, returning its canonical JSON.
|
|
392
|
+
*/
|
|
393
|
+
export function recoveryHandleVerifyJSON(handle_json: string): string;
|
|
394
|
+
|
|
216
395
|
export function reward_weighted_optimize(episodes_json: string, current_weights_json: string): any;
|
|
396
|
+
|
|
397
|
+
export function routingDecisionBuildJSON(input_json: string): string;
|
|
398
|
+
|
|
399
|
+
export function routingDecisionVerifyJSON(value_json: string): string;
|
|
400
|
+
|
|
401
|
+
export function verificationRecordBuildJSON(input_json: string): string;
|
|
402
|
+
|
|
403
|
+
export function verificationRecordFreshness(value_json: string, current_repository_commitment: string, now_ms: number, invalidated_commitments_json?: string | null): string;
|
|
404
|
+
|
|
405
|
+
export function verificationRecordVerifyJSON(value_json: string): string;
|
|
406
|
+
|
|
407
|
+
export function verifiedContextSnapshotVerifyBytes(payload: Uint8Array, expected_commitment: string): string;
|
|
408
|
+
|
|
409
|
+
export function workContinuationProofBuildJSON(input_json: string): string;
|
|
410
|
+
|
|
411
|
+
export function workContinuationProofState(value_json: string, repository_id: string, graph_revision: number, graph_commitment: string): string;
|
|
412
|
+
|
|
413
|
+
export function workContinuationProofVerifyJSON(value_json: string): string;
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Canonical edge identity. See `workGraphNodeId`.
|
|
417
|
+
*/
|
|
418
|
+
export function workGraphEdgeId(from: string, kind: string, to: string): string;
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Canonical node identity, so Node addresses artifacts exactly as Python and
|
|
422
|
+
* the graph itself do. Same engine function behind all three.
|
|
423
|
+
*/
|
|
424
|
+
export function workGraphNodeId(kind: string, repo_id: string, key: string): string;
|