@jmanuelcorral/openteam 0.16.0 → 0.16.1
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/README.es.md +1 -1
- package/README.md +1 -1
- package/dist/cli/graphOperator.d.ts +3 -3
- package/dist/cli/graphOperator.d.ts.map +1 -1
- package/dist/cli/opencodeVersion.d.ts +44 -0
- package/dist/cli/opencodeVersion.d.ts.map +1 -0
- package/dist/cli.js +1987 -995
- package/dist/commands/dispatch.d.ts +23 -1
- package/dist/commands/dispatch.d.ts.map +1 -1
- package/dist/commands/doctor.d.ts +19 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/graph.d.ts +40 -2
- package/dist/commands/graph.d.ts.map +1 -1
- package/dist/contract/opencode.d.ts +49 -3
- package/dist/contract/opencode.d.ts.map +1 -1
- package/dist/graph/certificate.d.ts.map +1 -1
- package/dist/index.d.ts +28 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +139 -23
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3,8 +3,9 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
4
4
|
|
|
5
5
|
// src/cli.ts
|
|
6
|
-
import { execFile as execFile2 } from "node:child_process";
|
|
6
|
+
import { exec, execFile as execFile2 } from "node:child_process";
|
|
7
7
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
8
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
8
9
|
import { dirname as dirname5, resolve as resolve6 } from "node:path";
|
|
9
10
|
import { promisify as promisify2 } from "node:util";
|
|
10
11
|
import {
|
|
@@ -8552,6 +8553,10 @@ function recoverJournal(spec, text) {
|
|
|
8552
8553
|
|
|
8553
8554
|
// src/cli/graphOperator.ts
|
|
8554
8555
|
var ALLOWED_GATE = { allowed: true, violations: [] };
|
|
8556
|
+
var ALLOWED_EVALUATION = {
|
|
8557
|
+
kind: "evaluated",
|
|
8558
|
+
gate: ALLOWED_GATE
|
|
8559
|
+
};
|
|
8555
8560
|
function journalRoot(config) {
|
|
8556
8561
|
return config.graph?.journalRoot ?? DEFAULT_GRAPH_JOURNAL_ROOT;
|
|
8557
8562
|
}
|
|
@@ -8641,7 +8646,7 @@ async function listWorktreeObservations(config, options) {
|
|
|
8641
8646
|
})));
|
|
8642
8647
|
}
|
|
8643
8648
|
function createGraphOperator(options) {
|
|
8644
|
-
const evaluateCutoverGate = options.evaluateCutoverGate ?? (async () =>
|
|
8649
|
+
const evaluateCutoverGate = options.evaluateCutoverGate ?? (async () => ALLOWED_EVALUATION);
|
|
8645
8650
|
const worktreeOptions = options.exec === undefined ? undefined : {
|
|
8646
8651
|
exec: options.exec,
|
|
8647
8652
|
repoRoot: options.repoRoot ?? process.cwd(),
|
|
@@ -8920,6 +8925,35 @@ function createMigrateAdapter(root) {
|
|
|
8920
8925
|
};
|
|
8921
8926
|
}
|
|
8922
8927
|
|
|
8928
|
+
// src/cli/opencodeVersion.ts
|
|
8929
|
+
var SEMVER_PATTERN = /(\d+\.\d+\.\d+)/;
|
|
8930
|
+
function normalizeVersion(raw) {
|
|
8931
|
+
if (raw === undefined) {
|
|
8932
|
+
return;
|
|
8933
|
+
}
|
|
8934
|
+
const trimmed = raw.trim();
|
|
8935
|
+
if (trimmed === "" || trimmed.toLowerCase() === "unknown") {
|
|
8936
|
+
return;
|
|
8937
|
+
}
|
|
8938
|
+
const match = SEMVER_PATTERN.exec(trimmed);
|
|
8939
|
+
return match?.[1] ?? undefined;
|
|
8940
|
+
}
|
|
8941
|
+
async function resolveOpencodeVersionBestEffort(deps) {
|
|
8942
|
+
try {
|
|
8943
|
+
const fromPackage = normalizeVersion(deps.readPackageVersion("opencode-ai"));
|
|
8944
|
+
if (fromPackage !== undefined) {
|
|
8945
|
+
return fromPackage;
|
|
8946
|
+
}
|
|
8947
|
+
} catch {}
|
|
8948
|
+
try {
|
|
8949
|
+
const fromCommand = normalizeVersion(await deps.runVersionCommand());
|
|
8950
|
+
if (fromCommand !== undefined) {
|
|
8951
|
+
return fromCommand;
|
|
8952
|
+
}
|
|
8953
|
+
} catch {}
|
|
8954
|
+
return;
|
|
8955
|
+
}
|
|
8956
|
+
|
|
8923
8957
|
// src/cli/purgeAdapter.ts
|
|
8924
8958
|
import { execFile } from "node:child_process";
|
|
8925
8959
|
import * as fs2 from "node:fs";
|
|
@@ -10239,6 +10273,54 @@ function createProbeRuntime(exec) {
|
|
|
10239
10273
|
}
|
|
10240
10274
|
|
|
10241
10275
|
// src/config/graphFeatureGate.ts
|
|
10276
|
+
function checkCertificate(status, name) {
|
|
10277
|
+
if (status.status === "absent") {
|
|
10278
|
+
return {
|
|
10279
|
+
code: `${name}-certificate-absent`,
|
|
10280
|
+
detail: `${name} certificate not found — run the ${name} certification suite to produce it`
|
|
10281
|
+
};
|
|
10282
|
+
}
|
|
10283
|
+
if (status.status === "invalid") {
|
|
10284
|
+
return {
|
|
10285
|
+
code: `${name}-certificate-invalid`,
|
|
10286
|
+
detail: `${name} certificate rejected by recomputing parser: ${status.code} — ${status.detail}`
|
|
10287
|
+
};
|
|
10288
|
+
}
|
|
10289
|
+
return;
|
|
10290
|
+
}
|
|
10291
|
+
function evaluateGraphGate(input) {
|
|
10292
|
+
const violations = [];
|
|
10293
|
+
const shadowV = checkCertificate(input.shadow, "shadow");
|
|
10294
|
+
if (shadowV !== undefined)
|
|
10295
|
+
violations.push(shadowV);
|
|
10296
|
+
const releaseV = checkCertificate(input.release, "release");
|
|
10297
|
+
if (releaseV !== undefined)
|
|
10298
|
+
violations.push(releaseV);
|
|
10299
|
+
const soakV = checkCertificate(input.soak, "soak");
|
|
10300
|
+
if (soakV !== undefined)
|
|
10301
|
+
violations.push(soakV);
|
|
10302
|
+
if (input.migration === "pending") {
|
|
10303
|
+
violations.push({
|
|
10304
|
+
code: "migration-pending",
|
|
10305
|
+
detail: "legacy migration has pending work — run the migration tool to completion before enabling active mode"
|
|
10306
|
+
});
|
|
10307
|
+
} else if (input.migration === "unknown") {
|
|
10308
|
+
violations.push({
|
|
10309
|
+
code: "migration-unknown",
|
|
10310
|
+
detail: "could not determine migration status — check ledger readability and storage access"
|
|
10311
|
+
});
|
|
10312
|
+
}
|
|
10313
|
+
if (!input.operatorApproval) {
|
|
10314
|
+
violations.push({
|
|
10315
|
+
code: "operator-approval-missing",
|
|
10316
|
+
detail: "set graph.operatorApproval to true in .opencode/openteam.json after reviewing all certificates and completing migration — this is a declaration of intent, not a proof"
|
|
10317
|
+
});
|
|
10318
|
+
}
|
|
10319
|
+
return {
|
|
10320
|
+
allowed: violations.length === 0,
|
|
10321
|
+
violations
|
|
10322
|
+
};
|
|
10323
|
+
}
|
|
10242
10324
|
function isGateApplicable(mode) {
|
|
10243
10325
|
return mode === "active";
|
|
10244
10326
|
}
|
|
@@ -11057,7 +11139,7 @@ function legacyRosterFindings(audit) {
|
|
|
11057
11139
|
}
|
|
11058
11140
|
return findings;
|
|
11059
11141
|
}
|
|
11060
|
-
function rosterHealthSection(audit, loadError, rosterRoleCount) {
|
|
11142
|
+
function rosterHealthSection(audit, loadError, rosterRoleCount, rosterMissing) {
|
|
11061
11143
|
const auditFindings = audit?.findings ?? legacyRosterFindings(audit ?? {});
|
|
11062
11144
|
const unparseable = auditFindings.find((finding) => finding.kind === "unparseable-roster");
|
|
11063
11145
|
const unparseableMessage = loadError ?? unparseable?.message;
|
|
@@ -11070,6 +11152,14 @@ function rosterHealthSection(audit, loadError, rosterRoleCount) {
|
|
|
11070
11152
|
];
|
|
11071
11153
|
}
|
|
11072
11154
|
if (audit === undefined) {
|
|
11155
|
+
if (rosterMissing === true) {
|
|
11156
|
+
return [
|
|
11157
|
+
" roster health:",
|
|
11158
|
+
` ✗ ${OPENTEAM_ROSTER_PATH} does not exist — no team roster has been cast.`,
|
|
11159
|
+
" consequence: without a roster openteam cannot distribute work across roles, so every request is handled by a single agent and no work splitting happens.",
|
|
11160
|
+
` remedy: run \`openteam setup\` to cast a team and write the roster (${OPENTEAM_ROSTER_PATH}), then re-run \`openteam doctor\`.`
|
|
11161
|
+
];
|
|
11162
|
+
}
|
|
11073
11163
|
return [];
|
|
11074
11164
|
}
|
|
11075
11165
|
const missing = auditFindings.filter((finding) => finding.kind === "missing-guaranteed-role").map((finding) => finding.roleID);
|
|
@@ -11105,6 +11195,14 @@ function rosterHealthSection(audit, loadError, rosterRoleCount) {
|
|
|
11105
11195
|
}
|
|
11106
11196
|
return lines;
|
|
11107
11197
|
}
|
|
11198
|
+
function orchestratorAgentSection() {
|
|
11199
|
+
return [
|
|
11200
|
+
" orchestrator agent:",
|
|
11201
|
+
` ✗ ${ORCHESTRATOR_AGENT_PATH} does not exist — opencode has no openteam coordinator agent.`,
|
|
11202
|
+
" consequence: this is the primary agent that reads the roster and calls `openteam-orchestrate` to fan work out across roles; without it opencode has no openteam coordinator, so every request is handled by a single agent and no work splitting happens.",
|
|
11203
|
+
` remedy: run \`openteam setup\` to generate ${ORCHESTRATOR_AGENT_PATH}, then re-run \`openteam doctor\`.`
|
|
11204
|
+
];
|
|
11205
|
+
}
|
|
11108
11206
|
function gitignoreSection(gitignore) {
|
|
11109
11207
|
if (gitignore.missingRules.length === 0) {
|
|
11110
11208
|
return [
|
|
@@ -11168,7 +11266,10 @@ function renderDoctor(input) {
|
|
|
11168
11266
|
if (input.diagnostics !== undefined) {
|
|
11169
11267
|
lines.push(...diagnosticsSection(input.diagnostics));
|
|
11170
11268
|
}
|
|
11171
|
-
lines.push(...rosterHealthSection(input.rosterAudit, input.rosterLoadError, input.rosterRoleCount));
|
|
11269
|
+
lines.push(...rosterHealthSection(input.rosterAudit, input.rosterLoadError, input.rosterRoleCount, input.rosterMissing));
|
|
11270
|
+
if (input.orchestratorAgentMissing === true) {
|
|
11271
|
+
lines.push(...orchestratorAgentSection());
|
|
11272
|
+
}
|
|
11172
11273
|
if (input.gitignore !== undefined) {
|
|
11173
11274
|
lines.push(...gitignoreSection(input.gitignore));
|
|
11174
11275
|
}
|
|
@@ -11237,14 +11338,31 @@ function leaseLine(lease) {
|
|
|
11237
11338
|
const state = lease.released ? "released" : "active";
|
|
11238
11339
|
return ` lease: ${lease.holder} → ${lease.runID} (${state})`;
|
|
11239
11340
|
}
|
|
11240
|
-
function
|
|
11341
|
+
function appendEffectiveLines(lines, gate) {
|
|
11342
|
+
switch (gate.kind) {
|
|
11343
|
+
case "not-applicable":
|
|
11344
|
+
return;
|
|
11345
|
+
case "passed":
|
|
11346
|
+
lines.push(" effective: active");
|
|
11347
|
+
return;
|
|
11348
|
+
case "unevaluable":
|
|
11349
|
+
lines.push(" effective: unknown — could not evaluate the cutover gate");
|
|
11350
|
+
lines.push(` ${gate.reason}`);
|
|
11351
|
+
return;
|
|
11352
|
+
case "denied":
|
|
11353
|
+
lines.push(" effective: off — cutover gate denied");
|
|
11354
|
+
for (const violation of gate.violations) {
|
|
11355
|
+
lines.push(` • ${violation.code}: ${violation.detail}`);
|
|
11356
|
+
}
|
|
11357
|
+
}
|
|
11358
|
+
}
|
|
11359
|
+
function renderGraphStatus(snapshot, gate = { kind: "not-applicable" }) {
|
|
11241
11360
|
const lines = [
|
|
11242
11361
|
"openteam graph status:",
|
|
11243
|
-
` config: ${snapshot.effectiveMode} (source: ${snapshot.source})
|
|
11244
|
-
leaseLine(snapshot.lease),
|
|
11245
|
-
` journal: ${snapshot.journal}`,
|
|
11246
|
-
` effects: ${snapshot.pendingEffects} pending, ${snapshot.unknownEffects} unknown`
|
|
11362
|
+
` config: ${snapshot.effectiveMode} (source: ${snapshot.source})`
|
|
11247
11363
|
];
|
|
11364
|
+
appendEffectiveLines(lines, gate);
|
|
11365
|
+
lines.push(leaseLine(snapshot.lease), ` journal: ${snapshot.journal}`, ` effects: ${snapshot.pendingEffects} pending, ${snapshot.unknownEffects} unknown`);
|
|
11248
11366
|
const needsReconciliation = isRecoveryRequired(snapshot.journal, snapshot.unknownEffects);
|
|
11249
11367
|
if (needsReconciliation) {
|
|
11250
11368
|
lines.push(" ⚠ Reconciliation required: journal or effects in an uncertain state.");
|
|
@@ -11495,11 +11613,152 @@ function mergeOpencodeConfigs(base, override) {
|
|
|
11495
11613
|
return result;
|
|
11496
11614
|
}
|
|
11497
11615
|
|
|
11616
|
+
// src/graph/soakLedger.ts
|
|
11617
|
+
import { z as z19 } from "zod";
|
|
11618
|
+
var Sha256Schema2 = z19.string().regex(/^[0-9a-f]{64}$/);
|
|
11619
|
+
var SoakPlatformSchema = z19.enum(["linux", "win32", "darwin"]);
|
|
11620
|
+
var PrivacyPairSchema = z19.object({
|
|
11621
|
+
surfacesScanned: z19.number().int().nonnegative(),
|
|
11622
|
+
rawFindings: z19.number().int().nonnegative()
|
|
11623
|
+
}).strict();
|
|
11624
|
+
var DuplicateEffectPairSchema = z19.object({
|
|
11625
|
+
effectsExamined: z19.number().int().nonnegative(),
|
|
11626
|
+
duplicatesFound: z19.number().int().nonnegative()
|
|
11627
|
+
}).strict();
|
|
11628
|
+
var ModelVerificationPairSchema = z19.object({
|
|
11629
|
+
nodesChecked: z19.number().int().nonnegative(),
|
|
11630
|
+
unverified: z19.number().int().nonnegative(),
|
|
11631
|
+
mismatched: z19.number().int().nonnegative()
|
|
11632
|
+
}).strict();
|
|
11633
|
+
var SoakObservationSchema = z19.object({
|
|
11634
|
+
version: z19.literal(1),
|
|
11635
|
+
seq: z19.number().int().nonnegative(),
|
|
11636
|
+
timestamp: z19.string().datetime(),
|
|
11637
|
+
platform: SoakPlatformSchema,
|
|
11638
|
+
opencodeVersion: z19.string().min(1),
|
|
11639
|
+
provenance: z19.enum(["genuine-usage", "ci-synthetic"]),
|
|
11640
|
+
traceDigest: Sha256Schema2,
|
|
11641
|
+
criticalDivergences: z19.number().int().nonnegative().nullable(),
|
|
11642
|
+
privacy: PrivacyPairSchema.nullable(),
|
|
11643
|
+
duplicateEffects: DuplicateEffectPairSchema.nullable(),
|
|
11644
|
+
modelVerification: ModelVerificationPairSchema.nullable(),
|
|
11645
|
+
chainDigest: Sha256Schema2
|
|
11646
|
+
}).strict();
|
|
11647
|
+
function canonicalObservationPreimage(obs) {
|
|
11648
|
+
return JSON.stringify({
|
|
11649
|
+
version: obs.version,
|
|
11650
|
+
seq: obs.seq,
|
|
11651
|
+
timestamp: obs.timestamp,
|
|
11652
|
+
platform: obs.platform,
|
|
11653
|
+
opencodeVersion: obs.opencodeVersion,
|
|
11654
|
+
provenance: obs.provenance,
|
|
11655
|
+
traceDigest: obs.traceDigest,
|
|
11656
|
+
criticalDivergences: obs.criticalDivergences,
|
|
11657
|
+
privacy: obs.privacy,
|
|
11658
|
+
duplicateEffects: obs.duplicateEffects,
|
|
11659
|
+
modelVerification: obs.modelVerification
|
|
11660
|
+
});
|
|
11661
|
+
}
|
|
11662
|
+
function validateChain(observations) {
|
|
11663
|
+
if (observations.length === 0) {
|
|
11664
|
+
return { valid: true, observations: [] };
|
|
11665
|
+
}
|
|
11666
|
+
let prevChainDigest = "0".repeat(64);
|
|
11667
|
+
for (let i = 0;i < observations.length; i++) {
|
|
11668
|
+
const obs = observations[i];
|
|
11669
|
+
if (obs.seq !== i) {
|
|
11670
|
+
return { valid: false, observations };
|
|
11671
|
+
}
|
|
11672
|
+
if (i > 0) {
|
|
11673
|
+
const prev = observations[i - 1];
|
|
11674
|
+
if (obs.timestamp <= prev.timestamp) {
|
|
11675
|
+
return { valid: false, observations };
|
|
11676
|
+
}
|
|
11677
|
+
}
|
|
11678
|
+
const preimage = canonicalObservationPreimage(obs);
|
|
11679
|
+
const expectedDigest = sha256Hex(prevChainDigest + preimage);
|
|
11680
|
+
if (obs.chainDigest !== expectedDigest) {
|
|
11681
|
+
return { valid: false, observations };
|
|
11682
|
+
}
|
|
11683
|
+
prevChainDigest = obs.chainDigest;
|
|
11684
|
+
}
|
|
11685
|
+
return { valid: true, observations };
|
|
11686
|
+
}
|
|
11687
|
+
function canonicalLedger(chains) {
|
|
11688
|
+
const validChains = [];
|
|
11689
|
+
for (const chain of chains) {
|
|
11690
|
+
const result = validateChain(chain);
|
|
11691
|
+
if (result.valid && chain.length > 0) {
|
|
11692
|
+
validChains.push(chain);
|
|
11693
|
+
}
|
|
11694
|
+
}
|
|
11695
|
+
validChains.sort((a, b) => {
|
|
11696
|
+
const aDigest = a[0].chainDigest;
|
|
11697
|
+
const bDigest = b[0].chainDigest;
|
|
11698
|
+
return aDigest < bDigest ? -1 : aDigest > bDigest ? 1 : 0;
|
|
11699
|
+
});
|
|
11700
|
+
const lines = [];
|
|
11701
|
+
for (const chain of validChains) {
|
|
11702
|
+
for (const obs of chain) {
|
|
11703
|
+
lines.push(JSON.stringify(obs));
|
|
11704
|
+
}
|
|
11705
|
+
}
|
|
11706
|
+
return sha256Hex(lines.join(`
|
|
11707
|
+
`));
|
|
11708
|
+
}
|
|
11709
|
+
|
|
11498
11710
|
// src/storage/graph/soakRecorder.ts
|
|
11499
11711
|
var SOAK_EVIDENCE_DIR = ".opencode/soak";
|
|
11500
11712
|
var SOAK_RECORDER_BASE_DIR = ".opencode";
|
|
11501
11713
|
var SOAK_RECORDER_ID_FILENAME = "soak-recorder-id";
|
|
11502
11714
|
var SOAK_RECORDER_ID_PATH = `${SOAK_RECORDER_BASE_DIR}/${SOAK_RECORDER_ID_FILENAME}`;
|
|
11715
|
+
async function readAllChains(ports, evidenceDir) {
|
|
11716
|
+
if (!await ports.fs.exists(evidenceDir)) {
|
|
11717
|
+
return { chains: [], rejectedLines: 0, rejections: [] };
|
|
11718
|
+
}
|
|
11719
|
+
const files = await ports.fs.readDir(evidenceDir);
|
|
11720
|
+
const chains = [];
|
|
11721
|
+
const rejections = [];
|
|
11722
|
+
for (const file of files) {
|
|
11723
|
+
if (!file.endsWith(".jsonl")) {
|
|
11724
|
+
continue;
|
|
11725
|
+
}
|
|
11726
|
+
const content = await ports.fs.readFile(`${evidenceDir}/${file}`);
|
|
11727
|
+
const lines = content.split(`
|
|
11728
|
+
`);
|
|
11729
|
+
const observations = [];
|
|
11730
|
+
for (const [index, line] of lines.entries()) {
|
|
11731
|
+
if (line.trim().length === 0) {
|
|
11732
|
+
continue;
|
|
11733
|
+
}
|
|
11734
|
+
const lineNumber = index + 1;
|
|
11735
|
+
let rawParsed;
|
|
11736
|
+
try {
|
|
11737
|
+
rawParsed = JSON.parse(line);
|
|
11738
|
+
} catch {
|
|
11739
|
+
rejections.push({ file, lineNumber, detail: "invalid JSON" });
|
|
11740
|
+
continue;
|
|
11741
|
+
}
|
|
11742
|
+
const parsed = SoakObservationSchema.safeParse(rawParsed);
|
|
11743
|
+
if (parsed.success) {
|
|
11744
|
+
observations.push(parsed.data);
|
|
11745
|
+
} else {
|
|
11746
|
+
rejections.push({
|
|
11747
|
+
file,
|
|
11748
|
+
lineNumber,
|
|
11749
|
+
detail: formatSoakObservationIssues(parsed.error.issues)
|
|
11750
|
+
});
|
|
11751
|
+
}
|
|
11752
|
+
}
|
|
11753
|
+
if (observations.length > 0) {
|
|
11754
|
+
chains.push(observations);
|
|
11755
|
+
}
|
|
11756
|
+
}
|
|
11757
|
+
return { chains, rejectedLines: rejections.length, rejections };
|
|
11758
|
+
}
|
|
11759
|
+
function formatSoakObservationIssues(issues) {
|
|
11760
|
+
return issues.map((i) => `${i.path.join(".")}: ${i.code}`).join("; ");
|
|
11761
|
+
}
|
|
11503
11762
|
|
|
11504
11763
|
// src/commands/frontierCatalog.ts
|
|
11505
11764
|
function weightedCost(inputUSD, outputUSD) {
|
|
@@ -13272,8 +13531,7 @@ async function runAgents(deps, configPath, opencodeConfigPaths, configResolution
|
|
|
13272
13531
|
async function runGraph(positionals, deps, configPath, configResolution) {
|
|
13273
13532
|
const sub = positionals[1];
|
|
13274
13533
|
if (sub === "status") {
|
|
13275
|
-
|
|
13276
|
-
return { exitCode: 0, stdout: renderGraphStatus(snapshot) };
|
|
13534
|
+
return runGraphStatus(deps, configPath, configResolution);
|
|
13277
13535
|
}
|
|
13278
13536
|
if (sub === "cancel") {
|
|
13279
13537
|
return runGraphCancel(positionals, deps, configPath, configResolution);
|
|
@@ -13328,7 +13586,9 @@ function renderGraphOutcome(outcome) {
|
|
|
13328
13586
|
async function resolveOperatorGraphPolicy(config, operator) {
|
|
13329
13587
|
let graph = resolveGraphConfig(config, "file");
|
|
13330
13588
|
if (isGateApplicable(graph.effectiveMode)) {
|
|
13331
|
-
|
|
13589
|
+
const evaluation = await operator.evaluateCutoverGate(config);
|
|
13590
|
+
const gate = evaluation.kind === "evaluated" ? evaluation.gate : { allowed: false, violations: [] };
|
|
13591
|
+
graph = applyGraphGate(graph, gate);
|
|
13332
13592
|
}
|
|
13333
13593
|
return {
|
|
13334
13594
|
graph,
|
|
@@ -13346,6 +13606,32 @@ function checkOperatorGate(policy) {
|
|
|
13346
13606
|
stdout: renderLegacyGraphReason(decision2)
|
|
13347
13607
|
};
|
|
13348
13608
|
}
|
|
13609
|
+
async function runGraphStatus(deps, configPath, configResolution) {
|
|
13610
|
+
const snapshot = await deps.readGraphSnapshot(configPath, configResolution);
|
|
13611
|
+
if (!isGateApplicable(snapshot.effectiveMode)) {
|
|
13612
|
+
return { exitCode: 0, stdout: renderGraphStatus(snapshot) };
|
|
13613
|
+
}
|
|
13614
|
+
const operator = deps.graphOperator;
|
|
13615
|
+
if (operator === undefined) {
|
|
13616
|
+
const gate2 = {
|
|
13617
|
+
kind: "unevaluable",
|
|
13618
|
+
reason: "graph operator ports are not configured"
|
|
13619
|
+
};
|
|
13620
|
+
return { exitCode: 0, stdout: renderGraphStatus(snapshot, gate2) };
|
|
13621
|
+
}
|
|
13622
|
+
const config = await deps.loadConfig(configPath, configResolution);
|
|
13623
|
+
const evaluation = await operator.evaluateCutoverGate(config);
|
|
13624
|
+
if (evaluation.kind === "unevaluable") {
|
|
13625
|
+
const gate2 = {
|
|
13626
|
+
kind: "unevaluable",
|
|
13627
|
+
reason: evaluation.reason
|
|
13628
|
+
};
|
|
13629
|
+
return { exitCode: 0, stdout: renderGraphStatus(snapshot, gate2) };
|
|
13630
|
+
}
|
|
13631
|
+
const resolved = applyGraphGate(resolveGraphConfig(config, "file"), evaluation.gate);
|
|
13632
|
+
const gate = resolved.gateDenied === true ? { kind: "denied", violations: resolved.gateViolations ?? [] } : { kind: "passed" };
|
|
13633
|
+
return { exitCode: 0, stdout: renderGraphStatus(snapshot, gate) };
|
|
13634
|
+
}
|
|
13349
13635
|
async function runGraphCancel(positionals, deps, configPath, configResolution) {
|
|
13350
13636
|
const runID = positionals[2];
|
|
13351
13637
|
if (runID === undefined || runID.trim() === "") {
|
|
@@ -13792,6 +14078,9 @@ async function runCli(argv, deps) {
|
|
|
13792
14078
|
const summary = summarizeQueueWaits(queueEvents);
|
|
13793
14079
|
queueWait = summary !== undefined ? { summary } : {};
|
|
13794
14080
|
}
|
|
14081
|
+
const rosterMissing = deps.loadRosterForDoctor !== undefined && roster === undefined && rosterLoadError === undefined;
|
|
14082
|
+
const orchestratorAgentName = ORCHESTRATOR_AGENT_PATH.slice(ORCHESTRATOR_AGENT_PATH.lastIndexOf("/") + 1).replace(/\.md$/, "");
|
|
14083
|
+
const orchestratorAgentMissing = !agentFiles.some((file) => file.name === orchestratorAgentName);
|
|
13795
14084
|
return {
|
|
13796
14085
|
exitCode: 0,
|
|
13797
14086
|
stdout: renderDoctor({
|
|
@@ -13805,6 +14094,8 @@ async function runCli(argv, deps) {
|
|
|
13805
14094
|
...rosterAudit !== undefined ? { rosterAudit } : {},
|
|
13806
14095
|
...rosterRoleCount !== undefined ? { rosterRoleCount } : {},
|
|
13807
14096
|
...rosterLoadError !== undefined ? { rosterLoadError } : {},
|
|
14097
|
+
...rosterMissing ? { rosterMissing } : {},
|
|
14098
|
+
...orchestratorAgentMissing ? { orchestratorAgentMissing } : {},
|
|
13808
14099
|
...diagnostics !== undefined && diagnostics.length > 0 ? { diagnostics } : {},
|
|
13809
14100
|
...opencodeConfigError !== undefined ? { opencodeConfigError } : {},
|
|
13810
14101
|
...cacheEntries !== undefined ? { cacheEntries, cliVersion: deps.version } : {},
|
|
@@ -14258,472 +14549,1040 @@ function planStartupHygieneMigration(exists) {
|
|
|
14258
14549
|
return planLegacyMigration(exists).filter((move) => move.portable === false && move.relocation === "move" && move.from.startsWith(".opencode/openteam/"));
|
|
14259
14550
|
}
|
|
14260
14551
|
|
|
14261
|
-
// src/
|
|
14262
|
-
import
|
|
14263
|
-
|
|
14264
|
-
|
|
14265
|
-
|
|
14266
|
-
|
|
14267
|
-
|
|
14268
|
-
|
|
14269
|
-
|
|
14552
|
+
// src/index.ts
|
|
14553
|
+
import {
|
|
14554
|
+
tool as tool2
|
|
14555
|
+
} from "@opencode-ai/plugin";
|
|
14556
|
+
|
|
14557
|
+
// src/graph/certificate.ts
|
|
14558
|
+
import { z as z20 } from "zod";
|
|
14559
|
+
|
|
14560
|
+
// src/contract/opencode.ts
|
|
14561
|
+
var SUPPORTED_OPENCODE_VERSIONS = [
|
|
14562
|
+
"1.17.13",
|
|
14563
|
+
"1.18.18",
|
|
14564
|
+
"1.18.19"
|
|
14565
|
+
];
|
|
14566
|
+
var SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)/;
|
|
14567
|
+
function parseSemver(version) {
|
|
14568
|
+
const normalized = version.trim().replace(/^[=^~v]+/, "");
|
|
14569
|
+
const match = SEMVER_RE.exec(normalized);
|
|
14570
|
+
if (match === null) {
|
|
14571
|
+
throw new Error(`invalid semver: "${version}"`);
|
|
14270
14572
|
}
|
|
14271
|
-
|
|
14272
|
-
|
|
14573
|
+
return {
|
|
14574
|
+
major: Number(match[1]),
|
|
14575
|
+
minor: Number(match[2]),
|
|
14576
|
+
patch: Number(match[3])
|
|
14577
|
+
};
|
|
14273
14578
|
}
|
|
14274
|
-
function
|
|
14275
|
-
|
|
14276
|
-
|
|
14277
|
-
const parsed = JSON.parse(text2);
|
|
14278
|
-
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
14279
|
-
return parsed;
|
|
14280
|
-
}
|
|
14281
|
-
return;
|
|
14282
|
-
} catch {
|
|
14283
|
-
return;
|
|
14579
|
+
function isCertificateVersionCompatible(certifiedVersion, liveVersion) {
|
|
14580
|
+
if (certifiedVersion === liveVersion) {
|
|
14581
|
+
return true;
|
|
14284
14582
|
}
|
|
14285
|
-
|
|
14286
|
-
|
|
14287
|
-
if (pkg === undefined)
|
|
14288
|
-
return "";
|
|
14289
|
-
const v = pkg.version;
|
|
14290
|
-
return typeof v === "string" ? v : "";
|
|
14291
|
-
}
|
|
14292
|
-
function readDirectoryEntries(dir) {
|
|
14583
|
+
let certified;
|
|
14584
|
+
let live;
|
|
14293
14585
|
try {
|
|
14294
|
-
|
|
14586
|
+
certified = parseSemver(certifiedVersion);
|
|
14587
|
+
live = parseSemver(liveVersion);
|
|
14295
14588
|
} catch {
|
|
14296
|
-
return
|
|
14589
|
+
return false;
|
|
14297
14590
|
}
|
|
14591
|
+
if (certified.major !== live.major || certified.minor !== live.minor) {
|
|
14592
|
+
return false;
|
|
14593
|
+
}
|
|
14594
|
+
return live.patch >= certified.patch;
|
|
14298
14595
|
}
|
|
14299
|
-
|
|
14300
|
-
|
|
14301
|
-
|
|
14302
|
-
|
|
14303
|
-
|
|
14304
|
-
|
|
14305
|
-
|
|
14306
|
-
|
|
14307
|
-
|
|
14596
|
+
|
|
14597
|
+
// src/graph/certificate.ts
|
|
14598
|
+
var SHADOW_CERTIFICATE_MIN_RUNS = 1000;
|
|
14599
|
+
var DivergenceCodeSchema = z20.enum([
|
|
14600
|
+
"status",
|
|
14601
|
+
"order",
|
|
14602
|
+
"roles",
|
|
14603
|
+
"models",
|
|
14604
|
+
"fixes",
|
|
14605
|
+
"outcome"
|
|
14606
|
+
]);
|
|
14607
|
+
var ProvenanceSchema = z20.enum([
|
|
14608
|
+
"recomputed",
|
|
14609
|
+
"compiled",
|
|
14610
|
+
"validated",
|
|
14611
|
+
"carried"
|
|
14612
|
+
]);
|
|
14613
|
+
var EvidenceSchema = z20.object({
|
|
14614
|
+
opencodeVersion: z20.string().min(1),
|
|
14615
|
+
parity: z20.object({
|
|
14616
|
+
runs: z20.number().int().nonnegative(),
|
|
14617
|
+
match: z20.number().int().nonnegative(),
|
|
14618
|
+
divergent: z20.number().int().nonnegative(),
|
|
14619
|
+
inconclusive: z20.number().int().nonnegative(),
|
|
14620
|
+
divergences: z20.array(DivergenceCodeSchema)
|
|
14621
|
+
}).strict(),
|
|
14622
|
+
legacy: z20.object({
|
|
14623
|
+
observed: z20.number().int().nonnegative(),
|
|
14624
|
+
duplicated: z20.number().int().nonnegative()
|
|
14625
|
+
}).strict(),
|
|
14626
|
+
privacy: z20.object({
|
|
14627
|
+
surfacesScanned: z20.number().int().nonnegative(),
|
|
14628
|
+
rawFindings: z20.number().int().nonnegative()
|
|
14629
|
+
}).strict(),
|
|
14630
|
+
overhead: z20.object({
|
|
14631
|
+
p95Millis: z20.number().nonnegative(),
|
|
14632
|
+
budgetMillis: z20.number().positive(),
|
|
14633
|
+
samples: z20.number().int().nonnegative()
|
|
14634
|
+
}).strict(),
|
|
14635
|
+
provenance: z20.record(DivergenceCodeSchema, ProvenanceSchema)
|
|
14636
|
+
}).strict();
|
|
14637
|
+
var CertificateSchema = z20.object({
|
|
14638
|
+
version: z20.literal(1),
|
|
14639
|
+
certificate: z20.literal("graph-shadow"),
|
|
14640
|
+
opencodeVersion: z20.string().min(1),
|
|
14641
|
+
evidence: EvidenceSchema,
|
|
14642
|
+
verdict: z20.enum(["pass", "fail"]),
|
|
14643
|
+
failedGates: z20.array(z20.enum([
|
|
14644
|
+
"sample",
|
|
14645
|
+
"parity",
|
|
14646
|
+
"one-legacy-execution",
|
|
14647
|
+
"privacy",
|
|
14648
|
+
"overhead"
|
|
14649
|
+
])),
|
|
14650
|
+
digest: z20.string().regex(/^[0-9a-f]{64}$/)
|
|
14651
|
+
}).strict();
|
|
14652
|
+
|
|
14653
|
+
class ShadowCertificateError extends Error {
|
|
14654
|
+
code;
|
|
14655
|
+
detail;
|
|
14656
|
+
constructor(code, detail) {
|
|
14657
|
+
super(`${code}: ${detail}`);
|
|
14658
|
+
this.name = "ShadowCertificateError";
|
|
14659
|
+
this.code = code;
|
|
14660
|
+
this.detail = detail;
|
|
14308
14661
|
}
|
|
14309
14662
|
}
|
|
14310
|
-
function
|
|
14311
|
-
const
|
|
14312
|
-
|
|
14313
|
-
|
|
14314
|
-
const topStat = lstatPlainDirectory(topPath);
|
|
14315
|
-
if (topStat === undefined) {
|
|
14316
|
-
continue;
|
|
14317
|
-
}
|
|
14318
|
-
if (!topEntry.name.startsWith("@")) {
|
|
14319
|
-
candidates.push({
|
|
14320
|
-
specDir: topEntry.name,
|
|
14321
|
-
absolutePath: topPath,
|
|
14322
|
-
stat: topStat
|
|
14323
|
-
});
|
|
14324
|
-
continue;
|
|
14325
|
-
}
|
|
14326
|
-
for (const packageEntry of readDirectoryEntries(topPath)) {
|
|
14327
|
-
const packagePath = path3.join(topPath, packageEntry.name);
|
|
14328
|
-
const packageStat = lstatPlainDirectory(packagePath);
|
|
14329
|
-
if (packageStat === undefined) {
|
|
14330
|
-
continue;
|
|
14331
|
-
}
|
|
14332
|
-
candidates.push({
|
|
14333
|
-
specDir: `${topEntry.name}/${packageEntry.name}`,
|
|
14334
|
-
absolutePath: packagePath,
|
|
14335
|
-
stat: packageStat
|
|
14336
|
-
});
|
|
14337
|
-
}
|
|
14663
|
+
function evaluateGates(evidence) {
|
|
14664
|
+
const failed = [];
|
|
14665
|
+
if (evidence.parity.runs < SHADOW_CERTIFICATE_MIN_RUNS) {
|
|
14666
|
+
failed.push("sample");
|
|
14338
14667
|
}
|
|
14339
|
-
|
|
14668
|
+
if (evidence.parity.divergent > 0 || evidence.parity.inconclusive > 0 || evidence.parity.divergences.length > 0 || evidence.parity.match !== evidence.parity.runs) {
|
|
14669
|
+
failed.push("parity");
|
|
14670
|
+
}
|
|
14671
|
+
if (evidence.legacy.duplicated > 0 || evidence.legacy.observed < 1) {
|
|
14672
|
+
failed.push("one-legacy-execution");
|
|
14673
|
+
}
|
|
14674
|
+
if (evidence.privacy.rawFindings > 0 || evidence.privacy.surfacesScanned < 1) {
|
|
14675
|
+
failed.push("privacy");
|
|
14676
|
+
}
|
|
14677
|
+
if (evidence.overhead.samples < 1 || evidence.overhead.p95Millis > evidence.overhead.budgetMillis) {
|
|
14678
|
+
failed.push("overhead");
|
|
14679
|
+
}
|
|
14680
|
+
return failed;
|
|
14340
14681
|
}
|
|
14341
|
-
|
|
14342
|
-
|
|
14343
|
-
|
|
14344
|
-
|
|
14345
|
-
|
|
14346
|
-
|
|
14347
|
-
|
|
14348
|
-
|
|
14349
|
-
|
|
14350
|
-
|
|
14351
|
-
|
|
14352
|
-
|
|
14353
|
-
|
|
14354
|
-
|
|
14682
|
+
function shadowCertificateBindingDigest(evidence) {
|
|
14683
|
+
return sha256Hex(JSON.stringify({
|
|
14684
|
+
opencodeVersion: evidence.opencodeVersion,
|
|
14685
|
+
parity: {
|
|
14686
|
+
runs: evidence.parity.runs,
|
|
14687
|
+
match: evidence.parity.match,
|
|
14688
|
+
divergent: evidence.parity.divergent,
|
|
14689
|
+
inconclusive: evidence.parity.inconclusive,
|
|
14690
|
+
divergences: [...evidence.parity.divergences].sort()
|
|
14691
|
+
},
|
|
14692
|
+
legacy: {
|
|
14693
|
+
observed: evidence.legacy.observed,
|
|
14694
|
+
duplicated: evidence.legacy.duplicated
|
|
14695
|
+
},
|
|
14696
|
+
privacy: {
|
|
14697
|
+
surfacesScanned: evidence.privacy.surfacesScanned,
|
|
14698
|
+
rawFindings: evidence.privacy.rawFindings
|
|
14699
|
+
},
|
|
14700
|
+
overhead: {
|
|
14701
|
+
budgetMillis: evidence.overhead.budgetMillis,
|
|
14702
|
+
samples: evidence.overhead.samples
|
|
14703
|
+
},
|
|
14704
|
+
provenance: Object.fromEntries(Object.entries(evidence.provenance).sort(([a], [b]) => a < b ? -1 : 1))
|
|
14705
|
+
}));
|
|
14706
|
+
}
|
|
14707
|
+
function canonicalCertificate(certificate) {
|
|
14708
|
+
const evidence = certificate.evidence;
|
|
14709
|
+
return JSON.stringify({
|
|
14710
|
+
version: certificate.version,
|
|
14711
|
+
certificate: certificate.certificate,
|
|
14712
|
+
opencodeVersion: certificate.opencodeVersion,
|
|
14713
|
+
verdict: certificate.verdict,
|
|
14714
|
+
failedGates: [...certificate.failedGates],
|
|
14715
|
+
evidence: {
|
|
14716
|
+
opencodeVersion: evidence.opencodeVersion,
|
|
14717
|
+
parity: {
|
|
14718
|
+
runs: evidence.parity.runs,
|
|
14719
|
+
match: evidence.parity.match,
|
|
14720
|
+
divergent: evidence.parity.divergent,
|
|
14721
|
+
inconclusive: evidence.parity.inconclusive,
|
|
14722
|
+
divergences: [...evidence.parity.divergences].sort()
|
|
14723
|
+
},
|
|
14724
|
+
legacy: {
|
|
14725
|
+
observed: evidence.legacy.observed,
|
|
14726
|
+
duplicated: evidence.legacy.duplicated
|
|
14727
|
+
},
|
|
14728
|
+
privacy: {
|
|
14729
|
+
surfacesScanned: evidence.privacy.surfacesScanned,
|
|
14730
|
+
rawFindings: evidence.privacy.rawFindings
|
|
14731
|
+
},
|
|
14732
|
+
overhead: {
|
|
14733
|
+
p95Millis: evidence.overhead.p95Millis,
|
|
14734
|
+
budgetMillis: evidence.overhead.budgetMillis,
|
|
14735
|
+
samples: evidence.overhead.samples
|
|
14736
|
+
},
|
|
14737
|
+
provenance: Object.fromEntries(Object.entries(evidence.provenance).sort(([a], [b]) => a < b ? -1 : 1))
|
|
14355
14738
|
}
|
|
14356
|
-
|
|
14357
|
-
const installedVersion = extractVersion(installedPkg);
|
|
14358
|
-
entries.push({
|
|
14359
|
-
specDir,
|
|
14360
|
-
absolutePath,
|
|
14361
|
-
pinnedVersion,
|
|
14362
|
-
installedVersion,
|
|
14363
|
-
mtimeIso
|
|
14364
|
-
});
|
|
14365
|
-
}
|
|
14366
|
-
return entries;
|
|
14739
|
+
});
|
|
14367
14740
|
}
|
|
14368
|
-
|
|
14369
|
-
|
|
14741
|
+
function sameGates(a, b) {
|
|
14742
|
+
return a.length === b.length && a.every((gate, index) => gate === b[index]);
|
|
14370
14743
|
}
|
|
14371
|
-
|
|
14372
|
-
|
|
14373
|
-
|
|
14374
|
-
|
|
14375
|
-
|
|
14376
|
-
|
|
14744
|
+
function parseShadowCertificate(value, opencodeVersion) {
|
|
14745
|
+
const parsed = CertificateSchema.safeParse(value);
|
|
14746
|
+
if (!parsed.success) {
|
|
14747
|
+
const detail = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.code}`).join("; ");
|
|
14748
|
+
throw new ShadowCertificateError("invalid-certificate", detail);
|
|
14749
|
+
}
|
|
14750
|
+
const certificate = parsed.data;
|
|
14751
|
+
const failedGates = evaluateGates(certificate.evidence);
|
|
14752
|
+
const verdict = failedGates.length === 0 ? "pass" : "fail";
|
|
14753
|
+
if (certificate.verdict !== verdict || !sameGates(certificate.failedGates, failedGates)) {
|
|
14754
|
+
throw new ShadowCertificateError("verdict-mismatch", `evidence yields "${verdict}" (${failedGates.join(",") || "no failed gate"})`);
|
|
14377
14755
|
}
|
|
14756
|
+
const { digest, ...unsigned } = certificate;
|
|
14757
|
+
if (sha256Hex(canonicalCertificate(unsigned)) !== digest) {
|
|
14758
|
+
throw new ShadowCertificateError("digest-mismatch", "certificate digest does not cover the presented evidence");
|
|
14759
|
+
}
|
|
14760
|
+
if (!isCertificateVersionCompatible(certificate.opencodeVersion, opencodeVersion)) {
|
|
14761
|
+
throw new ShadowCertificateError("opencode-mismatch", `certified for "${certificate.opencodeVersion}", running "${opencodeVersion}" — evidence is accepted only on ${certificate.opencodeVersion} or a newer patch of the same minor line`);
|
|
14762
|
+
}
|
|
14763
|
+
return certificate;
|
|
14378
14764
|
}
|
|
14379
|
-
var
|
|
14380
|
-
|
|
14381
|
-
|
|
14382
|
-
|
|
14383
|
-
|
|
14384
|
-
|
|
14765
|
+
var ReleaseDeterminismSchema = z20.object({ runs: z20.number().int().nonnegative(), allMatch: z20.boolean() }).strict();
|
|
14766
|
+
var ReleaseCrashRecoverySchema = z20.object({
|
|
14767
|
+
scenarios: z20.number().int().nonnegative(),
|
|
14768
|
+
allConverge: z20.boolean()
|
|
14769
|
+
}).strict();
|
|
14770
|
+
var ReleaseReplayEquivalenceSchema = z20.object({
|
|
14771
|
+
checks: z20.number().int().nonnegative(),
|
|
14772
|
+
allEquivalent: z20.boolean()
|
|
14773
|
+
}).strict();
|
|
14774
|
+
var ReleasePrivacySchema = z20.object({
|
|
14775
|
+
surfacesScanned: z20.number().int().nonnegative(),
|
|
14776
|
+
rawFindings: z20.number().int().nonnegative()
|
|
14777
|
+
}).strict();
|
|
14778
|
+
var ReleaseContractSchema = z20.object({
|
|
14779
|
+
roundTrips: z20.number().int().nonnegative(),
|
|
14780
|
+
allSettled: z20.boolean()
|
|
14781
|
+
}).strict();
|
|
14782
|
+
var ReleaseHealthSchema = z20.object({
|
|
14783
|
+
samples: z20.number().int().nonnegative(),
|
|
14784
|
+
bounded: z20.boolean(),
|
|
14785
|
+
idempotent: z20.boolean()
|
|
14786
|
+
}).strict();
|
|
14787
|
+
var ReleasePerformanceSchema = z20.object({
|
|
14788
|
+
p95Millis: z20.number().nonnegative(),
|
|
14789
|
+
budgetMillis: z20.number().positive(),
|
|
14790
|
+
samples: z20.number().int().nonnegative()
|
|
14791
|
+
}).strict();
|
|
14792
|
+
var ReleaseEvidenceSchema = z20.object({
|
|
14793
|
+
opencodeVersion: z20.string().min(1),
|
|
14794
|
+
platform: z20.enum(["linux", "win32"]),
|
|
14795
|
+
shadowCertificateDigest: z20.string().regex(/^[0-9a-f]{64}$/),
|
|
14796
|
+
determinism: ReleaseDeterminismSchema,
|
|
14797
|
+
crashRecovery: ReleaseCrashRecoverySchema,
|
|
14798
|
+
replayEquivalence: ReleaseReplayEquivalenceSchema,
|
|
14799
|
+
privacy: ReleasePrivacySchema,
|
|
14800
|
+
contract: ReleaseContractSchema,
|
|
14801
|
+
health: ReleaseHealthSchema,
|
|
14802
|
+
performance: ReleasePerformanceSchema
|
|
14803
|
+
}).strict();
|
|
14804
|
+
var ReleaseCertificateSchema = z20.object({
|
|
14805
|
+
version: z20.literal(2),
|
|
14806
|
+
certificate: z20.literal("graph-release"),
|
|
14807
|
+
platform: z20.enum(["linux", "win32"]),
|
|
14808
|
+
opencodeVersion: z20.string().min(1),
|
|
14809
|
+
shadowCertificateDigest: z20.string().regex(/^[0-9a-f]{64}$/),
|
|
14810
|
+
evidence: ReleaseEvidenceSchema,
|
|
14811
|
+
verdict: z20.enum(["pass", "fail"]),
|
|
14812
|
+
failedGates: z20.array(z20.enum([
|
|
14813
|
+
"shadow-valid",
|
|
14814
|
+
"determinism",
|
|
14815
|
+
"crash-recovery",
|
|
14816
|
+
"replay-equivalence",
|
|
14817
|
+
"privacy",
|
|
14818
|
+
"contract",
|
|
14819
|
+
"health",
|
|
14820
|
+
"performance"
|
|
14821
|
+
])),
|
|
14822
|
+
digest: z20.string().regex(/^[0-9a-f]{64}$/)
|
|
14823
|
+
}).strict();
|
|
14385
14824
|
|
|
14386
|
-
|
|
14387
|
-
|
|
14388
|
-
|
|
14389
|
-
|
|
14390
|
-
|
|
14391
|
-
|
|
14392
|
-
|
|
14393
|
-
|
|
14394
|
-
function recencyTimestamp(record) {
|
|
14395
|
-
if (record.kind === "preference" && record.lastAccessedAt !== null) {
|
|
14396
|
-
return record.lastAccessedAt;
|
|
14825
|
+
class ReleaseCertificateError extends Error {
|
|
14826
|
+
code;
|
|
14827
|
+
detail;
|
|
14828
|
+
constructor(code, detail) {
|
|
14829
|
+
super(`${code}: ${detail}`);
|
|
14830
|
+
this.name = "ReleaseCertificateError";
|
|
14831
|
+
this.code = code;
|
|
14832
|
+
this.detail = detail;
|
|
14397
14833
|
}
|
|
14398
|
-
return record.createdAt;
|
|
14399
|
-
}
|
|
14400
|
-
function recencyScore(record, signals) {
|
|
14401
|
-
const ageMs = Math.max(0, signals.now - recencyTimestamp(record));
|
|
14402
|
-
return 0.5 ** (ageMs / signals.recencyHalfLifeMs);
|
|
14403
14834
|
}
|
|
14404
|
-
function
|
|
14405
|
-
|
|
14406
|
-
|
|
14835
|
+
function evaluateReleaseGates(evidence, expectedShadowDigest) {
|
|
14836
|
+
const failed = [];
|
|
14837
|
+
if (evidence.shadowCertificateDigest !== expectedShadowDigest) {
|
|
14838
|
+
failed.push("shadow-valid");
|
|
14407
14839
|
}
|
|
14408
|
-
|
|
14409
|
-
|
|
14410
|
-
|
|
14411
|
-
|
|
14840
|
+
if (evidence.determinism.runs < 1 || !evidence.determinism.allMatch) {
|
|
14841
|
+
failed.push("determinism");
|
|
14842
|
+
}
|
|
14843
|
+
if (evidence.crashRecovery.scenarios < 1 || !evidence.crashRecovery.allConverge) {
|
|
14844
|
+
failed.push("crash-recovery");
|
|
14845
|
+
}
|
|
14846
|
+
if (evidence.replayEquivalence.checks < 1 || !evidence.replayEquivalence.allEquivalent) {
|
|
14847
|
+
failed.push("replay-equivalence");
|
|
14848
|
+
}
|
|
14849
|
+
if (evidence.privacy.surfacesScanned < 1 || evidence.privacy.rawFindings > 0) {
|
|
14850
|
+
failed.push("privacy");
|
|
14851
|
+
}
|
|
14852
|
+
if (evidence.contract.roundTrips < 1 || !evidence.contract.allSettled) {
|
|
14853
|
+
failed.push("contract");
|
|
14854
|
+
}
|
|
14855
|
+
if (evidence.health.samples < 1 || !evidence.health.bounded || !evidence.health.idempotent) {
|
|
14856
|
+
failed.push("health");
|
|
14857
|
+
}
|
|
14858
|
+
if (evidence.performance.samples < 1 || evidence.performance.p95Millis > evidence.performance.budgetMillis) {
|
|
14859
|
+
failed.push("performance");
|
|
14860
|
+
}
|
|
14861
|
+
return failed;
|
|
14412
14862
|
}
|
|
14413
|
-
function
|
|
14414
|
-
|
|
14415
|
-
|
|
14416
|
-
|
|
14417
|
-
|
|
14418
|
-
|
|
14419
|
-
|
|
14863
|
+
function canonicalReleaseCertificate(certificate) {
|
|
14864
|
+
const ev = certificate.evidence;
|
|
14865
|
+
return JSON.stringify({
|
|
14866
|
+
version: certificate.version,
|
|
14867
|
+
certificate: certificate.certificate,
|
|
14868
|
+
platform: certificate.platform,
|
|
14869
|
+
opencodeVersion: certificate.opencodeVersion,
|
|
14870
|
+
shadowCertificateDigest: certificate.shadowCertificateDigest,
|
|
14871
|
+
verdict: certificate.verdict,
|
|
14872
|
+
failedGates: [...certificate.failedGates],
|
|
14873
|
+
evidence: {
|
|
14874
|
+
opencodeVersion: ev.opencodeVersion,
|
|
14875
|
+
platform: ev.platform,
|
|
14876
|
+
shadowCertificateDigest: ev.shadowCertificateDigest,
|
|
14877
|
+
determinism: {
|
|
14878
|
+
runs: ev.determinism.runs,
|
|
14879
|
+
allMatch: ev.determinism.allMatch
|
|
14880
|
+
},
|
|
14881
|
+
crashRecovery: {
|
|
14882
|
+
scenarios: ev.crashRecovery.scenarios,
|
|
14883
|
+
allConverge: ev.crashRecovery.allConverge
|
|
14884
|
+
},
|
|
14885
|
+
replayEquivalence: {
|
|
14886
|
+
checks: ev.replayEquivalence.checks,
|
|
14887
|
+
allEquivalent: ev.replayEquivalence.allEquivalent
|
|
14888
|
+
},
|
|
14889
|
+
privacy: {
|
|
14890
|
+
surfacesScanned: ev.privacy.surfacesScanned,
|
|
14891
|
+
rawFindings: ev.privacy.rawFindings
|
|
14892
|
+
},
|
|
14893
|
+
contract: {
|
|
14894
|
+
roundTrips: ev.contract.roundTrips,
|
|
14895
|
+
allSettled: ev.contract.allSettled
|
|
14896
|
+
},
|
|
14897
|
+
health: {
|
|
14898
|
+
samples: ev.health.samples,
|
|
14899
|
+
bounded: ev.health.bounded,
|
|
14900
|
+
idempotent: ev.health.idempotent
|
|
14901
|
+
},
|
|
14902
|
+
performance: {
|
|
14903
|
+
p95Millis: ev.performance.p95Millis,
|
|
14904
|
+
budgetMillis: ev.performance.budgetMillis,
|
|
14905
|
+
samples: ev.performance.samples
|
|
14906
|
+
}
|
|
14420
14907
|
}
|
|
14421
|
-
return a.record.id < b.record.id ? -1 : a.record.id > b.record.id ? 1 : 0;
|
|
14422
14908
|
});
|
|
14423
14909
|
}
|
|
14424
|
-
|
|
14425
|
-
|
|
14426
|
-
function isTransactionActiveAt(record, asOf) {
|
|
14427
|
-
return record.invalidatedAt === null || record.invalidatedAt > asOf;
|
|
14910
|
+
function sameReleaseGates(a, b) {
|
|
14911
|
+
return a.length === b.length && a.every((gate, index) => gate === b[index]);
|
|
14428
14912
|
}
|
|
14429
|
-
function
|
|
14430
|
-
if (
|
|
14431
|
-
|
|
14913
|
+
function parseReleaseCertificate(value, opencodeVersion, expectedShadowDigest) {
|
|
14914
|
+
if (typeof value === "object" && value !== null && "version" in value && value.version === 1) {
|
|
14915
|
+
throw new ReleaseCertificateError("invalid-certificate", "certificate is schema version 1 (carried a removed 'migration' gate); " + "rebuild the release certificate against the current schema");
|
|
14432
14916
|
}
|
|
14433
|
-
|
|
14434
|
-
|
|
14435
|
-
|
|
14436
|
-
|
|
14437
|
-
}
|
|
14438
|
-
|
|
14439
|
-
|
|
14440
|
-
|
|
14441
|
-
|
|
14442
|
-
|
|
14443
|
-
|
|
14444
|
-
|
|
14917
|
+
const parsed = ReleaseCertificateSchema.safeParse(value);
|
|
14918
|
+
if (!parsed.success) {
|
|
14919
|
+
const detail = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.code}`).join("; ");
|
|
14920
|
+
throw new ReleaseCertificateError("invalid-certificate", detail);
|
|
14921
|
+
}
|
|
14922
|
+
const certificate = parsed.data;
|
|
14923
|
+
const inconsistencies = [];
|
|
14924
|
+
if (certificate.platform !== certificate.evidence.platform) {
|
|
14925
|
+
inconsistencies.push("platform");
|
|
14926
|
+
}
|
|
14927
|
+
if (certificate.opencodeVersion !== certificate.evidence.opencodeVersion) {
|
|
14928
|
+
inconsistencies.push("opencodeVersion");
|
|
14929
|
+
}
|
|
14930
|
+
if (certificate.shadowCertificateDigest !== certificate.evidence.shadowCertificateDigest) {
|
|
14931
|
+
inconsistencies.push("shadowCertificateDigest");
|
|
14932
|
+
}
|
|
14933
|
+
if (inconsistencies.length > 0) {
|
|
14934
|
+
throw new ReleaseCertificateError("field-inconsistency", `top-level/evidence divergence: ${inconsistencies.join(", ")}`);
|
|
14935
|
+
}
|
|
14936
|
+
const failedGates = evaluateReleaseGates(certificate.evidence, expectedShadowDigest);
|
|
14937
|
+
const verdict = failedGates.length === 0 ? "pass" : "fail";
|
|
14938
|
+
if (certificate.verdict !== verdict || !sameReleaseGates(certificate.failedGates, failedGates)) {
|
|
14939
|
+
throw new ReleaseCertificateError("verdict-mismatch", `evidence yields "${verdict}" (${failedGates.join(",") || "no failed gate"})`);
|
|
14940
|
+
}
|
|
14941
|
+
const { digest, ...unsigned } = certificate;
|
|
14942
|
+
if (sha256Hex(canonicalReleaseCertificate(unsigned)) !== digest) {
|
|
14943
|
+
throw new ReleaseCertificateError("digest-mismatch", "certificate digest does not cover the presented evidence");
|
|
14944
|
+
}
|
|
14945
|
+
if (!isCertificateVersionCompatible(certificate.opencodeVersion, opencodeVersion)) {
|
|
14946
|
+
throw new ReleaseCertificateError("opencode-mismatch", `certified for "${certificate.opencodeVersion}", running "${opencodeVersion}" — evidence is accepted only on ${certificate.opencodeVersion} or a newer patch of the same minor line`);
|
|
14947
|
+
}
|
|
14948
|
+
return certificate;
|
|
14445
14949
|
}
|
|
14446
|
-
|
|
14447
|
-
|
|
14448
|
-
|
|
14449
|
-
|
|
14450
|
-
|
|
14451
|
-
|
|
14452
|
-
|
|
14453
|
-
id: z19.string().min(1),
|
|
14454
|
-
ownerKey: OwnerKeySchema,
|
|
14455
|
-
confidence: z19.number().min(0).max(1),
|
|
14456
|
-
validFrom: z19.number().finite(),
|
|
14457
|
-
validUntil: z19.number().finite().nullable().default(null),
|
|
14458
|
-
createdAt: z19.number().finite(),
|
|
14459
|
-
invalidatedAt: z19.number().finite().nullable().default(null),
|
|
14460
|
-
sourceHash: z19.string().min(1),
|
|
14461
|
-
supersededBy: z19.string().min(1).nullable().default(null)
|
|
14462
|
-
}).strict();
|
|
14463
|
-
var FactSchema = MemoryBaseSchema.extend({
|
|
14464
|
-
kind: z19.literal("fact"),
|
|
14465
|
-
subject: z19.string().min(1),
|
|
14466
|
-
predicate: z19.string().min(1),
|
|
14467
|
-
object: z19.string().min(1),
|
|
14468
|
-
category: z19.string().min(1).nullable().default(null)
|
|
14469
|
-
});
|
|
14470
|
-
var PreferenceSchema = MemoryBaseSchema.extend({
|
|
14471
|
-
kind: z19.literal("preference"),
|
|
14472
|
-
category: z19.string().min(1),
|
|
14473
|
-
preference: z19.string().min(1),
|
|
14474
|
-
context: z19.string().min(1).nullable().default(null),
|
|
14475
|
-
lastAccessedAt: z19.number().finite().nullable().default(null),
|
|
14476
|
-
accessCount: z19.number().int().min(0).default(0)
|
|
14477
|
-
});
|
|
14478
|
-
var EntitySchema = MemoryBaseSchema.extend({
|
|
14479
|
-
kind: z19.literal("entity"),
|
|
14480
|
-
canonicalName: z19.string().min(1),
|
|
14481
|
-
type: z19.string().min(1),
|
|
14482
|
-
aliases: z19.array(z19.string().min(1)).default([])
|
|
14483
|
-
});
|
|
14484
|
-
var RelationSchema = MemoryBaseSchema.extend({
|
|
14485
|
-
kind: z19.literal("relation"),
|
|
14486
|
-
from: z19.string().min(1),
|
|
14487
|
-
to: z19.string().min(1),
|
|
14488
|
-
predicate: z19.string().min(1),
|
|
14489
|
-
annotation: z19.string().min(1).nullable().default(null)
|
|
14490
|
-
});
|
|
14491
|
-
var MemoryRecordSchema = z19.discriminatedUnion("kind", [
|
|
14492
|
-
FactSchema,
|
|
14493
|
-
PreferenceSchema,
|
|
14494
|
-
EntitySchema,
|
|
14495
|
-
RelationSchema
|
|
14950
|
+
var ShadowDivergenceCodeSchema = z20.enum([
|
|
14951
|
+
"status",
|
|
14952
|
+
"order",
|
|
14953
|
+
"roles",
|
|
14954
|
+
"models",
|
|
14955
|
+
"fixes",
|
|
14956
|
+
"outcome"
|
|
14496
14957
|
]);
|
|
14497
|
-
var
|
|
14498
|
-
|
|
14499
|
-
|
|
14500
|
-
|
|
14501
|
-
|
|
14502
|
-
|
|
14503
|
-
|
|
14958
|
+
var RECOMPUTED_DIVERGENCE_CODES = ["fixes"];
|
|
14959
|
+
var RecomputedDivergenceCodeSchema = z20.enum(RECOMPUTED_DIVERGENCE_CODES);
|
|
14960
|
+
var SoakPolicySchema = z20.object({
|
|
14961
|
+
minimumGenuineObservations: z20.number().int().positive(),
|
|
14962
|
+
minimumDistinctDays: z20.number().int().positive(),
|
|
14963
|
+
requireGenuineUsageOnAllPlatforms: z20.boolean(),
|
|
14964
|
+
supportedOpencodeVersions: z20.array(z20.string().min(1)).min(1),
|
|
14965
|
+
criticalDivergenceCodes: z20.array(RecomputedDivergenceCodeSchema).min(1)
|
|
14966
|
+
}).strict();
|
|
14967
|
+
var DEFAULT_SOAK_POLICY = {
|
|
14968
|
+
minimumGenuineObservations: 100,
|
|
14969
|
+
minimumDistinctDays: 14,
|
|
14970
|
+
requireGenuineUsageOnAllPlatforms: true,
|
|
14971
|
+
supportedOpencodeVersions: [...SUPPORTED_OPENCODE_VERSIONS],
|
|
14972
|
+
criticalDivergenceCodes: ["fixes"]
|
|
14973
|
+
};
|
|
14974
|
+
var SoakPlatformEnumSchema = z20.enum(["linux", "win32", "darwin"]);
|
|
14975
|
+
var SoakPrivacyPairEvidenceSchema = z20.object({
|
|
14976
|
+
surfacesScanned: z20.number().int().nonnegative(),
|
|
14977
|
+
rawFindings: z20.number().int().nonnegative()
|
|
14978
|
+
}).strict();
|
|
14979
|
+
var SoakDuplicateEffectPairEvidenceSchema = z20.object({
|
|
14980
|
+
effectsExamined: z20.number().int().nonnegative(),
|
|
14981
|
+
duplicatesFound: z20.number().int().nonnegative()
|
|
14982
|
+
}).strict();
|
|
14983
|
+
var SoakModelVerificationPairEvidenceSchema = z20.object({
|
|
14984
|
+
nodesChecked: z20.number().int().nonnegative(),
|
|
14985
|
+
unverified: z20.number().int().nonnegative(),
|
|
14986
|
+
mismatched: z20.number().int().nonnegative()
|
|
14987
|
+
}).strict();
|
|
14988
|
+
var SoakEvidenceSchema = z20.object({
|
|
14989
|
+
totalObservations: z20.number().int().nonnegative(),
|
|
14990
|
+
genuineUsageObservations: z20.number().int().nonnegative(),
|
|
14991
|
+
ciSyntheticObservations: z20.number().int().nonnegative(),
|
|
14992
|
+
recorderCount: z20.number().int().nonnegative(),
|
|
14993
|
+
ineligibleObservations: z20.number().int().nonnegative(),
|
|
14994
|
+
firstTimestamp: z20.string().datetime().nullable(),
|
|
14995
|
+
lastTimestamp: z20.string().datetime().nullable(),
|
|
14996
|
+
distinctDays: z20.number().int().nonnegative(),
|
|
14997
|
+
criticalDivergences: z20.number().int().nonnegative().nullable(),
|
|
14998
|
+
privacy: SoakPrivacyPairEvidenceSchema.nullable(),
|
|
14999
|
+
duplicateEffects: SoakDuplicateEffectPairEvidenceSchema.nullable(),
|
|
15000
|
+
modelVerification: SoakModelVerificationPairEvidenceSchema.nullable(),
|
|
15001
|
+
platformsGenuine: z20.array(SoakPlatformEnumSchema),
|
|
15002
|
+
platformsSynthetic: z20.array(SoakPlatformEnumSchema),
|
|
15003
|
+
opencodeVersionsObserved: z20.array(z20.string().min(1)),
|
|
15004
|
+
invalidChains: z20.number().int().nonnegative()
|
|
15005
|
+
}).strict();
|
|
15006
|
+
var SoakCertificateSchema = z20.object({
|
|
15007
|
+
version: z20.literal(1),
|
|
15008
|
+
certificate: z20.literal("graph-soak"),
|
|
15009
|
+
trustBoundary: z20.literal("contributors"),
|
|
15010
|
+
policy: SoakPolicySchema,
|
|
15011
|
+
evidence: SoakEvidenceSchema,
|
|
15012
|
+
verdict: z20.enum(["pass", "fail"]),
|
|
15013
|
+
failedGates: z20.array(z20.enum([
|
|
15014
|
+
"minimum-observations",
|
|
15015
|
+
"minimum-duration",
|
|
15016
|
+
"chain-integrity",
|
|
15017
|
+
"zero-critical-divergence",
|
|
15018
|
+
"zero-privacy-breach",
|
|
15019
|
+
"zero-duplicate-effect",
|
|
15020
|
+
"zero-model-mismatch",
|
|
15021
|
+
"os-diversity",
|
|
15022
|
+
"opencode-pin"
|
|
15023
|
+
])),
|
|
15024
|
+
ledgerDigest: z20.string().regex(/^[0-9a-f]{64}$/),
|
|
15025
|
+
digest: z20.string().regex(/^[0-9a-f]{64}$/)
|
|
14504
15026
|
}).strict();
|
|
14505
15027
|
|
|
14506
|
-
|
|
14507
|
-
|
|
14508
|
-
|
|
14509
|
-
|
|
14510
|
-
|
|
14511
|
-
|
|
14512
|
-
|
|
14513
|
-
|
|
15028
|
+
class SoakCertificateError extends Error {
|
|
15029
|
+
code;
|
|
15030
|
+
detail;
|
|
15031
|
+
constructor(code, detail) {
|
|
15032
|
+
super(`${code}: ${detail}`);
|
|
15033
|
+
this.name = "SoakCertificateError";
|
|
15034
|
+
this.code = code;
|
|
15035
|
+
this.detail = detail;
|
|
14514
15036
|
}
|
|
14515
|
-
return sum;
|
|
14516
15037
|
}
|
|
14517
|
-
function
|
|
14518
|
-
|
|
14519
|
-
|
|
14520
|
-
|
|
14521
|
-
sum += value * value;
|
|
15038
|
+
function evaluateSoakGates(evidence, policy) {
|
|
15039
|
+
const failed = [];
|
|
15040
|
+
if (evidence.genuineUsageObservations < policy.minimumGenuineObservations) {
|
|
15041
|
+
failed.push("minimum-observations");
|
|
14522
15042
|
}
|
|
14523
|
-
|
|
15043
|
+
if (evidence.distinctDays < policy.minimumDistinctDays) {
|
|
15044
|
+
failed.push("minimum-duration");
|
|
15045
|
+
}
|
|
15046
|
+
if (evidence.invalidChains > 0) {
|
|
15047
|
+
failed.push("chain-integrity");
|
|
15048
|
+
}
|
|
15049
|
+
if (evidence.criticalDivergences === null || evidence.criticalDivergences > 0) {
|
|
15050
|
+
failed.push("zero-critical-divergence");
|
|
15051
|
+
}
|
|
15052
|
+
if (evidence.privacy === null || evidence.privacy.surfacesScanned < 1 || evidence.privacy.rawFindings > 0) {
|
|
15053
|
+
failed.push("zero-privacy-breach");
|
|
15054
|
+
}
|
|
15055
|
+
if (evidence.duplicateEffects === null || evidence.duplicateEffects.effectsExamined < 1 || evidence.duplicateEffects.duplicatesFound > 0) {
|
|
15056
|
+
failed.push("zero-duplicate-effect");
|
|
15057
|
+
}
|
|
15058
|
+
if (evidence.modelVerification === null || evidence.modelVerification.nodesChecked < 1 || evidence.modelVerification.mismatched > 0) {
|
|
15059
|
+
failed.push("zero-model-mismatch");
|
|
15060
|
+
}
|
|
15061
|
+
if (policy.requireGenuineUsageOnAllPlatforms) {
|
|
15062
|
+
if (!evidence.platformsGenuine.includes("linux") || !evidence.platformsGenuine.includes("win32")) {
|
|
15063
|
+
failed.push("os-diversity");
|
|
15064
|
+
}
|
|
15065
|
+
} else {
|
|
15066
|
+
const allPlatforms = new Set([
|
|
15067
|
+
...evidence.platformsGenuine,
|
|
15068
|
+
...evidence.platformsSynthetic
|
|
15069
|
+
]);
|
|
15070
|
+
if (!allPlatforms.has("linux") || !allPlatforms.has("win32") || evidence.platformsGenuine.length < 1) {
|
|
15071
|
+
failed.push("os-diversity");
|
|
15072
|
+
}
|
|
15073
|
+
}
|
|
15074
|
+
const supported = new Set(policy.supportedOpencodeVersions);
|
|
15075
|
+
if (evidence.opencodeVersionsObserved.length === 0 || !evidence.opencodeVersionsObserved.every((v) => supported.has(v))) {
|
|
15076
|
+
failed.push("opencode-pin");
|
|
15077
|
+
}
|
|
15078
|
+
return failed;
|
|
14524
15079
|
}
|
|
14525
|
-
function
|
|
14526
|
-
const
|
|
14527
|
-
|
|
14528
|
-
|
|
15080
|
+
function canonicalSoakCertificate(certificate) {
|
|
15081
|
+
const ev = certificate.evidence;
|
|
15082
|
+
const pol = certificate.policy;
|
|
15083
|
+
return JSON.stringify({
|
|
15084
|
+
version: certificate.version,
|
|
15085
|
+
certificate: certificate.certificate,
|
|
15086
|
+
trustBoundary: certificate.trustBoundary,
|
|
15087
|
+
policy: {
|
|
15088
|
+
minimumGenuineObservations: pol.minimumGenuineObservations,
|
|
15089
|
+
minimumDistinctDays: pol.minimumDistinctDays,
|
|
15090
|
+
requireGenuineUsageOnAllPlatforms: pol.requireGenuineUsageOnAllPlatforms,
|
|
15091
|
+
supportedOpencodeVersions: [...pol.supportedOpencodeVersions].sort(),
|
|
15092
|
+
criticalDivergenceCodes: [...pol.criticalDivergenceCodes].sort()
|
|
15093
|
+
},
|
|
15094
|
+
verdict: certificate.verdict,
|
|
15095
|
+
failedGates: [...certificate.failedGates],
|
|
15096
|
+
ledgerDigest: certificate.ledgerDigest,
|
|
15097
|
+
evidence: {
|
|
15098
|
+
totalObservations: ev.totalObservations,
|
|
15099
|
+
genuineUsageObservations: ev.genuineUsageObservations,
|
|
15100
|
+
ciSyntheticObservations: ev.ciSyntheticObservations,
|
|
15101
|
+
recorderCount: ev.recorderCount,
|
|
15102
|
+
ineligibleObservations: ev.ineligibleObservations,
|
|
15103
|
+
firstTimestamp: ev.firstTimestamp,
|
|
15104
|
+
lastTimestamp: ev.lastTimestamp,
|
|
15105
|
+
distinctDays: ev.distinctDays,
|
|
15106
|
+
criticalDivergences: ev.criticalDivergences,
|
|
15107
|
+
privacy: ev.privacy,
|
|
15108
|
+
duplicateEffects: ev.duplicateEffects,
|
|
15109
|
+
modelVerification: ev.modelVerification,
|
|
15110
|
+
platformsGenuine: [...ev.platformsGenuine].sort(),
|
|
15111
|
+
platformsSynthetic: [...ev.platformsSynthetic].sort(),
|
|
15112
|
+
opencodeVersionsObserved: [...ev.opencodeVersionsObserved].sort(),
|
|
15113
|
+
invalidChains: ev.invalidChains
|
|
15114
|
+
}
|
|
15115
|
+
});
|
|
15116
|
+
}
|
|
15117
|
+
function sameSoakGates(a, b) {
|
|
15118
|
+
return a.length === b.length && a.every((gate, index) => gate === b[index]);
|
|
15119
|
+
}
|
|
15120
|
+
function sameSoakPolicy(a, b) {
|
|
15121
|
+
const aVersions = [...a.supportedOpencodeVersions].sort();
|
|
15122
|
+
const bVersions = [...b.supportedOpencodeVersions].sort();
|
|
15123
|
+
return a.minimumGenuineObservations === b.minimumGenuineObservations && a.minimumDistinctDays === b.minimumDistinctDays && a.requireGenuineUsageOnAllPlatforms === b.requireGenuineUsageOnAllPlatforms && aVersions.length === bVersions.length && aVersions.every((v, i) => v === bVersions[i]) && a.criticalDivergenceCodes.length === b.criticalDivergenceCodes.length && [...a.criticalDivergenceCodes].sort().every((code, i) => code === [...b.criticalDivergenceCodes].sort()[i]);
|
|
15124
|
+
}
|
|
15125
|
+
function parseSoakCertificate(value, expectedPolicy, expectedLedgerDigest) {
|
|
15126
|
+
const parsed = SoakCertificateSchema.safeParse(value);
|
|
15127
|
+
if (!parsed.success) {
|
|
15128
|
+
const detail = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.code}`).join("; ");
|
|
15129
|
+
throw new SoakCertificateError("invalid-certificate", detail);
|
|
14529
15130
|
}
|
|
14530
|
-
|
|
15131
|
+
const certificate = parsed.data;
|
|
15132
|
+
if (!sameSoakPolicy(certificate.policy, expectedPolicy)) {
|
|
15133
|
+
throw new SoakCertificateError("policy-mismatch", "embedded policy diverges from the expected policy");
|
|
15134
|
+
}
|
|
15135
|
+
const failedGates = evaluateSoakGates(certificate.evidence, certificate.policy);
|
|
15136
|
+
const verdict = failedGates.length === 0 ? "pass" : "fail";
|
|
15137
|
+
if (certificate.verdict !== verdict || !sameSoakGates(certificate.failedGates, failedGates)) {
|
|
15138
|
+
throw new SoakCertificateError("verdict-mismatch", `evidence yields "${verdict}" (${failedGates.join(",") || "no failed gate"})`);
|
|
15139
|
+
}
|
|
15140
|
+
const { digest, ...unsigned } = certificate;
|
|
15141
|
+
if (sha256Hex(canonicalSoakCertificate(unsigned)) !== digest) {
|
|
15142
|
+
throw new SoakCertificateError("digest-mismatch", "certificate digest does not cover the presented evidence");
|
|
15143
|
+
}
|
|
15144
|
+
if (certificate.ledgerDigest !== expectedLedgerDigest) {
|
|
15145
|
+
throw new SoakCertificateError("ledger-mismatch", "ledger digest does not match the evidence the caller holds");
|
|
15146
|
+
}
|
|
15147
|
+
return certificate;
|
|
14531
15148
|
}
|
|
14532
15149
|
|
|
14533
|
-
// src/
|
|
14534
|
-
|
|
14535
|
-
|
|
14536
|
-
|
|
15150
|
+
// src/local/cacheAdapter.ts
|
|
15151
|
+
import * as fs3 from "node:fs";
|
|
15152
|
+
import * as os from "node:os";
|
|
15153
|
+
import * as path3 from "node:path";
|
|
15154
|
+
var SCOPE_PREFIX2 = "@jmanuelcorral/openteam";
|
|
15155
|
+
var SCOPE_SEGMENTS = SCOPE_PREFIX2.split("/");
|
|
15156
|
+
function resolveCacheRoot(override) {
|
|
15157
|
+
if (override !== undefined && override.trim() !== "") {
|
|
15158
|
+
return override;
|
|
14537
15159
|
}
|
|
14538
|
-
|
|
15160
|
+
const base = process.env.XDG_CACHE_HOME ?? path3.join(os.homedir(), ".cache");
|
|
15161
|
+
return path3.join(base, "opencode", "packages");
|
|
14539
15162
|
}
|
|
14540
|
-
function
|
|
14541
|
-
|
|
14542
|
-
|
|
14543
|
-
|
|
14544
|
-
|
|
14545
|
-
|
|
14546
|
-
continue;
|
|
14547
|
-
}
|
|
14548
|
-
const embedding = deps.embeddings.get(record.id);
|
|
14549
|
-
if (embedding === undefined) {
|
|
14550
|
-
continue;
|
|
14551
|
-
}
|
|
14552
|
-
const similarity = cosineSimilarity(queryEmbedding, embedding);
|
|
14553
|
-
if (similarity < query.minSimilarity) {
|
|
14554
|
-
continue;
|
|
15163
|
+
function readJsonSafe(filePath) {
|
|
15164
|
+
try {
|
|
15165
|
+
const text2 = fs3.readFileSync(filePath, "utf8");
|
|
15166
|
+
const parsed = JSON.parse(text2);
|
|
15167
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
15168
|
+
return parsed;
|
|
14555
15169
|
}
|
|
14556
|
-
|
|
15170
|
+
return;
|
|
15171
|
+
} catch {
|
|
15172
|
+
return;
|
|
14557
15173
|
}
|
|
14558
|
-
const signals = {
|
|
14559
|
-
now: deps.now,
|
|
14560
|
-
...deps.signals ?? DEFAULT_RANK_SIGNALS
|
|
14561
|
-
};
|
|
14562
|
-
return rankRecall(candidates, signals).slice(0, query.limit);
|
|
14563
15174
|
}
|
|
14564
|
-
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
14568
|
-
|
|
15175
|
+
function extractVersion(pkg) {
|
|
15176
|
+
if (pkg === undefined)
|
|
15177
|
+
return "";
|
|
15178
|
+
const v = pkg.version;
|
|
15179
|
+
return typeof v === "string" ? v : "";
|
|
15180
|
+
}
|
|
15181
|
+
function readDirectoryEntries(dir) {
|
|
15182
|
+
try {
|
|
15183
|
+
return fs3.readdirSync(dir, { withFileTypes: true });
|
|
15184
|
+
} catch {
|
|
15185
|
+
return [];
|
|
14569
15186
|
}
|
|
14570
|
-
return includeShared && record.ownerKey === SHARED_OWNER_KEY;
|
|
14571
15187
|
}
|
|
14572
|
-
function
|
|
14573
|
-
|
|
14574
|
-
|
|
14575
|
-
|
|
14576
|
-
|
|
14577
|
-
continue;
|
|
15188
|
+
function lstatPlainDirectory(dir) {
|
|
15189
|
+
try {
|
|
15190
|
+
const stat2 = fs3.lstatSync(dir);
|
|
15191
|
+
if (!stat2.isDirectory() || stat2.isSymbolicLink()) {
|
|
15192
|
+
return;
|
|
14578
15193
|
}
|
|
14579
|
-
|
|
15194
|
+
return stat2;
|
|
15195
|
+
} catch {
|
|
15196
|
+
return;
|
|
15197
|
+
}
|
|
15198
|
+
}
|
|
15199
|
+
function findEntryDirs(cacheRoot) {
|
|
15200
|
+
const candidates = [];
|
|
15201
|
+
for (const topEntry of readDirectoryEntries(cacheRoot)) {
|
|
15202
|
+
const topPath = path3.join(cacheRoot, topEntry.name);
|
|
15203
|
+
const topStat = lstatPlainDirectory(topPath);
|
|
15204
|
+
if (topStat === undefined) {
|
|
14580
15205
|
continue;
|
|
14581
15206
|
}
|
|
14582
|
-
if (!
|
|
15207
|
+
if (!topEntry.name.startsWith("@")) {
|
|
15208
|
+
candidates.push({
|
|
15209
|
+
specDir: topEntry.name,
|
|
15210
|
+
absolutePath: topPath,
|
|
15211
|
+
stat: topStat
|
|
15212
|
+
});
|
|
14583
15213
|
continue;
|
|
14584
15214
|
}
|
|
14585
|
-
const
|
|
14586
|
-
|
|
14587
|
-
|
|
14588
|
-
|
|
14589
|
-
|
|
14590
|
-
}
|
|
14591
|
-
}
|
|
14592
|
-
const visited = new Set([query.seed]);
|
|
14593
|
-
const nodes = [{ id: query.seed, depth: 0 }];
|
|
14594
|
-
const edges = [];
|
|
14595
|
-
let frontier = [query.seed];
|
|
14596
|
-
for (let depth = 0;depth < query.maxDepth; depth += 1) {
|
|
14597
|
-
const nextFrontier = [];
|
|
14598
|
-
for (const nodeId of frontier) {
|
|
14599
|
-
const outgoing = adjacency.get(nodeId) ?? [];
|
|
14600
|
-
for (const edge of outgoing) {
|
|
14601
|
-
if (visited.has(edge.to)) {
|
|
14602
|
-
continue;
|
|
14603
|
-
}
|
|
14604
|
-
visited.add(edge.to);
|
|
14605
|
-
const childDepth = depth + 1;
|
|
14606
|
-
nodes.push({ id: edge.to, depth: childDepth });
|
|
14607
|
-
edges.push({
|
|
14608
|
-
from: edge.from,
|
|
14609
|
-
to: edge.to,
|
|
14610
|
-
predicate: edge.predicate,
|
|
14611
|
-
depth: childDepth
|
|
14612
|
-
});
|
|
14613
|
-
nextFrontier.push(edge.to);
|
|
15215
|
+
for (const packageEntry of readDirectoryEntries(topPath)) {
|
|
15216
|
+
const packagePath = path3.join(topPath, packageEntry.name);
|
|
15217
|
+
const packageStat = lstatPlainDirectory(packagePath);
|
|
15218
|
+
if (packageStat === undefined) {
|
|
15219
|
+
continue;
|
|
14614
15220
|
}
|
|
15221
|
+
candidates.push({
|
|
15222
|
+
specDir: `${topEntry.name}/${packageEntry.name}`,
|
|
15223
|
+
absolutePath: packagePath,
|
|
15224
|
+
stat: packageStat
|
|
15225
|
+
});
|
|
14615
15226
|
}
|
|
14616
|
-
frontier = nextFrontier;
|
|
14617
15227
|
}
|
|
14618
|
-
return
|
|
14619
|
-
}
|
|
14620
|
-
function seedNodeId(record) {
|
|
14621
|
-
return record.kind === "entity" ? record.canonicalName : undefined;
|
|
15228
|
+
return candidates.sort((a, b) => a.specDir.localeCompare(b.specDir));
|
|
14622
15229
|
}
|
|
14623
|
-
function
|
|
14624
|
-
const
|
|
14625
|
-
const
|
|
14626
|
-
|
|
14627
|
-
|
|
14628
|
-
for (const result of seeds) {
|
|
14629
|
-
const seed = seedNodeId(result.record);
|
|
14630
|
-
if (seed === undefined) {
|
|
15230
|
+
async function listEntries(cacheRoot) {
|
|
15231
|
+
const entries = [];
|
|
15232
|
+
for (const candidate of findEntryDirs(cacheRoot)) {
|
|
15233
|
+
const { specDir, absolutePath, stat: stat2 } = candidate;
|
|
15234
|
+
if (!specDir.startsWith(SCOPE_PREFIX2))
|
|
14631
15235
|
continue;
|
|
15236
|
+
const mtimeIso = stat2.mtime.toISOString();
|
|
15237
|
+
const entryPkg = readJsonSafe(path3.join(absolutePath, "package.json"));
|
|
15238
|
+
const deps = entryPkg?.dependencies;
|
|
15239
|
+
let pinnedVersion = "";
|
|
15240
|
+
if (deps !== null && typeof deps === "object" && !Array.isArray(deps)) {
|
|
15241
|
+
const depsObj = deps;
|
|
15242
|
+
const pinned = depsObj[SCOPE_PREFIX2];
|
|
15243
|
+
pinnedVersion = typeof pinned === "string" ? pinned : "";
|
|
14632
15244
|
}
|
|
14633
|
-
|
|
14634
|
-
|
|
14635
|
-
|
|
14636
|
-
|
|
14637
|
-
|
|
14638
|
-
|
|
14639
|
-
|
|
14640
|
-
|
|
14641
|
-
})
|
|
15245
|
+
const installedPkg = readJsonSafe(path3.join(absolutePath, "node_modules", ...SCOPE_SEGMENTS, "package.json"));
|
|
15246
|
+
const installedVersion = extractVersion(installedPkg);
|
|
15247
|
+
entries.push({
|
|
15248
|
+
specDir,
|
|
15249
|
+
absolutePath,
|
|
15250
|
+
pinnedVersion,
|
|
15251
|
+
installedVersion,
|
|
15252
|
+
mtimeIso
|
|
14642
15253
|
});
|
|
14643
15254
|
}
|
|
14644
|
-
return
|
|
14645
|
-
}
|
|
14646
|
-
|
|
14647
|
-
// src/memory/merge.ts
|
|
14648
|
-
var SEP = "\x00";
|
|
14649
|
-
function factSlotKey(fact) {
|
|
14650
|
-
return [fact.subject, fact.predicate, fact.ownerKey].join(SEP);
|
|
15255
|
+
return entries;
|
|
14651
15256
|
}
|
|
14652
|
-
function
|
|
14653
|
-
|
|
15257
|
+
async function deleteEntry(entryPath) {
|
|
15258
|
+
fs3.rmSync(entryPath, { recursive: true, force: true });
|
|
14654
15259
|
}
|
|
14655
|
-
function
|
|
14656
|
-
|
|
15260
|
+
async function isReparsePath(entryPath) {
|
|
15261
|
+
try {
|
|
15262
|
+
const stat2 = await fs3.promises.lstat(entryPath);
|
|
15263
|
+
return stat2.isSymbolicLink();
|
|
15264
|
+
} catch {
|
|
15265
|
+
return true;
|
|
15266
|
+
}
|
|
14657
15267
|
}
|
|
14658
|
-
|
|
14659
|
-
|
|
15268
|
+
var realCacheAdapter = {
|
|
15269
|
+
resolveCacheRoot,
|
|
15270
|
+
listEntries,
|
|
15271
|
+
deleteEntry,
|
|
15272
|
+
isReparsePath
|
|
15273
|
+
};
|
|
15274
|
+
|
|
15275
|
+
// src/orchestrator/rosterPersistence.ts
|
|
15276
|
+
function rosterFence(roster) {
|
|
15277
|
+
const data = { universe: roster.universe, entries: roster.entries };
|
|
15278
|
+
return `\`\`\`json
|
|
15279
|
+
${JSON.stringify(data, null, 2)}
|
|
15280
|
+
\`\`\``;
|
|
14660
15281
|
}
|
|
14661
|
-
function
|
|
14662
|
-
return
|
|
15282
|
+
function serializeRoster(roster) {
|
|
15283
|
+
return `# openteam roster
|
|
15284
|
+
|
|
15285
|
+
Universe: ${roster.universe}
|
|
15286
|
+
|
|
15287
|
+
${rosterFence(roster)}
|
|
15288
|
+
`;
|
|
14663
15289
|
}
|
|
14664
|
-
function
|
|
14665
|
-
|
|
15290
|
+
async function persistRoster(storage, roster, path4 = OPENTEAM_ROSTER_PATH) {
|
|
15291
|
+
await storage.write(path4, serializeRoster(roster));
|
|
15292
|
+
return path4;
|
|
14666
15293
|
}
|
|
14667
|
-
function
|
|
14668
|
-
|
|
15294
|
+
async function loadRosterFile(storage, path4 = OPENTEAM_ROSTER_PATH) {
|
|
15295
|
+
const content = await storage.read(path4);
|
|
15296
|
+
if (content === undefined) {
|
|
15297
|
+
return { status: "absent", path: path4 };
|
|
15298
|
+
}
|
|
15299
|
+
const parsed = parseRosterResult(content);
|
|
15300
|
+
if (!parsed.ok) {
|
|
15301
|
+
return { status: "invalid", path: path4, error: parsed.error };
|
|
15302
|
+
}
|
|
15303
|
+
return {
|
|
15304
|
+
status: "loaded",
|
|
15305
|
+
path: path4,
|
|
15306
|
+
roster: enforceGuaranteedRoles(parsed.roster)
|
|
15307
|
+
};
|
|
14669
15308
|
}
|
|
14670
|
-
function
|
|
14671
|
-
const
|
|
15309
|
+
async function loadOrGenerateRoster(storage, generate, path4 = OPENTEAM_ROSTER_PATH) {
|
|
15310
|
+
const existing = await loadRosterFile(storage, path4);
|
|
15311
|
+
if (existing.status === "loaded") {
|
|
15312
|
+
return { roster: existing.roster, regenerated: false };
|
|
15313
|
+
}
|
|
15314
|
+
const roster = enforceGuaranteedRoles(await generate());
|
|
15315
|
+
if (existing.status === "absent") {
|
|
15316
|
+
await persistRoster(storage, roster, path4);
|
|
15317
|
+
return { roster, regenerated: true };
|
|
15318
|
+
}
|
|
14672
15319
|
return {
|
|
14673
|
-
|
|
14674
|
-
|
|
14675
|
-
|
|
14676
|
-
|
|
15320
|
+
roster,
|
|
15321
|
+
regenerated: true,
|
|
15322
|
+
recoveredFromInvalidPersisted: true,
|
|
15323
|
+
invalidPersistedRosterError: existing.error.message
|
|
14677
15324
|
};
|
|
14678
15325
|
}
|
|
14679
|
-
|
|
14680
|
-
|
|
14681
|
-
|
|
14682
|
-
|
|
14683
|
-
|
|
14684
|
-
|
|
14685
|
-
|
|
14686
|
-
|
|
14687
|
-
|
|
14688
|
-
|
|
14689
|
-
|
|
14690
|
-
|
|
14691
|
-
|
|
14692
|
-
|
|
14693
|
-
|
|
14694
|
-
|
|
14695
|
-
|
|
14696
|
-
|
|
14697
|
-
|
|
14698
|
-
|
|
14699
|
-
|
|
14700
|
-
|
|
14701
|
-
|
|
14702
|
-
|
|
14703
|
-
|
|
14704
|
-
|
|
14705
|
-
|
|
15326
|
+
|
|
15327
|
+
// src/memory/types.ts
|
|
15328
|
+
import { z as z21 } from "zod";
|
|
15329
|
+
var SHARED_OWNER_KEY = "*";
|
|
15330
|
+
var OwnerKeySchema = z21.string().min(1);
|
|
15331
|
+
var MemoryKindSchema = z21.enum(["fact", "preference", "entity"]);
|
|
15332
|
+
var MemoryBaseSchema = z21.object({
|
|
15333
|
+
id: z21.string().min(1),
|
|
15334
|
+
ownerKey: OwnerKeySchema,
|
|
15335
|
+
confidence: z21.number().min(0).max(1),
|
|
15336
|
+
validFrom: z21.number().finite(),
|
|
15337
|
+
validUntil: z21.number().finite().nullable().default(null),
|
|
15338
|
+
createdAt: z21.number().finite(),
|
|
15339
|
+
invalidatedAt: z21.number().finite().nullable().default(null),
|
|
15340
|
+
sourceHash: z21.string().min(1),
|
|
15341
|
+
supersededBy: z21.string().min(1).nullable().default(null)
|
|
15342
|
+
}).strict();
|
|
15343
|
+
var FactSchema = MemoryBaseSchema.extend({
|
|
15344
|
+
kind: z21.literal("fact"),
|
|
15345
|
+
subject: z21.string().min(1),
|
|
15346
|
+
predicate: z21.string().min(1),
|
|
15347
|
+
object: z21.string().min(1),
|
|
15348
|
+
category: z21.string().min(1).nullable().default(null)
|
|
15349
|
+
});
|
|
15350
|
+
var PreferenceSchema = MemoryBaseSchema.extend({
|
|
15351
|
+
kind: z21.literal("preference"),
|
|
15352
|
+
category: z21.string().min(1),
|
|
15353
|
+
preference: z21.string().min(1),
|
|
15354
|
+
context: z21.string().min(1).nullable().default(null),
|
|
15355
|
+
lastAccessedAt: z21.number().finite().nullable().default(null),
|
|
15356
|
+
accessCount: z21.number().int().min(0).default(0)
|
|
15357
|
+
});
|
|
15358
|
+
var EntitySchema = MemoryBaseSchema.extend({
|
|
15359
|
+
kind: z21.literal("entity"),
|
|
15360
|
+
canonicalName: z21.string().min(1),
|
|
15361
|
+
type: z21.string().min(1),
|
|
15362
|
+
aliases: z21.array(z21.string().min(1)).default([])
|
|
15363
|
+
});
|
|
15364
|
+
var RelationSchema = MemoryBaseSchema.extend({
|
|
15365
|
+
kind: z21.literal("relation"),
|
|
15366
|
+
from: z21.string().min(1),
|
|
15367
|
+
to: z21.string().min(1),
|
|
15368
|
+
predicate: z21.string().min(1),
|
|
15369
|
+
annotation: z21.string().min(1).nullable().default(null)
|
|
15370
|
+
});
|
|
15371
|
+
var MemoryRecordSchema = z21.discriminatedUnion("kind", [
|
|
15372
|
+
FactSchema,
|
|
15373
|
+
PreferenceSchema,
|
|
15374
|
+
EntitySchema,
|
|
15375
|
+
RelationSchema
|
|
15376
|
+
]);
|
|
15377
|
+
var RecallQuerySchema = z21.object({
|
|
15378
|
+
ownerKey: OwnerKeySchema,
|
|
15379
|
+
kinds: z21.array(MemoryKindSchema).default(["fact", "preference", "entity"]),
|
|
15380
|
+
asOf: z21.number().finite().nullable().default(null),
|
|
15381
|
+
limit: z21.number().int().positive().default(8),
|
|
15382
|
+
minSimilarity: z21.number().min(0).max(1).default(0.2),
|
|
15383
|
+
includeShared: z21.boolean().default(true)
|
|
15384
|
+
}).strict();
|
|
15385
|
+
|
|
15386
|
+
// src/memory/rank.ts
|
|
15387
|
+
var DAY_MS = 86400000;
|
|
15388
|
+
var DEFAULT_RANK_SIGNALS = {
|
|
15389
|
+
similarityWeight: 1,
|
|
15390
|
+
recencyWeight: 0.2,
|
|
15391
|
+
accessWeight: 0.1,
|
|
15392
|
+
recencyHalfLifeMs: 14 * DAY_MS
|
|
15393
|
+
};
|
|
15394
|
+
function recencyTimestamp(record) {
|
|
15395
|
+
if (record.kind === "preference" && record.lastAccessedAt !== null) {
|
|
15396
|
+
return record.lastAccessedAt;
|
|
14706
15397
|
}
|
|
14707
|
-
|
|
14708
|
-
|
|
15398
|
+
return record.createdAt;
|
|
15399
|
+
}
|
|
15400
|
+
function recencyScore(record, signals) {
|
|
15401
|
+
const ageMs = Math.max(0, signals.now - recencyTimestamp(record));
|
|
15402
|
+
return 0.5 ** (ageMs / signals.recencyHalfLifeMs);
|
|
15403
|
+
}
|
|
15404
|
+
function accessScore(record) {
|
|
15405
|
+
if (record.kind !== "preference") {
|
|
15406
|
+
return 0;
|
|
14709
15407
|
}
|
|
14710
|
-
return
|
|
15408
|
+
return 1 - 1 / (1 + record.accessCount);
|
|
14711
15409
|
}
|
|
14712
|
-
function
|
|
14713
|
-
|
|
14714
|
-
|
|
14715
|
-
|
|
14716
|
-
|
|
14717
|
-
|
|
14718
|
-
|
|
14719
|
-
|
|
14720
|
-
|
|
14721
|
-
|
|
14722
|
-
}
|
|
14723
|
-
|
|
14724
|
-
|
|
14725
|
-
|
|
14726
|
-
|
|
15410
|
+
function scoreCandidate(candidate, signals) {
|
|
15411
|
+
return signals.similarityWeight * candidate.similarity + signals.recencyWeight * recencyScore(candidate.record, signals) + signals.accessWeight * accessScore(candidate.record);
|
|
15412
|
+
}
|
|
15413
|
+
function rankRecall(candidates, signals) {
|
|
15414
|
+
return candidates.map((candidate) => ({
|
|
15415
|
+
...candidate,
|
|
15416
|
+
score: scoreCandidate(candidate, signals)
|
|
15417
|
+
})).sort((a, b) => {
|
|
15418
|
+
if (b.score !== a.score) {
|
|
15419
|
+
return b.score - a.score;
|
|
15420
|
+
}
|
|
15421
|
+
return a.record.id < b.record.id ? -1 : a.record.id > b.record.id ? 1 : 0;
|
|
15422
|
+
});
|
|
15423
|
+
}
|
|
15424
|
+
|
|
15425
|
+
// src/memory/temporal.ts
|
|
15426
|
+
function isTransactionActiveAt(record, asOf) {
|
|
15427
|
+
return record.invalidatedAt === null || record.invalidatedAt > asOf;
|
|
15428
|
+
}
|
|
15429
|
+
function isValidAt(record, asOf) {
|
|
15430
|
+
if (record.validFrom > asOf) {
|
|
15431
|
+
return false;
|
|
15432
|
+
}
|
|
15433
|
+
return record.validUntil === null || record.validUntil > asOf;
|
|
15434
|
+
}
|
|
15435
|
+
function isActiveAt(record, asOf) {
|
|
15436
|
+
return isTransactionActiveAt(record, asOf) && isValidAt(record, asOf);
|
|
15437
|
+
}
|
|
15438
|
+
function filterActive(records, asOf) {
|
|
15439
|
+
return records.filter((record) => isActiveAt(record, asOf));
|
|
15440
|
+
}
|
|
15441
|
+
function coalesceWindow(a, b) {
|
|
15442
|
+
const validFrom = Math.min(a.validFrom, b.validFrom);
|
|
15443
|
+
const validUntil = a.validUntil === null || b.validUntil === null ? null : Math.max(a.validUntil, b.validUntil);
|
|
15444
|
+
return { validFrom, validUntil };
|
|
15445
|
+
}
|
|
15446
|
+
|
|
15447
|
+
// src/memory/vector.ts
|
|
15448
|
+
function dot(a, b) {
|
|
15449
|
+
if (a.length !== b.length) {
|
|
15450
|
+
throw new Error(`dimension mismatch: ${a.length} vs ${b.length}`);
|
|
15451
|
+
}
|
|
15452
|
+
let sum = 0;
|
|
15453
|
+
for (let i = 0;i < a.length; i += 1) {
|
|
15454
|
+
sum += a[i] * b[i];
|
|
15455
|
+
}
|
|
15456
|
+
return sum;
|
|
15457
|
+
}
|
|
15458
|
+
function norm(a) {
|
|
15459
|
+
let sum = 0;
|
|
15460
|
+
for (let i = 0;i < a.length; i += 1) {
|
|
15461
|
+
const value = a[i];
|
|
15462
|
+
sum += value * value;
|
|
15463
|
+
}
|
|
15464
|
+
return Math.sqrt(sum);
|
|
15465
|
+
}
|
|
15466
|
+
function cosineSimilarity(a, b) {
|
|
15467
|
+
const denom = norm(a) * norm(b);
|
|
15468
|
+
if (denom === 0) {
|
|
15469
|
+
return 0;
|
|
15470
|
+
}
|
|
15471
|
+
return dot(a, b) / denom;
|
|
15472
|
+
}
|
|
15473
|
+
|
|
15474
|
+
// src/memory/recall.ts
|
|
15475
|
+
function matchesScope(record, query) {
|
|
15476
|
+
if (record.ownerKey === query.ownerKey) {
|
|
15477
|
+
return true;
|
|
15478
|
+
}
|
|
15479
|
+
return query.includeShared && record.ownerKey === SHARED_OWNER_KEY;
|
|
15480
|
+
}
|
|
15481
|
+
function recall(records, queryEmbedding, query, deps) {
|
|
15482
|
+
const asOf = query.asOf ?? deps.now;
|
|
15483
|
+
const kinds = new Set(query.kinds);
|
|
15484
|
+
const candidates = [];
|
|
15485
|
+
for (const record of filterActive(records, asOf)) {
|
|
15486
|
+
if (!kinds.has(record.kind) || !matchesScope(record, query)) {
|
|
15487
|
+
continue;
|
|
15488
|
+
}
|
|
15489
|
+
const embedding = deps.embeddings.get(record.id);
|
|
15490
|
+
if (embedding === undefined) {
|
|
15491
|
+
continue;
|
|
15492
|
+
}
|
|
15493
|
+
const similarity = cosineSimilarity(queryEmbedding, embedding);
|
|
15494
|
+
if (similarity < query.minSimilarity) {
|
|
15495
|
+
continue;
|
|
15496
|
+
}
|
|
15497
|
+
candidates.push({ record, similarity });
|
|
15498
|
+
}
|
|
15499
|
+
const signals = {
|
|
15500
|
+
now: deps.now,
|
|
15501
|
+
...deps.signals ?? DEFAULT_RANK_SIGNALS
|
|
15502
|
+
};
|
|
15503
|
+
return rankRecall(candidates, signals).slice(0, query.limit);
|
|
15504
|
+
}
|
|
15505
|
+
|
|
15506
|
+
// src/memory/merge.ts
|
|
15507
|
+
var SEP = "\x00";
|
|
15508
|
+
function factSlotKey(fact) {
|
|
15509
|
+
return [fact.subject, fact.predicate, fact.ownerKey].join(SEP);
|
|
15510
|
+
}
|
|
15511
|
+
function factValueKey(fact) {
|
|
15512
|
+
return [factSlotKey(fact), fact.object].join(SEP);
|
|
15513
|
+
}
|
|
15514
|
+
function preferenceSlotKey(preference) {
|
|
15515
|
+
return [preference.category, preference.ownerKey].join(SEP);
|
|
15516
|
+
}
|
|
15517
|
+
function preferenceValueKey(preference) {
|
|
15518
|
+
return [preferenceSlotKey(preference), preference.preference].join(SEP);
|
|
15519
|
+
}
|
|
15520
|
+
function entitySlotKey(entity) {
|
|
15521
|
+
return [entity.canonicalName, entity.type, entity.ownerKey].join(SEP);
|
|
15522
|
+
}
|
|
15523
|
+
function relationSlotKey(relation) {
|
|
15524
|
+
return [relation.from, relation.predicate, relation.ownerKey].join(SEP);
|
|
15525
|
+
}
|
|
15526
|
+
function relationValueKey(relation) {
|
|
15527
|
+
return [relationSlotKey(relation), relation.to].join(SEP);
|
|
15528
|
+
}
|
|
15529
|
+
function coalesceFact(existing, incoming) {
|
|
15530
|
+
const window = coalesceWindow(existing, incoming);
|
|
15531
|
+
return {
|
|
15532
|
+
...existing,
|
|
15533
|
+
validFrom: window.validFrom,
|
|
15534
|
+
validUntil: window.validUntil,
|
|
15535
|
+
confidence: Math.max(existing.confidence, incoming.confidence)
|
|
15536
|
+
};
|
|
15537
|
+
}
|
|
15538
|
+
function applyFact(state, incoming, now) {
|
|
15539
|
+
const incomingSlot = factSlotKey(incoming);
|
|
15540
|
+
const incomingValue = factValueKey(incoming);
|
|
15541
|
+
const superseded = [];
|
|
15542
|
+
const records = [];
|
|
15543
|
+
let reaffirmed = false;
|
|
15544
|
+
for (const fact of state) {
|
|
15545
|
+
if (!isActiveAt(fact, now)) {
|
|
15546
|
+
records.push(fact);
|
|
15547
|
+
continue;
|
|
15548
|
+
}
|
|
15549
|
+
if (factValueKey(fact) === incomingValue) {
|
|
15550
|
+
records.push(coalesceFact(fact, incoming));
|
|
15551
|
+
reaffirmed = true;
|
|
15552
|
+
continue;
|
|
15553
|
+
}
|
|
15554
|
+
if (factSlotKey(fact) === incomingSlot) {
|
|
15555
|
+
const dead = {
|
|
15556
|
+
...fact,
|
|
15557
|
+
invalidatedAt: now,
|
|
15558
|
+
supersededBy: incoming.id
|
|
15559
|
+
};
|
|
15560
|
+
superseded.push(dead);
|
|
15561
|
+
records.push(dead);
|
|
15562
|
+
continue;
|
|
15563
|
+
}
|
|
15564
|
+
records.push(fact);
|
|
15565
|
+
}
|
|
15566
|
+
if (!reaffirmed) {
|
|
15567
|
+
records.push(incoming);
|
|
15568
|
+
}
|
|
15569
|
+
return { records, superseded };
|
|
15570
|
+
}
|
|
15571
|
+
function applyPreference(state, incoming, now) {
|
|
15572
|
+
const incomingSlot = preferenceSlotKey(incoming);
|
|
15573
|
+
const incomingValue = preferenceValueKey(incoming);
|
|
15574
|
+
const superseded = [];
|
|
15575
|
+
const records = [];
|
|
15576
|
+
let reaffirmed = false;
|
|
15577
|
+
for (const preference of state) {
|
|
15578
|
+
if (!isActiveAt(preference, now)) {
|
|
15579
|
+
records.push(preference);
|
|
15580
|
+
continue;
|
|
15581
|
+
}
|
|
15582
|
+
if (preferenceValueKey(preference) === incomingValue) {
|
|
15583
|
+
records.push({
|
|
15584
|
+
...preference,
|
|
15585
|
+
confidence: Math.max(preference.confidence, incoming.confidence)
|
|
14727
15586
|
});
|
|
14728
15587
|
reaffirmed = true;
|
|
14729
15588
|
continue;
|
|
@@ -15076,44 +15935,517 @@ async function recallMemory(deps, queryText, query) {
|
|
|
15076
15935
|
return recall(recordRead.records, queryEmbedding, query, recallDeps);
|
|
15077
15936
|
}
|
|
15078
15937
|
|
|
15079
|
-
// src/
|
|
15080
|
-
|
|
15081
|
-
|
|
15082
|
-
|
|
15083
|
-
|
|
15084
|
-
|
|
15085
|
-
|
|
15086
|
-
|
|
15087
|
-
|
|
15088
|
-
|
|
15089
|
-
|
|
15090
|
-
|
|
15091
|
-
|
|
15092
|
-
|
|
15093
|
-
|
|
15094
|
-
|
|
15095
|
-
|
|
15096
|
-
|
|
15938
|
+
// src/plugin/orchestrateTool.ts
|
|
15939
|
+
import { tool } from "@opencode-ai/plugin";
|
|
15940
|
+
import { z as z22 } from "zod";
|
|
15941
|
+
var _pluginWarnedRoles = new Set;
|
|
15942
|
+
var RoleAssignmentSchema = z22.object({
|
|
15943
|
+
roleID: z22.string().min(1).describe("Role identifier from the roster"),
|
|
15944
|
+
prompt: z22.string().min(1).describe("Work prompt for this role"),
|
|
15945
|
+
title: z22.string().min(1).optional().describe("Human-readable title"),
|
|
15946
|
+
dependsOn: z22.array(z22.string().min(1)).optional().describe("Role IDs this assignment depends on (DAG edges)")
|
|
15947
|
+
}).strict();
|
|
15948
|
+
var OrchestratePayloadSchema = z22.object({
|
|
15949
|
+
assignments: z22.array(RoleAssignmentSchema).min(1).describe("Role assignments to distribute"),
|
|
15950
|
+
parentSessionID: z22.string().min(1).optional().describe("Parent session for subsessions"),
|
|
15951
|
+
directory: z22.string().min(1).optional().describe("Working directory override")
|
|
15952
|
+
}).strict();
|
|
15953
|
+
function adaptSdkClient(sdk) {
|
|
15954
|
+
return {
|
|
15955
|
+
session: {
|
|
15956
|
+
create: async (args) => {
|
|
15957
|
+
const result = await sdk.session.create(args);
|
|
15958
|
+
const out = {};
|
|
15959
|
+
if (result.data !== undefined) {
|
|
15960
|
+
out.data = result.data;
|
|
15961
|
+
}
|
|
15962
|
+
if (result.error !== undefined) {
|
|
15963
|
+
out.error = result.error;
|
|
15964
|
+
}
|
|
15965
|
+
return out;
|
|
15966
|
+
},
|
|
15967
|
+
prompt: async (args) => {
|
|
15968
|
+
const result = await sdk.session.prompt(args);
|
|
15969
|
+
const out = {};
|
|
15970
|
+
if (result.data !== undefined) {
|
|
15971
|
+
out.data = result.data;
|
|
15972
|
+
}
|
|
15973
|
+
if (result.error !== undefined) {
|
|
15974
|
+
out.error = result.error;
|
|
15975
|
+
}
|
|
15976
|
+
return out;
|
|
15977
|
+
}
|
|
15978
|
+
}
|
|
15097
15979
|
};
|
|
15098
15980
|
}
|
|
15099
|
-
|
|
15100
|
-
|
|
15101
|
-
|
|
15102
|
-
|
|
15103
|
-
|
|
15104
|
-
|
|
15105
|
-
|
|
15106
|
-
|
|
15107
|
-
|
|
15108
|
-
|
|
15109
|
-
|
|
15110
|
-
|
|
15981
|
+
|
|
15982
|
+
// src/local/embeddings.ts
|
|
15983
|
+
function parseEmbeddingsResponse(payload) {
|
|
15984
|
+
if (typeof payload !== "object" || payload === null || !Array.isArray(payload.data)) {
|
|
15985
|
+
throw new Error("Malformed /embeddings response: missing 'data'");
|
|
15986
|
+
}
|
|
15987
|
+
const data = payload.data;
|
|
15988
|
+
return data.map((entry, index) => {
|
|
15989
|
+
const embedding = typeof entry === "object" && entry !== null ? entry.embedding : undefined;
|
|
15990
|
+
if (!Array.isArray(embedding) || !embedding.every((n) => typeof n === "number" && Number.isFinite(n))) {
|
|
15991
|
+
throw new Error(`Malformed /embeddings response: invalid vector at index ${index}`);
|
|
15992
|
+
}
|
|
15993
|
+
return embedding;
|
|
15994
|
+
});
|
|
15111
15995
|
}
|
|
15112
|
-
function
|
|
15113
|
-
|
|
15114
|
-
|
|
15115
|
-
|
|
15116
|
-
|
|
15996
|
+
async function embedTexts(request, deps) {
|
|
15997
|
+
if (request.texts.length === 0) {
|
|
15998
|
+
return [];
|
|
15999
|
+
}
|
|
16000
|
+
let response;
|
|
16001
|
+
try {
|
|
16002
|
+
response = await deps.fetch(embeddingsEndpoint(request.baseURL), {
|
|
16003
|
+
method: "POST",
|
|
16004
|
+
headers: {
|
|
16005
|
+
"content-type": "application/json",
|
|
16006
|
+
accept: "application/json"
|
|
16007
|
+
},
|
|
16008
|
+
body: JSON.stringify({
|
|
16009
|
+
model: request.modelID,
|
|
16010
|
+
input: [...request.texts]
|
|
16011
|
+
})
|
|
16012
|
+
});
|
|
16013
|
+
} catch (error) {
|
|
16014
|
+
throw new Error(`Local embeddings failed: ${errorMessage(error)}`);
|
|
16015
|
+
}
|
|
16016
|
+
if (!response.ok) {
|
|
16017
|
+
throw new Error(`Local embeddings failed: HTTP ${response.status} on /embeddings`);
|
|
16018
|
+
}
|
|
16019
|
+
let payload;
|
|
16020
|
+
try {
|
|
16021
|
+
payload = await response.json();
|
|
16022
|
+
} catch (error) {
|
|
16023
|
+
throw new Error(`Local embeddings failed: ${errorMessage(error)}`);
|
|
16024
|
+
}
|
|
16025
|
+
const vectors = parseEmbeddingsResponse(payload);
|
|
16026
|
+
if (vectors.length !== request.texts.length) {
|
|
16027
|
+
throw new Error(`Local embeddings returned ${vectors.length} vectors for ${request.texts.length} texts`);
|
|
16028
|
+
}
|
|
16029
|
+
return vectors;
|
|
16030
|
+
}
|
|
16031
|
+
function createLocalEmbedder(request, deps) {
|
|
16032
|
+
return (texts) => embedTexts({ ...request, texts }, deps);
|
|
16033
|
+
}
|
|
16034
|
+
|
|
16035
|
+
// src/memory/embedText.ts
|
|
16036
|
+
function normalize(parts) {
|
|
16037
|
+
return parts.map((part) => part.trim()).filter((part) => part.length > 0).join(" ");
|
|
16038
|
+
}
|
|
16039
|
+
function recordEmbeddingText(record) {
|
|
16040
|
+
if (record.kind === "fact") {
|
|
16041
|
+
return normalize([
|
|
16042
|
+
record.subject,
|
|
16043
|
+
record.predicate,
|
|
16044
|
+
record.object,
|
|
16045
|
+
record.category ?? ""
|
|
16046
|
+
]);
|
|
16047
|
+
}
|
|
16048
|
+
if (record.kind === "preference") {
|
|
16049
|
+
return normalize([
|
|
16050
|
+
record.category,
|
|
16051
|
+
record.preference,
|
|
16052
|
+
record.context ?? ""
|
|
16053
|
+
]);
|
|
16054
|
+
}
|
|
16055
|
+
if (record.kind === "relation") {
|
|
16056
|
+
return normalize([
|
|
16057
|
+
record.from,
|
|
16058
|
+
record.predicate,
|
|
16059
|
+
record.to,
|
|
16060
|
+
record.annotation ?? ""
|
|
16061
|
+
]);
|
|
16062
|
+
}
|
|
16063
|
+
return normalize([record.canonicalName, record.type, ...record.aliases]);
|
|
16064
|
+
}
|
|
16065
|
+
|
|
16066
|
+
// src/storage/index/memoryEmbeddings.ts
|
|
16067
|
+
async function ensureMemoryEmbeddings(deps) {
|
|
16068
|
+
const { index, embedder, model } = deps;
|
|
16069
|
+
const warn = deps.warn ?? console.warn;
|
|
16070
|
+
const storedModel = index.embeddingModel();
|
|
16071
|
+
const modelChanged = storedModel !== null && storedModel !== model;
|
|
16072
|
+
if (modelChanged) {
|
|
16073
|
+
index.clearEmbeddings();
|
|
16074
|
+
}
|
|
16075
|
+
index.setEmbeddingModel(model);
|
|
16076
|
+
const records = index.allRecords();
|
|
16077
|
+
index.pruneEmbeddings();
|
|
16078
|
+
const have = modelChanged ? new Set : new Set(index.embeddingMap().keys());
|
|
16079
|
+
const todo = records.filter((record) => !have.has(record.id));
|
|
16080
|
+
if (todo.length === 0) {
|
|
16081
|
+
return { embedded: 0, failed: 0, modelChanged };
|
|
16082
|
+
}
|
|
16083
|
+
let vectors;
|
|
16084
|
+
try {
|
|
16085
|
+
vectors = await embedder(todo.map(recordEmbeddingText));
|
|
16086
|
+
} catch (error) {
|
|
16087
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
16088
|
+
warn(`[openteam] could not compute embeddings for ${todo.length} memory record(s): ${reason}. ` + "Recall over them is unavailable until the local runtime is reachable.");
|
|
16089
|
+
return { embedded: 0, failed: todo.length, modelChanged };
|
|
16090
|
+
}
|
|
16091
|
+
if (vectors.length !== todo.length) {
|
|
16092
|
+
warn(`[openteam] could not compute embeddings for ${todo.length} memory record(s): ` + `the embedder returned ${vectors.length} vector(s). Recall over them is unavailable.`);
|
|
16093
|
+
return { embedded: 0, failed: todo.length, modelChanged };
|
|
16094
|
+
}
|
|
16095
|
+
const entries = todo.map((record, position) => ({
|
|
16096
|
+
recordId: record.id,
|
|
16097
|
+
vector: vectors[position]
|
|
16098
|
+
}));
|
|
16099
|
+
index.putEmbeddings(entries);
|
|
16100
|
+
return { embedded: entries.length, failed: 0, modelChanged };
|
|
16101
|
+
}
|
|
16102
|
+
|
|
16103
|
+
// src/storage/index/memoryRuntime.ts
|
|
16104
|
+
async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
|
|
16105
|
+
const semantic = resolveMemorySemantic(config);
|
|
16106
|
+
if (!semantic.enabled || semantic.embeddings.provider === "none") {
|
|
16107
|
+
return;
|
|
16108
|
+
}
|
|
16109
|
+
if (options.requireInjectionEnabled === true && !semantic.injection.enabled) {
|
|
16110
|
+
return;
|
|
16111
|
+
}
|
|
16112
|
+
const runtime = config.local.runtimes.find((rt) => rt.enabled && rt.baseURL !== undefined);
|
|
16113
|
+
if (runtime?.baseURL === undefined) {
|
|
16114
|
+
return;
|
|
16115
|
+
}
|
|
16116
|
+
const modelID = semantic.embeddings.model?.modelID ?? runtime.defaultModel.modelID;
|
|
16117
|
+
const openDatabase = deps.openDatabase ?? createBunSqliteDatabase;
|
|
16118
|
+
const makeEmbedder = deps.createEmbedder ?? createLocalEmbedder;
|
|
16119
|
+
const fetchImpl = deps.fetch ?? globalThis.fetch;
|
|
16120
|
+
const now = deps.now ?? (() => Date.now());
|
|
16121
|
+
const warn = deps.warn ?? console.warn;
|
|
16122
|
+
try {
|
|
16123
|
+
const db = await openDatabase(semantic.indexPath);
|
|
16124
|
+
const index = createMemoryIndex(db, warn);
|
|
16125
|
+
const rebuildResult = await rebuildMemoryIndexFromStorage(index, semantic.logPath, { storage: deps.storage });
|
|
16126
|
+
if (rebuildResult.rejectedLines > 0) {
|
|
16127
|
+
warn(`[openteam] memory log rejected ${rebuildResult.rejectedLines} line(s); semantic memory may be incomplete.`);
|
|
16128
|
+
}
|
|
16129
|
+
const embedder = makeEmbedder({ baseURL: runtime.baseURL, modelID }, { fetch: fetchImpl });
|
|
16130
|
+
await ensureMemoryEmbeddings({ index, embedder, model: modelID, warn });
|
|
16131
|
+
return {
|
|
16132
|
+
index,
|
|
16133
|
+
embedder,
|
|
16134
|
+
now,
|
|
16135
|
+
ownerKey: semantic.scope === "user" ? "user" : "project",
|
|
16136
|
+
semantic
|
|
16137
|
+
};
|
|
16138
|
+
} catch {
|
|
16139
|
+
return;
|
|
16140
|
+
}
|
|
16141
|
+
}
|
|
16142
|
+
// package.json
|
|
16143
|
+
var package_default = {
|
|
16144
|
+
name: "@jmanuelcorral/openteam",
|
|
16145
|
+
version: "0.16.1",
|
|
16146
|
+
packageManager: "bun@1.3.14",
|
|
16147
|
+
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
16148
|
+
license: "MIT",
|
|
16149
|
+
author: "Jose Manuel Corral",
|
|
16150
|
+
repository: {
|
|
16151
|
+
type: "git",
|
|
16152
|
+
url: "git+https://github.com/jmanuelcorral/openteam.git"
|
|
16153
|
+
},
|
|
16154
|
+
homepage: "https://github.com/jmanuelcorral/openteam#readme",
|
|
16155
|
+
bugs: {
|
|
16156
|
+
url: "https://github.com/jmanuelcorral/openteam/issues"
|
|
16157
|
+
},
|
|
16158
|
+
keywords: [
|
|
16159
|
+
"opencode",
|
|
16160
|
+
"opencode-plugin",
|
|
16161
|
+
"llm",
|
|
16162
|
+
"routing",
|
|
16163
|
+
"local-llm",
|
|
16164
|
+
"ollama",
|
|
16165
|
+
"lm-studio",
|
|
16166
|
+
"foundry-local",
|
|
16167
|
+
"cost-optimization",
|
|
16168
|
+
"multi-agent"
|
|
16169
|
+
],
|
|
16170
|
+
engines: {
|
|
16171
|
+
bun: ">=1.3",
|
|
16172
|
+
node: "^22.22.2 || ^24.15.0 || >=26.0.0"
|
|
16173
|
+
},
|
|
16174
|
+
type: "module",
|
|
16175
|
+
main: "./dist/index.js",
|
|
16176
|
+
module: "./dist/index.js",
|
|
16177
|
+
types: "./dist/index.d.ts",
|
|
16178
|
+
bin: {
|
|
16179
|
+
openteam: "./dist/cli.js"
|
|
16180
|
+
},
|
|
16181
|
+
exports: {
|
|
16182
|
+
".": {
|
|
16183
|
+
types: "./dist/index.d.ts",
|
|
16184
|
+
import: "./dist/index.js"
|
|
16185
|
+
},
|
|
16186
|
+
"./package.json": "./package.json"
|
|
16187
|
+
},
|
|
16188
|
+
files: [
|
|
16189
|
+
"dist",
|
|
16190
|
+
"README.md",
|
|
16191
|
+
"LICENSE",
|
|
16192
|
+
"AGENTS.md",
|
|
16193
|
+
".opencode/openteam.example.json",
|
|
16194
|
+
".opencode/command/openteam.md"
|
|
16195
|
+
],
|
|
16196
|
+
publishConfig: {
|
|
16197
|
+
access: "public",
|
|
16198
|
+
registry: "https://registry.npmjs.org/"
|
|
16199
|
+
},
|
|
16200
|
+
trustedDependencies: [],
|
|
16201
|
+
sideEffects: false,
|
|
16202
|
+
scripts: {
|
|
16203
|
+
prebuild: "bun run clean",
|
|
16204
|
+
build: "bun run build:js && bun run build:cli && bun run build:types",
|
|
16205
|
+
"build:js": "bun build ./src/index.ts --target=node --format=esm --outfile=dist/index.js --external @opencode-ai/plugin --external @opencode-ai/sdk --external zod --external @opentelemetry/api --external @opentelemetry/sdk-trace-base --external @opentelemetry/exporter-trace-otlp-http --external @opentelemetry/resources --external @langchain/langgraph",
|
|
16206
|
+
"build:cli": 'bun build ./src/cli.ts --target=node --format=esm --outfile=dist/cli.js --banner "#!/usr/bin/env node" --external @opencode-ai/plugin --external @opencode-ai/sdk --external zod --external @clack/prompts --external @opentelemetry/api --external @opentelemetry/sdk-trace-base --external @opentelemetry/exporter-trace-otlp-http --external @opentelemetry/resources --external @langchain/langgraph',
|
|
16207
|
+
"build:types": "tsc -p tsconfig.build.json",
|
|
16208
|
+
clean: `node -e "require('node:fs').rmSync('dist', { recursive: true, force: true })"`,
|
|
16209
|
+
test: "bun test",
|
|
16210
|
+
"test:cov": "bun test --coverage",
|
|
16211
|
+
"certify:shadow": "bun run scripts/certify-artifact.ts shadow",
|
|
16212
|
+
"certify:release": "bun run scripts/certify-artifact.ts release",
|
|
16213
|
+
"coverage:check": "node scripts/check-coverage.mjs",
|
|
16214
|
+
typecheck: "tsc --noEmit",
|
|
16215
|
+
lint: "biome check .",
|
|
16216
|
+
"format:check": "biome format .",
|
|
16217
|
+
"docs:install": "cd docs && bun install --frozen-lockfile --ignore-scripts",
|
|
16218
|
+
"docs:dev": "cd docs && bun run docs:dev",
|
|
16219
|
+
"docs:build": "cd docs && bun run docs:build",
|
|
16220
|
+
"docs:preview": "cd docs && bun run docs:preview",
|
|
16221
|
+
prepublishOnly: "bun run build",
|
|
16222
|
+
"link:local": "bun run build && npm link",
|
|
16223
|
+
"hooks:install": "git config core.hooksPath .githooks"
|
|
16224
|
+
},
|
|
16225
|
+
dependencies: {
|
|
16226
|
+
"@clack/prompts": "1.7.0",
|
|
16227
|
+
"@langchain/core": "1.2.9",
|
|
16228
|
+
"@langchain/langgraph": "1.4.12",
|
|
16229
|
+
"@opencode-ai/plugin": "1.18.19",
|
|
16230
|
+
"@opencode-ai/sdk": "1.18.19",
|
|
16231
|
+
"@opentelemetry/api": "1.9.1",
|
|
16232
|
+
"@opentelemetry/exporter-trace-otlp-http": "0.221.0",
|
|
16233
|
+
"@opentelemetry/resources": "2.10.0",
|
|
16234
|
+
"@opentelemetry/sdk-trace-base": "2.10.0",
|
|
16235
|
+
zod: "4.4.3"
|
|
16236
|
+
},
|
|
16237
|
+
devDependencies: {
|
|
16238
|
+
"@biomejs/biome": "2.5.9",
|
|
16239
|
+
"@types/bun": "1.3.14",
|
|
16240
|
+
typescript: "7.0.2"
|
|
16241
|
+
}
|
|
16242
|
+
};
|
|
16243
|
+
|
|
16244
|
+
// src/version.ts
|
|
16245
|
+
var PACKAGE_VERSION = package_default.version;
|
|
16246
|
+
|
|
16247
|
+
// src/index.ts
|
|
16248
|
+
function warnSoakEvidenceRejections(result, warn) {
|
|
16249
|
+
if (result.rejectedLines === 0) {
|
|
16250
|
+
return;
|
|
16251
|
+
}
|
|
16252
|
+
(warn ?? console.warn)(`[openteam] soak evidence reader rejected ${result.rejectedLines} observation line(s); cutover gate evidence may be incomplete.`);
|
|
16253
|
+
for (const rejection of result.rejections) {
|
|
16254
|
+
(warn ?? console.warn)(`[openteam] • ${rejection.file}:${rejection.lineNumber}: ${rejection.detail}`);
|
|
16255
|
+
}
|
|
16256
|
+
}
|
|
16257
|
+
var SHADOW_CERT_PATH = "artifacts/graph-shadow-certificate.json";
|
|
16258
|
+
var RELEASE_CERT_PATH = "artifacts/graph-release-certificate.json";
|
|
16259
|
+
var SOAK_CERT_PATH = "artifacts/graph-soak-certificate.json";
|
|
16260
|
+
async function readAndParseCertificate(storage, path4, parse2, digestExtractor) {
|
|
16261
|
+
try {
|
|
16262
|
+
const content = await storage.read(path4);
|
|
16263
|
+
if (content === undefined) {
|
|
16264
|
+
return { status: "absent" };
|
|
16265
|
+
}
|
|
16266
|
+
const raw = JSON.parse(content);
|
|
16267
|
+
const cert = parse2(raw);
|
|
16268
|
+
return { status: "valid", digest: digestExtractor(cert) };
|
|
16269
|
+
} catch (error) {
|
|
16270
|
+
if (isMissingFile(error)) {
|
|
16271
|
+
return { status: "absent" };
|
|
16272
|
+
}
|
|
16273
|
+
if (error instanceof ShadowCertificateError || error instanceof ReleaseCertificateError || error instanceof SoakCertificateError) {
|
|
16274
|
+
return { status: "invalid", code: error.code, detail: error.detail };
|
|
16275
|
+
}
|
|
16276
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
16277
|
+
return { status: "invalid", code: "read-error", detail: msg };
|
|
16278
|
+
}
|
|
16279
|
+
}
|
|
16280
|
+
async function buildGateInput(config, storage, opencodeVersion, warn) {
|
|
16281
|
+
const shadow = await readAndParseCertificate(storage, SHADOW_CERT_PATH, (raw) => parseShadowCertificate(raw, opencodeVersion), (cert) => shadowCertificateBindingDigest(cert.evidence));
|
|
16282
|
+
const shadowDigest = shadow.status === "valid" ? shadow.digest : "0".repeat(64);
|
|
16283
|
+
const release = await readAndParseCertificate(storage, RELEASE_CERT_PATH, (raw) => parseReleaseCertificate(raw, opencodeVersion, shadowDigest), (cert) => cert.digest);
|
|
16284
|
+
let soakLedgerDigest = "0".repeat(64);
|
|
16285
|
+
try {
|
|
16286
|
+
const recorderPorts = recorderPortsFromStorage(storage);
|
|
16287
|
+
const chainRead = await readAllChains(recorderPorts, SOAK_EVIDENCE_DIR);
|
|
16288
|
+
warnSoakEvidenceRejections(chainRead, warn);
|
|
16289
|
+
if (chainRead.chains.length > 0) {
|
|
16290
|
+
soakLedgerDigest = canonicalLedger(chainRead.chains);
|
|
16291
|
+
}
|
|
16292
|
+
} catch {}
|
|
16293
|
+
const soak = await readAndParseCertificate(storage, SOAK_CERT_PATH, (raw) => parseSoakCertificate(raw, DEFAULT_SOAK_POLICY, soakLedgerDigest), (cert) => cert.digest);
|
|
16294
|
+
const migration = "complete";
|
|
16295
|
+
const operatorApproval = config.graph?.operatorApproval ?? false;
|
|
16296
|
+
return { shadow, release, soak, migration, operatorApproval };
|
|
16297
|
+
}
|
|
16298
|
+
var OPENCODE_VERSION_UNRESOLVED_REASON = "the opencode version is not determinable outside a running opencode session, " + "so the cutover gate cannot be verified here — the running plugin logs the " + "authoritative gate result and warns loudly on a real denial";
|
|
16299
|
+
async function evaluateCutoverGateForBoundary(config, storage, version) {
|
|
16300
|
+
if (version === undefined) {
|
|
16301
|
+
return { kind: "unevaluable", reason: OPENCODE_VERSION_UNRESOLVED_REASON };
|
|
16302
|
+
}
|
|
16303
|
+
const gateInput = await buildGateInput(config, storage, version, () => {});
|
|
16304
|
+
return { kind: "evaluated", gate: evaluateGraphGate(gateInput) };
|
|
16305
|
+
}
|
|
16306
|
+
function recorderPortsFromStorage(storage) {
|
|
16307
|
+
return {
|
|
16308
|
+
fs: {
|
|
16309
|
+
readFile: async (path4) => {
|
|
16310
|
+
const content = await storage.read(path4);
|
|
16311
|
+
if (content === undefined) {
|
|
16312
|
+
throw Object.assign(new Error(`ENOENT: ${path4}`), { code: "ENOENT" });
|
|
16313
|
+
}
|
|
16314
|
+
return content;
|
|
16315
|
+
},
|
|
16316
|
+
writeFile: (path4, content) => storage.write(path4, content),
|
|
16317
|
+
exists: (path4) => storage.exists(path4),
|
|
16318
|
+
readDir: (path4) => storage.list(path4),
|
|
16319
|
+
mkdir: (path4) => storage.mkdir(path4)
|
|
16320
|
+
},
|
|
16321
|
+
clock: { now: () => new Date().toISOString() },
|
|
16322
|
+
id: { randomUUID: () => crypto.randomUUID() }
|
|
16323
|
+
};
|
|
16324
|
+
}
|
|
16325
|
+
function isMissingFile(error) {
|
|
16326
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
16327
|
+
}
|
|
16328
|
+
|
|
16329
|
+
// src/memory/traverse.ts
|
|
16330
|
+
function inOwnerScope(record, ownerKey, includeShared) {
|
|
16331
|
+
if (record.ownerKey === ownerKey) {
|
|
16332
|
+
return true;
|
|
16333
|
+
}
|
|
16334
|
+
return includeShared && record.ownerKey === SHARED_OWNER_KEY;
|
|
16335
|
+
}
|
|
16336
|
+
function traverseRelations(records, query) {
|
|
16337
|
+
const includeShared = query.includeShared ?? true;
|
|
16338
|
+
const adjacency = new Map;
|
|
16339
|
+
for (const record of records) {
|
|
16340
|
+
if (record.kind !== "relation") {
|
|
16341
|
+
continue;
|
|
16342
|
+
}
|
|
16343
|
+
if (!isActiveAt(record, query.asOf)) {
|
|
16344
|
+
continue;
|
|
16345
|
+
}
|
|
16346
|
+
if (!inOwnerScope(record, query.ownerKey, includeShared)) {
|
|
16347
|
+
continue;
|
|
16348
|
+
}
|
|
16349
|
+
const list = adjacency.get(record.from);
|
|
16350
|
+
if (list === undefined) {
|
|
16351
|
+
adjacency.set(record.from, [record]);
|
|
16352
|
+
} else {
|
|
16353
|
+
list.push(record);
|
|
16354
|
+
}
|
|
16355
|
+
}
|
|
16356
|
+
const visited = new Set([query.seed]);
|
|
16357
|
+
const nodes = [{ id: query.seed, depth: 0 }];
|
|
16358
|
+
const edges = [];
|
|
16359
|
+
let frontier = [query.seed];
|
|
16360
|
+
for (let depth = 0;depth < query.maxDepth; depth += 1) {
|
|
16361
|
+
const nextFrontier = [];
|
|
16362
|
+
for (const nodeId of frontier) {
|
|
16363
|
+
const outgoing = adjacency.get(nodeId) ?? [];
|
|
16364
|
+
for (const edge of outgoing) {
|
|
16365
|
+
if (visited.has(edge.to)) {
|
|
16366
|
+
continue;
|
|
16367
|
+
}
|
|
16368
|
+
visited.add(edge.to);
|
|
16369
|
+
const childDepth = depth + 1;
|
|
16370
|
+
nodes.push({ id: edge.to, depth: childDepth });
|
|
16371
|
+
edges.push({
|
|
16372
|
+
from: edge.from,
|
|
16373
|
+
to: edge.to,
|
|
16374
|
+
predicate: edge.predicate,
|
|
16375
|
+
depth: childDepth
|
|
16376
|
+
});
|
|
16377
|
+
nextFrontier.push(edge.to);
|
|
16378
|
+
}
|
|
16379
|
+
}
|
|
16380
|
+
frontier = nextFrontier;
|
|
16381
|
+
}
|
|
16382
|
+
return { seed: query.seed, nodes, edges };
|
|
16383
|
+
}
|
|
16384
|
+
function seedNodeId(record) {
|
|
16385
|
+
return record.kind === "entity" ? record.canonicalName : undefined;
|
|
16386
|
+
}
|
|
16387
|
+
function recallGraph(records, queryEmbedding, query, options, deps) {
|
|
16388
|
+
const seeds = recall(records, queryEmbedding, query, deps);
|
|
16389
|
+
const asOf = query.asOf ?? deps.now;
|
|
16390
|
+
const includeShared = options.includeShared ?? query.includeShared;
|
|
16391
|
+
const traversals = [];
|
|
16392
|
+
for (const result of seeds) {
|
|
16393
|
+
const seed = seedNodeId(result.record);
|
|
16394
|
+
if (seed === undefined) {
|
|
16395
|
+
continue;
|
|
16396
|
+
}
|
|
16397
|
+
traversals.push({
|
|
16398
|
+
seedRecordId: result.record.id,
|
|
16399
|
+
traversal: traverseRelations(records, {
|
|
16400
|
+
seed,
|
|
16401
|
+
ownerKey: query.ownerKey,
|
|
16402
|
+
asOf,
|
|
16403
|
+
maxDepth: options.maxDepth,
|
|
16404
|
+
includeShared
|
|
16405
|
+
})
|
|
16406
|
+
});
|
|
16407
|
+
}
|
|
16408
|
+
return { recall: seeds, traversals };
|
|
16409
|
+
}
|
|
16410
|
+
|
|
16411
|
+
// src/mcp/semanticRecall.ts
|
|
16412
|
+
function buildSemanticRecall(deps, policy) {
|
|
16413
|
+
return async ({ queryText, kinds, limit }) => {
|
|
16414
|
+
const query = RecallQuerySchema.parse({
|
|
16415
|
+
ownerKey: policy.ownerKey,
|
|
16416
|
+
kinds,
|
|
16417
|
+
asOf: policy.asOf ?? null,
|
|
16418
|
+
limit,
|
|
16419
|
+
minSimilarity: policy.minSimilarity,
|
|
16420
|
+
includeShared: policy.includeShared
|
|
16421
|
+
});
|
|
16422
|
+
const recallDeps = deps.signals === undefined ? { index: deps.index, embedder: deps.embedder, now: deps.now() } : {
|
|
16423
|
+
index: deps.index,
|
|
16424
|
+
embedder: deps.embedder,
|
|
16425
|
+
now: deps.now(),
|
|
16426
|
+
signals: deps.signals
|
|
16427
|
+
};
|
|
16428
|
+
return recallMemory(recallDeps, queryText, query);
|
|
16429
|
+
};
|
|
16430
|
+
}
|
|
16431
|
+
var DEFAULT_TRAVERSAL_DEPTH = 3;
|
|
16432
|
+
function buildRelationTraversal(deps, policy) {
|
|
16433
|
+
return async ({ seed, maxDepth }) => {
|
|
16434
|
+
const asOf = policy.asOf ?? deps.now();
|
|
16435
|
+
return traverseRelations(deps.index.allRecords(), {
|
|
16436
|
+
seed,
|
|
16437
|
+
ownerKey: policy.ownerKey,
|
|
16438
|
+
asOf,
|
|
16439
|
+
maxDepth: maxDepth ?? DEFAULT_TRAVERSAL_DEPTH,
|
|
16440
|
+
includeShared: policy.includeShared
|
|
16441
|
+
});
|
|
16442
|
+
};
|
|
16443
|
+
}
|
|
16444
|
+
function buildGraphRecall(deps, policy) {
|
|
16445
|
+
return async ({ queryText, limit, maxDepth }) => {
|
|
16446
|
+
const query = RecallQuerySchema.parse({
|
|
16447
|
+
ownerKey: policy.ownerKey,
|
|
16448
|
+
kinds: ["fact", "preference", "entity"],
|
|
15117
16449
|
asOf: policy.asOf ?? null,
|
|
15118
16450
|
limit,
|
|
15119
16451
|
minSimilarity: policy.minSimilarity,
|
|
@@ -15368,584 +16700,223 @@ function projectRecall(results) {
|
|
|
15368
16700
|
return {
|
|
15369
16701
|
...base,
|
|
15370
16702
|
category: record.category,
|
|
15371
|
-
preference: record.preference
|
|
15372
|
-
};
|
|
15373
|
-
}
|
|
15374
|
-
const entity = record;
|
|
15375
|
-
return { ...base, canonicalName: entity.canonicalName, type: entity.type };
|
|
15376
|
-
});
|
|
15377
|
-
}
|
|
15378
|
-
function projectGraphRecall(graph) {
|
|
15379
|
-
return {
|
|
15380
|
-
recall: projectRecall(graph.recall),
|
|
15381
|
-
traversals: graph.traversals.map((entry) => ({
|
|
15382
|
-
seedRecordId: entry.seedRecordId,
|
|
15383
|
-
traversal: projectRelationGraph(entry.traversal)
|
|
15384
|
-
}))
|
|
15385
|
-
};
|
|
15386
|
-
}
|
|
15387
|
-
async function callSemanticRecall(recall2, kinds, args) {
|
|
15388
|
-
const query = optionalString(args.query);
|
|
15389
|
-
if (query === undefined) {
|
|
15390
|
-
return textContent({ error: "requiere 'query'" });
|
|
15391
|
-
}
|
|
15392
|
-
const limit = optionalLimit(args.limit) ?? DEFAULT_RECALL_LIMIT;
|
|
15393
|
-
const results = await recall2({ queryText: query, kinds, limit });
|
|
15394
|
-
return textContent(projectRecall(results));
|
|
15395
|
-
}
|
|
15396
|
-
async function callRelationTraversal(traverse, args) {
|
|
15397
|
-
const entity = optionalString(args.entity);
|
|
15398
|
-
if (entity === undefined) {
|
|
15399
|
-
return textContent({ error: "requiere 'entity'" });
|
|
15400
|
-
}
|
|
15401
|
-
const depth = optionalLimit(args.depth) ?? DEFAULT_TRAVERSAL_DEPTH2;
|
|
15402
|
-
const graph = await traverse({ seed: entity, maxDepth: depth });
|
|
15403
|
-
return textContent(projectRelationGraph(graph));
|
|
15404
|
-
}
|
|
15405
|
-
async function callGraphRecall(recall2, args) {
|
|
15406
|
-
const query = optionalString(args.query);
|
|
15407
|
-
if (query === undefined) {
|
|
15408
|
-
return textContent({ error: "requiere 'query'" });
|
|
15409
|
-
}
|
|
15410
|
-
const limit = optionalLimit(args.limit) ?? DEFAULT_RECALL_LIMIT;
|
|
15411
|
-
const depth = optionalLimit(args.depth) ?? DEFAULT_TRAVERSAL_DEPTH2;
|
|
15412
|
-
const graph = await recall2({ queryText: query, limit, maxDepth: depth });
|
|
15413
|
-
return textContent(projectGraphRecall(graph));
|
|
15414
|
-
}
|
|
15415
|
-
async function callTool(name, args, deps) {
|
|
15416
|
-
if (deps.recallSemantic !== undefined) {
|
|
15417
|
-
switch (name) {
|
|
15418
|
-
case "recall_facts":
|
|
15419
|
-
return callSemanticRecall(deps.recallSemantic, ["fact"], args);
|
|
15420
|
-
case "recall_preferences":
|
|
15421
|
-
return callSemanticRecall(deps.recallSemantic, ["preference"], args);
|
|
15422
|
-
case "similar_tasks":
|
|
15423
|
-
return callSemanticRecall(deps.recallSemantic, ["fact", "preference", "entity"], args);
|
|
15424
|
-
default:
|
|
15425
|
-
break;
|
|
15426
|
-
}
|
|
15427
|
-
}
|
|
15428
|
-
if (deps.recallRelations !== undefined && name === "recall_relations") {
|
|
15429
|
-
return callRelationTraversal(deps.recallRelations, args);
|
|
15430
|
-
}
|
|
15431
|
-
if (deps.recallGraph !== undefined && name === "recall_graph") {
|
|
15432
|
-
return callGraphRecall(deps.recallGraph, args);
|
|
15433
|
-
}
|
|
15434
|
-
const memory = await deps.readMemory();
|
|
15435
|
-
switch (name) {
|
|
15436
|
-
case "list_decisions": {
|
|
15437
|
-
const query = {};
|
|
15438
|
-
const agent = optionalString(args.agent);
|
|
15439
|
-
const tag = optionalString(args.tag);
|
|
15440
|
-
const limit = optionalLimit(args.limit);
|
|
15441
|
-
if (agent !== undefined) {
|
|
15442
|
-
query.agent = agent;
|
|
15443
|
-
}
|
|
15444
|
-
if (tag !== undefined) {
|
|
15445
|
-
query.tag = tag;
|
|
15446
|
-
}
|
|
15447
|
-
if (limit !== undefined) {
|
|
15448
|
-
query.limit = limit;
|
|
15449
|
-
}
|
|
15450
|
-
return textContent(queryDecisions(memory, query));
|
|
15451
|
-
}
|
|
15452
|
-
case "list_meetings":
|
|
15453
|
-
return textContent(queryMeetings(memory, { limit: optionalLimit(args.limit) ?? 0 }));
|
|
15454
|
-
case "list_sessions":
|
|
15455
|
-
return textContent(querySessions(memory, { limit: optionalLimit(args.limit) ?? 0 }));
|
|
15456
|
-
case "cost_summary":
|
|
15457
|
-
return textContent(costSummary(memory));
|
|
15458
|
-
default:
|
|
15459
|
-
return;
|
|
15460
|
-
}
|
|
15461
|
-
}
|
|
15462
|
-
async function handleMcpMessage(message, deps) {
|
|
15463
|
-
const isNotification = message.id === undefined;
|
|
15464
|
-
const id = message.id ?? null;
|
|
15465
|
-
const serverInfo = deps.serverInfo ?? DEFAULT_SERVER_INFO;
|
|
15466
|
-
switch (message.method) {
|
|
15467
|
-
case "initialize":
|
|
15468
|
-
return response(id, {
|
|
15469
|
-
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
15470
|
-
capabilities: { tools: {} },
|
|
15471
|
-
serverInfo
|
|
15472
|
-
});
|
|
15473
|
-
case "tools/list":
|
|
15474
|
-
return response(id, { tools: availableTools(deps) });
|
|
15475
|
-
case "tools/call": {
|
|
15476
|
-
const params = message.params ?? {};
|
|
15477
|
-
const name = optionalString(params.name);
|
|
15478
|
-
if (name === undefined) {
|
|
15479
|
-
return errorResponse(id, -32602, "tools/call requiere 'name'");
|
|
15480
|
-
}
|
|
15481
|
-
const args = typeof params.arguments === "object" && params.arguments !== null ? params.arguments : {};
|
|
15482
|
-
const result = await callTool(name, args, deps);
|
|
15483
|
-
if (result === undefined) {
|
|
15484
|
-
return errorResponse(id, -32602, `unknown tool: ${name}`);
|
|
15485
|
-
}
|
|
15486
|
-
return response(id, result);
|
|
15487
|
-
}
|
|
15488
|
-
default:
|
|
15489
|
-
if (isNotification) {
|
|
15490
|
-
return null;
|
|
15491
|
-
}
|
|
15492
|
-
return errorResponse(id, -32601, `unsupported method: ${message.method}`);
|
|
15493
|
-
}
|
|
15494
|
-
}
|
|
15495
|
-
|
|
15496
|
-
// src/mcp/stdio.ts
|
|
15497
|
-
function parseErrorResponse() {
|
|
15498
|
-
return JSON.stringify({
|
|
15499
|
-
jsonrpc: "2.0",
|
|
15500
|
-
id: null,
|
|
15501
|
-
error: { code: -32700, message: "Invalid JSON" }
|
|
15502
|
-
});
|
|
15503
|
-
}
|
|
15504
|
-
async function runMcpStdio(deps, io) {
|
|
15505
|
-
for await (const rawLine of io.lines) {
|
|
15506
|
-
const line = rawLine.trim();
|
|
15507
|
-
if (line.length === 0) {
|
|
15508
|
-
continue;
|
|
15509
|
-
}
|
|
15510
|
-
let message;
|
|
15511
|
-
try {
|
|
15512
|
-
message = JSON.parse(line);
|
|
15513
|
-
} catch {
|
|
15514
|
-
io.write(`${parseErrorResponse()}
|
|
15515
|
-
`);
|
|
15516
|
-
continue;
|
|
15517
|
-
}
|
|
15518
|
-
const reply = await handleMcpMessage(message, deps);
|
|
15519
|
-
if (reply !== null) {
|
|
15520
|
-
io.write(`${JSON.stringify(reply)}
|
|
15521
|
-
`);
|
|
15522
|
-
}
|
|
15523
|
-
}
|
|
15524
|
-
}
|
|
15525
|
-
async function* linesFromReadable(readable) {
|
|
15526
|
-
let buffer = "";
|
|
15527
|
-
for await (const chunk of readable) {
|
|
15528
|
-
buffer += typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
15529
|
-
let newlineIndex = buffer.indexOf(`
|
|
15530
|
-
`);
|
|
15531
|
-
while (newlineIndex >= 0) {
|
|
15532
|
-
yield buffer.slice(0, newlineIndex);
|
|
15533
|
-
buffer = buffer.slice(newlineIndex + 1);
|
|
15534
|
-
newlineIndex = buffer.indexOf(`
|
|
15535
|
-
`);
|
|
15536
|
-
}
|
|
15537
|
-
}
|
|
15538
|
-
if (buffer.length > 0) {
|
|
15539
|
-
yield buffer;
|
|
15540
|
-
}
|
|
15541
|
-
}
|
|
15542
|
-
|
|
15543
|
-
// src/orchestrator/rosterPersistence.ts
|
|
15544
|
-
function rosterFence(roster) {
|
|
15545
|
-
const data = { universe: roster.universe, entries: roster.entries };
|
|
15546
|
-
return `\`\`\`json
|
|
15547
|
-
${JSON.stringify(data, null, 2)}
|
|
15548
|
-
\`\`\``;
|
|
15549
|
-
}
|
|
15550
|
-
function serializeRoster(roster) {
|
|
15551
|
-
return `# openteam roster
|
|
15552
|
-
|
|
15553
|
-
Universe: ${roster.universe}
|
|
15554
|
-
|
|
15555
|
-
${rosterFence(roster)}
|
|
15556
|
-
`;
|
|
15557
|
-
}
|
|
15558
|
-
async function persistRoster(storage, roster, path4 = OPENTEAM_ROSTER_PATH) {
|
|
15559
|
-
await storage.write(path4, serializeRoster(roster));
|
|
15560
|
-
return path4;
|
|
15561
|
-
}
|
|
15562
|
-
async function loadRosterFile(storage, path4 = OPENTEAM_ROSTER_PATH) {
|
|
15563
|
-
const content = await storage.read(path4);
|
|
15564
|
-
if (content === undefined) {
|
|
15565
|
-
return { status: "absent", path: path4 };
|
|
15566
|
-
}
|
|
15567
|
-
const parsed = parseRosterResult(content);
|
|
15568
|
-
if (!parsed.ok) {
|
|
15569
|
-
return { status: "invalid", path: path4, error: parsed.error };
|
|
15570
|
-
}
|
|
15571
|
-
return {
|
|
15572
|
-
status: "loaded",
|
|
15573
|
-
path: path4,
|
|
15574
|
-
roster: enforceGuaranteedRoles(parsed.roster)
|
|
15575
|
-
};
|
|
15576
|
-
}
|
|
15577
|
-
async function loadOrGenerateRoster(storage, generate, path4 = OPENTEAM_ROSTER_PATH) {
|
|
15578
|
-
const existing = await loadRosterFile(storage, path4);
|
|
15579
|
-
if (existing.status === "loaded") {
|
|
15580
|
-
return { roster: existing.roster, regenerated: false };
|
|
15581
|
-
}
|
|
15582
|
-
const roster = enforceGuaranteedRoles(await generate());
|
|
15583
|
-
if (existing.status === "absent") {
|
|
15584
|
-
await persistRoster(storage, roster, path4);
|
|
15585
|
-
return { roster, regenerated: true };
|
|
15586
|
-
}
|
|
15587
|
-
return {
|
|
15588
|
-
roster,
|
|
15589
|
-
regenerated: true,
|
|
15590
|
-
recoveredFromInvalidPersisted: true,
|
|
15591
|
-
invalidPersistedRosterError: existing.error.message
|
|
15592
|
-
};
|
|
16703
|
+
preference: record.preference
|
|
16704
|
+
};
|
|
16705
|
+
}
|
|
16706
|
+
const entity = record;
|
|
16707
|
+
return { ...base, canonicalName: entity.canonicalName, type: entity.type };
|
|
16708
|
+
});
|
|
15593
16709
|
}
|
|
15594
|
-
|
|
15595
|
-
// src/plugin/orchestrateTool.ts
|
|
15596
|
-
import { tool } from "@opencode-ai/plugin";
|
|
15597
|
-
import { z as z20 } from "zod";
|
|
15598
|
-
var _pluginWarnedRoles = new Set;
|
|
15599
|
-
var RoleAssignmentSchema = z20.object({
|
|
15600
|
-
roleID: z20.string().min(1).describe("Role identifier from the roster"),
|
|
15601
|
-
prompt: z20.string().min(1).describe("Work prompt for this role"),
|
|
15602
|
-
title: z20.string().min(1).optional().describe("Human-readable title"),
|
|
15603
|
-
dependsOn: z20.array(z20.string().min(1)).optional().describe("Role IDs this assignment depends on (DAG edges)")
|
|
15604
|
-
}).strict();
|
|
15605
|
-
var OrchestratePayloadSchema = z20.object({
|
|
15606
|
-
assignments: z20.array(RoleAssignmentSchema).min(1).describe("Role assignments to distribute"),
|
|
15607
|
-
parentSessionID: z20.string().min(1).optional().describe("Parent session for subsessions"),
|
|
15608
|
-
directory: z20.string().min(1).optional().describe("Working directory override")
|
|
15609
|
-
}).strict();
|
|
15610
|
-
function adaptSdkClient(sdk) {
|
|
16710
|
+
function projectGraphRecall(graph) {
|
|
15611
16711
|
return {
|
|
15612
|
-
|
|
15613
|
-
|
|
15614
|
-
|
|
15615
|
-
|
|
15616
|
-
|
|
15617
|
-
out.data = result.data;
|
|
15618
|
-
}
|
|
15619
|
-
if (result.error !== undefined) {
|
|
15620
|
-
out.error = result.error;
|
|
15621
|
-
}
|
|
15622
|
-
return out;
|
|
15623
|
-
},
|
|
15624
|
-
prompt: async (args) => {
|
|
15625
|
-
const result = await sdk.session.prompt(args);
|
|
15626
|
-
const out = {};
|
|
15627
|
-
if (result.data !== undefined) {
|
|
15628
|
-
out.data = result.data;
|
|
15629
|
-
}
|
|
15630
|
-
if (result.error !== undefined) {
|
|
15631
|
-
out.error = result.error;
|
|
15632
|
-
}
|
|
15633
|
-
return out;
|
|
15634
|
-
}
|
|
15635
|
-
}
|
|
16712
|
+
recall: projectRecall(graph.recall),
|
|
16713
|
+
traversals: graph.traversals.map((entry) => ({
|
|
16714
|
+
seedRecordId: entry.seedRecordId,
|
|
16715
|
+
traversal: projectRelationGraph(entry.traversal)
|
|
16716
|
+
}))
|
|
15636
16717
|
};
|
|
15637
16718
|
}
|
|
15638
|
-
|
|
15639
|
-
|
|
15640
|
-
|
|
15641
|
-
|
|
15642
|
-
halfLifeMs: 90 * DAY_MS2,
|
|
15643
|
-
forgetThreshold: 0.05
|
|
15644
|
-
};
|
|
15645
|
-
function lastReinforcedAt(record) {
|
|
15646
|
-
if (record.kind === "preference" && record.lastAccessedAt !== null) {
|
|
15647
|
-
return record.lastAccessedAt;
|
|
16719
|
+
async function callSemanticRecall(recall2, kinds, args) {
|
|
16720
|
+
const query = optionalString(args.query);
|
|
16721
|
+
if (query === undefined) {
|
|
16722
|
+
return textContent({ error: "requiere 'query'" });
|
|
15648
16723
|
}
|
|
15649
|
-
|
|
15650
|
-
}
|
|
15651
|
-
|
|
15652
|
-
const ageMs = Math.max(0, now - lastReinforcedAt(record));
|
|
15653
|
-
return record.confidence * 0.5 ** (ageMs / params.halfLifeMs);
|
|
16724
|
+
const limit = optionalLimit(args.limit) ?? DEFAULT_RECALL_LIMIT;
|
|
16725
|
+
const results = await recall2({ queryText: query, kinds, limit });
|
|
16726
|
+
return textContent(projectRecall(results));
|
|
15654
16727
|
}
|
|
15655
|
-
function
|
|
15656
|
-
const
|
|
15657
|
-
|
|
15658
|
-
|
|
15659
|
-
continue;
|
|
15660
|
-
}
|
|
15661
|
-
if (decayedConfidence(record, now, params) < params.forgetThreshold) {
|
|
15662
|
-
tombstones.push({ ...record, invalidatedAt: now, supersededBy: null });
|
|
15663
|
-
}
|
|
16728
|
+
async function callRelationTraversal(traverse, args) {
|
|
16729
|
+
const entity = optionalString(args.entity);
|
|
16730
|
+
if (entity === undefined) {
|
|
16731
|
+
return textContent({ error: "requiere 'entity'" });
|
|
15664
16732
|
}
|
|
15665
|
-
|
|
16733
|
+
const depth = optionalLimit(args.depth) ?? DEFAULT_TRAVERSAL_DEPTH2;
|
|
16734
|
+
const graph = await traverse({ seed: entity, maxDepth: depth });
|
|
16735
|
+
return textContent(projectRelationGraph(graph));
|
|
15666
16736
|
}
|
|
15667
|
-
|
|
15668
|
-
|
|
15669
|
-
|
|
15670
|
-
|
|
15671
|
-
const text2 = await deps.storage.read(logPath) ?? "";
|
|
15672
|
-
const { records, rejectedLines } = parseMemoryLog(text2);
|
|
15673
|
-
const state = foldAssertions(records);
|
|
15674
|
-
const tombstones = consolidate(allRecords(state), deps.now, params);
|
|
15675
|
-
if (tombstones.length === 0) {
|
|
15676
|
-
return { forgotten: 0, rejectedLines };
|
|
16737
|
+
async function callGraphRecall(recall2, args) {
|
|
16738
|
+
const query = optionalString(args.query);
|
|
16739
|
+
if (query === undefined) {
|
|
16740
|
+
return textContent({ error: "requiere 'query'" });
|
|
15677
16741
|
}
|
|
15678
|
-
const
|
|
15679
|
-
|
|
15680
|
-
|
|
15681
|
-
|
|
15682
|
-
return { forgotten: tombstones.length, rejectedLines };
|
|
16742
|
+
const limit = optionalLimit(args.limit) ?? DEFAULT_RECALL_LIMIT;
|
|
16743
|
+
const depth = optionalLimit(args.depth) ?? DEFAULT_TRAVERSAL_DEPTH2;
|
|
16744
|
+
const graph = await recall2({ queryText: query, limit, maxDepth: depth });
|
|
16745
|
+
return textContent(projectGraphRecall(graph));
|
|
15683
16746
|
}
|
|
15684
|
-
|
|
15685
|
-
|
|
15686
|
-
|
|
15687
|
-
|
|
15688
|
-
|
|
15689
|
-
|
|
15690
|
-
|
|
15691
|
-
|
|
15692
|
-
|
|
15693
|
-
|
|
15694
|
-
|
|
16747
|
+
async function callTool(name, args, deps) {
|
|
16748
|
+
if (deps.recallSemantic !== undefined) {
|
|
16749
|
+
switch (name) {
|
|
16750
|
+
case "recall_facts":
|
|
16751
|
+
return callSemanticRecall(deps.recallSemantic, ["fact"], args);
|
|
16752
|
+
case "recall_preferences":
|
|
16753
|
+
return callSemanticRecall(deps.recallSemantic, ["preference"], args);
|
|
16754
|
+
case "similar_tasks":
|
|
16755
|
+
return callSemanticRecall(deps.recallSemantic, ["fact", "preference", "entity"], args);
|
|
16756
|
+
default:
|
|
16757
|
+
break;
|
|
15695
16758
|
}
|
|
15696
|
-
return embedding;
|
|
15697
|
-
});
|
|
15698
|
-
}
|
|
15699
|
-
async function embedTexts(request, deps) {
|
|
15700
|
-
if (request.texts.length === 0) {
|
|
15701
|
-
return [];
|
|
15702
|
-
}
|
|
15703
|
-
let response2;
|
|
15704
|
-
try {
|
|
15705
|
-
response2 = await deps.fetch(embeddingsEndpoint(request.baseURL), {
|
|
15706
|
-
method: "POST",
|
|
15707
|
-
headers: {
|
|
15708
|
-
"content-type": "application/json",
|
|
15709
|
-
accept: "application/json"
|
|
15710
|
-
},
|
|
15711
|
-
body: JSON.stringify({
|
|
15712
|
-
model: request.modelID,
|
|
15713
|
-
input: [...request.texts]
|
|
15714
|
-
})
|
|
15715
|
-
});
|
|
15716
|
-
} catch (error) {
|
|
15717
|
-
throw new Error(`Local embeddings failed: ${errorMessage(error)}`);
|
|
15718
|
-
}
|
|
15719
|
-
if (!response2.ok) {
|
|
15720
|
-
throw new Error(`Local embeddings failed: HTTP ${response2.status} on /embeddings`);
|
|
15721
|
-
}
|
|
15722
|
-
let payload;
|
|
15723
|
-
try {
|
|
15724
|
-
payload = await response2.json();
|
|
15725
|
-
} catch (error) {
|
|
15726
|
-
throw new Error(`Local embeddings failed: ${errorMessage(error)}`);
|
|
15727
|
-
}
|
|
15728
|
-
const vectors = parseEmbeddingsResponse(payload);
|
|
15729
|
-
if (vectors.length !== request.texts.length) {
|
|
15730
|
-
throw new Error(`Local embeddings returned ${vectors.length} vectors for ${request.texts.length} texts`);
|
|
15731
16759
|
}
|
|
15732
|
-
|
|
15733
|
-
|
|
15734
|
-
function createLocalEmbedder(request, deps) {
|
|
15735
|
-
return (texts) => embedTexts({ ...request, texts }, deps);
|
|
15736
|
-
}
|
|
15737
|
-
|
|
15738
|
-
// src/memory/embedText.ts
|
|
15739
|
-
function normalize(parts) {
|
|
15740
|
-
return parts.map((part) => part.trim()).filter((part) => part.length > 0).join(" ");
|
|
15741
|
-
}
|
|
15742
|
-
function recordEmbeddingText(record) {
|
|
15743
|
-
if (record.kind === "fact") {
|
|
15744
|
-
return normalize([
|
|
15745
|
-
record.subject,
|
|
15746
|
-
record.predicate,
|
|
15747
|
-
record.object,
|
|
15748
|
-
record.category ?? ""
|
|
15749
|
-
]);
|
|
16760
|
+
if (deps.recallRelations !== undefined && name === "recall_relations") {
|
|
16761
|
+
return callRelationTraversal(deps.recallRelations, args);
|
|
15750
16762
|
}
|
|
15751
|
-
if (
|
|
15752
|
-
return
|
|
15753
|
-
record.category,
|
|
15754
|
-
record.preference,
|
|
15755
|
-
record.context ?? ""
|
|
15756
|
-
]);
|
|
16763
|
+
if (deps.recallGraph !== undefined && name === "recall_graph") {
|
|
16764
|
+
return callGraphRecall(deps.recallGraph, args);
|
|
15757
16765
|
}
|
|
15758
|
-
|
|
15759
|
-
|
|
15760
|
-
|
|
15761
|
-
|
|
15762
|
-
|
|
15763
|
-
|
|
15764
|
-
|
|
16766
|
+
const memory = await deps.readMemory();
|
|
16767
|
+
switch (name) {
|
|
16768
|
+
case "list_decisions": {
|
|
16769
|
+
const query = {};
|
|
16770
|
+
const agent = optionalString(args.agent);
|
|
16771
|
+
const tag = optionalString(args.tag);
|
|
16772
|
+
const limit = optionalLimit(args.limit);
|
|
16773
|
+
if (agent !== undefined) {
|
|
16774
|
+
query.agent = agent;
|
|
16775
|
+
}
|
|
16776
|
+
if (tag !== undefined) {
|
|
16777
|
+
query.tag = tag;
|
|
16778
|
+
}
|
|
16779
|
+
if (limit !== undefined) {
|
|
16780
|
+
query.limit = limit;
|
|
16781
|
+
}
|
|
16782
|
+
return textContent(queryDecisions(memory, query));
|
|
16783
|
+
}
|
|
16784
|
+
case "list_meetings":
|
|
16785
|
+
return textContent(queryMeetings(memory, { limit: optionalLimit(args.limit) ?? 0 }));
|
|
16786
|
+
case "list_sessions":
|
|
16787
|
+
return textContent(querySessions(memory, { limit: optionalLimit(args.limit) ?? 0 }));
|
|
16788
|
+
case "cost_summary":
|
|
16789
|
+
return textContent(costSummary(memory));
|
|
16790
|
+
default:
|
|
16791
|
+
return;
|
|
15765
16792
|
}
|
|
15766
|
-
return normalize([record.canonicalName, record.type, ...record.aliases]);
|
|
15767
16793
|
}
|
|
15768
|
-
|
|
15769
|
-
|
|
15770
|
-
|
|
15771
|
-
const
|
|
15772
|
-
|
|
15773
|
-
|
|
15774
|
-
|
|
15775
|
-
|
|
15776
|
-
|
|
16794
|
+
async function handleMcpMessage(message, deps) {
|
|
16795
|
+
const isNotification = message.id === undefined;
|
|
16796
|
+
const id = message.id ?? null;
|
|
16797
|
+
const serverInfo = deps.serverInfo ?? DEFAULT_SERVER_INFO;
|
|
16798
|
+
switch (message.method) {
|
|
16799
|
+
case "initialize":
|
|
16800
|
+
return response(id, {
|
|
16801
|
+
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
16802
|
+
capabilities: { tools: {} },
|
|
16803
|
+
serverInfo
|
|
16804
|
+
});
|
|
16805
|
+
case "tools/list":
|
|
16806
|
+
return response(id, { tools: availableTools(deps) });
|
|
16807
|
+
case "tools/call": {
|
|
16808
|
+
const params = message.params ?? {};
|
|
16809
|
+
const name = optionalString(params.name);
|
|
16810
|
+
if (name === undefined) {
|
|
16811
|
+
return errorResponse(id, -32602, "tools/call requiere 'name'");
|
|
16812
|
+
}
|
|
16813
|
+
const args = typeof params.arguments === "object" && params.arguments !== null ? params.arguments : {};
|
|
16814
|
+
const result = await callTool(name, args, deps);
|
|
16815
|
+
if (result === undefined) {
|
|
16816
|
+
return errorResponse(id, -32602, `unknown tool: ${name}`);
|
|
16817
|
+
}
|
|
16818
|
+
return response(id, result);
|
|
16819
|
+
}
|
|
16820
|
+
default:
|
|
16821
|
+
if (isNotification) {
|
|
16822
|
+
return null;
|
|
16823
|
+
}
|
|
16824
|
+
return errorResponse(id, -32601, `unsupported method: ${message.method}`);
|
|
15777
16825
|
}
|
|
15778
|
-
|
|
15779
|
-
|
|
15780
|
-
|
|
15781
|
-
|
|
15782
|
-
|
|
15783
|
-
|
|
15784
|
-
|
|
16826
|
+
}
|
|
16827
|
+
|
|
16828
|
+
// src/mcp/stdio.ts
|
|
16829
|
+
function parseErrorResponse() {
|
|
16830
|
+
return JSON.stringify({
|
|
16831
|
+
jsonrpc: "2.0",
|
|
16832
|
+
id: null,
|
|
16833
|
+
error: { code: -32700, message: "Invalid JSON" }
|
|
16834
|
+
});
|
|
16835
|
+
}
|
|
16836
|
+
async function runMcpStdio(deps, io) {
|
|
16837
|
+
for await (const rawLine of io.lines) {
|
|
16838
|
+
const line = rawLine.trim();
|
|
16839
|
+
if (line.length === 0) {
|
|
16840
|
+
continue;
|
|
16841
|
+
}
|
|
16842
|
+
let message;
|
|
16843
|
+
try {
|
|
16844
|
+
message = JSON.parse(line);
|
|
16845
|
+
} catch {
|
|
16846
|
+
io.write(`${parseErrorResponse()}
|
|
16847
|
+
`);
|
|
16848
|
+
continue;
|
|
16849
|
+
}
|
|
16850
|
+
const reply = await handleMcpMessage(message, deps);
|
|
16851
|
+
if (reply !== null) {
|
|
16852
|
+
io.write(`${JSON.stringify(reply)}
|
|
16853
|
+
`);
|
|
16854
|
+
}
|
|
15785
16855
|
}
|
|
15786
|
-
|
|
15787
|
-
|
|
15788
|
-
|
|
15789
|
-
|
|
15790
|
-
|
|
15791
|
-
|
|
15792
|
-
|
|
16856
|
+
}
|
|
16857
|
+
async function* linesFromReadable(readable) {
|
|
16858
|
+
let buffer = "";
|
|
16859
|
+
for await (const chunk of readable) {
|
|
16860
|
+
buffer += typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
16861
|
+
let newlineIndex = buffer.indexOf(`
|
|
16862
|
+
`);
|
|
16863
|
+
while (newlineIndex >= 0) {
|
|
16864
|
+
yield buffer.slice(0, newlineIndex);
|
|
16865
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
16866
|
+
newlineIndex = buffer.indexOf(`
|
|
16867
|
+
`);
|
|
16868
|
+
}
|
|
15793
16869
|
}
|
|
15794
|
-
if (
|
|
15795
|
-
|
|
15796
|
-
return { embedded: 0, failed: todo.length, modelChanged };
|
|
16870
|
+
if (buffer.length > 0) {
|
|
16871
|
+
yield buffer;
|
|
15797
16872
|
}
|
|
15798
|
-
const entries = todo.map((record, position) => ({
|
|
15799
|
-
recordId: record.id,
|
|
15800
|
-
vector: vectors[position]
|
|
15801
|
-
}));
|
|
15802
|
-
index.putEmbeddings(entries);
|
|
15803
|
-
return { embedded: entries.length, failed: 0, modelChanged };
|
|
15804
16873
|
}
|
|
15805
16874
|
|
|
15806
|
-
// src/
|
|
15807
|
-
|
|
15808
|
-
|
|
15809
|
-
|
|
15810
|
-
|
|
15811
|
-
|
|
15812
|
-
|
|
15813
|
-
|
|
15814
|
-
|
|
15815
|
-
const runtime = config.local.runtimes.find((rt) => rt.enabled && rt.baseURL !== undefined);
|
|
15816
|
-
if (runtime?.baseURL === undefined) {
|
|
15817
|
-
return;
|
|
16875
|
+
// src/memory/consolidate.ts
|
|
16876
|
+
var DAY_MS2 = 86400000;
|
|
16877
|
+
var DEFAULT_DECAY_PARAMS = {
|
|
16878
|
+
halfLifeMs: 90 * DAY_MS2,
|
|
16879
|
+
forgetThreshold: 0.05
|
|
16880
|
+
};
|
|
16881
|
+
function lastReinforcedAt(record) {
|
|
16882
|
+
if (record.kind === "preference" && record.lastAccessedAt !== null) {
|
|
16883
|
+
return record.lastAccessedAt;
|
|
15818
16884
|
}
|
|
15819
|
-
|
|
15820
|
-
|
|
15821
|
-
|
|
15822
|
-
const
|
|
15823
|
-
|
|
15824
|
-
|
|
15825
|
-
|
|
15826
|
-
|
|
15827
|
-
|
|
15828
|
-
|
|
15829
|
-
|
|
15830
|
-
|
|
16885
|
+
return record.createdAt;
|
|
16886
|
+
}
|
|
16887
|
+
function decayedConfidence(record, now, params = DEFAULT_DECAY_PARAMS) {
|
|
16888
|
+
const ageMs = Math.max(0, now - lastReinforcedAt(record));
|
|
16889
|
+
return record.confidence * 0.5 ** (ageMs / params.halfLifeMs);
|
|
16890
|
+
}
|
|
16891
|
+
function consolidate(records, now, params = DEFAULT_DECAY_PARAMS) {
|
|
16892
|
+
const tombstones = [];
|
|
16893
|
+
for (const record of records) {
|
|
16894
|
+
if (!isTransactionActiveAt(record, now)) {
|
|
16895
|
+
continue;
|
|
16896
|
+
}
|
|
16897
|
+
if (decayedConfidence(record, now, params) < params.forgetThreshold) {
|
|
16898
|
+
tombstones.push({ ...record, invalidatedAt: now, supersededBy: null });
|
|
15831
16899
|
}
|
|
15832
|
-
const embedder = makeEmbedder({ baseURL: runtime.baseURL, modelID }, { fetch: fetchImpl });
|
|
15833
|
-
await ensureMemoryEmbeddings({ index, embedder, model: modelID, warn });
|
|
15834
|
-
return {
|
|
15835
|
-
index,
|
|
15836
|
-
embedder,
|
|
15837
|
-
now,
|
|
15838
|
-
ownerKey: semantic.scope === "user" ? "user" : "project",
|
|
15839
|
-
semantic
|
|
15840
|
-
};
|
|
15841
|
-
} catch {
|
|
15842
|
-
return;
|
|
15843
16900
|
}
|
|
16901
|
+
return tombstones;
|
|
15844
16902
|
}
|
|
15845
|
-
// package.json
|
|
15846
|
-
var package_default = {
|
|
15847
|
-
name: "@jmanuelcorral/openteam",
|
|
15848
|
-
version: "0.16.0",
|
|
15849
|
-
packageManager: "bun@1.3.14",
|
|
15850
|
-
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
15851
|
-
license: "MIT",
|
|
15852
|
-
author: "Jose Manuel Corral",
|
|
15853
|
-
repository: {
|
|
15854
|
-
type: "git",
|
|
15855
|
-
url: "git+https://github.com/jmanuelcorral/openteam.git"
|
|
15856
|
-
},
|
|
15857
|
-
homepage: "https://github.com/jmanuelcorral/openteam#readme",
|
|
15858
|
-
bugs: {
|
|
15859
|
-
url: "https://github.com/jmanuelcorral/openteam/issues"
|
|
15860
|
-
},
|
|
15861
|
-
keywords: [
|
|
15862
|
-
"opencode",
|
|
15863
|
-
"opencode-plugin",
|
|
15864
|
-
"llm",
|
|
15865
|
-
"routing",
|
|
15866
|
-
"local-llm",
|
|
15867
|
-
"ollama",
|
|
15868
|
-
"lm-studio",
|
|
15869
|
-
"foundry-local",
|
|
15870
|
-
"cost-optimization",
|
|
15871
|
-
"multi-agent"
|
|
15872
|
-
],
|
|
15873
|
-
engines: {
|
|
15874
|
-
bun: ">=1.3",
|
|
15875
|
-
node: "^22.22.2 || ^24.15.0 || >=26.0.0"
|
|
15876
|
-
},
|
|
15877
|
-
type: "module",
|
|
15878
|
-
main: "./dist/index.js",
|
|
15879
|
-
module: "./dist/index.js",
|
|
15880
|
-
types: "./dist/index.d.ts",
|
|
15881
|
-
bin: {
|
|
15882
|
-
openteam: "./dist/cli.js"
|
|
15883
|
-
},
|
|
15884
|
-
exports: {
|
|
15885
|
-
".": {
|
|
15886
|
-
types: "./dist/index.d.ts",
|
|
15887
|
-
import: "./dist/index.js"
|
|
15888
|
-
},
|
|
15889
|
-
"./package.json": "./package.json"
|
|
15890
|
-
},
|
|
15891
|
-
files: [
|
|
15892
|
-
"dist",
|
|
15893
|
-
"README.md",
|
|
15894
|
-
"LICENSE",
|
|
15895
|
-
"AGENTS.md",
|
|
15896
|
-
".opencode/openteam.example.json",
|
|
15897
|
-
".opencode/command/openteam.md"
|
|
15898
|
-
],
|
|
15899
|
-
publishConfig: {
|
|
15900
|
-
access: "public",
|
|
15901
|
-
registry: "https://registry.npmjs.org/"
|
|
15902
|
-
},
|
|
15903
|
-
trustedDependencies: [],
|
|
15904
|
-
sideEffects: false,
|
|
15905
|
-
scripts: {
|
|
15906
|
-
prebuild: "bun run clean",
|
|
15907
|
-
build: "bun run build:js && bun run build:cli && bun run build:types",
|
|
15908
|
-
"build:js": "bun build ./src/index.ts --target=node --format=esm --outfile=dist/index.js --external @opencode-ai/plugin --external @opencode-ai/sdk --external zod --external @opentelemetry/api --external @opentelemetry/sdk-trace-base --external @opentelemetry/exporter-trace-otlp-http --external @opentelemetry/resources --external @langchain/langgraph",
|
|
15909
|
-
"build:cli": 'bun build ./src/cli.ts --target=node --format=esm --outfile=dist/cli.js --banner "#!/usr/bin/env node" --external @opencode-ai/plugin --external @opencode-ai/sdk --external zod --external @clack/prompts --external @opentelemetry/api --external @opentelemetry/sdk-trace-base --external @opentelemetry/exporter-trace-otlp-http --external @opentelemetry/resources --external @langchain/langgraph',
|
|
15910
|
-
"build:types": "tsc -p tsconfig.build.json",
|
|
15911
|
-
clean: `node -e "require('node:fs').rmSync('dist', { recursive: true, force: true })"`,
|
|
15912
|
-
test: "bun test",
|
|
15913
|
-
"test:cov": "bun test --coverage",
|
|
15914
|
-
"certify:shadow": "bun run scripts/certify-artifact.ts shadow",
|
|
15915
|
-
"certify:release": "bun run scripts/certify-artifact.ts release",
|
|
15916
|
-
"coverage:check": "node scripts/check-coverage.mjs",
|
|
15917
|
-
typecheck: "tsc --noEmit",
|
|
15918
|
-
lint: "biome check .",
|
|
15919
|
-
"format:check": "biome format .",
|
|
15920
|
-
"docs:install": "cd docs && bun install --frozen-lockfile --ignore-scripts",
|
|
15921
|
-
"docs:dev": "cd docs && bun run docs:dev",
|
|
15922
|
-
"docs:build": "cd docs && bun run docs:build",
|
|
15923
|
-
"docs:preview": "cd docs && bun run docs:preview",
|
|
15924
|
-
prepublishOnly: "bun run build",
|
|
15925
|
-
"link:local": "bun run build && npm link",
|
|
15926
|
-
"hooks:install": "git config core.hooksPath .githooks"
|
|
15927
|
-
},
|
|
15928
|
-
dependencies: {
|
|
15929
|
-
"@clack/prompts": "1.7.0",
|
|
15930
|
-
"@langchain/core": "1.2.9",
|
|
15931
|
-
"@langchain/langgraph": "1.4.12",
|
|
15932
|
-
"@opencode-ai/plugin": "1.18.19",
|
|
15933
|
-
"@opencode-ai/sdk": "1.18.19",
|
|
15934
|
-
"@opentelemetry/api": "1.9.1",
|
|
15935
|
-
"@opentelemetry/exporter-trace-otlp-http": "0.221.0",
|
|
15936
|
-
"@opentelemetry/resources": "2.10.0",
|
|
15937
|
-
"@opentelemetry/sdk-trace-base": "2.10.0",
|
|
15938
|
-
zod: "4.4.3"
|
|
15939
|
-
},
|
|
15940
|
-
devDependencies: {
|
|
15941
|
-
"@biomejs/biome": "2.5.9",
|
|
15942
|
-
"@types/bun": "1.3.14",
|
|
15943
|
-
typescript: "7.0.2"
|
|
15944
|
-
}
|
|
15945
|
-
};
|
|
15946
16903
|
|
|
15947
|
-
// src/
|
|
15948
|
-
|
|
16904
|
+
// src/storage/index/memoryConsolidate.ts
|
|
16905
|
+
async function runConsolidation(logPath, deps) {
|
|
16906
|
+
const params = deps.params ?? DEFAULT_DECAY_PARAMS;
|
|
16907
|
+
const text2 = await deps.storage.read(logPath) ?? "";
|
|
16908
|
+
const { records, rejectedLines } = parseMemoryLog(text2);
|
|
16909
|
+
const state = foldAssertions(records);
|
|
16910
|
+
const tombstones = consolidate(allRecords(state), deps.now, params);
|
|
16911
|
+
if (tombstones.length === 0) {
|
|
16912
|
+
return { forgotten: 0, rejectedLines };
|
|
16913
|
+
}
|
|
16914
|
+
const appended = `${tombstones.map(serializeAssertion).join(`
|
|
16915
|
+
`)}
|
|
16916
|
+
`;
|
|
16917
|
+
await deps.storage.append(logPath, appended);
|
|
16918
|
+
return { forgotten: tombstones.length, rejectedLines };
|
|
16919
|
+
}
|
|
15949
16920
|
|
|
15950
16921
|
// src/web/git.ts
|
|
15951
16922
|
function createGitLastCommit(exec) {
|
|
@@ -15968,6 +16939,7 @@ function createGitLastCommit(exec) {
|
|
|
15968
16939
|
|
|
15969
16940
|
// src/cli.ts
|
|
15970
16941
|
var execFileAsync2 = promisify2(execFile2);
|
|
16942
|
+
var execAsync = promisify2(exec);
|
|
15971
16943
|
var AGENT_DIR2 = dirname5(ORCHESTRATOR_AGENT_PATH);
|
|
15972
16944
|
var storage = createFsStorageProvider(process.cwd());
|
|
15973
16945
|
async function readStoredRosterForDoctor() {
|
|
@@ -15996,6 +16968,22 @@ var nodeExec2 = async (command, args) => {
|
|
|
15996
16968
|
};
|
|
15997
16969
|
}
|
|
15998
16970
|
};
|
|
16971
|
+
var requireFromCli = createRequire2(import.meta.url);
|
|
16972
|
+
function readPackageVersion(packageName) {
|
|
16973
|
+
try {
|
|
16974
|
+
const pkg = requireFromCli(`${packageName}/package.json`);
|
|
16975
|
+
return typeof pkg.version === "string" ? pkg.version : undefined;
|
|
16976
|
+
} catch {
|
|
16977
|
+
return;
|
|
16978
|
+
}
|
|
16979
|
+
}
|
|
16980
|
+
async function runOpencodeVersionCommand() {
|
|
16981
|
+
const { stdout } = await execAsync("opencode --version", {
|
|
16982
|
+
timeout: 4000,
|
|
16983
|
+
windowsHide: true
|
|
16984
|
+
});
|
|
16985
|
+
return stdout;
|
|
16986
|
+
}
|
|
15999
16987
|
function describeFileReadError(error) {
|
|
16000
16988
|
const code = typeof error === "object" && error !== null && "code" in error ? String(error.code) : "";
|
|
16001
16989
|
if (code === "ENOENT") {
|
|
@@ -16153,7 +17141,11 @@ var deps = {
|
|
|
16153
17141
|
storage,
|
|
16154
17142
|
holder: "openteam-cli",
|
|
16155
17143
|
exec: nodeExec2,
|
|
16156
|
-
repoRoot: process.cwd()
|
|
17144
|
+
repoRoot: process.cwd(),
|
|
17145
|
+
evaluateCutoverGate: async (gateConfig) => evaluateCutoverGateForBoundary(gateConfig, storage, await resolveOpencodeVersionBestEffort({
|
|
17146
|
+
readPackageVersion,
|
|
17147
|
+
runVersionCommand: runOpencodeVersionCommand
|
|
17148
|
+
}))
|
|
16157
17149
|
}),
|
|
16158
17150
|
configPath: DEFAULT_CONFIG_PATH,
|
|
16159
17151
|
telemetryPath: DEFAULT_TELEMETRY_PATH,
|