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
|
+
// Local repository observation only. Work-state inference/trust remains in Rust.
|
|
4
|
+
const crypto = require('crypto');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const zlib = require('zlib');
|
|
9
|
+
const { execFileSync } = require('child_process');
|
|
10
|
+
|
|
11
|
+
const MAX_GIT_OUTPUT_BYTES = 8 * 1024 * 1024;
|
|
12
|
+
const MAX_CHANGES = 16384;
|
|
13
|
+
const MAX_COMMITS = 20;
|
|
14
|
+
const MAX_CHECKPOINT_BYTES = 32 * 1024 * 1024;
|
|
15
|
+
|
|
16
|
+
class RepositoryDiscoveryError extends Error {
|
|
17
|
+
constructor(message) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'RepositoryDiscoveryError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function runGit(cwd, args, { timeout = 5000, check = true } = {}) {
|
|
24
|
+
const commandArgs = [
|
|
25
|
+
'-c', 'core.fsmonitor=false',
|
|
26
|
+
'-c', 'core.untrackedCache=false',
|
|
27
|
+
'-c', 'submodule.recurse=false',
|
|
28
|
+
'-C', cwd,
|
|
29
|
+
...args,
|
|
30
|
+
];
|
|
31
|
+
const env = {
|
|
32
|
+
...process.env,
|
|
33
|
+
GIT_TERMINAL_PROMPT: '0',
|
|
34
|
+
GIT_OPTIONAL_LOCKS: '0',
|
|
35
|
+
GIT_PAGER: 'cat',
|
|
36
|
+
LC_ALL: 'C',
|
|
37
|
+
LANG: 'C',
|
|
38
|
+
};
|
|
39
|
+
try {
|
|
40
|
+
return execFileSync('git', commandArgs, {
|
|
41
|
+
encoding: 'utf8',
|
|
42
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
43
|
+
timeout,
|
|
44
|
+
maxBuffer: MAX_GIT_OUTPUT_BYTES,
|
|
45
|
+
env,
|
|
46
|
+
});
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (!check) return '';
|
|
49
|
+
const stderr = error && error.stderr ? String(error.stderr).trim() : '';
|
|
50
|
+
throw new RepositoryDiscoveryError(
|
|
51
|
+
`git ${args.join(' ')} failed: ${stderr || (error && error.message) || 'unknown error'}`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function tryGit(cwd, args, options = {}) {
|
|
57
|
+
try { return runGit(cwd, args, options).trim(); }
|
|
58
|
+
catch (_) { return ''; }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function normalizeRemote(remote) {
|
|
62
|
+
let value = String(remote || '').trim().replace(/\/$/, '');
|
|
63
|
+
if (!value) return '';
|
|
64
|
+
if (value.endsWith('.git')) value = value.slice(0, -4);
|
|
65
|
+
if (value.includes('://')) {
|
|
66
|
+
try {
|
|
67
|
+
const parsed = new URL(value);
|
|
68
|
+
const host = parsed.port
|
|
69
|
+
? `${parsed.hostname.toLowerCase()}:${parsed.port}`
|
|
70
|
+
: parsed.hostname.toLowerCase();
|
|
71
|
+
const repoPath = parsed.pathname.replace(/^\/+|\/+$/g, '');
|
|
72
|
+
return host && repoPath ? `${host}/${repoPath}` : '';
|
|
73
|
+
} catch (_) { return ''; }
|
|
74
|
+
}
|
|
75
|
+
const scp = value.match(/^(?:[^@]+@)?([^:]+):(.+)$/);
|
|
76
|
+
if (scp) return `${scp[1].toLowerCase()}/${scp[2].replace(/^\/+|\/+$/g, '')}`;
|
|
77
|
+
return '';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function sha32(value) {
|
|
81
|
+
return crypto.createHash('sha256').update(value).digest('hex').slice(0, 32);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function resolveRoot(repoPath) {
|
|
85
|
+
let candidate = path.resolve(String(repoPath || '.'));
|
|
86
|
+
try { if (fs.statSync(candidate).isFile()) candidate = path.dirname(candidate); }
|
|
87
|
+
catch (_) {}
|
|
88
|
+
const root = tryGit(candidate, ['rev-parse', '--show-toplevel']);
|
|
89
|
+
if (!root) throw new RepositoryDiscoveryError(`not a Git worktree: ${candidate}`);
|
|
90
|
+
return path.resolve(root);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function repositoryId(root) {
|
|
94
|
+
const remote = normalizeRemote(tryGit(root, ['config', '--get', 'remote.origin.url']));
|
|
95
|
+
if (remote) return `git:${sha32(remote)}`;
|
|
96
|
+
const roots = tryGit(root, ['rev-list', '--max-parents=0', 'HEAD'])
|
|
97
|
+
.split(/\r?\n/).filter(Boolean);
|
|
98
|
+
if (roots.length) return `git-root:${sha32(`${roots[0]}\0${path.basename(root)}`)}`;
|
|
99
|
+
return `git-local:${sha32(process.platform === 'win32' ? root.toLowerCase() : root)}`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function discoverRepositoryIdentity(repoPath = '.') {
|
|
103
|
+
const root = resolveRoot(repoPath);
|
|
104
|
+
return { repo_id: repositoryId(root), root };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function validateDefaultBranch(root, override) {
|
|
108
|
+
if (!override) return '';
|
|
109
|
+
const name = String(override).replace(/^origin\//, '').trim();
|
|
110
|
+
if (!name || name.startsWith('-') || /[\0\r\n]/.test(name)) {
|
|
111
|
+
throw new RepositoryDiscoveryError(`invalid default branch override: ${JSON.stringify(override)}`);
|
|
112
|
+
}
|
|
113
|
+
try { runGit(root, ['check-ref-format', `refs/heads/${name}`]); }
|
|
114
|
+
catch (_) {
|
|
115
|
+
throw new RepositoryDiscoveryError(`invalid default branch override: ${JSON.stringify(override)}`);
|
|
116
|
+
}
|
|
117
|
+
return name;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function defaultBranch(root, override) {
|
|
121
|
+
const explicit = validateDefaultBranch(root, override);
|
|
122
|
+
if (explicit) return explicit;
|
|
123
|
+
const remoteHead = tryGit(root, ['symbolic-ref', '--quiet', '--short', 'refs/remotes/origin/HEAD']);
|
|
124
|
+
if (remoteHead.startsWith('origin/')) return remoteHead.slice('origin/'.length);
|
|
125
|
+
for (const candidate of ['main', 'master']) {
|
|
126
|
+
if (tryGit(root, ['rev-parse', '--verify', '--quiet', `refs/heads/${candidate}`])) return candidate;
|
|
127
|
+
}
|
|
128
|
+
return '';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function baseRef(root, defaultName) {
|
|
132
|
+
if (!defaultName) return '';
|
|
133
|
+
for (const candidate of [`refs/remotes/origin/${defaultName}`, `refs/heads/${defaultName}`]) {
|
|
134
|
+
if (tryGit(root, ['rev-parse', '--verify', '--quiet', candidate])) return candidate;
|
|
135
|
+
}
|
|
136
|
+
return '';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function aheadBehind(root, base) {
|
|
140
|
+
if (!base) return [0, 0];
|
|
141
|
+
const parts = tryGit(root, ['rev-list', '--left-right', '--count', `${base}...HEAD`]).split(/\s+/);
|
|
142
|
+
if (parts.length < 2) return [0, 0];
|
|
143
|
+
const behind = Number.parseInt(parts[0], 10);
|
|
144
|
+
const ahead = Number.parseInt(parts[1], 10);
|
|
145
|
+
return [Number.isFinite(ahead) ? ahead : 0, Number.isFinite(behind) ? behind : 0];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function parseStatus(root) {
|
|
149
|
+
const raw = runGit(root, [
|
|
150
|
+
'status', '--porcelain=v1', '-z', '--untracked-files=all', '--ignore-submodules=all',
|
|
151
|
+
]);
|
|
152
|
+
const tokens = raw.split('\0');
|
|
153
|
+
const changes = [];
|
|
154
|
+
for (let index = 0; index < tokens.length;) {
|
|
155
|
+
const entry = tokens[index++];
|
|
156
|
+
if (!entry) continue;
|
|
157
|
+
if (entry.length < 3) throw new RepositoryDiscoveryError('malformed porcelain status record');
|
|
158
|
+
const xy = entry.slice(0, 2);
|
|
159
|
+
const repoPath = entry.slice(3).replace(/\\/g, '/');
|
|
160
|
+
let oldPath = '';
|
|
161
|
+
if ((xy.includes('R') || xy.includes('C')) && index < tokens.length) {
|
|
162
|
+
oldPath = tokens[index++].replace(/\\/g, '/');
|
|
163
|
+
}
|
|
164
|
+
const conflicted = xy.includes('U') || xy === 'DD' || xy === 'AA';
|
|
165
|
+
let kind = 'unknown';
|
|
166
|
+
if (xy === '??') kind = 'untracked';
|
|
167
|
+
else if (conflicted) kind = 'unmerged';
|
|
168
|
+
else if (xy.includes('R')) kind = 'renamed';
|
|
169
|
+
else if (xy.includes('C')) kind = 'copied';
|
|
170
|
+
else if (xy.includes('D')) kind = 'deleted';
|
|
171
|
+
else if (xy.includes('A')) kind = 'added';
|
|
172
|
+
else if (xy.includes('M') || xy.includes('T')) kind = 'modified';
|
|
173
|
+
changes.push({
|
|
174
|
+
path: repoPath,
|
|
175
|
+
kind,
|
|
176
|
+
staged: ![' ', '?', '!'].includes(xy[0]),
|
|
177
|
+
conflicted,
|
|
178
|
+
old_path: oldPath,
|
|
179
|
+
});
|
|
180
|
+
if (changes.length > MAX_CHANGES) {
|
|
181
|
+
throw new RepositoryDiscoveryError(
|
|
182
|
+
`repository has more than ${MAX_CHANGES} changed/untracked paths; ` +
|
|
183
|
+
'refusing a partial Work Graph observation',
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
changes.sort((a, b) =>
|
|
188
|
+
`${a.path}\0${a.old_path}\0${a.kind}`.localeCompare(`${b.path}\0${b.old_path}\0${b.kind}`));
|
|
189
|
+
return changes;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function branchCommits(root, base, ahead, maxCommits) {
|
|
193
|
+
const limit = Number(maxCommits);
|
|
194
|
+
if (!Number.isSafeInteger(limit) || limit < 0 || limit > MAX_COMMITS) {
|
|
195
|
+
throw new RepositoryDiscoveryError(`maxCommits must be a safe integer between 0 and ${MAX_COMMITS}`);
|
|
196
|
+
}
|
|
197
|
+
if (ahead <= 0 || !base || limit === 0) return [];
|
|
198
|
+
const output = runGit(root, [
|
|
199
|
+
'log', '--no-decorate', `-n${limit}`, '--format=%H%x00%ct%x00%P%x00%s%x00', `${base}..HEAD`,
|
|
200
|
+
]);
|
|
201
|
+
const fields = output.split('\0');
|
|
202
|
+
const commits = [];
|
|
203
|
+
for (let offset = 0; offset + 3 < fields.length; offset += 4) {
|
|
204
|
+
const sha = fields[offset].trim();
|
|
205
|
+
if (!sha) continue;
|
|
206
|
+
const seconds = Number.parseInt(fields[offset + 1].trim(), 10);
|
|
207
|
+
commits.push({
|
|
208
|
+
sha,
|
|
209
|
+
subject: fields[offset + 3].trim(),
|
|
210
|
+
timestamp_ms: Number.isFinite(seconds) ? seconds * 1000 : 0,
|
|
211
|
+
parent_shas: fields[offset + 2].trim().split(/\s+/).filter(Boolean),
|
|
212
|
+
changed_paths: [],
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
commits.sort((a, b) => a.timestamp_ms - b.timestamp_ms || a.sha.localeCompare(b.sha));
|
|
216
|
+
return commits;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function projectCheckpointCandidates(root, explicitDir = null) {
|
|
220
|
+
if (explicitDir) return [path.resolve(String(explicitDir))];
|
|
221
|
+
if (process.env.ENTROLY_DIR) return [path.resolve(process.env.ENTROLY_DIR)];
|
|
222
|
+
const projectHash = crypto
|
|
223
|
+
.createHash('sha256')
|
|
224
|
+
.update(path.resolve(root), 'utf8')
|
|
225
|
+
.digest('hex')
|
|
226
|
+
.slice(0, 12);
|
|
227
|
+
return [
|
|
228
|
+
path.join(os.homedir(), '.entroly', 'checkpoints', projectHash),
|
|
229
|
+
path.join(os.tmpdir(), 'entroly', 'checkpoints', projectHash),
|
|
230
|
+
];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function existingCheckpointDir(root, explicitDir = null) {
|
|
234
|
+
for (const candidate of projectCheckpointCandidates(root, explicitDir)) {
|
|
235
|
+
try {
|
|
236
|
+
const stat = fs.lstatSync(candidate);
|
|
237
|
+
if (!stat.isSymbolicLink() && stat.isDirectory()) return candidate;
|
|
238
|
+
} catch (_) {}
|
|
239
|
+
}
|
|
240
|
+
return '';
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function latestCheckpointMetadata(checkpointDir) {
|
|
244
|
+
if (!checkpointDir) return ['', {}];
|
|
245
|
+
const directory = path.resolve(String(checkpointDir));
|
|
246
|
+
let entries;
|
|
247
|
+
try {
|
|
248
|
+
entries = fs.readdirSync(directory)
|
|
249
|
+
.filter(name => /^(?:ckpt_|checkpoint_).+\.json\.gz$/.test(name))
|
|
250
|
+
.map(name => {
|
|
251
|
+
const full = path.join(directory, name);
|
|
252
|
+
return { name, full, stat: fs.statSync(full) };
|
|
253
|
+
})
|
|
254
|
+
.filter(item => item.stat.isFile() && item.stat.size <= MAX_CHECKPOINT_BYTES)
|
|
255
|
+
.sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs || b.name.localeCompare(a.name));
|
|
256
|
+
} catch (_) { return ['', {}]; }
|
|
257
|
+
for (const item of entries) {
|
|
258
|
+
try {
|
|
259
|
+
const raw = zlib.gunzipSync(fs.readFileSync(item.full), { maxOutputLength: MAX_CHECKPOINT_BYTES });
|
|
260
|
+
const checkpoint = JSON.parse(raw.toString('utf8'));
|
|
261
|
+
const id = String(checkpoint.checkpoint_id || item.name.replace(/\.json\.gz$/, ''));
|
|
262
|
+
const metadata = checkpoint.metadata && typeof checkpoint.metadata === 'object'
|
|
263
|
+
? checkpoint.metadata
|
|
264
|
+
: checkpoint;
|
|
265
|
+
return [id, metadata];
|
|
266
|
+
} catch (_) {}
|
|
267
|
+
}
|
|
268
|
+
return ['', {}];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function discoverRepositoryObservation(repoPath = '.', options = {}) {
|
|
272
|
+
const root = resolveRoot(repoPath);
|
|
273
|
+
const branchName = tryGit(root, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
|
|
274
|
+
const headSha = tryGit(root, ['rev-parse', '--verify', 'HEAD']);
|
|
275
|
+
const defaultName = defaultBranch(root, options.defaultBranch || null);
|
|
276
|
+
const base = baseRef(root, defaultName);
|
|
277
|
+
const [ahead, behind] = aheadBehind(root, base);
|
|
278
|
+
const gitDirText = tryGit(root, ['rev-parse', '--absolute-git-dir']);
|
|
279
|
+
const gitDir = gitDirText ? path.resolve(gitDirText) : null;
|
|
280
|
+
const mergeInProgress = Boolean(gitDir && fs.existsSync(path.join(gitDir, 'MERGE_HEAD')));
|
|
281
|
+
const rebaseInProgress = Boolean(gitDir && (
|
|
282
|
+
fs.existsSync(path.join(gitDir, 'rebase-merge')) ||
|
|
283
|
+
fs.existsSync(path.join(gitDir, 'rebase-apply'))
|
|
284
|
+
));
|
|
285
|
+
const changes = parseStatus(root);
|
|
286
|
+
const maxCommits = options.maxCommits == null ? MAX_COMMITS : options.maxCommits;
|
|
287
|
+
const commits = branchCommits(root, base, ahead, maxCommits);
|
|
288
|
+
const meaningfulGit = Boolean(changes.length || ahead || mergeInProgress || rebaseInProgress);
|
|
289
|
+
|
|
290
|
+
let taskHint = options.taskHint ? { ...options.taskHint } : null;
|
|
291
|
+
const decisions = [];
|
|
292
|
+
const includeCheckpoint = options.includeCheckpoint !== false;
|
|
293
|
+
const checkpointDir = existingCheckpointDir(root, options.checkpointDir || null);
|
|
294
|
+
if (includeCheckpoint && meaningfulGit && checkpointDir) {
|
|
295
|
+
const [checkpointId, metadata] = latestCheckpointMetadata(checkpointDir);
|
|
296
|
+
if (checkpointId) {
|
|
297
|
+
const sourceRef = `checkpoint:${checkpointId}`;
|
|
298
|
+
if (!taskHint) {
|
|
299
|
+
const task = String(metadata.task || '').trim();
|
|
300
|
+
if (task) {
|
|
301
|
+
const step = String(metadata.step || metadata.current_step || '').trim();
|
|
302
|
+
taskHint = {
|
|
303
|
+
task_id: `checkpoint:${checkpointId}`,
|
|
304
|
+
title: task,
|
|
305
|
+
trust: 'observed',
|
|
306
|
+
explicit_status: 'unknown',
|
|
307
|
+
remaining_work: step ? [step] : [],
|
|
308
|
+
source_kind: 'checkpoint',
|
|
309
|
+
source_ref: sourceRef,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const rawDecisions = Array.isArray(metadata.decisions) ? metadata.decisions.slice(0, 20) : [];
|
|
314
|
+
rawDecisions.forEach((value, index) => {
|
|
315
|
+
const text = String(value || '').trim();
|
|
316
|
+
if (text) decisions.push({
|
|
317
|
+
decision_id: `${checkpointId}:${index}`,
|
|
318
|
+
text,
|
|
319
|
+
source_ref: sourceRef,
|
|
320
|
+
source_kind: 'checkpoint',
|
|
321
|
+
trust: 'observed',
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const observedAt = options.observedAtMs == null ? Date.now() : Number(options.observedAtMs);
|
|
328
|
+
if (!Number.isSafeInteger(observedAt)) {
|
|
329
|
+
throw new RepositoryDiscoveryError('observedAtMs must be a JavaScript-safe integer');
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
repo_id: repositoryId(root),
|
|
334
|
+
observed_at_ms: observedAt,
|
|
335
|
+
repository_label: path.basename(root),
|
|
336
|
+
agent_id: String(options.agentId || ''),
|
|
337
|
+
session_id: String(options.sessionId || ''),
|
|
338
|
+
task_hint: taskHint,
|
|
339
|
+
branch: {
|
|
340
|
+
name: branchName,
|
|
341
|
+
head_sha: headSha,
|
|
342
|
+
base_ref: base,
|
|
343
|
+
default_branch: defaultName,
|
|
344
|
+
ahead_by: ahead,
|
|
345
|
+
behind_by: behind,
|
|
346
|
+
merge_in_progress: mergeInProgress,
|
|
347
|
+
rebase_in_progress: rebaseInProgress,
|
|
348
|
+
detached: !branchName,
|
|
349
|
+
},
|
|
350
|
+
changes,
|
|
351
|
+
commits,
|
|
352
|
+
verifications: [],
|
|
353
|
+
decisions,
|
|
354
|
+
claims: [],
|
|
355
|
+
leases: [],
|
|
356
|
+
model_executions: [],
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
module.exports = {
|
|
361
|
+
RepositoryDiscoveryError,
|
|
362
|
+
discoverRepositoryIdentity,
|
|
363
|
+
discoverRepositoryObservation,
|
|
364
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
WorkGraph,
|
|
3
|
+
WorkGraphCoordinationReport,
|
|
4
|
+
WorkGraphHandoffReceipt,
|
|
5
|
+
WorkGraphResumeView,
|
|
6
|
+
WorkContinuationManifest,
|
|
7
|
+
WorkContinuationProof,
|
|
8
|
+
} from "./work_graph";
|
|
9
|
+
import type {
|
|
10
|
+
ModelExecutionOutcome,
|
|
11
|
+
RoutingDecision,
|
|
12
|
+
VerificationRecord,
|
|
13
|
+
} from "./continuity_contracts";
|
|
14
|
+
import type { RepositoryDiscoveryOptions } from "./work_graph_repo";
|
|
15
|
+
|
|
16
|
+
export interface WorkGraphStoreOptions {
|
|
17
|
+
root?: string;
|
|
18
|
+
lockTimeoutMs?: number;
|
|
19
|
+
staleLockMs?: number;
|
|
20
|
+
maxStateBytes?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface WorkClaimOptions {
|
|
24
|
+
agentId: string;
|
|
25
|
+
taskTitle: string;
|
|
26
|
+
taskId?: string;
|
|
27
|
+
sessionId?: string;
|
|
28
|
+
scopePaths?: string[];
|
|
29
|
+
scopeSymbols?: string[];
|
|
30
|
+
ttlMs?: number;
|
|
31
|
+
leaseId?: string;
|
|
32
|
+
observedAtMs?: number;
|
|
33
|
+
sourceKind?: "agent_statement" | "user_statement";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class WorkGraphStoreError extends Error {}
|
|
37
|
+
export class WorkGraphLockTimeout extends WorkGraphStoreError {}
|
|
38
|
+
export class WorkGraphStateError extends WorkGraphStoreError {}
|
|
39
|
+
|
|
40
|
+
export class WorkGraphStore {
|
|
41
|
+
constructor(repoId: string, options?: WorkGraphStoreOptions);
|
|
42
|
+
static forRepository(path?: string, options?: WorkGraphStoreOptions): WorkGraphStore;
|
|
43
|
+
readonly repoId: string;
|
|
44
|
+
readonly root: string;
|
|
45
|
+
readonly repoDir: string;
|
|
46
|
+
readonly statePath: string;
|
|
47
|
+
readonly lockPath: string;
|
|
48
|
+
load(): WorkGraph;
|
|
49
|
+
save(graph: WorkGraph): WorkGraph;
|
|
50
|
+
submitObservation(observation: Record<string, unknown>): WorkGraph;
|
|
51
|
+
updateRepository(path?: string, options?: RepositoryDiscoveryOptions): WorkGraph;
|
|
52
|
+
claimWork(path: string, options: WorkClaimOptions): { graph: WorkGraph; leaseId: string };
|
|
53
|
+
coordination(nowMs?: number): WorkGraphCoordinationReport;
|
|
54
|
+
resume(workstreamId?: string | null, maxEvidence?: number): WorkGraphResumeView;
|
|
55
|
+
recordContextReceipt(
|
|
56
|
+
receipt: string | Record<string, unknown>,
|
|
57
|
+
options?: { agentId?: string; sessionId?: string },
|
|
58
|
+
): { graph: WorkGraph; result: string };
|
|
59
|
+
recordMemory(
|
|
60
|
+
memory: string | Record<string, unknown>,
|
|
61
|
+
nowMs: number,
|
|
62
|
+
supersededIds?: string[],
|
|
63
|
+
): { graph: WorkGraph; result: string };
|
|
64
|
+
recordExecutionChain(
|
|
65
|
+
route: string | RoutingDecision,
|
|
66
|
+
outcome: string | ModelExecutionOutcome,
|
|
67
|
+
verification: string | VerificationRecord,
|
|
68
|
+
invalidatedCommitments?: string[],
|
|
69
|
+
): { graph: WorkGraph; result: string };
|
|
70
|
+
continuationProof(
|
|
71
|
+
handoff: string | WorkGraphHandoffReceipt,
|
|
72
|
+
manifest: WorkContinuationManifest,
|
|
73
|
+
): WorkContinuationProof;
|
|
74
|
+
reconstructedContinuationProof(
|
|
75
|
+
workstreamId: string,
|
|
76
|
+
toAgent: string,
|
|
77
|
+
manifest: WorkContinuationManifest,
|
|
78
|
+
): WorkContinuationProof;
|
|
79
|
+
handoff(
|
|
80
|
+
workstreamId: string,
|
|
81
|
+
fromAgent: string,
|
|
82
|
+
toAgent: string,
|
|
83
|
+
generatedAtMs?: number,
|
|
84
|
+
): WorkGraphHandoffReceipt;
|
|
85
|
+
}
|