@jmanuelcorral/openteam 0.26.0 → 0.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.es.md +11 -8
- package/README.md +11 -8
- package/dist/certificates/graph-release-certificate.json +2 -2
- package/dist/certificates/graph-shadow-certificate.json +2 -2
- package/dist/certificates/opencode-2.0.5/graph-release-certificate.json +45 -0
- package/dist/certificates/opencode-2.0.5/graph-shadow-certificate.json +39 -0
- package/dist/cli/consoleRuntimeState.d.ts.map +1 -1
- package/dist/cli/consoleServe.d.ts +2 -1
- package/dist/cli/consoleServe.d.ts.map +1 -1
- package/dist/cli/opencodeVersion.d.ts.map +1 -1
- package/dist/cli.js +21893 -12535
- package/dist/commands/setup.d.ts +2 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/upgrade.d.ts +1 -1
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/config/fieldProjection.d.ts +3 -0
- package/dist/config/fieldProjection.d.ts.map +1 -0
- package/dist/config/graphFeatureGate.d.ts +3 -3
- package/dist/config/nativeOpencode.d.ts +5 -0
- package/dist/config/nativeOpencode.d.ts.map +1 -0
- package/dist/console/auth.d.ts +5 -0
- package/dist/console/auth.d.ts.map +1 -0
- package/dist/console/conversation.d.ts +8 -1
- package/dist/console/conversation.d.ts.map +1 -1
- package/dist/console/historyBoundary.d.ts +1 -1
- package/dist/console/historyBoundary.d.ts.map +1 -1
- package/dist/console/nativeConversation.d.ts +7 -0
- package/dist/console/nativeConversation.d.ts.map +1 -0
- package/dist/console/opencodeClient.d.ts +3 -0
- package/dist/console/opencodeClient.d.ts.map +1 -1
- package/dist/console/pty.d.ts +4 -0
- package/dist/console/pty.d.ts.map +1 -1
- package/dist/contract/opencode.d.ts +21 -14
- package/dist/contract/opencode.d.ts.map +1 -1
- package/dist/graph/certificate.d.ts.map +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1174 -209
- package/dist/messages/consoleDetail.d.ts +3 -0
- package/dist/messages/consoleDetail.d.ts.map +1 -1
- package/dist/messages/nativeHost.d.ts +22 -0
- package/dist/messages/nativeHost.d.ts.map +1 -0
- package/dist/plugin/availability.d.ts +1 -0
- package/dist/plugin/availability.d.ts.map +1 -1
- package/dist/plugin/consoleTool.d.ts +1 -0
- package/dist/plugin/consoleTool.d.ts.map +1 -1
- package/dist/plugin/hooks.d.ts +3 -3
- package/dist/plugin/hooks.d.ts.map +1 -1
- package/dist/plugin/modelResidency.d.ts +1 -0
- package/dist/plugin/modelResidency.d.ts.map +1 -1
- package/dist/plugin/nativeHost.d.ts +5 -0
- package/dist/plugin/nativeHost.d.ts.map +1 -0
- package/dist/plugin/nativeHostContext.d.ts +228 -0
- package/dist/plugin/nativeHostContext.d.ts.map +1 -0
- package/dist/plugin/nativeInventory.d.ts +5 -0
- package/dist/plugin/nativeInventory.d.ts.map +1 -0
- package/dist/plugin/nativeResidency.d.ts +30 -0
- package/dist/plugin/nativeResidency.d.ts.map +1 -0
- package/dist/plugin/nativeSessions.d.ts +131 -0
- package/dist/plugin/nativeSessions.d.ts.map +1 -0
- package/dist/plugin/orchestrateTool.d.ts.map +1 -1
- package/dist/plugin/reloadTool.d.ts +3 -2
- package/dist/plugin/reloadTool.d.ts.map +1 -1
- package/dist/plugin/runtimeContext.d.ts +42 -0
- package/dist/plugin/runtimeContext.d.ts.map +1 -0
- package/dist/web/console.d.ts +1 -1
- package/dist/web/console.d.ts.map +1 -1
- package/dist/web/server.d.ts +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/start.d.ts +1 -1
- package/dist/web/start.d.ts.map +1 -1
- package/package.json +6 -3
package/dist/index.js
CHANGED
|
@@ -784,6 +784,9 @@ function migrateConfig(raw) {
|
|
|
784
784
|
|
|
785
785
|
// src/messages/consoleDetail.ts
|
|
786
786
|
var consoleDetailMessages = {
|
|
787
|
+
runtimeStateCleanupFailed: "The Console runtime state could not be published and its staging file could not be removed.",
|
|
788
|
+
requestFailed: "The local opencode request failed.",
|
|
789
|
+
nativeToolFailed: "The native tool execution failed.",
|
|
787
790
|
follow: "Follow new activity",
|
|
788
791
|
metadataOnly: "Lifecycle and telemetry stay metadata-only.",
|
|
789
792
|
logsDescription: "Current recorded conversations load automatically. Lifecycle and telemetry remain metadata-only; credentials are masked.",
|
|
@@ -5757,7 +5760,7 @@ import { z as z15 } from "zod";
|
|
|
5757
5760
|
// package.json
|
|
5758
5761
|
var package_default = {
|
|
5759
5762
|
name: "@jmanuelcorral/openteam",
|
|
5760
|
-
version: "0.
|
|
5763
|
+
version: "0.27.1",
|
|
5761
5764
|
packageManager: "bun@1.3.14",
|
|
5762
5765
|
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
5763
5766
|
license: "MIT",
|
|
@@ -5817,12 +5820,13 @@ var package_default = {
|
|
|
5817
5820
|
scripts: {
|
|
5818
5821
|
prebuild: "bun run clean",
|
|
5819
5822
|
build: "bun run build:js && bun run build:cli && bun run build:types && bun run build:certificates",
|
|
5820
|
-
"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",
|
|
5821
|
-
"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',
|
|
5823
|
+
"build:js": "bun build ./src/index.ts --target=node --format=esm --outfile=dist/index.js --external @opencode-ai/plugin --external @opencode-ai/sdk --external @opencode/schema --external effect --external zod --external @opentelemetry/api --external @opentelemetry/sdk-trace-base --external @opentelemetry/exporter-trace-otlp-http --external @opentelemetry/resources --external @langchain/langgraph",
|
|
5824
|
+
"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 @opencode/schema --external effect --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',
|
|
5822
5825
|
"build:types": "tsc -p tsconfig.build.json",
|
|
5823
5826
|
clean: `node -e "require('node:fs').rmSync('dist', { recursive: true, force: true })"`,
|
|
5824
5827
|
test: "bun test",
|
|
5825
5828
|
"test:cov": "bun test --coverage",
|
|
5829
|
+
"verify:opencode-native": "bun scripts/verify-opencode-native.mjs",
|
|
5826
5830
|
"certify:shadow": "bun run scripts/certify-artifact.ts shadow",
|
|
5827
5831
|
"certify:release": "bun run scripts/certify-artifact.ts release",
|
|
5828
5832
|
"build:certificates": "bun run certify:shadow && bun run certify:release && bun run scripts/bundle-certificates.ts",
|
|
@@ -5844,10 +5848,12 @@ var package_default = {
|
|
|
5844
5848
|
"@langchain/langgraph": "1.4.12",
|
|
5845
5849
|
"@opencode-ai/plugin": "1.18.19",
|
|
5846
5850
|
"@opencode-ai/sdk": "1.18.19",
|
|
5851
|
+
"@opencode/schema": "2.0.3",
|
|
5847
5852
|
"@opentelemetry/api": "1.9.1",
|
|
5848
5853
|
"@opentelemetry/exporter-trace-otlp-http": "0.221.0",
|
|
5849
5854
|
"@opentelemetry/resources": "2.10.0",
|
|
5850
5855
|
"@opentelemetry/sdk-trace-base": "2.10.0",
|
|
5856
|
+
effect: "4.0.0-rc.112",
|
|
5851
5857
|
zod: "4.4.3"
|
|
5852
5858
|
},
|
|
5853
5859
|
devDependencies: {
|
|
@@ -6363,7 +6369,7 @@ var NPM_LATEST_URL = `${NPM_ORIGIN}${NPM_PACKAGE_PATH}/latest`;
|
|
|
6363
6369
|
var FETCH_TIMEOUT_MS = 5000;
|
|
6364
6370
|
var MAX_RESPONSE_BYTES = 64 * 1024;
|
|
6365
6371
|
var MAX_FETCH_ATTEMPTS = 2;
|
|
6366
|
-
var
|
|
6372
|
+
var PLUGIN_KEYS = ["plugin", "plugins"];
|
|
6367
6373
|
var PRIVATE_DIRECTORY_MODE = 448;
|
|
6368
6374
|
var PRIVATE_FILE_MODE = 384;
|
|
6369
6375
|
var UPGRADE_BACKUP_GITIGNORE_CONTENT = `*
|
|
@@ -6417,6 +6423,8 @@ function extractSpecString(entry) {
|
|
|
6417
6423
|
if (isTuplePluginEntry(entry)) {
|
|
6418
6424
|
return entry[0];
|
|
6419
6425
|
}
|
|
6426
|
+
if (isRecord3(entry) && typeof entry.package === "string")
|
|
6427
|
+
return entry.package;
|
|
6420
6428
|
return;
|
|
6421
6429
|
}
|
|
6422
6430
|
function isLocalFileSpec(spec) {
|
|
@@ -6629,7 +6637,7 @@ function readJsoncValueEnd(src, start, limit) {
|
|
|
6629
6637
|
}
|
|
6630
6638
|
return i > start ? i : undefined;
|
|
6631
6639
|
}
|
|
6632
|
-
function findTopLevelPluginArray(raw) {
|
|
6640
|
+
function findTopLevelPluginArray(raw, pluginKey) {
|
|
6633
6641
|
let found;
|
|
6634
6642
|
let i = 0;
|
|
6635
6643
|
let depth = 0;
|
|
@@ -6676,7 +6684,7 @@ function findTopLevelPluginArray(raw) {
|
|
|
6676
6684
|
return;
|
|
6677
6685
|
}
|
|
6678
6686
|
i = token.end;
|
|
6679
|
-
if (key !==
|
|
6687
|
+
if (key !== pluginKey || depth !== 1) {
|
|
6680
6688
|
continue;
|
|
6681
6689
|
}
|
|
6682
6690
|
i = skipTrivia(raw, i);
|
|
@@ -6742,6 +6750,33 @@ function findEntrySpecStringSpan(raw, element, entry, expectedSpec) {
|
|
|
6742
6750
|
const span2 = { start: element.start, end: token2.end };
|
|
6743
6751
|
return readJsonStringValue(raw, span2) === expectedSpec ? span2 : undefined;
|
|
6744
6752
|
}
|
|
6753
|
+
if (isRecord3(entry) && typeof entry.package === "string") {
|
|
6754
|
+
let found;
|
|
6755
|
+
let i = skipTrivia(raw, element.start + 1, element.end);
|
|
6756
|
+
while (i < element.end && raw[i] !== "}") {
|
|
6757
|
+
const key = readStringToken(raw, i, element.end);
|
|
6758
|
+
if (key === undefined)
|
|
6759
|
+
return;
|
|
6760
|
+
const name = readJsonStringValue(raw, { start: i, end: key.end });
|
|
6761
|
+
i = skipTrivia(raw, key.end, element.end);
|
|
6762
|
+
if (raw[i] !== ":")
|
|
6763
|
+
return;
|
|
6764
|
+
i = skipTrivia(raw, i + 1, element.end);
|
|
6765
|
+
const end = readJsoncValueEnd(raw, i, element.end);
|
|
6766
|
+
if (end === undefined)
|
|
6767
|
+
return;
|
|
6768
|
+
if (name === "package") {
|
|
6769
|
+
const span2 = { start: i, end };
|
|
6770
|
+
found = readJsonStringValue(raw, span2) === expectedSpec ? span2 : undefined;
|
|
6771
|
+
}
|
|
6772
|
+
i = skipTrivia(raw, end, element.end);
|
|
6773
|
+
if (raw[i] === ",")
|
|
6774
|
+
i = skipTrivia(raw, i + 1, element.end);
|
|
6775
|
+
else if (raw[i] !== "}")
|
|
6776
|
+
return;
|
|
6777
|
+
}
|
|
6778
|
+
return found;
|
|
6779
|
+
}
|
|
6745
6780
|
if (!isTuplePluginEntry(entry)) {
|
|
6746
6781
|
return;
|
|
6747
6782
|
}
|
|
@@ -6769,20 +6804,23 @@ function validateEffectivePluginUpdate(path, nextContent, expectedManagedEntries
|
|
|
6769
6804
|
if (!parsed.ok) {
|
|
6770
6805
|
return parsed.error;
|
|
6771
6806
|
}
|
|
6772
|
-
const pluginValue = parsed.value[PLUGIN_KEY];
|
|
6773
|
-
if (!Array.isArray(pluginValue)) {
|
|
6774
|
-
return upgradeMessages.effectivePluginUpdateMismatch(path);
|
|
6775
|
-
}
|
|
6776
6807
|
let managedEntries = 0;
|
|
6777
6808
|
let updatedEntries = 0;
|
|
6778
|
-
for (const
|
|
6779
|
-
const
|
|
6780
|
-
if (
|
|
6809
|
+
for (const key of PLUGIN_KEYS) {
|
|
6810
|
+
const pluginValue = parsed.value[key];
|
|
6811
|
+
if (pluginValue === undefined)
|
|
6781
6812
|
continue;
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6813
|
+
if (!Array.isArray(pluginValue))
|
|
6814
|
+
return upgradeMessages.effectivePluginUpdateMismatch(path);
|
|
6815
|
+
for (const entry of pluginValue) {
|
|
6816
|
+
const spec = extractSpecString(entry);
|
|
6817
|
+
if (spec === undefined || !isOurSpec(spec)) {
|
|
6818
|
+
continue;
|
|
6819
|
+
}
|
|
6820
|
+
managedEntries += 1;
|
|
6821
|
+
if (spec === nextSpec) {
|
|
6822
|
+
updatedEntries += 1;
|
|
6823
|
+
}
|
|
6786
6824
|
}
|
|
6787
6825
|
}
|
|
6788
6826
|
return managedEntries === expectedManagedEntries && updatedEntries === expectedManagedEntries ? undefined : upgradeMessages.effectivePluginUpdateMismatch(path);
|
|
@@ -7043,70 +7081,52 @@ async function analyseConfigFiles(paths, port) {
|
|
|
7043
7081
|
parseError: parsed.error
|
|
7044
7082
|
};
|
|
7045
7083
|
}
|
|
7046
|
-
const
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7050
|
-
if (!Array.isArray(pluginValue)) {
|
|
7051
|
-
return {
|
|
7052
|
-
files,
|
|
7053
|
-
foundConfigFile,
|
|
7054
|
-
localOpenteamEntries,
|
|
7055
|
-
parseError: upgradeMessages.pluginFieldMustBeArray(path)
|
|
7056
|
-
};
|
|
7057
|
-
}
|
|
7058
|
-
const managedCandidates = [];
|
|
7059
|
-
for (let index = 0;index < pluginValue.length; index += 1) {
|
|
7060
|
-
const entry = pluginValue[index];
|
|
7061
|
-
const spec = extractSpecString(entry);
|
|
7062
|
-
if (spec === undefined) {
|
|
7084
|
+
const fileReplacements = [];
|
|
7085
|
+
for (const pluginKey of PLUGIN_KEYS) {
|
|
7086
|
+
const pluginValue = parsed.value[pluginKey];
|
|
7087
|
+
if (pluginValue === undefined) {
|
|
7063
7088
|
continue;
|
|
7064
7089
|
}
|
|
7065
|
-
if (
|
|
7066
|
-
|
|
7067
|
-
|
|
7090
|
+
if (!Array.isArray(pluginValue)) {
|
|
7091
|
+
return {
|
|
7092
|
+
files,
|
|
7093
|
+
foundConfigFile,
|
|
7094
|
+
localOpenteamEntries,
|
|
7095
|
+
parseError: upgradeMessages.pluginFieldMustBeArray(path)
|
|
7096
|
+
};
|
|
7097
|
+
}
|
|
7098
|
+
const managedCandidates = [];
|
|
7099
|
+
for (let index = 0;index < pluginValue.length; index += 1) {
|
|
7100
|
+
const entry = pluginValue[index];
|
|
7101
|
+
const spec = extractSpecString(entry);
|
|
7102
|
+
if (spec === undefined) {
|
|
7103
|
+
continue;
|
|
7104
|
+
}
|
|
7105
|
+
if (isLocalFileSpec(spec)) {
|
|
7106
|
+
const localKind = await port.classifyLocalPluginSpec({
|
|
7107
|
+
configPath: path,
|
|
7108
|
+
spec
|
|
7109
|
+
});
|
|
7110
|
+
if (localKind === "ours") {
|
|
7111
|
+
localOpenteamEntries.push({ path, spec });
|
|
7112
|
+
}
|
|
7113
|
+
continue;
|
|
7114
|
+
}
|
|
7115
|
+
if (!isOurSpec(spec)) {
|
|
7116
|
+
continue;
|
|
7117
|
+
}
|
|
7118
|
+
managedCandidates.push({
|
|
7119
|
+
currentVersion: currentPinnedVersion(spec),
|
|
7120
|
+
entry,
|
|
7121
|
+
index,
|
|
7068
7122
|
spec
|
|
7069
7123
|
});
|
|
7070
|
-
if (localKind === "ours") {
|
|
7071
|
-
localOpenteamEntries.push({ path, spec });
|
|
7072
|
-
}
|
|
7073
|
-
continue;
|
|
7074
7124
|
}
|
|
7075
|
-
if (
|
|
7125
|
+
if (managedCandidates.length === 0) {
|
|
7076
7126
|
continue;
|
|
7077
7127
|
}
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
entry,
|
|
7081
|
-
index,
|
|
7082
|
-
spec
|
|
7083
|
-
});
|
|
7084
|
-
}
|
|
7085
|
-
if (managedCandidates.length === 0) {
|
|
7086
|
-
continue;
|
|
7087
|
-
}
|
|
7088
|
-
const pluginArray = findTopLevelPluginArray(content);
|
|
7089
|
-
if (pluginArray === undefined) {
|
|
7090
|
-
return {
|
|
7091
|
-
files,
|
|
7092
|
-
foundConfigFile,
|
|
7093
|
-
localOpenteamEntries,
|
|
7094
|
-
parseError: upgradeMessages.pluginArrayEditUnavailable(path)
|
|
7095
|
-
};
|
|
7096
|
-
}
|
|
7097
|
-
const elementSpans = scanTopLevelArrayElements(content, pluginArray.start, pluginArray.end);
|
|
7098
|
-
if (elementSpans === undefined || elementSpans.length !== pluginValue.length) {
|
|
7099
|
-
return {
|
|
7100
|
-
files,
|
|
7101
|
-
foundConfigFile,
|
|
7102
|
-
localOpenteamEntries,
|
|
7103
|
-
parseError: upgradeMessages.pluginArrayEditUnavailable(path)
|
|
7104
|
-
};
|
|
7105
|
-
}
|
|
7106
|
-
const replacements = [];
|
|
7107
|
-
for (const candidate of managedCandidates) {
|
|
7108
|
-
const elementSpan = elementSpans[candidate.index];
|
|
7109
|
-
if (elementSpan === undefined) {
|
|
7128
|
+
const pluginArray = findTopLevelPluginArray(content, pluginKey);
|
|
7129
|
+
if (pluginArray === undefined) {
|
|
7110
7130
|
return {
|
|
7111
7131
|
files,
|
|
7112
7132
|
foundConfigFile,
|
|
@@ -7114,8 +7134,8 @@ async function analyseConfigFiles(paths, port) {
|
|
|
7114
7134
|
parseError: upgradeMessages.pluginArrayEditUnavailable(path)
|
|
7115
7135
|
};
|
|
7116
7136
|
}
|
|
7117
|
-
const
|
|
7118
|
-
if (
|
|
7137
|
+
const elementSpans = scanTopLevelArrayElements(content, pluginArray.start, pluginArray.end);
|
|
7138
|
+
if (elementSpans === undefined || elementSpans.length !== pluginValue.length) {
|
|
7119
7139
|
return {
|
|
7120
7140
|
files,
|
|
7121
7141
|
foundConfigFile,
|
|
@@ -7123,16 +7143,40 @@ async function analyseConfigFiles(paths, port) {
|
|
|
7123
7143
|
parseError: upgradeMessages.pluginArrayEditUnavailable(path)
|
|
7124
7144
|
};
|
|
7125
7145
|
}
|
|
7126
|
-
replacements
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7146
|
+
const replacements = [];
|
|
7147
|
+
for (const candidate of managedCandidates) {
|
|
7148
|
+
const elementSpan = elementSpans[candidate.index];
|
|
7149
|
+
if (elementSpan === undefined) {
|
|
7150
|
+
return {
|
|
7151
|
+
files,
|
|
7152
|
+
foundConfigFile,
|
|
7153
|
+
localOpenteamEntries,
|
|
7154
|
+
parseError: upgradeMessages.pluginArrayEditUnavailable(path)
|
|
7155
|
+
};
|
|
7156
|
+
}
|
|
7157
|
+
const specSpan = findEntrySpecStringSpan(content, elementSpan, candidate.entry, candidate.spec);
|
|
7158
|
+
if (specSpan === undefined) {
|
|
7159
|
+
return {
|
|
7160
|
+
files,
|
|
7161
|
+
foundConfigFile,
|
|
7162
|
+
localOpenteamEntries,
|
|
7163
|
+
parseError: upgradeMessages.pluginArrayEditUnavailable(path)
|
|
7164
|
+
};
|
|
7165
|
+
}
|
|
7166
|
+
replacements.push({
|
|
7167
|
+
...specSpan,
|
|
7168
|
+
currentVersion: candidate.currentVersion
|
|
7169
|
+
});
|
|
7170
|
+
}
|
|
7171
|
+
fileReplacements.push(...replacements);
|
|
7130
7172
|
}
|
|
7173
|
+
if (fileReplacements.length === 0)
|
|
7174
|
+
continue;
|
|
7131
7175
|
files.push({
|
|
7132
|
-
currentVersions:
|
|
7176
|
+
currentVersions: fileReplacements.map((replacement) => replacement.currentVersion),
|
|
7133
7177
|
path,
|
|
7134
7178
|
originalContent: content,
|
|
7135
|
-
replacements
|
|
7179
|
+
replacements: fileReplacements
|
|
7136
7180
|
});
|
|
7137
7181
|
}
|
|
7138
7182
|
return {
|
|
@@ -7860,15 +7904,14 @@ function mergeOpencodeConfigs(base, override) {
|
|
|
7860
7904
|
return result;
|
|
7861
7905
|
}
|
|
7862
7906
|
|
|
7863
|
-
// src/graph/certificate.ts
|
|
7864
|
-
import { z as z17 } from "zod";
|
|
7865
|
-
|
|
7866
7907
|
// src/contract/opencode.ts
|
|
7867
7908
|
var SUPPORTED_OPENCODE_VERSIONS = [
|
|
7868
7909
|
"1.17.13",
|
|
7869
7910
|
"1.18.18",
|
|
7870
7911
|
"1.18.19"
|
|
7871
7912
|
];
|
|
7913
|
+
var NATIVE_OPENCODE_VERSION = "2.0.5";
|
|
7914
|
+
var NATIVE_CERTIFICATE_DIRECTORY = `opencode-${NATIVE_OPENCODE_VERSION}`;
|
|
7872
7915
|
var SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)/;
|
|
7873
7916
|
function parseSemver(version) {
|
|
7874
7917
|
const normalized = version.trim().replace(/^[=^~v]+/, "");
|
|
@@ -7882,10 +7925,31 @@ function parseSemver(version) {
|
|
|
7882
7925
|
patch: Number(match[3])
|
|
7883
7926
|
};
|
|
7884
7927
|
}
|
|
7928
|
+
function compareSemver2(a, b) {
|
|
7929
|
+
if (a.major !== b.major) {
|
|
7930
|
+
return a.major < b.major ? -1 : 1;
|
|
7931
|
+
}
|
|
7932
|
+
if (a.minor !== b.minor) {
|
|
7933
|
+
return a.minor < b.minor ? -1 : 1;
|
|
7934
|
+
}
|
|
7935
|
+
if (a.patch !== b.patch) {
|
|
7936
|
+
return a.patch < b.patch ? -1 : 1;
|
|
7937
|
+
}
|
|
7938
|
+
return 0;
|
|
7939
|
+
}
|
|
7940
|
+
function isSupportedNativeOpencodeVersion(version) {
|
|
7941
|
+
if (version === undefined || !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.test(version))
|
|
7942
|
+
return false;
|
|
7943
|
+
const live = parseSemver(version);
|
|
7944
|
+
const minimum = parseSemver(NATIVE_OPENCODE_VERSION);
|
|
7945
|
+
return Object.values(live).every(Number.isSafeInteger) && live.major === minimum.major && compareSemver2(live, minimum) >= 0;
|
|
7946
|
+
}
|
|
7885
7947
|
function isCertificateVersionCompatible(certifiedVersion, liveVersion) {
|
|
7886
7948
|
if (certifiedVersion === liveVersion) {
|
|
7887
7949
|
return true;
|
|
7888
7950
|
}
|
|
7951
|
+
if (isSupportedNativeOpencodeVersion(certifiedVersion) && isSupportedNativeOpencodeVersion(liveVersion))
|
|
7952
|
+
return compareSemver2(parseSemver(liveVersion), parseSemver(certifiedVersion)) >= 0;
|
|
7889
7953
|
let certified;
|
|
7890
7954
|
let live;
|
|
7891
7955
|
try {
|
|
@@ -7894,12 +7958,38 @@ function isCertificateVersionCompatible(certifiedVersion, liveVersion) {
|
|
|
7894
7958
|
} catch {
|
|
7895
7959
|
return false;
|
|
7896
7960
|
}
|
|
7897
|
-
if (certified.major !== live.major || certified.minor !== live.minor) {
|
|
7961
|
+
if (certified.major !== 1 || certified.major !== live.major || certified.minor !== live.minor) {
|
|
7898
7962
|
return false;
|
|
7899
7963
|
}
|
|
7900
7964
|
return live.patch >= certified.patch;
|
|
7901
7965
|
}
|
|
7902
7966
|
|
|
7967
|
+
// src/graph/certificate.ts
|
|
7968
|
+
import { z as z17 } from "zod";
|
|
7969
|
+
|
|
7970
|
+
// src/messages/nativeHost.ts
|
|
7971
|
+
var nativeHostMessages = {
|
|
7972
|
+
invalidNativeConfig: "The existing native opencode plugins/providers configuration cannot be safely merged. Correct its object and plugin declaration shapes before running setup.",
|
|
7973
|
+
setupPolicyQuestion: (paths, providers) => `Remove exact project-local provider.use deny rules for ${providers.join(", ")} from ${paths.join(", ")}? Older setup added these rules, but they may also be operator limits. Confirm only if you intend to enable the guarded native transport.`,
|
|
7974
|
+
setupPolicyPreserved: "Setup stopped. Provider-denial rules were preserved and no files were written.",
|
|
7975
|
+
setupPolicyNotice: "Only the explicitly reviewed project rules were removed. Wildcard, scoped, unrelated and global provider denials remain authoritative.",
|
|
7976
|
+
unsupportedVersion: (version) => `openteam does not support native opencode ${version}. The supported stable native range is >=2.0.5 <3.0.0.`,
|
|
7977
|
+
certificateVersionMismatch: (certified, live) => `certified for "${certified}", running "${live}" — evidence is outside the supported host compatibility range`,
|
|
7978
|
+
missingBindings: "The native opencode execution context is unavailable. No child session or privileged operation was started.",
|
|
7979
|
+
missingVersion: "The opencode host did not provide an authoritative version or server endpoint.",
|
|
7980
|
+
workspaceMismatch: "The native opencode session does not belong to this workspace.",
|
|
7981
|
+
noCompletedResponse: "The native opencode session stopped without a completed assistant response.",
|
|
7982
|
+
executionFailed: "The native opencode session failed.",
|
|
7983
|
+
executionInterrupted: "The native opencode session was interrupted.",
|
|
7984
|
+
unknownAgent: "The native opencode session has no available agent.",
|
|
7985
|
+
noAvailableModel: "The native opencode host has no model available in the configured execution domain.",
|
|
7986
|
+
executionDomainBlocked: "The native opencode request is outside the configured execution domain.",
|
|
7987
|
+
transportUnavailable: "This local runtime requires the guarded @ai-sdk/openai-compatible transport. Native and WebSocket transports are not admitted.",
|
|
7988
|
+
missingAdmission: "The native local request has no matching model authorization. No inference was sent.",
|
|
7989
|
+
toolFailed: "The openteam tool failed in the native opencode host.",
|
|
7990
|
+
eventCaptureFailed: "Native opencode event capture failed. The console may be missing activity; reload the plugin after resolving the host error."
|
|
7991
|
+
};
|
|
7992
|
+
|
|
7903
7993
|
// src/graph/soakLedger.ts
|
|
7904
7994
|
import { z as z16 } from "zod";
|
|
7905
7995
|
var Sha256Schema2 = z16.string().regex(/^[0-9a-f]{64}$/);
|
|
@@ -8158,7 +8248,7 @@ function parseShadowCertificate(value, opencodeVersion) {
|
|
|
8158
8248
|
throw new ShadowCertificateError("digest-mismatch", "certificate digest does not cover the presented evidence");
|
|
8159
8249
|
}
|
|
8160
8250
|
if (!isCertificateVersionCompatible(certificate.opencodeVersion, opencodeVersion)) {
|
|
8161
|
-
throw new ShadowCertificateError("opencode-mismatch",
|
|
8251
|
+
throw new ShadowCertificateError("opencode-mismatch", nativeHostMessages.certificateVersionMismatch(certificate.opencodeVersion, opencodeVersion));
|
|
8162
8252
|
}
|
|
8163
8253
|
return certificate;
|
|
8164
8254
|
}
|
|
@@ -8343,7 +8433,7 @@ function parseReleaseCertificate(value, opencodeVersion, expectedShadowDigest) {
|
|
|
8343
8433
|
throw new ReleaseCertificateError("digest-mismatch", "certificate digest does not cover the presented evidence");
|
|
8344
8434
|
}
|
|
8345
8435
|
if (!isCertificateVersionCompatible(certificate.opencodeVersion, opencodeVersion)) {
|
|
8346
|
-
throw new ReleaseCertificateError("opencode-mismatch",
|
|
8436
|
+
throw new ReleaseCertificateError("opencode-mismatch", nativeHostMessages.certificateVersionMismatch(certificate.opencodeVersion, opencodeVersion));
|
|
8347
8437
|
}
|
|
8348
8438
|
return certificate;
|
|
8349
8439
|
}
|
|
@@ -11967,6 +12057,10 @@ function createAvailabilityCache(options) {
|
|
|
11967
12057
|
ref: { ...profile.ref },
|
|
11968
12058
|
costPer1M: { ...profile.costPer1M }
|
|
11969
12059
|
})),
|
|
12060
|
+
waitForRefresh: async () => {
|
|
12061
|
+
while (inFlight !== undefined)
|
|
12062
|
+
await inFlight;
|
|
12063
|
+
},
|
|
11970
12064
|
refresh: () => {
|
|
11971
12065
|
if (inFlight === undefined) {
|
|
11972
12066
|
cached = cached.map((model) => requiresModelResidency(options.config, model) ? { ...model, available: false } : model);
|
|
@@ -13801,6 +13895,16 @@ function renderMigration(report) {
|
|
|
13801
13895
|
// src/commands/purge.ts
|
|
13802
13896
|
import * as path3 from "node:path";
|
|
13803
13897
|
|
|
13898
|
+
// src/config/fieldProjection.ts
|
|
13899
|
+
function only(keys) {
|
|
13900
|
+
return (value) => {
|
|
13901
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
13902
|
+
return value;
|
|
13903
|
+
const record = value;
|
|
13904
|
+
return Object.fromEntries(keys.filter((key) => Object.hasOwn(record, key)).map((key) => [key, record[key]]));
|
|
13905
|
+
};
|
|
13906
|
+
}
|
|
13907
|
+
|
|
13804
13908
|
// src/storage/graph/soakRecorder.ts
|
|
13805
13909
|
var SOAK_EVIDENCE_DIR = ".opencode/soak";
|
|
13806
13910
|
var SOAK_RECORDER_BASE_DIR = ".opencode";
|
|
@@ -15595,7 +15699,7 @@ function createCommandTool(deps) {
|
|
|
15595
15699
|
// src/plugin/consoleTool.ts
|
|
15596
15700
|
import { spawn as nodeSpawn } from "node:child_process";
|
|
15597
15701
|
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
|
|
15598
|
-
import { mkdir as mkdir4, open as open3 } from "node:fs/promises";
|
|
15702
|
+
import { mkdir as mkdir4, open as open3, stat as stat3 } from "node:fs/promises";
|
|
15599
15703
|
import { dirname as dirname6, join as join13, resolve as resolve8 } from "node:path";
|
|
15600
15704
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
15601
15705
|
import { tool as tool2 } from "@opencode-ai/plugin";
|
|
@@ -15605,8 +15709,8 @@ import {
|
|
|
15605
15709
|
mkdir as mkdir3,
|
|
15606
15710
|
open as open2,
|
|
15607
15711
|
readFile as readFile4,
|
|
15608
|
-
|
|
15609
|
-
|
|
15712
|
+
rename as rename2,
|
|
15713
|
+
unlink
|
|
15610
15714
|
} from "node:fs/promises";
|
|
15611
15715
|
import { dirname as dirname5, join as join12, resolve as resolve7 } from "node:path";
|
|
15612
15716
|
import { z as z22 } from "zod";
|
|
@@ -15906,10 +16010,17 @@ async function acquireLaunchLockOrWait(workspaceRoot, paths, launchId, deps) {
|
|
|
15906
16010
|
currentLock = await readConsoleLaunchLock(paths.launchLockPath);
|
|
15907
16011
|
} catch (error) {
|
|
15908
16012
|
if (error instanceof ConsoleRuntimeStateFileError) {
|
|
15909
|
-
await
|
|
15910
|
-
|
|
15911
|
-
|
|
15912
|
-
|
|
16013
|
+
const info = await stat3(paths.launchLockPath).catch((error2) => {
|
|
16014
|
+
if (error2 instanceof Error && "code" in error2 && error2.code === "ENOENT")
|
|
16015
|
+
return;
|
|
16016
|
+
throw error2;
|
|
16017
|
+
});
|
|
16018
|
+
if (info === undefined || deps.now() - info.mtimeMs > LAUNCH_LOCK_STALE_MS) {
|
|
16019
|
+
await removeConsoleLaunchLock(paths.launchLockPath);
|
|
16020
|
+
const retry = await acquireConsoleLaunchLock(paths.launchLockPath, attemptLock);
|
|
16021
|
+
if (retry !== "busy") {
|
|
16022
|
+
return { kind: "acquired", release: retry.release };
|
|
16023
|
+
}
|
|
15913
16024
|
}
|
|
15914
16025
|
} else {
|
|
15915
16026
|
throw error;
|
|
@@ -15982,7 +16093,8 @@ async function spawnDetachedConsole(workspaceRoot, paths, launchId, deps) {
|
|
|
15982
16093
|
], {
|
|
15983
16094
|
cwd: workspaceRoot,
|
|
15984
16095
|
detached: true,
|
|
15985
|
-
stdio: ["ignore", logHandle.fd, logHandle.fd]
|
|
16096
|
+
stdio: ["ignore", logHandle.fd, logHandle.fd],
|
|
16097
|
+
...deps.environment === undefined ? {} : { env: deps.environment() }
|
|
15986
16098
|
});
|
|
15987
16099
|
child.unref?.();
|
|
15988
16100
|
return child;
|
|
@@ -16017,7 +16129,8 @@ function createConsoleTool(deps = {}) {
|
|
|
16017
16129
|
sendSignal,
|
|
16018
16130
|
sleep,
|
|
16019
16131
|
resolveCliEntrypoint,
|
|
16020
|
-
spawn
|
|
16132
|
+
spawn,
|
|
16133
|
+
...deps.environment === undefined ? {} : { environment: deps.environment }
|
|
16021
16134
|
};
|
|
16022
16135
|
if (args.action === "status") {
|
|
16023
16136
|
return summaryFromProbe(await readRuntimeProbe(workspaceRoot, {
|
|
@@ -16135,10 +16248,7 @@ function createConsoleTool(deps = {}) {
|
|
|
16135
16248
|
});
|
|
16136
16249
|
}
|
|
16137
16250
|
await removeConsoleRuntimeState(paths.runtimeStatePath);
|
|
16138
|
-
const child = await spawnDetachedConsole(workspaceRoot, paths, launchId,
|
|
16139
|
-
resolveCliEntrypoint: runtimeDeps.resolveCliEntrypoint,
|
|
16140
|
-
spawn: runtimeDeps.spawn
|
|
16141
|
-
});
|
|
16251
|
+
const child = await spawnDetachedConsole(workspaceRoot, paths, launchId, runtimeDeps);
|
|
16142
16252
|
const probe = await waitForHealthyRuntime(workspaceRoot, START_TIMEOUT_MS, {
|
|
16143
16253
|
fetch: runtimeDeps.fetch,
|
|
16144
16254
|
processExists: runtimeDeps.processExists,
|
|
@@ -18037,8 +18147,8 @@ function createChatMessageHook(config, getAvailable, options = {}) {
|
|
|
18037
18147
|
await injectMemoryBestEffort(options.injectMemory, prompt, output);
|
|
18038
18148
|
return;
|
|
18039
18149
|
}
|
|
18040
|
-
await options.beforeRoute?.();
|
|
18041
18150
|
const role = await roleForAgentName(config, input.agent ?? output.message.agent, options.resolveAgentRole);
|
|
18151
|
+
await options.beforeRoute?.();
|
|
18042
18152
|
const derivedSignals = deriveTaskSignals(input, output);
|
|
18043
18153
|
const signals = role === undefined ? derivedSignals : withoutExplicitOverride(derivedSignals);
|
|
18044
18154
|
const executionPolicy = role === undefined ? config.orchestrator?.primary : agentExecutionPolicyForRole(role);
|
|
@@ -18092,8 +18202,8 @@ function createChatMessageHook(config, getAvailable, options = {}) {
|
|
|
18092
18202
|
function createHooks(config, getAvailable, options = {}) {
|
|
18093
18203
|
const residency = options.modelResidency ?? createModelResidencyGuard(config, { fetch: globalThis.fetch });
|
|
18094
18204
|
return {
|
|
18095
|
-
config: residency.config,
|
|
18096
|
-
"chat.params": residency.beforeInference,
|
|
18205
|
+
...residency.config === undefined ? {} : { config: residency.config },
|
|
18206
|
+
...residency.beforeInference === undefined ? {} : { "chat.params": residency.beforeInference },
|
|
18097
18207
|
"chat.message": createChatMessageHook(config, getAvailable, options)
|
|
18098
18208
|
};
|
|
18099
18209
|
}
|
|
@@ -19243,12 +19353,841 @@ function createOrchestratedModelOwnership() {
|
|
|
19243
19353
|
};
|
|
19244
19354
|
}
|
|
19245
19355
|
|
|
19356
|
+
// src/plugin/nativeHost.ts
|
|
19357
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
19358
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
19359
|
+
import { resolve as resolve10 } from "node:path";
|
|
19360
|
+
import { Model as Model2 } from "@opencode/schema/model";
|
|
19361
|
+
import { Session as Session2 } from "@opencode/schema/session";
|
|
19362
|
+
import { Tool } from "@opencode/schema/tool";
|
|
19363
|
+
import { tool as legacyTool } from "@opencode-ai/plugin/tool";
|
|
19364
|
+
import { Clock, Effect, Option, Stream } from "effect";
|
|
19365
|
+
import { z as z30 } from "zod";
|
|
19366
|
+
|
|
19367
|
+
// src/plugin/nativeHostContext.ts
|
|
19368
|
+
import {
|
|
19369
|
+
Context
|
|
19370
|
+
} from "effect";
|
|
19371
|
+
|
|
19372
|
+
class NativeSessions extends Context.Service()("@opencode/Session") {
|
|
19373
|
+
}
|
|
19374
|
+
|
|
19375
|
+
class NativePermissions extends Context.Service()("@opencode/Permission") {
|
|
19376
|
+
}
|
|
19377
|
+
|
|
19378
|
+
class NativeAgents extends Context.Service()("@opencode/Agent") {
|
|
19379
|
+
}
|
|
19380
|
+
|
|
19381
|
+
class NativeLocations extends Context.Service()("@opencode/example/LocationServiceMap") {
|
|
19382
|
+
}
|
|
19383
|
+
|
|
19384
|
+
class NativeServerInfo extends Context.Service()("@opencode/server/ServerInfo") {
|
|
19385
|
+
}
|
|
19386
|
+
|
|
19387
|
+
class NativeServerAuth extends Context.Service()("@opencode/ServerAuthConfig") {
|
|
19388
|
+
}
|
|
19389
|
+
|
|
19390
|
+
// src/plugin/nativeInventory.ts
|
|
19391
|
+
function nativeConfiguredInventory(models, config) {
|
|
19392
|
+
const local = new Set(config.local.runtimes.map((runtime) => runtime.defaultModel.providerID));
|
|
19393
|
+
const enabled = models.filter((model) => model.enabled);
|
|
19394
|
+
const catalog = new Map;
|
|
19395
|
+
for (const model of enabled) {
|
|
19396
|
+
if (local.has(model.providerID))
|
|
19397
|
+
continue;
|
|
19398
|
+
const provider = catalog.get(model.providerID) ?? { models: [] };
|
|
19399
|
+
provider.models.push({
|
|
19400
|
+
id: model.id,
|
|
19401
|
+
name: model.name,
|
|
19402
|
+
limit: model.limit,
|
|
19403
|
+
cost: model.cost.find((tier) => tier.tier === undefined),
|
|
19404
|
+
status: model.status,
|
|
19405
|
+
tool_call: model.capabilities.tools,
|
|
19406
|
+
modalities: { input: model.capabilities.input },
|
|
19407
|
+
reasoning: model.capabilities.output.includes("reasoning")
|
|
19408
|
+
});
|
|
19409
|
+
catalog.set(model.providerID, provider);
|
|
19410
|
+
}
|
|
19411
|
+
return {
|
|
19412
|
+
models: enabled.map((model) => ({
|
|
19413
|
+
providerID: model.providerID,
|
|
19414
|
+
modelID: model.id,
|
|
19415
|
+
apiModelID: model.modelID,
|
|
19416
|
+
...local.has(model.providerID) ? {} : {
|
|
19417
|
+
supportsTools: model.capabilities.tools,
|
|
19418
|
+
...model.limit.context > 0 ? { contextWindow: model.limit.context } : {}
|
|
19419
|
+
}
|
|
19420
|
+
})),
|
|
19421
|
+
profiles: normalizeModelsDevCatalog(Object.fromEntries(catalog))
|
|
19422
|
+
};
|
|
19423
|
+
}
|
|
19424
|
+
|
|
19425
|
+
// src/plugin/nativeResidency.ts
|
|
19426
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
19427
|
+
import { z as z29 } from "zod";
|
|
19428
|
+
var NATIVE_RESIDENCY_PROVIDER_PACKAGE = "aisdk:@ai-sdk/openai-compatible@2.0.75";
|
|
19429
|
+
var NATIVE_ADMISSION_HEADER = "x-openteam-local-admission";
|
|
19430
|
+
var MAX_ADMISSIONS = 2048;
|
|
19431
|
+
var compatiblePackages = new Set([
|
|
19432
|
+
"@ai-sdk/openai-compatible",
|
|
19433
|
+
"aisdk:@ai-sdk/openai-compatible",
|
|
19434
|
+
"@opencode/ai/providers/openai-compatible",
|
|
19435
|
+
NATIVE_RESIDENCY_PROVIDER_PACKAGE
|
|
19436
|
+
]);
|
|
19437
|
+
function key(ref) {
|
|
19438
|
+
return `${ref.providerID}\x00${ref.modelID}`;
|
|
19439
|
+
}
|
|
19440
|
+
function label(runtime) {
|
|
19441
|
+
return localRuntimeKind(runtime) === "llama-swap" ? "llama-swap" : "Lemonade";
|
|
19442
|
+
}
|
|
19443
|
+
function runtimeBase2(runtime) {
|
|
19444
|
+
return localRuntimeKind(runtime) === "llama-swap" ? llamaSwapBaseURL(runtime.baseURL ?? LLAMA_SWAP_DEFAULT_BASE_URL) : lemonadeBaseURL(runtime.baseURL ?? LEMONADE_DEFAULT_BASE_URL);
|
|
19445
|
+
}
|
|
19446
|
+
function createNativeModelResidencyGuard(config, options) {
|
|
19447
|
+
const admissions = new Map;
|
|
19448
|
+
const localTargets = new Map;
|
|
19449
|
+
let disposed = false;
|
|
19450
|
+
const residentRuntimes = config.local.runtimes.filter((runtime) => runtimeRequiresModelResidency(localRuntimeKind(runtime)));
|
|
19451
|
+
const globalMode = () => resolveExecutionMode({
|
|
19452
|
+
routerMode: config.router.executionMode,
|
|
19453
|
+
legacyLocalOnly: config.router.localOnly,
|
|
19454
|
+
legacyFrontierOnly: config.router.frontierOnly
|
|
19455
|
+
});
|
|
19456
|
+
function allowed(providerID, mode) {
|
|
19457
|
+
const local = config.local.runtimes.filter((runtime) => runtime.defaultModel.providerID === providerID);
|
|
19458
|
+
return local.length > 0 ? mode !== "frontier" && local.some((runtime) => runtime.enabled) : mode !== "local";
|
|
19459
|
+
}
|
|
19460
|
+
function protects(providerID, url) {
|
|
19461
|
+
return residentRuntimes.some((runtime) => {
|
|
19462
|
+
if (runtime.defaultModel.providerID === providerID)
|
|
19463
|
+
return true;
|
|
19464
|
+
if (url === undefined)
|
|
19465
|
+
return false;
|
|
19466
|
+
if (!URL.canParse(url))
|
|
19467
|
+
return true;
|
|
19468
|
+
return new URL(url).origin === new URL(runtimeBase2(runtime)).origin;
|
|
19469
|
+
});
|
|
19470
|
+
}
|
|
19471
|
+
function bind(model) {
|
|
19472
|
+
const runtimes = config.local.runtimes.filter((runtime2) => runtime2.defaultModel.providerID === model.providerID);
|
|
19473
|
+
const runtime = runtimes[0];
|
|
19474
|
+
const runtimeLabel = runtime === undefined ? undefined : label(runtime);
|
|
19475
|
+
if (runtimes.length !== 1 || runtime === undefined || !runtime.enabled)
|
|
19476
|
+
throw new ModelResidencyError("destination", runtimeLabel);
|
|
19477
|
+
const baseURL = runtimeBase2(runtime);
|
|
19478
|
+
const base = model.settings?.baseURL;
|
|
19479
|
+
const normalized = typeof base !== "string" ? undefined : localRuntimeKind(runtime) === "llama-swap" ? llamaSwapBaseURL(base) : lemonadeBaseURL(base);
|
|
19480
|
+
if (normalized !== baseURL)
|
|
19481
|
+
throw new ModelResidencyError("destination", runtimeLabel);
|
|
19482
|
+
if (model.package !== NATIVE_RESIDENCY_PROVIDER_PACKAGE || model.transport === "websocket" || model.settings?.fetch !== undefined || model.settings?.queryParams !== undefined || model.settings?.transformRequestBody !== undefined)
|
|
19483
|
+
throw new ModelResidencyError("transport", runtimeLabel);
|
|
19484
|
+
if (!model.modelID || model.modelID !== model.modelID.trim() || model.body?.model !== undefined && model.body.model !== model.modelID)
|
|
19485
|
+
throw new ModelResidencyError("identity", runtimeLabel);
|
|
19486
|
+
return { runtime, model, baseURL };
|
|
19487
|
+
}
|
|
19488
|
+
function guardedFetch(binding, send, authorized = () => true) {
|
|
19489
|
+
const create = localRuntimeKind(binding.runtime) === "llama-swap" ? createLlamaSwapGuardedFetch : createLemonadeGuardedFetch;
|
|
19490
|
+
return create({
|
|
19491
|
+
...options,
|
|
19492
|
+
fetch: Object.assign((input, init) => {
|
|
19493
|
+
if (disposed || !authorized())
|
|
19494
|
+
throw new Error(nativeHostMessages.missingAdmission);
|
|
19495
|
+
return send(input, init);
|
|
19496
|
+
}, {
|
|
19497
|
+
preconnect: (...args) => send.preconnect?.(...args)
|
|
19498
|
+
}),
|
|
19499
|
+
healthFetch: options.fetch,
|
|
19500
|
+
baseURL: binding.baseURL,
|
|
19501
|
+
modelIDs: new Set([binding.model.modelID])
|
|
19502
|
+
});
|
|
19503
|
+
}
|
|
19504
|
+
function target(model, send, baseURL) {
|
|
19505
|
+
const headers = new Headers(z29.record(z29.string(), z29.string()).parse(model.headers ?? {}));
|
|
19506
|
+
if (typeof model.settings?.apiKey === "string" && !headers.has("authorization"))
|
|
19507
|
+
headers.set("authorization", `Bearer ${model.settings.apiKey}`);
|
|
19508
|
+
return {
|
|
19509
|
+
baseURL,
|
|
19510
|
+
modelID: model.modelID,
|
|
19511
|
+
fetch: Object.assign(async (input, init) => {
|
|
19512
|
+
if (disposed)
|
|
19513
|
+
throw new Error(nativeHostMessages.missingAdmission);
|
|
19514
|
+
const request = new Request(input, init);
|
|
19515
|
+
for (const [name, value] of headers)
|
|
19516
|
+
if (!request.headers.has(name))
|
|
19517
|
+
request.headers.set(name, value);
|
|
19518
|
+
return send(request);
|
|
19519
|
+
}, {
|
|
19520
|
+
preconnect: (...args) => send.preconnect?.(...args)
|
|
19521
|
+
})
|
|
19522
|
+
};
|
|
19523
|
+
}
|
|
19524
|
+
function observeModels(models) {
|
|
19525
|
+
localTargets.clear();
|
|
19526
|
+
return models.map((model) => {
|
|
19527
|
+
if (!allowed(model.providerID, globalMode()))
|
|
19528
|
+
return { ...model, enabled: false };
|
|
19529
|
+
if (!model.enabled)
|
|
19530
|
+
return model;
|
|
19531
|
+
const ref = { providerID: model.providerID, modelID: model.id };
|
|
19532
|
+
const base = model.settings?.baseURL;
|
|
19533
|
+
if (!protects(model.providerID, typeof base === "string" ? base : undefined)) {
|
|
19534
|
+
if (config.local.runtimes.some((runtime) => runtime.enabled && runtime.defaultModel.providerID === model.providerID) && typeof base === "string")
|
|
19535
|
+
localTargets.set(key(ref), target(model, options.fetch, base));
|
|
19536
|
+
return model;
|
|
19537
|
+
}
|
|
19538
|
+
try {
|
|
19539
|
+
const binding = bind(model);
|
|
19540
|
+
localTargets.set(key(ref), target(model, guardedFetch(binding, options.fetch), binding.baseURL));
|
|
19541
|
+
return model;
|
|
19542
|
+
} catch (error) {
|
|
19543
|
+
if (!(error instanceof ModelResidencyError) && !(error instanceof z29.ZodError))
|
|
19544
|
+
throw error;
|
|
19545
|
+
(options.warn ?? console.warn)(modelResidencyMessages.providerDisabled(model.providerID, residentRuntimes.find((runtime) => runtime.defaultModel.providerID === model.providerID)?.kind === "llama-swap" ? "llama-swap" : "Lemonade"));
|
|
19546
|
+
return { ...model, enabled: false };
|
|
19547
|
+
}
|
|
19548
|
+
});
|
|
19549
|
+
}
|
|
19550
|
+
return {
|
|
19551
|
+
providers(editor) {
|
|
19552
|
+
for (const record of editor.list())
|
|
19553
|
+
if (!allowed(record.provider.id, globalMode()))
|
|
19554
|
+
editor.remove(record.provider.id);
|
|
19555
|
+
},
|
|
19556
|
+
transform(editor) {
|
|
19557
|
+
for (const model of editor.list()) {
|
|
19558
|
+
const provider = editor.provider.get(model.providerID)?.provider;
|
|
19559
|
+
const base = model.settings?.baseURL ?? provider?.settings?.baseURL;
|
|
19560
|
+
const pkg = model.package ?? provider?.package;
|
|
19561
|
+
if (protects(model.providerID, typeof base === "string" ? base : undefined) && pkg !== undefined && compatiblePackages.has(pkg))
|
|
19562
|
+
editor.update(model.providerID, model.id, (draft) => {
|
|
19563
|
+
draft.package = NATIVE_RESIDENCY_PROVIDER_PACKAGE;
|
|
19564
|
+
});
|
|
19565
|
+
}
|
|
19566
|
+
},
|
|
19567
|
+
observeModels,
|
|
19568
|
+
sdk(event) {
|
|
19569
|
+
if (!protects(event.model.providerID, typeof event.options.baseURL === "string" ? event.options.baseURL : undefined))
|
|
19570
|
+
return;
|
|
19571
|
+
const factory = bind(event.model);
|
|
19572
|
+
if (event.package !== NATIVE_RESIDENCY_PROVIDER_PACKAGE.slice("aisdk:".length) || typeof event.options.fetch !== "function")
|
|
19573
|
+
throw new Error(nativeHostMessages.transportUnavailable);
|
|
19574
|
+
const upstream = event.options.fetch;
|
|
19575
|
+
const transport = Object.assign((input, init) => {
|
|
19576
|
+
const request = new Request(input, init);
|
|
19577
|
+
return upstream(request, {
|
|
19578
|
+
signal: request.signal,
|
|
19579
|
+
redirect: "error"
|
|
19580
|
+
});
|
|
19581
|
+
}, {
|
|
19582
|
+
preconnect: (...args) => upstream.preconnect?.(...args)
|
|
19583
|
+
});
|
|
19584
|
+
event.options.fetch = Object.assign(async (input, init) => {
|
|
19585
|
+
let request = new Request(input, init);
|
|
19586
|
+
const token = request.headers.get(NATIVE_ADMISSION_HEADER);
|
|
19587
|
+
const admission = token === null ? undefined : admissions.get(token);
|
|
19588
|
+
if (token === null || admission === undefined || admission.model.providerID !== factory.model.providerID || admission.baseURL !== factory.baseURL)
|
|
19589
|
+
throw new Error(nativeHostMessages.missingAdmission);
|
|
19590
|
+
request.headers.delete(NATIVE_ADMISSION_HEADER);
|
|
19591
|
+
if (factory.model.body !== undefined) {
|
|
19592
|
+
let body;
|
|
19593
|
+
try {
|
|
19594
|
+
body = await request.json();
|
|
19595
|
+
} catch {
|
|
19596
|
+
throw new ModelResidencyError("request", label(factory.runtime));
|
|
19597
|
+
}
|
|
19598
|
+
if (body === null || typeof body !== "object" || Array.isArray(body))
|
|
19599
|
+
throw new ModelResidencyError("request", label(factory.runtime));
|
|
19600
|
+
request = new Request(request, {
|
|
19601
|
+
body: JSON.stringify(mergeConfigInputs(body, factory.model.body))
|
|
19602
|
+
});
|
|
19603
|
+
}
|
|
19604
|
+
return guardedFetch(admission, transport, () => admissions.get(token) === admission)(request);
|
|
19605
|
+
}, {
|
|
19606
|
+
preconnect: (...args) => upstream.preconnect?.(...args)
|
|
19607
|
+
});
|
|
19608
|
+
},
|
|
19609
|
+
async modelRequest(event) {
|
|
19610
|
+
if (disposed)
|
|
19611
|
+
throw new Error(nativeHostMessages.missingAdmission);
|
|
19612
|
+
const roleID = await options.resolveAgentRole?.(event.agent) ?? event.agent;
|
|
19613
|
+
const role = isKnownNonWorkerRole(roleID) ? undefined : getRoleProfile(roleID, config.orchestrator?.roles);
|
|
19614
|
+
const policy = role === undefined ? config.orchestrator?.primary : agentExecutionPolicyForRole(role);
|
|
19615
|
+
const mode = resolveExecutionMode({
|
|
19616
|
+
routerMode: globalMode(),
|
|
19617
|
+
agentMode: policy?.executionMode
|
|
19618
|
+
});
|
|
19619
|
+
if (!allowed(event.model.providerID, mode))
|
|
19620
|
+
throw new Error(nativeHostMessages.executionDomainBlocked);
|
|
19621
|
+
if (!protects(event.model.providerID, event.baseURL))
|
|
19622
|
+
return;
|
|
19623
|
+
const model = (await options.readModels()).find((candidate) => candidate.providerID === event.model.providerID && candidate.id === event.model.id && candidate.enabled);
|
|
19624
|
+
if (model === undefined)
|
|
19625
|
+
throw new Error(nativeHostMessages.transportUnavailable);
|
|
19626
|
+
const variant = model.variants.find((candidate) => candidate.id === event.model.variant);
|
|
19627
|
+
const effective = variant === undefined ? model : {
|
|
19628
|
+
...model,
|
|
19629
|
+
settings: { ...model.settings, ...variant.settings },
|
|
19630
|
+
headers: { ...model.headers, ...variant.headers },
|
|
19631
|
+
body: { ...model.body, ...variant.body }
|
|
19632
|
+
};
|
|
19633
|
+
const binding = bind(effective);
|
|
19634
|
+
if (disposed)
|
|
19635
|
+
throw new Error(nativeHostMessages.missingAdmission);
|
|
19636
|
+
const token = (options.newRequestID ?? randomUUID2)();
|
|
19637
|
+
admissions.set(token, {
|
|
19638
|
+
...binding,
|
|
19639
|
+
sessionID: event.sessionID,
|
|
19640
|
+
kind: event.kind
|
|
19641
|
+
});
|
|
19642
|
+
const oldest = admissions.keys().next().value;
|
|
19643
|
+
if (admissions.size > MAX_ADMISSIONS && oldest !== undefined)
|
|
19644
|
+
admissions.delete(oldest);
|
|
19645
|
+
event.headers[NATIVE_ADMISSION_HEADER] = token;
|
|
19646
|
+
},
|
|
19647
|
+
async http(event) {
|
|
19648
|
+
if (protects(event.model.providerID, event.request.url))
|
|
19649
|
+
throw new Error(nativeHostMessages.transportUnavailable);
|
|
19650
|
+
},
|
|
19651
|
+
websocket(event) {
|
|
19652
|
+
const url = new URL(event.url);
|
|
19653
|
+
if (url.protocol === "ws:")
|
|
19654
|
+
url.protocol = "http:";
|
|
19655
|
+
if (url.protocol === "wss:")
|
|
19656
|
+
url.protocol = "https:";
|
|
19657
|
+
if (protects(event.model.providerID, url.href))
|
|
19658
|
+
throw new Error(nativeHostMessages.transportUnavailable);
|
|
19659
|
+
},
|
|
19660
|
+
finished(sessionID) {
|
|
19661
|
+
for (const [token, admission] of admissions)
|
|
19662
|
+
if (admission.sessionID === sessionID)
|
|
19663
|
+
admissions.delete(token);
|
|
19664
|
+
},
|
|
19665
|
+
dispose() {
|
|
19666
|
+
disposed = true;
|
|
19667
|
+
admissions.clear();
|
|
19668
|
+
localTargets.clear();
|
|
19669
|
+
},
|
|
19670
|
+
localTarget(ref) {
|
|
19671
|
+
const value = localTargets.get(key(ref));
|
|
19672
|
+
if (value === undefined)
|
|
19673
|
+
throw new Error(nativeHostMessages.transportUnavailable);
|
|
19674
|
+
return value;
|
|
19675
|
+
}
|
|
19676
|
+
};
|
|
19677
|
+
}
|
|
19678
|
+
|
|
19679
|
+
// src/plugin/nativeSessions.ts
|
|
19680
|
+
import { resolve as resolve9 } from "node:path";
|
|
19681
|
+
import { Agent } from "@opencode/schema/agent";
|
|
19682
|
+
import { Model } from "@opencode/schema/model";
|
|
19683
|
+
import { Session } from "@opencode/schema/session";
|
|
19684
|
+
import { DateTime } from "effect";
|
|
19685
|
+
function sameNativeWorkspace(actual, expected) {
|
|
19686
|
+
return resolve9(actual.directory) === resolve9(expected.directory) && actual.workspaceID === expected.workspaceID;
|
|
19687
|
+
}
|
|
19688
|
+
function nativeAssistantResponse(sessionID, message) {
|
|
19689
|
+
return {
|
|
19690
|
+
info: {
|
|
19691
|
+
id: message.id,
|
|
19692
|
+
sessionID,
|
|
19693
|
+
role: "assistant",
|
|
19694
|
+
mode: message.agent,
|
|
19695
|
+
providerID: message.model.providerID,
|
|
19696
|
+
modelID: message.model.id,
|
|
19697
|
+
...message.cost === undefined ? {} : { cost: message.cost },
|
|
19698
|
+
...message.tokens === undefined ? {} : { tokens: message.tokens },
|
|
19699
|
+
...message.error === undefined ? {} : { error: message.error },
|
|
19700
|
+
time: {
|
|
19701
|
+
created: DateTime.toEpochMillis(message.time.created),
|
|
19702
|
+
...message.time.completed === undefined ? {} : { completed: DateTime.toEpochMillis(message.time.completed) }
|
|
19703
|
+
}
|
|
19704
|
+
},
|
|
19705
|
+
parts: message.content.flatMap((part) => part.type === "text" ? [{ type: "text", text: part.text }] : [])
|
|
19706
|
+
};
|
|
19707
|
+
}
|
|
19708
|
+
function createNativeSessionClient(deps) {
|
|
19709
|
+
const directory = resolve9(deps.directory);
|
|
19710
|
+
const location = {
|
|
19711
|
+
directory,
|
|
19712
|
+
...deps.workspaceID === undefined ? {} : { workspaceID: deps.workspaceID }
|
|
19713
|
+
};
|
|
19714
|
+
function assertDirectory(candidate) {
|
|
19715
|
+
if (candidate !== undefined && resolve9(candidate) !== directory)
|
|
19716
|
+
throw new Error(nativeHostMessages.workspaceMismatch);
|
|
19717
|
+
}
|
|
19718
|
+
async function ownedSession(id, signal) {
|
|
19719
|
+
const info = await deps.run(deps.sessions().get(id), signal === undefined ? undefined : { signal });
|
|
19720
|
+
if (!sameNativeWorkspace(info.location, location))
|
|
19721
|
+
throw new Error(nativeHostMessages.workspaceMismatch);
|
|
19722
|
+
return info;
|
|
19723
|
+
}
|
|
19724
|
+
return {
|
|
19725
|
+
async create(args) {
|
|
19726
|
+
const signal = deps.signal?.();
|
|
19727
|
+
signal?.throwIfAborted();
|
|
19728
|
+
assertDirectory(args.query?.directory);
|
|
19729
|
+
if (args.body?.parentID === undefined)
|
|
19730
|
+
throw new Error(nativeHostMessages.missingBindings);
|
|
19731
|
+
const parentID = Session.ID.make(args.body.parentID);
|
|
19732
|
+
await ownedSession(parentID, signal);
|
|
19733
|
+
const child = await deps.run(deps.sessions().create({
|
|
19734
|
+
parentID,
|
|
19735
|
+
...args.body.title === undefined ? {} : { title: args.body.title }
|
|
19736
|
+
}));
|
|
19737
|
+
if (!sameNativeWorkspace(child.location, location))
|
|
19738
|
+
throw new Error(nativeHostMessages.workspaceMismatch);
|
|
19739
|
+
if (child.parentID !== parentID)
|
|
19740
|
+
throw new Error(nativeHostMessages.missingBindings);
|
|
19741
|
+
signal?.throwIfAborted();
|
|
19742
|
+
return { data: { id: child.id }, error: undefined };
|
|
19743
|
+
},
|
|
19744
|
+
async prompt(args) {
|
|
19745
|
+
const parentSignal = deps.signal?.();
|
|
19746
|
+
const signal = parentSignal === undefined ? args.signal : args.signal === undefined ? parentSignal : AbortSignal.any([parentSignal, args.signal]);
|
|
19747
|
+
const sessionID = Session.ID.make(args.path.id);
|
|
19748
|
+
await ownedSession(sessionID, signal);
|
|
19749
|
+
const run = (effect) => deps.run(effect, signal === undefined ? undefined : { signal });
|
|
19750
|
+
const sessions = deps.sessions();
|
|
19751
|
+
try {
|
|
19752
|
+
if (args.body.agent !== undefined)
|
|
19753
|
+
await run(sessions.switchAgent({
|
|
19754
|
+
sessionID,
|
|
19755
|
+
agent: Agent.ID.make(args.body.agent)
|
|
19756
|
+
}));
|
|
19757
|
+
if (args.body.model !== undefined)
|
|
19758
|
+
await run(sessions.switchModel({
|
|
19759
|
+
sessionID,
|
|
19760
|
+
model: Model.Ref.parse(`${args.body.model.providerID}/${args.body.model.modelID}`)
|
|
19761
|
+
}));
|
|
19762
|
+
if (args.body.system !== undefined)
|
|
19763
|
+
deps.systemPrompts.set(sessionID, args.body.system);
|
|
19764
|
+
await run(sessions.prompt({
|
|
19765
|
+
sessionID,
|
|
19766
|
+
text: args.body.parts.map((part) => part.text).join(`
|
|
19767
|
+
`)
|
|
19768
|
+
}));
|
|
19769
|
+
await run(sessions.wait(sessionID));
|
|
19770
|
+
const final = await ownedSession(sessionID, signal);
|
|
19771
|
+
const messages = await run(sessions.messages({ sessionID, limit: 100 }));
|
|
19772
|
+
const assistant = [...messages].reverse().find((message) => message.type === "assistant");
|
|
19773
|
+
if (final.outcome === "interrupted")
|
|
19774
|
+
throw new Error(nativeHostMessages.executionInterrupted);
|
|
19775
|
+
if (final.outcome !== "succeeded" || assistant?.error !== undefined)
|
|
19776
|
+
throw new Error(nativeHostMessages.executionFailed);
|
|
19777
|
+
if (assistant?.time.completed === undefined)
|
|
19778
|
+
throw new Error(nativeHostMessages.noCompletedResponse);
|
|
19779
|
+
return {
|
|
19780
|
+
data: nativeAssistantResponse(sessionID, assistant),
|
|
19781
|
+
error: undefined
|
|
19782
|
+
};
|
|
19783
|
+
} finally {
|
|
19784
|
+
if (signal?.aborted)
|
|
19785
|
+
await deps.run(sessions.interrupt(sessionID, { resume: false }));
|
|
19786
|
+
}
|
|
19787
|
+
},
|
|
19788
|
+
async abort(args) {
|
|
19789
|
+
assertDirectory(args.query?.directory);
|
|
19790
|
+
const id = Session.ID.make(args.path.id);
|
|
19791
|
+
await ownedSession(id, args.signal);
|
|
19792
|
+
const options = args.signal === undefined ? undefined : { signal: args.signal };
|
|
19793
|
+
await deps.run(deps.sessions().interrupt(id, { resume: false }), options);
|
|
19794
|
+
const active = await deps.run(deps.sessions().active, options);
|
|
19795
|
+
return { data: !active.has(id), error: undefined };
|
|
19796
|
+
},
|
|
19797
|
+
async status(args) {
|
|
19798
|
+
assertDirectory(args?.query?.directory);
|
|
19799
|
+
const options = args?.signal == null ? undefined : { signal: args.signal };
|
|
19800
|
+
const sessions = deps.sessions();
|
|
19801
|
+
const active = await deps.run(sessions.active, options);
|
|
19802
|
+
const entries = [];
|
|
19803
|
+
for (const id of active) {
|
|
19804
|
+
const info = await deps.run(sessions.get(id), options);
|
|
19805
|
+
if (sameNativeWorkspace(info.location, location))
|
|
19806
|
+
entries.push([id, { type: "busy" }]);
|
|
19807
|
+
}
|
|
19808
|
+
return { data: Object.fromEntries(entries), error: undefined };
|
|
19809
|
+
}
|
|
19810
|
+
};
|
|
19811
|
+
}
|
|
19812
|
+
|
|
19813
|
+
// src/plugin/nativeHost.ts
|
|
19814
|
+
var executionEvent = z30.preprocess(only(["type", "location", "data"]), z30.object({
|
|
19815
|
+
type: z30.enum([
|
|
19816
|
+
"session.created",
|
|
19817
|
+
"session.deleted",
|
|
19818
|
+
"session.execution.started",
|
|
19819
|
+
"session.execution.succeeded",
|
|
19820
|
+
"session.execution.failed",
|
|
19821
|
+
"session.execution.interrupted",
|
|
19822
|
+
"session.step.ended",
|
|
19823
|
+
"session.step.failed"
|
|
19824
|
+
]),
|
|
19825
|
+
location: z30.preprocess(only(["directory", "workspaceID"]), z30.object({
|
|
19826
|
+
directory: z30.string(),
|
|
19827
|
+
workspaceID: z30.string().optional()
|
|
19828
|
+
}).strict()).optional(),
|
|
19829
|
+
data: z30.preprocess(only(["sessionID", "assistantMessageID"]), z30.object({
|
|
19830
|
+
sessionID: z30.string(),
|
|
19831
|
+
assistantMessageID: z30.string().optional()
|
|
19832
|
+
}).strict())
|
|
19833
|
+
}).strict());
|
|
19834
|
+
var nativeBindings = Effect.fn("openteam.nativeBindings")(function* () {
|
|
19835
|
+
const sessions = yield* Effect.serviceOption(NativeSessions);
|
|
19836
|
+
const permissions = yield* Effect.serviceOption(NativePermissions);
|
|
19837
|
+
const agents = yield* Effect.serviceOption(NativeAgents);
|
|
19838
|
+
const locations = yield* Effect.serviceOption(NativeLocations);
|
|
19839
|
+
if (Option.isNone(sessions) || Option.isNone(permissions) || Option.isNone(agents) || Option.isNone(locations))
|
|
19840
|
+
return yield* Effect.die(new Error(nativeHostMessages.missingBindings));
|
|
19841
|
+
const server = yield* Effect.serviceOption(NativeServerInfo);
|
|
19842
|
+
const auth = yield* Effect.serviceOption(NativeServerAuth);
|
|
19843
|
+
return {
|
|
19844
|
+
sessions: sessions.value,
|
|
19845
|
+
permissions: permissions.value,
|
|
19846
|
+
agents: agents.value,
|
|
19847
|
+
locations: locations.value,
|
|
19848
|
+
...Option.isNone(server) ? {} : { server: server.value },
|
|
19849
|
+
...Option.isNone(auth) ? {} : { auth: auth.value }
|
|
19850
|
+
};
|
|
19851
|
+
});
|
|
19852
|
+
function nativeExec(directory) {
|
|
19853
|
+
return (command, args) => new Promise((resolveOutput, reject) => {
|
|
19854
|
+
execFile3(command, [...args], { cwd: directory }, (error, stdout, stderr) => {
|
|
19855
|
+
if (error !== null && typeof error.code !== "number") {
|
|
19856
|
+
reject(error);
|
|
19857
|
+
return;
|
|
19858
|
+
}
|
|
19859
|
+
resolveOutput({
|
|
19860
|
+
exitCode: typeof error?.code === "number" ? error.code : 0,
|
|
19861
|
+
stdout,
|
|
19862
|
+
stderr
|
|
19863
|
+
});
|
|
19864
|
+
});
|
|
19865
|
+
});
|
|
19866
|
+
}
|
|
19867
|
+
function legacyModel(ref) {
|
|
19868
|
+
return { providerID: ref.providerID, modelID: ref.id };
|
|
19869
|
+
}
|
|
19870
|
+
function createNativePluginEffect(factory) {
|
|
19871
|
+
return Effect.fn("openteam.native")(function* (ctx) {
|
|
19872
|
+
if (!isSupportedNativeOpencodeVersion(ctx.app.version))
|
|
19873
|
+
return yield* Effect.die(new Error(nativeHostMessages.unsupportedVersion(ctx.app.version)));
|
|
19874
|
+
const version = ctx.app.version;
|
|
19875
|
+
const effectContext = yield* Effect.context();
|
|
19876
|
+
const directory = resolve10(ctx.location.directory);
|
|
19877
|
+
let bindings;
|
|
19878
|
+
const run = (effect, options) => {
|
|
19879
|
+
const current = bindings;
|
|
19880
|
+
const bound = current === undefined ? effect : effect.pipe(Effect.provideService(NativeSessions, current.sessions), Effect.provideService(NativePermissions, current.permissions), Effect.provideService(NativeAgents, current.agents), Effect.provideService(NativeLocations, current.locations));
|
|
19881
|
+
return Effect.runPromiseWith(effectContext)(bound, options);
|
|
19882
|
+
};
|
|
19883
|
+
let config;
|
|
19884
|
+
let residency;
|
|
19885
|
+
const systemPrompts = new Map;
|
|
19886
|
+
const toolSignals = new AsyncLocalStorage;
|
|
19887
|
+
const remember = (next) => {
|
|
19888
|
+
bindings = { ...bindings, ...next };
|
|
19889
|
+
};
|
|
19890
|
+
const requiredBindings = () => {
|
|
19891
|
+
if (bindings === undefined)
|
|
19892
|
+
throw new Error(nativeHostMessages.missingBindings);
|
|
19893
|
+
return bindings;
|
|
19894
|
+
};
|
|
19895
|
+
const assertWorkspace = (candidate) => {
|
|
19896
|
+
if (!sameNativeWorkspace(candidate, ctx.location))
|
|
19897
|
+
throw new Error(nativeHostMessages.workspaceMismatch);
|
|
19898
|
+
};
|
|
19899
|
+
const session = createNativeSessionClient({
|
|
19900
|
+
directory,
|
|
19901
|
+
...ctx.location.workspaceID === undefined ? {} : { workspaceID: ctx.location.workspaceID },
|
|
19902
|
+
sessions: () => requiredBindings().sessions,
|
|
19903
|
+
run,
|
|
19904
|
+
systemPrompts,
|
|
19905
|
+
signal: () => toolSignals.getStore()
|
|
19906
|
+
});
|
|
19907
|
+
const client = {
|
|
19908
|
+
session,
|
|
19909
|
+
app: {
|
|
19910
|
+
async agents() {
|
|
19911
|
+
const result = await run(ctx.agent.list());
|
|
19912
|
+
return {
|
|
19913
|
+
data: result.data.map((agent) => ({ name: agent.id })),
|
|
19914
|
+
error: undefined
|
|
19915
|
+
};
|
|
19916
|
+
},
|
|
19917
|
+
async log(input) {
|
|
19918
|
+
const message = input.body?.message ?? nativeHostMessages.toolFailed;
|
|
19919
|
+
await run(input.body?.level === "error" ? Effect.logError(message) : input.body?.level === "warn" ? Effect.logWarning(message) : Effect.logInfo(message));
|
|
19920
|
+
}
|
|
19921
|
+
},
|
|
19922
|
+
instance: {
|
|
19923
|
+
async dispose(input) {
|
|
19924
|
+
assertWorkspace({
|
|
19925
|
+
...ctx.location,
|
|
19926
|
+
directory: input.query?.directory ?? directory
|
|
19927
|
+
});
|
|
19928
|
+
await run(requiredBindings().locations.invalidate({
|
|
19929
|
+
directory: ctx.location.directory,
|
|
19930
|
+
...ctx.location.workspaceID === undefined ? {} : { workspaceID: ctx.location.workspaceID }
|
|
19931
|
+
}), input.signal == null ? undefined : { signal: input.signal });
|
|
19932
|
+
return { data: true, error: undefined };
|
|
19933
|
+
}
|
|
19934
|
+
}
|
|
19935
|
+
};
|
|
19936
|
+
const hooks = yield* Effect.promise(() => factory({
|
|
19937
|
+
directory,
|
|
19938
|
+
worktree: ctx.location.project.directory,
|
|
19939
|
+
client,
|
|
19940
|
+
exec: nativeExec(directory),
|
|
19941
|
+
serverUrl: () => {
|
|
19942
|
+
const url = bindings?.server?.urls().find((value) => {
|
|
19943
|
+
if (!URL.canParse(value))
|
|
19944
|
+
return false;
|
|
19945
|
+
return ["127.0.0.1", "localhost", "[::1]"].includes(new URL(value).hostname);
|
|
19946
|
+
});
|
|
19947
|
+
return url === undefined ? undefined : new URL(url);
|
|
19948
|
+
},
|
|
19949
|
+
opencodeVersion: async () => version,
|
|
19950
|
+
listConfiguredInventory: async () => {
|
|
19951
|
+
if (config === undefined || residency === undefined)
|
|
19952
|
+
throw new Error(nativeHostMessages.missingBindings);
|
|
19953
|
+
const models = residency.observeModels((await run(ctx.model.list())).data);
|
|
19954
|
+
return nativeConfiguredInventory(models, config);
|
|
19955
|
+
},
|
|
19956
|
+
consoleEnvironment: () => {
|
|
19957
|
+
const auth = bindings?.auth;
|
|
19958
|
+
return {
|
|
19959
|
+
...process.env,
|
|
19960
|
+
BUN_BE_BUN: "1",
|
|
19961
|
+
OPENCODE_SERVER_USERNAME: auth?.username,
|
|
19962
|
+
OPENCODE_SERVER_PASSWORD: auth && Option.isSome(auth.password) ? auth.password.value : undefined
|
|
19963
|
+
};
|
|
19964
|
+
},
|
|
19965
|
+
createResidencyGuard: (runtimeConfig, options) => {
|
|
19966
|
+
config = runtimeConfig;
|
|
19967
|
+
residency = createNativeModelResidencyGuard(runtimeConfig, {
|
|
19968
|
+
...options,
|
|
19969
|
+
readModels: async () => (await run(ctx.model.list())).data
|
|
19970
|
+
});
|
|
19971
|
+
return residency;
|
|
19972
|
+
}
|
|
19973
|
+
}, ctx.options));
|
|
19974
|
+
const guard = residency;
|
|
19975
|
+
if (guard === undefined)
|
|
19976
|
+
return yield* Effect.die(new Error(nativeHostMessages.missingBindings));
|
|
19977
|
+
const chatMessage = hooks["chat.message"];
|
|
19978
|
+
const tools = hooks.tool;
|
|
19979
|
+
if (chatMessage === undefined || tools === undefined)
|
|
19980
|
+
return yield* Effect.die(new Error(nativeHostMessages.missingBindings));
|
|
19981
|
+
yield* Effect.addFinalizer(() => Effect.promise(async () => {
|
|
19982
|
+
guard.dispose();
|
|
19983
|
+
systemPrompts.clear();
|
|
19984
|
+
await hooks.dispose?.();
|
|
19985
|
+
}));
|
|
19986
|
+
yield* ctx.provider.transform(guard.providers);
|
|
19987
|
+
yield* ctx.model.transform(guard.transform);
|
|
19988
|
+
yield* ctx.aisdk.hook("sdk", (event) => Effect.sync(() => guard.sdk(event)));
|
|
19989
|
+
yield* ctx.session.hook("model.request", (event) => Effect.promise(() => guard.modelRequest(event)));
|
|
19990
|
+
yield* ctx.session.hook("http.request", (event) => Effect.promise(() => guard.http(event)));
|
|
19991
|
+
yield* ctx.session.hook("experimental.ws.handshake", (event) => Effect.sync(() => guard.websocket(event)));
|
|
19992
|
+
yield* ctx.session.hook("context", (event) => Effect.sync(() => {
|
|
19993
|
+
const system = systemPrompts.get(event.sessionID);
|
|
19994
|
+
if (system !== undefined)
|
|
19995
|
+
event.system.push({ type: "text", text: system });
|
|
19996
|
+
}));
|
|
19997
|
+
yield* ctx.session.hook("prompt", Effect.fn("openteam.nativePrompt")(function* (event) {
|
|
19998
|
+
const currentBindings = yield* nativeBindings();
|
|
19999
|
+
const current = yield* ctx.session.get({ sessionID: event.sessionID }).pipe(Effect.orDie);
|
|
20000
|
+
assertWorkspace(current.location);
|
|
20001
|
+
remember(currentBindings);
|
|
20002
|
+
const agent = yield* currentBindings.agents.resolve(current.agent).pipe(Effect.orDie);
|
|
20003
|
+
if (agent === undefined)
|
|
20004
|
+
return yield* Effect.die(new Error(nativeHostMessages.unknownAgent));
|
|
20005
|
+
const selected = current.model ?? (yield* ctx.model.default().pipe(Effect.orDie)).data ?? (yield* ctx.model.list().pipe(Effect.orDie)).data[0];
|
|
20006
|
+
if (selected === undefined)
|
|
20007
|
+
return yield* Effect.die(new Error(nativeHostMessages.noAvailableModel));
|
|
20008
|
+
const created = yield* Clock.currentTimeMillis;
|
|
20009
|
+
const output = {
|
|
20010
|
+
message: {
|
|
20011
|
+
id: event.messageID,
|
|
20012
|
+
sessionID: event.sessionID,
|
|
20013
|
+
role: "user",
|
|
20014
|
+
time: { created },
|
|
20015
|
+
agent: agent.id,
|
|
20016
|
+
model: legacyModel(selected)
|
|
20017
|
+
},
|
|
20018
|
+
parts: [
|
|
20019
|
+
{
|
|
20020
|
+
id: event.messageID,
|
|
20021
|
+
sessionID: event.sessionID,
|
|
20022
|
+
messageID: event.messageID,
|
|
20023
|
+
type: "text",
|
|
20024
|
+
text: event.prompt.text
|
|
20025
|
+
}
|
|
20026
|
+
]
|
|
20027
|
+
};
|
|
20028
|
+
yield* Effect.promise(() => chatMessage({
|
|
20029
|
+
sessionID: event.sessionID,
|
|
20030
|
+
messageID: event.messageID,
|
|
20031
|
+
agent: agent.id,
|
|
20032
|
+
...current.model === undefined ? {} : { model: legacyModel(current.model) }
|
|
20033
|
+
}, output));
|
|
20034
|
+
const routed = output.message.model;
|
|
20035
|
+
yield* ctx.session.switchModel({
|
|
20036
|
+
sessionID: event.sessionID,
|
|
20037
|
+
model: {
|
|
20038
|
+
...Model2.Ref.parse(`${routed.providerID}/${routed.modelID}`),
|
|
20039
|
+
...current.model?.providerID === routed.providerID && current.model.id === routed.modelID && current.model.variant !== undefined ? { variant: current.model.variant } : {}
|
|
20040
|
+
}
|
|
20041
|
+
}).pipe(Effect.orDie);
|
|
20042
|
+
const part = output.parts[0];
|
|
20043
|
+
if (part?.type === "text")
|
|
20044
|
+
event.prompt.text = part.text;
|
|
20045
|
+
}));
|
|
20046
|
+
yield* ctx.tool.transform((editor) => {
|
|
20047
|
+
for (const [name, definition] of Object.entries(tools)) {
|
|
20048
|
+
const input = legacyTool.schema.object(definition.args);
|
|
20049
|
+
editor.add({
|
|
20050
|
+
name,
|
|
20051
|
+
description: definition.description,
|
|
20052
|
+
input: legacyTool.schema.toJSONSchema(input, { io: "input" }),
|
|
20053
|
+
options: { codemode: false },
|
|
20054
|
+
execute: Effect.fn("openteam.nativeTool")(function* (_input, toolContext) {
|
|
20055
|
+
const current = requiredBindings();
|
|
20056
|
+
const parent = yield* current.sessions.get(toolContext.sessionID).pipe(Effect.orDie);
|
|
20057
|
+
assertWorkspace(parent.location);
|
|
20058
|
+
remember(current);
|
|
20059
|
+
return yield* Effect.tryPromise(async (signal) => {
|
|
20060
|
+
const progress = [];
|
|
20061
|
+
const context = {
|
|
20062
|
+
sessionID: toolContext.sessionID,
|
|
20063
|
+
messageID: toolContext.messageID,
|
|
20064
|
+
agent: toolContext.agent,
|
|
20065
|
+
directory,
|
|
20066
|
+
worktree: ctx.location.project.directory,
|
|
20067
|
+
abort: signal,
|
|
20068
|
+
metadata: (update) => {
|
|
20069
|
+
progress.push(run(toolContext.progress({
|
|
20070
|
+
...update.metadata,
|
|
20071
|
+
...update.title === undefined ? {} : { title: update.title }
|
|
20072
|
+
}), { signal }).then(() => ({}), (error) => ({ error })));
|
|
20073
|
+
},
|
|
20074
|
+
ask: async (request) => {
|
|
20075
|
+
await run(current.permissions.assert({
|
|
20076
|
+
sessionID: toolContext.sessionID,
|
|
20077
|
+
agent: toolContext.agent,
|
|
20078
|
+
action: request.permission,
|
|
20079
|
+
resources: request.patterns,
|
|
20080
|
+
save: request.always,
|
|
20081
|
+
metadata: request.metadata,
|
|
20082
|
+
source: {
|
|
20083
|
+
type: "tool",
|
|
20084
|
+
messageID: toolContext.messageID,
|
|
20085
|
+
id: toolContext.id
|
|
20086
|
+
}
|
|
20087
|
+
}), { signal });
|
|
20088
|
+
}
|
|
20089
|
+
};
|
|
20090
|
+
const result = await toolSignals.run(signal, () => definition.execute(input.parse(_input), context));
|
|
20091
|
+
const failed = (await Promise.all(progress)).find((entry) => entry.error !== undefined);
|
|
20092
|
+
if (failed)
|
|
20093
|
+
throw failed.error;
|
|
20094
|
+
if (typeof result === "string")
|
|
20095
|
+
return { content: result };
|
|
20096
|
+
return {
|
|
20097
|
+
content: [
|
|
20098
|
+
{ type: "text", text: result.output },
|
|
20099
|
+
...(result.attachments ?? []).map((attachment) => ({
|
|
20100
|
+
type: "file",
|
|
20101
|
+
uri: attachment.url,
|
|
20102
|
+
mime: attachment.mime,
|
|
20103
|
+
...attachment.filename === undefined ? {} : { name: attachment.filename }
|
|
20104
|
+
}))
|
|
20105
|
+
],
|
|
20106
|
+
metadata: {
|
|
20107
|
+
...result.metadata,
|
|
20108
|
+
...result.title === undefined ? {} : { title: result.title }
|
|
20109
|
+
}
|
|
20110
|
+
};
|
|
20111
|
+
}).pipe(Effect.mapError(() => new Tool.Error({ message: nativeHostMessages.toolFailed })));
|
|
20112
|
+
})
|
|
20113
|
+
});
|
|
20114
|
+
}
|
|
20115
|
+
});
|
|
20116
|
+
yield* ctx.tool.hook("execute.before", (event) => Effect.promise(() => hooks["tool.execute.before"]?.({ tool: event.tool, sessionID: event.sessionID, callID: event.id }, { args: event.input }) ?? Promise.resolve()));
|
|
20117
|
+
yield* ctx.tool.hook("execute.after", (event) => Effect.promise(() => hooks["tool.execute.after"]?.({
|
|
20118
|
+
tool: event.tool,
|
|
20119
|
+
sessionID: event.sessionID,
|
|
20120
|
+
callID: event.id,
|
|
20121
|
+
args: event.input
|
|
20122
|
+
}, { title: event.tool, output: "", metadata: {} }) ?? Promise.resolve()));
|
|
20123
|
+
yield* ctx.event.subscribe().pipe(Stream.runForEach((event) => Effect.tryPromise(async () => {
|
|
20124
|
+
const parsed = executionEvent.safeParse(event);
|
|
20125
|
+
if (!parsed.success)
|
|
20126
|
+
return;
|
|
20127
|
+
const value = parsed.data;
|
|
20128
|
+
if (value.location !== undefined) {
|
|
20129
|
+
if (!sameNativeWorkspace(value.location, ctx.location))
|
|
20130
|
+
return;
|
|
20131
|
+
} else if (value.type !== "session.deleted") {
|
|
20132
|
+
const info = await run(ctx.session.get({
|
|
20133
|
+
sessionID: Session2.ID.make(value.data.sessionID)
|
|
20134
|
+
}));
|
|
20135
|
+
if (!sameNativeWorkspace(info.location, ctx.location))
|
|
20136
|
+
return;
|
|
20137
|
+
} else
|
|
20138
|
+
return;
|
|
20139
|
+
const sessionID = value.data.sessionID;
|
|
20140
|
+
if (value.type === "session.deleted") {
|
|
20141
|
+
guard.finished(sessionID);
|
|
20142
|
+
systemPrompts.delete(sessionID);
|
|
20143
|
+
}
|
|
20144
|
+
let mapped;
|
|
20145
|
+
if (value.type === "session.created" || value.type === "session.deleted") {
|
|
20146
|
+
mapped = {
|
|
20147
|
+
type: value.type,
|
|
20148
|
+
properties: { info: { id: sessionID } }
|
|
20149
|
+
};
|
|
20150
|
+
} else if (value.type === "session.execution.started") {
|
|
20151
|
+
mapped = {
|
|
20152
|
+
type: "session.status",
|
|
20153
|
+
properties: { sessionID, status: { type: "busy" } }
|
|
20154
|
+
};
|
|
20155
|
+
} else if (value.type === "session.step.ended" || value.type === "session.step.failed") {
|
|
20156
|
+
if (bindings === undefined)
|
|
20157
|
+
return;
|
|
20158
|
+
const messages = await run(bindings.sessions.messages({
|
|
20159
|
+
sessionID: Session2.ID.make(sessionID),
|
|
20160
|
+
limit: 100
|
|
20161
|
+
}));
|
|
20162
|
+
const message = messages.find((candidate) => candidate.id === value.data.assistantMessageID);
|
|
20163
|
+
if (message?.type !== "assistant")
|
|
20164
|
+
return;
|
|
20165
|
+
mapped = {
|
|
20166
|
+
type: "message.updated",
|
|
20167
|
+
properties: {
|
|
20168
|
+
info: nativeAssistantResponse(sessionID, message).info
|
|
20169
|
+
}
|
|
20170
|
+
};
|
|
20171
|
+
} else {
|
|
20172
|
+
systemPrompts.delete(sessionID);
|
|
20173
|
+
guard.finished(sessionID);
|
|
20174
|
+
if (value.type !== "session.execution.succeeded")
|
|
20175
|
+
await hooks.event?.({
|
|
20176
|
+
event: { type: "session.error", properties: { sessionID } }
|
|
20177
|
+
});
|
|
20178
|
+
mapped = { type: "session.idle", properties: { sessionID } };
|
|
20179
|
+
}
|
|
20180
|
+
await hooks.event?.({ event: mapped });
|
|
20181
|
+
}).pipe(Effect.catch(() => Effect.logError(nativeHostMessages.eventCaptureFailed)))), Effect.tapCause(() => Effect.logError(nativeHostMessages.eventCaptureFailed)), Effect.forkScoped);
|
|
20182
|
+
});
|
|
20183
|
+
}
|
|
20184
|
+
|
|
19246
20185
|
// src/plugin/orchestrateTool.ts
|
|
19247
20186
|
import { tool as tool5 } from "@opencode-ai/plugin";
|
|
19248
|
-
import { z as
|
|
20187
|
+
import { z as z32 } from "zod";
|
|
19249
20188
|
|
|
19250
20189
|
// src/orchestrator/coordinator.ts
|
|
19251
|
-
import { z as
|
|
20190
|
+
import { z as z31 } from "zod";
|
|
19252
20191
|
|
|
19253
20192
|
// src/orchestrator/nodeIteration.ts
|
|
19254
20193
|
var DEFAULT_MAX_RETRIES = 2;
|
|
@@ -19722,7 +20661,7 @@ function buildRecord(input, decision2, subsession, deps, decisionID, batchID) {
|
|
|
19722
20661
|
}
|
|
19723
20662
|
return record;
|
|
19724
20663
|
}
|
|
19725
|
-
var TelemetryFailureClassSchema =
|
|
20664
|
+
var TelemetryFailureClassSchema = z31.enum([
|
|
19726
20665
|
"create-rejected",
|
|
19727
20666
|
"create-no-id",
|
|
19728
20667
|
"prompt-rejected",
|
|
@@ -20148,10 +21087,10 @@ function uniqueModels(models) {
|
|
|
20148
21087
|
const seen = new Set;
|
|
20149
21088
|
const unique = [];
|
|
20150
21089
|
for (const model of models) {
|
|
20151
|
-
const
|
|
20152
|
-
if (seen.has(
|
|
21090
|
+
const key2 = modelKey4(model);
|
|
21091
|
+
if (seen.has(key2))
|
|
20153
21092
|
continue;
|
|
20154
|
-
seen.add(
|
|
21093
|
+
seen.add(key2);
|
|
20155
21094
|
unique.push(model);
|
|
20156
21095
|
}
|
|
20157
21096
|
return unique;
|
|
@@ -20539,7 +21478,7 @@ async function runRoleTasks(inputs, deps, options = {}) {
|
|
|
20539
21478
|
var _pluginWarnedRoles = new Set;
|
|
20540
21479
|
var EMPTY_ROLE_ID_SET = new Set;
|
|
20541
21480
|
var SAFE_ROLE_ID = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
20542
|
-
var RoleIDSchema =
|
|
21481
|
+
var RoleIDSchema = z32.string().min(1).superRefine((roleID, ctx) => {
|
|
20543
21482
|
if (!SAFE_ROLE_ID.test(roleID)) {
|
|
20544
21483
|
ctx.addIssue({
|
|
20545
21484
|
code: "custom",
|
|
@@ -20547,16 +21486,16 @@ var RoleIDSchema = z30.string().min(1).superRefine((roleID, ctx) => {
|
|
|
20547
21486
|
});
|
|
20548
21487
|
}
|
|
20549
21488
|
});
|
|
20550
|
-
var RoleAssignmentSchema =
|
|
21489
|
+
var RoleAssignmentSchema = z32.object({
|
|
20551
21490
|
roleID: RoleIDSchema.describe("Role identifier from the roster"),
|
|
20552
|
-
prompt:
|
|
20553
|
-
title:
|
|
20554
|
-
dependsOn:
|
|
21491
|
+
prompt: z32.string().min(1).describe("Work prompt for this role"),
|
|
21492
|
+
title: z32.string().min(1).optional().describe("Human-readable title"),
|
|
21493
|
+
dependsOn: z32.array(RoleIDSchema).optional().describe("Role IDs this assignment depends on (DAG edges)")
|
|
20555
21494
|
}).strict();
|
|
20556
|
-
var OrchestratePayloadSchema =
|
|
20557
|
-
assignments:
|
|
20558
|
-
parentSessionID:
|
|
20559
|
-
directory:
|
|
21495
|
+
var OrchestratePayloadSchema = z32.object({
|
|
21496
|
+
assignments: z32.array(RoleAssignmentSchema).min(1).describe("Role assignments to distribute"),
|
|
21497
|
+
parentSessionID: z32.string().min(1).optional().describe(PARENT_SESSION_DESCRIPTION),
|
|
21498
|
+
directory: z32.string().min(1).optional().describe("Working directory override")
|
|
20560
21499
|
}).strict();
|
|
20561
21500
|
function validateAssignmentDependencies(assignments) {
|
|
20562
21501
|
const ids = new Set;
|
|
@@ -20617,14 +21556,14 @@ function validateAssignmentDependencies(assignments) {
|
|
|
20617
21556
|
function isRecord7(value) {
|
|
20618
21557
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20619
21558
|
}
|
|
20620
|
-
function nestedRecord2(value,
|
|
20621
|
-
const nested = value[
|
|
21559
|
+
function nestedRecord2(value, key2) {
|
|
21560
|
+
const nested = value[key2];
|
|
20622
21561
|
return isRecord7(nested) ? nested : undefined;
|
|
20623
21562
|
}
|
|
20624
21563
|
function numberField(records, keys) {
|
|
20625
21564
|
for (const record of records) {
|
|
20626
|
-
for (const
|
|
20627
|
-
const value = record[
|
|
21565
|
+
for (const key2 of keys) {
|
|
21566
|
+
const value = record[key2];
|
|
20628
21567
|
if (typeof value === "number" && Number.isInteger(value)) {
|
|
20629
21568
|
return value;
|
|
20630
21569
|
}
|
|
@@ -20634,8 +21573,8 @@ function numberField(records, keys) {
|
|
|
20634
21573
|
}
|
|
20635
21574
|
function booleanField(records, keys) {
|
|
20636
21575
|
for (const record of records) {
|
|
20637
|
-
for (const
|
|
20638
|
-
const value = record[
|
|
21576
|
+
for (const key2 of keys) {
|
|
21577
|
+
const value = record[key2];
|
|
20639
21578
|
if (typeof value === "boolean") {
|
|
20640
21579
|
return value;
|
|
20641
21580
|
}
|
|
@@ -20646,8 +21585,8 @@ function booleanField(records, keys) {
|
|
|
20646
21585
|
function boundedErrorTokens(records) {
|
|
20647
21586
|
const tokens = [];
|
|
20648
21587
|
for (const record of records) {
|
|
20649
|
-
for (const
|
|
20650
|
-
const value = record[
|
|
21588
|
+
for (const key2 of ["name", "code", "type", "message"]) {
|
|
21589
|
+
const value = record[key2];
|
|
20651
21590
|
if (typeof value === "string" && value.length <= 100) {
|
|
20652
21591
|
tokens.push(value.toLowerCase());
|
|
20653
21592
|
}
|
|
@@ -21185,6 +22124,8 @@ function createOrchestrateTool(deps) {
|
|
|
21185
22124
|
}
|
|
21186
22125
|
const parentOverrideIgnored = parsed.data.parentSessionID !== undefined && parsed.data.parentSessionID !== context.sessionID;
|
|
21187
22126
|
parsed.data.parentSessionID = context.sessionID;
|
|
22127
|
+
if (parsed.data.directory === undefined && context.directory !== undefined)
|
|
22128
|
+
parsed.data.directory = context.directory;
|
|
21188
22129
|
const depError = validateAssignmentDependencies(parsed.data.assignments);
|
|
21189
22130
|
if (depError !== undefined) {
|
|
21190
22131
|
return dependencyValidationError(depError.code, depError.detail);
|
|
@@ -21292,7 +22233,7 @@ ${advisory}`;
|
|
|
21292
22233
|
|
|
21293
22234
|
// src/plugin/registerCastTool.ts
|
|
21294
22235
|
import { tool as tool6 } from "@opencode-ai/plugin";
|
|
21295
|
-
import { z as
|
|
22236
|
+
import { z as z33 } from "zod";
|
|
21296
22237
|
|
|
21297
22238
|
// src/messages/rosterSummary.ts
|
|
21298
22239
|
var ROSTER_SUMMARY_HEADING = "Registered team model policies";
|
|
@@ -21408,12 +22349,12 @@ function createTeamPreparation(deps) {
|
|
|
21408
22349
|
OpenTeamConfigSchema.parse(migrateConfig(baseRaw));
|
|
21409
22350
|
const overlay = overlayBefore === undefined ? undefined : parseConfigFileJson(DEFAULT_LOCAL_OVERLAY_PATH, overlayBefore);
|
|
21410
22351
|
const options = configOptionsFromPluginOptions(deps.options);
|
|
21411
|
-
const
|
|
22352
|
+
const resolve11 = (raw) => {
|
|
21412
22353
|
const config = validateConfigInput(TEAM_PREPARATION_CONFIG, mergeConfigInputs(mergeConfigInputs(raw, options), overlay));
|
|
21413
22354
|
assertEffectiveConfigModelDomains(config);
|
|
21414
22355
|
return config;
|
|
21415
22356
|
};
|
|
21416
|
-
const current =
|
|
22357
|
+
const current = resolve11(baseRaw);
|
|
21417
22358
|
const live = liveConfig ?? current;
|
|
21418
22359
|
if (resolveExecutionMode({
|
|
21419
22360
|
routerMode: current.router.executionMode,
|
|
@@ -21435,9 +22376,9 @@ function createTeamPreparation(deps) {
|
|
|
21435
22376
|
]))
|
|
21436
22377
|
}
|
|
21437
22378
|
});
|
|
21438
|
-
const effective =
|
|
22379
|
+
const effective = resolve11(candidate);
|
|
21439
22380
|
const requestedProfiles = new Set(roster.entries.filter((entry) => !isKnownNonWorkerRole(entry.roleID) && getRoleProfile(entry.roleID, live.orchestrator?.roles) === undefined).map((entry) => getRoleProfile(entry.roleID, effective.orchestrator?.roles)));
|
|
21440
|
-
const additions = Object.fromEntries(Object.entries(effective.orchestrator?.roles ?? {}).filter(([
|
|
22381
|
+
const additions = Object.fromEntries(Object.entries(effective.orchestrator?.roles ?? {}).filter(([key2, profile]) => requestedProfiles.has(profile) && !Object.hasOwn(live.orchestrator?.roles ?? {}, key2)));
|
|
21441
22382
|
const hasAdditions = Object.keys(additions).length > 0;
|
|
21442
22383
|
const next = hasAdditions ? validateConfigInput(TEAM_PREPARATION_CONFIG, {
|
|
21443
22384
|
...live,
|
|
@@ -21521,19 +22462,19 @@ async function persistPreparedTeam(storage, files) {
|
|
|
21521
22462
|
}
|
|
21522
22463
|
|
|
21523
22464
|
// src/plugin/registerCastTool.ts
|
|
21524
|
-
var CastEntrySchema =
|
|
21525
|
-
roleID:
|
|
21526
|
-
agentName:
|
|
22465
|
+
var CastEntrySchema = z33.object({
|
|
22466
|
+
roleID: z33.string().min(1).describe("Stable role identifier, e.g. scribe or guardian"),
|
|
22467
|
+
agentName: z33.string().min(1).describe("Themed character name assigned to the role")
|
|
21527
22468
|
}).strict();
|
|
21528
|
-
var RegisterCastPayloadSchema =
|
|
21529
|
-
universe:
|
|
21530
|
-
entries:
|
|
22469
|
+
var RegisterCastPayloadSchema = z33.object({
|
|
22470
|
+
universe: z33.string().min(1).describe("Casting universe for this roster"),
|
|
22471
|
+
entries: z33.array(CastEntrySchema).min(1).describe("Role-to-name mappings")
|
|
21531
22472
|
}).strict();
|
|
21532
22473
|
function offendingFields(error) {
|
|
21533
22474
|
const fields = error.issues.flatMap((issue) => {
|
|
21534
22475
|
const base = issue.path.map((segment) => String(segment));
|
|
21535
22476
|
if (issue.code === "unrecognized_keys") {
|
|
21536
|
-
return issue.keys.map((
|
|
22477
|
+
return issue.keys.map((key2) => [...base, key2].join("."));
|
|
21537
22478
|
}
|
|
21538
22479
|
return [base.join(".") || "(root)"];
|
|
21539
22480
|
});
|
|
@@ -21573,12 +22514,12 @@ function markdownCell(value) {
|
|
|
21573
22514
|
}
|
|
21574
22515
|
function modelPolicyLabel(policy) {
|
|
21575
22516
|
const model = policy?.model;
|
|
21576
|
-
const
|
|
22517
|
+
const label2 = model === undefined || model === "auto" ? ROSTER_AUTO_MODEL : `${model.providerID}/${model.modelID}`;
|
|
21577
22518
|
if (policy?.fallbacks === undefined || policy.fallbacks.length === 0) {
|
|
21578
|
-
return
|
|
22519
|
+
return label2;
|
|
21579
22520
|
}
|
|
21580
22521
|
const fallbacks = policy.fallbacks.map((fallback) => `${fallback.providerID}/${fallback.modelID}`);
|
|
21581
|
-
return `${
|
|
22522
|
+
return `${label2}; ${rosterOrderedFallbacks(fallbacks)}`;
|
|
21582
22523
|
}
|
|
21583
22524
|
function registeredTeamTable(roster, deps) {
|
|
21584
22525
|
const rows = roster.entries.map((entry) => {
|
|
@@ -21647,7 +22588,7 @@ function createRegisterCastTool(deps) {
|
|
|
21647
22588
|
}
|
|
21648
22589
|
|
|
21649
22590
|
// src/plugin/reloadTool.ts
|
|
21650
|
-
import { resolve as
|
|
22591
|
+
import { resolve as resolve11 } from "node:path";
|
|
21651
22592
|
import { tool as tool7 } from "@opencode-ai/plugin/tool";
|
|
21652
22593
|
var WAIT_MS = 30000;
|
|
21653
22594
|
var SDK_TIMEOUT_MS = 5000;
|
|
@@ -21681,7 +22622,7 @@ function createReloadController(deps) {
|
|
|
21681
22622
|
return () => clearTimeout(timer);
|
|
21682
22623
|
}
|
|
21683
22624
|
};
|
|
21684
|
-
const directory =
|
|
22625
|
+
const directory = resolve11(deps.directory);
|
|
21685
22626
|
let pending;
|
|
21686
22627
|
let authorizing;
|
|
21687
22628
|
let closed = false;
|
|
@@ -21829,7 +22770,7 @@ function createReloadController(deps) {
|
|
|
21829
22770
|
const parsed = schema.safeParse(args);
|
|
21830
22771
|
if (!parsed.success)
|
|
21831
22772
|
return reloadMessages.invalid;
|
|
21832
|
-
if (context.agent !== "openteam" ||
|
|
22773
|
+
if (context.agent !== "openteam" || resolve11(context.directory) !== directory || context.sessionID.trim().length === 0)
|
|
21833
22774
|
return reloadMessages.denied;
|
|
21834
22775
|
if (parsed.data.action === "cancel") {
|
|
21835
22776
|
if ((pending?.sessionID ?? authorizing?.sessionID) !== context.sessionID)
|
|
@@ -21975,7 +22916,7 @@ function createSessionTracker() {
|
|
|
21975
22916
|
}
|
|
21976
22917
|
|
|
21977
22918
|
// src/plugin/toolcalls.ts
|
|
21978
|
-
function
|
|
22919
|
+
function key2(sessionID, callID) {
|
|
21979
22920
|
return `${sessionID}\x00${callID}`;
|
|
21980
22921
|
}
|
|
21981
22922
|
function createToolcallTracker(deps) {
|
|
@@ -21983,10 +22924,10 @@ function createToolcallTracker(deps) {
|
|
|
21983
22924
|
const started = new Map;
|
|
21984
22925
|
return {
|
|
21985
22926
|
before(input) {
|
|
21986
|
-
started.set(
|
|
22927
|
+
started.set(key2(input.sessionID, input.callID), now());
|
|
21987
22928
|
},
|
|
21988
22929
|
after(input) {
|
|
21989
|
-
const mapKey =
|
|
22930
|
+
const mapKey = key2(input.sessionID, input.callID);
|
|
21990
22931
|
const start = started.get(mapKey);
|
|
21991
22932
|
started.delete(mapKey);
|
|
21992
22933
|
const end = now();
|
|
@@ -22196,7 +23137,7 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
|
|
|
22196
23137
|
}
|
|
22197
23138
|
|
|
22198
23139
|
// src/storage/lifecycle/fsLifecycleJournal.ts
|
|
22199
|
-
import { randomUUID as
|
|
23140
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
22200
23141
|
import {
|
|
22201
23142
|
lstatSync as lstatSync3,
|
|
22202
23143
|
mkdirSync as mkdirSync3,
|
|
@@ -22206,22 +23147,22 @@ import {
|
|
|
22206
23147
|
statSync,
|
|
22207
23148
|
unlinkSync as unlinkSync2
|
|
22208
23149
|
} from "node:fs";
|
|
22209
|
-
import { join as join15, resolve as
|
|
23150
|
+
import { join as join15, resolve as resolve13 } from "node:path";
|
|
22210
23151
|
import { ZodError } from "zod";
|
|
22211
23152
|
|
|
22212
23153
|
// src/storage/lifecycle/codec.ts
|
|
22213
|
-
import { z as
|
|
23154
|
+
import { z as z34 } from "zod";
|
|
22214
23155
|
var LIFECYCLE_CODEC_VERSION = 1;
|
|
22215
23156
|
var LIFECYCLE_GENESIS_DIGEST = sha256Hex("openteam/lifecycle-journal/genesis/v1");
|
|
22216
23157
|
var NUL5 = "\x00";
|
|
22217
23158
|
var NEWLINE2 = `
|
|
22218
23159
|
`;
|
|
22219
|
-
var frameSchema =
|
|
22220
|
-
v:
|
|
22221
|
-
seq:
|
|
22222
|
-
prev:
|
|
22223
|
-
sum:
|
|
22224
|
-
event:
|
|
23160
|
+
var frameSchema = z34.object({
|
|
23161
|
+
v: z34.literal(LIFECYCLE_CODEC_VERSION),
|
|
23162
|
+
seq: z34.number().int().nonnegative(),
|
|
23163
|
+
prev: z34.string().min(1),
|
|
23164
|
+
sum: z34.string().min(1),
|
|
23165
|
+
event: z34.unknown()
|
|
22225
23166
|
}).strict();
|
|
22226
23167
|
function canonical2(value) {
|
|
22227
23168
|
if (Array.isArray(value)) {
|
|
@@ -22230,7 +23171,7 @@ function canonical2(value) {
|
|
|
22230
23171
|
if (value === null || typeof value !== "object") {
|
|
22231
23172
|
return JSON.stringify(value);
|
|
22232
23173
|
}
|
|
22233
|
-
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([
|
|
23174
|
+
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key3, child]) => `${JSON.stringify(key3)}:${canonical2(child)}`).join(",")}}`;
|
|
22234
23175
|
}
|
|
22235
23176
|
function lifecycleFrameDigest(previousDigest, event) {
|
|
22236
23177
|
return sha256Hex(`${previousDigest}${NUL5}${canonical2(event)}`);
|
|
@@ -22308,7 +23249,7 @@ function decodeLifecycleJournal(text) {
|
|
|
22308
23249
|
}
|
|
22309
23250
|
|
|
22310
23251
|
// src/storage/lifecycle/fsLifecycleSupport.ts
|
|
22311
|
-
import { randomUUID as
|
|
23252
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
22312
23253
|
import {
|
|
22313
23254
|
appendFileSync,
|
|
22314
23255
|
closeSync as closeSync2,
|
|
@@ -22325,7 +23266,7 @@ import {
|
|
|
22325
23266
|
unlinkSync,
|
|
22326
23267
|
writeSync as writeSync2
|
|
22327
23268
|
} from "node:fs";
|
|
22328
|
-
import { basename as basename3, dirname as dirname7, join as join14, relative as relative3, resolve as
|
|
23269
|
+
import { basename as basename3, dirname as dirname7, join as join14, relative as relative3, resolve as resolve12 } from "node:path";
|
|
22329
23270
|
var SAFE_RUN_ID = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,126}[A-Za-z0-9])?$/u;
|
|
22330
23271
|
|
|
22331
23272
|
class LifecycleFsError extends Error {
|
|
@@ -22349,7 +23290,7 @@ function validateRunID(runID) {
|
|
|
22349
23290
|
}
|
|
22350
23291
|
function resolvedLifecycleRoot(root) {
|
|
22351
23292
|
try {
|
|
22352
|
-
const absolute =
|
|
23293
|
+
const absolute = resolve12(root);
|
|
22353
23294
|
mkdirSync2(absolute, { recursive: true });
|
|
22354
23295
|
const rootStat = lstatSync2(absolute);
|
|
22355
23296
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
|
|
@@ -22392,7 +23333,7 @@ function assertExistingSafeRun(root, runID) {
|
|
|
22392
23333
|
throw new LifecycleFsError("unavailable");
|
|
22393
23334
|
}
|
|
22394
23335
|
const child = relative3(root, real);
|
|
22395
|
-
if (child === "" || child.startsWith("..") ||
|
|
23336
|
+
if (child === "" || child.startsWith("..") || resolve12(root, child) !== real || dirname7(real) !== root) {
|
|
22396
23337
|
throw new LifecycleFsError("corrupt");
|
|
22397
23338
|
}
|
|
22398
23339
|
return real;
|
|
@@ -22441,7 +23382,7 @@ function appendDurable2(path4, content) {
|
|
|
22441
23382
|
}
|
|
22442
23383
|
}
|
|
22443
23384
|
function writeDurableAtomically(path4, content) {
|
|
22444
|
-
const temporary = join14(dirname7(path4), `.${basename3(path4)}.${
|
|
23385
|
+
const temporary = join14(dirname7(path4), `.${basename3(path4)}.${randomUUID3()}.next`);
|
|
22445
23386
|
try {
|
|
22446
23387
|
writeDurable2(temporary, content);
|
|
22447
23388
|
renameSync(temporary, path4);
|
|
@@ -22464,7 +23405,7 @@ function readLockContents(path4) {
|
|
|
22464
23405
|
}
|
|
22465
23406
|
function withRunMutationLock(runDir, mutate) {
|
|
22466
23407
|
const lockPath = join14(runDir, ".mutation-lock");
|
|
22467
|
-
const lockToken =
|
|
23408
|
+
const lockToken = randomUUID3();
|
|
22468
23409
|
let descriptor;
|
|
22469
23410
|
try {
|
|
22470
23411
|
descriptor = openSync2(lockPath, "wx");
|
|
@@ -22533,7 +23474,7 @@ function parseJson(text, parse2) {
|
|
|
22533
23474
|
}
|
|
22534
23475
|
}
|
|
22535
23476
|
function issueWriterToken() {
|
|
22536
|
-
return
|
|
23477
|
+
return randomUUID4().replaceAll("-", "");
|
|
22537
23478
|
}
|
|
22538
23479
|
function createLease(runID, writerToken, input) {
|
|
22539
23480
|
return parseLifecycleWriterLease({
|
|
@@ -22632,7 +23573,7 @@ function canDeleteTerminalRun(runDir, runID, now) {
|
|
|
22632
23573
|
return now >= lease.expiresAt;
|
|
22633
23574
|
}
|
|
22634
23575
|
var createFsLifecycleJournal = (options) => {
|
|
22635
|
-
const configuredRoot =
|
|
23576
|
+
const configuredRoot = resolve13(options.root);
|
|
22636
23577
|
const now = options.now ?? Date.now;
|
|
22637
23578
|
const mutateRun = options.withMutationLock ?? withRunMutationLock;
|
|
22638
23579
|
return {
|
|
@@ -22654,7 +23595,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
22654
23595
|
throw error;
|
|
22655
23596
|
}
|
|
22656
23597
|
}
|
|
22657
|
-
stagingPath = join15(root, `.start-${runID}-${
|
|
23598
|
+
stagingPath = join15(root, `.start-${runID}-${randomUUID4()}`);
|
|
22658
23599
|
mkdirSync3(stagingPath);
|
|
22659
23600
|
const writerToken = issueWriterToken();
|
|
22660
23601
|
const eventAt = now();
|
|
@@ -23013,8 +23954,8 @@ async function initSpanEmit(connection, config) {
|
|
|
23013
23954
|
const tracer = provider.getTracer(DEFAULT_SERVICE_NAME);
|
|
23014
23955
|
return (record) => {
|
|
23015
23956
|
const span = tracer.startSpan(record.name);
|
|
23016
|
-
for (const [
|
|
23017
|
-
span.setAttribute(
|
|
23957
|
+
for (const [key3, value] of Object.entries(record.attributes)) {
|
|
23958
|
+
span.setAttribute(key3, value);
|
|
23018
23959
|
}
|
|
23019
23960
|
span.end();
|
|
23020
23961
|
};
|
|
@@ -23132,7 +24073,8 @@ var RELEASE_CERT_PATH = "artifacts/graph-release-certificate.json";
|
|
|
23132
24073
|
var SOAK_CERT_PATH = "artifacts/graph-soak-certificate.json";
|
|
23133
24074
|
async function readPackagedCertificate(path4) {
|
|
23134
24075
|
try {
|
|
23135
|
-
|
|
24076
|
+
const hostDirectory = basename4(dirname8(path4)) === NATIVE_CERTIFICATE_DIRECTORY ? `${NATIVE_CERTIFICATE_DIRECTORY}/` : "";
|
|
24077
|
+
return await readFile5(new URL(`./certificates/${hostDirectory}${basename4(path4)}`, import.meta.url), "utf8");
|
|
23136
24078
|
} catch {
|
|
23137
24079
|
return;
|
|
23138
24080
|
}
|
|
@@ -23264,8 +24206,8 @@ async function readOpencodeVersion(serverUrl, options = {}) {
|
|
|
23264
24206
|
}
|
|
23265
24207
|
var DEFAULT_OPENCODE_VERSION_BACKOFF_MS = [50, 250];
|
|
23266
24208
|
function defaultSleep(ms) {
|
|
23267
|
-
return new Promise((
|
|
23268
|
-
setTimeout(
|
|
24209
|
+
return new Promise((resolve14) => {
|
|
24210
|
+
setTimeout(resolve14, ms);
|
|
23269
24211
|
});
|
|
23270
24212
|
}
|
|
23271
24213
|
function createLazyOpencodeVersionReader(serverUrl, options = {}) {
|
|
@@ -23308,9 +24250,10 @@ function createLazyOpencodeVersionReader(serverUrl, options = {}) {
|
|
|
23308
24250
|
};
|
|
23309
24251
|
}
|
|
23310
24252
|
async function buildGateInput(config, storage, opencodeVersion, warn, packagedRead = readPackagedCertificate) {
|
|
23311
|
-
const
|
|
24253
|
+
const hostPath = (path4) => isSupportedNativeOpencodeVersion(opencodeVersion) ? `${dirname8(path4)}/${NATIVE_CERTIFICATE_DIRECTORY}/${basename4(path4)}` : path4;
|
|
24254
|
+
const shadow = await readAndParseCertificate(storage, hostPath(SHADOW_CERT_PATH), (raw) => parseShadowCertificate(raw, opencodeVersion), (cert) => shadowCertificateBindingDigest(cert.evidence), packagedRead);
|
|
23312
24255
|
const shadowDigest = shadow.status === "valid" ? shadow.digest : "0".repeat(64);
|
|
23313
|
-
const release = await readAndParseCertificate(storage, RELEASE_CERT_PATH, (raw) => parseReleaseCertificate(raw, opencodeVersion, shadowDigest), (cert) => cert.digest, packagedRead);
|
|
24256
|
+
const release = await readAndParseCertificate(storage, hostPath(RELEASE_CERT_PATH), (raw) => parseReleaseCertificate(raw, opencodeVersion, shadowDigest), (cert) => cert.digest, packagedRead);
|
|
23314
24257
|
let soakLedgerDigest = "0".repeat(64);
|
|
23315
24258
|
try {
|
|
23316
24259
|
const recorderPorts = recorderPortsFromStorage(storage);
|
|
@@ -23565,14 +24508,17 @@ async function listConfiguredOpencodeInventory(ctx) {
|
|
|
23565
24508
|
profiles: normalizeModelsDevCatalog(Object.fromEntries(providers.map((provider) => [provider.id, provider]))).filter((profile) => profile.costPer1M.inputUSD > 0 && profile.costPer1M.outputUSD > 0)
|
|
23566
24509
|
};
|
|
23567
24510
|
}
|
|
23568
|
-
|
|
24511
|
+
async function createPluginRuntime(ctx, rawOptions) {
|
|
23569
24512
|
const now = () => Date.now();
|
|
23570
24513
|
const diagnostics = createPluginDiagnosticChannel({
|
|
23571
24514
|
client: ctx.client,
|
|
23572
24515
|
directory: ctx.directory,
|
|
23573
24516
|
now
|
|
23574
24517
|
});
|
|
23575
|
-
|
|
24518
|
+
const initialServerUrl = ctx.serverUrl();
|
|
24519
|
+
if (initialServerUrl !== undefined) {
|
|
24520
|
+
logOpencodeServerUrl(initialServerUrl, diagnostics.info("opencode-server-url", { persist: false, toast: false }));
|
|
24521
|
+
}
|
|
23576
24522
|
const storage = createFsStorageProvider(ctx.directory || ctx.worktree || process.cwd());
|
|
23577
24523
|
const runtimeConfig = await loadRuntimeOpenTeamConfig(storage, rawOptions);
|
|
23578
24524
|
const config = runtimeConfig.config;
|
|
@@ -23581,20 +24527,19 @@ var server = async (ctx, rawOptions) => {
|
|
|
23581
24527
|
const registry = new RuntimeRegistry({
|
|
23582
24528
|
fetch: globalThis.fetch,
|
|
23583
24529
|
clock: () => new Date().toISOString(),
|
|
23584
|
-
foundryDiscovery: foundryDiscoveryFromExec(
|
|
24530
|
+
foundryDiscovery: foundryDiscoveryFromExec(ctx.exec)
|
|
23585
24531
|
});
|
|
23586
24532
|
const cache = createAvailabilityCache({
|
|
23587
24533
|
config,
|
|
23588
24534
|
registry,
|
|
23589
|
-
...ctx.
|
|
23590
|
-
listConfiguredInventory: () => listConfiguredOpencodeInventory(ctx)
|
|
23591
|
-
},
|
|
24535
|
+
...ctx.listConfiguredInventory === undefined ? {} : { listConfiguredInventory: ctx.listConfiguredInventory },
|
|
23592
24536
|
onRefreshError: (error) => logAvailabilityRefreshError(error, diagnostics.warn("availability-refresh-failed", { toast: false }))
|
|
23593
24537
|
});
|
|
23594
24538
|
let availabilityReady;
|
|
23595
|
-
const ensureAvailability = () => {
|
|
24539
|
+
const ensureAvailability = async () => {
|
|
23596
24540
|
availabilityReady ??= cache.refresh();
|
|
23597
|
-
|
|
24541
|
+
await availabilityReady;
|
|
24542
|
+
await cache.waitForRefresh();
|
|
23598
24543
|
};
|
|
23599
24544
|
const capabilityProfiles = () => {
|
|
23600
24545
|
const availableModelKeys = new Set(cache.get().filter((model) => model.available).map((model) => `${model.providerID}\x00${model.modelID}`));
|
|
@@ -23623,17 +24568,19 @@ var server = async (ctx, rawOptions) => {
|
|
|
23623
24568
|
const injectMemory = await buildMemoryInjectorFromConfig(config, storage, diagnostics.warn("memory-runtime-warning", { toast: false }));
|
|
23624
24569
|
const sessionTracker = createSessionTracker();
|
|
23625
24570
|
const orchestratedModelOwnership = createOrchestratedModelOwnership();
|
|
23626
|
-
const
|
|
24571
|
+
const resolveAgentRole = async (agentName) => {
|
|
24572
|
+
const entry = (await readRoutingRosterEntries(storage)).find((candidate) => candidate.agentName === agentName);
|
|
24573
|
+
return entry?.roleID;
|
|
24574
|
+
};
|
|
24575
|
+
const residencyOptions = {
|
|
23627
24576
|
fetch: globalThis.fetch,
|
|
23628
|
-
|
|
24577
|
+
resolveAgentRole,
|
|
24578
|
+
...ctx.listConfiguredInventory === undefined ? {} : {
|
|
23629
24579
|
resolveApiModelID: cache.resolveApiModelID,
|
|
23630
24580
|
modelInventoryReady: ensureAvailability
|
|
23631
24581
|
}
|
|
23632
|
-
});
|
|
23633
|
-
const resolveAgentRole = async (agentName) => {
|
|
23634
|
-
const entry = (await readRoutingRosterEntries(storage)).find((candidate) => candidate.agentName === agentName);
|
|
23635
|
-
return entry?.roleID;
|
|
23636
24582
|
};
|
|
24583
|
+
const modelResidency = (ctx.createResidencyGuard ?? createModelResidencyGuard)(config, residencyOptions);
|
|
23637
24584
|
const hooks = createHooks(config, cache.get, injectMemory === undefined ? {
|
|
23638
24585
|
sink,
|
|
23639
24586
|
modelResidency,
|
|
@@ -23652,10 +24599,12 @@ var server = async (ctx, rawOptions) => {
|
|
|
23652
24599
|
resolveAgentRole,
|
|
23653
24600
|
onRoute: (sid, model) => sessionTracker.trackRoutedModel(sid, model)
|
|
23654
24601
|
});
|
|
23655
|
-
const getOpencodeVersion =
|
|
24602
|
+
const getOpencodeVersion = ctx.opencodeVersion ?? (initialServerUrl === undefined ? async () => {
|
|
24603
|
+
throw new Error(nativeHostMessages.missingVersion);
|
|
24604
|
+
} : createLazyOpencodeVersionReader(initialServerUrl, {
|
|
23656
24605
|
client: ctx.client,
|
|
23657
24606
|
onFailure: createOpencodeVersionReadFailureLogger(MAX_LOGGED_OPENCODE_VERSION_FAILURE_CAUSES, diagnostics.warn("opencode-version-read-failed", { toast: false }))
|
|
23658
|
-
});
|
|
24607
|
+
}));
|
|
23659
24608
|
const cliDeps = createCliDeps(config, registry, telemetryPath, sessionsDir, storage, runtimeConfig.source, rawOptions, async () => {
|
|
23660
24609
|
const version = await getOpencodeVersion();
|
|
23661
24610
|
return version === "unknown" ? undefined : version;
|
|
@@ -23666,12 +24615,15 @@ var server = async (ctx, rawOptions) => {
|
|
|
23666
24615
|
if (sessionID === undefined || announcedSessions.has(sessionID)) {
|
|
23667
24616
|
return;
|
|
23668
24617
|
}
|
|
23669
|
-
|
|
23670
|
-
|
|
24618
|
+
const serverUrl = ctx.serverUrl();
|
|
24619
|
+
if (serverUrl === undefined)
|
|
24620
|
+
return;
|
|
24621
|
+
const endpoint = sessionEndpointEventFrom(sessionID, serverUrl, now, {
|
|
23671
24622
|
directory: ctx.directory,
|
|
23672
24623
|
worktree: ctx.worktree
|
|
23673
24624
|
});
|
|
23674
24625
|
if (endpoint !== undefined) {
|
|
24626
|
+
announcedSessions.add(sessionID);
|
|
23675
24627
|
sink.emit(endpoint);
|
|
23676
24628
|
}
|
|
23677
24629
|
};
|
|
@@ -23723,7 +24675,7 @@ var server = async (ctx, rawOptions) => {
|
|
|
23723
24675
|
holder: "openteam-plugin",
|
|
23724
24676
|
lifecycleSource: "plugin",
|
|
23725
24677
|
lifecycleRecorder,
|
|
23726
|
-
exec:
|
|
24678
|
+
exec: ctx.exec,
|
|
23727
24679
|
repoRoot: ctx.directory
|
|
23728
24680
|
});
|
|
23729
24681
|
const graphSurface = createGraphTool({
|
|
@@ -23759,8 +24711,8 @@ var server = async (ctx, rawOptions) => {
|
|
|
23759
24711
|
rememberReportedSlots(snapshots);
|
|
23760
24712
|
return reachableRuntimeIds(snapshots);
|
|
23761
24713
|
};
|
|
23762
|
-
const runtimeById = (
|
|
23763
|
-
const runtimeId = slotPoolRuntimeID(
|
|
24714
|
+
const runtimeById = (key3) => {
|
|
24715
|
+
const runtimeId = slotPoolRuntimeID(key3);
|
|
23764
24716
|
const runtime = config.local.runtimes.find((candidate) => candidate.id === runtimeId);
|
|
23765
24717
|
if (runtime === undefined) {
|
|
23766
24718
|
return;
|
|
@@ -23768,13 +24720,13 @@ var server = async (ctx, rawOptions) => {
|
|
|
23768
24720
|
return withReportedModelSlots(runtime, reportedSlotsByRuntime.get(runtimeId), localModelAliases(runtime.defaultModel.providerID, cache.get()));
|
|
23769
24721
|
};
|
|
23770
24722
|
const runtimeLimiter = createRuntimeConcurrencyLimiter({
|
|
23771
|
-
capacityFor: (
|
|
23772
|
-
const runtime = runtimeById(
|
|
23773
|
-
return runtime === undefined ? unknownPoolCapacity() : slotPoolCapacity(runtime, slotPoolModelID(
|
|
24723
|
+
capacityFor: (key3) => {
|
|
24724
|
+
const runtime = runtimeById(key3);
|
|
24725
|
+
return runtime === undefined ? unknownPoolCapacity() : slotPoolCapacity(runtime, slotPoolModelID(key3));
|
|
23774
24726
|
},
|
|
23775
|
-
reservedInteractiveFor: (
|
|
23776
|
-
const runtime = runtimeById(
|
|
23777
|
-
return runtime === undefined ? 0 : slotPoolReservedInteractive(runtime, slotPoolModelID(
|
|
24727
|
+
reservedInteractiveFor: (key3) => {
|
|
24728
|
+
const runtime = runtimeById(key3);
|
|
24729
|
+
return runtime === undefined ? 0 : slotPoolReservedInteractive(runtime, slotPoolModelID(key3));
|
|
23778
24730
|
},
|
|
23779
24731
|
now
|
|
23780
24732
|
});
|
|
@@ -23801,8 +24753,8 @@ var server = async (ctx, rawOptions) => {
|
|
|
23801
24753
|
lifecycleRecorder,
|
|
23802
24754
|
abortGraceMs: DEFAULT_ABORT_GRACE_MS,
|
|
23803
24755
|
statusPollMs: DEFAULT_STATUS_POLL_MS,
|
|
23804
|
-
delay: (ms) => new Promise((
|
|
23805
|
-
setTimeout(
|
|
24756
|
+
delay: (ms) => new Promise((resolve14) => {
|
|
24757
|
+
setTimeout(resolve14, ms);
|
|
23806
24758
|
}),
|
|
23807
24759
|
warn: diagnostics.warn("unknown-role")
|
|
23808
24760
|
});
|
|
@@ -23812,7 +24764,7 @@ var server = async (ctx, rawOptions) => {
|
|
|
23812
24764
|
now,
|
|
23813
24765
|
localRuntimeReachable: async (runtime, signal) => {
|
|
23814
24766
|
if (localRuntimeKind(runtime) === "llama-swap") {
|
|
23815
|
-
if (ctx.
|
|
24767
|
+
if (ctx.listConfiguredInventory !== undefined)
|
|
23816
24768
|
await ensureAvailability();
|
|
23817
24769
|
signal?.throwIfAborted();
|
|
23818
24770
|
const target = modelResidency.localTarget(resolveMemorySemantic(config).extraction.model ?? runtime.defaultModel);
|
|
@@ -23826,7 +24778,7 @@ var server = async (ctx, rawOptions) => {
|
|
|
23826
24778
|
return true;
|
|
23827
24779
|
}
|
|
23828
24780
|
if (localRuntimeKind(runtime) === "lemonade") {
|
|
23829
|
-
if (ctx.
|
|
24781
|
+
if (ctx.listConfiguredInventory !== undefined)
|
|
23830
24782
|
await ensureAvailability();
|
|
23831
24783
|
signal?.throwIfAborted();
|
|
23832
24784
|
const target = modelResidency.localTarget(resolveMemorySemantic(config).extraction.model ?? runtime.defaultModel);
|
|
@@ -23841,7 +24793,7 @@ var server = async (ctx, rawOptions) => {
|
|
|
23841
24793
|
return anyRuntimeReachable(snapshots);
|
|
23842
24794
|
},
|
|
23843
24795
|
resolveExtractionTarget: async (model) => {
|
|
23844
|
-
if (ctx.
|
|
24796
|
+
if (ctx.listConfiguredInventory !== undefined)
|
|
23845
24797
|
await ensureAvailability();
|
|
23846
24798
|
return modelResidency.localTarget(model);
|
|
23847
24799
|
},
|
|
@@ -23869,6 +24821,7 @@ var server = async (ctx, rawOptions) => {
|
|
|
23869
24821
|
"chat.message": async (input, output) => {
|
|
23870
24822
|
reload.userTurn(input.sessionID);
|
|
23871
24823
|
await hooks["chat.message"]?.(input, output);
|
|
24824
|
+
announceEndpoint(input.sessionID);
|
|
23872
24825
|
},
|
|
23873
24826
|
dispose: async () => {
|
|
23874
24827
|
reload.dispose();
|
|
@@ -23876,7 +24829,7 @@ var server = async (ctx, rawOptions) => {
|
|
|
23876
24829
|
},
|
|
23877
24830
|
tool: {
|
|
23878
24831
|
openteam: createCommandTool(cliDeps),
|
|
23879
|
-
"openteam-console": createConsoleTool(),
|
|
24832
|
+
"openteam-console": createConsoleTool(ctx.consoleEnvironment === undefined ? {} : { environment: ctx.consoleEnvironment }),
|
|
23880
24833
|
"openteam-graph": graphSurface.definition,
|
|
23881
24834
|
"openteam-orchestrate": orchestrateTool,
|
|
23882
24835
|
"openteam-memory": memoryTool,
|
|
@@ -23913,10 +24866,21 @@ var server = async (ctx, rawOptions) => {
|
|
|
23913
24866
|
}
|
|
23914
24867
|
}
|
|
23915
24868
|
};
|
|
23916
|
-
}
|
|
24869
|
+
}
|
|
24870
|
+
var server = (ctx, rawOptions) => createPluginRuntime({
|
|
24871
|
+
directory: ctx.directory,
|
|
24872
|
+
worktree: ctx.worktree,
|
|
24873
|
+
client: ctx.client,
|
|
24874
|
+
exec: createShellExec(ctx.$),
|
|
24875
|
+
serverUrl: () => ctx.serverUrl,
|
|
24876
|
+
...ctx.client.config?.providers === undefined ? {} : {
|
|
24877
|
+
listConfiguredInventory: () => listConfiguredOpencodeInventory(ctx)
|
|
24878
|
+
}
|
|
24879
|
+
}, rawOptions);
|
|
23917
24880
|
var plugin = {
|
|
23918
24881
|
id: "openteam",
|
|
23919
|
-
server
|
|
24882
|
+
server,
|
|
24883
|
+
effect: createNativePluginEffect(createPluginRuntime)
|
|
23920
24884
|
};
|
|
23921
24885
|
var src_default = plugin;
|
|
23922
24886
|
export {
|
|
@@ -23934,6 +24898,7 @@ export {
|
|
|
23934
24898
|
isMissingFile2 as isMissingFile,
|
|
23935
24899
|
evaluateCutoverGateForBoundary,
|
|
23936
24900
|
src_default as default,
|
|
24901
|
+
createPluginRuntime,
|
|
23937
24902
|
createOpencodeVersionReadFailureLogger,
|
|
23938
24903
|
createLazyOpencodeVersionReader,
|
|
23939
24904
|
createEventSink,
|