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