@jmanuelcorral/openteam 0.20.0 → 0.22.0
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 +32 -1
- package/README.md +30 -1
- package/dist/certificates/graph-release-certificate.json +2 -2
- package/dist/certificates/graph-shadow-certificate.json +2 -2
- package/dist/cli/consoleServe.d.ts +1 -0
- package/dist/cli/consoleServe.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +5681 -1465
- package/dist/commands/dispatch.d.ts +9 -4
- package/dist/commands/dispatch.d.ts.map +1 -1
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/setup.d.ts +137 -4
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/types.d.ts +4 -0
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/upgrade.d.ts +42 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/config/errors.d.ts.map +1 -1
- package/dist/config/historyEndpoint.d.ts +3 -0
- package/dist/config/historyEndpoint.d.ts.map +1 -0
- package/dist/config/pluginSpec.d.ts +43 -0
- package/dist/config/pluginSpec.d.ts.map +1 -0
- package/dist/config/schema.d.ts +12 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/console/assets.d.ts +3 -3
- package/dist/console/assets.d.ts.map +1 -1
- package/dist/console/conversation.d.ts +75 -0
- package/dist/console/conversation.d.ts.map +1 -0
- package/dist/console/historyBoundary.d.ts +6 -0
- package/dist/console/historyBoundary.d.ts.map +1 -0
- package/dist/console/inspector.d.ts +3 -0
- package/dist/console/inspector.d.ts.map +1 -0
- package/dist/console/labels.d.ts +12 -0
- package/dist/console/labels.d.ts.map +1 -0
- package/dist/console/opencodeClient.d.ts.map +1 -1
- package/dist/console/refresh.d.ts +3 -0
- package/dist/console/refresh.d.ts.map +1 -0
- package/dist/console/render.d.ts +7 -0
- package/dist/console/render.d.ts.map +1 -1
- package/dist/console/rootAssociation.d.ts +7 -0
- package/dist/console/rootAssociation.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2887 -907
- package/dist/local/lemonade.d.ts.map +1 -1
- package/dist/local/openai-compatible.d.ts.map +1 -1
- package/dist/local/types.d.ts +16 -0
- package/dist/local/types.d.ts.map +1 -1
- package/dist/messages/commands.d.ts +9 -0
- package/dist/messages/commands.d.ts.map +1 -1
- package/dist/messages/consoleDetail.d.ts +54 -0
- package/dist/messages/consoleDetail.d.ts.map +1 -0
- package/dist/messages/executionSetup.d.ts +43 -0
- package/dist/messages/executionSetup.d.ts.map +1 -1
- package/dist/messages/index.d.ts +1 -0
- package/dist/messages/index.d.ts.map +1 -1
- package/dist/messages/orchestration.d.ts +3 -0
- package/dist/messages/orchestration.d.ts.map +1 -1
- package/dist/messages/upgrade.d.ts +129 -0
- package/dist/messages/upgrade.d.ts.map +1 -0
- package/dist/plugin/commandTool.d.ts +4 -4
- package/dist/plugin/commandTool.d.ts.map +1 -1
- package/dist/plugin/orchestrateTool.d.ts.map +1 -1
- package/dist/web/configApi.d.ts +1 -1
- package/dist/web/configApi.d.ts.map +1 -1
- package/dist/web/console.d.ts.map +1 -1
- package/dist/web/conversationRoute.d.ts +16 -0
- package/dist/web/conversationRoute.d.ts.map +1 -0
- package/dist/web/server.d.ts +5 -0
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/start.d.ts +6 -0
- package/dist/web/start.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@ import { createRequire } from "node:module";
|
|
|
2
2
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
5
|
-
import { readFile as
|
|
6
|
-
import { basename as
|
|
5
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
6
|
+
import { basename as basename4, dirname as dirname6 } from "node:path";
|
|
7
7
|
|
|
8
8
|
// src/capabilities/curated.ts
|
|
9
9
|
var CURATED_FRONTIER_PROFILES = [
|
|
@@ -782,6 +782,72 @@ function migrateConfig(raw) {
|
|
|
782
782
|
};
|
|
783
783
|
}
|
|
784
784
|
|
|
785
|
+
// src/messages/consoleDetail.ts
|
|
786
|
+
var consoleDetailMessages = {
|
|
787
|
+
follow: "Follow new activity",
|
|
788
|
+
metadataOnly: "Lifecycle and telemetry stay metadata-only.",
|
|
789
|
+
filter: "Filter sessions",
|
|
790
|
+
incoming: "New activity available — show updates",
|
|
791
|
+
refreshError: "Live updates unavailable; retrying.",
|
|
792
|
+
inspectConversation: "Show messages and tool calls",
|
|
793
|
+
refresh: "Refresh conversation",
|
|
794
|
+
close: "Hide messages and tool calls",
|
|
795
|
+
title: "Recorded messages and tool calls",
|
|
796
|
+
orchestrator: "Orchestrator",
|
|
797
|
+
worker: "Worker",
|
|
798
|
+
session: "Session",
|
|
799
|
+
runStarted: "Run started",
|
|
800
|
+
sessionCreated: "Session created",
|
|
801
|
+
firstObserved: "First observed",
|
|
802
|
+
timeUnknown: "Time unknown",
|
|
803
|
+
utc: "UTC",
|
|
804
|
+
technicalID: "Technical ID",
|
|
805
|
+
currentMetadata: "Current opencode title; not historical metadata",
|
|
806
|
+
partialMetadata: "Some current session titles are unavailable or outside the bounded batch; fallback labels remain.",
|
|
807
|
+
rootCurrent: "Current whole orchestrator session; may contain multiple batches. Not a historical or batch-only transcript.",
|
|
808
|
+
recovered: "Read-only association verified from current opencode history; not an immutable lifecycle event.",
|
|
809
|
+
rootUnlinked: "Orchestrator session not recorded. Reveal to try a bounded, read-only relationship search.",
|
|
810
|
+
rootUnavailable: "Orchestrator session unavailable: no unique, verifiable relationship was found in local history.",
|
|
811
|
+
rootAmbiguous: "Orchestrator session unavailable: conflicting or copied relationships are ambiguous.",
|
|
812
|
+
searchIncomplete: "Orchestrator association search incomplete or exceeded its bounded budget. No session was guessed.",
|
|
813
|
+
prompt: "Received prompts",
|
|
814
|
+
assistant: "Visible agent responses",
|
|
815
|
+
tools: "Tool calls ({count})",
|
|
816
|
+
noPrompts: "No received prompt text retained.",
|
|
817
|
+
noOutput: "No visible agent response text retained.",
|
|
818
|
+
noTools: "No tool calls retained.",
|
|
819
|
+
arguments: "Arguments",
|
|
820
|
+
result: "Result",
|
|
821
|
+
loading: "Loading local conversation…",
|
|
822
|
+
current: "Present-day session, not a timeline reconstruction. May include later messages and tools. Refresh explicitly for updates.",
|
|
823
|
+
historical: "Historical cursor: conversation content is hidden to avoid showing future mutable text. Return to live before revealing this operation.",
|
|
824
|
+
disabled: "Content is disabled. Set console.sessionHistory.contentEnabled to true in .opencode/openteam.json and restart the Console. Then reveal content here.",
|
|
825
|
+
unavailable: "Conversation unavailable. Start an operator-owned local opencode serve against the same workspace and user history, configure console.sessionHistory.endpoint, then retry. No inference was requested.",
|
|
826
|
+
empty: "No readable user messages, assistant output or tool calls remain in this session.",
|
|
827
|
+
invalid: "This attempt has no recorded session in the selected run, or its history is incomplete.",
|
|
828
|
+
unauthorized: "Conversation access denied.",
|
|
829
|
+
pending: "Still streaming or unavailable.",
|
|
830
|
+
compacted: "Tool result was compacted by opencode.",
|
|
831
|
+
invalidEndpoint: "Expected a loopback HTTP origin without credentials, path, query or fragment.",
|
|
832
|
+
readFailed: "Local session history could not be read.",
|
|
833
|
+
oversized: "Conversation exceeds the local size limit (4 MiB). No content was loaded.",
|
|
834
|
+
truncated: "Conversation display is truncated by local safety limits; omitted content is not empty history.",
|
|
835
|
+
truncatedMarker: `
|
|
836
|
+
[truncated]`,
|
|
837
|
+
terminalGap: "Live collection was interrupted; events during the gap are unavailable. This is not complete session history.",
|
|
838
|
+
terminalTrimmed: "Older live output was discarded by the local display limit."
|
|
839
|
+
};
|
|
840
|
+
|
|
841
|
+
// src/config/historyEndpoint.ts
|
|
842
|
+
function isLocalHistoryEndpoint(value) {
|
|
843
|
+
try {
|
|
844
|
+
const url = new URL(value);
|
|
845
|
+
return url.protocol === "http:" && ["127.0.0.1", "[::1]"].includes(url.hostname) && !url.username && !url.password && url.pathname === "/" && !url.search && !url.hash;
|
|
846
|
+
} catch {
|
|
847
|
+
return false;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
785
851
|
// src/config/schema.ts
|
|
786
852
|
var ModelRefSchema = z3.object({
|
|
787
853
|
providerID: z3.string().min(1),
|
|
@@ -841,6 +907,10 @@ var ConsoleConfigSchema = z3.object({
|
|
|
841
907
|
recentRoutes: z3.number().int().positive().default(50),
|
|
842
908
|
openBrowser: z3.boolean().default(false),
|
|
843
909
|
remoteStorage: z3.boolean().default(false),
|
|
910
|
+
sessionHistory: z3.object({
|
|
911
|
+
contentEnabled: z3.boolean().default(false),
|
|
912
|
+
endpoint: z3.string().refine(isLocalHistoryEndpoint, consoleDetailMessages.invalidEndpoint).optional()
|
|
913
|
+
}).strict().optional(),
|
|
844
914
|
terminal: z3.object({
|
|
845
915
|
enabled: z3.boolean().default(true),
|
|
846
916
|
pty: z3.boolean().optional()
|
|
@@ -3841,11 +3911,13 @@ var KNOWN_CONFIG_KEYS_BY_PATH = new Map([
|
|
|
3841
3911
|
"openBrowser",
|
|
3842
3912
|
"remoteStorage",
|
|
3843
3913
|
"terminal",
|
|
3844
|
-
"graphView"
|
|
3914
|
+
"graphView",
|
|
3915
|
+
"sessionHistory"
|
|
3845
3916
|
]
|
|
3846
3917
|
],
|
|
3847
3918
|
["console.terminal", ["enabled", "pty"]],
|
|
3848
3919
|
["console.graphView", ["enabled"]],
|
|
3920
|
+
["console.sessionHistory", ["contentEnabled", "endpoint"]],
|
|
3849
3921
|
["storage", ["sqliteIndex"]],
|
|
3850
3922
|
["storage.sqliteIndex", ["enabled", "path"]],
|
|
3851
3923
|
["memory", ["semantic"]],
|
|
@@ -5317,153 +5389,2032 @@ function createPurgeAdapter(root) {
|
|
|
5317
5389
|
};
|
|
5318
5390
|
}
|
|
5319
5391
|
|
|
5320
|
-
// src/
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5392
|
+
// src/commands/upgrade.ts
|
|
5393
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
5394
|
+
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
5395
|
+
import {
|
|
5396
|
+
chmod,
|
|
5397
|
+
lstat,
|
|
5398
|
+
mkdir as mkdir2,
|
|
5399
|
+
open,
|
|
5400
|
+
readFile as readFile2,
|
|
5401
|
+
rename,
|
|
5402
|
+
rm as rm2
|
|
5403
|
+
} from "node:fs/promises";
|
|
5404
|
+
import { basename as basename2, dirname as dirname4, join as join9, relative, resolve as resolve3, win32 } from "node:path";
|
|
5405
|
+
import { fileURLToPath } from "node:url";
|
|
5406
|
+
import { promisify as promisify2 } from "node:util";
|
|
5407
|
+
import { z as z15 } from "zod";
|
|
5408
|
+
// package.json
|
|
5409
|
+
var package_default = {
|
|
5410
|
+
name: "@jmanuelcorral/openteam",
|
|
5411
|
+
version: "0.22.0",
|
|
5412
|
+
packageManager: "bun@1.3.14",
|
|
5413
|
+
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
5414
|
+
license: "MIT",
|
|
5415
|
+
author: "Jose Manuel Corral",
|
|
5416
|
+
repository: {
|
|
5417
|
+
type: "git",
|
|
5418
|
+
url: "git+https://github.com/jmanuelcorral/openteam.git"
|
|
5419
|
+
},
|
|
5420
|
+
homepage: "https://github.com/jmanuelcorral/openteam#readme",
|
|
5421
|
+
bugs: {
|
|
5422
|
+
url: "https://github.com/jmanuelcorral/openteam/issues"
|
|
5423
|
+
},
|
|
5424
|
+
keywords: [
|
|
5425
|
+
"opencode",
|
|
5426
|
+
"opencode-plugin",
|
|
5427
|
+
"llm",
|
|
5428
|
+
"routing",
|
|
5429
|
+
"local-llm",
|
|
5430
|
+
"ollama",
|
|
5431
|
+
"lm-studio",
|
|
5432
|
+
"foundry-local",
|
|
5433
|
+
"cost-optimization",
|
|
5434
|
+
"multi-agent"
|
|
5435
|
+
],
|
|
5436
|
+
engines: {
|
|
5437
|
+
bun: ">=1.3",
|
|
5438
|
+
node: "^22.22.2 || ^24.15.0 || >=26.0.0"
|
|
5439
|
+
},
|
|
5440
|
+
type: "module",
|
|
5441
|
+
main: "./dist/index.js",
|
|
5442
|
+
module: "./dist/index.js",
|
|
5443
|
+
types: "./dist/index.d.ts",
|
|
5444
|
+
bin: {
|
|
5445
|
+
openteam: "./dist/cli.js"
|
|
5446
|
+
},
|
|
5447
|
+
exports: {
|
|
5448
|
+
".": {
|
|
5449
|
+
types: "./dist/index.d.ts",
|
|
5450
|
+
import: "./dist/index.js"
|
|
5451
|
+
},
|
|
5452
|
+
"./package.json": "./package.json"
|
|
5453
|
+
},
|
|
5454
|
+
files: [
|
|
5455
|
+
"dist",
|
|
5456
|
+
"README.md",
|
|
5457
|
+
"LICENSE",
|
|
5458
|
+
"AGENTS.md",
|
|
5459
|
+
".opencode/openteam.example.json",
|
|
5460
|
+
".opencode/command/openteam.md"
|
|
5461
|
+
],
|
|
5462
|
+
publishConfig: {
|
|
5463
|
+
access: "public",
|
|
5464
|
+
registry: "https://registry.npmjs.org/"
|
|
5465
|
+
},
|
|
5466
|
+
trustedDependencies: [],
|
|
5467
|
+
sideEffects: false,
|
|
5468
|
+
scripts: {
|
|
5469
|
+
prebuild: "bun run clean",
|
|
5470
|
+
build: "bun run build:js && bun run build:cli && bun run build:types && bun run build:certificates",
|
|
5471
|
+
"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",
|
|
5472
|
+
"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',
|
|
5473
|
+
"build:types": "tsc -p tsconfig.build.json",
|
|
5474
|
+
clean: `node -e "require('node:fs').rmSync('dist', { recursive: true, force: true })"`,
|
|
5475
|
+
test: "bun test",
|
|
5476
|
+
"test:cov": "bun test --coverage",
|
|
5477
|
+
"certify:shadow": "bun run scripts/certify-artifact.ts shadow",
|
|
5478
|
+
"certify:release": "bun run scripts/certify-artifact.ts release",
|
|
5479
|
+
"build:certificates": "bun run certify:shadow && bun run certify:release && bun run scripts/bundle-certificates.ts",
|
|
5480
|
+
"coverage:check": "node scripts/check-coverage.mjs",
|
|
5481
|
+
typecheck: "tsc --noEmit",
|
|
5482
|
+
lint: "biome check .",
|
|
5483
|
+
"format:check": "biome format .",
|
|
5484
|
+
"docs:install": "cd docs && bun install --frozen-lockfile --ignore-scripts",
|
|
5485
|
+
"docs:dev": "cd docs && bun run docs:dev",
|
|
5486
|
+
"docs:build": "cd docs && bun run docs:build",
|
|
5487
|
+
"docs:preview": "cd docs && bun run docs:preview",
|
|
5488
|
+
prepublishOnly: "bun run build",
|
|
5489
|
+
"link:local": "bun run build && npm link",
|
|
5490
|
+
"hooks:install": "git config core.hooksPath .githooks"
|
|
5491
|
+
},
|
|
5492
|
+
dependencies: {
|
|
5493
|
+
"@clack/prompts": "1.7.0",
|
|
5494
|
+
"@langchain/core": "1.2.9",
|
|
5495
|
+
"@langchain/langgraph": "1.4.12",
|
|
5496
|
+
"@opencode-ai/plugin": "1.18.19",
|
|
5497
|
+
"@opencode-ai/sdk": "1.18.19",
|
|
5498
|
+
"@opentelemetry/api": "1.9.1",
|
|
5499
|
+
"@opentelemetry/exporter-trace-otlp-http": "0.221.0",
|
|
5500
|
+
"@opentelemetry/resources": "2.10.0",
|
|
5501
|
+
"@opentelemetry/sdk-trace-base": "2.10.0",
|
|
5502
|
+
zod: "4.4.3"
|
|
5503
|
+
},
|
|
5504
|
+
devDependencies: {
|
|
5505
|
+
"@biomejs/biome": "2.5.9",
|
|
5506
|
+
"@types/bun": "1.3.14",
|
|
5507
|
+
typescript: "7.0.2"
|
|
5333
5508
|
}
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
const
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
if (
|
|
5349
|
-
|
|
5350
|
-
code: "migration-pending",
|
|
5351
|
-
detail: "legacy migration has pending work — run the migration tool to completion before enabling active mode"
|
|
5352
|
-
});
|
|
5353
|
-
} else if (input.migration === "unknown") {
|
|
5354
|
-
violations.push({
|
|
5355
|
-
code: "migration-unknown",
|
|
5356
|
-
detail: "could not determine migration status — check ledger readability and storage access"
|
|
5357
|
-
});
|
|
5509
|
+
};
|
|
5510
|
+
|
|
5511
|
+
// src/version.ts
|
|
5512
|
+
var PACKAGE_VERSION = package_default.version;
|
|
5513
|
+
|
|
5514
|
+
// src/config/pluginSpec.ts
|
|
5515
|
+
var OPENTEAM_PACKAGE_NAME = "@jmanuelcorral/openteam";
|
|
5516
|
+
function pinnedPluginSpec(version) {
|
|
5517
|
+
const v = version ?? PACKAGE_VERSION;
|
|
5518
|
+
return `${OPENTEAM_PACKAGE_NAME}@${v}`;
|
|
5519
|
+
}
|
|
5520
|
+
var STRICT_SEMVER_RE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
5521
|
+
function parseStrictSemverParts(version) {
|
|
5522
|
+
const match = STRICT_SEMVER_RE.exec(version);
|
|
5523
|
+
if (match === null) {
|
|
5524
|
+
return;
|
|
5358
5525
|
}
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5526
|
+
const major = Number(match[1]);
|
|
5527
|
+
const minor = Number(match[2]);
|
|
5528
|
+
const patch = Number(match[3]);
|
|
5529
|
+
if (!Number.isSafeInteger(major) || !Number.isSafeInteger(minor) || !Number.isSafeInteger(patch)) {
|
|
5530
|
+
return;
|
|
5364
5531
|
}
|
|
5365
|
-
return
|
|
5366
|
-
allowed: violations.length === 0,
|
|
5367
|
-
violations,
|
|
5368
|
-
advisories
|
|
5369
|
-
};
|
|
5370
|
-
}
|
|
5371
|
-
function isGateApplicable(mode) {
|
|
5372
|
-
return mode === "active";
|
|
5532
|
+
return [major, minor, patch];
|
|
5373
5533
|
}
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
let i = 0;
|
|
5379
|
-
while (i < src.length) {
|
|
5380
|
-
const ch = src[i];
|
|
5381
|
-
if (ch === undefined)
|
|
5382
|
-
break;
|
|
5383
|
-
if (ch === '"') {
|
|
5384
|
-
out.push(ch);
|
|
5385
|
-
i++;
|
|
5386
|
-
while (i < src.length) {
|
|
5387
|
-
const c = src[i];
|
|
5388
|
-
if (c === undefined)
|
|
5389
|
-
break;
|
|
5390
|
-
out.push(c);
|
|
5391
|
-
i++;
|
|
5392
|
-
if (c === "\\") {
|
|
5393
|
-
const escaped = src[i];
|
|
5394
|
-
if (escaped !== undefined) {
|
|
5395
|
-
out.push(escaped);
|
|
5396
|
-
i++;
|
|
5397
|
-
}
|
|
5398
|
-
} else if (c === '"') {
|
|
5399
|
-
break;
|
|
5400
|
-
}
|
|
5401
|
-
}
|
|
5402
|
-
} else if (ch === "/" && i + 1 < src.length) {
|
|
5403
|
-
if (src[i + 1] === "/") {
|
|
5404
|
-
i += 2;
|
|
5405
|
-
while (i < src.length && src[i] !== `
|
|
5406
|
-
`) {
|
|
5407
|
-
i++;
|
|
5408
|
-
}
|
|
5409
|
-
} else if (src[i + 1] === "*") {
|
|
5410
|
-
i += 2;
|
|
5411
|
-
while (i < src.length && !(src[i] === "*" && src[i + 1] === "/")) {
|
|
5412
|
-
i++;
|
|
5413
|
-
}
|
|
5414
|
-
if (i < src.length) {
|
|
5415
|
-
i += 2;
|
|
5416
|
-
}
|
|
5417
|
-
} else {
|
|
5418
|
-
out.push(ch);
|
|
5419
|
-
i++;
|
|
5420
|
-
}
|
|
5421
|
-
} else {
|
|
5422
|
-
out.push(ch);
|
|
5423
|
-
i++;
|
|
5424
|
-
}
|
|
5534
|
+
function readStrictSemverParts(version) {
|
|
5535
|
+
const parsed = parseStrictSemverParts(version);
|
|
5536
|
+
if (parsed === undefined) {
|
|
5537
|
+
throw new Error(`invalid-strict-semver:${version}`);
|
|
5425
5538
|
}
|
|
5426
|
-
return
|
|
5539
|
+
return parsed;
|
|
5427
5540
|
}
|
|
5428
|
-
function
|
|
5429
|
-
return
|
|
5541
|
+
function isStrictSemver(v) {
|
|
5542
|
+
return parseStrictSemverParts(v) !== undefined;
|
|
5430
5543
|
}
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
if (isRecord3(baseVal) && isRecord3(value)) {
|
|
5440
|
-
result[key] = mergeOpencodeConfigs(baseVal, value);
|
|
5441
|
-
} else {
|
|
5442
|
-
result[key] = value;
|
|
5443
|
-
}
|
|
5444
|
-
}
|
|
5445
|
-
return result;
|
|
5544
|
+
function compareSemver(a, b) {
|
|
5545
|
+
const [aM, am, ap] = readStrictSemverParts(a);
|
|
5546
|
+
const [bM, bm, bp] = readStrictSemverParts(b);
|
|
5547
|
+
if (aM !== bM)
|
|
5548
|
+
return aM - bM;
|
|
5549
|
+
if (am !== bm)
|
|
5550
|
+
return am - bm;
|
|
5551
|
+
return ap - bp;
|
|
5446
5552
|
}
|
|
5447
5553
|
|
|
5448
|
-
// src/
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5554
|
+
// src/messages/commands.ts
|
|
5555
|
+
var clearCacheMessages = {
|
|
5556
|
+
header: "openteam clear-cache — frozen plugin cache entries:",
|
|
5557
|
+
columns: {
|
|
5558
|
+
specDir: "spec dir",
|
|
5559
|
+
pinned: "spec-pinned",
|
|
5560
|
+
installed: "installed",
|
|
5561
|
+
mtime: "mtime"
|
|
5562
|
+
},
|
|
5563
|
+
reparseSkipSuffix: " [SKIP — reparse point]",
|
|
5564
|
+
deletedLabel: "deleted.",
|
|
5565
|
+
lockedLabel: (message) => `[LOCKED] ${message}`,
|
|
5566
|
+
pathOutsideWarning: (specDir, absolutePath) => ` ⚠ ${specDir}: path outside cacheRoot (${absolutePath}), skipped.`,
|
|
5567
|
+
processed: (count) => `${count} entry(ies) processed.`,
|
|
5568
|
+
found: (count) => `${count} entry(ies) found. Use --delete to remove them.`
|
|
5569
|
+
};
|
|
5570
|
+
var baselineMessages = {
|
|
5571
|
+
effectiveAuto: "cheapest-capable (auto)",
|
|
5572
|
+
pinnedSuffix: (ref) => `${ref} (pinned)`,
|
|
5573
|
+
summary: (params) => [
|
|
5574
|
+
"openteam baseline:",
|
|
5575
|
+
` mode: ${params.mode}`,
|
|
5576
|
+
` pinned: ${params.pinned}`,
|
|
5577
|
+
` hardDefault: ${params.hardDefault}`,
|
|
5578
|
+
` effective: ${params.effective}`
|
|
5579
|
+
],
|
|
5580
|
+
invalidModel: (input) => `Invalid model "${input}". Use the provider/model format, e.g. anthropic/claude-sonnet-4-5.`,
|
|
5581
|
+
pinnedTo: (ref) => `Baseline pinned to ${ref} (pinned mode).`,
|
|
5582
|
+
autoMode: "Baseline set to auto mode (cheapest-capable)."
|
|
5583
|
+
};
|
|
5584
|
+
var localMessages = {
|
|
5585
|
+
help: {
|
|
5586
|
+
status: " openteam local status Show the execution mode (local / frontier / mixed)",
|
|
5587
|
+
off: " openteam local off Use frontier models only",
|
|
5588
|
+
only: " openteam local only Use local models only",
|
|
5589
|
+
on: " openteam local on Enable mixed local/frontier execution"
|
|
5590
|
+
},
|
|
5591
|
+
noRuntimes: "none",
|
|
5592
|
+
modeFrontier: "frontier",
|
|
5593
|
+
modeLocal: "local",
|
|
5594
|
+
modeMixed: "mixed",
|
|
5595
|
+
summary: (params) => [
|
|
5596
|
+
"openteam local:",
|
|
5597
|
+
` execution mode: ${params.mode}`,
|
|
5598
|
+
` local runtimes: ${params.runtimes}`
|
|
5599
|
+
],
|
|
5600
|
+
frontierOnlyNoChange: "No change: execution mode is already frontier.",
|
|
5601
|
+
frontierOnlyEnabled: "Frontier execution enabled.",
|
|
5602
|
+
localOnlyNoRuntimes: "Cannot enable local execution: no enabled local runtime is configured. Run 'openteam setup' or enable a local runtime in .opencode/openteam.json first.",
|
|
5603
|
+
localOnlyNoChange: "No change: execution mode is already local.",
|
|
5604
|
+
localOnlyEnabled: "Local execution enabled.",
|
|
5605
|
+
localFirstNoChange: "No change: execution mode is already mixed.",
|
|
5606
|
+
localFirstReEnabled: "Mixed local/frontier execution enabled. Make sure each configured provider is reachable.",
|
|
5607
|
+
unknownSubcommand: (subcommand, help) => `Unknown local subcommand: ${subcommand}
|
|
5608
|
+
|
|
5609
|
+
${help}`
|
|
5610
|
+
};
|
|
5611
|
+
var localRuntimeMessages = {
|
|
5612
|
+
modelListHttpError: (status) => `GET /models failed with HTTP ${status}`,
|
|
5613
|
+
malformedModelsJson: (detail) => `Malformed JSON from /models: ${detail}`,
|
|
5614
|
+
malformedModelsResponseExpectedDataArray: "Malformed /models response: expected data array",
|
|
5615
|
+
malformedModelsResponseModelId: "Malformed /models response: model id must be a string",
|
|
5616
|
+
dnsLookupFailedFor: (hostname, code) => `DNS lookup failed for ${hostname} (${code})`,
|
|
5617
|
+
dnsLookupFailed: (code) => `DNS lookup failed (${code})`
|
|
5618
|
+
};
|
|
5619
|
+
var yoloMessages = {
|
|
5620
|
+
updated: (path, status, agentNote) => `${path} updated. ${status}${agentNote}
|
|
5621
|
+
Restart opencode (or reload) so agents pick up the new permissions.`
|
|
5622
|
+
};
|
|
5623
|
+
var migrateMessages = {
|
|
5624
|
+
header: "openteam migrate:",
|
|
5625
|
+
nothingToMigrate: " nothing to migrate — the P15b layout is already in place.",
|
|
5626
|
+
counts: (params) => [
|
|
5627
|
+
` moved: ${params.moved} file(s)`,
|
|
5628
|
+
` deduped: ${params.deduped} file(s) (destination already identical)`,
|
|
5629
|
+
` conflicts: ${params.conflicts} file(s)`
|
|
5630
|
+
],
|
|
5631
|
+
relocatedHeader: " relocated:",
|
|
5632
|
+
relocatedEntry: (from, to, deduped) => ` · ${from} → ${to}${deduped ? " (deduped)" : ""}`,
|
|
5633
|
+
conflictsHeader: " ⚠ left in place (destination exists with different content — no data lost):",
|
|
5634
|
+
conflictEntry: (from, to) => ` · ${from} → ${to}`,
|
|
5635
|
+
manualWorktreesHeader: " ⚠ legacy git worktree(s) need a manual move (run `git worktree move`):",
|
|
5636
|
+
manualWorktreeEntry: (label, from, to) => ` · ${label}: ${from} → ${to}`,
|
|
5637
|
+
success: " ✓ machine-local runtime output relocated under .opencode/openteam-local/."
|
|
5638
|
+
};
|
|
5639
|
+
var rolesInitMessages = {
|
|
5640
|
+
help: " openteam roles init Compose per-role execution, model, and fallback policy",
|
|
5641
|
+
header: "openteam roles init:",
|
|
5642
|
+
title: "openteam roles init",
|
|
5643
|
+
noRoster: (path) => ` ✗ no roster at ${path}.`,
|
|
5644
|
+
noRosterRemedy: " Cast the team first: run `openteam setup`, then ask the orchestrator to register the cast.",
|
|
5645
|
+
unparseableRoster: (path, error) => ` ✗ ${path} is present but unparseable: ${error}`,
|
|
5646
|
+
unparseableRosterRemedy: " Run `openteam doctor` for the remedy, then re-run this command.",
|
|
5647
|
+
allProfiled: (count) => ` ✓ ${count} roster role(s) checked; no unprofiled roles — every role resolves a routing profile.`,
|
|
5648
|
+
skipLabel: "Skip for now",
|
|
5649
|
+
skipHint: "leaves the role on its built-in or fallback policy; doctor keeps reporting the missing explicit override",
|
|
5650
|
+
runtimeQuestion: (roleID) => `Preferred local runtime(s) for "${roleID}" (in failover order)`,
|
|
5651
|
+
runtimeHint: "machine-local — written to the git-ignored overlay",
|
|
5652
|
+
cancelled: (reason) => ` ✗ cancelled (${reason}); nothing was written.`,
|
|
5653
|
+
invalidResult: (reason) => ` ✗ refusing to write: the resulting config is invalid — ${reason}`,
|
|
5654
|
+
deprecation: (message) => ` ⚠ ${message}`,
|
|
5655
|
+
nothingWritten: (skipped) => ` · skipped ${skipped}; nothing written.`,
|
|
5656
|
+
nothingToWriteOutro: "Nothing to write.",
|
|
5657
|
+
runtimeBinding: (path) => ` ✓ runtime binding: ${path} (git-ignored, machine-local)`,
|
|
5658
|
+
skippedSummary: (roleIDs) => ` · skipped: ${roleIDs} — using built-in or fallback policy; re-run this command to add an explicit override.`,
|
|
5659
|
+
outro: "Role policy updated."
|
|
5660
|
+
};
|
|
5661
|
+
|
|
5662
|
+
// src/messages/executionSetup.ts
|
|
5663
|
+
var executionSetupMessages = {
|
|
5664
|
+
setupIntro: "openteam setup — configure local, frontier, or mixed team execution",
|
|
5665
|
+
runtimeQuestion: "Which local runtimes do you want to enable? (choose 'None' for frontier-only)",
|
|
5666
|
+
runtimeNoneLabel: "None — use frontier models only",
|
|
5667
|
+
runtimeNoneHint: "no local runtime (frontier execution)",
|
|
5668
|
+
executionModeQuestion: "Team execution mode",
|
|
5669
|
+
executionModeChoices: {
|
|
5670
|
+
local: {
|
|
5671
|
+
label: "local — every agent stays on configured local providers",
|
|
5672
|
+
hint: "requires at least one enabled local runtime"
|
|
5673
|
+
},
|
|
5674
|
+
frontier: {
|
|
5675
|
+
label: "frontier — every agent uses frontier providers",
|
|
5676
|
+
hint: "does not require a local runtime"
|
|
5677
|
+
},
|
|
5678
|
+
mixed: {
|
|
5679
|
+
label: "mixed — policies may select local or frontier models",
|
|
5680
|
+
hint: "the global mode is an upper bound; per-agent policies may narrow it"
|
|
5681
|
+
}
|
|
5682
|
+
},
|
|
5683
|
+
frontierOnlyNote: [
|
|
5684
|
+
"No local runtime is enabled, so the team will use frontier providers.",
|
|
5685
|
+
"The selected primary model is written consistently to opencode.json and",
|
|
5686
|
+
".opencode/agent/openteam.md."
|
|
5687
|
+
].join(`
|
|
5688
|
+
`),
|
|
5689
|
+
frontierOnlyTitle: "Frontier execution",
|
|
5690
|
+
localOnlyNote: (model) => [
|
|
5691
|
+
"Every team agent is restricted to configured local providers.",
|
|
5692
|
+
`The primary coordinator is pinned to ${model}.`,
|
|
5693
|
+
"No frontier provider is required for execution while this mode is active."
|
|
5694
|
+
].join(`
|
|
5695
|
+
`),
|
|
5696
|
+
localOnlyTitle: "Local execution",
|
|
5697
|
+
localRequiredError: "local execution requires an enabled local runtime",
|
|
5698
|
+
mixedPrimaryQuestion: "Primary coordinator model",
|
|
5699
|
+
mixedPrimaryLocal: (model) => `Use local thinking model ${model}`,
|
|
5700
|
+
mixedPrimaryFrontier: "Choose a frontier model",
|
|
5701
|
+
frontierModelQuestion: "Frontier model (type to search; cheapest capable entries first)",
|
|
5702
|
+
primaryPolicySummary: (params) => [
|
|
5703
|
+
`Execution mode: ${params.executionMode}`,
|
|
5704
|
+
`Primary model: ${params.primaryModel}`,
|
|
5705
|
+
`Primary fallbacks: ${params.fallbacks}`,
|
|
5706
|
+
"Worker model policy: auto within the global execution mode"
|
|
5707
|
+
],
|
|
5708
|
+
noFallbacks: "none",
|
|
5709
|
+
yoloQuestion: "Enable YOLO mode? (opencode auto-approves all permissions)",
|
|
5710
|
+
configuredSummary: (params) => [
|
|
5711
|
+
...executionSetupMessages.primaryPolicySummary({
|
|
5712
|
+
executionMode: params.executionMode,
|
|
5713
|
+
primaryModel: params.primaryModel,
|
|
5714
|
+
fallbacks: executionSetupMessages.noFallbacks
|
|
5715
|
+
}),
|
|
5716
|
+
`Frontier baseline: ${params.frontierBaseline}`,
|
|
5717
|
+
`Local runtimes: ${params.localRuntimes}`,
|
|
5718
|
+
`YOLO mode: ${params.yolo ? "enabled (auto-approves permissions)" : "disabled"}`,
|
|
5719
|
+
"Web Console: launched separately with 'openteam console' (multi-session, loopback)",
|
|
5720
|
+
`Wrote: ${params.opencodePath}, ${params.configPath}, ${params.agentPath}, ${params.agentDir}/*.md (${params.roleAgentCount} standard subagents), ${params.commandDir}/*.md (${params.commandCount} commands); ensured ${params.gitignorePath}`,
|
|
5721
|
+
"",
|
|
5722
|
+
"Next steps:",
|
|
5723
|
+
params.executionMode === "local" ? " 1. No frontier authentication is required while local execution is active" : " 1. Authenticate the frontier provider: opencode auth login",
|
|
5724
|
+
params.executionMode === "local" ? executionSetupMessages.localRuntimeNextStep : params.executionMode === "mixed" ? executionSetupMessages.mixedNextStep : executionSetupMessages.frontierNextStep,
|
|
5725
|
+
" 3. Press Tab and pick the 'openteam' agent, or type / and pick an /openteam… command"
|
|
5726
|
+
],
|
|
5727
|
+
configuredTitle: "openteam configured",
|
|
5728
|
+
complete: (paths) => `openteam setup complete: ${paths}`,
|
|
5729
|
+
error: (message) => `setup error: ${message}`,
|
|
5730
|
+
localRuntimeNextStep: " 2. Make sure every configured local runtime is reachable",
|
|
5731
|
+
frontierNextStep: " 2. Open opencode in this repo; openteam will use frontier models",
|
|
5732
|
+
mixedNextStep: " 2. Make sure local runtimes are reachable; unavailable candidates can use configured fallbacks",
|
|
5733
|
+
done: "Done. Open opencode and select the 'openteam' agent.",
|
|
5734
|
+
pluginDowngradeNote: (existingVersion, binaryVersion) => [
|
|
5735
|
+
`The installed opencode.json pin is @${existingVersion}, which is newer than this binary (${binaryVersion}).`,
|
|
5736
|
+
"Re-running setup with an older binary would quietly downgrade the pin.",
|
|
5737
|
+
"Confirm below to downgrade, or cancel to keep the existing pin."
|
|
5738
|
+
].join(`
|
|
5739
|
+
`),
|
|
5740
|
+
pluginDowngradeTitle: "Plugin pin downgrade detected",
|
|
5741
|
+
pluginDowngradeConfirm: (existingVersion, binaryVersion) => `Downgrade plugin pin from ${existingVersion} to ${binaryVersion}?`,
|
|
5742
|
+
pluginDowngradePreservedNote: (existingVersion) => `Preserved existing plugin pin @${existingVersion} (not downgraded).`,
|
|
5743
|
+
rerun: {
|
|
5744
|
+
unsafeExistingConfig: (path, detail) => `${path} cannot be safely updated. Fix the file first, then re-run setup. Detail: ${detail}`,
|
|
5745
|
+
emptyConfigObject: "the file is empty; expected a JSON object at the top level",
|
|
5746
|
+
topLevelObjectRequired: "expected a JSON object at the top level",
|
|
5747
|
+
configFormatKinds: {
|
|
5748
|
+
comments: "JSONC comments",
|
|
5749
|
+
trailingCommas: "trailing commas",
|
|
5750
|
+
commentsAndTrailingCommas: "JSONC comments and trailing commas"
|
|
5751
|
+
},
|
|
5752
|
+
configFormatNormalizationNote: (path, kinds) => `${path} uses ${kinds}. Re-running setup rewrites it as standard JSON and removes them.`,
|
|
5753
|
+
configFormatNormalizationTitle: "Config format will be normalized",
|
|
5754
|
+
configFormatNormalizationConfirm: (path) => `Rewrite ${path} as standard JSON?`,
|
|
5755
|
+
providerModelsObjectRequired: (providerID) => `provider.${providerID}.models must be a JSON object`,
|
|
5756
|
+
duplicateTopLevelKeys: (keys) => `duplicate top-level key(s): ${keys.map((key) => JSON.stringify(key)).join(", ")}`,
|
|
5757
|
+
unknownLocalPluginIdentity: (spec) => `plugin entry ${JSON.stringify(spec)} points to a local file whose package identity could not be verified; keep the existing local loader or replace it with an explicit ${JSON.stringify("@jmanuelcorral/openteam@x.y.z")} npm pin before re-running setup`,
|
|
5758
|
+
providerModelObjectRequired: (providerID, modelID) => `provider.${providerID}.models.${modelID} must be a JSON object`,
|
|
5759
|
+
providerModelLimitObjectRequired: (providerID, modelID) => `provider.${providerID}.models.${modelID}.limit must be a JSON object`,
|
|
5760
|
+
providerModelLimitPositiveInteger: (providerID, modelID, field) => `provider.${providerID}.models.${modelID}.limit.${field} must be a positive integer`
|
|
5761
|
+
},
|
|
5762
|
+
rolePolicy: {
|
|
5763
|
+
whyTitle: "Configure execution and model selection",
|
|
5764
|
+
why: (count) => `${count} roster role(s) have no explicit execution/model override. Configure a compact policy now, or leave them on the built-in automatic policy.`,
|
|
5765
|
+
modeQuestion: (roleID, agentName) => `Execution mode for "${roleID}" (${agentName})`,
|
|
5766
|
+
modeInheritLabel: "Inherit the team execution mode",
|
|
5767
|
+
modeLocalLabel: "Local only",
|
|
5768
|
+
modeFrontierLabel: "Frontier only",
|
|
5769
|
+
modelQuestion: (roleID) => `Model selection for "${roleID}"`,
|
|
5770
|
+
modelAutoLabel: "Auto — choose the cheapest capable eligible model",
|
|
5771
|
+
modelExactLabel: "Exact provider/model pin",
|
|
5772
|
+
modelExactQuestion: (roleID) => `Exact model for "${roleID}" as provider/model`,
|
|
5773
|
+
modelExactPlaceholder: "provider/model",
|
|
5774
|
+
fallbacksQuestion: (roleID) => `Ordered fallbacks for "${roleID}" (comma-separated provider/model, blank for none)`,
|
|
5775
|
+
fallbacksPlaceholder: "provider/model, provider/model",
|
|
5776
|
+
configured: (roleIDs, path) => ` ✓ execution/model policy: ${roleIDs} → ${path}`,
|
|
5777
|
+
invalidModelRef: (value) => `invalid model "${value}"; expected provider/model`
|
|
5778
|
+
}
|
|
5779
|
+
};
|
|
5780
|
+
var executionPolicyMessages = {
|
|
5781
|
+
doctorHelp: " openteam doctor Diagnose runtimes, execution policies, and config",
|
|
5782
|
+
agentsHelp: " openteam agents List agents, model identity, and execution policy",
|
|
5783
|
+
section: "Configured execution policies:",
|
|
5784
|
+
globalMode: (mode) => ` execution mode: ${mode}`,
|
|
5785
|
+
line: (policy) => ` ${policy.owner}: mode=${policy.executionMode ?? "inherit"} · model=${policy.model} · fallbacks=${policy.fallbacks.length > 0 ? policy.fallbacks.join(" → ") : "none"}`,
|
|
5786
|
+
retryLimits: (maxRetries, maxModelsPerNode) => ` retry limits: ${maxRetries} retries per model · ${maxModelsPerNode} model(s) per node`,
|
|
5787
|
+
inheritedDefaultUnset: "inherits the opencode.json default (not set); execution follows the configured team and agent policy",
|
|
5788
|
+
inheritedDefault: (subscription) => `inherits default → ${subscription}; execution follows the configured team and agent policy`,
|
|
5789
|
+
unprofiledRoleRouting: " routing: no explicit override — the role inherits its built-in or fallback policy within the global execution-mode upper bound. Roster prose is not executable configuration.",
|
|
5790
|
+
unprofiledRoleRemedy: " remedy: run `openteam roles init`, or add executionMode, model, and ordered fallbacks under orchestrator.roles in .opencode/openteam.json.",
|
|
5791
|
+
noLocalMixed: " ⚠ No local runtime reachable: mixed execution currently has only frontier candidates.",
|
|
5792
|
+
noLocalBlocked: " ✗ No local runtime reachable: local execution is blocked until a configured runtime is available.",
|
|
5793
|
+
primaryLocalMismatch: (name, providerID) => ` ✗ local execution is configured, but primary agent '${name}' points at provider '${providerID}', which opencode.json does not configure.`,
|
|
5794
|
+
primaryLocalMismatchCause: " cause: the primary agent artifact and opencode.json no longer agree on the selected provider/model identity.",
|
|
5795
|
+
primaryLocalMismatchConsequence: " consequence: opencode cannot start the coordinator, so it cannot read the roster or distribute work.",
|
|
5796
|
+
primaryLocalMismatchRemedy: (sourceFile) => ` remedy: re-run \`openteam setup\` to regenerate ${sourceFile} and opencode.json from the same primary policy, then re-run \`openteam doctor\`.`
|
|
5797
|
+
};
|
|
5798
|
+
var doctorMessages = {
|
|
5799
|
+
localModelLimits: {
|
|
5800
|
+
section: " local model limits:",
|
|
5801
|
+
healthy: " ✓ enabled local provider models declare valid output and context limits in opencode.json.",
|
|
5802
|
+
warningSummary: (count) => ` local model limits: ${count} warning(s)`,
|
|
5803
|
+
modelWarning: (providerID, modelID, problems) => ` ⚠ ${providerID}/${modelID}: ${problems}`,
|
|
5804
|
+
invalidLimitBlock: "invalid limit block (expected an object)",
|
|
5805
|
+
missingOutput: "no limit.output (opencode falls back to its 32 000-token default instead of openteam's 8 192-token client policy)",
|
|
5806
|
+
missingContext: "no limit.context (the runtime's usable prompt window remains unknown to opencode)",
|
|
5807
|
+
invalidOutput: "invalid limit.output (expected a positive integer token count)",
|
|
5808
|
+
invalidContext: "invalid limit.context (expected a positive integer token count)",
|
|
5809
|
+
invalidInput: "invalid limit.input (expected a positive integer token count)",
|
|
5810
|
+
outputExceedsContext: "limit.output is greater than or equal to limit.context, so the configured context leaves no usable input window",
|
|
5811
|
+
outputExceedsInput: "limit.input is less than or equal to the reserved output budget, so compaction would have no usable input threshold",
|
|
5812
|
+
outputRemedy: " remedy: re-run `openteam setup` to write openteam's 8 192-token local output default, then re-run `openteam doctor`.",
|
|
5813
|
+
detectedContextRemedy: " remedy: re-run `openteam setup` while the runtime is reachable to copy the detected usable context budget, then re-run `openteam doctor`.",
|
|
5814
|
+
unknownContextRemedy: " remedy: add `limit.context` manually for models whose runtime does not advertise a context window; `openteam setup` will not invent one.",
|
|
5815
|
+
invalidLimitRemedy: " remedy: fix the invalid local limit values in opencode.json before relying on this provider configuration."
|
|
5816
|
+
}
|
|
5817
|
+
};
|
|
5818
|
+
var localModeChangeMessages = {
|
|
5819
|
+
localProviderInFrontierDomain: (path, domainPath, providerID, modelID) => `${path}: model "${providerID}/${modelID}" uses provider "${providerID}", which is configured for local dispatch and cannot be selected when ${domainPath} is "frontier". Update this policy or use \`openteam local on\`.`,
|
|
5820
|
+
frontierProviderInLocalDomain: (path, domainPath, providerID, modelID) => `${path}: model "${providerID}/${modelID}" uses provider "${providerID}", which is not a configured local provider and cannot be selected when ${domainPath} is "local". Update this policy or use \`openteam local on\`.`
|
|
5821
|
+
};
|
|
5822
|
+
|
|
5823
|
+
// src/messages/upgrade.ts
|
|
5824
|
+
var upgradeMessages = {
|
|
5825
|
+
header: "openteam upgrade:",
|
|
5826
|
+
help: {
|
|
5827
|
+
command: " openteam upgrade Update the openteam plugin pin to the latest published version",
|
|
5828
|
+
check: " openteam upgrade --check Show current/target versions without making changes",
|
|
5829
|
+
version: " openteam upgrade --version x.y.z Pin to a specific published version",
|
|
5830
|
+
usage: " openteam upgrade [--check] [--version x.y.z]"
|
|
5831
|
+
},
|
|
5832
|
+
usageLabel: "Usage:",
|
|
5833
|
+
invalidArguments: (detail) => ` ✗ ${detail}`,
|
|
5834
|
+
duplicateCheck: "Flag --check may be provided only once.",
|
|
5835
|
+
duplicateVersion: "Flag --version may be provided only once.",
|
|
5836
|
+
missingVersionValue: "Flag --version requires a plain x.y.z value.",
|
|
5837
|
+
unknownFlag: (flag) => `Unknown flag ${flag}.`,
|
|
5838
|
+
unexpectedArgument: (value) => `Unexpected argument ${value}.`,
|
|
5839
|
+
checkNeedsUpdate: (params) => ` ${params.path}: ${params.current !== null ? params.current : "(unpinned)"} → ${params.target}`,
|
|
5840
|
+
checkAlreadyCurrent: (params) => ` ${params.path}: already at ${params.version}`,
|
|
5841
|
+
checkHint: (version) => version === undefined ? " Run 'openteam upgrade' (without --check) to apply." : ` Run 'openteam upgrade --version ${version}' (without --check) to apply.`,
|
|
5842
|
+
alreadyCurrent: (version) => ` Already at ${version}; nothing to update.`,
|
|
5843
|
+
updatedHeader: (version) => ` ✓ Plugin pin updated to ${version} in:`,
|
|
5844
|
+
partialHeader: (version) => ` ⚠ Plugin pin updated to ${version} in:`,
|
|
5845
|
+
partialFailuresHeader: " The following file(s) were not changed:",
|
|
5846
|
+
nothingChanged: " ✗ No files were changed.",
|
|
5847
|
+
writtenEntry: (path) => ` ✓ ${path}`,
|
|
5848
|
+
failedEntry: (params) => ` ✗ ${params.path}: ${params.error}`,
|
|
5849
|
+
backupNote: (directory) => ` Backups of the previous file contents were saved under ${directory}.`,
|
|
5850
|
+
restartHint: " Restart opencode to load the new plugin version.",
|
|
5851
|
+
cacheCleanupHint: " Cache cleanup is optional; run 'openteam clear-cache --delete' if you want to remove stale cache entries.",
|
|
5852
|
+
resolveFailuresBeforeRestart: " Resolve the failed file(s) before restarting opencode.",
|
|
5853
|
+
rerunAfterFailures: " Resolve the failed file(s) and re-run the command; no restart is needed.",
|
|
5854
|
+
noConfigFound: (paths) => `No opencode config found (searched: ${paths.join(", ")}). Run 'openteam setup' first.`,
|
|
5855
|
+
noPluginEntry: "No openteam plugin entry found in opencode config. Run 'openteam setup' first.",
|
|
5856
|
+
localFileSkipped: (params) => ` ⚠ Skipped local openteam file entry in ${params.path}: ${params.spec} — local development installs are not managed by upgrade.`,
|
|
5857
|
+
localFileOnlyHeader: " Local openteam file plugin entries were found:",
|
|
5858
|
+
localFileOnlyEntry: (params) => ` ${params.path}: ${params.spec}`,
|
|
5859
|
+
localFileOnlyRemedy: ' Upgrade manages npm pins only. Keep the local development install, or replace the entry manually with "@jmanuelcorral/openteam@x.y.z".',
|
|
5860
|
+
invalidVersion: (v) => `Invalid version "${v}": must be a plain semver (e.g. 1.2.3) with no leading zeros, range operators, or dist-tags.`,
|
|
5861
|
+
versionNotFound: (v) => `Version ${v} was not found in the npm registry. Verify that the version is published.`,
|
|
5862
|
+
fetchError: (message) => `Failed to resolve version from the npm registry: ${message}`,
|
|
5863
|
+
noDowngrade: (params) => `Automatic latest (${params.target}) is older than the current pin (${params.current}). ` + `The npm registry metadata may be stale. Use --version ${params.current} to keep the ` + `current pin, or --version ${params.target} to explicitly downgrade.`,
|
|
5864
|
+
portNotConfigured: "The upgrade port is not configured in this environment.",
|
|
5865
|
+
genericFetchFailed: "fetch failed",
|
|
5866
|
+
networkRequestFailed: "network request failed",
|
|
5867
|
+
networkRequestFailedWithDetail: (detail) => `network request failed: ${detail}`,
|
|
5868
|
+
requestTimedOut: (timeoutMs) => `request timed out after ${timeoutMs} ms`,
|
|
5869
|
+
responseReadFailed: "response body could not be read completely",
|
|
5870
|
+
responseTooLarge: (limitBytes) => `response body exceeded the ${limitBytes}-byte limit`,
|
|
5871
|
+
missingRegistryBody: "registry response body was empty",
|
|
5872
|
+
invalidRegistryJson: "invalid JSON in registry response",
|
|
5873
|
+
unterminatedBlockComment: "unterminated block comment",
|
|
5874
|
+
invalidRegistryPayload: 'unexpected registry response: expected a JSON object with string "name" and "version" fields',
|
|
5875
|
+
unexpectedVersionField: (raw) => `unexpected registry response: version field is ${raw}`,
|
|
5876
|
+
wrongPackageIdentity: (name) => `registry returned wrong package identity "${name}"`,
|
|
5877
|
+
unexpectedPublishedVersion: (params) => `registry returned version "${params.actual}" while verifying ${params.expected}`,
|
|
5878
|
+
httpStatus: (status) => `HTTP ${status}`,
|
|
5879
|
+
readConfigError: (path, message) => `Error reading ${path}: ${message}`,
|
|
5880
|
+
parseConfigError: (path, message) => `Cannot parse ${path} (malformed JSONC): ${message}`,
|
|
5881
|
+
configRootMustBeObject: (path, kind) => `Cannot parse ${path}: top-level value must be a JSON object (found ${kind}).`,
|
|
5882
|
+
pluginFieldMustBeArray: (path) => `Cannot parse ${path}: the top-level plugin field must be an array when present.`,
|
|
5883
|
+
pluginArrayEditUnavailable: (path) => `Cannot update ${path}: could not locate the top-level plugin array for a source-preserving edit.`,
|
|
5884
|
+
effectivePluginUpdateMismatch: (path) => `Cannot update ${path}: the source-preserving edit did not change the effective top-level plugin entry as expected.`,
|
|
5885
|
+
concurrentEdit: (path) => `${path} changed since it was read; refusing to overwrite it.`,
|
|
5886
|
+
writeTargetMissing: (path) => `${path} disappeared before it could be updated.`,
|
|
5887
|
+
unsafeFilesystemEntry: "expected a regular file inside the workspace; symlinks are not supported",
|
|
5888
|
+
backupLocationUnavailable: (path) => `Cannot update config: backup location ${path} is unavailable or unsafe.`,
|
|
5889
|
+
backupConflict: (path) => `Refusing to overwrite unexpected backup file ${path}.`,
|
|
5890
|
+
backupGitignoreUnexpected: (directory) => `Cannot write upgrade backups: the .gitignore in ${directory} has unexpected content. ` + `It must contain only "*\\n" (ignore everything). Restore it or remove it so the upgrade can manage it.`,
|
|
5891
|
+
windowsDaclPrepFailed: (path, message) => `Cannot update ${path}: failed to apply file ACL to staging file before write: ${message}`,
|
|
5892
|
+
windowsReplaceFailed: (path, message) => `Cannot update ${path} while preserving Windows file ACLs: ${message}`
|
|
5893
|
+
};
|
|
5894
|
+
|
|
5895
|
+
// src/commands/upgrade.ts
|
|
5896
|
+
var NPM_ORIGIN = "https://registry.npmjs.org";
|
|
5897
|
+
var NPM_PACKAGE_PATH = "/@jmanuelcorral%2Fopenteam";
|
|
5898
|
+
var NPM_LATEST_URL = `${NPM_ORIGIN}${NPM_PACKAGE_PATH}/latest`;
|
|
5899
|
+
var FETCH_TIMEOUT_MS = 5000;
|
|
5900
|
+
var MAX_RESPONSE_BYTES = 64 * 1024;
|
|
5901
|
+
var MAX_FETCH_ATTEMPTS = 2;
|
|
5902
|
+
var PLUGIN_KEY = "plugin";
|
|
5903
|
+
var PRIVATE_DIRECTORY_MODE = 448;
|
|
5904
|
+
var PRIVATE_FILE_MODE = 384;
|
|
5905
|
+
var UPGRADE_BACKUP_GITIGNORE_CONTENT = `*
|
|
5906
|
+
`;
|
|
5907
|
+
var WINDOWS_POWERSHELL_EXE = join9(process.env.SystemRoot ?? "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
|
|
5908
|
+
var WINDOWS_PS_TIMEOUT_MS = 1e4;
|
|
5909
|
+
var UPGRADE_BACKUP_SUFFIX = ".openteam-upgrade.bak";
|
|
5910
|
+
var UPGRADE_BACKUP_DIRECTORY = ".opencode/openteam-local/upgrade-backups";
|
|
5911
|
+
function npmVersionUrl(version) {
|
|
5912
|
+
return `${NPM_ORIGIN}${NPM_PACKAGE_PATH}/${version}`;
|
|
5913
|
+
}
|
|
5914
|
+
var RegistryPackageIdentitySchema = z15.object({
|
|
5915
|
+
name: z15.string(),
|
|
5916
|
+
version: z15.string()
|
|
5917
|
+
}).strict();
|
|
5918
|
+
|
|
5919
|
+
class TransientFetchError extends Error {
|
|
5920
|
+
constructor(message) {
|
|
5921
|
+
super(message);
|
|
5922
|
+
this.name = "TransientFetchError";
|
|
5923
|
+
}
|
|
5924
|
+
}
|
|
5925
|
+
|
|
5926
|
+
class PermanentFetchError extends Error {
|
|
5927
|
+
constructor(message) {
|
|
5928
|
+
super(message);
|
|
5929
|
+
this.name = "PermanentFetchError";
|
|
5930
|
+
}
|
|
5931
|
+
}
|
|
5932
|
+
var GENERIC_FETCH_FAILURE_MESSAGES = new Set([
|
|
5933
|
+
upgradeMessages.genericFetchFailed,
|
|
5934
|
+
upgradeMessages.networkRequestFailed
|
|
5935
|
+
]);
|
|
5936
|
+
var execFileAsync2 = promisify2(execFile2);
|
|
5937
|
+
function isMissingFile(error) {
|
|
5938
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
5939
|
+
}
|
|
5940
|
+
function isAlreadyExistsFile(error) {
|
|
5941
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
5942
|
+
}
|
|
5943
|
+
function isRecord3(value) {
|
|
5944
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5945
|
+
}
|
|
5946
|
+
function isTuplePluginEntry(value) {
|
|
5947
|
+
return Array.isArray(value) && value.length >= 1 && typeof value[0] === "string";
|
|
5948
|
+
}
|
|
5949
|
+
function extractSpecString(entry) {
|
|
5950
|
+
if (typeof entry === "string") {
|
|
5951
|
+
return entry;
|
|
5952
|
+
}
|
|
5953
|
+
if (isTuplePluginEntry(entry)) {
|
|
5954
|
+
return entry[0];
|
|
5955
|
+
}
|
|
5956
|
+
return;
|
|
5957
|
+
}
|
|
5958
|
+
function isLocalFileSpec(spec) {
|
|
5959
|
+
const lower = spec.toLowerCase();
|
|
5960
|
+
return lower.startsWith("file:") || spec.startsWith("./") || spec.startsWith(".\\") || spec.startsWith("../") || spec.startsWith("..\\") || spec.startsWith("/") || spec.startsWith("\\") || win32.isAbsolute(spec);
|
|
5961
|
+
}
|
|
5962
|
+
function isOurSpec(spec) {
|
|
5963
|
+
return spec === OPENTEAM_PACKAGE_NAME || spec.startsWith(`${OPENTEAM_PACKAGE_NAME}@`);
|
|
5964
|
+
}
|
|
5965
|
+
function currentPinnedVersion(spec) {
|
|
5966
|
+
if (spec === OPENTEAM_PACKAGE_NAME) {
|
|
5967
|
+
return null;
|
|
5968
|
+
}
|
|
5969
|
+
const version = spec.slice(`${OPENTEAM_PACKAGE_NAME}@`.length);
|
|
5970
|
+
return version.length > 0 ? version : null;
|
|
5971
|
+
}
|
|
5972
|
+
function describeJsonRootKind(value) {
|
|
5973
|
+
if (value === null) {
|
|
5974
|
+
return "null";
|
|
5975
|
+
}
|
|
5976
|
+
if (Array.isArray(value)) {
|
|
5977
|
+
return "array";
|
|
5978
|
+
}
|
|
5979
|
+
switch (typeof value) {
|
|
5980
|
+
case "boolean":
|
|
5981
|
+
return "boolean";
|
|
5982
|
+
case "number":
|
|
5983
|
+
return "number";
|
|
5984
|
+
default:
|
|
5985
|
+
return "string";
|
|
5986
|
+
}
|
|
5987
|
+
}
|
|
5988
|
+
function findBlockCommentEnd(src, start, limit = src.length) {
|
|
5989
|
+
let i = start + 2;
|
|
5990
|
+
while (i < limit && !(src[i] === "*" && src[i + 1] === "/")) {
|
|
5991
|
+
i += 1;
|
|
5992
|
+
}
|
|
5993
|
+
return i < limit ? i + 2 : undefined;
|
|
5994
|
+
}
|
|
5995
|
+
function skipTrivia(src, start, limit = src.length) {
|
|
5996
|
+
let i = start;
|
|
5997
|
+
while (i < limit) {
|
|
5998
|
+
const ch = src[i];
|
|
5999
|
+
if (ch === undefined) {
|
|
6000
|
+
break;
|
|
6001
|
+
}
|
|
6002
|
+
if (/\s/u.test(ch)) {
|
|
6003
|
+
i += 1;
|
|
6004
|
+
continue;
|
|
6005
|
+
}
|
|
6006
|
+
if (ch === "/" && src[i + 1] === "/") {
|
|
6007
|
+
i += 2;
|
|
6008
|
+
while (i < limit && src[i] !== `
|
|
6009
|
+
`) {
|
|
6010
|
+
i += 1;
|
|
6011
|
+
}
|
|
6012
|
+
continue;
|
|
6013
|
+
}
|
|
6014
|
+
if (ch === "/" && src[i + 1] === "*") {
|
|
6015
|
+
const blockCommentEnd = findBlockCommentEnd(src, i, limit);
|
|
6016
|
+
if (blockCommentEnd === undefined) {
|
|
6017
|
+
return limit;
|
|
6018
|
+
}
|
|
6019
|
+
i = blockCommentEnd;
|
|
6020
|
+
continue;
|
|
6021
|
+
}
|
|
6022
|
+
break;
|
|
6023
|
+
}
|
|
6024
|
+
return i;
|
|
6025
|
+
}
|
|
6026
|
+
function readStringToken(src, start, limit = src.length) {
|
|
6027
|
+
if (src[start] !== '"') {
|
|
6028
|
+
return;
|
|
6029
|
+
}
|
|
6030
|
+
let i = start + 1;
|
|
6031
|
+
while (i < limit) {
|
|
6032
|
+
const ch = src[i];
|
|
6033
|
+
if (ch === undefined) {
|
|
6034
|
+
return;
|
|
6035
|
+
}
|
|
6036
|
+
if (ch === "\\") {
|
|
6037
|
+
i += 2;
|
|
6038
|
+
continue;
|
|
6039
|
+
}
|
|
6040
|
+
if (ch === '"') {
|
|
6041
|
+
return { end: i + 1 };
|
|
6042
|
+
}
|
|
6043
|
+
i += 1;
|
|
6044
|
+
}
|
|
6045
|
+
return;
|
|
6046
|
+
}
|
|
6047
|
+
function normalizeJsoncForParse(src) {
|
|
6048
|
+
const out = [];
|
|
6049
|
+
let i = 0;
|
|
6050
|
+
while (i < src.length) {
|
|
6051
|
+
const ch = src[i];
|
|
6052
|
+
if (ch === undefined) {
|
|
6053
|
+
break;
|
|
6054
|
+
}
|
|
6055
|
+
if (ch === '"') {
|
|
6056
|
+
const token = readStringToken(src, i);
|
|
6057
|
+
if (token === undefined) {
|
|
6058
|
+
out.push(ch);
|
|
6059
|
+
i += 1;
|
|
6060
|
+
continue;
|
|
6061
|
+
}
|
|
6062
|
+
out.push(src.slice(i, token.end));
|
|
6063
|
+
i = token.end;
|
|
6064
|
+
continue;
|
|
6065
|
+
}
|
|
6066
|
+
if (ch === "/" && src[i + 1] === "/") {
|
|
6067
|
+
i = skipTrivia(src, i);
|
|
6068
|
+
continue;
|
|
6069
|
+
}
|
|
6070
|
+
if (ch === "/" && src[i + 1] === "*") {
|
|
6071
|
+
const blockCommentEnd = findBlockCommentEnd(src, i);
|
|
6072
|
+
if (blockCommentEnd === undefined) {
|
|
6073
|
+
throw new Error(upgradeMessages.unterminatedBlockComment);
|
|
6074
|
+
}
|
|
6075
|
+
i = blockCommentEnd;
|
|
6076
|
+
continue;
|
|
6077
|
+
}
|
|
6078
|
+
if (ch === ",") {
|
|
6079
|
+
const next = skipTrivia(src, i + 1);
|
|
6080
|
+
const nextChar = src[next];
|
|
6081
|
+
if (nextChar === "]" || nextChar === "}") {
|
|
6082
|
+
i += 1;
|
|
6083
|
+
continue;
|
|
6084
|
+
}
|
|
6085
|
+
}
|
|
6086
|
+
out.push(ch);
|
|
6087
|
+
i += 1;
|
|
6088
|
+
}
|
|
6089
|
+
return out.join("");
|
|
6090
|
+
}
|
|
6091
|
+
function parseConfigDocument(path, content) {
|
|
6092
|
+
let parsed;
|
|
6093
|
+
try {
|
|
6094
|
+
const normalized = normalizeJsoncForParse(content);
|
|
6095
|
+
parsed = JSON.parse(normalized);
|
|
6096
|
+
} catch (error) {
|
|
6097
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6098
|
+
return { ok: false, error: upgradeMessages.parseConfigError(path, message) };
|
|
6099
|
+
}
|
|
6100
|
+
if (!isRecord3(parsed)) {
|
|
6101
|
+
return {
|
|
6102
|
+
ok: false,
|
|
6103
|
+
error: upgradeMessages.configRootMustBeObject(path, describeJsonRootKind(parsed))
|
|
6104
|
+
};
|
|
6105
|
+
}
|
|
6106
|
+
return { ok: true, value: parsed };
|
|
6107
|
+
}
|
|
6108
|
+
function readJsoncValueEnd(src, start, limit) {
|
|
6109
|
+
const ch = src[start];
|
|
6110
|
+
if (ch === undefined) {
|
|
6111
|
+
return;
|
|
6112
|
+
}
|
|
6113
|
+
if (ch === '"') {
|
|
6114
|
+
return readStringToken(src, start, limit)?.end;
|
|
6115
|
+
}
|
|
6116
|
+
if (ch === "{" || ch === "[") {
|
|
6117
|
+
const stack = [];
|
|
6118
|
+
let i2 = start;
|
|
6119
|
+
while (i2 < limit) {
|
|
6120
|
+
const next = skipTrivia(src, i2, limit);
|
|
6121
|
+
i2 = next;
|
|
6122
|
+
const current = src[i2];
|
|
6123
|
+
if (current === undefined) {
|
|
6124
|
+
return;
|
|
6125
|
+
}
|
|
6126
|
+
if (current === '"') {
|
|
6127
|
+
const token = readStringToken(src, i2, limit);
|
|
6128
|
+
if (token === undefined) {
|
|
6129
|
+
return;
|
|
6130
|
+
}
|
|
6131
|
+
i2 = token.end;
|
|
6132
|
+
continue;
|
|
6133
|
+
}
|
|
6134
|
+
if (current === "{" || current === "[") {
|
|
6135
|
+
stack.push(current);
|
|
6136
|
+
i2 += 1;
|
|
6137
|
+
continue;
|
|
6138
|
+
}
|
|
6139
|
+
if (current === "}" || current === "]") {
|
|
6140
|
+
const open2 = stack[stack.length - 1];
|
|
6141
|
+
if (current === "}" && open2 !== "{" || current === "]" && open2 !== "[") {
|
|
6142
|
+
return;
|
|
6143
|
+
}
|
|
6144
|
+
stack.pop();
|
|
6145
|
+
i2 += 1;
|
|
6146
|
+
if (stack.length === 0) {
|
|
6147
|
+
return i2;
|
|
6148
|
+
}
|
|
6149
|
+
continue;
|
|
6150
|
+
}
|
|
6151
|
+
i2 += 1;
|
|
6152
|
+
}
|
|
6153
|
+
return;
|
|
6154
|
+
}
|
|
6155
|
+
let i = start;
|
|
6156
|
+
while (i < limit) {
|
|
6157
|
+
const current = src[i];
|
|
6158
|
+
if (current === undefined) {
|
|
6159
|
+
break;
|
|
6160
|
+
}
|
|
6161
|
+
if (/\s/u.test(current) || current === "," || current === "]" || current === "}" || current === "/" && (src[i + 1] === "/" || src[i + 1] === "*")) {
|
|
6162
|
+
break;
|
|
6163
|
+
}
|
|
6164
|
+
i += 1;
|
|
6165
|
+
}
|
|
6166
|
+
return i > start ? i : undefined;
|
|
6167
|
+
}
|
|
6168
|
+
function findTopLevelPluginArray(raw) {
|
|
6169
|
+
let found;
|
|
6170
|
+
let i = 0;
|
|
6171
|
+
let depth = 0;
|
|
6172
|
+
while (i < raw.length) {
|
|
6173
|
+
i = skipTrivia(raw, i);
|
|
6174
|
+
const ch = raw[i];
|
|
6175
|
+
if (ch === undefined) {
|
|
6176
|
+
break;
|
|
6177
|
+
}
|
|
6178
|
+
if (ch === "{") {
|
|
6179
|
+
depth += 1;
|
|
6180
|
+
i += 1;
|
|
6181
|
+
continue;
|
|
6182
|
+
}
|
|
6183
|
+
if (ch === "}") {
|
|
6184
|
+
if (depth > 0) {
|
|
6185
|
+
depth -= 1;
|
|
6186
|
+
}
|
|
6187
|
+
i += 1;
|
|
6188
|
+
continue;
|
|
6189
|
+
}
|
|
6190
|
+
if (ch === "[") {
|
|
6191
|
+
depth += 1;
|
|
6192
|
+
i += 1;
|
|
6193
|
+
continue;
|
|
6194
|
+
}
|
|
6195
|
+
if (ch === "]") {
|
|
6196
|
+
if (depth > 0) {
|
|
6197
|
+
depth -= 1;
|
|
6198
|
+
}
|
|
6199
|
+
i += 1;
|
|
6200
|
+
continue;
|
|
6201
|
+
}
|
|
6202
|
+
if (ch !== '"') {
|
|
6203
|
+
i += 1;
|
|
6204
|
+
continue;
|
|
6205
|
+
}
|
|
6206
|
+
const token = readStringToken(raw, i);
|
|
6207
|
+
if (token === undefined) {
|
|
6208
|
+
return;
|
|
6209
|
+
}
|
|
6210
|
+
const key = readJsonStringValue(raw, { start: i, end: token.end });
|
|
6211
|
+
if (key === undefined) {
|
|
6212
|
+
return;
|
|
6213
|
+
}
|
|
6214
|
+
i = token.end;
|
|
6215
|
+
if (key !== PLUGIN_KEY || depth !== 1) {
|
|
6216
|
+
continue;
|
|
6217
|
+
}
|
|
6218
|
+
i = skipTrivia(raw, i);
|
|
6219
|
+
if (raw[i] !== ":") {
|
|
6220
|
+
continue;
|
|
6221
|
+
}
|
|
6222
|
+
i += 1;
|
|
6223
|
+
i = skipTrivia(raw, i);
|
|
6224
|
+
if (raw[i] !== "[") {
|
|
6225
|
+
continue;
|
|
6226
|
+
}
|
|
6227
|
+
const arrayEnd = readJsoncValueEnd(raw, i, raw.length);
|
|
6228
|
+
if (arrayEnd === undefined) {
|
|
6229
|
+
return;
|
|
6230
|
+
}
|
|
6231
|
+
found = { start: i, end: arrayEnd };
|
|
6232
|
+
}
|
|
6233
|
+
return found;
|
|
6234
|
+
}
|
|
6235
|
+
function scanTopLevelArrayElements(raw, arrayStart, arrayEnd) {
|
|
6236
|
+
const elements = [];
|
|
6237
|
+
let i = skipTrivia(raw, arrayStart + 1, arrayEnd);
|
|
6238
|
+
while (i < arrayEnd) {
|
|
6239
|
+
const ch = raw[i];
|
|
6240
|
+
if (ch === undefined || ch === "]") {
|
|
6241
|
+
break;
|
|
6242
|
+
}
|
|
6243
|
+
const end = readJsoncValueEnd(raw, i, arrayEnd);
|
|
6244
|
+
if (end === undefined) {
|
|
6245
|
+
return;
|
|
6246
|
+
}
|
|
6247
|
+
elements.push({ start: i, end });
|
|
6248
|
+
i = skipTrivia(raw, end, arrayEnd);
|
|
6249
|
+
const next = raw[i];
|
|
6250
|
+
if (next === ",") {
|
|
6251
|
+
i = skipTrivia(raw, i + 1, arrayEnd);
|
|
6252
|
+
if (raw[i] === "]") {
|
|
6253
|
+
break;
|
|
6254
|
+
}
|
|
6255
|
+
continue;
|
|
6256
|
+
}
|
|
6257
|
+
if (next === "]") {
|
|
6258
|
+
break;
|
|
6259
|
+
}
|
|
6260
|
+
return;
|
|
6261
|
+
}
|
|
6262
|
+
return elements;
|
|
6263
|
+
}
|
|
6264
|
+
function readJsonStringValue(raw, span) {
|
|
6265
|
+
try {
|
|
6266
|
+
const parsed = JSON.parse(raw.slice(span.start, span.end));
|
|
6267
|
+
return typeof parsed === "string" ? parsed : undefined;
|
|
6268
|
+
} catch {
|
|
6269
|
+
return;
|
|
6270
|
+
}
|
|
6271
|
+
}
|
|
6272
|
+
function findEntrySpecStringSpan(raw, element, entry, expectedSpec) {
|
|
6273
|
+
if (typeof entry === "string") {
|
|
6274
|
+
const token2 = readStringToken(raw, element.start, element.end);
|
|
6275
|
+
if (token2 === undefined) {
|
|
6276
|
+
return;
|
|
6277
|
+
}
|
|
6278
|
+
const span2 = { start: element.start, end: token2.end };
|
|
6279
|
+
return readJsonStringValue(raw, span2) === expectedSpec ? span2 : undefined;
|
|
6280
|
+
}
|
|
6281
|
+
if (!isTuplePluginEntry(entry)) {
|
|
6282
|
+
return;
|
|
6283
|
+
}
|
|
6284
|
+
if (raw[element.start] !== "[") {
|
|
6285
|
+
return;
|
|
6286
|
+
}
|
|
6287
|
+
const firstValueStart = skipTrivia(raw, element.start + 1, element.end);
|
|
6288
|
+
const token = readStringToken(raw, firstValueStart, element.end);
|
|
6289
|
+
if (token === undefined) {
|
|
6290
|
+
return;
|
|
6291
|
+
}
|
|
6292
|
+
const span = { start: firstValueStart, end: token.end };
|
|
6293
|
+
return readJsonStringValue(raw, span) === expectedSpec ? span : undefined;
|
|
6294
|
+
}
|
|
6295
|
+
function buildUpdatedContent(originalContent, replacements, nextSpec) {
|
|
6296
|
+
const jsonSpec = JSON.stringify(nextSpec);
|
|
6297
|
+
let nextContent = originalContent;
|
|
6298
|
+
for (const replacement of [...replacements].sort((left, right) => right.start - left.start)) {
|
|
6299
|
+
nextContent = nextContent.slice(0, replacement.start) + jsonSpec + nextContent.slice(replacement.end);
|
|
6300
|
+
}
|
|
6301
|
+
return nextContent;
|
|
6302
|
+
}
|
|
6303
|
+
function validateEffectivePluginUpdate(path, nextContent, expectedManagedEntries, nextSpec) {
|
|
6304
|
+
const parsed = parseConfigDocument(path, nextContent);
|
|
6305
|
+
if (!parsed.ok) {
|
|
6306
|
+
return parsed.error;
|
|
6307
|
+
}
|
|
6308
|
+
const pluginValue = parsed.value[PLUGIN_KEY];
|
|
6309
|
+
if (!Array.isArray(pluginValue)) {
|
|
6310
|
+
return upgradeMessages.effectivePluginUpdateMismatch(path);
|
|
6311
|
+
}
|
|
6312
|
+
let managedEntries = 0;
|
|
6313
|
+
let updatedEntries = 0;
|
|
6314
|
+
for (const entry of pluginValue) {
|
|
6315
|
+
const spec = extractSpecString(entry);
|
|
6316
|
+
if (spec === undefined || !isOurSpec(spec)) {
|
|
6317
|
+
continue;
|
|
6318
|
+
}
|
|
6319
|
+
managedEntries += 1;
|
|
6320
|
+
if (spec === nextSpec) {
|
|
6321
|
+
updatedEntries += 1;
|
|
6322
|
+
}
|
|
6323
|
+
}
|
|
6324
|
+
return managedEntries === expectedManagedEntries && updatedEntries === expectedManagedEntries ? undefined : upgradeMessages.effectivePluginUpdateMismatch(path);
|
|
6325
|
+
}
|
|
6326
|
+
function parseUpgradePositionals(positionals) {
|
|
6327
|
+
let check = false;
|
|
6328
|
+
let targetVersion;
|
|
6329
|
+
for (let i = 1;i < positionals.length; i += 1) {
|
|
6330
|
+
const arg = positionals[i];
|
|
6331
|
+
if (arg === "--check") {
|
|
6332
|
+
if (check) {
|
|
6333
|
+
return { ok: false, error: upgradeMessages.duplicateCheck };
|
|
6334
|
+
}
|
|
6335
|
+
check = true;
|
|
6336
|
+
continue;
|
|
6337
|
+
}
|
|
6338
|
+
if (arg === "--version") {
|
|
6339
|
+
if (targetVersion !== undefined) {
|
|
6340
|
+
return { ok: false, error: upgradeMessages.duplicateVersion };
|
|
6341
|
+
}
|
|
6342
|
+
const next = positionals[i + 1];
|
|
6343
|
+
if (next === undefined || next.startsWith("--")) {
|
|
6344
|
+
return { ok: false, error: upgradeMessages.missingVersionValue };
|
|
6345
|
+
}
|
|
6346
|
+
targetVersion = next;
|
|
6347
|
+
i += 1;
|
|
6348
|
+
continue;
|
|
6349
|
+
}
|
|
6350
|
+
if (arg?.startsWith("--")) {
|
|
6351
|
+
return { ok: false, error: upgradeMessages.unknownFlag(arg) };
|
|
6352
|
+
}
|
|
6353
|
+
if (arg !== undefined) {
|
|
6354
|
+
return { ok: false, error: upgradeMessages.unexpectedArgument(arg) };
|
|
6355
|
+
}
|
|
6356
|
+
}
|
|
6357
|
+
return { ok: true, value: { check, targetVersion } };
|
|
6358
|
+
}
|
|
6359
|
+
async function raceWithAbort(promise, signal, message) {
|
|
6360
|
+
if (signal.aborted) {
|
|
6361
|
+
throw new TransientFetchError(message);
|
|
6362
|
+
}
|
|
6363
|
+
let onAbort;
|
|
6364
|
+
try {
|
|
6365
|
+
return await Promise.race([
|
|
6366
|
+
promise,
|
|
6367
|
+
new Promise((_, reject) => {
|
|
6368
|
+
onAbort = () => reject(new TransientFetchError(message));
|
|
6369
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
6370
|
+
})
|
|
6371
|
+
]);
|
|
6372
|
+
} finally {
|
|
6373
|
+
if (onAbort !== undefined) {
|
|
6374
|
+
signal.removeEventListener("abort", onAbort);
|
|
6375
|
+
}
|
|
6376
|
+
}
|
|
6377
|
+
}
|
|
6378
|
+
function scheduleCleanup(action) {
|
|
6379
|
+
try {
|
|
6380
|
+
const promise = action();
|
|
6381
|
+
promise?.catch(() => {});
|
|
6382
|
+
} catch {}
|
|
6383
|
+
}
|
|
6384
|
+
function scheduleResponseBodyCancel(response) {
|
|
6385
|
+
scheduleCleanup(() => response.body?.cancel());
|
|
6386
|
+
}
|
|
6387
|
+
function scheduleReaderCancel(reader) {
|
|
6388
|
+
scheduleCleanup(() => reader.cancel());
|
|
6389
|
+
}
|
|
6390
|
+
function extractFetchFailureDetail(error) {
|
|
6391
|
+
const seen = new Set;
|
|
6392
|
+
let current = error;
|
|
6393
|
+
let fallback;
|
|
6394
|
+
while (current instanceof Error && !seen.has(current)) {
|
|
6395
|
+
seen.add(current);
|
|
6396
|
+
const message = current.message.trim();
|
|
6397
|
+
if (message !== "" && !GENERIC_FETCH_FAILURE_MESSAGES.has(message.toLowerCase())) {
|
|
6398
|
+
return message;
|
|
6399
|
+
}
|
|
6400
|
+
if (message !== "" && fallback === undefined) {
|
|
6401
|
+
fallback = message;
|
|
6402
|
+
}
|
|
6403
|
+
current = "cause" in current ? current.cause : undefined;
|
|
6404
|
+
}
|
|
6405
|
+
if (typeof current === "string") {
|
|
6406
|
+
const message = current.trim();
|
|
6407
|
+
if (message !== "") {
|
|
6408
|
+
return message;
|
|
6409
|
+
}
|
|
6410
|
+
}
|
|
6411
|
+
return fallback;
|
|
6412
|
+
}
|
|
6413
|
+
function classifyUnexpectedFetchFailure(error, timedOut) {
|
|
6414
|
+
if (timedOut) {
|
|
6415
|
+
return new TransientFetchError(upgradeMessages.requestTimedOut(FETCH_TIMEOUT_MS));
|
|
6416
|
+
}
|
|
6417
|
+
const detail = extractFetchFailureDetail(error);
|
|
6418
|
+
return new TransientFetchError(detail === undefined ? upgradeMessages.networkRequestFailed : upgradeMessages.networkRequestFailedWithDetail(detail));
|
|
6419
|
+
}
|
|
6420
|
+
async function readBoundedJsonResponse(response, signal) {
|
|
6421
|
+
const contentLength = Number(response.headers.get("content-length"));
|
|
6422
|
+
if (Number.isFinite(contentLength) && contentLength > MAX_RESPONSE_BYTES) {
|
|
6423
|
+
scheduleResponseBodyCancel(response);
|
|
6424
|
+
throw new PermanentFetchError(upgradeMessages.responseTooLarge(MAX_RESPONSE_BYTES));
|
|
6425
|
+
}
|
|
6426
|
+
const body = response.body;
|
|
6427
|
+
if (body === null) {
|
|
6428
|
+
throw new PermanentFetchError(upgradeMessages.missingRegistryBody);
|
|
6429
|
+
}
|
|
6430
|
+
const reader = body.getReader();
|
|
6431
|
+
const cancelReader = () => {
|
|
6432
|
+
scheduleReaderCancel(reader);
|
|
6433
|
+
};
|
|
6434
|
+
signal.addEventListener("abort", cancelReader, { once: true });
|
|
6435
|
+
const chunks = [];
|
|
6436
|
+
let total = 0;
|
|
6437
|
+
try {
|
|
6438
|
+
while (true) {
|
|
6439
|
+
const chunk = await raceWithAbort(reader.read(), signal, upgradeMessages.requestTimedOut(FETCH_TIMEOUT_MS));
|
|
6440
|
+
if (chunk.done) {
|
|
6441
|
+
break;
|
|
6442
|
+
}
|
|
6443
|
+
total += chunk.value.byteLength;
|
|
6444
|
+
if (total > MAX_RESPONSE_BYTES) {
|
|
6445
|
+
throw new PermanentFetchError(upgradeMessages.responseTooLarge(MAX_RESPONSE_BYTES));
|
|
6446
|
+
}
|
|
6447
|
+
chunks.push(chunk.value);
|
|
6448
|
+
}
|
|
6449
|
+
} catch (error) {
|
|
6450
|
+
scheduleReaderCancel(reader);
|
|
6451
|
+
if (error instanceof PermanentFetchError) {
|
|
6452
|
+
throw error;
|
|
6453
|
+
}
|
|
6454
|
+
throw new TransientFetchError(signal.aborted ? upgradeMessages.requestTimedOut(FETCH_TIMEOUT_MS) : upgradeMessages.responseReadFailed);
|
|
6455
|
+
} finally {
|
|
6456
|
+
signal.removeEventListener("abort", cancelReader);
|
|
6457
|
+
reader.releaseLock();
|
|
6458
|
+
}
|
|
6459
|
+
const bytes = new Uint8Array(total);
|
|
6460
|
+
let offset = 0;
|
|
6461
|
+
for (const chunk of chunks) {
|
|
6462
|
+
bytes.set(chunk, offset);
|
|
6463
|
+
offset += chunk.byteLength;
|
|
6464
|
+
}
|
|
6465
|
+
try {
|
|
6466
|
+
return JSON.parse(new TextDecoder().decode(bytes));
|
|
6467
|
+
} catch {
|
|
6468
|
+
throw new PermanentFetchError(upgradeMessages.invalidRegistryJson);
|
|
6469
|
+
}
|
|
6470
|
+
}
|
|
6471
|
+
async function fetchFromNpm(url, fetchFn) {
|
|
6472
|
+
for (let attempt = 1;attempt <= MAX_FETCH_ATTEMPTS; attempt += 1) {
|
|
6473
|
+
const controller = new AbortController;
|
|
6474
|
+
const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
6475
|
+
try {
|
|
6476
|
+
const response = await raceWithAbort(fetchFn(url, { signal: controller.signal }), controller.signal, upgradeMessages.requestTimedOut(FETCH_TIMEOUT_MS));
|
|
6477
|
+
if (!response.ok) {
|
|
6478
|
+
scheduleResponseBodyCancel(response);
|
|
6479
|
+
return { ok: false, kind: "http", status: response.status };
|
|
6480
|
+
}
|
|
6481
|
+
const data = await readBoundedJsonResponse(response, controller.signal);
|
|
6482
|
+
return { ok: true, data };
|
|
6483
|
+
} catch (error) {
|
|
6484
|
+
const timedOut = controller.signal.aborted;
|
|
6485
|
+
controller.abort();
|
|
6486
|
+
if (error instanceof PermanentFetchError) {
|
|
6487
|
+
return { ok: false, kind: "error", error: error.message };
|
|
6488
|
+
}
|
|
6489
|
+
const transientError = error instanceof TransientFetchError ? error : classifyUnexpectedFetchFailure(error, timedOut);
|
|
6490
|
+
if (attempt === MAX_FETCH_ATTEMPTS) {
|
|
6491
|
+
return { ok: false, kind: "error", error: transientError.message };
|
|
6492
|
+
}
|
|
6493
|
+
} finally {
|
|
6494
|
+
clearTimeout(timeoutId);
|
|
6495
|
+
}
|
|
6496
|
+
}
|
|
6497
|
+
return { ok: false, kind: "error", error: upgradeMessages.networkRequestFailed };
|
|
6498
|
+
}
|
|
6499
|
+
function validateRegistryPackageResponse(data) {
|
|
6500
|
+
const parsed = RegistryPackageIdentitySchema.safeParse(isRecord3(data) ? { name: data.name, version: data.version } : data);
|
|
6501
|
+
if (!parsed.success) {
|
|
6502
|
+
return { ok: false, error: upgradeMessages.invalidRegistryPayload };
|
|
6503
|
+
}
|
|
6504
|
+
if (parsed.data.name !== OPENTEAM_PACKAGE_NAME) {
|
|
6505
|
+
return { ok: false, error: upgradeMessages.wrongPackageIdentity(parsed.data.name) };
|
|
6506
|
+
}
|
|
6507
|
+
if (!isStrictSemver(parsed.data.version)) {
|
|
6508
|
+
return {
|
|
6509
|
+
ok: false,
|
|
6510
|
+
error: upgradeMessages.unexpectedVersionField(JSON.stringify(parsed.data.version))
|
|
6511
|
+
};
|
|
6512
|
+
}
|
|
6513
|
+
return { ok: true, version: parsed.data.version };
|
|
6514
|
+
}
|
|
6515
|
+
async function fetchLatestVersion(fetchFn) {
|
|
6516
|
+
const result = await fetchFromNpm(NPM_LATEST_URL, fetchFn);
|
|
6517
|
+
if (!result.ok) {
|
|
6518
|
+
if (result.kind === "http") {
|
|
6519
|
+
return { ok: false, error: upgradeMessages.fetchError(upgradeMessages.httpStatus(result.status)) };
|
|
6520
|
+
}
|
|
6521
|
+
return { ok: false, error: upgradeMessages.fetchError(result.error) };
|
|
6522
|
+
}
|
|
6523
|
+
const validated = validateRegistryPackageResponse(result.data);
|
|
6524
|
+
if (!validated.ok) {
|
|
6525
|
+
return { ok: false, error: upgradeMessages.fetchError(validated.error) };
|
|
6526
|
+
}
|
|
6527
|
+
return { ok: true, version: validated.version };
|
|
6528
|
+
}
|
|
6529
|
+
async function verifyVersionExists(version, fetchFn) {
|
|
6530
|
+
const result = await fetchFromNpm(npmVersionUrl(version), fetchFn);
|
|
6531
|
+
if (!result.ok) {
|
|
6532
|
+
if (result.kind === "http") {
|
|
6533
|
+
return result.status === 404 ? { ok: false, error: upgradeMessages.versionNotFound(version) } : { ok: false, error: upgradeMessages.fetchError(upgradeMessages.httpStatus(result.status)) };
|
|
6534
|
+
}
|
|
6535
|
+
return { ok: false, error: upgradeMessages.fetchError(result.error) };
|
|
6536
|
+
}
|
|
6537
|
+
const validated = validateRegistryPackageResponse(result.data);
|
|
6538
|
+
if (!validated.ok) {
|
|
6539
|
+
return { ok: false, error: upgradeMessages.fetchError(validated.error) };
|
|
6540
|
+
}
|
|
6541
|
+
if (validated.version !== version) {
|
|
6542
|
+
return {
|
|
6543
|
+
ok: false,
|
|
6544
|
+
error: upgradeMessages.fetchError(upgradeMessages.unexpectedPublishedVersion({
|
|
6545
|
+
expected: version,
|
|
6546
|
+
actual: validated.version
|
|
6547
|
+
}))
|
|
6548
|
+
};
|
|
6549
|
+
}
|
|
6550
|
+
return { ok: true };
|
|
6551
|
+
}
|
|
6552
|
+
async function analyseConfigFiles(paths, port) {
|
|
6553
|
+
const files = [];
|
|
6554
|
+
const localOpenteamEntries = [];
|
|
6555
|
+
let foundConfigFile = false;
|
|
6556
|
+
for (const path of paths) {
|
|
6557
|
+
let content;
|
|
6558
|
+
try {
|
|
6559
|
+
content = await port.readOpencodeConfigFile(path);
|
|
6560
|
+
} catch (error) {
|
|
6561
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6562
|
+
return {
|
|
6563
|
+
files,
|
|
6564
|
+
foundConfigFile,
|
|
6565
|
+
localOpenteamEntries,
|
|
6566
|
+
parseError: upgradeMessages.readConfigError(path, message)
|
|
6567
|
+
};
|
|
6568
|
+
}
|
|
6569
|
+
if (content === undefined) {
|
|
6570
|
+
continue;
|
|
6571
|
+
}
|
|
6572
|
+
foundConfigFile = true;
|
|
6573
|
+
const parsed = parseConfigDocument(path, content);
|
|
6574
|
+
if (!parsed.ok) {
|
|
6575
|
+
return {
|
|
6576
|
+
files,
|
|
6577
|
+
foundConfigFile,
|
|
6578
|
+
localOpenteamEntries,
|
|
6579
|
+
parseError: parsed.error
|
|
6580
|
+
};
|
|
6581
|
+
}
|
|
6582
|
+
const pluginValue = parsed.value[PLUGIN_KEY];
|
|
6583
|
+
if (pluginValue === undefined) {
|
|
6584
|
+
continue;
|
|
6585
|
+
}
|
|
6586
|
+
if (!Array.isArray(pluginValue)) {
|
|
6587
|
+
return {
|
|
6588
|
+
files,
|
|
6589
|
+
foundConfigFile,
|
|
6590
|
+
localOpenteamEntries,
|
|
6591
|
+
parseError: upgradeMessages.pluginFieldMustBeArray(path)
|
|
6592
|
+
};
|
|
6593
|
+
}
|
|
6594
|
+
const managedCandidates = [];
|
|
6595
|
+
for (let index = 0;index < pluginValue.length; index += 1) {
|
|
6596
|
+
const entry = pluginValue[index];
|
|
6597
|
+
const spec = extractSpecString(entry);
|
|
6598
|
+
if (spec === undefined) {
|
|
6599
|
+
continue;
|
|
6600
|
+
}
|
|
6601
|
+
if (isLocalFileSpec(spec)) {
|
|
6602
|
+
const localKind = await port.classifyLocalPluginSpec({
|
|
6603
|
+
configPath: path,
|
|
6604
|
+
spec
|
|
6605
|
+
});
|
|
6606
|
+
if (localKind === "ours") {
|
|
6607
|
+
localOpenteamEntries.push({ path, spec });
|
|
6608
|
+
}
|
|
6609
|
+
continue;
|
|
6610
|
+
}
|
|
6611
|
+
if (!isOurSpec(spec)) {
|
|
6612
|
+
continue;
|
|
6613
|
+
}
|
|
6614
|
+
managedCandidates.push({
|
|
6615
|
+
currentVersion: currentPinnedVersion(spec),
|
|
6616
|
+
entry,
|
|
6617
|
+
index,
|
|
6618
|
+
spec
|
|
6619
|
+
});
|
|
6620
|
+
}
|
|
6621
|
+
if (managedCandidates.length === 0) {
|
|
6622
|
+
continue;
|
|
6623
|
+
}
|
|
6624
|
+
const pluginArray = findTopLevelPluginArray(content);
|
|
6625
|
+
if (pluginArray === undefined) {
|
|
6626
|
+
return {
|
|
6627
|
+
files,
|
|
6628
|
+
foundConfigFile,
|
|
6629
|
+
localOpenteamEntries,
|
|
6630
|
+
parseError: upgradeMessages.pluginArrayEditUnavailable(path)
|
|
6631
|
+
};
|
|
6632
|
+
}
|
|
6633
|
+
const elementSpans = scanTopLevelArrayElements(content, pluginArray.start, pluginArray.end);
|
|
6634
|
+
if (elementSpans === undefined || elementSpans.length !== pluginValue.length) {
|
|
6635
|
+
return {
|
|
6636
|
+
files,
|
|
6637
|
+
foundConfigFile,
|
|
6638
|
+
localOpenteamEntries,
|
|
6639
|
+
parseError: upgradeMessages.pluginArrayEditUnavailable(path)
|
|
6640
|
+
};
|
|
6641
|
+
}
|
|
6642
|
+
const replacements = [];
|
|
6643
|
+
for (const candidate of managedCandidates) {
|
|
6644
|
+
const elementSpan = elementSpans[candidate.index];
|
|
6645
|
+
if (elementSpan === undefined) {
|
|
6646
|
+
return {
|
|
6647
|
+
files,
|
|
6648
|
+
foundConfigFile,
|
|
6649
|
+
localOpenteamEntries,
|
|
6650
|
+
parseError: upgradeMessages.pluginArrayEditUnavailable(path)
|
|
6651
|
+
};
|
|
6652
|
+
}
|
|
6653
|
+
const specSpan = findEntrySpecStringSpan(content, elementSpan, candidate.entry, candidate.spec);
|
|
6654
|
+
if (specSpan === undefined) {
|
|
6655
|
+
return {
|
|
6656
|
+
files,
|
|
6657
|
+
foundConfigFile,
|
|
6658
|
+
localOpenteamEntries,
|
|
6659
|
+
parseError: upgradeMessages.pluginArrayEditUnavailable(path)
|
|
6660
|
+
};
|
|
6661
|
+
}
|
|
6662
|
+
replacements.push({
|
|
6663
|
+
...specSpan,
|
|
6664
|
+
currentVersion: candidate.currentVersion
|
|
6665
|
+
});
|
|
6666
|
+
}
|
|
6667
|
+
files.push({
|
|
6668
|
+
currentVersions: replacements.map((replacement) => replacement.currentVersion),
|
|
6669
|
+
path,
|
|
6670
|
+
originalContent: content,
|
|
6671
|
+
replacements
|
|
6672
|
+
});
|
|
6673
|
+
}
|
|
6674
|
+
return {
|
|
6675
|
+
files,
|
|
6676
|
+
foundConfigFile,
|
|
6677
|
+
localOpenteamEntries,
|
|
6678
|
+
parseError: undefined
|
|
6679
|
+
};
|
|
6680
|
+
}
|
|
6681
|
+
function renderArgError(error) {
|
|
6682
|
+
return {
|
|
6683
|
+
exitCode: 1,
|
|
6684
|
+
stdout: [
|
|
6685
|
+
upgradeMessages.header,
|
|
6686
|
+
upgradeMessages.invalidArguments(error),
|
|
6687
|
+
"",
|
|
6688
|
+
upgradeMessages.usageLabel,
|
|
6689
|
+
upgradeMessages.help.usage
|
|
6690
|
+
].join(`
|
|
6691
|
+
`)
|
|
6692
|
+
};
|
|
6693
|
+
}
|
|
6694
|
+
function renderFailedWrites(localWarnings, failed) {
|
|
6695
|
+
return {
|
|
6696
|
+
exitCode: 1,
|
|
6697
|
+
stdout: [
|
|
6698
|
+
upgradeMessages.header,
|
|
6699
|
+
...localWarnings,
|
|
6700
|
+
upgradeMessages.nothingChanged,
|
|
6701
|
+
...failed.map((entry) => upgradeMessages.failedEntry(entry)),
|
|
6702
|
+
"",
|
|
6703
|
+
upgradeMessages.rerunAfterFailures
|
|
6704
|
+
].join(`
|
|
6705
|
+
`)
|
|
6706
|
+
};
|
|
6707
|
+
}
|
|
6708
|
+
function renderPartialSuccess(version, localWarnings, written, failed) {
|
|
6709
|
+
return {
|
|
6710
|
+
exitCode: 1,
|
|
6711
|
+
stdout: [
|
|
6712
|
+
upgradeMessages.header,
|
|
6713
|
+
...localWarnings,
|
|
6714
|
+
upgradeMessages.partialHeader(version),
|
|
6715
|
+
...written.map((path) => upgradeMessages.writtenEntry(path)),
|
|
6716
|
+
upgradeMessages.partialFailuresHeader,
|
|
6717
|
+
...failed.map((entry) => upgradeMessages.failedEntry(entry)),
|
|
6718
|
+
"",
|
|
6719
|
+
upgradeMessages.backupNote(UPGRADE_BACKUP_DIRECTORY),
|
|
6720
|
+
upgradeMessages.resolveFailuresBeforeRestart
|
|
6721
|
+
].join(`
|
|
6722
|
+
`)
|
|
6723
|
+
};
|
|
6724
|
+
}
|
|
6725
|
+
function renderSuccess(version, localWarnings, written) {
|
|
6726
|
+
return {
|
|
6727
|
+
exitCode: 0,
|
|
6728
|
+
stdout: [
|
|
6729
|
+
upgradeMessages.header,
|
|
6730
|
+
...localWarnings,
|
|
6731
|
+
upgradeMessages.updatedHeader(version),
|
|
6732
|
+
...written.map((path) => upgradeMessages.writtenEntry(path)),
|
|
6733
|
+
"",
|
|
6734
|
+
upgradeMessages.backupNote(UPGRADE_BACKUP_DIRECTORY),
|
|
6735
|
+
upgradeMessages.restartHint,
|
|
6736
|
+
upgradeMessages.cacheCleanupHint
|
|
6737
|
+
].join(`
|
|
6738
|
+
`)
|
|
6739
|
+
};
|
|
6740
|
+
}
|
|
6741
|
+
function resolveProjectPath(workspaceRoot, configPath) {
|
|
6742
|
+
const absoluteRoot = resolve3(workspaceRoot);
|
|
6743
|
+
const absolutePath = resolve3(absoluteRoot, configPath);
|
|
6744
|
+
const rel = relative(absoluteRoot, absolutePath);
|
|
6745
|
+
if (rel === "" || rel.startsWith("..") || win32.isAbsolute(rel)) {
|
|
6746
|
+
throw new Error("path-outside-root");
|
|
6747
|
+
}
|
|
6748
|
+
return absolutePath;
|
|
6749
|
+
}
|
|
6750
|
+
function resolveLocalSpecPath(workspaceRoot, configPath, spec) {
|
|
6751
|
+
if (spec.toLowerCase().startsWith("file:")) {
|
|
6752
|
+
try {
|
|
6753
|
+
return fileURLToPath(new URL(spec));
|
|
6754
|
+
} catch {
|
|
6755
|
+
return;
|
|
6756
|
+
}
|
|
6757
|
+
}
|
|
6758
|
+
if (win32.isAbsolute(spec)) {
|
|
6759
|
+
return spec;
|
|
6760
|
+
}
|
|
6761
|
+
const configAbsolutePath = resolveProjectPath(workspaceRoot, configPath);
|
|
6762
|
+
return resolve3(dirname4(configAbsolutePath), spec);
|
|
6763
|
+
}
|
|
6764
|
+
async function readPackageManifestName(packageJsonPath) {
|
|
6765
|
+
let content;
|
|
6766
|
+
try {
|
|
6767
|
+
content = await readFile2(packageJsonPath, "utf8");
|
|
6768
|
+
} catch (error) {
|
|
6769
|
+
return isMissingFile(error) ? { kind: "missing" } : { kind: "invalid" };
|
|
6770
|
+
}
|
|
6771
|
+
let parsed;
|
|
6772
|
+
try {
|
|
6773
|
+
parsed = JSON.parse(content);
|
|
6774
|
+
} catch {
|
|
6775
|
+
return { kind: "invalid" };
|
|
6776
|
+
}
|
|
6777
|
+
if (!isRecord3(parsed) || typeof parsed.name !== "string") {
|
|
6778
|
+
return { kind: "invalid" };
|
|
6779
|
+
}
|
|
6780
|
+
return { kind: "name", name: parsed.name };
|
|
6781
|
+
}
|
|
6782
|
+
async function manifestSearchStart(targetPath, spec) {
|
|
6783
|
+
try {
|
|
6784
|
+
const stats = await lstat(targetPath);
|
|
6785
|
+
return stats.isDirectory() ? targetPath : dirname4(targetPath);
|
|
6786
|
+
} catch {
|
|
6787
|
+
return spec.endsWith("/") || spec.endsWith("\\") ? targetPath : dirname4(targetPath);
|
|
6788
|
+
}
|
|
6789
|
+
}
|
|
6790
|
+
function splitRelativeProjectPath(workspaceRoot, targetPath) {
|
|
6791
|
+
const rel = relative(workspaceRoot, targetPath);
|
|
6792
|
+
if (rel === "") {
|
|
6793
|
+
return [];
|
|
6794
|
+
}
|
|
6795
|
+
if (rel.startsWith("..") || win32.isAbsolute(rel)) {
|
|
6796
|
+
throw new Error("path-outside-root");
|
|
6797
|
+
}
|
|
6798
|
+
return rel.split(/[\\/]+/u).filter((segment) => segment.length > 0);
|
|
6799
|
+
}
|
|
6800
|
+
async function validateExistingAncestorDirectories(workspaceRoot, targetDirectoryPath) {
|
|
6801
|
+
const absoluteRoot = resolve3(workspaceRoot);
|
|
6802
|
+
const rootStats = await lstat(absoluteRoot);
|
|
6803
|
+
if (!rootStats.isDirectory() || rootStats.isSymbolicLink()) {
|
|
6804
|
+
throw new Error(upgradeMessages.unsafeFilesystemEntry);
|
|
6805
|
+
}
|
|
6806
|
+
let current = absoluteRoot;
|
|
6807
|
+
for (const segment of splitRelativeProjectPath(absoluteRoot, targetDirectoryPath)) {
|
|
6808
|
+
current = join9(current, segment);
|
|
6809
|
+
let stats;
|
|
6810
|
+
try {
|
|
6811
|
+
stats = await lstat(current);
|
|
6812
|
+
} catch (error) {
|
|
6813
|
+
if (isMissingFile(error)) {
|
|
6814
|
+
return false;
|
|
6815
|
+
}
|
|
6816
|
+
throw error;
|
|
6817
|
+
}
|
|
6818
|
+
if (!stats.isDirectory() || stats.isSymbolicLink()) {
|
|
6819
|
+
throw new Error(upgradeMessages.unsafeFilesystemEntry);
|
|
6820
|
+
}
|
|
6821
|
+
}
|
|
6822
|
+
return true;
|
|
6823
|
+
}
|
|
6824
|
+
async function ensurePrivateDirectoryChain(workspaceRoot, targetDirectoryPath) {
|
|
6825
|
+
const absoluteRoot = resolve3(workspaceRoot);
|
|
6826
|
+
const rootStats = await lstat(absoluteRoot);
|
|
6827
|
+
if (!rootStats.isDirectory() || rootStats.isSymbolicLink()) {
|
|
6828
|
+
throw new Error(upgradeMessages.backupLocationUnavailable(UPGRADE_BACKUP_DIRECTORY));
|
|
6829
|
+
}
|
|
6830
|
+
let current = absoluteRoot;
|
|
6831
|
+
for (const segment of splitRelativeProjectPath(absoluteRoot, targetDirectoryPath)) {
|
|
6832
|
+
current = join9(current, segment);
|
|
6833
|
+
try {
|
|
6834
|
+
const stats = await lstat(current);
|
|
6835
|
+
if (!stats.isDirectory() || stats.isSymbolicLink()) {
|
|
6836
|
+
throw new Error(upgradeMessages.backupLocationUnavailable(UPGRADE_BACKUP_DIRECTORY));
|
|
6837
|
+
}
|
|
6838
|
+
continue;
|
|
6839
|
+
} catch (error) {
|
|
6840
|
+
if (!isMissingFile(error)) {
|
|
6841
|
+
throw error;
|
|
6842
|
+
}
|
|
6843
|
+
}
|
|
6844
|
+
try {
|
|
6845
|
+
await mkdir2(current, { mode: PRIVATE_DIRECTORY_MODE });
|
|
6846
|
+
} catch (error) {
|
|
6847
|
+
if (!isAlreadyExistsFile(error)) {
|
|
6848
|
+
throw error;
|
|
6849
|
+
}
|
|
6850
|
+
const stats = await lstat(current);
|
|
6851
|
+
if (!stats.isDirectory() || stats.isSymbolicLink()) {
|
|
6852
|
+
throw new Error(upgradeMessages.backupLocationUnavailable(UPGRADE_BACKUP_DIRECTORY));
|
|
6853
|
+
}
|
|
6854
|
+
}
|
|
6855
|
+
}
|
|
6856
|
+
}
|
|
6857
|
+
async function readSafeTextFileSnapshot(workspaceRoot, diskPath) {
|
|
6858
|
+
const parentsExist = await validateExistingAncestorDirectories(workspaceRoot, dirname4(diskPath));
|
|
6859
|
+
if (!parentsExist) {
|
|
6860
|
+
return;
|
|
6861
|
+
}
|
|
6862
|
+
let stats;
|
|
6863
|
+
try {
|
|
6864
|
+
stats = await lstat(diskPath);
|
|
6865
|
+
} catch (error) {
|
|
6866
|
+
if (isMissingFile(error)) {
|
|
6867
|
+
return;
|
|
6868
|
+
}
|
|
6869
|
+
throw error;
|
|
6870
|
+
}
|
|
6871
|
+
if (!stats.isFile() || stats.isSymbolicLink()) {
|
|
6872
|
+
throw new Error(upgradeMessages.unsafeFilesystemEntry);
|
|
6873
|
+
}
|
|
6874
|
+
const content = await readFile2(diskPath, "utf8");
|
|
6875
|
+
return {
|
|
6876
|
+
content,
|
|
6877
|
+
gid: stats.gid,
|
|
6878
|
+
mode: stats.mode & 511,
|
|
6879
|
+
uid: stats.uid
|
|
6880
|
+
};
|
|
6881
|
+
}
|
|
6882
|
+
async function writePrivateTextFile(path, content, flags) {
|
|
6883
|
+
const handle = await open(path, flags, PRIVATE_FILE_MODE);
|
|
6884
|
+
try {
|
|
6885
|
+
await handle.writeFile(content, "utf8");
|
|
6886
|
+
await handle.sync();
|
|
6887
|
+
} finally {
|
|
6888
|
+
await handle.close();
|
|
6889
|
+
}
|
|
6890
|
+
}
|
|
6891
|
+
async function writeAtomicPrivateFile(path, content, finalMode, options) {
|
|
6892
|
+
const temporary = join9(dirname4(path), `.${basename2(path)}.${randomUUID()}.next`);
|
|
6893
|
+
const handle = await open(temporary, "wx", PRIVATE_FILE_MODE);
|
|
6894
|
+
try {
|
|
6895
|
+
if (process.platform !== "win32") {
|
|
6896
|
+
if (finalMode !== PRIVATE_FILE_MODE) {
|
|
6897
|
+
await handle.chmod(finalMode);
|
|
6898
|
+
}
|
|
6899
|
+
const owner = options?.originalOwner;
|
|
6900
|
+
if (owner !== undefined) {
|
|
6901
|
+
await handle.chown(owner.uid, owner.gid);
|
|
6902
|
+
}
|
|
6903
|
+
}
|
|
6904
|
+
await handle.writeFile(content, "utf8");
|
|
6905
|
+
await handle.sync();
|
|
6906
|
+
} catch (error) {
|
|
6907
|
+
await handle.close();
|
|
6908
|
+
await rm2(temporary, { force: true }).catch(() => {});
|
|
6909
|
+
throw error;
|
|
6910
|
+
}
|
|
6911
|
+
await handle.close();
|
|
6912
|
+
try {
|
|
6913
|
+
await rename(temporary, path);
|
|
6914
|
+
options?.onReplaced?.();
|
|
6915
|
+
} finally {
|
|
6916
|
+
await rm2(temporary, { force: true }).catch(() => {});
|
|
6917
|
+
}
|
|
6918
|
+
}
|
|
6919
|
+
async function replaceWindowsFilePreservingAcl(sourcePath, destinationPath, backupPath, displayPath) {
|
|
6920
|
+
const script = `$ErrorActionPreference = 'Stop'; $source = $env:OPENTEAM_UPGRADE_SOURCE; $destination = $env:OPENTEAM_UPGRADE_DESTINATION; $backup = $env:OPENTEAM_UPGRADE_BACKUP; if ([string]::IsNullOrEmpty($backup)) { [System.IO.File]::Replace($source, $destination, $null) } else { [System.IO.File]::Replace($source, $destination, $backup) }`;
|
|
6921
|
+
try {
|
|
6922
|
+
await execFileAsync2(WINDOWS_POWERSHELL_EXE, ["-NoProfile", "-NonInteractive", "-Command", script], {
|
|
6923
|
+
encoding: "utf8",
|
|
6924
|
+
env: {
|
|
6925
|
+
...process.env,
|
|
6926
|
+
OPENTEAM_UPGRADE_BACKUP: backupPath ?? "",
|
|
6927
|
+
OPENTEAM_UPGRADE_DESTINATION: destinationPath,
|
|
6928
|
+
OPENTEAM_UPGRADE_SOURCE: sourcePath
|
|
6929
|
+
},
|
|
6930
|
+
timeout: WINDOWS_PS_TIMEOUT_MS,
|
|
6931
|
+
windowsHide: true
|
|
6932
|
+
});
|
|
6933
|
+
} catch (error) {
|
|
6934
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6935
|
+
throw new Error(upgradeMessages.windowsReplaceFailed(displayPath, message));
|
|
6936
|
+
}
|
|
6937
|
+
}
|
|
6938
|
+
async function applyWindowsFileDaclToTemp(sourcePath, targetPath, displayPath) {
|
|
6939
|
+
const script = `$ErrorActionPreference = 'Stop'; $source = $env:OPENTEAM_UPGRADE_ACL_SOURCE; $target = $env:OPENTEAM_UPGRADE_ACL_TARGET; $acl = New-Object System.Security.AccessControl.FileSecurity($source, [System.Security.AccessControl.AccessControlSections]::Access); $acl.SetAccessRuleProtection($acl.AreAccessRulesProtected, $acl.AreAccessRulesCanonical); [System.IO.File]::SetAccessControl($target, $acl)`;
|
|
6940
|
+
try {
|
|
6941
|
+
await execFileAsync2(WINDOWS_POWERSHELL_EXE, ["-NoProfile", "-NonInteractive", "-Command", script], {
|
|
6942
|
+
encoding: "utf8",
|
|
6943
|
+
env: {
|
|
6944
|
+
...process.env,
|
|
6945
|
+
OPENTEAM_UPGRADE_ACL_SOURCE: sourcePath,
|
|
6946
|
+
OPENTEAM_UPGRADE_ACL_TARGET: targetPath
|
|
6947
|
+
},
|
|
6948
|
+
timeout: WINDOWS_PS_TIMEOUT_MS,
|
|
6949
|
+
windowsHide: true
|
|
6950
|
+
});
|
|
6951
|
+
} catch (error) {
|
|
6952
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6953
|
+
throw new Error(upgradeMessages.windowsDaclPrepFailed(displayPath, message));
|
|
6954
|
+
}
|
|
6955
|
+
}
|
|
6956
|
+
async function writeWindowsFileReplacingPreservedAcl(destinationPath, content, backupPath, displayPath) {
|
|
6957
|
+
const temporary = join9(dirname4(destinationPath), `.${basename2(destinationPath)}.${randomUUID()}.next`);
|
|
6958
|
+
const handle = await open(temporary, "wx", PRIVATE_FILE_MODE);
|
|
6959
|
+
try {
|
|
6960
|
+
await applyWindowsFileDaclToTemp(destinationPath, temporary, displayPath);
|
|
6961
|
+
await handle.writeFile(content, "utf8");
|
|
6962
|
+
await handle.sync();
|
|
6963
|
+
} catch (error) {
|
|
6964
|
+
await handle.close();
|
|
6965
|
+
await rm2(temporary, { force: true }).catch(() => {});
|
|
6966
|
+
throw error;
|
|
6967
|
+
}
|
|
6968
|
+
await handle.close();
|
|
6969
|
+
try {
|
|
6970
|
+
await replaceWindowsFilePreservingAcl(temporary, destinationPath, backupPath, displayPath);
|
|
6971
|
+
} finally {
|
|
6972
|
+
await rm2(temporary, { force: true }).catch(() => {});
|
|
6973
|
+
}
|
|
6974
|
+
}
|
|
6975
|
+
function backupFileNameForConfig(configPath, content) {
|
|
6976
|
+
const safeStem = configPath.replace(/^[./\\]+/u, "").replace(/[\\/]+/gu, "__").replace(/[^A-Za-z0-9._-]/gu, "_");
|
|
6977
|
+
const stem = safeStem === "" ? "opencode" : safeStem;
|
|
6978
|
+
const digest = createHash2("sha256").update(content).digest("hex").slice(0, 12);
|
|
6979
|
+
return `${stem}.${digest}${UPGRADE_BACKUP_SUFFIX}`;
|
|
6980
|
+
}
|
|
6981
|
+
async function ensureUpgradeBackupRoot(workspaceRoot) {
|
|
6982
|
+
const backupRoot = resolveProjectPath(workspaceRoot, UPGRADE_BACKUP_DIRECTORY);
|
|
6983
|
+
await ensurePrivateDirectoryChain(workspaceRoot, backupRoot);
|
|
6984
|
+
if (process.platform !== "win32") {
|
|
6985
|
+
const dirStats = await lstat(backupRoot);
|
|
6986
|
+
if ((dirStats.mode & 511) !== PRIVATE_DIRECTORY_MODE) {
|
|
6987
|
+
await chmod(backupRoot, PRIVATE_DIRECTORY_MODE);
|
|
6988
|
+
}
|
|
6989
|
+
}
|
|
6990
|
+
const ignorePath = join9(backupRoot, ".gitignore");
|
|
6991
|
+
const ignoreFile = await readSafeTextFileSnapshot(workspaceRoot, ignorePath);
|
|
6992
|
+
if (ignoreFile !== undefined) {
|
|
6993
|
+
if (ignoreFile.content !== UPGRADE_BACKUP_GITIGNORE_CONTENT) {
|
|
6994
|
+
throw new Error(upgradeMessages.backupGitignoreUnexpected(UPGRADE_BACKUP_DIRECTORY));
|
|
6995
|
+
}
|
|
6996
|
+
return backupRoot;
|
|
6997
|
+
}
|
|
6998
|
+
try {
|
|
6999
|
+
await writePrivateTextFile(ignorePath, UPGRADE_BACKUP_GITIGNORE_CONTENT, "wx");
|
|
7000
|
+
} catch (error) {
|
|
7001
|
+
if (!isAlreadyExistsFile(error)) {
|
|
7002
|
+
throw error;
|
|
7003
|
+
}
|
|
7004
|
+
const concurrent = await readSafeTextFileSnapshot(workspaceRoot, ignorePath);
|
|
7005
|
+
if (concurrent === undefined) {
|
|
7006
|
+
throw error;
|
|
7007
|
+
}
|
|
7008
|
+
if (concurrent.content !== UPGRADE_BACKUP_GITIGNORE_CONTENT) {
|
|
7009
|
+
throw new Error(upgradeMessages.backupGitignoreUnexpected(UPGRADE_BACKUP_DIRECTORY));
|
|
7010
|
+
}
|
|
7011
|
+
}
|
|
7012
|
+
return backupRoot;
|
|
7013
|
+
}
|
|
7014
|
+
async function ensureUpgradeBackupFile(workspaceRoot, configPath, expectedContent) {
|
|
7015
|
+
try {
|
|
7016
|
+
await ensureUpgradeBackupRoot(workspaceRoot);
|
|
7017
|
+
} catch {
|
|
7018
|
+
throw new Error(upgradeMessages.backupLocationUnavailable(UPGRADE_BACKUP_DIRECTORY));
|
|
7019
|
+
}
|
|
7020
|
+
const backupRelativePath = `${UPGRADE_BACKUP_DIRECTORY}/` + backupFileNameForConfig(configPath, expectedContent);
|
|
7021
|
+
const backupDiskPath = resolveProjectPath(workspaceRoot, backupRelativePath);
|
|
7022
|
+
let existingBackup;
|
|
7023
|
+
try {
|
|
7024
|
+
existingBackup = await readSafeTextFileSnapshot(workspaceRoot, backupDiskPath);
|
|
7025
|
+
} catch {
|
|
7026
|
+
throw new Error(upgradeMessages.backupLocationUnavailable(UPGRADE_BACKUP_DIRECTORY));
|
|
7027
|
+
}
|
|
7028
|
+
if (existingBackup !== undefined) {
|
|
7029
|
+
if (existingBackup.content !== expectedContent) {
|
|
7030
|
+
throw new Error(upgradeMessages.backupConflict(backupRelativePath));
|
|
7031
|
+
}
|
|
7032
|
+
return { created: false, diskPath: backupDiskPath, reuseExisting: true };
|
|
7033
|
+
}
|
|
7034
|
+
if (process.platform === "win32") {
|
|
7035
|
+
return { created: false, diskPath: backupDiskPath, reuseExisting: false };
|
|
7036
|
+
}
|
|
7037
|
+
try {
|
|
7038
|
+
await writeAtomicPrivateFile(backupDiskPath, expectedContent, PRIVATE_FILE_MODE);
|
|
7039
|
+
} catch {
|
|
7040
|
+
throw new Error(upgradeMessages.backupLocationUnavailable(UPGRADE_BACKUP_DIRECTORY));
|
|
7041
|
+
}
|
|
7042
|
+
return { created: true, diskPath: backupDiskPath, reuseExisting: false };
|
|
7043
|
+
}
|
|
7044
|
+
async function readExpectedConfigSnapshot(workspaceRoot, configPath, expectedContent) {
|
|
7045
|
+
const diskPath = resolveProjectPath(workspaceRoot, configPath);
|
|
7046
|
+
const snapshot = await readSafeTextFileSnapshot(workspaceRoot, diskPath);
|
|
7047
|
+
if (snapshot === undefined) {
|
|
7048
|
+
throw new Error(upgradeMessages.writeTargetMissing(configPath));
|
|
7049
|
+
}
|
|
7050
|
+
if (snapshot.content !== expectedContent) {
|
|
7051
|
+
throw new Error(upgradeMessages.concurrentEdit(configPath));
|
|
7052
|
+
}
|
|
7053
|
+
return snapshot;
|
|
7054
|
+
}
|
|
7055
|
+
function createFsUpgradePort(workspaceRoot, fetch) {
|
|
7056
|
+
return {
|
|
7057
|
+
async readOpencodeConfigFile(path) {
|
|
7058
|
+
const diskPath = resolveProjectPath(workspaceRoot, path);
|
|
7059
|
+
const snapshot = await readSafeTextFileSnapshot(workspaceRoot, diskPath);
|
|
7060
|
+
return snapshot?.content;
|
|
7061
|
+
},
|
|
7062
|
+
async writeOpencodeConfigFile(request) {
|
|
7063
|
+
const diskPath = resolveProjectPath(workspaceRoot, request.path);
|
|
7064
|
+
await readExpectedConfigSnapshot(workspaceRoot, request.path, request.expectedContent);
|
|
7065
|
+
const backup = await ensureUpgradeBackupFile(workspaceRoot, request.path, request.expectedContent);
|
|
7066
|
+
let configWritten = false;
|
|
7067
|
+
try {
|
|
7068
|
+
const current = await readExpectedConfigSnapshot(workspaceRoot, request.path, request.expectedContent);
|
|
7069
|
+
if (process.platform === "win32") {
|
|
7070
|
+
await writeWindowsFileReplacingPreservedAcl(diskPath, request.nextContent, backup.reuseExisting ? undefined : backup.diskPath, request.path);
|
|
7071
|
+
configWritten = true;
|
|
7072
|
+
} else {
|
|
7073
|
+
await writeAtomicPrivateFile(diskPath, request.nextContent, current.mode, {
|
|
7074
|
+
originalOwner: { gid: current.gid, uid: current.uid },
|
|
7075
|
+
onReplaced: () => {
|
|
7076
|
+
configWritten = true;
|
|
7077
|
+
}
|
|
7078
|
+
});
|
|
7079
|
+
}
|
|
7080
|
+
} catch (error) {
|
|
7081
|
+
if (backup.created && !configWritten) {
|
|
7082
|
+
await rm2(backup.diskPath, { force: true }).catch(() => {});
|
|
7083
|
+
}
|
|
7084
|
+
throw error;
|
|
7085
|
+
}
|
|
7086
|
+
},
|
|
7087
|
+
async classifyLocalPluginSpec({ configPath, spec }) {
|
|
7088
|
+
const resolved = resolveLocalSpecPath(workspaceRoot, configPath, spec);
|
|
7089
|
+
if (resolved === undefined) {
|
|
7090
|
+
return "unknown";
|
|
7091
|
+
}
|
|
7092
|
+
let current = await manifestSearchStart(resolved, spec);
|
|
7093
|
+
while (true) {
|
|
7094
|
+
const manifest = await readPackageManifestName(join9(current, "package.json"));
|
|
7095
|
+
if (manifest.kind === "name") {
|
|
7096
|
+
return manifest.name === OPENTEAM_PACKAGE_NAME ? "ours" : "other";
|
|
7097
|
+
}
|
|
7098
|
+
if (manifest.kind === "invalid") {
|
|
7099
|
+
return "unknown";
|
|
7100
|
+
}
|
|
7101
|
+
const parent = dirname4(current);
|
|
7102
|
+
if (parent === current) {
|
|
7103
|
+
return "unknown";
|
|
7104
|
+
}
|
|
7105
|
+
current = parent;
|
|
7106
|
+
}
|
|
7107
|
+
},
|
|
7108
|
+
fetch
|
|
7109
|
+
};
|
|
7110
|
+
}
|
|
7111
|
+
async function runUpgrade(positionals, port, opencodeConfigPaths) {
|
|
7112
|
+
const parsedArgs = parseUpgradePositionals(positionals);
|
|
7113
|
+
if (!parsedArgs.ok) {
|
|
7114
|
+
return renderArgError(parsedArgs.error);
|
|
7115
|
+
}
|
|
7116
|
+
const explicitVersion = parsedArgs.value.targetVersion;
|
|
7117
|
+
if (explicitVersion !== undefined && !isStrictSemver(explicitVersion)) {
|
|
7118
|
+
return {
|
|
7119
|
+
exitCode: 1,
|
|
7120
|
+
stdout: [upgradeMessages.header, upgradeMessages.invalidVersion(explicitVersion)].join(`
|
|
7121
|
+
`)
|
|
7122
|
+
};
|
|
7123
|
+
}
|
|
7124
|
+
const analysis = await analyseConfigFiles(opencodeConfigPaths, port);
|
|
7125
|
+
if (analysis.parseError !== undefined) {
|
|
7126
|
+
return {
|
|
7127
|
+
exitCode: 1,
|
|
7128
|
+
stdout: [upgradeMessages.header, analysis.parseError].join(`
|
|
7129
|
+
`)
|
|
7130
|
+
};
|
|
7131
|
+
}
|
|
7132
|
+
if (analysis.files.length === 0) {
|
|
7133
|
+
if (analysis.localOpenteamEntries.length > 0) {
|
|
7134
|
+
return {
|
|
7135
|
+
exitCode: 1,
|
|
7136
|
+
stdout: [
|
|
7137
|
+
upgradeMessages.header,
|
|
7138
|
+
upgradeMessages.localFileOnlyHeader,
|
|
7139
|
+
...analysis.localOpenteamEntries.map((entry) => upgradeMessages.localFileOnlyEntry(entry)),
|
|
7140
|
+
upgradeMessages.localFileOnlyRemedy
|
|
7141
|
+
].join(`
|
|
7142
|
+
`)
|
|
7143
|
+
};
|
|
7144
|
+
}
|
|
7145
|
+
return {
|
|
7146
|
+
exitCode: 1,
|
|
7147
|
+
stdout: [
|
|
7148
|
+
upgradeMessages.header,
|
|
7149
|
+
analysis.foundConfigFile ? upgradeMessages.noPluginEntry : upgradeMessages.noConfigFound(opencodeConfigPaths)
|
|
7150
|
+
].join(`
|
|
7151
|
+
`)
|
|
7152
|
+
};
|
|
7153
|
+
}
|
|
7154
|
+
let targetVersion;
|
|
7155
|
+
if (explicitVersion !== undefined) {
|
|
7156
|
+
const verified = await verifyVersionExists(explicitVersion, port.fetch);
|
|
7157
|
+
if (!verified.ok) {
|
|
7158
|
+
return { exitCode: 1, stdout: [upgradeMessages.header, verified.error].join(`
|
|
7159
|
+
`) };
|
|
7160
|
+
}
|
|
7161
|
+
targetVersion = explicitVersion;
|
|
7162
|
+
} else {
|
|
7163
|
+
const latest = await fetchLatestVersion(port.fetch);
|
|
7164
|
+
if (!latest.ok) {
|
|
7165
|
+
return { exitCode: 1, stdout: [upgradeMessages.header, latest.error].join(`
|
|
7166
|
+
`) };
|
|
7167
|
+
}
|
|
7168
|
+
targetVersion = latest.version;
|
|
7169
|
+
}
|
|
7170
|
+
const localWarnings = analysis.localOpenteamEntries.map((entry) => upgradeMessages.localFileSkipped(entry));
|
|
7171
|
+
if (explicitVersion === undefined) {
|
|
7172
|
+
for (const file of analysis.files) {
|
|
7173
|
+
for (const currentVersion of file.currentVersions) {
|
|
7174
|
+
if (currentVersion !== null && isStrictSemver(currentVersion) && compareSemver(currentVersion, targetVersion) > 0) {
|
|
7175
|
+
return {
|
|
7176
|
+
exitCode: 1,
|
|
7177
|
+
stdout: [
|
|
7178
|
+
upgradeMessages.header,
|
|
7179
|
+
upgradeMessages.noDowngrade({
|
|
7180
|
+
current: currentVersion,
|
|
7181
|
+
target: targetVersion
|
|
7182
|
+
})
|
|
7183
|
+
].join(`
|
|
7184
|
+
`)
|
|
7185
|
+
};
|
|
7186
|
+
}
|
|
7187
|
+
}
|
|
7188
|
+
}
|
|
7189
|
+
}
|
|
7190
|
+
if (parsedArgs.value.check) {
|
|
7191
|
+
const lines = [upgradeMessages.header];
|
|
7192
|
+
let needsUpdate = false;
|
|
7193
|
+
for (const file of analysis.files) {
|
|
7194
|
+
for (const currentVersion of file.currentVersions) {
|
|
7195
|
+
if (currentVersion === targetVersion) {
|
|
7196
|
+
lines.push(upgradeMessages.checkAlreadyCurrent({
|
|
7197
|
+
path: file.path,
|
|
7198
|
+
version: targetVersion
|
|
7199
|
+
}));
|
|
7200
|
+
} else {
|
|
7201
|
+
lines.push(upgradeMessages.checkNeedsUpdate({
|
|
7202
|
+
path: file.path,
|
|
7203
|
+
current: currentVersion,
|
|
7204
|
+
target: targetVersion
|
|
7205
|
+
}));
|
|
7206
|
+
needsUpdate = true;
|
|
7207
|
+
}
|
|
7208
|
+
}
|
|
7209
|
+
}
|
|
7210
|
+
lines.push(...localWarnings);
|
|
7211
|
+
if (needsUpdate) {
|
|
7212
|
+
lines.push(upgradeMessages.checkHint(explicitVersion));
|
|
7213
|
+
}
|
|
7214
|
+
return { exitCode: 0, stdout: lines.join(`
|
|
7215
|
+
`) };
|
|
7216
|
+
}
|
|
7217
|
+
const nextSpec = pinnedPluginSpec(targetVersion);
|
|
7218
|
+
const plans = [];
|
|
7219
|
+
for (const file of analysis.files) {
|
|
7220
|
+
const nextContent = buildUpdatedContent(file.originalContent, file.replacements, nextSpec);
|
|
7221
|
+
if (nextContent === file.originalContent) {
|
|
7222
|
+
continue;
|
|
7223
|
+
}
|
|
7224
|
+
const validationError = validateEffectivePluginUpdate(file.path, nextContent, file.replacements.length, nextSpec);
|
|
7225
|
+
if (validationError !== undefined) {
|
|
7226
|
+
return {
|
|
7227
|
+
exitCode: 1,
|
|
7228
|
+
stdout: [upgradeMessages.header, validationError].join(`
|
|
7229
|
+
`)
|
|
7230
|
+
};
|
|
7231
|
+
}
|
|
7232
|
+
plans.push({
|
|
7233
|
+
path: file.path,
|
|
7234
|
+
expectedContent: file.originalContent,
|
|
7235
|
+
nextContent
|
|
7236
|
+
});
|
|
7237
|
+
}
|
|
7238
|
+
if (plans.length === 0) {
|
|
7239
|
+
return {
|
|
7240
|
+
exitCode: 0,
|
|
7241
|
+
stdout: [
|
|
7242
|
+
upgradeMessages.header,
|
|
7243
|
+
...localWarnings,
|
|
7244
|
+
upgradeMessages.alreadyCurrent(targetVersion)
|
|
7245
|
+
].join(`
|
|
7246
|
+
`)
|
|
7247
|
+
};
|
|
7248
|
+
}
|
|
7249
|
+
const written = [];
|
|
7250
|
+
const failed = [];
|
|
7251
|
+
for (const plan2 of plans) {
|
|
7252
|
+
try {
|
|
7253
|
+
await port.writeOpencodeConfigFile(plan2);
|
|
7254
|
+
written.push(plan2.path);
|
|
7255
|
+
} catch (error) {
|
|
7256
|
+
failed.push({
|
|
7257
|
+
path: plan2.path,
|
|
7258
|
+
error: error instanceof Error ? error.message : String(error)
|
|
7259
|
+
});
|
|
7260
|
+
}
|
|
7261
|
+
}
|
|
7262
|
+
if (failed.length === 0) {
|
|
7263
|
+
return renderSuccess(targetVersion, localWarnings, written);
|
|
7264
|
+
}
|
|
7265
|
+
if (written.length === 0) {
|
|
7266
|
+
return renderFailedWrites(localWarnings, failed);
|
|
7267
|
+
}
|
|
7268
|
+
return renderPartialSuccess(targetVersion, localWarnings, written, failed);
|
|
7269
|
+
}
|
|
7270
|
+
|
|
7271
|
+
// src/config/graphFeatureGate.ts
|
|
7272
|
+
function checkCertificate(status, name) {
|
|
7273
|
+
if (status.status === "absent") {
|
|
7274
|
+
return {
|
|
7275
|
+
code: `${name}-certificate-absent`,
|
|
7276
|
+
detail: `${name} certificate not found — run the ${name} certification suite to produce it`
|
|
7277
|
+
};
|
|
7278
|
+
}
|
|
7279
|
+
if (status.status === "invalid") {
|
|
7280
|
+
return {
|
|
7281
|
+
code: `${name}-certificate-invalid`,
|
|
7282
|
+
detail: `${name} certificate rejected by recomputing parser: ${status.code} — ${status.detail}`
|
|
7283
|
+
};
|
|
7284
|
+
}
|
|
7285
|
+
return;
|
|
7286
|
+
}
|
|
7287
|
+
function evaluateGraphGate(input) {
|
|
7288
|
+
const violations = [];
|
|
7289
|
+
const advisories = [];
|
|
7290
|
+
const shadowV = checkCertificate(input.shadow, "shadow");
|
|
7291
|
+
if (shadowV !== undefined)
|
|
7292
|
+
violations.push(shadowV);
|
|
7293
|
+
const releaseV = checkCertificate(input.release, "release");
|
|
7294
|
+
if (releaseV !== undefined)
|
|
7295
|
+
violations.push(releaseV);
|
|
7296
|
+
const soakV = checkCertificate(input.soak, "soak");
|
|
7297
|
+
if (soakV !== undefined)
|
|
7298
|
+
advisories.push(soakV);
|
|
7299
|
+
if (input.migration === "pending") {
|
|
7300
|
+
violations.push({
|
|
7301
|
+
code: "migration-pending",
|
|
7302
|
+
detail: "legacy migration has pending work — run the migration tool to completion before enabling active mode"
|
|
7303
|
+
});
|
|
7304
|
+
} else if (input.migration === "unknown") {
|
|
7305
|
+
violations.push({
|
|
7306
|
+
code: "migration-unknown",
|
|
7307
|
+
detail: "could not determine migration status — check ledger readability and storage access"
|
|
7308
|
+
});
|
|
7309
|
+
}
|
|
7310
|
+
if (!input.operatorApproval) {
|
|
7311
|
+
violations.push({
|
|
7312
|
+
code: "operator-approval-missing",
|
|
7313
|
+
detail: "set graph.operatorApproval to true in .opencode/openteam.json after reviewing all certificates and completing migration — this is a declaration of intent, not a proof"
|
|
7314
|
+
});
|
|
7315
|
+
}
|
|
7316
|
+
return {
|
|
7317
|
+
allowed: violations.length === 0,
|
|
7318
|
+
violations,
|
|
7319
|
+
advisories
|
|
7320
|
+
};
|
|
7321
|
+
}
|
|
7322
|
+
function isGateApplicable(mode) {
|
|
7323
|
+
return mode === "active";
|
|
7324
|
+
}
|
|
7325
|
+
|
|
7326
|
+
// src/config/opencode.ts
|
|
7327
|
+
function stripJsoncComments(src) {
|
|
7328
|
+
const out = [];
|
|
7329
|
+
let i = 0;
|
|
7330
|
+
while (i < src.length) {
|
|
7331
|
+
const ch = src[i];
|
|
7332
|
+
if (ch === undefined)
|
|
7333
|
+
break;
|
|
7334
|
+
if (ch === '"') {
|
|
7335
|
+
out.push(ch);
|
|
7336
|
+
i++;
|
|
7337
|
+
while (i < src.length) {
|
|
7338
|
+
const c = src[i];
|
|
7339
|
+
if (c === undefined)
|
|
7340
|
+
break;
|
|
7341
|
+
out.push(c);
|
|
7342
|
+
i++;
|
|
7343
|
+
if (c === "\\") {
|
|
7344
|
+
const escaped = src[i];
|
|
7345
|
+
if (escaped !== undefined) {
|
|
7346
|
+
out.push(escaped);
|
|
7347
|
+
i++;
|
|
7348
|
+
}
|
|
7349
|
+
} else if (c === '"') {
|
|
7350
|
+
break;
|
|
7351
|
+
}
|
|
7352
|
+
}
|
|
7353
|
+
} else if (ch === "/" && i + 1 < src.length) {
|
|
7354
|
+
if (src[i + 1] === "/") {
|
|
7355
|
+
i += 2;
|
|
7356
|
+
while (i < src.length && src[i] !== `
|
|
7357
|
+
`) {
|
|
7358
|
+
i++;
|
|
7359
|
+
}
|
|
7360
|
+
} else if (src[i + 1] === "*") {
|
|
7361
|
+
i += 2;
|
|
7362
|
+
while (i < src.length && !(src[i] === "*" && src[i + 1] === "/")) {
|
|
7363
|
+
i++;
|
|
7364
|
+
}
|
|
7365
|
+
if (i < src.length) {
|
|
7366
|
+
i += 2;
|
|
7367
|
+
}
|
|
7368
|
+
} else {
|
|
7369
|
+
out.push(ch);
|
|
7370
|
+
i++;
|
|
7371
|
+
}
|
|
7372
|
+
} else {
|
|
7373
|
+
out.push(ch);
|
|
7374
|
+
i++;
|
|
7375
|
+
}
|
|
7376
|
+
}
|
|
7377
|
+
return out.join("");
|
|
7378
|
+
}
|
|
7379
|
+
function isRecord4(v) {
|
|
7380
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
7381
|
+
}
|
|
7382
|
+
var OPENCODE_CONFIG_CANDIDATES = [
|
|
7383
|
+
".opencode/opencode.json",
|
|
7384
|
+
"opencode.json"
|
|
7385
|
+
];
|
|
7386
|
+
function mergeOpencodeConfigs(base, override) {
|
|
7387
|
+
const result = { ...base };
|
|
7388
|
+
for (const [key, value] of Object.entries(override)) {
|
|
7389
|
+
const baseVal = result[key];
|
|
7390
|
+
if (isRecord4(baseVal) && isRecord4(value)) {
|
|
7391
|
+
result[key] = mergeOpencodeConfigs(baseVal, value);
|
|
7392
|
+
} else {
|
|
7393
|
+
result[key] = value;
|
|
7394
|
+
}
|
|
7395
|
+
}
|
|
7396
|
+
return result;
|
|
7397
|
+
}
|
|
7398
|
+
|
|
7399
|
+
// src/graph/certificate.ts
|
|
7400
|
+
import { z as z17 } from "zod";
|
|
7401
|
+
|
|
7402
|
+
// src/contract/opencode.ts
|
|
7403
|
+
var SUPPORTED_OPENCODE_VERSIONS = [
|
|
7404
|
+
"1.17.13",
|
|
7405
|
+
"1.18.18",
|
|
7406
|
+
"1.18.19"
|
|
7407
|
+
];
|
|
7408
|
+
var SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)/;
|
|
7409
|
+
function parseSemver(version) {
|
|
7410
|
+
const normalized = version.trim().replace(/^[=^~v]+/, "");
|
|
7411
|
+
const match = SEMVER_RE.exec(normalized);
|
|
7412
|
+
if (match === null) {
|
|
7413
|
+
throw new Error(`invalid semver: "${version}"`);
|
|
7414
|
+
}
|
|
7415
|
+
return {
|
|
7416
|
+
major: Number(match[1]),
|
|
7417
|
+
minor: Number(match[2]),
|
|
5467
7418
|
patch: Number(match[3])
|
|
5468
7419
|
};
|
|
5469
7420
|
}
|
|
@@ -5486,31 +7437,31 @@ function isCertificateVersionCompatible(certifiedVersion, liveVersion) {
|
|
|
5486
7437
|
}
|
|
5487
7438
|
|
|
5488
7439
|
// src/graph/soakLedger.ts
|
|
5489
|
-
import { z as
|
|
5490
|
-
var Sha256Schema2 =
|
|
5491
|
-
var SoakPlatformSchema =
|
|
5492
|
-
var PrivacyPairSchema =
|
|
5493
|
-
surfacesScanned:
|
|
5494
|
-
rawFindings:
|
|
7440
|
+
import { z as z16 } from "zod";
|
|
7441
|
+
var Sha256Schema2 = z16.string().regex(/^[0-9a-f]{64}$/);
|
|
7442
|
+
var SoakPlatformSchema = z16.enum(["linux", "win32", "darwin"]);
|
|
7443
|
+
var PrivacyPairSchema = z16.object({
|
|
7444
|
+
surfacesScanned: z16.number().int().nonnegative(),
|
|
7445
|
+
rawFindings: z16.number().int().nonnegative()
|
|
5495
7446
|
}).strict();
|
|
5496
|
-
var DuplicateEffectPairSchema =
|
|
5497
|
-
effectsExamined:
|
|
5498
|
-
duplicatesFound:
|
|
7447
|
+
var DuplicateEffectPairSchema = z16.object({
|
|
7448
|
+
effectsExamined: z16.number().int().nonnegative(),
|
|
7449
|
+
duplicatesFound: z16.number().int().nonnegative()
|
|
5499
7450
|
}).strict();
|
|
5500
|
-
var ModelVerificationPairSchema =
|
|
5501
|
-
nodesChecked:
|
|
5502
|
-
unverified:
|
|
5503
|
-
mismatched:
|
|
7451
|
+
var ModelVerificationPairSchema = z16.object({
|
|
7452
|
+
nodesChecked: z16.number().int().nonnegative(),
|
|
7453
|
+
unverified: z16.number().int().nonnegative(),
|
|
7454
|
+
mismatched: z16.number().int().nonnegative()
|
|
5504
7455
|
}).strict();
|
|
5505
|
-
var SoakObservationSchema =
|
|
5506
|
-
version:
|
|
5507
|
-
seq:
|
|
5508
|
-
timestamp:
|
|
7456
|
+
var SoakObservationSchema = z16.object({
|
|
7457
|
+
version: z16.literal(1),
|
|
7458
|
+
seq: z16.number().int().nonnegative(),
|
|
7459
|
+
timestamp: z16.string().datetime(),
|
|
5509
7460
|
platform: SoakPlatformSchema,
|
|
5510
|
-
opencodeVersion:
|
|
5511
|
-
provenance:
|
|
7461
|
+
opencodeVersion: z16.string().min(1),
|
|
7462
|
+
provenance: z16.enum(["genuine-usage", "ci-synthetic"]),
|
|
5512
7463
|
traceDigest: Sha256Schema2,
|
|
5513
|
-
criticalDivergences:
|
|
7464
|
+
criticalDivergences: z16.number().int().nonnegative().nullable(),
|
|
5514
7465
|
privacy: PrivacyPairSchema.nullable(),
|
|
5515
7466
|
duplicateEffects: DuplicateEffectPairSchema.nullable(),
|
|
5516
7467
|
modelVerification: ModelVerificationPairSchema.nullable(),
|
|
@@ -5581,7 +7532,7 @@ function canonicalLedger(chains) {
|
|
|
5581
7532
|
|
|
5582
7533
|
// src/graph/certificate.ts
|
|
5583
7534
|
var SHADOW_CERTIFICATE_MIN_RUNS = 1000;
|
|
5584
|
-
var DivergenceCodeSchema =
|
|
7535
|
+
var DivergenceCodeSchema = z17.enum([
|
|
5585
7536
|
"status",
|
|
5586
7537
|
"order",
|
|
5587
7538
|
"roles",
|
|
@@ -5589,50 +7540,50 @@ var DivergenceCodeSchema = z16.enum([
|
|
|
5589
7540
|
"fixes",
|
|
5590
7541
|
"outcome"
|
|
5591
7542
|
]);
|
|
5592
|
-
var ProvenanceSchema =
|
|
7543
|
+
var ProvenanceSchema = z17.enum([
|
|
5593
7544
|
"recomputed",
|
|
5594
7545
|
"compiled",
|
|
5595
7546
|
"validated",
|
|
5596
7547
|
"carried"
|
|
5597
7548
|
]);
|
|
5598
|
-
var EvidenceSchema =
|
|
5599
|
-
opencodeVersion:
|
|
5600
|
-
parity:
|
|
5601
|
-
runs:
|
|
5602
|
-
match:
|
|
5603
|
-
divergent:
|
|
5604
|
-
inconclusive:
|
|
5605
|
-
divergences:
|
|
7549
|
+
var EvidenceSchema = z17.object({
|
|
7550
|
+
opencodeVersion: z17.string().min(1),
|
|
7551
|
+
parity: z17.object({
|
|
7552
|
+
runs: z17.number().int().nonnegative(),
|
|
7553
|
+
match: z17.number().int().nonnegative(),
|
|
7554
|
+
divergent: z17.number().int().nonnegative(),
|
|
7555
|
+
inconclusive: z17.number().int().nonnegative(),
|
|
7556
|
+
divergences: z17.array(DivergenceCodeSchema)
|
|
5606
7557
|
}).strict(),
|
|
5607
|
-
legacy:
|
|
5608
|
-
observed:
|
|
5609
|
-
duplicated:
|
|
7558
|
+
legacy: z17.object({
|
|
7559
|
+
observed: z17.number().int().nonnegative(),
|
|
7560
|
+
duplicated: z17.number().int().nonnegative()
|
|
5610
7561
|
}).strict(),
|
|
5611
|
-
privacy:
|
|
5612
|
-
surfacesScanned:
|
|
5613
|
-
rawFindings:
|
|
7562
|
+
privacy: z17.object({
|
|
7563
|
+
surfacesScanned: z17.number().int().nonnegative(),
|
|
7564
|
+
rawFindings: z17.number().int().nonnegative()
|
|
5614
7565
|
}).strict(),
|
|
5615
|
-
overhead:
|
|
5616
|
-
p95Millis:
|
|
5617
|
-
budgetMillis:
|
|
5618
|
-
samples:
|
|
7566
|
+
overhead: z17.object({
|
|
7567
|
+
p95Millis: z17.number().nonnegative(),
|
|
7568
|
+
budgetMillis: z17.number().positive(),
|
|
7569
|
+
samples: z17.number().int().nonnegative()
|
|
5619
7570
|
}).strict(),
|
|
5620
|
-
provenance:
|
|
7571
|
+
provenance: z17.record(DivergenceCodeSchema, ProvenanceSchema)
|
|
5621
7572
|
}).strict();
|
|
5622
|
-
var CertificateSchema =
|
|
5623
|
-
version:
|
|
5624
|
-
certificate:
|
|
5625
|
-
opencodeVersion:
|
|
7573
|
+
var CertificateSchema = z17.object({
|
|
7574
|
+
version: z17.literal(1),
|
|
7575
|
+
certificate: z17.literal("graph-shadow"),
|
|
7576
|
+
opencodeVersion: z17.string().min(1),
|
|
5626
7577
|
evidence: EvidenceSchema,
|
|
5627
|
-
verdict:
|
|
5628
|
-
failedGates:
|
|
7578
|
+
verdict: z17.enum(["pass", "fail"]),
|
|
7579
|
+
failedGates: z17.array(z17.enum([
|
|
5629
7580
|
"sample",
|
|
5630
7581
|
"parity",
|
|
5631
7582
|
"one-legacy-execution",
|
|
5632
7583
|
"privacy",
|
|
5633
7584
|
"overhead"
|
|
5634
7585
|
])),
|
|
5635
|
-
digest:
|
|
7586
|
+
digest: z17.string().regex(/^[0-9a-f]{64}$/)
|
|
5636
7587
|
}).strict();
|
|
5637
7588
|
|
|
5638
7589
|
class ShadowCertificateError extends Error {
|
|
@@ -5747,37 +7698,37 @@ function parseShadowCertificate(value, opencodeVersion) {
|
|
|
5747
7698
|
}
|
|
5748
7699
|
return certificate;
|
|
5749
7700
|
}
|
|
5750
|
-
var ReleaseDeterminismSchema =
|
|
5751
|
-
var ReleaseCrashRecoverySchema =
|
|
5752
|
-
scenarios:
|
|
5753
|
-
allConverge:
|
|
7701
|
+
var ReleaseDeterminismSchema = z17.object({ runs: z17.number().int().nonnegative(), allMatch: z17.boolean() }).strict();
|
|
7702
|
+
var ReleaseCrashRecoverySchema = z17.object({
|
|
7703
|
+
scenarios: z17.number().int().nonnegative(),
|
|
7704
|
+
allConverge: z17.boolean()
|
|
5754
7705
|
}).strict();
|
|
5755
|
-
var ReleaseReplayEquivalenceSchema =
|
|
5756
|
-
checks:
|
|
5757
|
-
allEquivalent:
|
|
7706
|
+
var ReleaseReplayEquivalenceSchema = z17.object({
|
|
7707
|
+
checks: z17.number().int().nonnegative(),
|
|
7708
|
+
allEquivalent: z17.boolean()
|
|
5758
7709
|
}).strict();
|
|
5759
|
-
var ReleasePrivacySchema =
|
|
5760
|
-
surfacesScanned:
|
|
5761
|
-
rawFindings:
|
|
7710
|
+
var ReleasePrivacySchema = z17.object({
|
|
7711
|
+
surfacesScanned: z17.number().int().nonnegative(),
|
|
7712
|
+
rawFindings: z17.number().int().nonnegative()
|
|
5762
7713
|
}).strict();
|
|
5763
|
-
var ReleaseContractSchema =
|
|
5764
|
-
roundTrips:
|
|
5765
|
-
allSettled:
|
|
7714
|
+
var ReleaseContractSchema = z17.object({
|
|
7715
|
+
roundTrips: z17.number().int().nonnegative(),
|
|
7716
|
+
allSettled: z17.boolean()
|
|
5766
7717
|
}).strict();
|
|
5767
|
-
var ReleaseHealthSchema =
|
|
5768
|
-
samples:
|
|
5769
|
-
bounded:
|
|
5770
|
-
idempotent:
|
|
7718
|
+
var ReleaseHealthSchema = z17.object({
|
|
7719
|
+
samples: z17.number().int().nonnegative(),
|
|
7720
|
+
bounded: z17.boolean(),
|
|
7721
|
+
idempotent: z17.boolean()
|
|
5771
7722
|
}).strict();
|
|
5772
|
-
var ReleasePerformanceSchema =
|
|
5773
|
-
p95Millis:
|
|
5774
|
-
budgetMillis:
|
|
5775
|
-
samples:
|
|
7723
|
+
var ReleasePerformanceSchema = z17.object({
|
|
7724
|
+
p95Millis: z17.number().nonnegative(),
|
|
7725
|
+
budgetMillis: z17.number().positive(),
|
|
7726
|
+
samples: z17.number().int().nonnegative()
|
|
5776
7727
|
}).strict();
|
|
5777
|
-
var ReleaseEvidenceSchema =
|
|
5778
|
-
opencodeVersion:
|
|
5779
|
-
platform:
|
|
5780
|
-
shadowCertificateDigest:
|
|
7728
|
+
var ReleaseEvidenceSchema = z17.object({
|
|
7729
|
+
opencodeVersion: z17.string().min(1),
|
|
7730
|
+
platform: z17.enum(["linux", "win32"]),
|
|
7731
|
+
shadowCertificateDigest: z17.string().regex(/^[0-9a-f]{64}$/),
|
|
5781
7732
|
determinism: ReleaseDeterminismSchema,
|
|
5782
7733
|
crashRecovery: ReleaseCrashRecoverySchema,
|
|
5783
7734
|
replayEquivalence: ReleaseReplayEquivalenceSchema,
|
|
@@ -5786,15 +7737,15 @@ var ReleaseEvidenceSchema = z16.object({
|
|
|
5786
7737
|
health: ReleaseHealthSchema,
|
|
5787
7738
|
performance: ReleasePerformanceSchema
|
|
5788
7739
|
}).strict();
|
|
5789
|
-
var ReleaseCertificateSchema =
|
|
5790
|
-
version:
|
|
5791
|
-
certificate:
|
|
5792
|
-
platform:
|
|
5793
|
-
opencodeVersion:
|
|
5794
|
-
shadowCertificateDigest:
|
|
7740
|
+
var ReleaseCertificateSchema = z17.object({
|
|
7741
|
+
version: z17.literal(2),
|
|
7742
|
+
certificate: z17.literal("graph-release"),
|
|
7743
|
+
platform: z17.enum(["linux", "win32"]),
|
|
7744
|
+
opencodeVersion: z17.string().min(1),
|
|
7745
|
+
shadowCertificateDigest: z17.string().regex(/^[0-9a-f]{64}$/),
|
|
5795
7746
|
evidence: ReleaseEvidenceSchema,
|
|
5796
|
-
verdict:
|
|
5797
|
-
failedGates:
|
|
7747
|
+
verdict: z17.enum(["pass", "fail"]),
|
|
7748
|
+
failedGates: z17.array(z17.enum([
|
|
5798
7749
|
"shadow-valid",
|
|
5799
7750
|
"determinism",
|
|
5800
7751
|
"crash-recovery",
|
|
@@ -5804,7 +7755,7 @@ var ReleaseCertificateSchema = z16.object({
|
|
|
5804
7755
|
"health",
|
|
5805
7756
|
"performance"
|
|
5806
7757
|
])),
|
|
5807
|
-
digest:
|
|
7758
|
+
digest: z17.string().regex(/^[0-9a-f]{64}$/)
|
|
5808
7759
|
}).strict();
|
|
5809
7760
|
|
|
5810
7761
|
class ReleaseCertificateError extends Error {
|
|
@@ -5932,7 +7883,7 @@ function parseReleaseCertificate(value, opencodeVersion, expectedShadowDigest) {
|
|
|
5932
7883
|
}
|
|
5933
7884
|
return certificate;
|
|
5934
7885
|
}
|
|
5935
|
-
var ShadowDivergenceCodeSchema =
|
|
7886
|
+
var ShadowDivergenceCodeSchema = z17.enum([
|
|
5936
7887
|
"status",
|
|
5937
7888
|
"order",
|
|
5938
7889
|
"roles",
|
|
@@ -5941,13 +7892,13 @@ var ShadowDivergenceCodeSchema = z16.enum([
|
|
|
5941
7892
|
"outcome"
|
|
5942
7893
|
]);
|
|
5943
7894
|
var RECOMPUTED_DIVERGENCE_CODES = ["fixes"];
|
|
5944
|
-
var RecomputedDivergenceCodeSchema =
|
|
5945
|
-
var SoakPolicySchema =
|
|
5946
|
-
minimumGenuineObservations:
|
|
5947
|
-
minimumDistinctDays:
|
|
5948
|
-
requireGenuineUsageOnAllPlatforms:
|
|
5949
|
-
supportedOpencodeVersions:
|
|
5950
|
-
criticalDivergenceCodes:
|
|
7895
|
+
var RecomputedDivergenceCodeSchema = z17.enum(RECOMPUTED_DIVERGENCE_CODES);
|
|
7896
|
+
var SoakPolicySchema = z17.object({
|
|
7897
|
+
minimumGenuineObservations: z17.number().int().positive(),
|
|
7898
|
+
minimumDistinctDays: z17.number().int().positive(),
|
|
7899
|
+
requireGenuineUsageOnAllPlatforms: z17.boolean(),
|
|
7900
|
+
supportedOpencodeVersions: z17.array(z17.string().min(1)).min(1),
|
|
7901
|
+
criticalDivergenceCodes: z17.array(RecomputedDivergenceCodeSchema).min(1)
|
|
5951
7902
|
}).strict();
|
|
5952
7903
|
var DEFAULT_SOAK_POLICY = {
|
|
5953
7904
|
minimumGenuineObservations: 100,
|
|
@@ -5956,46 +7907,46 @@ var DEFAULT_SOAK_POLICY = {
|
|
|
5956
7907
|
supportedOpencodeVersions: [...SUPPORTED_OPENCODE_VERSIONS],
|
|
5957
7908
|
criticalDivergenceCodes: ["fixes"]
|
|
5958
7909
|
};
|
|
5959
|
-
var SoakPlatformEnumSchema =
|
|
5960
|
-
var SoakPrivacyPairEvidenceSchema =
|
|
5961
|
-
surfacesScanned:
|
|
5962
|
-
rawFindings:
|
|
7910
|
+
var SoakPlatformEnumSchema = z17.enum(["linux", "win32", "darwin"]);
|
|
7911
|
+
var SoakPrivacyPairEvidenceSchema = z17.object({
|
|
7912
|
+
surfacesScanned: z17.number().int().nonnegative(),
|
|
7913
|
+
rawFindings: z17.number().int().nonnegative()
|
|
5963
7914
|
}).strict();
|
|
5964
|
-
var SoakDuplicateEffectPairEvidenceSchema =
|
|
5965
|
-
effectsExamined:
|
|
5966
|
-
duplicatesFound:
|
|
7915
|
+
var SoakDuplicateEffectPairEvidenceSchema = z17.object({
|
|
7916
|
+
effectsExamined: z17.number().int().nonnegative(),
|
|
7917
|
+
duplicatesFound: z17.number().int().nonnegative()
|
|
5967
7918
|
}).strict();
|
|
5968
|
-
var SoakModelVerificationPairEvidenceSchema =
|
|
5969
|
-
nodesChecked:
|
|
5970
|
-
unverified:
|
|
5971
|
-
mismatched:
|
|
7919
|
+
var SoakModelVerificationPairEvidenceSchema = z17.object({
|
|
7920
|
+
nodesChecked: z17.number().int().nonnegative(),
|
|
7921
|
+
unverified: z17.number().int().nonnegative(),
|
|
7922
|
+
mismatched: z17.number().int().nonnegative()
|
|
5972
7923
|
}).strict();
|
|
5973
|
-
var SoakEvidenceSchema =
|
|
5974
|
-
totalObservations:
|
|
5975
|
-
genuineUsageObservations:
|
|
5976
|
-
ciSyntheticObservations:
|
|
5977
|
-
recorderCount:
|
|
5978
|
-
ineligibleObservations:
|
|
5979
|
-
firstTimestamp:
|
|
5980
|
-
lastTimestamp:
|
|
5981
|
-
distinctDays:
|
|
5982
|
-
criticalDivergences:
|
|
7924
|
+
var SoakEvidenceSchema = z17.object({
|
|
7925
|
+
totalObservations: z17.number().int().nonnegative(),
|
|
7926
|
+
genuineUsageObservations: z17.number().int().nonnegative(),
|
|
7927
|
+
ciSyntheticObservations: z17.number().int().nonnegative(),
|
|
7928
|
+
recorderCount: z17.number().int().nonnegative(),
|
|
7929
|
+
ineligibleObservations: z17.number().int().nonnegative(),
|
|
7930
|
+
firstTimestamp: z17.string().datetime().nullable(),
|
|
7931
|
+
lastTimestamp: z17.string().datetime().nullable(),
|
|
7932
|
+
distinctDays: z17.number().int().nonnegative(),
|
|
7933
|
+
criticalDivergences: z17.number().int().nonnegative().nullable(),
|
|
5983
7934
|
privacy: SoakPrivacyPairEvidenceSchema.nullable(),
|
|
5984
7935
|
duplicateEffects: SoakDuplicateEffectPairEvidenceSchema.nullable(),
|
|
5985
7936
|
modelVerification: SoakModelVerificationPairEvidenceSchema.nullable(),
|
|
5986
|
-
platformsGenuine:
|
|
5987
|
-
platformsSynthetic:
|
|
5988
|
-
opencodeVersionsObserved:
|
|
5989
|
-
invalidChains:
|
|
7937
|
+
platformsGenuine: z17.array(SoakPlatformEnumSchema),
|
|
7938
|
+
platformsSynthetic: z17.array(SoakPlatformEnumSchema),
|
|
7939
|
+
opencodeVersionsObserved: z17.array(z17.string().min(1)),
|
|
7940
|
+
invalidChains: z17.number().int().nonnegative()
|
|
5990
7941
|
}).strict();
|
|
5991
|
-
var SoakCertificateSchema =
|
|
5992
|
-
version:
|
|
5993
|
-
certificate:
|
|
5994
|
-
trustBoundary:
|
|
7942
|
+
var SoakCertificateSchema = z17.object({
|
|
7943
|
+
version: z17.literal(1),
|
|
7944
|
+
certificate: z17.literal("graph-soak"),
|
|
7945
|
+
trustBoundary: z17.literal("contributors"),
|
|
5995
7946
|
policy: SoakPolicySchema,
|
|
5996
7947
|
evidence: SoakEvidenceSchema,
|
|
5997
|
-
verdict:
|
|
5998
|
-
failedGates:
|
|
7948
|
+
verdict: z17.enum(["pass", "fail"]),
|
|
7949
|
+
failedGates: z17.array(z17.enum([
|
|
5999
7950
|
"minimum-observations",
|
|
6000
7951
|
"minimum-duration",
|
|
6001
7952
|
"chain-integrity",
|
|
@@ -6006,8 +7957,8 @@ var SoakCertificateSchema = z16.object({
|
|
|
6006
7957
|
"os-diversity",
|
|
6007
7958
|
"opencode-pin"
|
|
6008
7959
|
])),
|
|
6009
|
-
ledgerDigest:
|
|
6010
|
-
digest:
|
|
7960
|
+
ledgerDigest: z17.string().regex(/^[0-9a-f]{64}$/),
|
|
7961
|
+
digest: z17.string().regex(/^[0-9a-f]{64}$/)
|
|
6011
7962
|
}).strict();
|
|
6012
7963
|
|
|
6013
7964
|
class SoakCertificateError extends Error {
|
|
@@ -6133,7 +8084,7 @@ function parseSoakCertificate(value, expectedPolicy, expectedLedgerDigest) {
|
|
|
6133
8084
|
}
|
|
6134
8085
|
|
|
6135
8086
|
// src/lifecycle/root.ts
|
|
6136
|
-
import { isAbsolute, normalize, relative, resolve as
|
|
8087
|
+
import { isAbsolute, normalize, relative as relative2, resolve as resolve4 } from "node:path";
|
|
6137
8088
|
|
|
6138
8089
|
// src/messages/lifecycleStorage.ts
|
|
6139
8090
|
var lifecycleStorageMessages = {
|
|
@@ -6142,12 +8093,12 @@ var lifecycleStorageMessages = {
|
|
|
6142
8093
|
|
|
6143
8094
|
// src/lifecycle/root.ts
|
|
6144
8095
|
var resolveLifecycleRoot = (options) => {
|
|
6145
|
-
const workspaceRoot =
|
|
8096
|
+
const workspaceRoot = resolve4(options.workspaceRoot);
|
|
6146
8097
|
if (isAbsolute(options.configuredRoot)) {
|
|
6147
|
-
return normalize(
|
|
8098
|
+
return normalize(resolve4(options.configuredRoot));
|
|
6148
8099
|
}
|
|
6149
|
-
const resolved =
|
|
6150
|
-
const workspaceRelative =
|
|
8100
|
+
const resolved = resolve4(workspaceRoot, options.configuredRoot);
|
|
8101
|
+
const workspaceRelative = relative2(workspaceRoot, resolved);
|
|
6151
8102
|
if (workspaceRelative === ".." || workspaceRelative.startsWith(`..\\`) || workspaceRelative.startsWith("../") || isAbsolute(workspaceRelative)) {
|
|
6152
8103
|
throw new Error(lifecycleStorageMessages.configuredRootEscapesWorkspace);
|
|
6153
8104
|
}
|
|
@@ -6155,16 +8106,16 @@ var resolveLifecycleRoot = (options) => {
|
|
|
6155
8106
|
};
|
|
6156
8107
|
|
|
6157
8108
|
// src/lifecycle/schema.ts
|
|
6158
|
-
import { z as
|
|
6159
|
-
var nonEmptyString =
|
|
6160
|
-
var nonNegativeInteger =
|
|
6161
|
-
var positiveInteger =
|
|
6162
|
-
var modelSelectionSchema2 =
|
|
8109
|
+
import { z as z18 } from "zod";
|
|
8110
|
+
var nonEmptyString = z18.string().min(1);
|
|
8111
|
+
var nonNegativeInteger = z18.number().int().nonnegative();
|
|
8112
|
+
var positiveInteger = z18.number().int().positive();
|
|
8113
|
+
var modelSelectionSchema2 = z18.object({
|
|
6163
8114
|
providerID: nonEmptyString,
|
|
6164
8115
|
modelID: nonEmptyString
|
|
6165
8116
|
}).strict();
|
|
6166
|
-
var lifecycleFailureSchema =
|
|
6167
|
-
class:
|
|
8117
|
+
var lifecycleFailureSchema = z18.object({
|
|
8118
|
+
class: z18.enum([
|
|
6168
8119
|
"routing-blocked",
|
|
6169
8120
|
"create-rejected",
|
|
6170
8121
|
"create-no-id",
|
|
@@ -6186,25 +8137,25 @@ var lifecycleFailureSchema = z17.object({
|
|
|
6186
8137
|
"interrupted",
|
|
6187
8138
|
"unknown"
|
|
6188
8139
|
]),
|
|
6189
|
-
statusCode:
|
|
6190
|
-
retryable:
|
|
8140
|
+
statusCode: z18.number().int().min(100).max(599).optional(),
|
|
8141
|
+
retryable: z18.boolean().optional()
|
|
6191
8142
|
}).strict();
|
|
6192
|
-
var lifecycleRootOperationSchema =
|
|
8143
|
+
var lifecycleRootOperationSchema = z18.object({
|
|
6193
8144
|
operationID: nonEmptyString,
|
|
6194
8145
|
taskID: nonEmptyString,
|
|
6195
|
-
kind:
|
|
8146
|
+
kind: z18.enum(["coordinator", "graph-node"]),
|
|
6196
8147
|
roleID: nonEmptyString,
|
|
6197
8148
|
agentID: nonEmptyString.optional(),
|
|
6198
8149
|
sessionID: nonEmptyString.optional()
|
|
6199
8150
|
}).strict();
|
|
6200
|
-
var lifecycleRunStartInputSchema =
|
|
8151
|
+
var lifecycleRunStartInputSchema = z18.object({
|
|
6201
8152
|
runID: nonEmptyString,
|
|
6202
|
-
source:
|
|
6203
|
-
executionAuthority:
|
|
8153
|
+
source: z18.enum(["plugin", "cli"]),
|
|
8154
|
+
executionAuthority: z18.enum(["coordinator", "graph"]),
|
|
6204
8155
|
root: lifecycleRootOperationSchema
|
|
6205
8156
|
}).strict();
|
|
6206
8157
|
var LifecycleRunMetadataSchema = lifecycleRunStartInputSchema.extend({
|
|
6207
|
-
version:
|
|
8158
|
+
version: z18.literal(1),
|
|
6208
8159
|
createdAt: nonNegativeInteger
|
|
6209
8160
|
}).strict();
|
|
6210
8161
|
var attemptRefShape = {
|
|
@@ -6216,34 +8167,34 @@ var attemptRefShape = {
|
|
|
6216
8167
|
retryIndex: nonNegativeInteger
|
|
6217
8168
|
};
|
|
6218
8169
|
var eventEnvelopeShape = {
|
|
6219
|
-
v:
|
|
8170
|
+
v: z18.literal(1),
|
|
6220
8171
|
seq: nonNegativeInteger,
|
|
6221
8172
|
runID: nonEmptyString,
|
|
6222
8173
|
at: nonNegativeInteger
|
|
6223
8174
|
};
|
|
6224
8175
|
var runStartedBodyShape = {
|
|
6225
|
-
type:
|
|
6226
|
-
source:
|
|
6227
|
-
executionAuthority:
|
|
8176
|
+
type: z18.literal("run.started"),
|
|
8177
|
+
source: z18.enum(["plugin", "cli"]),
|
|
8178
|
+
executionAuthority: z18.enum(["coordinator", "graph"]),
|
|
6228
8179
|
root: lifecycleRootOperationSchema
|
|
6229
8180
|
};
|
|
6230
8181
|
var operationQueuedBodyShape = {
|
|
6231
|
-
type:
|
|
8182
|
+
type: z18.literal("operation.queued"),
|
|
6232
8183
|
operationID: nonEmptyString,
|
|
6233
8184
|
taskID: nonEmptyString,
|
|
6234
|
-
kind:
|
|
8185
|
+
kind: z18.enum(["role", "graph-node"]),
|
|
6235
8186
|
roleID: nonEmptyString,
|
|
6236
8187
|
agentID: nonEmptyString.optional(),
|
|
6237
8188
|
parentOperationID: nonEmptyString,
|
|
6238
|
-
dependsOnOperationIDs:
|
|
8189
|
+
dependsOnOperationIDs: z18.array(nonEmptyString).readonly()
|
|
6239
8190
|
};
|
|
6240
8191
|
var modelSelectedBodyShape = {
|
|
6241
|
-
type:
|
|
8192
|
+
type: z18.literal("attempt.model-selected"),
|
|
6242
8193
|
...attemptRefShape,
|
|
6243
8194
|
decisionID: nonEmptyString,
|
|
6244
8195
|
model: modelSelectionSchema2,
|
|
6245
|
-
routeKind:
|
|
6246
|
-
selectionCause:
|
|
8196
|
+
routeKind: z18.enum(["local", "frontier"]),
|
|
8197
|
+
selectionCause: z18.enum([
|
|
6247
8198
|
"initial",
|
|
6248
8199
|
"retry-incomplete",
|
|
6249
8200
|
"retry-transport",
|
|
@@ -6253,31 +8204,31 @@ var modelSelectedBodyShape = {
|
|
|
6253
8204
|
runtimeID: nonEmptyString.optional()
|
|
6254
8205
|
};
|
|
6255
8206
|
var attemptQueuedBodyShape = {
|
|
6256
|
-
type:
|
|
8207
|
+
type: z18.literal("attempt.queued"),
|
|
6257
8208
|
...attemptRefShape,
|
|
6258
8209
|
runtimeID: nonEmptyString.optional()
|
|
6259
8210
|
};
|
|
6260
8211
|
var attemptStartedBodyShape = {
|
|
6261
|
-
type:
|
|
8212
|
+
type: z18.literal("attempt.started"),
|
|
6262
8213
|
...attemptRefShape
|
|
6263
8214
|
};
|
|
6264
8215
|
var sessionCreatedBodyShape = {
|
|
6265
|
-
type:
|
|
8216
|
+
type: z18.literal("session.created"),
|
|
6266
8217
|
...attemptRefShape,
|
|
6267
8218
|
sessionID: nonEmptyString,
|
|
6268
8219
|
parentSessionID: nonEmptyString.optional()
|
|
6269
8220
|
};
|
|
6270
8221
|
var attemptTerminalBodyShape = {
|
|
6271
|
-
type:
|
|
8222
|
+
type: z18.literal("attempt.terminal"),
|
|
6272
8223
|
...attemptRefShape,
|
|
6273
|
-
outcome:
|
|
8224
|
+
outcome: z18.enum([
|
|
6274
8225
|
"succeeded",
|
|
6275
8226
|
"failed",
|
|
6276
8227
|
"cancelled",
|
|
6277
8228
|
"interrupted",
|
|
6278
8229
|
"unknown"
|
|
6279
8230
|
]),
|
|
6280
|
-
continuation:
|
|
8231
|
+
continuation: z18.enum([
|
|
6281
8232
|
"none",
|
|
6282
8233
|
"retry-same-model",
|
|
6283
8234
|
"fallback-next-model",
|
|
@@ -6287,10 +8238,10 @@ var attemptTerminalBodyShape = {
|
|
|
6287
8238
|
failure: lifecycleFailureSchema.optional()
|
|
6288
8239
|
};
|
|
6289
8240
|
var operationTerminalBodyShape = {
|
|
6290
|
-
type:
|
|
8241
|
+
type: z18.literal("operation.terminal"),
|
|
6291
8242
|
operationID: nonEmptyString,
|
|
6292
8243
|
taskID: nonEmptyString,
|
|
6293
|
-
outcome:
|
|
8244
|
+
outcome: z18.enum([
|
|
6294
8245
|
"succeeded",
|
|
6295
8246
|
"failed",
|
|
6296
8247
|
"cancelled",
|
|
@@ -6303,8 +8254,8 @@ var operationTerminalBodyShape = {
|
|
|
6303
8254
|
failure: lifecycleFailureSchema.optional()
|
|
6304
8255
|
};
|
|
6305
8256
|
var runTerminalBodyShape = {
|
|
6306
|
-
type:
|
|
6307
|
-
outcome:
|
|
8257
|
+
type: z18.literal("run.terminal"),
|
|
8258
|
+
outcome: z18.enum([
|
|
6308
8259
|
"succeeded",
|
|
6309
8260
|
"failed",
|
|
6310
8261
|
"cancelled",
|
|
@@ -6315,39 +8266,39 @@ var runTerminalBodyShape = {
|
|
|
6315
8266
|
failure: lifecycleFailureSchema.optional()
|
|
6316
8267
|
};
|
|
6317
8268
|
var bodySchemas = [
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
8269
|
+
z18.object(runStartedBodyShape).strict(),
|
|
8270
|
+
z18.object(operationQueuedBodyShape).strict(),
|
|
8271
|
+
z18.object(modelSelectedBodyShape).strict(),
|
|
8272
|
+
z18.object(attemptQueuedBodyShape).strict(),
|
|
8273
|
+
z18.object(attemptStartedBodyShape).strict(),
|
|
8274
|
+
z18.object(sessionCreatedBodyShape).strict(),
|
|
8275
|
+
z18.object(attemptTerminalBodyShape).strict(),
|
|
8276
|
+
z18.object(operationTerminalBodyShape).strict(),
|
|
8277
|
+
z18.object(runTerminalBodyShape).strict()
|
|
6327
8278
|
];
|
|
6328
8279
|
var appendBodySchemas = bodySchemas.slice(1);
|
|
6329
|
-
var LifecycleAppendEventSchema =
|
|
6330
|
-
var LifecycleEventSchema =
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
8280
|
+
var LifecycleAppendEventSchema = z18.discriminatedUnion("type", appendBodySchemas);
|
|
8281
|
+
var LifecycleEventSchema = z18.discriminatedUnion("type", [
|
|
8282
|
+
z18.object({ ...eventEnvelopeShape, ...runStartedBodyShape }).strict(),
|
|
8283
|
+
z18.object({ ...eventEnvelopeShape, ...operationQueuedBodyShape }).strict(),
|
|
8284
|
+
z18.object({ ...eventEnvelopeShape, ...modelSelectedBodyShape }).strict(),
|
|
8285
|
+
z18.object({ ...eventEnvelopeShape, ...attemptQueuedBodyShape }).strict(),
|
|
8286
|
+
z18.object({ ...eventEnvelopeShape, ...attemptStartedBodyShape }).strict(),
|
|
8287
|
+
z18.object({ ...eventEnvelopeShape, ...sessionCreatedBodyShape }).strict(),
|
|
8288
|
+
z18.object({ ...eventEnvelopeShape, ...attemptTerminalBodyShape }).strict(),
|
|
8289
|
+
z18.object({ ...eventEnvelopeShape, ...operationTerminalBodyShape }).strict(),
|
|
8290
|
+
z18.object({ ...eventEnvelopeShape, ...runTerminalBodyShape }).strict()
|
|
6340
8291
|
]);
|
|
6341
|
-
var LifecycleWriterLeaseInputSchema =
|
|
6342
|
-
writer:
|
|
8292
|
+
var LifecycleWriterLeaseInputSchema = z18.object({
|
|
8293
|
+
writer: z18.object({
|
|
6343
8294
|
processID: positiveInteger,
|
|
6344
8295
|
processInstanceID: nonEmptyString
|
|
6345
8296
|
}).strict(),
|
|
6346
8297
|
now: nonNegativeInteger,
|
|
6347
8298
|
leaseDurationMs: positiveInteger
|
|
6348
8299
|
}).strict();
|
|
6349
|
-
var LifecycleWriterLeaseSchema =
|
|
6350
|
-
version:
|
|
8300
|
+
var LifecycleWriterLeaseSchema = z18.object({
|
|
8301
|
+
version: z18.literal(1),
|
|
6351
8302
|
runID: nonEmptyString,
|
|
6352
8303
|
writerToken: nonEmptyString,
|
|
6353
8304
|
processID: positiveInteger,
|
|
@@ -7232,9 +9183,9 @@ function createRuntimeConcurrencyLimiter(options) {
|
|
|
7232
9183
|
}
|
|
7233
9184
|
const state = stateFor(runtimeId);
|
|
7234
9185
|
const queuedAt = options.now();
|
|
7235
|
-
return new Promise((
|
|
9186
|
+
return new Promise((resolve5) => {
|
|
7236
9187
|
state.queues[priority].push((release) => {
|
|
7237
|
-
|
|
9188
|
+
resolve5({ release, waitedMs: options.now() - queuedAt });
|
|
7238
9189
|
});
|
|
7239
9190
|
});
|
|
7240
9191
|
},
|
|
@@ -7269,30 +9220,82 @@ function embeddingsEndpoint(baseURL) {
|
|
|
7269
9220
|
return `${normalizeBaseURL(baseURL)}/embeddings`;
|
|
7270
9221
|
}
|
|
7271
9222
|
function errorMessage(error) {
|
|
9223
|
+
const chain = errorChain(error);
|
|
9224
|
+
const dnsDetail = dnsErrorMessage(chain);
|
|
9225
|
+
if (dnsDetail !== undefined) {
|
|
9226
|
+
return dnsDetail;
|
|
9227
|
+
}
|
|
9228
|
+
for (const entry of chain) {
|
|
9229
|
+
if (!(entry instanceof Error)) {
|
|
9230
|
+
continue;
|
|
9231
|
+
}
|
|
9232
|
+
if (!isGenericTransportMessage(entry.message)) {
|
|
9233
|
+
return entry.message;
|
|
9234
|
+
}
|
|
9235
|
+
}
|
|
7272
9236
|
if (error instanceof Error) {
|
|
7273
9237
|
return error.message;
|
|
7274
9238
|
}
|
|
7275
9239
|
return String(error);
|
|
7276
9240
|
}
|
|
9241
|
+
function errorChain(error) {
|
|
9242
|
+
const chain = [];
|
|
9243
|
+
const seen = new Set;
|
|
9244
|
+
let current = error;
|
|
9245
|
+
while (current !== undefined && !seen.has(current)) {
|
|
9246
|
+
chain.push(current);
|
|
9247
|
+
seen.add(current);
|
|
9248
|
+
if (typeof current === "object" && current !== null && "cause" in current) {
|
|
9249
|
+
current = current.cause;
|
|
9250
|
+
continue;
|
|
9251
|
+
}
|
|
9252
|
+
break;
|
|
9253
|
+
}
|
|
9254
|
+
return chain;
|
|
9255
|
+
}
|
|
9256
|
+
function errorCode(error) {
|
|
9257
|
+
return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : undefined;
|
|
9258
|
+
}
|
|
9259
|
+
function errorHostname(error) {
|
|
9260
|
+
return typeof error === "object" && error !== null && "hostname" in error && typeof error.hostname === "string" ? error.hostname : undefined;
|
|
9261
|
+
}
|
|
9262
|
+
function isGenericTransportMessage(message) {
|
|
9263
|
+
const normalized = message.trim().toLowerCase();
|
|
9264
|
+
return normalized.length === 0 || normalized === "fetch failed" || normalized === "network error" || normalized === "network request failed";
|
|
9265
|
+
}
|
|
9266
|
+
function dnsErrorMessage(chain) {
|
|
9267
|
+
for (const entry of chain) {
|
|
9268
|
+
const code = errorCode(entry);
|
|
9269
|
+
if (code !== "ENOTFOUND" && code !== "EAI_AGAIN") {
|
|
9270
|
+
continue;
|
|
9271
|
+
}
|
|
9272
|
+
if (entry instanceof Error && !isGenericTransportMessage(entry.message)) {
|
|
9273
|
+
return entry.message;
|
|
9274
|
+
}
|
|
9275
|
+
const hostname = errorHostname(entry);
|
|
9276
|
+
return hostname !== undefined && hostname.length > 0 ? localRuntimeMessages.dnsLookupFailedFor(hostname, code) : localRuntimeMessages.dnsLookupFailed(code);
|
|
9277
|
+
}
|
|
9278
|
+
return;
|
|
9279
|
+
}
|
|
7277
9280
|
async function listOpenAICompatibleModels(baseURL, fetch) {
|
|
7278
9281
|
const response = await fetch(modelsEndpoint(baseURL), {
|
|
7279
9282
|
method: "GET",
|
|
7280
9283
|
headers: { accept: "application/json" }
|
|
7281
9284
|
});
|
|
7282
9285
|
if (!response.ok) {
|
|
7283
|
-
throw new Error(
|
|
9286
|
+
throw new Error(localRuntimeMessages.modelListHttpError(response.status));
|
|
7284
9287
|
}
|
|
7285
9288
|
let payload;
|
|
7286
9289
|
try {
|
|
7287
9290
|
payload = await response.json();
|
|
7288
9291
|
} catch (error) {
|
|
7289
|
-
throw new Error(
|
|
9292
|
+
throw new Error(localRuntimeMessages.malformedModelsJson(errorMessage(error)));
|
|
7290
9293
|
}
|
|
7291
9294
|
return parseOpenAIModels(payload);
|
|
7292
9295
|
}
|
|
7293
9296
|
function parseOpenAIModels(payload) {
|
|
7294
9297
|
if (!isObject(payload) || !Array.isArray(payload.data)) {
|
|
7295
|
-
throw new Error(
|
|
9298
|
+
throw new Error(localRuntimeMessages.malformedModelsResponseExpectedDataArray);
|
|
7296
9299
|
}
|
|
7297
9300
|
return payload.data.map(parseOpenAIModel);
|
|
7298
9301
|
}
|
|
@@ -7327,7 +9330,7 @@ async function probeOpenAICompatibleRuntime(input) {
|
|
|
7327
9330
|
}
|
|
7328
9331
|
function parseOpenAIModel(value) {
|
|
7329
9332
|
if (!isObject(value) || typeof value.id !== "string" || value.id.length === 0) {
|
|
7330
|
-
throw new Error(
|
|
9333
|
+
throw new Error(localRuntimeMessages.malformedModelsResponseModelId);
|
|
7331
9334
|
}
|
|
7332
9335
|
const contextWindow = readContextWindow(value);
|
|
7333
9336
|
const model = {
|
|
@@ -7525,9 +9528,12 @@ var NON_TEXT_LABELS = new Set([
|
|
|
7525
9528
|
"embedding",
|
|
7526
9529
|
"reranking"
|
|
7527
9530
|
]);
|
|
7528
|
-
var PARALLEL_ARG = /(?:^|\s)(?:--parallel|-np)[\s=]+(\d+)(
|
|
9531
|
+
var PARALLEL_ARG = /(?:^|\s)(?:--parallel|-np)[\s=]+(\d+)(?=\s|$)/;
|
|
7529
9532
|
var PARALLEL_FLAGS = new Set(["--parallel", "-np"]);
|
|
7530
9533
|
var PARALLEL_FUSED = /^(?:--parallel|-np)=(\d+)$/;
|
|
9534
|
+
var CTX_SIZE_FUSED = /^--ctx-size=(\d+)$/;
|
|
9535
|
+
var CTX_SIZE_FLAGS = new Set(["--ctx-size"]);
|
|
9536
|
+
var CTX_SIZE_ARG = /(?:^|\s)--ctx-size[\s=]+(\d+)(?=\s|$)/;
|
|
7531
9537
|
function createLemonadeAdapter() {
|
|
7532
9538
|
const listModels = async (options) => {
|
|
7533
9539
|
const baseURL = normalizeBaseURL(options.baseURL ?? LEMONADE_DEFAULT_BASE_URL);
|
|
@@ -7566,13 +9572,13 @@ async function listLemonadeModels(baseURL, fetch) {
|
|
|
7566
9572
|
headers: { accept: "application/json" }
|
|
7567
9573
|
});
|
|
7568
9574
|
if (!response.ok) {
|
|
7569
|
-
throw new Error(
|
|
9575
|
+
throw new Error(localRuntimeMessages.modelListHttpError(response.status));
|
|
7570
9576
|
}
|
|
7571
9577
|
let payload;
|
|
7572
9578
|
try {
|
|
7573
9579
|
payload = await response.json();
|
|
7574
9580
|
} catch (error) {
|
|
7575
|
-
throw new Error(
|
|
9581
|
+
throw new Error(localRuntimeMessages.malformedModelsJson(errorMessage(error)));
|
|
7576
9582
|
}
|
|
7577
9583
|
const nonText = readNonTextModelIDs(payload);
|
|
7578
9584
|
return parseOpenAIModels(payload).filter((model) => !nonText.has(model.modelID));
|
|
@@ -7623,13 +9629,19 @@ async function readLoadedModels(baseURL, fetch) {
|
|
|
7623
9629
|
if (entry.loaded === false) {
|
|
7624
9630
|
continue;
|
|
7625
9631
|
}
|
|
7626
|
-
loaded.set(entry.model_name, {
|
|
9632
|
+
loaded.set(entry.model_name, {
|
|
9633
|
+
slots: readSlotCount(entry),
|
|
9634
|
+
totalContextWindow: readLoadedContextWindow(entry)
|
|
9635
|
+
});
|
|
7627
9636
|
}
|
|
7628
9637
|
return loaded;
|
|
7629
9638
|
}
|
|
7630
9639
|
function readSlotCount(entry) {
|
|
7631
9640
|
return slotsFromLlamacppArgs(entry) ?? slotsFromLaunchCommand(entry);
|
|
7632
9641
|
}
|
|
9642
|
+
function readLoadedContextWindow(entry) {
|
|
9643
|
+
return contextWindowFromRecipeOptions(entry) ?? contextWindowFromLaunchCommand(entry);
|
|
9644
|
+
}
|
|
7633
9645
|
function slotsFromLlamacppArgs(entry) {
|
|
7634
9646
|
const options = entry.recipe_options;
|
|
7635
9647
|
if (!isObject2(options) || typeof options.llamacpp_args !== "string") {
|
|
@@ -7640,7 +9652,7 @@ function slotsFromLlamacppArgs(entry) {
|
|
|
7640
9652
|
}
|
|
7641
9653
|
function slotsFromLaunchCommand(entry) {
|
|
7642
9654
|
const argv = entry.launch_command;
|
|
7643
|
-
if (!Array.isArray(argv)) {
|
|
9655
|
+
if (!Array.isArray(argv) || !launchCommandLooksLikeLlamacpp(argv)) {
|
|
7644
9656
|
return;
|
|
7645
9657
|
}
|
|
7646
9658
|
for (let index = 0;index < argv.length; index += 1) {
|
|
@@ -7666,23 +9678,119 @@ function slotsFromLaunchCommand(entry) {
|
|
|
7666
9678
|
}
|
|
7667
9679
|
return;
|
|
7668
9680
|
}
|
|
7669
|
-
function
|
|
7670
|
-
|
|
9681
|
+
function contextWindowFromRecipeOptions(entry) {
|
|
9682
|
+
const options = entry.recipe_options;
|
|
9683
|
+
if (!isObject2(options) || !hasLlamacppEvidence(entry)) {
|
|
9684
|
+
return;
|
|
9685
|
+
}
|
|
9686
|
+
const direct = positiveIntegerValue(options.ctx_size);
|
|
9687
|
+
if (direct !== undefined) {
|
|
9688
|
+
return direct;
|
|
9689
|
+
}
|
|
9690
|
+
if (typeof options.llamacpp_args !== "string") {
|
|
9691
|
+
return;
|
|
9692
|
+
}
|
|
9693
|
+
const match = CTX_SIZE_ARG.exec(options.llamacpp_args);
|
|
9694
|
+
return match === null ? undefined : positiveSlotCount(match[1]);
|
|
9695
|
+
}
|
|
9696
|
+
function contextWindowFromLaunchCommand(entry) {
|
|
9697
|
+
const argv = entry.launch_command;
|
|
9698
|
+
if (!Array.isArray(argv) || !launchCommandLooksLikeLlamacpp(argv)) {
|
|
9699
|
+
return;
|
|
9700
|
+
}
|
|
9701
|
+
for (let index = 0;index < argv.length; index += 1) {
|
|
9702
|
+
const token = argv[index];
|
|
9703
|
+
if (typeof token !== "string") {
|
|
9704
|
+
continue;
|
|
9705
|
+
}
|
|
9706
|
+
const fused = CTX_SIZE_FUSED.exec(token);
|
|
9707
|
+
if (fused !== null) {
|
|
9708
|
+
const contextWindow = positiveSlotCount(fused[1]);
|
|
9709
|
+
if (contextWindow !== undefined) {
|
|
9710
|
+
return contextWindow;
|
|
9711
|
+
}
|
|
9712
|
+
continue;
|
|
9713
|
+
}
|
|
9714
|
+
if (CTX_SIZE_FLAGS.has(token)) {
|
|
9715
|
+
const next = argv[index + 1];
|
|
9716
|
+
const contextWindow = typeof next === "string" ? positiveSlotCount(next) : undefined;
|
|
9717
|
+
if (contextWindow !== undefined) {
|
|
9718
|
+
return contextWindow;
|
|
9719
|
+
}
|
|
9720
|
+
}
|
|
9721
|
+
}
|
|
9722
|
+
return;
|
|
9723
|
+
}
|
|
9724
|
+
function positiveSlotCount(raw) {
|
|
9725
|
+
if (raw === undefined || !/^\d+$/.test(raw)) {
|
|
9726
|
+
return;
|
|
9727
|
+
}
|
|
9728
|
+
const parsed = Number.parseInt(raw, 10);
|
|
9729
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined;
|
|
9730
|
+
}
|
|
9731
|
+
function positiveIntegerValue(value) {
|
|
9732
|
+
if (typeof value === "number") {
|
|
9733
|
+
return Number.isSafeInteger(value) && value > 0 ? value : undefined;
|
|
9734
|
+
}
|
|
9735
|
+
return typeof value === "string" ? positiveSlotCount(value) : undefined;
|
|
9736
|
+
}
|
|
9737
|
+
function hasLlamacppEvidence(entry) {
|
|
9738
|
+
const recipe = entry.recipe;
|
|
9739
|
+
if (typeof recipe === "string" && recipe.toLowerCase().includes("llamacpp")) {
|
|
9740
|
+
return true;
|
|
9741
|
+
}
|
|
9742
|
+
const options = entry.recipe_options;
|
|
9743
|
+
if (isObject2(options) && typeof options.llamacpp_args === "string") {
|
|
9744
|
+
return true;
|
|
9745
|
+
}
|
|
9746
|
+
return Array.isArray(entry.launch_command) && launchCommandLooksLikeLlamacpp(entry.launch_command);
|
|
9747
|
+
}
|
|
9748
|
+
function launchCommandLooksLikeLlamacpp(argv) {
|
|
9749
|
+
const firstToken = argv.find((token) => typeof token === "string" && token.length > 0);
|
|
9750
|
+
if (firstToken === undefined) {
|
|
9751
|
+
return false;
|
|
9752
|
+
}
|
|
9753
|
+
const normalized = firstToken.replace(/\\/g, "/").toLowerCase();
|
|
9754
|
+
return normalized === "llama-server" || normalized.endsWith("/llama-server") || normalized === "llama-server.exe" || normalized.endsWith("/llama-server.exe");
|
|
9755
|
+
}
|
|
9756
|
+
function derivedConservativeContextWindow(reportedContextWindow, loaded) {
|
|
9757
|
+
if (loaded.totalContextWindow === undefined || loaded.slots === undefined || loaded.slots <= 0) {
|
|
7671
9758
|
return;
|
|
7672
9759
|
}
|
|
7673
|
-
const
|
|
7674
|
-
|
|
9760
|
+
const derived = Math.floor(loaded.totalContextWindow / loaded.slots);
|
|
9761
|
+
if (derived <= 0) {
|
|
9762
|
+
return;
|
|
9763
|
+
}
|
|
9764
|
+
return reportedContextWindow === undefined ? derived : Math.min(reportedContextWindow, derived);
|
|
9765
|
+
}
|
|
9766
|
+
function withoutUnverifiedContextWindow(model) {
|
|
9767
|
+
const {
|
|
9768
|
+
contextWindow: _contextWindow,
|
|
9769
|
+
contextWindowProvenance: _contextWindowProvenance,
|
|
9770
|
+
...withoutContext
|
|
9771
|
+
} = model;
|
|
9772
|
+
return withoutContext;
|
|
7675
9773
|
}
|
|
7676
9774
|
function enrichWithLoadState(models, loaded) {
|
|
7677
9775
|
if (loaded === undefined) {
|
|
7678
|
-
return
|
|
9776
|
+
return models.map((model) => withoutUnverifiedContextWindow(model));
|
|
7679
9777
|
}
|
|
7680
9778
|
return models.map((model) => {
|
|
9779
|
+
const base = withoutUnverifiedContextWindow(model);
|
|
7681
9780
|
const hit = loaded.get(model.modelID);
|
|
7682
9781
|
if (hit === undefined) {
|
|
7683
|
-
return { ...
|
|
9782
|
+
return { ...base, loaded: false };
|
|
7684
9783
|
}
|
|
7685
|
-
|
|
9784
|
+
const contextWindow = derivedConservativeContextWindow(model.contextWindow, hit);
|
|
9785
|
+
return {
|
|
9786
|
+
...base,
|
|
9787
|
+
loaded: true,
|
|
9788
|
+
...hit.slots !== undefined ? { slots: hit.slots } : {},
|
|
9789
|
+
...contextWindow !== undefined ? {
|
|
9790
|
+
contextWindow,
|
|
9791
|
+
contextWindowProvenance: "derived-conservative"
|
|
9792
|
+
} : {}
|
|
9793
|
+
};
|
|
7686
9794
|
});
|
|
7687
9795
|
}
|
|
7688
9796
|
function isObject2(value) {
|
|
@@ -7856,6 +9964,9 @@ function withReportedModelSlots(runtime, reported) {
|
|
|
7856
9964
|
}
|
|
7857
9965
|
|
|
7858
9966
|
// src/messages/orchestration.ts
|
|
9967
|
+
var HOST_SESSION_REQUIRED = "Orchestration requires a nonempty host ToolContext sessionID.";
|
|
9968
|
+
var PARENT_OVERRIDE_IGNORED = "parentSessionID override ignored: the trusted host ToolContext session owns this orchestration and its children. Programmatic callers must supply their parent as the ToolContext sessionID.";
|
|
9969
|
+
var PARENT_SESSION_DESCRIPTION = "Legacy parent reference. Omit it: the trusted host ToolContext session is the parent. A differing payload value is ignored with an advisory.";
|
|
7859
9970
|
var SESSION_CREATE_MISSING_ID = "create response did not include a session id";
|
|
7860
9971
|
function orchestrationSummaryHeading(roleCount, completed) {
|
|
7861
9972
|
return `orchestration ${completed ? "completed" : "incomplete"} (${roleCount} role(s)):`;
|
|
@@ -7932,24 +10043,24 @@ var reportArtifactExists = async (reportPath) => {
|
|
|
7932
10043
|
};
|
|
7933
10044
|
|
|
7934
10045
|
// src/orchestrator/reportArtifactReader.ts
|
|
7935
|
-
import { readFile as
|
|
10046
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
7936
10047
|
var readReportArtifact = async (reportPath) => {
|
|
7937
10048
|
try {
|
|
7938
|
-
return await
|
|
10049
|
+
return await readFile3(reportPath, "utf8");
|
|
7939
10050
|
} catch {
|
|
7940
10051
|
return;
|
|
7941
10052
|
}
|
|
7942
10053
|
};
|
|
7943
10054
|
|
|
7944
10055
|
// src/orchestrator/roster.ts
|
|
7945
|
-
import { z as
|
|
7946
|
-
var RosterEntrySchema =
|
|
7947
|
-
roleID:
|
|
7948
|
-
agentName:
|
|
10056
|
+
import { z as z19 } from "zod";
|
|
10057
|
+
var RosterEntrySchema = z19.object({
|
|
10058
|
+
roleID: z19.string().min(1),
|
|
10059
|
+
agentName: z19.string().min(1)
|
|
7949
10060
|
}).strict();
|
|
7950
|
-
var RosterSchema =
|
|
7951
|
-
universe:
|
|
7952
|
-
entries:
|
|
10061
|
+
var RosterSchema = z19.object({
|
|
10062
|
+
universe: z19.string().min(1),
|
|
10063
|
+
entries: z19.array(RosterEntrySchema)
|
|
7953
10064
|
}).strict();
|
|
7954
10065
|
var ROSTER_JSON_FENCE = /```json\s*([\s\S]*?)```/;
|
|
7955
10066
|
|
|
@@ -8318,9 +10429,9 @@ async function withTimeout(promise, timeoutMs) {
|
|
|
8318
10429
|
return { kind: "settled", value: await promise };
|
|
8319
10430
|
}
|
|
8320
10431
|
let timeoutID;
|
|
8321
|
-
const timeout = new Promise((
|
|
10432
|
+
const timeout = new Promise((resolve5) => {
|
|
8322
10433
|
timeoutID = setTimeout(() => {
|
|
8323
|
-
|
|
10434
|
+
resolve5({ kind: "timeout" });
|
|
8324
10435
|
}, timeoutMs);
|
|
8325
10436
|
});
|
|
8326
10437
|
try {
|
|
@@ -8340,8 +10451,8 @@ async function beforeDeadline(request, deadline, deps) {
|
|
|
8340
10451
|
const controller = new AbortController;
|
|
8341
10452
|
let timeoutID;
|
|
8342
10453
|
const observedRequest = Promise.resolve().then(() => request(controller.signal)).then((value) => ({ kind: "settled", value }), (error) => ({ kind: "rejected", error }));
|
|
8343
|
-
const timeout = new Promise((
|
|
8344
|
-
timeoutID = setTimeout(() =>
|
|
10454
|
+
const timeout = new Promise((resolve5) => {
|
|
10455
|
+
timeoutID = setTimeout(() => resolve5({ kind: "timeout" }), remainingMs);
|
|
8345
10456
|
});
|
|
8346
10457
|
try {
|
|
8347
10458
|
const outcome = await Promise.race([observedRequest, timeout]);
|
|
@@ -8863,257 +10974,44 @@ function sessionEndpointEventFrom(sessionID, url, now, meta = {}) {
|
|
|
8863
10974
|
}
|
|
8864
10975
|
var ACTIVITY_SUMMARIES = {
|
|
8865
10976
|
"session.created": "Session created",
|
|
8866
|
-
"session.idle": "Session idle",
|
|
8867
|
-
"session.error": "Session error"
|
|
8868
|
-
};
|
|
8869
|
-
function sessionIDFromEvent(event) {
|
|
8870
|
-
const properties = event.properties;
|
|
8871
|
-
if (properties === null || typeof properties !== "object") {
|
|
8872
|
-
return;
|
|
8873
|
-
}
|
|
8874
|
-
const record = properties;
|
|
8875
|
-
if (typeof record.sessionID === "string") {
|
|
8876
|
-
return record.sessionID;
|
|
8877
|
-
}
|
|
8878
|
-
if (typeof record.info?.id === "string") {
|
|
8879
|
-
return record.info.id;
|
|
8880
|
-
}
|
|
8881
|
-
return;
|
|
8882
|
-
}
|
|
8883
|
-
function activityEventFrom(event, now) {
|
|
8884
|
-
const summary = ACTIVITY_SUMMARIES[event.type];
|
|
8885
|
-
if (summary === undefined) {
|
|
8886
|
-
return;
|
|
8887
|
-
}
|
|
8888
|
-
const sessionID = sessionIDFromEvent(event);
|
|
8889
|
-
if (sessionID === undefined) {
|
|
8890
|
-
return;
|
|
8891
|
-
}
|
|
8892
|
-
return {
|
|
8893
|
-
v: EVENT_SCHEMA_VERSION,
|
|
8894
|
-
type: "activity",
|
|
8895
|
-
ts: now(),
|
|
8896
|
-
sessionID,
|
|
8897
|
-
kind: "agent",
|
|
8898
|
-
summary
|
|
8899
|
-
};
|
|
8900
|
-
}
|
|
8901
|
-
|
|
8902
|
-
// src/plugin/commandTool.ts
|
|
8903
|
-
import { tool } from "@opencode-ai/plugin";
|
|
8904
|
-
|
|
8905
|
-
// src/messages/commands.ts
|
|
8906
|
-
var clearCacheMessages = {
|
|
8907
|
-
header: "openteam clear-cache — frozen plugin cache entries:",
|
|
8908
|
-
columns: {
|
|
8909
|
-
specDir: "spec dir",
|
|
8910
|
-
pinned: "spec-pinned",
|
|
8911
|
-
installed: "installed",
|
|
8912
|
-
mtime: "mtime"
|
|
8913
|
-
},
|
|
8914
|
-
reparseSkipSuffix: " [SKIP — reparse point]",
|
|
8915
|
-
deletedLabel: "deleted.",
|
|
8916
|
-
lockedLabel: (message) => `[LOCKED] ${message}`,
|
|
8917
|
-
pathOutsideWarning: (specDir, absolutePath) => ` ⚠ ${specDir}: path outside cacheRoot (${absolutePath}), skipped.`,
|
|
8918
|
-
processed: (count) => `${count} entry(ies) processed.`,
|
|
8919
|
-
found: (count) => `${count} entry(ies) found. Use --delete to remove them.`
|
|
8920
|
-
};
|
|
8921
|
-
var baselineMessages = {
|
|
8922
|
-
effectiveAuto: "cheapest-capable (auto)",
|
|
8923
|
-
pinnedSuffix: (ref) => `${ref} (pinned)`,
|
|
8924
|
-
summary: (params) => [
|
|
8925
|
-
"openteam baseline:",
|
|
8926
|
-
` mode: ${params.mode}`,
|
|
8927
|
-
` pinned: ${params.pinned}`,
|
|
8928
|
-
` hardDefault: ${params.hardDefault}`,
|
|
8929
|
-
` effective: ${params.effective}`
|
|
8930
|
-
],
|
|
8931
|
-
invalidModel: (input) => `Invalid model "${input}". Use the provider/model format, e.g. anthropic/claude-sonnet-4-5.`,
|
|
8932
|
-
pinnedTo: (ref) => `Baseline pinned to ${ref} (pinned mode).`,
|
|
8933
|
-
autoMode: "Baseline set to auto mode (cheapest-capable)."
|
|
8934
|
-
};
|
|
8935
|
-
var localMessages = {
|
|
8936
|
-
help: {
|
|
8937
|
-
status: " openteam local status Show the execution mode (local / frontier / mixed)",
|
|
8938
|
-
off: " openteam local off Use frontier models only",
|
|
8939
|
-
only: " openteam local only Use local models only",
|
|
8940
|
-
on: " openteam local on Enable mixed local/frontier execution"
|
|
8941
|
-
},
|
|
8942
|
-
noRuntimes: "none",
|
|
8943
|
-
modeFrontier: "frontier",
|
|
8944
|
-
modeLocal: "local",
|
|
8945
|
-
modeMixed: "mixed",
|
|
8946
|
-
summary: (params) => [
|
|
8947
|
-
"openteam local:",
|
|
8948
|
-
` execution mode: ${params.mode}`,
|
|
8949
|
-
` local runtimes: ${params.runtimes}`
|
|
8950
|
-
],
|
|
8951
|
-
frontierOnlyNoChange: "No change: execution mode is already frontier.",
|
|
8952
|
-
frontierOnlyEnabled: "Frontier execution enabled.",
|
|
8953
|
-
localOnlyNoRuntimes: "Cannot enable local execution: no enabled local runtime is configured. Run 'openteam setup' or enable a local runtime in .opencode/openteam.json first.",
|
|
8954
|
-
localOnlyNoChange: "No change: execution mode is already local.",
|
|
8955
|
-
localOnlyEnabled: "Local execution enabled.",
|
|
8956
|
-
localFirstNoChange: "No change: execution mode is already mixed.",
|
|
8957
|
-
localFirstReEnabled: "Mixed local/frontier execution enabled. Make sure each configured provider is reachable.",
|
|
8958
|
-
unknownSubcommand: (subcommand, help) => `Unknown local subcommand: ${subcommand}
|
|
8959
|
-
|
|
8960
|
-
${help}`
|
|
8961
|
-
};
|
|
8962
|
-
var yoloMessages = {
|
|
8963
|
-
updated: (path2, status, agentNote) => `${path2} updated. ${status}${agentNote}
|
|
8964
|
-
Restart opencode (or reload) so agents pick up the new permissions.`
|
|
8965
|
-
};
|
|
8966
|
-
var migrateMessages = {
|
|
8967
|
-
header: "openteam migrate:",
|
|
8968
|
-
nothingToMigrate: " nothing to migrate — the P15b layout is already in place.",
|
|
8969
|
-
counts: (params) => [
|
|
8970
|
-
` moved: ${params.moved} file(s)`,
|
|
8971
|
-
` deduped: ${params.deduped} file(s) (destination already identical)`,
|
|
8972
|
-
` conflicts: ${params.conflicts} file(s)`
|
|
8973
|
-
],
|
|
8974
|
-
relocatedHeader: " relocated:",
|
|
8975
|
-
relocatedEntry: (from, to, deduped) => ` · ${from} → ${to}${deduped ? " (deduped)" : ""}`,
|
|
8976
|
-
conflictsHeader: " ⚠ left in place (destination exists with different content — no data lost):",
|
|
8977
|
-
conflictEntry: (from, to) => ` · ${from} → ${to}`,
|
|
8978
|
-
manualWorktreesHeader: " ⚠ legacy git worktree(s) need a manual move (run `git worktree move`):",
|
|
8979
|
-
manualWorktreeEntry: (label, from, to) => ` · ${label}: ${from} → ${to}`,
|
|
8980
|
-
success: " ✓ machine-local runtime output relocated under .opencode/openteam-local/."
|
|
8981
|
-
};
|
|
8982
|
-
var rolesInitMessages = {
|
|
8983
|
-
help: " openteam roles init Compose per-role execution, model, and fallback policy",
|
|
8984
|
-
header: "openteam roles init:",
|
|
8985
|
-
title: "openteam roles init",
|
|
8986
|
-
noRoster: (path2) => ` ✗ no roster at ${path2}.`,
|
|
8987
|
-
noRosterRemedy: " Cast the team first: run `openteam setup`, then ask the orchestrator to register the cast.",
|
|
8988
|
-
unparseableRoster: (path2, error) => ` ✗ ${path2} is present but unparseable: ${error}`,
|
|
8989
|
-
unparseableRosterRemedy: " Run `openteam doctor` for the remedy, then re-run this command.",
|
|
8990
|
-
allProfiled: (count) => ` ✓ ${count} roster role(s) checked; no unprofiled roles — every role resolves a routing profile.`,
|
|
8991
|
-
skipLabel: "Skip for now",
|
|
8992
|
-
skipHint: "leaves the role on its built-in or fallback policy; doctor keeps reporting the missing explicit override",
|
|
8993
|
-
runtimeQuestion: (roleID) => `Preferred local runtime(s) for "${roleID}" (in failover order)`,
|
|
8994
|
-
runtimeHint: "machine-local — written to the git-ignored overlay",
|
|
8995
|
-
cancelled: (reason) => ` ✗ cancelled (${reason}); nothing was written.`,
|
|
8996
|
-
invalidResult: (reason) => ` ✗ refusing to write: the resulting config is invalid — ${reason}`,
|
|
8997
|
-
deprecation: (message) => ` ⚠ ${message}`,
|
|
8998
|
-
nothingWritten: (skipped) => ` · skipped ${skipped}; nothing written.`,
|
|
8999
|
-
nothingToWriteOutro: "Nothing to write.",
|
|
9000
|
-
runtimeBinding: (path2) => ` ✓ runtime binding: ${path2} (git-ignored, machine-local)`,
|
|
9001
|
-
skippedSummary: (roleIDs) => ` · skipped: ${roleIDs} — using built-in or fallback policy; re-run this command to add an explicit override.`,
|
|
9002
|
-
outro: "Role policy updated."
|
|
9003
|
-
};
|
|
9004
|
-
|
|
9005
|
-
// src/messages/executionSetup.ts
|
|
9006
|
-
var executionSetupMessages = {
|
|
9007
|
-
setupIntro: "openteam setup — configure local, frontier, or mixed team execution",
|
|
9008
|
-
runtimeQuestion: "Which local runtimes do you want to enable? (choose 'None' for frontier-only)",
|
|
9009
|
-
runtimeNoneLabel: "None — use frontier models only",
|
|
9010
|
-
runtimeNoneHint: "no local runtime (frontier execution)",
|
|
9011
|
-
executionModeQuestion: "Team execution mode",
|
|
9012
|
-
executionModeChoices: {
|
|
9013
|
-
local: {
|
|
9014
|
-
label: "local — every agent stays on configured local providers",
|
|
9015
|
-
hint: "requires at least one enabled local runtime"
|
|
9016
|
-
},
|
|
9017
|
-
frontier: {
|
|
9018
|
-
label: "frontier — every agent uses frontier providers",
|
|
9019
|
-
hint: "does not require a local runtime"
|
|
9020
|
-
},
|
|
9021
|
-
mixed: {
|
|
9022
|
-
label: "mixed — policies may select local or frontier models",
|
|
9023
|
-
hint: "the global mode is an upper bound; per-agent policies may narrow it"
|
|
9024
|
-
}
|
|
9025
|
-
},
|
|
9026
|
-
frontierOnlyNote: [
|
|
9027
|
-
"No local runtime is enabled, so the team will use frontier providers.",
|
|
9028
|
-
"The selected primary model is written consistently to opencode.json and",
|
|
9029
|
-
".opencode/agent/openteam.md."
|
|
9030
|
-
].join(`
|
|
9031
|
-
`),
|
|
9032
|
-
frontierOnlyTitle: "Frontier execution",
|
|
9033
|
-
localOnlyNote: (model) => [
|
|
9034
|
-
"Every team agent is restricted to configured local providers.",
|
|
9035
|
-
`The primary coordinator is pinned to ${model}.`,
|
|
9036
|
-
"No frontier provider is required for execution while this mode is active."
|
|
9037
|
-
].join(`
|
|
9038
|
-
`),
|
|
9039
|
-
localOnlyTitle: "Local execution",
|
|
9040
|
-
localRequiredError: "local execution requires an enabled local runtime",
|
|
9041
|
-
mixedPrimaryQuestion: "Primary coordinator model",
|
|
9042
|
-
mixedPrimaryLocal: (model) => `Use local thinking model ${model}`,
|
|
9043
|
-
mixedPrimaryFrontier: "Choose a frontier model",
|
|
9044
|
-
frontierModelQuestion: "Frontier model (type to search; cheapest capable entries first)",
|
|
9045
|
-
primaryPolicySummary: (params) => [
|
|
9046
|
-
`Execution mode: ${params.executionMode}`,
|
|
9047
|
-
`Primary model: ${params.primaryModel}`,
|
|
9048
|
-
`Primary fallbacks: ${params.fallbacks}`,
|
|
9049
|
-
"Worker model policy: auto within the global execution mode"
|
|
9050
|
-
],
|
|
9051
|
-
noFallbacks: "none",
|
|
9052
|
-
yoloQuestion: "Enable YOLO mode? (opencode auto-approves all permissions)",
|
|
9053
|
-
configuredSummary: (params) => [
|
|
9054
|
-
...executionSetupMessages.primaryPolicySummary({
|
|
9055
|
-
executionMode: params.executionMode,
|
|
9056
|
-
primaryModel: params.primaryModel,
|
|
9057
|
-
fallbacks: executionSetupMessages.noFallbacks
|
|
9058
|
-
}),
|
|
9059
|
-
`Frontier baseline: ${params.frontierBaseline}`,
|
|
9060
|
-
`Local runtimes: ${params.localRuntimes}`,
|
|
9061
|
-
`YOLO mode: ${params.yolo ? "enabled (auto-approves permissions)" : "disabled"}`,
|
|
9062
|
-
"Web Console: launched separately with 'openteam console' (multi-session, loopback)",
|
|
9063
|
-
`Wrote: ${params.opencodePath}, ${params.configPath}, ${params.agentPath}, ${params.agentDir}/*.md (${params.roleAgentCount} standard subagents), ${params.commandDir}/*.md (${params.commandCount} commands); ensured ${params.gitignorePath}`,
|
|
9064
|
-
"",
|
|
9065
|
-
"Next steps:",
|
|
9066
|
-
params.executionMode === "local" ? " 1. No frontier authentication is required while local execution is active" : " 1. Authenticate the frontier provider: opencode auth login",
|
|
9067
|
-
params.executionMode === "local" ? executionSetupMessages.localRuntimeNextStep : params.executionMode === "mixed" ? executionSetupMessages.mixedNextStep : executionSetupMessages.frontierNextStep,
|
|
9068
|
-
" 3. Press Tab and pick the 'openteam' agent, or type / and pick an /openteam… command"
|
|
9069
|
-
],
|
|
9070
|
-
configuredTitle: "openteam configured",
|
|
9071
|
-
complete: (paths) => `openteam setup complete: ${paths}`,
|
|
9072
|
-
error: (message) => `setup error: ${message}`,
|
|
9073
|
-
localRuntimeNextStep: " 2. Make sure every configured local runtime is reachable",
|
|
9074
|
-
frontierNextStep: " 2. Open opencode in this repo; openteam will use frontier models",
|
|
9075
|
-
mixedNextStep: " 2. Make sure local runtimes are reachable; unavailable candidates can use configured fallbacks",
|
|
9076
|
-
done: "Done. Open opencode and select the 'openteam' agent.",
|
|
9077
|
-
rolePolicy: {
|
|
9078
|
-
whyTitle: "Configure execution and model selection",
|
|
9079
|
-
why: (count) => `${count} roster role(s) have no explicit execution/model override. Configure a compact policy now, or leave them on the built-in automatic policy.`,
|
|
9080
|
-
modeQuestion: (roleID, agentName) => `Execution mode for "${roleID}" (${agentName})`,
|
|
9081
|
-
modeInheritLabel: "Inherit the team execution mode",
|
|
9082
|
-
modeLocalLabel: "Local only",
|
|
9083
|
-
modeFrontierLabel: "Frontier only",
|
|
9084
|
-
modelQuestion: (roleID) => `Model selection for "${roleID}"`,
|
|
9085
|
-
modelAutoLabel: "Auto — choose the cheapest capable eligible model",
|
|
9086
|
-
modelExactLabel: "Exact provider/model pin",
|
|
9087
|
-
modelExactQuestion: (roleID) => `Exact model for "${roleID}" as provider/model`,
|
|
9088
|
-
modelExactPlaceholder: "provider/model",
|
|
9089
|
-
fallbacksQuestion: (roleID) => `Ordered fallbacks for "${roleID}" (comma-separated provider/model, blank for none)`,
|
|
9090
|
-
fallbacksPlaceholder: "provider/model, provider/model",
|
|
9091
|
-
configured: (roleIDs, path2) => ` ✓ execution/model policy: ${roleIDs} → ${path2}`,
|
|
9092
|
-
invalidModelRef: (value) => `invalid model "${value}"; expected provider/model`
|
|
9093
|
-
}
|
|
9094
|
-
};
|
|
9095
|
-
var executionPolicyMessages = {
|
|
9096
|
-
doctorHelp: " openteam doctor Diagnose runtimes, execution policies, and config",
|
|
9097
|
-
agentsHelp: " openteam agents List agents, model identity, and execution policy",
|
|
9098
|
-
section: "Configured execution policies:",
|
|
9099
|
-
globalMode: (mode) => ` execution mode: ${mode}`,
|
|
9100
|
-
line: (policy) => ` ${policy.owner}: mode=${policy.executionMode ?? "inherit"} · model=${policy.model} · fallbacks=${policy.fallbacks.length > 0 ? policy.fallbacks.join(" → ") : "none"}`,
|
|
9101
|
-
retryLimits: (maxRetries, maxModelsPerNode) => ` retry limits: ${maxRetries} retries per model · ${maxModelsPerNode} model(s) per node`,
|
|
9102
|
-
inheritedDefaultUnset: "inherits the opencode.json default (not set); execution follows the configured team and agent policy",
|
|
9103
|
-
inheritedDefault: (subscription) => `inherits default → ${subscription}; execution follows the configured team and agent policy`,
|
|
9104
|
-
unprofiledRoleRouting: " routing: no explicit override — the role inherits its built-in or fallback policy within the global execution-mode upper bound. Roster prose is not executable configuration.",
|
|
9105
|
-
unprofiledRoleRemedy: " remedy: run `openteam roles init`, or add executionMode, model, and ordered fallbacks under orchestrator.roles in .opencode/openteam.json.",
|
|
9106
|
-
noLocalMixed: " ⚠ No local runtime reachable: mixed execution currently has only frontier candidates.",
|
|
9107
|
-
noLocalBlocked: " ✗ No local runtime reachable: local execution is blocked until a configured runtime is available.",
|
|
9108
|
-
primaryLocalMismatch: (name, providerID) => ` ✗ local execution is configured, but primary agent '${name}' points at provider '${providerID}', which opencode.json does not configure.`,
|
|
9109
|
-
primaryLocalMismatchCause: " cause: the primary agent artifact and opencode.json no longer agree on the selected provider/model identity.",
|
|
9110
|
-
primaryLocalMismatchConsequence: " consequence: opencode cannot start the coordinator, so it cannot read the roster or distribute work.",
|
|
9111
|
-
primaryLocalMismatchRemedy: (sourceFile) => ` remedy: re-run \`openteam setup\` to regenerate ${sourceFile} and opencode.json from the same primary policy, then re-run \`openteam doctor\`.`
|
|
9112
|
-
};
|
|
9113
|
-
var localModeChangeMessages = {
|
|
9114
|
-
localProviderInFrontierDomain: (path2, domainPath, providerID, modelID) => `${path2}: model "${providerID}/${modelID}" uses provider "${providerID}", which is configured for local dispatch and cannot be selected when ${domainPath} is "frontier". Update this policy or use \`openteam local on\`.`,
|
|
9115
|
-
frontierProviderInLocalDomain: (path2, domainPath, providerID, modelID) => `${path2}: model "${providerID}/${modelID}" uses provider "${providerID}", which is not a configured local provider and cannot be selected when ${domainPath} is "local". Update this policy or use \`openteam local on\`.`
|
|
10977
|
+
"session.idle": "Session idle",
|
|
10978
|
+
"session.error": "Session error"
|
|
9116
10979
|
};
|
|
10980
|
+
function sessionIDFromEvent(event) {
|
|
10981
|
+
const properties = event.properties;
|
|
10982
|
+
if (properties === null || typeof properties !== "object") {
|
|
10983
|
+
return;
|
|
10984
|
+
}
|
|
10985
|
+
const record = properties;
|
|
10986
|
+
if (typeof record.sessionID === "string") {
|
|
10987
|
+
return record.sessionID;
|
|
10988
|
+
}
|
|
10989
|
+
if (typeof record.info?.id === "string") {
|
|
10990
|
+
return record.info.id;
|
|
10991
|
+
}
|
|
10992
|
+
return;
|
|
10993
|
+
}
|
|
10994
|
+
function activityEventFrom(event, now) {
|
|
10995
|
+
const summary = ACTIVITY_SUMMARIES[event.type];
|
|
10996
|
+
if (summary === undefined) {
|
|
10997
|
+
return;
|
|
10998
|
+
}
|
|
10999
|
+
const sessionID = sessionIDFromEvent(event);
|
|
11000
|
+
if (sessionID === undefined) {
|
|
11001
|
+
return;
|
|
11002
|
+
}
|
|
11003
|
+
return {
|
|
11004
|
+
v: EVENT_SCHEMA_VERSION,
|
|
11005
|
+
type: "activity",
|
|
11006
|
+
ts: now(),
|
|
11007
|
+
sessionID,
|
|
11008
|
+
kind: "agent",
|
|
11009
|
+
summary
|
|
11010
|
+
};
|
|
11011
|
+
}
|
|
11012
|
+
|
|
11013
|
+
// src/plugin/commandTool.ts
|
|
11014
|
+
import { tool } from "@opencode-ai/plugin";
|
|
9117
11015
|
|
|
9118
11016
|
// src/orchestrator/worktreeReconciler.ts
|
|
9119
11017
|
function planOne(wt) {
|
|
@@ -9169,7 +11067,7 @@ function planWorktreeReconciliation(input) {
|
|
|
9169
11067
|
}
|
|
9170
11068
|
|
|
9171
11069
|
// src/telemetry/otelConfig.ts
|
|
9172
|
-
import { z as
|
|
11070
|
+
import { z as z20 } from "zod";
|
|
9173
11071
|
|
|
9174
11072
|
// src/telemetry/fanout.ts
|
|
9175
11073
|
function createFanOutSink(deps) {
|
|
@@ -9247,10 +11145,10 @@ function createOtelSink(deps) {
|
|
|
9247
11145
|
}
|
|
9248
11146
|
|
|
9249
11147
|
// src/telemetry/otelConfig.ts
|
|
9250
|
-
var OtelBackendConfigSchema =
|
|
9251
|
-
backend:
|
|
9252
|
-
connectionEnv:
|
|
9253
|
-
serviceName:
|
|
11148
|
+
var OtelBackendConfigSchema = z20.object({
|
|
11149
|
+
backend: z20.literal("opentelemetry"),
|
|
11150
|
+
connectionEnv: z20.string().min(1),
|
|
11151
|
+
serviceName: z20.string().min(1).optional()
|
|
9254
11152
|
}).strict();
|
|
9255
11153
|
function parseConnectionString(raw) {
|
|
9256
11154
|
const pairs = new Map;
|
|
@@ -9653,22 +11551,22 @@ var KNOWN_FRONTIER_PROVIDER_IDS = new Set([
|
|
|
9653
11551
|
"openrouter"
|
|
9654
11552
|
]);
|
|
9655
11553
|
var VIRTUAL_ROUTER_PROVIDER_ID = "openteam-router";
|
|
9656
|
-
function
|
|
11554
|
+
function isRecord5(value) {
|
|
9657
11555
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9658
11556
|
}
|
|
9659
11557
|
function parseOpencodeProviders(opencodeConfig) {
|
|
9660
11558
|
const result = new Map;
|
|
9661
11559
|
const provider = opencodeConfig?.provider;
|
|
9662
|
-
if (!
|
|
11560
|
+
if (!isRecord5(provider)) {
|
|
9663
11561
|
return result;
|
|
9664
11562
|
}
|
|
9665
11563
|
for (const [id, value] of Object.entries(provider)) {
|
|
9666
|
-
if (!
|
|
11564
|
+
if (!isRecord5(value)) {
|
|
9667
11565
|
result.set(id, {});
|
|
9668
11566
|
continue;
|
|
9669
11567
|
}
|
|
9670
11568
|
const models = value.models;
|
|
9671
|
-
result.set(id,
|
|
11569
|
+
result.set(id, isRecord5(models) ? { models: new Set(Object.keys(models)) } : {});
|
|
9672
11570
|
}
|
|
9673
11571
|
return result;
|
|
9674
11572
|
}
|
|
@@ -9922,6 +11820,54 @@ function renderConsoleStatus(console_) {
|
|
|
9922
11820
|
}
|
|
9923
11821
|
|
|
9924
11822
|
// src/commands/doctor.ts
|
|
11823
|
+
var DEFAULT_COMPACTION_RESERVED_MAX = 20000;
|
|
11824
|
+
function isRecord6(value) {
|
|
11825
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11826
|
+
}
|
|
11827
|
+
function hasOwn(record, key) {
|
|
11828
|
+
return Object.hasOwn(record, key);
|
|
11829
|
+
}
|
|
11830
|
+
function positiveInteger2(value) {
|
|
11831
|
+
return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value > 0 ? value : undefined;
|
|
11832
|
+
}
|
|
11833
|
+
function recordAt(source, key) {
|
|
11834
|
+
const value = source?.[key];
|
|
11835
|
+
return isRecord6(value) ? value : undefined;
|
|
11836
|
+
}
|
|
11837
|
+
function enabledLocalProviderIDs(config) {
|
|
11838
|
+
const providers = new Set;
|
|
11839
|
+
for (const runtime of config.local.runtimes) {
|
|
11840
|
+
if (!runtime.enabled) {
|
|
11841
|
+
continue;
|
|
11842
|
+
}
|
|
11843
|
+
providers.add(runtime.defaultModel.providerID);
|
|
11844
|
+
}
|
|
11845
|
+
return providers;
|
|
11846
|
+
}
|
|
11847
|
+
function detectedContextsByProvider(config, snapshots) {
|
|
11848
|
+
const reachableByRuntime = new Map(snapshots.filter((snapshot) => snapshot.reachable).map((snapshot) => [snapshot.id, snapshot]));
|
|
11849
|
+
const detected = new Map;
|
|
11850
|
+
for (const runtime of config.local.runtimes) {
|
|
11851
|
+
if (!runtime.enabled) {
|
|
11852
|
+
continue;
|
|
11853
|
+
}
|
|
11854
|
+
const snapshot = reachableByRuntime.get(runtime.id);
|
|
11855
|
+
if (snapshot === undefined) {
|
|
11856
|
+
continue;
|
|
11857
|
+
}
|
|
11858
|
+
const providerID = runtime.defaultModel.providerID;
|
|
11859
|
+
const byModel = detected.get(providerID) ?? new Map;
|
|
11860
|
+
for (const model of snapshot.models) {
|
|
11861
|
+
if (model.contextWindow !== undefined) {
|
|
11862
|
+
byModel.set(model.modelID, model.contextWindow);
|
|
11863
|
+
}
|
|
11864
|
+
}
|
|
11865
|
+
if (byModel.size > 0) {
|
|
11866
|
+
detected.set(providerID, byModel);
|
|
11867
|
+
}
|
|
11868
|
+
}
|
|
11869
|
+
return detected;
|
|
11870
|
+
}
|
|
9925
11871
|
function runtimeClassLine(runtime) {
|
|
9926
11872
|
if (runtime === undefined) {
|
|
9927
11873
|
return;
|
|
@@ -10206,6 +12152,118 @@ function agentModelsSection(diagnostics, searchedPaths, localOnly) {
|
|
|
10206
12152
|
lines.push(" note: static checks are offline and deterministic; live checks need a reachable local runtime and can be inconclusive.");
|
|
10207
12153
|
return lines;
|
|
10208
12154
|
}
|
|
12155
|
+
function collectLocalModelLimitWarnings(input) {
|
|
12156
|
+
if (input.opencodeConfig === undefined) {
|
|
12157
|
+
return;
|
|
12158
|
+
}
|
|
12159
|
+
const enabledProviders = enabledLocalProviderIDs(input.config);
|
|
12160
|
+
if (enabledProviders.size === 0) {
|
|
12161
|
+
return { inspectedModels: 0, warnings: [] };
|
|
12162
|
+
}
|
|
12163
|
+
const providerConfig = recordAt(input.opencodeConfig, "provider");
|
|
12164
|
+
const detectedContexts = detectedContextsByProvider(input.config, input.snapshots);
|
|
12165
|
+
const compactionReserved = positiveInteger2(recordAt(input.opencodeConfig, "compaction")?.reserved);
|
|
12166
|
+
const warnings = [];
|
|
12167
|
+
let inspectedModels = 0;
|
|
12168
|
+
for (const providerID of enabledProviders) {
|
|
12169
|
+
const provider = recordAt(providerConfig, providerID);
|
|
12170
|
+
const models = recordAt(provider, "models");
|
|
12171
|
+
if (models === undefined) {
|
|
12172
|
+
continue;
|
|
12173
|
+
}
|
|
12174
|
+
for (const [modelID, modelValue] of Object.entries(models)) {
|
|
12175
|
+
inspectedModels += 1;
|
|
12176
|
+
const problems = [];
|
|
12177
|
+
const remedies = new Set;
|
|
12178
|
+
if (!isRecord6(modelValue)) {
|
|
12179
|
+
problems.push(doctorMessages.localModelLimits.invalidLimitBlock);
|
|
12180
|
+
remedies.add(doctorMessages.localModelLimits.invalidLimitRemedy);
|
|
12181
|
+
warnings.push({
|
|
12182
|
+
providerID,
|
|
12183
|
+
modelID,
|
|
12184
|
+
problems,
|
|
12185
|
+
remedies: [...remedies]
|
|
12186
|
+
});
|
|
12187
|
+
continue;
|
|
12188
|
+
}
|
|
12189
|
+
if (hasOwn(modelValue, "limit") && recordAt(modelValue, "limit") === undefined) {
|
|
12190
|
+
problems.push(doctorMessages.localModelLimits.invalidLimitBlock);
|
|
12191
|
+
remedies.add(doctorMessages.localModelLimits.invalidLimitRemedy);
|
|
12192
|
+
warnings.push({
|
|
12193
|
+
providerID,
|
|
12194
|
+
modelID,
|
|
12195
|
+
problems,
|
|
12196
|
+
remedies: [...remedies]
|
|
12197
|
+
});
|
|
12198
|
+
continue;
|
|
12199
|
+
}
|
|
12200
|
+
const limit = recordAt(modelValue, "limit");
|
|
12201
|
+
const rawOutput = limit?.output;
|
|
12202
|
+
const rawContext = limit?.context;
|
|
12203
|
+
const rawInput = limit?.input;
|
|
12204
|
+
const output = positiveInteger2(rawOutput);
|
|
12205
|
+
const context = positiveInteger2(rawContext);
|
|
12206
|
+
const inputLimit = positiveInteger2(rawInput);
|
|
12207
|
+
if (limit === undefined || !hasOwn(limit, "output")) {
|
|
12208
|
+
problems.push(doctorMessages.localModelLimits.missingOutput);
|
|
12209
|
+
remedies.add(doctorMessages.localModelLimits.outputRemedy);
|
|
12210
|
+
} else if (output === undefined) {
|
|
12211
|
+
problems.push(doctorMessages.localModelLimits.invalidOutput);
|
|
12212
|
+
remedies.add(doctorMessages.localModelLimits.invalidLimitRemedy);
|
|
12213
|
+
}
|
|
12214
|
+
if (limit === undefined || !hasOwn(limit, "context")) {
|
|
12215
|
+
problems.push(doctorMessages.localModelLimits.missingContext);
|
|
12216
|
+
const runtimeContext = detectedContexts.get(providerID)?.get(modelID);
|
|
12217
|
+
remedies.add(runtimeContext === undefined ? doctorMessages.localModelLimits.unknownContextRemedy : doctorMessages.localModelLimits.detectedContextRemedy);
|
|
12218
|
+
} else if (context === undefined) {
|
|
12219
|
+
problems.push(doctorMessages.localModelLimits.invalidContext);
|
|
12220
|
+
remedies.add(doctorMessages.localModelLimits.invalidLimitRemedy);
|
|
12221
|
+
}
|
|
12222
|
+
if (limit !== undefined && hasOwn(limit, "input") && inputLimit === undefined) {
|
|
12223
|
+
problems.push(doctorMessages.localModelLimits.invalidInput);
|
|
12224
|
+
remedies.add(doctorMessages.localModelLimits.invalidLimitRemedy);
|
|
12225
|
+
}
|
|
12226
|
+
if (output !== undefined && context !== undefined && output >= context) {
|
|
12227
|
+
problems.push(doctorMessages.localModelLimits.outputExceedsContext);
|
|
12228
|
+
remedies.add(doctorMessages.localModelLimits.invalidLimitRemedy);
|
|
12229
|
+
}
|
|
12230
|
+
if (output !== undefined && inputLimit !== undefined && inputLimit <= (compactionReserved ?? Math.min(DEFAULT_COMPACTION_RESERVED_MAX, output))) {
|
|
12231
|
+
problems.push(doctorMessages.localModelLimits.outputExceedsInput);
|
|
12232
|
+
remedies.add(doctorMessages.localModelLimits.invalidLimitRemedy);
|
|
12233
|
+
}
|
|
12234
|
+
if (problems.length > 0) {
|
|
12235
|
+
warnings.push({
|
|
12236
|
+
providerID,
|
|
12237
|
+
modelID,
|
|
12238
|
+
problems,
|
|
12239
|
+
remedies: [...remedies]
|
|
12240
|
+
});
|
|
12241
|
+
}
|
|
12242
|
+
}
|
|
12243
|
+
}
|
|
12244
|
+
return { inspectedModels, warnings };
|
|
12245
|
+
}
|
|
12246
|
+
function localModelLimitsSection(input) {
|
|
12247
|
+
const report = collectLocalModelLimitWarnings(input);
|
|
12248
|
+
if (report === undefined || report.inspectedModels === 0 && report.warnings.length === 0) {
|
|
12249
|
+
return [];
|
|
12250
|
+
}
|
|
12251
|
+
if (report.warnings.length === 0) {
|
|
12252
|
+
return [doctorMessages.localModelLimits.section, doctorMessages.localModelLimits.healthy];
|
|
12253
|
+
}
|
|
12254
|
+
const lines = [doctorMessages.localModelLimits.warningSummary(report.warnings.length)];
|
|
12255
|
+
const remedies = new Set;
|
|
12256
|
+
for (const warning of report.warnings) {
|
|
12257
|
+
lines.push(doctorMessages.localModelLimits.modelWarning(warning.providerID, warning.modelID, warning.problems.join("; ")));
|
|
12258
|
+
for (const remedy of warning.remedies) {
|
|
12259
|
+
remedies.add(remedy);
|
|
12260
|
+
}
|
|
12261
|
+
}
|
|
12262
|
+
for (const remedy of remedies) {
|
|
12263
|
+
lines.push(remedy);
|
|
12264
|
+
}
|
|
12265
|
+
return lines;
|
|
12266
|
+
}
|
|
10209
12267
|
function renderDoctor(input) {
|
|
10210
12268
|
const enabledRuntimes = input.config.local.runtimes.filter((r) => r.enabled);
|
|
10211
12269
|
const reachable = input.snapshots.filter((s) => s.reachable).length;
|
|
@@ -10264,6 +12322,7 @@ function renderDoctor(input) {
|
|
|
10264
12322
|
if (input.gitignore !== undefined) {
|
|
10265
12323
|
lines.push(...gitignoreSection(input.gitignore));
|
|
10266
12324
|
}
|
|
12325
|
+
lines.push(...localModelLimitsSection(input));
|
|
10267
12326
|
if (input.otelBackend !== undefined) {
|
|
10268
12327
|
const otel = input.otelBackend;
|
|
10269
12328
|
lines.push(" opentelemetry:");
|
|
@@ -10798,9 +12857,7 @@ ${line}`);
|
|
|
10798
12857
|
}
|
|
10799
12858
|
return observation;
|
|
10800
12859
|
}
|
|
10801
|
-
|
|
10802
12860
|
// src/commands/setup.ts
|
|
10803
|
-
var OPENTEAM_PLUGIN_SPEC = "@jmanuelcorral/openteam";
|
|
10804
12861
|
var OPENCODE_GITIGNORE_PATH = ".opencode/.gitignore";
|
|
10805
12862
|
var GENERATED_OPENTEAM_STATE_PATHS = [
|
|
10806
12863
|
DEFAULT_TELEMETRY_PATH,
|
|
@@ -10931,7 +12988,7 @@ function isInsideRepo(repoRoot, relPath) {
|
|
|
10931
12988
|
function isOpenteamEntry(entry) {
|
|
10932
12989
|
if (typeof entry !== "string")
|
|
10933
12990
|
return false;
|
|
10934
|
-
return entry ===
|
|
12991
|
+
return entry === OPENTEAM_PACKAGE_NAME || entry.startsWith(`${OPENTEAM_PACKAGE_NAME}@`);
|
|
10935
12992
|
}
|
|
10936
12993
|
function escapeRegex(s) {
|
|
10937
12994
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -11106,7 +13163,7 @@ function stripOpenteamFromOpencodeConfig(raw) {
|
|
|
11106
13163
|
try {
|
|
11107
13164
|
parsed = JSON.parse(stripped);
|
|
11108
13165
|
} catch {
|
|
11109
|
-
if (raw.includes(
|
|
13166
|
+
if (raw.includes(OPENTEAM_PACKAGE_NAME)) {
|
|
11110
13167
|
return {
|
|
11111
13168
|
status: "failed",
|
|
11112
13169
|
reason: "document is not valid JSON/JSONC; remove the @jmanuelcorral/openteam plugin entry manually"
|
|
@@ -11115,7 +13172,7 @@ function stripOpenteamFromOpencodeConfig(raw) {
|
|
|
11115
13172
|
return { status: "not-present" };
|
|
11116
13173
|
}
|
|
11117
13174
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
11118
|
-
if (raw.includes(
|
|
13175
|
+
if (raw.includes(OPENTEAM_PACKAGE_NAME)) {
|
|
11119
13176
|
return {
|
|
11120
13177
|
status: "failed",
|
|
11121
13178
|
reason: "top-level value is not a JSON object; remove the @jmanuelcorral/openteam plugin entry manually"
|
|
@@ -11126,7 +13183,7 @@ function stripOpenteamFromOpencodeConfig(raw) {
|
|
|
11126
13183
|
const record = parsed;
|
|
11127
13184
|
const plugins = record.plugin;
|
|
11128
13185
|
if (!Array.isArray(plugins)) {
|
|
11129
|
-
if (raw.includes(
|
|
13186
|
+
if (raw.includes(OPENTEAM_PACKAGE_NAME)) {
|
|
11130
13187
|
return {
|
|
11131
13188
|
status: "failed",
|
|
11132
13189
|
reason: "could not locate a top-level plugin array; remove the @jmanuelcorral/openteam plugin entry manually"
|
|
@@ -11149,7 +13206,7 @@ function stripOpenteamFromOpencodeConfig(raw) {
|
|
|
11149
13206
|
const { keyStart, arrayStart, arrayEnd } = bounds;
|
|
11150
13207
|
if (remaining.length === 0) {
|
|
11151
13208
|
const contents2 = removePluginKeyFromObject(raw, keyStart, arrayEnd);
|
|
11152
|
-
const residue2 = contents2.includes(
|
|
13209
|
+
const residue2 = contents2.includes(OPENTEAM_PACKAGE_NAME) ? "openteam is still referenced in a nested context — remove it manually" : undefined;
|
|
11153
13210
|
return residue2 !== undefined ? { status: "removed", contents: contents2, residue: residue2 } : { status: "removed", contents: contents2 };
|
|
11154
13211
|
}
|
|
11155
13212
|
let arrayText = raw.slice(arrayStart, arrayEnd + 1);
|
|
@@ -11157,7 +13214,7 @@ function stripOpenteamFromOpencodeConfig(raw) {
|
|
|
11157
13214
|
arrayText = removeEntryFromArrayText(arrayText, JSON.stringify(entry));
|
|
11158
13215
|
}
|
|
11159
13216
|
const contents = raw.slice(0, arrayStart) + arrayText + raw.slice(arrayEnd + 1);
|
|
11160
|
-
const residue = contents.includes(
|
|
13217
|
+
const residue = contents.includes(OPENTEAM_PACKAGE_NAME) ? "openteam is still referenced in a nested context — remove it manually" : undefined;
|
|
11161
13218
|
return residue !== undefined ? { status: "removed", contents, residue } : { status: "removed", contents };
|
|
11162
13219
|
}
|
|
11163
13220
|
function stripOpenteamFromGitignore(raw) {
|
|
@@ -11221,7 +13278,7 @@ function describeItem(item) {
|
|
|
11221
13278
|
case "agent":
|
|
11222
13279
|
return `${item.path} (${item.name})`;
|
|
11223
13280
|
case "opencode-config":
|
|
11224
|
-
return `${item.path} (remove the ${
|
|
13281
|
+
return `${item.path} (remove the ${OPENTEAM_PACKAGE_NAME} plugin entry)`;
|
|
11225
13282
|
case "gitignore":
|
|
11226
13283
|
return `${item.path} (remove openteam's generated-state rules)`;
|
|
11227
13284
|
case "worktree":
|
|
@@ -11633,6 +13690,9 @@ var HELP = [
|
|
|
11633
13690
|
" openteam report Cost/savings summary (telemetry)",
|
|
11634
13691
|
" openteam clear-cache List the plugin's frozen cache entries",
|
|
11635
13692
|
" openteam clear-cache --delete Delete the frozen cache entries",
|
|
13693
|
+
upgradeMessages.help.command,
|
|
13694
|
+
upgradeMessages.help.check,
|
|
13695
|
+
upgradeMessages.help.version,
|
|
11636
13696
|
" openteam purge List openteam's footprint (dry run, removes nothing)",
|
|
11637
13697
|
" openteam purge --delete Interactively remove openteam category by category",
|
|
11638
13698
|
" openteam purge --yes Remove every openteam category without prompting",
|
|
@@ -12210,6 +14270,7 @@ async function runCli(argv, deps) {
|
|
|
12210
14270
|
telemetryRecords: records.length,
|
|
12211
14271
|
agentModels,
|
|
12212
14272
|
opencodeConfigPaths,
|
|
14273
|
+
...opencodeConfig !== undefined ? { opencodeConfig } : {},
|
|
12213
14274
|
...queueWait !== undefined ? { queueWait } : {},
|
|
12214
14275
|
...rosterAudit !== undefined ? { rosterAudit } : {},
|
|
12215
14276
|
...rosterRoleCount !== undefined ? { rosterRoleCount } : {},
|
|
@@ -12311,6 +14372,15 @@ async function runCli(argv, deps) {
|
|
|
12311
14372
|
...configWarning !== undefined ? { configWarning } : {}
|
|
12312
14373
|
});
|
|
12313
14374
|
}
|
|
14375
|
+
if (command === "upgrade") {
|
|
14376
|
+
if (deps.upgradePort === undefined) {
|
|
14377
|
+
return {
|
|
14378
|
+
exitCode: 1,
|
|
14379
|
+
stdout: upgradeMessages.portNotConfigured
|
|
14380
|
+
};
|
|
14381
|
+
}
|
|
14382
|
+
return await runUpgrade(parsed.positionals, deps.upgradePort, opencodeConfigPaths);
|
|
14383
|
+
}
|
|
12314
14384
|
if (command === "--version" || command === "-v") {
|
|
12315
14385
|
return { exitCode: 0, stdout: deps.version };
|
|
12316
14386
|
}
|
|
@@ -12330,7 +14400,7 @@ ${HELP}`
|
|
|
12330
14400
|
}
|
|
12331
14401
|
|
|
12332
14402
|
// src/plugin/commandTool.ts
|
|
12333
|
-
function commandArgv(action, model) {
|
|
14403
|
+
function commandArgv(action, model, version) {
|
|
12334
14404
|
switch (action) {
|
|
12335
14405
|
case "show":
|
|
12336
14406
|
return ["baseline", "show"];
|
|
@@ -12348,11 +14418,15 @@ function commandArgv(action, model) {
|
|
|
12348
14418
|
return ["console"];
|
|
12349
14419
|
case "clear-cache":
|
|
12350
14420
|
return ["clear-cache"];
|
|
14421
|
+
case "upgrade":
|
|
14422
|
+
return version === undefined ? ["upgrade"] : ["upgrade", "--version", version];
|
|
14423
|
+
case "upgrade-check":
|
|
14424
|
+
return version === undefined ? ["upgrade", "--check"] : ["upgrade", "--check", "--version", version];
|
|
12351
14425
|
}
|
|
12352
14426
|
}
|
|
12353
14427
|
function createCommandTool(deps) {
|
|
12354
14428
|
return tool({
|
|
12355
|
-
description: "openteam runtime commands: baseline (show/set/auto), doctor, report, agents (LLM per agent: local/frontier + subscription)
|
|
14429
|
+
description: "openteam runtime commands: baseline (show/set/auto), doctor, report, agents (LLM per agent: local/frontier + subscription), console (status/URL of the web Console), upgrade (update plugin pin) and upgrade-check (show current vs target without changes).",
|
|
12356
14430
|
args: {
|
|
12357
14431
|
action: tool.schema.enum([
|
|
12358
14432
|
"show",
|
|
@@ -12362,12 +14436,15 @@ function createCommandTool(deps) {
|
|
|
12362
14436
|
"report",
|
|
12363
14437
|
"agents",
|
|
12364
14438
|
"console",
|
|
12365
|
-
"clear-cache"
|
|
14439
|
+
"clear-cache",
|
|
14440
|
+
"upgrade",
|
|
14441
|
+
"upgrade-check"
|
|
12366
14442
|
]).describe("Action to run"),
|
|
12367
|
-
model: tool.schema.string().optional().describe("Model provider/model (only for action=set)")
|
|
14443
|
+
model: tool.schema.string().optional().describe("Model provider/model (only for action=set)"),
|
|
14444
|
+
version: tool.schema.string().optional()
|
|
12368
14445
|
},
|
|
12369
14446
|
async execute(args) {
|
|
12370
|
-
const result = await runCli(commandArgv(args.action, args.model), deps);
|
|
14447
|
+
const result = await runCli(commandArgv(args.action, args.model, args.version), deps);
|
|
12371
14448
|
return result.stdout;
|
|
12372
14449
|
}
|
|
12373
14450
|
});
|
|
@@ -12537,36 +14614,36 @@ function formatResponse(response) {
|
|
|
12537
14614
|
}
|
|
12538
14615
|
|
|
12539
14616
|
// src/plugin/reportRunSchema.ts
|
|
12540
|
-
import { z as
|
|
14617
|
+
import { z as z22 } from "zod";
|
|
12541
14618
|
|
|
12542
14619
|
// src/plugin/graphShadowIngress.ts
|
|
12543
|
-
import { z as
|
|
14620
|
+
import { z as z21 } from "zod";
|
|
12544
14621
|
var LEGACY_EXECUTION_TRACE_VERSION = 1;
|
|
12545
|
-
var LegacyExecutionStatusSchema =
|
|
14622
|
+
var LegacyExecutionStatusSchema = z21.enum([
|
|
12546
14623
|
"completed",
|
|
12547
14624
|
"failed",
|
|
12548
14625
|
"cancelled"
|
|
12549
14626
|
]);
|
|
12550
|
-
var LegacyReviewOutcomeSchema =
|
|
14627
|
+
var LegacyReviewOutcomeSchema = z21.enum([
|
|
12551
14628
|
"approved",
|
|
12552
14629
|
"rejected",
|
|
12553
14630
|
"inconclusive"
|
|
12554
14631
|
]);
|
|
12555
|
-
var LegacyTraceNodeV1Schema =
|
|
14632
|
+
var LegacyTraceNodeV1Schema = z21.object({
|
|
12556
14633
|
id: NodeIDSchema,
|
|
12557
14634
|
role: NodeRoleSchema,
|
|
12558
|
-
model:
|
|
12559
|
-
sessionRef:
|
|
14635
|
+
model: z21.string().min(1),
|
|
14636
|
+
sessionRef: z21.string().min(1).optional(),
|
|
12560
14637
|
errorClass: ErrorClassSchema.optional()
|
|
12561
14638
|
}).strict();
|
|
12562
|
-
var LegacyExecutionTraceV1Schema =
|
|
12563
|
-
version:
|
|
14639
|
+
var LegacyExecutionTraceV1Schema = z21.object({
|
|
14640
|
+
version: z21.literal(LEGACY_EXECUTION_TRACE_VERSION),
|
|
12564
14641
|
runID: NodeIDSchema,
|
|
12565
14642
|
status: LegacyExecutionStatusSchema,
|
|
12566
14643
|
outcome: LegacyReviewOutcomeSchema,
|
|
12567
|
-
fixes:
|
|
12568
|
-
nodes:
|
|
12569
|
-
parentSessionRef:
|
|
14644
|
+
fixes: z21.number().int().nonnegative(),
|
|
14645
|
+
nodes: z21.array(LegacyTraceNodeV1Schema).min(1),
|
|
14646
|
+
parentSessionRef: z21.string().min(1).optional()
|
|
12570
14647
|
}).strict();
|
|
12571
14648
|
function gateReason2(gate) {
|
|
12572
14649
|
if (gate === undefined || gate.mode === "off") {
|
|
@@ -12637,20 +14714,20 @@ function parseLegacyExecutionTrace(input) {
|
|
|
12637
14714
|
}
|
|
12638
14715
|
|
|
12639
14716
|
// src/plugin/reportRunSchema.ts
|
|
12640
|
-
var ReportRunNodeSchema =
|
|
14717
|
+
var ReportRunNodeSchema = z22.object({
|
|
12641
14718
|
id: NodeIDSchema,
|
|
12642
14719
|
role: NodeRoleSchema,
|
|
12643
|
-
model:
|
|
12644
|
-
ok:
|
|
12645
|
-
sessionRef:
|
|
14720
|
+
model: z22.string().min(1),
|
|
14721
|
+
ok: z22.boolean(),
|
|
14722
|
+
sessionRef: z22.string().min(1).optional(),
|
|
12646
14723
|
errorClass: ErrorClassSchema.optional()
|
|
12647
14724
|
}).strict();
|
|
12648
|
-
var ReportRunPayloadSchema =
|
|
14725
|
+
var ReportRunPayloadSchema = z22.object({
|
|
12649
14726
|
runID: NodeIDSchema,
|
|
12650
14727
|
status: LegacyExecutionStatusSchema,
|
|
12651
|
-
fixes:
|
|
12652
|
-
nodes:
|
|
12653
|
-
parentSessionRef:
|
|
14728
|
+
fixes: z22.number().int().nonnegative(),
|
|
14729
|
+
nodes: z22.array(ReportRunNodeSchema).min(1),
|
|
14730
|
+
parentSessionRef: z22.string().min(1).optional()
|
|
12654
14731
|
}).strict();
|
|
12655
14732
|
|
|
12656
14733
|
// src/orchestrator/graphShadow.ts
|
|
@@ -13951,62 +16028,62 @@ ${lines.join(`
|
|
|
13951
16028
|
}
|
|
13952
16029
|
|
|
13953
16030
|
// src/memory/types.ts
|
|
13954
|
-
import { z as
|
|
16031
|
+
import { z as z23 } from "zod";
|
|
13955
16032
|
var SHARED_OWNER_KEY = "*";
|
|
13956
|
-
var OwnerKeySchema =
|
|
13957
|
-
var MemoryKindSchema =
|
|
13958
|
-
var MemoryBaseSchema =
|
|
13959
|
-
id:
|
|
16033
|
+
var OwnerKeySchema = z23.string().min(1);
|
|
16034
|
+
var MemoryKindSchema = z23.enum(["fact", "preference", "entity"]);
|
|
16035
|
+
var MemoryBaseSchema = z23.object({
|
|
16036
|
+
id: z23.string().min(1),
|
|
13960
16037
|
ownerKey: OwnerKeySchema,
|
|
13961
|
-
confidence:
|
|
13962
|
-
validFrom:
|
|
13963
|
-
validUntil:
|
|
13964
|
-
createdAt:
|
|
13965
|
-
invalidatedAt:
|
|
13966
|
-
sourceHash:
|
|
13967
|
-
supersededBy:
|
|
16038
|
+
confidence: z23.number().min(0).max(1),
|
|
16039
|
+
validFrom: z23.number().finite(),
|
|
16040
|
+
validUntil: z23.number().finite().nullable().default(null),
|
|
16041
|
+
createdAt: z23.number().finite(),
|
|
16042
|
+
invalidatedAt: z23.number().finite().nullable().default(null),
|
|
16043
|
+
sourceHash: z23.string().min(1),
|
|
16044
|
+
supersededBy: z23.string().min(1).nullable().default(null)
|
|
13968
16045
|
}).strict();
|
|
13969
16046
|
var FactSchema = MemoryBaseSchema.extend({
|
|
13970
|
-
kind:
|
|
13971
|
-
subject:
|
|
13972
|
-
predicate:
|
|
13973
|
-
object:
|
|
13974
|
-
category:
|
|
16047
|
+
kind: z23.literal("fact"),
|
|
16048
|
+
subject: z23.string().min(1),
|
|
16049
|
+
predicate: z23.string().min(1),
|
|
16050
|
+
object: z23.string().min(1),
|
|
16051
|
+
category: z23.string().min(1).nullable().default(null)
|
|
13975
16052
|
});
|
|
13976
16053
|
var PreferenceSchema = MemoryBaseSchema.extend({
|
|
13977
|
-
kind:
|
|
13978
|
-
category:
|
|
13979
|
-
preference:
|
|
13980
|
-
context:
|
|
13981
|
-
lastAccessedAt:
|
|
13982
|
-
accessCount:
|
|
16054
|
+
kind: z23.literal("preference"),
|
|
16055
|
+
category: z23.string().min(1),
|
|
16056
|
+
preference: z23.string().min(1),
|
|
16057
|
+
context: z23.string().min(1).nullable().default(null),
|
|
16058
|
+
lastAccessedAt: z23.number().finite().nullable().default(null),
|
|
16059
|
+
accessCount: z23.number().int().min(0).default(0)
|
|
13983
16060
|
});
|
|
13984
16061
|
var EntitySchema = MemoryBaseSchema.extend({
|
|
13985
|
-
kind:
|
|
13986
|
-
canonicalName:
|
|
13987
|
-
type:
|
|
13988
|
-
aliases:
|
|
16062
|
+
kind: z23.literal("entity"),
|
|
16063
|
+
canonicalName: z23.string().min(1),
|
|
16064
|
+
type: z23.string().min(1),
|
|
16065
|
+
aliases: z23.array(z23.string().min(1)).default([])
|
|
13989
16066
|
});
|
|
13990
16067
|
var RelationSchema = MemoryBaseSchema.extend({
|
|
13991
|
-
kind:
|
|
13992
|
-
from:
|
|
13993
|
-
to:
|
|
13994
|
-
predicate:
|
|
13995
|
-
annotation:
|
|
16068
|
+
kind: z23.literal("relation"),
|
|
16069
|
+
from: z23.string().min(1),
|
|
16070
|
+
to: z23.string().min(1),
|
|
16071
|
+
predicate: z23.string().min(1),
|
|
16072
|
+
annotation: z23.string().min(1).nullable().default(null)
|
|
13996
16073
|
});
|
|
13997
|
-
var MemoryRecordSchema =
|
|
16074
|
+
var MemoryRecordSchema = z23.discriminatedUnion("kind", [
|
|
13998
16075
|
FactSchema,
|
|
13999
16076
|
PreferenceSchema,
|
|
14000
16077
|
EntitySchema,
|
|
14001
16078
|
RelationSchema
|
|
14002
16079
|
]);
|
|
14003
|
-
var RecallQuerySchema =
|
|
16080
|
+
var RecallQuerySchema = z23.object({
|
|
14004
16081
|
ownerKey: OwnerKeySchema,
|
|
14005
|
-
kinds:
|
|
14006
|
-
asOf:
|
|
14007
|
-
limit:
|
|
14008
|
-
minSimilarity:
|
|
14009
|
-
includeShared:
|
|
16082
|
+
kinds: z23.array(MemoryKindSchema).default(["fact", "preference", "entity"]),
|
|
16083
|
+
asOf: z23.number().finite().nullable().default(null),
|
|
16084
|
+
limit: z23.number().int().positive().default(8),
|
|
16085
|
+
minSimilarity: z23.number().min(0).max(1).default(0.2),
|
|
16086
|
+
includeShared: z23.boolean().default(true)
|
|
14010
16087
|
}).strict();
|
|
14011
16088
|
|
|
14012
16089
|
// src/memory/rank.ts
|
|
@@ -14577,42 +16654,42 @@ function buildMemoryInjector(deps, policy) {
|
|
|
14577
16654
|
|
|
14578
16655
|
// src/plugin/memoryTool.ts
|
|
14579
16656
|
import { tool as tool3 } from "@opencode-ai/plugin";
|
|
14580
|
-
import { z as
|
|
16657
|
+
import { z as z25 } from "zod";
|
|
14581
16658
|
|
|
14582
16659
|
// src/memory/extract.ts
|
|
14583
|
-
import { z as
|
|
16660
|
+
import { z as z24 } from "zod";
|
|
14584
16661
|
var REDACTED = "[redacted]";
|
|
14585
|
-
var RawFactSchema =
|
|
14586
|
-
subject:
|
|
14587
|
-
predicate:
|
|
14588
|
-
object:
|
|
14589
|
-
category:
|
|
14590
|
-
confidence:
|
|
16662
|
+
var RawFactSchema = z24.object({
|
|
16663
|
+
subject: z24.string().min(1),
|
|
16664
|
+
predicate: z24.string().min(1),
|
|
16665
|
+
object: z24.string().min(1),
|
|
16666
|
+
category: z24.string().min(1).nullable().optional(),
|
|
16667
|
+
confidence: z24.number().min(0).max(1).optional()
|
|
14591
16668
|
});
|
|
14592
|
-
var RawPreferenceSchema =
|
|
14593
|
-
category:
|
|
14594
|
-
preference:
|
|
14595
|
-
context:
|
|
14596
|
-
confidence:
|
|
16669
|
+
var RawPreferenceSchema = z24.object({
|
|
16670
|
+
category: z24.string().min(1),
|
|
16671
|
+
preference: z24.string().min(1),
|
|
16672
|
+
context: z24.string().min(1).nullable().optional(),
|
|
16673
|
+
confidence: z24.number().min(0).max(1).optional()
|
|
14597
16674
|
});
|
|
14598
|
-
var RawEntitySchema =
|
|
14599
|
-
canonicalName:
|
|
14600
|
-
type:
|
|
14601
|
-
aliases:
|
|
14602
|
-
confidence:
|
|
16675
|
+
var RawEntitySchema = z24.object({
|
|
16676
|
+
canonicalName: z24.string().min(1),
|
|
16677
|
+
type: z24.string().min(1),
|
|
16678
|
+
aliases: z24.array(z24.string().min(1)).optional(),
|
|
16679
|
+
confidence: z24.number().min(0).max(1).optional()
|
|
14603
16680
|
});
|
|
14604
|
-
var RawRelationSchema =
|
|
14605
|
-
from:
|
|
14606
|
-
to:
|
|
14607
|
-
predicate:
|
|
14608
|
-
annotation:
|
|
14609
|
-
confidence:
|
|
16681
|
+
var RawRelationSchema = z24.object({
|
|
16682
|
+
from: z24.string().min(1),
|
|
16683
|
+
to: z24.string().min(1),
|
|
16684
|
+
predicate: z24.string().min(1),
|
|
16685
|
+
annotation: z24.string().min(1).nullable().optional(),
|
|
16686
|
+
confidence: z24.number().min(0).max(1).optional()
|
|
14610
16687
|
}).strict();
|
|
14611
|
-
var RawExtractionSchema =
|
|
14612
|
-
facts:
|
|
14613
|
-
preferences:
|
|
14614
|
-
entities:
|
|
14615
|
-
relations:
|
|
16688
|
+
var RawExtractionSchema = z24.object({
|
|
16689
|
+
facts: z24.array(RawFactSchema).default([]),
|
|
16690
|
+
preferences: z24.array(RawPreferenceSchema).default([]),
|
|
16691
|
+
entities: z24.array(RawEntitySchema).default([]),
|
|
16692
|
+
relations: z24.array(RawRelationSchema).default([])
|
|
14616
16693
|
});
|
|
14617
16694
|
var DEFAULT_CONFIDENCE = 0.6;
|
|
14618
16695
|
var SYSTEM_PROMPT = [
|
|
@@ -14866,13 +16943,13 @@ var memoryToolMessages = {
|
|
|
14866
16943
|
|
|
14867
16944
|
// src/plugin/memoryTool.ts
|
|
14868
16945
|
var SCRIBE_ROLE_ID = "scribe";
|
|
14869
|
-
var MemoryMessageSchema =
|
|
14870
|
-
role:
|
|
14871
|
-
content:
|
|
16946
|
+
var MemoryMessageSchema = z25.object({
|
|
16947
|
+
role: z25.enum(["system", "user", "assistant"]).describe(memoryToolMessages.messageRoleDescription),
|
|
16948
|
+
content: z25.string().min(1).describe(memoryToolMessages.messageContentDescription)
|
|
14872
16949
|
}).strict();
|
|
14873
|
-
var MemoryWritePayloadSchema =
|
|
14874
|
-
messages:
|
|
14875
|
-
roleID:
|
|
16950
|
+
var MemoryWritePayloadSchema = z25.object({
|
|
16951
|
+
messages: z25.array(MemoryMessageSchema).min(1).describe(memoryToolMessages.messagesDescription),
|
|
16952
|
+
roleID: z25.string().min(1).default(SCRIBE_ROLE_ID).describe(memoryToolMessages.roleIDDescription)
|
|
14876
16953
|
}).strict();
|
|
14877
16954
|
function createMemoryTool(deps) {
|
|
14878
16955
|
return tool3({
|
|
@@ -14997,10 +17074,10 @@ function createOrchestratedModelOwnership() {
|
|
|
14997
17074
|
|
|
14998
17075
|
// src/plugin/orchestrateTool.ts
|
|
14999
17076
|
import { tool as tool4 } from "@opencode-ai/plugin";
|
|
15000
|
-
import { z as
|
|
17077
|
+
import { z as z27 } from "zod";
|
|
15001
17078
|
|
|
15002
17079
|
// src/orchestrator/coordinator.ts
|
|
15003
|
-
import { z as
|
|
17080
|
+
import { z as z26 } from "zod";
|
|
15004
17081
|
|
|
15005
17082
|
// src/orchestrator/nodeIteration.ts
|
|
15006
17083
|
var DEFAULT_MAX_RETRIES = 2;
|
|
@@ -15009,7 +17086,7 @@ function nodePassBudget(maxRetries) {
|
|
|
15009
17086
|
}
|
|
15010
17087
|
|
|
15011
17088
|
// src/orchestrator/outputContract.ts
|
|
15012
|
-
import { createHash as
|
|
17089
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
15013
17090
|
var ROLE_REPORTS_ROOT = ".opencode/openteam-local/reports";
|
|
15014
17091
|
var REPORT_STATUS_MARKER = "openteam-status";
|
|
15015
17092
|
var REPORT_STATUS_LINE_PATTERN = /^[ ]{0,3}openteam-status:[ \t]*(.*?)[ \t]*$/i;
|
|
@@ -15076,7 +17153,7 @@ var REPORT_SEGMENT_HASH_CHARS = 24;
|
|
|
15076
17153
|
var SAFE_REPORT_SEGMENT = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,62}[A-Za-z0-9_-])?$/;
|
|
15077
17154
|
var WINDOWS_DEVICE_NAME = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i;
|
|
15078
17155
|
function reportSegmentHash(value) {
|
|
15079
|
-
return
|
|
17156
|
+
return createHash3("sha256").update(value, "utf8").digest("hex").slice(0, REPORT_SEGMENT_HASH_CHARS);
|
|
15080
17157
|
}
|
|
15081
17158
|
function reportPathSegment(value) {
|
|
15082
17159
|
if (value.length <= MAX_REPORT_SEGMENT_CHARS && SAFE_REPORT_SEGMENT.test(value) && value === value.toLowerCase() && !WINDOWS_DEVICE_NAME.test(value)) {
|
|
@@ -15468,7 +17545,7 @@ function buildRecord(input, decision2, subsession, deps, decisionID, batchID) {
|
|
|
15468
17545
|
}
|
|
15469
17546
|
return record;
|
|
15470
17547
|
}
|
|
15471
|
-
var TelemetryFailureClassSchema =
|
|
17548
|
+
var TelemetryFailureClassSchema = z26.enum([
|
|
15472
17549
|
"create-rejected",
|
|
15473
17550
|
"create-no-id",
|
|
15474
17551
|
"prompt-rejected",
|
|
@@ -16284,7 +18361,7 @@ async function runRoleTasks(inputs, deps, options = {}) {
|
|
|
16284
18361
|
var _pluginWarnedRoles = new Set;
|
|
16285
18362
|
var EMPTY_ROLE_ID_SET = new Set;
|
|
16286
18363
|
var SAFE_ROLE_ID = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
16287
|
-
var RoleIDSchema =
|
|
18364
|
+
var RoleIDSchema = z27.string().min(1).superRefine((roleID, ctx) => {
|
|
16288
18365
|
if (!SAFE_ROLE_ID.test(roleID)) {
|
|
16289
18366
|
ctx.addIssue({
|
|
16290
18367
|
code: "custom",
|
|
@@ -16292,16 +18369,16 @@ var RoleIDSchema = z26.string().min(1).superRefine((roleID, ctx) => {
|
|
|
16292
18369
|
});
|
|
16293
18370
|
}
|
|
16294
18371
|
});
|
|
16295
|
-
var RoleAssignmentSchema =
|
|
18372
|
+
var RoleAssignmentSchema = z27.object({
|
|
16296
18373
|
roleID: RoleIDSchema.describe("Role identifier from the roster"),
|
|
16297
|
-
prompt:
|
|
16298
|
-
title:
|
|
16299
|
-
dependsOn:
|
|
18374
|
+
prompt: z27.string().min(1).describe("Work prompt for this role"),
|
|
18375
|
+
title: z27.string().min(1).optional().describe("Human-readable title"),
|
|
18376
|
+
dependsOn: z27.array(RoleIDSchema).optional().describe("Role IDs this assignment depends on (DAG edges)")
|
|
16300
18377
|
}).strict();
|
|
16301
|
-
var OrchestratePayloadSchema =
|
|
16302
|
-
assignments:
|
|
16303
|
-
parentSessionID:
|
|
16304
|
-
directory:
|
|
18378
|
+
var OrchestratePayloadSchema = z27.object({
|
|
18379
|
+
assignments: z27.array(RoleAssignmentSchema).min(1).describe("Role assignments to distribute"),
|
|
18380
|
+
parentSessionID: z27.string().min(1).optional().describe(PARENT_SESSION_DESCRIPTION),
|
|
18381
|
+
directory: z27.string().min(1).optional().describe("Working directory override")
|
|
16305
18382
|
}).strict();
|
|
16306
18383
|
function validateAssignmentDependencies(assignments) {
|
|
16307
18384
|
const ids = new Set;
|
|
@@ -16359,12 +18436,12 @@ function validateAssignmentDependencies(assignments) {
|
|
|
16359
18436
|
}
|
|
16360
18437
|
return;
|
|
16361
18438
|
}
|
|
16362
|
-
function
|
|
18439
|
+
function isRecord7(value) {
|
|
16363
18440
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16364
18441
|
}
|
|
16365
18442
|
function nestedRecord2(value, key) {
|
|
16366
18443
|
const nested = value[key];
|
|
16367
|
-
return
|
|
18444
|
+
return isRecord7(nested) ? nested : undefined;
|
|
16368
18445
|
}
|
|
16369
18446
|
function numberField(records, keys) {
|
|
16370
18447
|
for (const record of records) {
|
|
@@ -16437,7 +18514,7 @@ function retryableFailure(failureClass, statusCode, declared) {
|
|
|
16437
18514
|
return failureClass === "prompt-timeout" || failureClass === "prompt-rate-limited" || failureClass === "prompt-connection" || failureClass === "prompt-server" || statusCode !== undefined && statusCode >= 500 && statusCode <= 599;
|
|
16438
18515
|
}
|
|
16439
18516
|
function normalizeSdkSessionFailure(error, stage) {
|
|
16440
|
-
const root =
|
|
18517
|
+
const root = isRecord7(error) ? error : {};
|
|
16441
18518
|
const data = nestedRecord2(root, "data");
|
|
16442
18519
|
const nestedError = nestedRecord2(root, "error");
|
|
16443
18520
|
const records = [
|
|
@@ -16456,7 +18533,7 @@ function normalizeSdkSessionFailure(error, stage) {
|
|
|
16456
18533
|
};
|
|
16457
18534
|
}
|
|
16458
18535
|
function nestedAssistantFailure(data) {
|
|
16459
|
-
if (!
|
|
18536
|
+
if (!isRecord7(data)) {
|
|
16460
18537
|
return;
|
|
16461
18538
|
}
|
|
16462
18539
|
return nestedRecord2(data, "info")?.error;
|
|
@@ -16917,14 +18994,19 @@ function createOrchestrateTool(deps) {
|
|
|
16917
18994
|
title: tool4.schema.string().optional().describe("Human-readable title"),
|
|
16918
18995
|
dependsOn: tool4.schema.array(tool4.schema.string()).optional().describe("Role IDs this assignment depends on")
|
|
16919
18996
|
})).describe("Role assignments to distribute"),
|
|
16920
|
-
parentSessionID: tool4.schema.string().optional().describe(
|
|
18997
|
+
parentSessionID: tool4.schema.string().optional().describe(PARENT_SESSION_DESCRIPTION),
|
|
16921
18998
|
directory: tool4.schema.string().optional().describe("Working directory override")
|
|
16922
18999
|
},
|
|
16923
|
-
async execute(args) {
|
|
19000
|
+
async execute(args, context) {
|
|
16924
19001
|
const parsed = OrchestratePayloadSchema.safeParse(args);
|
|
16925
19002
|
if (!parsed.success) {
|
|
16926
19003
|
return `validation error: ${parsed.error.message}`;
|
|
16927
19004
|
}
|
|
19005
|
+
if (typeof context.sessionID !== "string" || !context.sessionID.trim()) {
|
|
19006
|
+
return HOST_SESSION_REQUIRED;
|
|
19007
|
+
}
|
|
19008
|
+
const parentOverrideIgnored = parsed.data.parentSessionID !== undefined && parsed.data.parentSessionID !== context.sessionID;
|
|
19009
|
+
parsed.data.parentSessionID = context.sessionID;
|
|
16928
19010
|
const depError = validateAssignmentDependencies(parsed.data.assignments);
|
|
16929
19011
|
if (depError !== undefined) {
|
|
16930
19012
|
return dependencyValidationError(depError.code, depError.detail);
|
|
@@ -16959,7 +19041,7 @@ function createOrchestrateTool(deps) {
|
|
|
16959
19041
|
taskID: batchID,
|
|
16960
19042
|
kind: "coordinator",
|
|
16961
19043
|
roleID: "openteam",
|
|
16962
|
-
agentID:
|
|
19044
|
+
agentID: context.agent,
|
|
16963
19045
|
...parsed.data.parentSessionID === undefined ? {} : { sessionID: parsed.data.parentSessionID }
|
|
16964
19046
|
}
|
|
16965
19047
|
});
|
|
@@ -16998,7 +19080,9 @@ function createOrchestrateTool(deps) {
|
|
|
16998
19080
|
lifecycleStatus = activeLifecycleRecorder?.status() ?? lifecycleStatus;
|
|
16999
19081
|
const projected = projectResults(batch.results, batch.cancelled);
|
|
17000
19082
|
const shadowResult = await runShadowProducer(deps, parsed.data, batch);
|
|
17001
|
-
const base = formatResult(projected)
|
|
19083
|
+
const base = formatResult(projected) + (parentOverrideIgnored ? `
|
|
19084
|
+
|
|
19085
|
+
${PARENT_OVERRIDE_IGNORED}` : "");
|
|
17002
19086
|
const advisory = singleAssignmentAdvisory(parsed.data.assignments.length, assignableRoleIDs(deps.config).length);
|
|
17003
19087
|
const withAdvisory = advisory === undefined ? base : `${base}
|
|
17004
19088
|
|
|
@@ -17030,7 +19114,7 @@ ${advisory}`;
|
|
|
17030
19114
|
|
|
17031
19115
|
// src/plugin/registerCastTool.ts
|
|
17032
19116
|
import { tool as tool5 } from "@opencode-ai/plugin";
|
|
17033
|
-
import { z as
|
|
19117
|
+
import { z as z28 } from "zod";
|
|
17034
19118
|
|
|
17035
19119
|
// src/orchestrator/rosterPersistence.ts
|
|
17036
19120
|
function rosterFence(roster) {
|
|
@@ -17065,13 +19149,13 @@ async function persistRosterPreservingProse(storage, roster, path4 = OPENTEAM_RO
|
|
|
17065
19149
|
}
|
|
17066
19150
|
|
|
17067
19151
|
// src/plugin/registerCastTool.ts
|
|
17068
|
-
var CastEntrySchema =
|
|
17069
|
-
roleID:
|
|
17070
|
-
agentName:
|
|
19152
|
+
var CastEntrySchema = z28.object({
|
|
19153
|
+
roleID: z28.string().min(1).describe("Stable role identifier, e.g. scribe or guardian"),
|
|
19154
|
+
agentName: z28.string().min(1).describe("Themed character name assigned to the role")
|
|
17071
19155
|
}).strict();
|
|
17072
|
-
var RegisterCastPayloadSchema =
|
|
17073
|
-
universe:
|
|
17074
|
-
entries:
|
|
19156
|
+
var RegisterCastPayloadSchema = z28.object({
|
|
19157
|
+
universe: z28.string().min(1).describe("Casting universe for this roster"),
|
|
19158
|
+
entries: z28.array(CastEntrySchema).min(1).describe("Role-to-name mappings")
|
|
17075
19159
|
}).strict();
|
|
17076
19160
|
function offendingFields(error) {
|
|
17077
19161
|
const fields = error.issues.flatMap((issue) => {
|
|
@@ -17361,7 +19445,7 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
|
|
|
17361
19445
|
}
|
|
17362
19446
|
|
|
17363
19447
|
// src/storage/lifecycle/fsLifecycleJournal.ts
|
|
17364
|
-
import { randomUUID as
|
|
19448
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
17365
19449
|
import {
|
|
17366
19450
|
lstatSync as lstatSync3,
|
|
17367
19451
|
mkdirSync as mkdirSync3,
|
|
@@ -17371,22 +19455,22 @@ import {
|
|
|
17371
19455
|
statSync,
|
|
17372
19456
|
unlinkSync as unlinkSync2
|
|
17373
19457
|
} from "node:fs";
|
|
17374
|
-
import { join as
|
|
19458
|
+
import { join as join13, resolve as resolve8 } from "node:path";
|
|
17375
19459
|
import { ZodError } from "zod";
|
|
17376
19460
|
|
|
17377
19461
|
// src/storage/lifecycle/codec.ts
|
|
17378
|
-
import { z as
|
|
19462
|
+
import { z as z29 } from "zod";
|
|
17379
19463
|
var LIFECYCLE_CODEC_VERSION = 1;
|
|
17380
19464
|
var LIFECYCLE_GENESIS_DIGEST = sha256Hex("openteam/lifecycle-journal/genesis/v1");
|
|
17381
19465
|
var NUL5 = "\x00";
|
|
17382
19466
|
var NEWLINE2 = `
|
|
17383
19467
|
`;
|
|
17384
|
-
var frameSchema =
|
|
17385
|
-
v:
|
|
17386
|
-
seq:
|
|
17387
|
-
prev:
|
|
17388
|
-
sum:
|
|
17389
|
-
event:
|
|
19468
|
+
var frameSchema = z29.object({
|
|
19469
|
+
v: z29.literal(LIFECYCLE_CODEC_VERSION),
|
|
19470
|
+
seq: z29.number().int().nonnegative(),
|
|
19471
|
+
prev: z29.string().min(1),
|
|
19472
|
+
sum: z29.string().min(1),
|
|
19473
|
+
event: z29.unknown()
|
|
17390
19474
|
}).strict();
|
|
17391
19475
|
function canonical2(value) {
|
|
17392
19476
|
if (Array.isArray(value)) {
|
|
@@ -17473,7 +19557,7 @@ function decodeLifecycleJournal(text) {
|
|
|
17473
19557
|
}
|
|
17474
19558
|
|
|
17475
19559
|
// src/storage/lifecycle/fsLifecycleSupport.ts
|
|
17476
|
-
import { randomUUID } from "node:crypto";
|
|
19560
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
17477
19561
|
import {
|
|
17478
19562
|
appendFileSync,
|
|
17479
19563
|
closeSync as closeSync2,
|
|
@@ -17490,7 +19574,7 @@ import {
|
|
|
17490
19574
|
unlinkSync,
|
|
17491
19575
|
writeSync as writeSync2
|
|
17492
19576
|
} from "node:fs";
|
|
17493
|
-
import { basename as
|
|
19577
|
+
import { basename as basename3, dirname as dirname5, join as join12, relative as relative3, resolve as resolve7 } from "node:path";
|
|
17494
19578
|
var SAFE_RUN_ID = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,126}[A-Za-z0-9])?$/u;
|
|
17495
19579
|
|
|
17496
19580
|
class LifecycleFsError extends Error {
|
|
@@ -17514,7 +19598,7 @@ function validateRunID(runID) {
|
|
|
17514
19598
|
}
|
|
17515
19599
|
function resolvedLifecycleRoot(root) {
|
|
17516
19600
|
try {
|
|
17517
|
-
const absolute =
|
|
19601
|
+
const absolute = resolve7(root);
|
|
17518
19602
|
mkdirSync2(absolute, { recursive: true });
|
|
17519
19603
|
const rootStat = lstatSync2(absolute);
|
|
17520
19604
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
|
|
@@ -17530,8 +19614,8 @@ function resolvedLifecycleRoot(root) {
|
|
|
17530
19614
|
}
|
|
17531
19615
|
function directRunPath(root, runID) {
|
|
17532
19616
|
validateRunID(runID);
|
|
17533
|
-
const path4 =
|
|
17534
|
-
if (
|
|
19617
|
+
const path4 = join12(root, runID);
|
|
19618
|
+
if (dirname5(path4) !== root || basename3(path4) !== runID) {
|
|
17535
19619
|
throw new LifecycleFsError("corrupt");
|
|
17536
19620
|
}
|
|
17537
19621
|
return path4;
|
|
@@ -17556,8 +19640,8 @@ function assertExistingSafeRun(root, runID) {
|
|
|
17556
19640
|
} catch {
|
|
17557
19641
|
throw new LifecycleFsError("unavailable");
|
|
17558
19642
|
}
|
|
17559
|
-
const child =
|
|
17560
|
-
if (child === "" || child.startsWith("..") ||
|
|
19643
|
+
const child = relative3(root, real);
|
|
19644
|
+
if (child === "" || child.startsWith("..") || resolve7(root, child) !== real || dirname5(real) !== root) {
|
|
17561
19645
|
throw new LifecycleFsError("corrupt");
|
|
17562
19646
|
}
|
|
17563
19647
|
return real;
|
|
@@ -17606,7 +19690,7 @@ function appendDurable2(path4, content) {
|
|
|
17606
19690
|
}
|
|
17607
19691
|
}
|
|
17608
19692
|
function writeDurableAtomically(path4, content) {
|
|
17609
|
-
const temporary =
|
|
19693
|
+
const temporary = join12(dirname5(path4), `.${basename3(path4)}.${randomUUID2()}.next`);
|
|
17610
19694
|
try {
|
|
17611
19695
|
writeDurable2(temporary, content);
|
|
17612
19696
|
renameSync(temporary, path4);
|
|
@@ -17628,8 +19712,8 @@ function readLockContents(path4) {
|
|
|
17628
19712
|
}
|
|
17629
19713
|
}
|
|
17630
19714
|
function withRunMutationLock(runDir, mutate) {
|
|
17631
|
-
const lockPath =
|
|
17632
|
-
const lockToken =
|
|
19715
|
+
const lockPath = join12(runDir, ".mutation-lock");
|
|
19716
|
+
const lockToken = randomUUID2();
|
|
17633
19717
|
let descriptor;
|
|
17634
19718
|
try {
|
|
17635
19719
|
descriptor = openSync2(lockPath, "wx");
|
|
@@ -17698,7 +19782,7 @@ function parseJson(text, parse2) {
|
|
|
17698
19782
|
}
|
|
17699
19783
|
}
|
|
17700
19784
|
function issueWriterToken() {
|
|
17701
|
-
return
|
|
19785
|
+
return randomUUID3().replaceAll("-", "");
|
|
17702
19786
|
}
|
|
17703
19787
|
function createLease(runID, writerToken, input) {
|
|
17704
19788
|
return parseLifecycleWriterLease({
|
|
@@ -17713,12 +19797,12 @@ function createLease(runID, writerToken, input) {
|
|
|
17713
19797
|
});
|
|
17714
19798
|
}
|
|
17715
19799
|
function readLease2(runDir) {
|
|
17716
|
-
const text = readUtf8(
|
|
19800
|
+
const text = readUtf8(join13(runDir, OWNER_FILE2));
|
|
17717
19801
|
return text === undefined ? undefined : parseJson(text, parseLifecycleWriterLease);
|
|
17718
19802
|
}
|
|
17719
19803
|
function readRun(runDir, runID) {
|
|
17720
|
-
const metadataPath =
|
|
17721
|
-
const eventsPath =
|
|
19804
|
+
const metadataPath = join13(runDir, METADATA_FILE);
|
|
19805
|
+
const eventsPath = join13(runDir, EVENTS_FILE);
|
|
17722
19806
|
assertSafeRegularFile(metadataPath);
|
|
17723
19807
|
assertSafeRegularFile(eventsPath);
|
|
17724
19808
|
const metadataText = readUtf8(metadataPath);
|
|
@@ -17765,7 +19849,7 @@ function summaryForRun(runDir, runID) {
|
|
|
17765
19849
|
}
|
|
17766
19850
|
function runBytes(runDir) {
|
|
17767
19851
|
return readdirSync2(runDir).reduce((total, entry) => {
|
|
17768
|
-
const path4 =
|
|
19852
|
+
const path4 = join13(runDir, entry);
|
|
17769
19853
|
const stats = lstatSync3(path4);
|
|
17770
19854
|
if (!stats.isFile() || stats.isSymbolicLink()) {
|
|
17771
19855
|
throw new LifecycleFsError("corrupt");
|
|
@@ -17797,7 +19881,7 @@ function canDeleteTerminalRun(runDir, runID, now) {
|
|
|
17797
19881
|
return now >= lease.expiresAt;
|
|
17798
19882
|
}
|
|
17799
19883
|
var createFsLifecycleJournal = (options) => {
|
|
17800
|
-
const configuredRoot =
|
|
19884
|
+
const configuredRoot = resolve8(options.root);
|
|
17801
19885
|
const now = options.now ?? Date.now;
|
|
17802
19886
|
const mutateRun = options.withMutationLock ?? withRunMutationLock;
|
|
17803
19887
|
return {
|
|
@@ -17819,7 +19903,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
17819
19903
|
throw error;
|
|
17820
19904
|
}
|
|
17821
19905
|
}
|
|
17822
|
-
stagingPath =
|
|
19906
|
+
stagingPath = join13(root, `.start-${runID}-${randomUUID3()}`);
|
|
17823
19907
|
mkdirSync3(stagingPath);
|
|
17824
19908
|
const writerToken = issueWriterToken();
|
|
17825
19909
|
const eventAt = now();
|
|
@@ -17839,10 +19923,10 @@ var createFsLifecycleJournal = (options) => {
|
|
|
17839
19923
|
executionAuthority: parsedInput.executionAuthority,
|
|
17840
19924
|
root: parsedInput.root
|
|
17841
19925
|
});
|
|
17842
|
-
writeDurable2(
|
|
19926
|
+
writeDurable2(join13(stagingPath, METADATA_FILE), `${JSON.stringify(metadata)}
|
|
17843
19927
|
`);
|
|
17844
|
-
writeDurable2(
|
|
17845
|
-
writeDurable2(
|
|
19928
|
+
writeDurable2(join13(stagingPath, EVENTS_FILE), encodeLifecycleJournal([event]));
|
|
19929
|
+
writeDurable2(join13(stagingPath, OWNER_FILE2), `${JSON.stringify(lease)}
|
|
17846
19930
|
`);
|
|
17847
19931
|
try {
|
|
17848
19932
|
renameSync2(stagingPath, runPath);
|
|
@@ -17884,7 +19968,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
17884
19968
|
}
|
|
17885
19969
|
const writerToken = issueWriterToken();
|
|
17886
19970
|
const lease = createLease(runID, writerToken, parsedLeaseInput);
|
|
17887
|
-
writeDurableAtomically(
|
|
19971
|
+
writeDurableAtomically(join13(runDir, OWNER_FILE2), `${JSON.stringify(lease)}
|
|
17888
19972
|
`);
|
|
17889
19973
|
return ok({ runID, writerToken });
|
|
17890
19974
|
});
|
|
@@ -17941,7 +20025,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
17941
20025
|
...parsedBody
|
|
17942
20026
|
});
|
|
17943
20027
|
const frame = encodeLifecycleFrame(loaded.decoded.digest, committedEvent);
|
|
17944
|
-
appendDurable2(
|
|
20028
|
+
appendDurable2(join13(runDir, EVENTS_FILE), `${frame.line}
|
|
17945
20029
|
`);
|
|
17946
20030
|
return ok({ event: committedEvent, head: actualHead + 1 });
|
|
17947
20031
|
});
|
|
@@ -17971,7 +20055,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
17971
20055
|
heartbeatAt: parsed.now,
|
|
17972
20056
|
expiresAt: parsed.now + parsed.leaseDurationMs
|
|
17973
20057
|
});
|
|
17974
|
-
writeDurableAtomically(
|
|
20058
|
+
writeDurableAtomically(join13(runDir, OWNER_FILE2), `${JSON.stringify(lease)}
|
|
17975
20059
|
`);
|
|
17976
20060
|
return ok({ lease });
|
|
17977
20061
|
});
|
|
@@ -17991,7 +20075,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
17991
20075
|
runID: handle.runID
|
|
17992
20076
|
}));
|
|
17993
20077
|
}
|
|
17994
|
-
unlinkSync2(
|
|
20078
|
+
unlinkSync2(join13(runDir, OWNER_FILE2));
|
|
17995
20079
|
return ok(undefined);
|
|
17996
20080
|
});
|
|
17997
20081
|
} catch (error) {
|
|
@@ -18102,14 +20186,14 @@ var createFsLifecycleJournal = (options) => {
|
|
|
18102
20186
|
};
|
|
18103
20187
|
|
|
18104
20188
|
// src/storage/lifecycle/fsLifecycleWriterLivenessProbe.ts
|
|
18105
|
-
import { join as
|
|
20189
|
+
import { join as join14 } from "node:path";
|
|
18106
20190
|
var createFsLifecycleWriterLivenessProbe = (options) => ({
|
|
18107
20191
|
async observe(runID) {
|
|
18108
20192
|
const observedAt = options.now();
|
|
18109
20193
|
try {
|
|
18110
20194
|
const root = resolvedLifecycleRoot(options.root);
|
|
18111
20195
|
const runDir = assertExistingSafeRun(root, runID);
|
|
18112
|
-
const ownerText = readUtf8(
|
|
20196
|
+
const ownerText = readUtf8(join14(runDir, "owner"));
|
|
18113
20197
|
if (ownerText === undefined) {
|
|
18114
20198
|
return { kind: "absent", observedAt };
|
|
18115
20199
|
}
|
|
@@ -18196,111 +20280,6 @@ var createOtlpSpanExporter = (connection, config) => {
|
|
|
18196
20280
|
}
|
|
18197
20281
|
};
|
|
18198
20282
|
};
|
|
18199
|
-
// package.json
|
|
18200
|
-
var package_default = {
|
|
18201
|
-
name: "@jmanuelcorral/openteam",
|
|
18202
|
-
version: "0.20.0",
|
|
18203
|
-
packageManager: "bun@1.3.14",
|
|
18204
|
-
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
18205
|
-
license: "MIT",
|
|
18206
|
-
author: "Jose Manuel Corral",
|
|
18207
|
-
repository: {
|
|
18208
|
-
type: "git",
|
|
18209
|
-
url: "git+https://github.com/jmanuelcorral/openteam.git"
|
|
18210
|
-
},
|
|
18211
|
-
homepage: "https://github.com/jmanuelcorral/openteam#readme",
|
|
18212
|
-
bugs: {
|
|
18213
|
-
url: "https://github.com/jmanuelcorral/openteam/issues"
|
|
18214
|
-
},
|
|
18215
|
-
keywords: [
|
|
18216
|
-
"opencode",
|
|
18217
|
-
"opencode-plugin",
|
|
18218
|
-
"llm",
|
|
18219
|
-
"routing",
|
|
18220
|
-
"local-llm",
|
|
18221
|
-
"ollama",
|
|
18222
|
-
"lm-studio",
|
|
18223
|
-
"foundry-local",
|
|
18224
|
-
"cost-optimization",
|
|
18225
|
-
"multi-agent"
|
|
18226
|
-
],
|
|
18227
|
-
engines: {
|
|
18228
|
-
bun: ">=1.3",
|
|
18229
|
-
node: "^22.22.2 || ^24.15.0 || >=26.0.0"
|
|
18230
|
-
},
|
|
18231
|
-
type: "module",
|
|
18232
|
-
main: "./dist/index.js",
|
|
18233
|
-
module: "./dist/index.js",
|
|
18234
|
-
types: "./dist/index.d.ts",
|
|
18235
|
-
bin: {
|
|
18236
|
-
openteam: "./dist/cli.js"
|
|
18237
|
-
},
|
|
18238
|
-
exports: {
|
|
18239
|
-
".": {
|
|
18240
|
-
types: "./dist/index.d.ts",
|
|
18241
|
-
import: "./dist/index.js"
|
|
18242
|
-
},
|
|
18243
|
-
"./package.json": "./package.json"
|
|
18244
|
-
},
|
|
18245
|
-
files: [
|
|
18246
|
-
"dist",
|
|
18247
|
-
"README.md",
|
|
18248
|
-
"LICENSE",
|
|
18249
|
-
"AGENTS.md",
|
|
18250
|
-
".opencode/openteam.example.json",
|
|
18251
|
-
".opencode/command/openteam.md"
|
|
18252
|
-
],
|
|
18253
|
-
publishConfig: {
|
|
18254
|
-
access: "public",
|
|
18255
|
-
registry: "https://registry.npmjs.org/"
|
|
18256
|
-
},
|
|
18257
|
-
trustedDependencies: [],
|
|
18258
|
-
sideEffects: false,
|
|
18259
|
-
scripts: {
|
|
18260
|
-
prebuild: "bun run clean",
|
|
18261
|
-
build: "bun run build:js && bun run build:cli && bun run build:types && bun run build:certificates",
|
|
18262
|
-
"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",
|
|
18263
|
-
"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',
|
|
18264
|
-
"build:types": "tsc -p tsconfig.build.json",
|
|
18265
|
-
clean: `node -e "require('node:fs').rmSync('dist', { recursive: true, force: true })"`,
|
|
18266
|
-
test: "bun test",
|
|
18267
|
-
"test:cov": "bun test --coverage",
|
|
18268
|
-
"certify:shadow": "bun run scripts/certify-artifact.ts shadow",
|
|
18269
|
-
"certify:release": "bun run scripts/certify-artifact.ts release",
|
|
18270
|
-
"build:certificates": "bun run certify:shadow && bun run certify:release && bun run scripts/bundle-certificates.ts",
|
|
18271
|
-
"coverage:check": "node scripts/check-coverage.mjs",
|
|
18272
|
-
typecheck: "tsc --noEmit",
|
|
18273
|
-
lint: "biome check .",
|
|
18274
|
-
"format:check": "biome format .",
|
|
18275
|
-
"docs:install": "cd docs && bun install --frozen-lockfile --ignore-scripts",
|
|
18276
|
-
"docs:dev": "cd docs && bun run docs:dev",
|
|
18277
|
-
"docs:build": "cd docs && bun run docs:build",
|
|
18278
|
-
"docs:preview": "cd docs && bun run docs:preview",
|
|
18279
|
-
prepublishOnly: "bun run build",
|
|
18280
|
-
"link:local": "bun run build && npm link",
|
|
18281
|
-
"hooks:install": "git config core.hooksPath .githooks"
|
|
18282
|
-
},
|
|
18283
|
-
dependencies: {
|
|
18284
|
-
"@clack/prompts": "1.7.0",
|
|
18285
|
-
"@langchain/core": "1.2.9",
|
|
18286
|
-
"@langchain/langgraph": "1.4.12",
|
|
18287
|
-
"@opencode-ai/plugin": "1.18.19",
|
|
18288
|
-
"@opencode-ai/sdk": "1.18.19",
|
|
18289
|
-
"@opentelemetry/api": "1.9.1",
|
|
18290
|
-
"@opentelemetry/exporter-trace-otlp-http": "0.221.0",
|
|
18291
|
-
"@opentelemetry/resources": "2.10.0",
|
|
18292
|
-
"@opentelemetry/sdk-trace-base": "2.10.0",
|
|
18293
|
-
zod: "4.4.3"
|
|
18294
|
-
},
|
|
18295
|
-
devDependencies: {
|
|
18296
|
-
"@biomejs/biome": "2.5.9",
|
|
18297
|
-
"@types/bun": "1.3.14",
|
|
18298
|
-
typescript: "7.0.2"
|
|
18299
|
-
}
|
|
18300
|
-
};
|
|
18301
|
-
|
|
18302
|
-
// src/version.ts
|
|
18303
|
-
var PACKAGE_VERSION = package_default.version;
|
|
18304
20283
|
|
|
18305
20284
|
// src/index.ts
|
|
18306
20285
|
var LIFECYCLE_WRITER_IDENTITY = {
|
|
@@ -18402,7 +20381,7 @@ var RELEASE_CERT_PATH = "artifacts/graph-release-certificate.json";
|
|
|
18402
20381
|
var SOAK_CERT_PATH = "artifacts/graph-soak-certificate.json";
|
|
18403
20382
|
async function readPackagedCertificate(path4) {
|
|
18404
20383
|
try {
|
|
18405
|
-
return await
|
|
20384
|
+
return await readFile4(new URL(`./certificates/${basename4(path4)}`, import.meta.url), "utf8");
|
|
18406
20385
|
} catch {
|
|
18407
20386
|
return;
|
|
18408
20387
|
}
|
|
@@ -18417,7 +20396,7 @@ async function readAndParseCertificate(storage, path4, parse2, digestExtractor,
|
|
|
18417
20396
|
const cert = parse2(raw);
|
|
18418
20397
|
return { status: "valid", digest: digestExtractor(cert) };
|
|
18419
20398
|
} catch (error) {
|
|
18420
|
-
if (
|
|
20399
|
+
if (isMissingFile2(error)) {
|
|
18421
20400
|
return { status: "absent" };
|
|
18422
20401
|
}
|
|
18423
20402
|
if (error instanceof ShadowCertificateError || error instanceof ReleaseCertificateError || error instanceof SoakCertificateError) {
|
|
@@ -18534,8 +20513,8 @@ async function readOpencodeVersion(serverUrl, options = {}) {
|
|
|
18534
20513
|
}
|
|
18535
20514
|
var DEFAULT_OPENCODE_VERSION_BACKOFF_MS = [50, 250];
|
|
18536
20515
|
function defaultSleep(ms) {
|
|
18537
|
-
return new Promise((
|
|
18538
|
-
setTimeout(
|
|
20516
|
+
return new Promise((resolve9) => {
|
|
20517
|
+
setTimeout(resolve9, ms);
|
|
18539
20518
|
});
|
|
18540
20519
|
}
|
|
18541
20520
|
function createLazyOpencodeVersionReader(serverUrl, options = {}) {
|
|
@@ -18663,7 +20642,7 @@ function createEventSink(rawOptions, storage = createFsStorageProvider(process.c
|
|
|
18663
20642
|
});
|
|
18664
20643
|
return sink;
|
|
18665
20644
|
}
|
|
18666
|
-
function
|
|
20645
|
+
function isMissingFile2(error) {
|
|
18667
20646
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
18668
20647
|
}
|
|
18669
20648
|
function configReadFailure(path4) {
|
|
@@ -18703,7 +20682,7 @@ async function readRoutingRosterEntries(storage) {
|
|
|
18703
20682
|
return content === undefined ? [] : parseRoster(content).entries;
|
|
18704
20683
|
}
|
|
18705
20684
|
var auditStoredRosterForDoctor = (roster, configuredRoles) => typeof roster === "string" ? auditRoster(roster, configuredRoles) : auditRoster(roster, configuredRoles);
|
|
18706
|
-
function createCliDeps(config, registry, telemetryPath, sessionsDir = DEFAULT_SESSIONS_DIR, storage = createFsStorageProvider(process.cwd()), fallbackSource = "options", rawOptions, resolveOpencodeVersion) {
|
|
20685
|
+
function createCliDeps(config, registry, telemetryPath, sessionsDir = DEFAULT_SESSIONS_DIR, storage = createFsStorageProvider(process.cwd()), fallbackSource = "options", rawOptions, resolveOpencodeVersion, workspaceRoot = process.cwd()) {
|
|
18707
20686
|
return {
|
|
18708
20687
|
loadConfig: async (path4, resolution = { explicit: false }) => {
|
|
18709
20688
|
const content = await readCliConfigFromStorage(storage, path4, resolution);
|
|
@@ -18786,12 +20765,13 @@ function createCliDeps(config, registry, telemetryPath, sessionsDir = DEFAULT_SE
|
|
|
18786
20765
|
telemetryPath,
|
|
18787
20766
|
opencodeConfigPaths: OPENCODE_CONFIG_CANDIDATES,
|
|
18788
20767
|
orchestratorAgentPath: ORCHESTRATOR_AGENT_PATH,
|
|
18789
|
-
agentDir:
|
|
20768
|
+
agentDir: dirname6(ORCHESTRATOR_AGENT_PATH),
|
|
18790
20769
|
cachePort: realCacheAdapter,
|
|
18791
20770
|
purge: createPluginPurgeRuntime(sessionsDir),
|
|
18792
20771
|
loadRosterForDoctor: () => readStoredRosterForDoctor(storage),
|
|
18793
20772
|
auditRoster: auditStoredRosterForDoctor,
|
|
18794
|
-
version: PACKAGE_VERSION
|
|
20773
|
+
version: PACKAGE_VERSION,
|
|
20774
|
+
upgradePort: createFsUpgradePort(workspaceRoot, globalThis.fetch)
|
|
18795
20775
|
};
|
|
18796
20776
|
}
|
|
18797
20777
|
function createPluginPurgeRuntime(sessionsDir) {
|
|
@@ -18916,7 +20896,7 @@ var server = async (ctx, rawOptions) => {
|
|
|
18916
20896
|
const cliDeps = createCliDeps(config, registry, telemetryPath, sessionsDir, storage, runtimeConfig.source, rawOptions, async () => {
|
|
18917
20897
|
const version = await getOpencodeVersion();
|
|
18918
20898
|
return version === "unknown" ? undefined : version;
|
|
18919
|
-
});
|
|
20899
|
+
}, workspaceRoot);
|
|
18920
20900
|
const toolcalls = createToolcallTracker({ sink });
|
|
18921
20901
|
const announcedSessions = new Set;
|
|
18922
20902
|
const announceEndpoint = (sessionID) => {
|
|
@@ -19058,8 +21038,8 @@ var server = async (ctx, rawOptions) => {
|
|
|
19058
21038
|
lifecycleRecorder,
|
|
19059
21039
|
abortGraceMs: DEFAULT_ABORT_GRACE_MS,
|
|
19060
21040
|
statusPollMs: DEFAULT_STATUS_POLL_MS,
|
|
19061
|
-
delay: (ms) => new Promise((
|
|
19062
|
-
setTimeout(
|
|
21041
|
+
delay: (ms) => new Promise((resolve9) => {
|
|
21042
|
+
setTimeout(resolve9, ms);
|
|
19063
21043
|
}),
|
|
19064
21044
|
warn: diagnostics.warn("unknown-role")
|
|
19065
21045
|
});
|
|
@@ -19129,7 +21109,7 @@ export {
|
|
|
19129
21109
|
logTelemetryError,
|
|
19130
21110
|
logOpencodeServerUrl,
|
|
19131
21111
|
logAvailabilityRefreshError,
|
|
19132
|
-
isMissingFile,
|
|
21112
|
+
isMissingFile2 as isMissingFile,
|
|
19133
21113
|
evaluateCutoverGateForBoundary,
|
|
19134
21114
|
src_default as default,
|
|
19135
21115
|
createOpencodeVersionReadFailureLogger,
|