@jmanuelcorral/openteam 0.21.0 → 0.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.es.md +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.d.ts.map +1 -1
- package/dist/cli.js +3801 -1022
- 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 +135 -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/pluginSpec.d.ts +43 -0
- package/dist/config/pluginSpec.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2819 -910
- 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/executionSetup.d.ts +48 -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/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/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 = [
|
|
@@ -5389,161 +5389,2045 @@ function createPurgeAdapter(root) {
|
|
|
5389
5389
|
};
|
|
5390
5390
|
}
|
|
5391
5391
|
|
|
5392
|
-
// src/
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
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.1",
|
|
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"
|
|
5405
5508
|
}
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
const
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
if (
|
|
5421
|
-
|
|
5422
|
-
code: "migration-pending",
|
|
5423
|
-
detail: "legacy migration has pending work — run the migration tool to completion before enabling active mode"
|
|
5424
|
-
});
|
|
5425
|
-
} else if (input.migration === "unknown") {
|
|
5426
|
-
violations.push({
|
|
5427
|
-
code: "migration-unknown",
|
|
5428
|
-
detail: "could not determine migration status — check ledger readability and storage access"
|
|
5429
|
-
});
|
|
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;
|
|
5430
5525
|
}
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
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;
|
|
5436
5531
|
}
|
|
5437
|
-
return
|
|
5438
|
-
allowed: violations.length === 0,
|
|
5439
|
-
violations,
|
|
5440
|
-
advisories
|
|
5441
|
-
};
|
|
5442
|
-
}
|
|
5443
|
-
function isGateApplicable(mode) {
|
|
5444
|
-
return mode === "active";
|
|
5532
|
+
return [major, minor, patch];
|
|
5445
5533
|
}
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
let i = 0;
|
|
5451
|
-
while (i < src.length) {
|
|
5452
|
-
const ch = src[i];
|
|
5453
|
-
if (ch === undefined)
|
|
5454
|
-
break;
|
|
5455
|
-
if (ch === '"') {
|
|
5456
|
-
out.push(ch);
|
|
5457
|
-
i++;
|
|
5458
|
-
while (i < src.length) {
|
|
5459
|
-
const c = src[i];
|
|
5460
|
-
if (c === undefined)
|
|
5461
|
-
break;
|
|
5462
|
-
out.push(c);
|
|
5463
|
-
i++;
|
|
5464
|
-
if (c === "\\") {
|
|
5465
|
-
const escaped = src[i];
|
|
5466
|
-
if (escaped !== undefined) {
|
|
5467
|
-
out.push(escaped);
|
|
5468
|
-
i++;
|
|
5469
|
-
}
|
|
5470
|
-
} else if (c === '"') {
|
|
5471
|
-
break;
|
|
5472
|
-
}
|
|
5473
|
-
}
|
|
5474
|
-
} else if (ch === "/" && i + 1 < src.length) {
|
|
5475
|
-
if (src[i + 1] === "/") {
|
|
5476
|
-
i += 2;
|
|
5477
|
-
while (i < src.length && src[i] !== `
|
|
5478
|
-
`) {
|
|
5479
|
-
i++;
|
|
5480
|
-
}
|
|
5481
|
-
} else if (src[i + 1] === "*") {
|
|
5482
|
-
i += 2;
|
|
5483
|
-
while (i < src.length && !(src[i] === "*" && src[i + 1] === "/")) {
|
|
5484
|
-
i++;
|
|
5485
|
-
}
|
|
5486
|
-
if (i < src.length) {
|
|
5487
|
-
i += 2;
|
|
5488
|
-
}
|
|
5489
|
-
} else {
|
|
5490
|
-
out.push(ch);
|
|
5491
|
-
i++;
|
|
5492
|
-
}
|
|
5493
|
-
} else {
|
|
5494
|
-
out.push(ch);
|
|
5495
|
-
i++;
|
|
5496
|
-
}
|
|
5534
|
+
function readStrictSemverParts(version) {
|
|
5535
|
+
const parsed = parseStrictSemverParts(version);
|
|
5536
|
+
if (parsed === undefined) {
|
|
5537
|
+
throw new Error(`invalid-strict-semver:${version}`);
|
|
5497
5538
|
}
|
|
5498
|
-
return
|
|
5539
|
+
return parsed;
|
|
5499
5540
|
}
|
|
5500
|
-
function
|
|
5501
|
-
return
|
|
5541
|
+
function isStrictSemver(v) {
|
|
5542
|
+
return parseStrictSemverParts(v) !== undefined;
|
|
5502
5543
|
}
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
if (isRecord3(baseVal) && isRecord3(value)) {
|
|
5512
|
-
result[key] = mergeOpencodeConfigs(baseVal, value);
|
|
5513
|
-
} else {
|
|
5514
|
-
result[key] = value;
|
|
5515
|
-
}
|
|
5516
|
-
}
|
|
5517
|
-
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;
|
|
5518
5552
|
}
|
|
5519
5553
|
|
|
5520
|
-
// src/
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
}
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
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
|
+
providerModelLimitInteger: (providerID, modelID, field) => `provider.${providerID}.models.${modelID}.limit.${field} must be ${field === "context" ? "a non-negative integer (0 means unknown)" : "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
|
+
unconfiguredOutput: "no limit.output (no explicit local output budget; opencode uses its model defaults)",
|
|
5806
|
+
unconfiguredContext: "no limit.context (no explicit usable context budget is configured)",
|
|
5807
|
+
missingOutput: "no limit.output (opencode rejects the provider model because output is required whenever limit is present)",
|
|
5808
|
+
missingContext: "no limit.context (opencode rejects the provider model because context is required whenever limit is present)",
|
|
5809
|
+
unknownContext: "limit.context is 0, so context is unknown and automatic compaction is disabled",
|
|
5810
|
+
invalidOutput: "invalid limit.output (expected a positive integer token count)",
|
|
5811
|
+
invalidContext: "invalid limit.context (expected a non-negative integer token count; 0 means unknown)",
|
|
5812
|
+
invalidInput: "invalid limit.input (expected a positive integer token count)",
|
|
5813
|
+
outputExceedsContext: "limit.output is greater than or equal to limit.context, so the configured context leaves no usable input window",
|
|
5814
|
+
outputExceedsInput: "limit.input is less than or equal to the reserved output budget, so compaction would have no usable input threshold",
|
|
5815
|
+
outputRemedy: " remedy: re-run `openteam setup` to write openteam's 8 192-token local output default, then re-run `openteam doctor`.",
|
|
5816
|
+
unconfiguredLimitRemedy: " remedy: the optional limit block may remain absent; to configure explicit limits, manually add a complete limit object in opencode.json with positive output and non-negative context (0 means unknown), because setup fills an absent limit block only for models the runtime currently discovers. Then re-run `openteam doctor`.",
|
|
5817
|
+
detectedContextRemedy: " remedy: re-run `openteam setup` while the runtime is reachable to copy the detected usable context budget, then re-run `openteam doctor`.",
|
|
5818
|
+
unknownContextRemedy: " remedy: re-run `openteam setup` to write the required context:0 sentinel; automatic compaction remains disabled until a positive context is configured.",
|
|
5819
|
+
zeroContextRemedy: " remedy: edit or remove limit.context and re-run `openteam setup` while the runtime advertises a positive context window to enable automatic compaction.",
|
|
5820
|
+
invalidLimitRemedy: " remedy: fix the invalid local limit values in opencode.json before relying on this provider configuration."
|
|
5821
|
+
}
|
|
5822
|
+
};
|
|
5823
|
+
var localModeChangeMessages = {
|
|
5824
|
+
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\`.`,
|
|
5825
|
+
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\`.`
|
|
5826
|
+
};
|
|
5827
|
+
|
|
5828
|
+
// src/messages/upgrade.ts
|
|
5829
|
+
var upgradeMessages = {
|
|
5830
|
+
header: "openteam upgrade:",
|
|
5831
|
+
help: {
|
|
5832
|
+
command: " openteam upgrade Update the openteam plugin pin to the latest published version",
|
|
5833
|
+
check: " openteam upgrade --check Show current/target versions without making changes",
|
|
5834
|
+
version: " openteam upgrade --version x.y.z Pin to a specific published version",
|
|
5835
|
+
usage: " openteam upgrade [--check] [--version x.y.z]"
|
|
5836
|
+
},
|
|
5837
|
+
usageLabel: "Usage:",
|
|
5838
|
+
invalidArguments: (detail) => ` ✗ ${detail}`,
|
|
5839
|
+
duplicateCheck: "Flag --check may be provided only once.",
|
|
5840
|
+
duplicateVersion: "Flag --version may be provided only once.",
|
|
5841
|
+
missingVersionValue: "Flag --version requires a plain x.y.z value.",
|
|
5842
|
+
unknownFlag: (flag) => `Unknown flag ${flag}.`,
|
|
5843
|
+
unexpectedArgument: (value) => `Unexpected argument ${value}.`,
|
|
5844
|
+
checkNeedsUpdate: (params) => ` ${params.path}: ${params.current !== null ? params.current : "(unpinned)"} → ${params.target}`,
|
|
5845
|
+
checkAlreadyCurrent: (params) => ` ${params.path}: already at ${params.version}`,
|
|
5846
|
+
checkHint: (version) => version === undefined ? " Run 'openteam upgrade' (without --check) to apply." : ` Run 'openteam upgrade --version ${version}' (without --check) to apply.`,
|
|
5847
|
+
alreadyCurrent: (version) => ` Already at ${version}; nothing to update.`,
|
|
5848
|
+
updatedHeader: (version) => ` ✓ Plugin pin updated to ${version} in:`,
|
|
5849
|
+
partialHeader: (version) => ` ⚠ Plugin pin updated to ${version} in:`,
|
|
5850
|
+
partialFailuresHeader: " The following file(s) were not changed:",
|
|
5851
|
+
nothingChanged: " ✗ No files were changed.",
|
|
5852
|
+
writtenEntry: (path) => ` ✓ ${path}`,
|
|
5853
|
+
failedEntry: (params) => ` ✗ ${params.path}: ${params.error}`,
|
|
5854
|
+
backupNote: (directory) => ` Backups of the previous file contents were saved under ${directory}.`,
|
|
5855
|
+
restartHint: " Restart opencode to load the new plugin version.",
|
|
5856
|
+
cacheCleanupHint: " Cache cleanup is optional; run 'openteam clear-cache --delete' if you want to remove stale cache entries.",
|
|
5857
|
+
resolveFailuresBeforeRestart: " Resolve the failed file(s) before restarting opencode.",
|
|
5858
|
+
rerunAfterFailures: " Resolve the failed file(s) and re-run the command; no restart is needed.",
|
|
5859
|
+
noConfigFound: (paths) => `No opencode config found (searched: ${paths.join(", ")}). Run 'openteam setup' first.`,
|
|
5860
|
+
noPluginEntry: "No openteam plugin entry found in opencode config. Run 'openteam setup' first.",
|
|
5861
|
+
localFileSkipped: (params) => ` ⚠ Skipped local openteam file entry in ${params.path}: ${params.spec} — local development installs are not managed by upgrade.`,
|
|
5862
|
+
localFileOnlyHeader: " Local openteam file plugin entries were found:",
|
|
5863
|
+
localFileOnlyEntry: (params) => ` ${params.path}: ${params.spec}`,
|
|
5864
|
+
localFileOnlyRemedy: ' Upgrade manages npm pins only. Keep the local development install, or replace the entry manually with "@jmanuelcorral/openteam@x.y.z".',
|
|
5865
|
+
invalidVersion: (v) => `Invalid version "${v}": must be a plain semver (e.g. 1.2.3) with no leading zeros, range operators, or dist-tags.`,
|
|
5866
|
+
versionNotFound: (v) => `Version ${v} was not found in the npm registry. Verify that the version is published.`,
|
|
5867
|
+
fetchError: (message) => `Failed to resolve version from the npm registry: ${message}`,
|
|
5868
|
+
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.`,
|
|
5869
|
+
portNotConfigured: "The upgrade port is not configured in this environment.",
|
|
5870
|
+
genericFetchFailed: "fetch failed",
|
|
5871
|
+
networkRequestFailed: "network request failed",
|
|
5872
|
+
networkRequestFailedWithDetail: (detail) => `network request failed: ${detail}`,
|
|
5873
|
+
requestTimedOut: (timeoutMs) => `request timed out after ${timeoutMs} ms`,
|
|
5874
|
+
responseReadFailed: "response body could not be read completely",
|
|
5875
|
+
responseTooLarge: (limitBytes) => `response body exceeded the ${limitBytes}-byte limit`,
|
|
5876
|
+
missingRegistryBody: "registry response body was empty",
|
|
5877
|
+
invalidRegistryJson: "invalid JSON in registry response",
|
|
5878
|
+
unterminatedBlockComment: "unterminated block comment",
|
|
5879
|
+
invalidRegistryPayload: 'unexpected registry response: expected a JSON object with string "name" and "version" fields',
|
|
5880
|
+
unexpectedVersionField: (raw) => `unexpected registry response: version field is ${raw}`,
|
|
5881
|
+
wrongPackageIdentity: (name) => `registry returned wrong package identity "${name}"`,
|
|
5882
|
+
unexpectedPublishedVersion: (params) => `registry returned version "${params.actual}" while verifying ${params.expected}`,
|
|
5883
|
+
httpStatus: (status) => `HTTP ${status}`,
|
|
5884
|
+
readConfigError: (path, message) => `Error reading ${path}: ${message}`,
|
|
5885
|
+
parseConfigError: (path, message) => `Cannot parse ${path} (malformed JSONC): ${message}`,
|
|
5886
|
+
configRootMustBeObject: (path, kind) => `Cannot parse ${path}: top-level value must be a JSON object (found ${kind}).`,
|
|
5887
|
+
pluginFieldMustBeArray: (path) => `Cannot parse ${path}: the top-level plugin field must be an array when present.`,
|
|
5888
|
+
pluginArrayEditUnavailable: (path) => `Cannot update ${path}: could not locate the top-level plugin array for a source-preserving edit.`,
|
|
5889
|
+
effectivePluginUpdateMismatch: (path) => `Cannot update ${path}: the source-preserving edit did not change the effective top-level plugin entry as expected.`,
|
|
5890
|
+
concurrentEdit: (path) => `${path} changed since it was read; refusing to overwrite it.`,
|
|
5891
|
+
writeTargetMissing: (path) => `${path} disappeared before it could be updated.`,
|
|
5892
|
+
unsafeFilesystemEntry: "expected a regular file inside the workspace; symlinks are not supported",
|
|
5893
|
+
backupLocationUnavailable: (path) => `Cannot update config: backup location ${path} is unavailable or unsafe.`,
|
|
5894
|
+
backupConflict: (path) => `Refusing to overwrite unexpected backup file ${path}.`,
|
|
5895
|
+
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.`,
|
|
5896
|
+
windowsDaclPrepFailed: (path, message) => `Cannot update ${path}: failed to apply file ACL to staging file before write: ${message}`,
|
|
5897
|
+
windowsReplaceFailed: (path, message) => `Cannot update ${path} while preserving Windows file ACLs: ${message}`
|
|
5898
|
+
};
|
|
5899
|
+
|
|
5900
|
+
// src/commands/upgrade.ts
|
|
5901
|
+
var NPM_ORIGIN = "https://registry.npmjs.org";
|
|
5902
|
+
var NPM_PACKAGE_PATH = "/@jmanuelcorral%2Fopenteam";
|
|
5903
|
+
var NPM_LATEST_URL = `${NPM_ORIGIN}${NPM_PACKAGE_PATH}/latest`;
|
|
5904
|
+
var FETCH_TIMEOUT_MS = 5000;
|
|
5905
|
+
var MAX_RESPONSE_BYTES = 64 * 1024;
|
|
5906
|
+
var MAX_FETCH_ATTEMPTS = 2;
|
|
5907
|
+
var PLUGIN_KEY = "plugin";
|
|
5908
|
+
var PRIVATE_DIRECTORY_MODE = 448;
|
|
5909
|
+
var PRIVATE_FILE_MODE = 384;
|
|
5910
|
+
var UPGRADE_BACKUP_GITIGNORE_CONTENT = `*
|
|
5911
|
+
`;
|
|
5912
|
+
var WINDOWS_POWERSHELL_EXE = join9(process.env.SystemRoot ?? "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
|
|
5913
|
+
var WINDOWS_PS_TIMEOUT_MS = 1e4;
|
|
5914
|
+
var UPGRADE_BACKUP_SUFFIX = ".openteam-upgrade.bak";
|
|
5915
|
+
var UPGRADE_BACKUP_DIRECTORY = ".opencode/openteam-local/upgrade-backups";
|
|
5916
|
+
function npmVersionUrl(version) {
|
|
5917
|
+
return `${NPM_ORIGIN}${NPM_PACKAGE_PATH}/${version}`;
|
|
5918
|
+
}
|
|
5919
|
+
var RegistryPackageIdentitySchema = z15.object({
|
|
5920
|
+
name: z15.string(),
|
|
5921
|
+
version: z15.string()
|
|
5922
|
+
}).strict();
|
|
5923
|
+
|
|
5924
|
+
class TransientFetchError extends Error {
|
|
5925
|
+
constructor(message) {
|
|
5926
|
+
super(message);
|
|
5927
|
+
this.name = "TransientFetchError";
|
|
5928
|
+
}
|
|
5929
|
+
}
|
|
5930
|
+
|
|
5931
|
+
class PermanentFetchError extends Error {
|
|
5932
|
+
constructor(message) {
|
|
5933
|
+
super(message);
|
|
5934
|
+
this.name = "PermanentFetchError";
|
|
5935
|
+
}
|
|
5936
|
+
}
|
|
5937
|
+
var GENERIC_FETCH_FAILURE_MESSAGES = new Set([
|
|
5938
|
+
upgradeMessages.genericFetchFailed,
|
|
5939
|
+
upgradeMessages.networkRequestFailed
|
|
5940
|
+
]);
|
|
5941
|
+
var execFileAsync2 = promisify2(execFile2);
|
|
5942
|
+
function isMissingFile(error) {
|
|
5943
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
5944
|
+
}
|
|
5945
|
+
function isAlreadyExistsFile(error) {
|
|
5946
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
5947
|
+
}
|
|
5948
|
+
function isRecord3(value) {
|
|
5949
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5950
|
+
}
|
|
5951
|
+
function isTuplePluginEntry(value) {
|
|
5952
|
+
return Array.isArray(value) && value.length >= 1 && typeof value[0] === "string";
|
|
5953
|
+
}
|
|
5954
|
+
function extractSpecString(entry) {
|
|
5955
|
+
if (typeof entry === "string") {
|
|
5956
|
+
return entry;
|
|
5957
|
+
}
|
|
5958
|
+
if (isTuplePluginEntry(entry)) {
|
|
5959
|
+
return entry[0];
|
|
5960
|
+
}
|
|
5961
|
+
return;
|
|
5962
|
+
}
|
|
5963
|
+
function isLocalFileSpec(spec) {
|
|
5964
|
+
const lower = spec.toLowerCase();
|
|
5965
|
+
return lower.startsWith("file:") || spec.startsWith("./") || spec.startsWith(".\\") || spec.startsWith("../") || spec.startsWith("..\\") || spec.startsWith("/") || spec.startsWith("\\") || win32.isAbsolute(spec);
|
|
5966
|
+
}
|
|
5967
|
+
function isOurSpec(spec) {
|
|
5968
|
+
return spec === OPENTEAM_PACKAGE_NAME || spec.startsWith(`${OPENTEAM_PACKAGE_NAME}@`);
|
|
5969
|
+
}
|
|
5970
|
+
function currentPinnedVersion(spec) {
|
|
5971
|
+
if (spec === OPENTEAM_PACKAGE_NAME) {
|
|
5972
|
+
return null;
|
|
5973
|
+
}
|
|
5974
|
+
const version = spec.slice(`${OPENTEAM_PACKAGE_NAME}@`.length);
|
|
5975
|
+
return version.length > 0 ? version : null;
|
|
5976
|
+
}
|
|
5977
|
+
function describeJsonRootKind(value) {
|
|
5978
|
+
if (value === null) {
|
|
5979
|
+
return "null";
|
|
5980
|
+
}
|
|
5981
|
+
if (Array.isArray(value)) {
|
|
5982
|
+
return "array";
|
|
5983
|
+
}
|
|
5984
|
+
switch (typeof value) {
|
|
5985
|
+
case "boolean":
|
|
5986
|
+
return "boolean";
|
|
5987
|
+
case "number":
|
|
5988
|
+
return "number";
|
|
5989
|
+
default:
|
|
5990
|
+
return "string";
|
|
5991
|
+
}
|
|
5992
|
+
}
|
|
5993
|
+
function findBlockCommentEnd(src, start, limit = src.length) {
|
|
5994
|
+
let i = start + 2;
|
|
5995
|
+
while (i < limit && !(src[i] === "*" && src[i + 1] === "/")) {
|
|
5996
|
+
i += 1;
|
|
5997
|
+
}
|
|
5998
|
+
return i < limit ? i + 2 : undefined;
|
|
5999
|
+
}
|
|
6000
|
+
function skipTrivia(src, start, limit = src.length) {
|
|
6001
|
+
let i = start;
|
|
6002
|
+
while (i < limit) {
|
|
6003
|
+
const ch = src[i];
|
|
6004
|
+
if (ch === undefined) {
|
|
6005
|
+
break;
|
|
6006
|
+
}
|
|
6007
|
+
if (/\s/u.test(ch)) {
|
|
6008
|
+
i += 1;
|
|
6009
|
+
continue;
|
|
6010
|
+
}
|
|
6011
|
+
if (ch === "/" && src[i + 1] === "/") {
|
|
6012
|
+
i += 2;
|
|
6013
|
+
while (i < limit && src[i] !== `
|
|
6014
|
+
`) {
|
|
6015
|
+
i += 1;
|
|
6016
|
+
}
|
|
6017
|
+
continue;
|
|
6018
|
+
}
|
|
6019
|
+
if (ch === "/" && src[i + 1] === "*") {
|
|
6020
|
+
const blockCommentEnd = findBlockCommentEnd(src, i, limit);
|
|
6021
|
+
if (blockCommentEnd === undefined) {
|
|
6022
|
+
return limit;
|
|
6023
|
+
}
|
|
6024
|
+
i = blockCommentEnd;
|
|
6025
|
+
continue;
|
|
6026
|
+
}
|
|
6027
|
+
break;
|
|
6028
|
+
}
|
|
6029
|
+
return i;
|
|
6030
|
+
}
|
|
6031
|
+
function readStringToken(src, start, limit = src.length) {
|
|
6032
|
+
if (src[start] !== '"') {
|
|
6033
|
+
return;
|
|
6034
|
+
}
|
|
6035
|
+
let i = start + 1;
|
|
6036
|
+
while (i < limit) {
|
|
6037
|
+
const ch = src[i];
|
|
6038
|
+
if (ch === undefined) {
|
|
6039
|
+
return;
|
|
6040
|
+
}
|
|
6041
|
+
if (ch === "\\") {
|
|
6042
|
+
i += 2;
|
|
6043
|
+
continue;
|
|
6044
|
+
}
|
|
6045
|
+
if (ch === '"') {
|
|
6046
|
+
return { end: i + 1 };
|
|
6047
|
+
}
|
|
6048
|
+
i += 1;
|
|
6049
|
+
}
|
|
6050
|
+
return;
|
|
6051
|
+
}
|
|
6052
|
+
function normalizeJsoncForParse(src) {
|
|
6053
|
+
const out = [];
|
|
6054
|
+
let i = 0;
|
|
6055
|
+
while (i < src.length) {
|
|
6056
|
+
const ch = src[i];
|
|
6057
|
+
if (ch === undefined) {
|
|
6058
|
+
break;
|
|
6059
|
+
}
|
|
6060
|
+
if (ch === '"') {
|
|
6061
|
+
const token = readStringToken(src, i);
|
|
6062
|
+
if (token === undefined) {
|
|
6063
|
+
out.push(ch);
|
|
6064
|
+
i += 1;
|
|
6065
|
+
continue;
|
|
6066
|
+
}
|
|
6067
|
+
out.push(src.slice(i, token.end));
|
|
6068
|
+
i = token.end;
|
|
6069
|
+
continue;
|
|
6070
|
+
}
|
|
6071
|
+
if (ch === "/" && src[i + 1] === "/") {
|
|
6072
|
+
i = skipTrivia(src, i);
|
|
6073
|
+
continue;
|
|
6074
|
+
}
|
|
6075
|
+
if (ch === "/" && src[i + 1] === "*") {
|
|
6076
|
+
const blockCommentEnd = findBlockCommentEnd(src, i);
|
|
6077
|
+
if (blockCommentEnd === undefined) {
|
|
6078
|
+
throw new Error(upgradeMessages.unterminatedBlockComment);
|
|
6079
|
+
}
|
|
6080
|
+
i = blockCommentEnd;
|
|
6081
|
+
continue;
|
|
6082
|
+
}
|
|
6083
|
+
if (ch === ",") {
|
|
6084
|
+
const next = skipTrivia(src, i + 1);
|
|
6085
|
+
const nextChar = src[next];
|
|
6086
|
+
if (nextChar === "]" || nextChar === "}") {
|
|
6087
|
+
i += 1;
|
|
6088
|
+
continue;
|
|
6089
|
+
}
|
|
6090
|
+
}
|
|
6091
|
+
out.push(ch);
|
|
6092
|
+
i += 1;
|
|
6093
|
+
}
|
|
6094
|
+
return out.join("");
|
|
6095
|
+
}
|
|
6096
|
+
function parseConfigDocument(path, content) {
|
|
6097
|
+
let parsed;
|
|
6098
|
+
try {
|
|
6099
|
+
const normalized = normalizeJsoncForParse(content);
|
|
6100
|
+
parsed = JSON.parse(normalized);
|
|
6101
|
+
} catch (error) {
|
|
6102
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6103
|
+
return { ok: false, error: upgradeMessages.parseConfigError(path, message) };
|
|
6104
|
+
}
|
|
6105
|
+
if (!isRecord3(parsed)) {
|
|
6106
|
+
return {
|
|
6107
|
+
ok: false,
|
|
6108
|
+
error: upgradeMessages.configRootMustBeObject(path, describeJsonRootKind(parsed))
|
|
6109
|
+
};
|
|
6110
|
+
}
|
|
6111
|
+
return { ok: true, value: parsed };
|
|
6112
|
+
}
|
|
6113
|
+
function readJsoncValueEnd(src, start, limit) {
|
|
6114
|
+
const ch = src[start];
|
|
6115
|
+
if (ch === undefined) {
|
|
6116
|
+
return;
|
|
6117
|
+
}
|
|
6118
|
+
if (ch === '"') {
|
|
6119
|
+
return readStringToken(src, start, limit)?.end;
|
|
6120
|
+
}
|
|
6121
|
+
if (ch === "{" || ch === "[") {
|
|
6122
|
+
const stack = [];
|
|
6123
|
+
let i2 = start;
|
|
6124
|
+
while (i2 < limit) {
|
|
6125
|
+
const next = skipTrivia(src, i2, limit);
|
|
6126
|
+
i2 = next;
|
|
6127
|
+
const current = src[i2];
|
|
6128
|
+
if (current === undefined) {
|
|
6129
|
+
return;
|
|
6130
|
+
}
|
|
6131
|
+
if (current === '"') {
|
|
6132
|
+
const token = readStringToken(src, i2, limit);
|
|
6133
|
+
if (token === undefined) {
|
|
6134
|
+
return;
|
|
6135
|
+
}
|
|
6136
|
+
i2 = token.end;
|
|
6137
|
+
continue;
|
|
6138
|
+
}
|
|
6139
|
+
if (current === "{" || current === "[") {
|
|
6140
|
+
stack.push(current);
|
|
6141
|
+
i2 += 1;
|
|
6142
|
+
continue;
|
|
6143
|
+
}
|
|
6144
|
+
if (current === "}" || current === "]") {
|
|
6145
|
+
const open2 = stack[stack.length - 1];
|
|
6146
|
+
if (current === "}" && open2 !== "{" || current === "]" && open2 !== "[") {
|
|
6147
|
+
return;
|
|
6148
|
+
}
|
|
6149
|
+
stack.pop();
|
|
6150
|
+
i2 += 1;
|
|
6151
|
+
if (stack.length === 0) {
|
|
6152
|
+
return i2;
|
|
6153
|
+
}
|
|
6154
|
+
continue;
|
|
6155
|
+
}
|
|
6156
|
+
i2 += 1;
|
|
6157
|
+
}
|
|
6158
|
+
return;
|
|
6159
|
+
}
|
|
6160
|
+
let i = start;
|
|
6161
|
+
while (i < limit) {
|
|
6162
|
+
const current = src[i];
|
|
6163
|
+
if (current === undefined) {
|
|
6164
|
+
break;
|
|
6165
|
+
}
|
|
6166
|
+
if (/\s/u.test(current) || current === "," || current === "]" || current === "}" || current === "/" && (src[i + 1] === "/" || src[i + 1] === "*")) {
|
|
6167
|
+
break;
|
|
6168
|
+
}
|
|
6169
|
+
i += 1;
|
|
6170
|
+
}
|
|
6171
|
+
return i > start ? i : undefined;
|
|
6172
|
+
}
|
|
6173
|
+
function findTopLevelPluginArray(raw) {
|
|
6174
|
+
let found;
|
|
6175
|
+
let i = 0;
|
|
6176
|
+
let depth = 0;
|
|
6177
|
+
while (i < raw.length) {
|
|
6178
|
+
i = skipTrivia(raw, i);
|
|
6179
|
+
const ch = raw[i];
|
|
6180
|
+
if (ch === undefined) {
|
|
6181
|
+
break;
|
|
6182
|
+
}
|
|
6183
|
+
if (ch === "{") {
|
|
6184
|
+
depth += 1;
|
|
6185
|
+
i += 1;
|
|
6186
|
+
continue;
|
|
6187
|
+
}
|
|
6188
|
+
if (ch === "}") {
|
|
6189
|
+
if (depth > 0) {
|
|
6190
|
+
depth -= 1;
|
|
6191
|
+
}
|
|
6192
|
+
i += 1;
|
|
6193
|
+
continue;
|
|
6194
|
+
}
|
|
6195
|
+
if (ch === "[") {
|
|
6196
|
+
depth += 1;
|
|
6197
|
+
i += 1;
|
|
6198
|
+
continue;
|
|
6199
|
+
}
|
|
6200
|
+
if (ch === "]") {
|
|
6201
|
+
if (depth > 0) {
|
|
6202
|
+
depth -= 1;
|
|
6203
|
+
}
|
|
6204
|
+
i += 1;
|
|
6205
|
+
continue;
|
|
6206
|
+
}
|
|
6207
|
+
if (ch !== '"') {
|
|
6208
|
+
i += 1;
|
|
6209
|
+
continue;
|
|
6210
|
+
}
|
|
6211
|
+
const token = readStringToken(raw, i);
|
|
6212
|
+
if (token === undefined) {
|
|
6213
|
+
return;
|
|
6214
|
+
}
|
|
6215
|
+
const key = readJsonStringValue(raw, { start: i, end: token.end });
|
|
6216
|
+
if (key === undefined) {
|
|
6217
|
+
return;
|
|
6218
|
+
}
|
|
6219
|
+
i = token.end;
|
|
6220
|
+
if (key !== PLUGIN_KEY || depth !== 1) {
|
|
6221
|
+
continue;
|
|
6222
|
+
}
|
|
6223
|
+
i = skipTrivia(raw, i);
|
|
6224
|
+
if (raw[i] !== ":") {
|
|
6225
|
+
continue;
|
|
6226
|
+
}
|
|
6227
|
+
i += 1;
|
|
6228
|
+
i = skipTrivia(raw, i);
|
|
6229
|
+
if (raw[i] !== "[") {
|
|
6230
|
+
continue;
|
|
6231
|
+
}
|
|
6232
|
+
const arrayEnd = readJsoncValueEnd(raw, i, raw.length);
|
|
6233
|
+
if (arrayEnd === undefined) {
|
|
6234
|
+
return;
|
|
6235
|
+
}
|
|
6236
|
+
found = { start: i, end: arrayEnd };
|
|
6237
|
+
}
|
|
6238
|
+
return found;
|
|
6239
|
+
}
|
|
6240
|
+
function scanTopLevelArrayElements(raw, arrayStart, arrayEnd) {
|
|
6241
|
+
const elements = [];
|
|
6242
|
+
let i = skipTrivia(raw, arrayStart + 1, arrayEnd);
|
|
6243
|
+
while (i < arrayEnd) {
|
|
6244
|
+
const ch = raw[i];
|
|
6245
|
+
if (ch === undefined || ch === "]") {
|
|
6246
|
+
break;
|
|
6247
|
+
}
|
|
6248
|
+
const end = readJsoncValueEnd(raw, i, arrayEnd);
|
|
6249
|
+
if (end === undefined) {
|
|
6250
|
+
return;
|
|
6251
|
+
}
|
|
6252
|
+
elements.push({ start: i, end });
|
|
6253
|
+
i = skipTrivia(raw, end, arrayEnd);
|
|
6254
|
+
const next = raw[i];
|
|
6255
|
+
if (next === ",") {
|
|
6256
|
+
i = skipTrivia(raw, i + 1, arrayEnd);
|
|
6257
|
+
if (raw[i] === "]") {
|
|
6258
|
+
break;
|
|
6259
|
+
}
|
|
6260
|
+
continue;
|
|
6261
|
+
}
|
|
6262
|
+
if (next === "]") {
|
|
6263
|
+
break;
|
|
6264
|
+
}
|
|
6265
|
+
return;
|
|
6266
|
+
}
|
|
6267
|
+
return elements;
|
|
6268
|
+
}
|
|
6269
|
+
function readJsonStringValue(raw, span) {
|
|
6270
|
+
try {
|
|
6271
|
+
const parsed = JSON.parse(raw.slice(span.start, span.end));
|
|
6272
|
+
return typeof parsed === "string" ? parsed : undefined;
|
|
6273
|
+
} catch {
|
|
6274
|
+
return;
|
|
6275
|
+
}
|
|
6276
|
+
}
|
|
6277
|
+
function findEntrySpecStringSpan(raw, element, entry, expectedSpec) {
|
|
6278
|
+
if (typeof entry === "string") {
|
|
6279
|
+
const token2 = readStringToken(raw, element.start, element.end);
|
|
6280
|
+
if (token2 === undefined) {
|
|
6281
|
+
return;
|
|
6282
|
+
}
|
|
6283
|
+
const span2 = { start: element.start, end: token2.end };
|
|
6284
|
+
return readJsonStringValue(raw, span2) === expectedSpec ? span2 : undefined;
|
|
6285
|
+
}
|
|
6286
|
+
if (!isTuplePluginEntry(entry)) {
|
|
6287
|
+
return;
|
|
6288
|
+
}
|
|
6289
|
+
if (raw[element.start] !== "[") {
|
|
6290
|
+
return;
|
|
6291
|
+
}
|
|
6292
|
+
const firstValueStart = skipTrivia(raw, element.start + 1, element.end);
|
|
6293
|
+
const token = readStringToken(raw, firstValueStart, element.end);
|
|
6294
|
+
if (token === undefined) {
|
|
6295
|
+
return;
|
|
6296
|
+
}
|
|
6297
|
+
const span = { start: firstValueStart, end: token.end };
|
|
6298
|
+
return readJsonStringValue(raw, span) === expectedSpec ? span : undefined;
|
|
6299
|
+
}
|
|
6300
|
+
function buildUpdatedContent(originalContent, replacements, nextSpec) {
|
|
6301
|
+
const jsonSpec = JSON.stringify(nextSpec);
|
|
6302
|
+
let nextContent = originalContent;
|
|
6303
|
+
for (const replacement of [...replacements].sort((left, right) => right.start - left.start)) {
|
|
6304
|
+
nextContent = nextContent.slice(0, replacement.start) + jsonSpec + nextContent.slice(replacement.end);
|
|
6305
|
+
}
|
|
6306
|
+
return nextContent;
|
|
6307
|
+
}
|
|
6308
|
+
function validateEffectivePluginUpdate(path, nextContent, expectedManagedEntries, nextSpec) {
|
|
6309
|
+
const parsed = parseConfigDocument(path, nextContent);
|
|
6310
|
+
if (!parsed.ok) {
|
|
6311
|
+
return parsed.error;
|
|
6312
|
+
}
|
|
6313
|
+
const pluginValue = parsed.value[PLUGIN_KEY];
|
|
6314
|
+
if (!Array.isArray(pluginValue)) {
|
|
6315
|
+
return upgradeMessages.effectivePluginUpdateMismatch(path);
|
|
6316
|
+
}
|
|
6317
|
+
let managedEntries = 0;
|
|
6318
|
+
let updatedEntries = 0;
|
|
6319
|
+
for (const entry of pluginValue) {
|
|
6320
|
+
const spec = extractSpecString(entry);
|
|
6321
|
+
if (spec === undefined || !isOurSpec(spec)) {
|
|
6322
|
+
continue;
|
|
6323
|
+
}
|
|
6324
|
+
managedEntries += 1;
|
|
6325
|
+
if (spec === nextSpec) {
|
|
6326
|
+
updatedEntries += 1;
|
|
6327
|
+
}
|
|
6328
|
+
}
|
|
6329
|
+
return managedEntries === expectedManagedEntries && updatedEntries === expectedManagedEntries ? undefined : upgradeMessages.effectivePluginUpdateMismatch(path);
|
|
6330
|
+
}
|
|
6331
|
+
function parseUpgradePositionals(positionals) {
|
|
6332
|
+
let check = false;
|
|
6333
|
+
let targetVersion;
|
|
6334
|
+
for (let i = 1;i < positionals.length; i += 1) {
|
|
6335
|
+
const arg = positionals[i];
|
|
6336
|
+
if (arg === "--check") {
|
|
6337
|
+
if (check) {
|
|
6338
|
+
return { ok: false, error: upgradeMessages.duplicateCheck };
|
|
6339
|
+
}
|
|
6340
|
+
check = true;
|
|
6341
|
+
continue;
|
|
6342
|
+
}
|
|
6343
|
+
if (arg === "--version") {
|
|
6344
|
+
if (targetVersion !== undefined) {
|
|
6345
|
+
return { ok: false, error: upgradeMessages.duplicateVersion };
|
|
6346
|
+
}
|
|
6347
|
+
const next = positionals[i + 1];
|
|
6348
|
+
if (next === undefined || next.startsWith("--")) {
|
|
6349
|
+
return { ok: false, error: upgradeMessages.missingVersionValue };
|
|
6350
|
+
}
|
|
6351
|
+
targetVersion = next;
|
|
6352
|
+
i += 1;
|
|
6353
|
+
continue;
|
|
6354
|
+
}
|
|
6355
|
+
if (arg?.startsWith("--")) {
|
|
6356
|
+
return { ok: false, error: upgradeMessages.unknownFlag(arg) };
|
|
6357
|
+
}
|
|
6358
|
+
if (arg !== undefined) {
|
|
6359
|
+
return { ok: false, error: upgradeMessages.unexpectedArgument(arg) };
|
|
6360
|
+
}
|
|
6361
|
+
}
|
|
6362
|
+
return { ok: true, value: { check, targetVersion } };
|
|
6363
|
+
}
|
|
6364
|
+
async function raceWithAbort(promise, signal, message) {
|
|
6365
|
+
if (signal.aborted) {
|
|
6366
|
+
throw new TransientFetchError(message);
|
|
6367
|
+
}
|
|
6368
|
+
let onAbort;
|
|
6369
|
+
try {
|
|
6370
|
+
return await Promise.race([
|
|
6371
|
+
promise,
|
|
6372
|
+
new Promise((_, reject) => {
|
|
6373
|
+
onAbort = () => reject(new TransientFetchError(message));
|
|
6374
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
6375
|
+
})
|
|
6376
|
+
]);
|
|
6377
|
+
} finally {
|
|
6378
|
+
if (onAbort !== undefined) {
|
|
6379
|
+
signal.removeEventListener("abort", onAbort);
|
|
6380
|
+
}
|
|
6381
|
+
}
|
|
6382
|
+
}
|
|
6383
|
+
function scheduleCleanup(action) {
|
|
6384
|
+
try {
|
|
6385
|
+
const promise = action();
|
|
6386
|
+
promise?.catch(() => {});
|
|
6387
|
+
} catch {}
|
|
6388
|
+
}
|
|
6389
|
+
function scheduleResponseBodyCancel(response) {
|
|
6390
|
+
scheduleCleanup(() => response.body?.cancel());
|
|
6391
|
+
}
|
|
6392
|
+
function scheduleReaderCancel(reader) {
|
|
6393
|
+
scheduleCleanup(() => reader.cancel());
|
|
6394
|
+
}
|
|
6395
|
+
function extractFetchFailureDetail(error) {
|
|
6396
|
+
const seen = new Set;
|
|
6397
|
+
let current = error;
|
|
6398
|
+
let fallback;
|
|
6399
|
+
while (current instanceof Error && !seen.has(current)) {
|
|
6400
|
+
seen.add(current);
|
|
6401
|
+
const message = current.message.trim();
|
|
6402
|
+
if (message !== "" && !GENERIC_FETCH_FAILURE_MESSAGES.has(message.toLowerCase())) {
|
|
6403
|
+
return message;
|
|
6404
|
+
}
|
|
6405
|
+
if (message !== "" && fallback === undefined) {
|
|
6406
|
+
fallback = message;
|
|
6407
|
+
}
|
|
6408
|
+
current = "cause" in current ? current.cause : undefined;
|
|
6409
|
+
}
|
|
6410
|
+
if (typeof current === "string") {
|
|
6411
|
+
const message = current.trim();
|
|
6412
|
+
if (message !== "") {
|
|
6413
|
+
return message;
|
|
6414
|
+
}
|
|
6415
|
+
}
|
|
6416
|
+
return fallback;
|
|
6417
|
+
}
|
|
6418
|
+
function classifyUnexpectedFetchFailure(error, timedOut) {
|
|
6419
|
+
if (timedOut) {
|
|
6420
|
+
return new TransientFetchError(upgradeMessages.requestTimedOut(FETCH_TIMEOUT_MS));
|
|
6421
|
+
}
|
|
6422
|
+
const detail = extractFetchFailureDetail(error);
|
|
6423
|
+
return new TransientFetchError(detail === undefined ? upgradeMessages.networkRequestFailed : upgradeMessages.networkRequestFailedWithDetail(detail));
|
|
6424
|
+
}
|
|
6425
|
+
async function readBoundedJsonResponse(response, signal) {
|
|
6426
|
+
const contentLength = Number(response.headers.get("content-length"));
|
|
6427
|
+
if (Number.isFinite(contentLength) && contentLength > MAX_RESPONSE_BYTES) {
|
|
6428
|
+
scheduleResponseBodyCancel(response);
|
|
6429
|
+
throw new PermanentFetchError(upgradeMessages.responseTooLarge(MAX_RESPONSE_BYTES));
|
|
6430
|
+
}
|
|
6431
|
+
const body = response.body;
|
|
6432
|
+
if (body === null) {
|
|
6433
|
+
throw new PermanentFetchError(upgradeMessages.missingRegistryBody);
|
|
6434
|
+
}
|
|
6435
|
+
const reader = body.getReader();
|
|
6436
|
+
const cancelReader = () => {
|
|
6437
|
+
scheduleReaderCancel(reader);
|
|
6438
|
+
};
|
|
6439
|
+
signal.addEventListener("abort", cancelReader, { once: true });
|
|
6440
|
+
const chunks = [];
|
|
6441
|
+
let total = 0;
|
|
6442
|
+
try {
|
|
6443
|
+
while (true) {
|
|
6444
|
+
const chunk = await raceWithAbort(reader.read(), signal, upgradeMessages.requestTimedOut(FETCH_TIMEOUT_MS));
|
|
6445
|
+
if (chunk.done) {
|
|
6446
|
+
break;
|
|
6447
|
+
}
|
|
6448
|
+
total += chunk.value.byteLength;
|
|
6449
|
+
if (total > MAX_RESPONSE_BYTES) {
|
|
6450
|
+
throw new PermanentFetchError(upgradeMessages.responseTooLarge(MAX_RESPONSE_BYTES));
|
|
6451
|
+
}
|
|
6452
|
+
chunks.push(chunk.value);
|
|
6453
|
+
}
|
|
6454
|
+
} catch (error) {
|
|
6455
|
+
scheduleReaderCancel(reader);
|
|
6456
|
+
if (error instanceof PermanentFetchError) {
|
|
6457
|
+
throw error;
|
|
6458
|
+
}
|
|
6459
|
+
throw new TransientFetchError(signal.aborted ? upgradeMessages.requestTimedOut(FETCH_TIMEOUT_MS) : upgradeMessages.responseReadFailed);
|
|
6460
|
+
} finally {
|
|
6461
|
+
signal.removeEventListener("abort", cancelReader);
|
|
6462
|
+
reader.releaseLock();
|
|
6463
|
+
}
|
|
6464
|
+
const bytes = new Uint8Array(total);
|
|
6465
|
+
let offset = 0;
|
|
6466
|
+
for (const chunk of chunks) {
|
|
6467
|
+
bytes.set(chunk, offset);
|
|
6468
|
+
offset += chunk.byteLength;
|
|
6469
|
+
}
|
|
6470
|
+
try {
|
|
6471
|
+
return JSON.parse(new TextDecoder().decode(bytes));
|
|
6472
|
+
} catch {
|
|
6473
|
+
throw new PermanentFetchError(upgradeMessages.invalidRegistryJson);
|
|
6474
|
+
}
|
|
6475
|
+
}
|
|
6476
|
+
async function fetchFromNpm(url, fetchFn) {
|
|
6477
|
+
for (let attempt = 1;attempt <= MAX_FETCH_ATTEMPTS; attempt += 1) {
|
|
6478
|
+
const controller = new AbortController;
|
|
6479
|
+
const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
6480
|
+
try {
|
|
6481
|
+
const response = await raceWithAbort(fetchFn(url, { signal: controller.signal }), controller.signal, upgradeMessages.requestTimedOut(FETCH_TIMEOUT_MS));
|
|
6482
|
+
if (!response.ok) {
|
|
6483
|
+
scheduleResponseBodyCancel(response);
|
|
6484
|
+
return { ok: false, kind: "http", status: response.status };
|
|
6485
|
+
}
|
|
6486
|
+
const data = await readBoundedJsonResponse(response, controller.signal);
|
|
6487
|
+
return { ok: true, data };
|
|
6488
|
+
} catch (error) {
|
|
6489
|
+
const timedOut = controller.signal.aborted;
|
|
6490
|
+
controller.abort();
|
|
6491
|
+
if (error instanceof PermanentFetchError) {
|
|
6492
|
+
return { ok: false, kind: "error", error: error.message };
|
|
6493
|
+
}
|
|
6494
|
+
const transientError = error instanceof TransientFetchError ? error : classifyUnexpectedFetchFailure(error, timedOut);
|
|
6495
|
+
if (attempt === MAX_FETCH_ATTEMPTS) {
|
|
6496
|
+
return { ok: false, kind: "error", error: transientError.message };
|
|
6497
|
+
}
|
|
6498
|
+
} finally {
|
|
6499
|
+
clearTimeout(timeoutId);
|
|
6500
|
+
}
|
|
6501
|
+
}
|
|
6502
|
+
return { ok: false, kind: "error", error: upgradeMessages.networkRequestFailed };
|
|
6503
|
+
}
|
|
6504
|
+
function validateRegistryPackageResponse(data) {
|
|
6505
|
+
const parsed = RegistryPackageIdentitySchema.safeParse(isRecord3(data) ? { name: data.name, version: data.version } : data);
|
|
6506
|
+
if (!parsed.success) {
|
|
6507
|
+
return { ok: false, error: upgradeMessages.invalidRegistryPayload };
|
|
6508
|
+
}
|
|
6509
|
+
if (parsed.data.name !== OPENTEAM_PACKAGE_NAME) {
|
|
6510
|
+
return { ok: false, error: upgradeMessages.wrongPackageIdentity(parsed.data.name) };
|
|
6511
|
+
}
|
|
6512
|
+
if (!isStrictSemver(parsed.data.version)) {
|
|
6513
|
+
return {
|
|
6514
|
+
ok: false,
|
|
6515
|
+
error: upgradeMessages.unexpectedVersionField(JSON.stringify(parsed.data.version))
|
|
6516
|
+
};
|
|
6517
|
+
}
|
|
6518
|
+
return { ok: true, version: parsed.data.version };
|
|
6519
|
+
}
|
|
6520
|
+
async function fetchLatestVersion(fetchFn) {
|
|
6521
|
+
const result = await fetchFromNpm(NPM_LATEST_URL, fetchFn);
|
|
6522
|
+
if (!result.ok) {
|
|
6523
|
+
if (result.kind === "http") {
|
|
6524
|
+
return { ok: false, error: upgradeMessages.fetchError(upgradeMessages.httpStatus(result.status)) };
|
|
6525
|
+
}
|
|
6526
|
+
return { ok: false, error: upgradeMessages.fetchError(result.error) };
|
|
6527
|
+
}
|
|
6528
|
+
const validated = validateRegistryPackageResponse(result.data);
|
|
6529
|
+
if (!validated.ok) {
|
|
6530
|
+
return { ok: false, error: upgradeMessages.fetchError(validated.error) };
|
|
6531
|
+
}
|
|
6532
|
+
return { ok: true, version: validated.version };
|
|
6533
|
+
}
|
|
6534
|
+
async function verifyVersionExists(version, fetchFn) {
|
|
6535
|
+
const result = await fetchFromNpm(npmVersionUrl(version), fetchFn);
|
|
6536
|
+
if (!result.ok) {
|
|
6537
|
+
if (result.kind === "http") {
|
|
6538
|
+
return result.status === 404 ? { ok: false, error: upgradeMessages.versionNotFound(version) } : { ok: false, error: upgradeMessages.fetchError(upgradeMessages.httpStatus(result.status)) };
|
|
6539
|
+
}
|
|
6540
|
+
return { ok: false, error: upgradeMessages.fetchError(result.error) };
|
|
6541
|
+
}
|
|
6542
|
+
const validated = validateRegistryPackageResponse(result.data);
|
|
6543
|
+
if (!validated.ok) {
|
|
6544
|
+
return { ok: false, error: upgradeMessages.fetchError(validated.error) };
|
|
6545
|
+
}
|
|
6546
|
+
if (validated.version !== version) {
|
|
6547
|
+
return {
|
|
6548
|
+
ok: false,
|
|
6549
|
+
error: upgradeMessages.fetchError(upgradeMessages.unexpectedPublishedVersion({
|
|
6550
|
+
expected: version,
|
|
6551
|
+
actual: validated.version
|
|
6552
|
+
}))
|
|
6553
|
+
};
|
|
6554
|
+
}
|
|
6555
|
+
return { ok: true };
|
|
6556
|
+
}
|
|
6557
|
+
async function analyseConfigFiles(paths, port) {
|
|
6558
|
+
const files = [];
|
|
6559
|
+
const localOpenteamEntries = [];
|
|
6560
|
+
let foundConfigFile = false;
|
|
6561
|
+
for (const path of paths) {
|
|
6562
|
+
let content;
|
|
6563
|
+
try {
|
|
6564
|
+
content = await port.readOpencodeConfigFile(path);
|
|
6565
|
+
} catch (error) {
|
|
6566
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6567
|
+
return {
|
|
6568
|
+
files,
|
|
6569
|
+
foundConfigFile,
|
|
6570
|
+
localOpenteamEntries,
|
|
6571
|
+
parseError: upgradeMessages.readConfigError(path, message)
|
|
6572
|
+
};
|
|
6573
|
+
}
|
|
6574
|
+
if (content === undefined) {
|
|
6575
|
+
continue;
|
|
6576
|
+
}
|
|
6577
|
+
foundConfigFile = true;
|
|
6578
|
+
const parsed = parseConfigDocument(path, content);
|
|
6579
|
+
if (!parsed.ok) {
|
|
6580
|
+
return {
|
|
6581
|
+
files,
|
|
6582
|
+
foundConfigFile,
|
|
6583
|
+
localOpenteamEntries,
|
|
6584
|
+
parseError: parsed.error
|
|
6585
|
+
};
|
|
6586
|
+
}
|
|
6587
|
+
const pluginValue = parsed.value[PLUGIN_KEY];
|
|
6588
|
+
if (pluginValue === undefined) {
|
|
6589
|
+
continue;
|
|
6590
|
+
}
|
|
6591
|
+
if (!Array.isArray(pluginValue)) {
|
|
6592
|
+
return {
|
|
6593
|
+
files,
|
|
6594
|
+
foundConfigFile,
|
|
6595
|
+
localOpenteamEntries,
|
|
6596
|
+
parseError: upgradeMessages.pluginFieldMustBeArray(path)
|
|
6597
|
+
};
|
|
6598
|
+
}
|
|
6599
|
+
const managedCandidates = [];
|
|
6600
|
+
for (let index = 0;index < pluginValue.length; index += 1) {
|
|
6601
|
+
const entry = pluginValue[index];
|
|
6602
|
+
const spec = extractSpecString(entry);
|
|
6603
|
+
if (spec === undefined) {
|
|
6604
|
+
continue;
|
|
6605
|
+
}
|
|
6606
|
+
if (isLocalFileSpec(spec)) {
|
|
6607
|
+
const localKind = await port.classifyLocalPluginSpec({
|
|
6608
|
+
configPath: path,
|
|
6609
|
+
spec
|
|
6610
|
+
});
|
|
6611
|
+
if (localKind === "ours") {
|
|
6612
|
+
localOpenteamEntries.push({ path, spec });
|
|
6613
|
+
}
|
|
6614
|
+
continue;
|
|
6615
|
+
}
|
|
6616
|
+
if (!isOurSpec(spec)) {
|
|
6617
|
+
continue;
|
|
6618
|
+
}
|
|
6619
|
+
managedCandidates.push({
|
|
6620
|
+
currentVersion: currentPinnedVersion(spec),
|
|
6621
|
+
entry,
|
|
6622
|
+
index,
|
|
6623
|
+
spec
|
|
6624
|
+
});
|
|
6625
|
+
}
|
|
6626
|
+
if (managedCandidates.length === 0) {
|
|
6627
|
+
continue;
|
|
6628
|
+
}
|
|
6629
|
+
const pluginArray = findTopLevelPluginArray(content);
|
|
6630
|
+
if (pluginArray === undefined) {
|
|
6631
|
+
return {
|
|
6632
|
+
files,
|
|
6633
|
+
foundConfigFile,
|
|
6634
|
+
localOpenteamEntries,
|
|
6635
|
+
parseError: upgradeMessages.pluginArrayEditUnavailable(path)
|
|
6636
|
+
};
|
|
6637
|
+
}
|
|
6638
|
+
const elementSpans = scanTopLevelArrayElements(content, pluginArray.start, pluginArray.end);
|
|
6639
|
+
if (elementSpans === undefined || elementSpans.length !== pluginValue.length) {
|
|
6640
|
+
return {
|
|
6641
|
+
files,
|
|
6642
|
+
foundConfigFile,
|
|
6643
|
+
localOpenteamEntries,
|
|
6644
|
+
parseError: upgradeMessages.pluginArrayEditUnavailable(path)
|
|
6645
|
+
};
|
|
6646
|
+
}
|
|
6647
|
+
const replacements = [];
|
|
6648
|
+
for (const candidate of managedCandidates) {
|
|
6649
|
+
const elementSpan = elementSpans[candidate.index];
|
|
6650
|
+
if (elementSpan === undefined) {
|
|
6651
|
+
return {
|
|
6652
|
+
files,
|
|
6653
|
+
foundConfigFile,
|
|
6654
|
+
localOpenteamEntries,
|
|
6655
|
+
parseError: upgradeMessages.pluginArrayEditUnavailable(path)
|
|
6656
|
+
};
|
|
6657
|
+
}
|
|
6658
|
+
const specSpan = findEntrySpecStringSpan(content, elementSpan, candidate.entry, candidate.spec);
|
|
6659
|
+
if (specSpan === undefined) {
|
|
6660
|
+
return {
|
|
6661
|
+
files,
|
|
6662
|
+
foundConfigFile,
|
|
6663
|
+
localOpenteamEntries,
|
|
6664
|
+
parseError: upgradeMessages.pluginArrayEditUnavailable(path)
|
|
6665
|
+
};
|
|
6666
|
+
}
|
|
6667
|
+
replacements.push({
|
|
6668
|
+
...specSpan,
|
|
6669
|
+
currentVersion: candidate.currentVersion
|
|
6670
|
+
});
|
|
6671
|
+
}
|
|
6672
|
+
files.push({
|
|
6673
|
+
currentVersions: replacements.map((replacement) => replacement.currentVersion),
|
|
6674
|
+
path,
|
|
6675
|
+
originalContent: content,
|
|
6676
|
+
replacements
|
|
6677
|
+
});
|
|
6678
|
+
}
|
|
6679
|
+
return {
|
|
6680
|
+
files,
|
|
6681
|
+
foundConfigFile,
|
|
6682
|
+
localOpenteamEntries,
|
|
6683
|
+
parseError: undefined
|
|
6684
|
+
};
|
|
6685
|
+
}
|
|
6686
|
+
function renderArgError(error) {
|
|
6687
|
+
return {
|
|
6688
|
+
exitCode: 1,
|
|
6689
|
+
stdout: [
|
|
6690
|
+
upgradeMessages.header,
|
|
6691
|
+
upgradeMessages.invalidArguments(error),
|
|
6692
|
+
"",
|
|
6693
|
+
upgradeMessages.usageLabel,
|
|
6694
|
+
upgradeMessages.help.usage
|
|
6695
|
+
].join(`
|
|
6696
|
+
`)
|
|
6697
|
+
};
|
|
6698
|
+
}
|
|
6699
|
+
function renderFailedWrites(localWarnings, failed) {
|
|
6700
|
+
return {
|
|
6701
|
+
exitCode: 1,
|
|
6702
|
+
stdout: [
|
|
6703
|
+
upgradeMessages.header,
|
|
6704
|
+
...localWarnings,
|
|
6705
|
+
upgradeMessages.nothingChanged,
|
|
6706
|
+
...failed.map((entry) => upgradeMessages.failedEntry(entry)),
|
|
6707
|
+
"",
|
|
6708
|
+
upgradeMessages.rerunAfterFailures
|
|
6709
|
+
].join(`
|
|
6710
|
+
`)
|
|
6711
|
+
};
|
|
6712
|
+
}
|
|
6713
|
+
function renderPartialSuccess(version, localWarnings, written, failed) {
|
|
6714
|
+
return {
|
|
6715
|
+
exitCode: 1,
|
|
6716
|
+
stdout: [
|
|
6717
|
+
upgradeMessages.header,
|
|
6718
|
+
...localWarnings,
|
|
6719
|
+
upgradeMessages.partialHeader(version),
|
|
6720
|
+
...written.map((path) => upgradeMessages.writtenEntry(path)),
|
|
6721
|
+
upgradeMessages.partialFailuresHeader,
|
|
6722
|
+
...failed.map((entry) => upgradeMessages.failedEntry(entry)),
|
|
6723
|
+
"",
|
|
6724
|
+
upgradeMessages.backupNote(UPGRADE_BACKUP_DIRECTORY),
|
|
6725
|
+
upgradeMessages.resolveFailuresBeforeRestart
|
|
6726
|
+
].join(`
|
|
6727
|
+
`)
|
|
6728
|
+
};
|
|
6729
|
+
}
|
|
6730
|
+
function renderSuccess(version, localWarnings, written) {
|
|
6731
|
+
return {
|
|
6732
|
+
exitCode: 0,
|
|
6733
|
+
stdout: [
|
|
6734
|
+
upgradeMessages.header,
|
|
6735
|
+
...localWarnings,
|
|
6736
|
+
upgradeMessages.updatedHeader(version),
|
|
6737
|
+
...written.map((path) => upgradeMessages.writtenEntry(path)),
|
|
6738
|
+
"",
|
|
6739
|
+
upgradeMessages.backupNote(UPGRADE_BACKUP_DIRECTORY),
|
|
6740
|
+
upgradeMessages.restartHint,
|
|
6741
|
+
upgradeMessages.cacheCleanupHint
|
|
6742
|
+
].join(`
|
|
6743
|
+
`)
|
|
6744
|
+
};
|
|
6745
|
+
}
|
|
6746
|
+
function resolveProjectPath(workspaceRoot, configPath) {
|
|
6747
|
+
const absoluteRoot = resolve3(workspaceRoot);
|
|
6748
|
+
const absolutePath = resolve3(absoluteRoot, configPath);
|
|
6749
|
+
const rel = relative(absoluteRoot, absolutePath);
|
|
6750
|
+
if (rel === "" || rel.startsWith("..") || win32.isAbsolute(rel)) {
|
|
6751
|
+
throw new Error("path-outside-root");
|
|
6752
|
+
}
|
|
6753
|
+
return absolutePath;
|
|
6754
|
+
}
|
|
6755
|
+
function resolveLocalSpecPath(workspaceRoot, configPath, spec) {
|
|
6756
|
+
if (spec.toLowerCase().startsWith("file:")) {
|
|
6757
|
+
try {
|
|
6758
|
+
return fileURLToPath(new URL(spec));
|
|
6759
|
+
} catch {
|
|
6760
|
+
return;
|
|
6761
|
+
}
|
|
6762
|
+
}
|
|
6763
|
+
if (win32.isAbsolute(spec)) {
|
|
6764
|
+
return spec;
|
|
6765
|
+
}
|
|
6766
|
+
const configAbsolutePath = resolveProjectPath(workspaceRoot, configPath);
|
|
6767
|
+
return resolve3(dirname4(configAbsolutePath), spec);
|
|
6768
|
+
}
|
|
6769
|
+
async function readPackageManifestName(packageJsonPath) {
|
|
6770
|
+
let content;
|
|
6771
|
+
try {
|
|
6772
|
+
content = await readFile2(packageJsonPath, "utf8");
|
|
6773
|
+
} catch (error) {
|
|
6774
|
+
return isMissingFile(error) ? { kind: "missing" } : { kind: "invalid" };
|
|
6775
|
+
}
|
|
6776
|
+
let parsed;
|
|
6777
|
+
try {
|
|
6778
|
+
parsed = JSON.parse(content);
|
|
6779
|
+
} catch {
|
|
6780
|
+
return { kind: "invalid" };
|
|
6781
|
+
}
|
|
6782
|
+
if (!isRecord3(parsed) || typeof parsed.name !== "string") {
|
|
6783
|
+
return { kind: "invalid" };
|
|
6784
|
+
}
|
|
6785
|
+
return { kind: "name", name: parsed.name };
|
|
6786
|
+
}
|
|
6787
|
+
async function manifestSearchStart(targetPath, spec) {
|
|
6788
|
+
try {
|
|
6789
|
+
const stats = await lstat(targetPath);
|
|
6790
|
+
return stats.isDirectory() ? targetPath : dirname4(targetPath);
|
|
6791
|
+
} catch {
|
|
6792
|
+
return spec.endsWith("/") || spec.endsWith("\\") ? targetPath : dirname4(targetPath);
|
|
6793
|
+
}
|
|
6794
|
+
}
|
|
6795
|
+
function splitRelativeProjectPath(workspaceRoot, targetPath) {
|
|
6796
|
+
const rel = relative(workspaceRoot, targetPath);
|
|
6797
|
+
if (rel === "") {
|
|
6798
|
+
return [];
|
|
6799
|
+
}
|
|
6800
|
+
if (rel.startsWith("..") || win32.isAbsolute(rel)) {
|
|
6801
|
+
throw new Error("path-outside-root");
|
|
6802
|
+
}
|
|
6803
|
+
return rel.split(/[\\/]+/u).filter((segment) => segment.length > 0);
|
|
6804
|
+
}
|
|
6805
|
+
async function validateExistingAncestorDirectories(workspaceRoot, targetDirectoryPath) {
|
|
6806
|
+
const absoluteRoot = resolve3(workspaceRoot);
|
|
6807
|
+
const rootStats = await lstat(absoluteRoot);
|
|
6808
|
+
if (!rootStats.isDirectory() || rootStats.isSymbolicLink()) {
|
|
6809
|
+
throw new Error(upgradeMessages.unsafeFilesystemEntry);
|
|
6810
|
+
}
|
|
6811
|
+
let current = absoluteRoot;
|
|
6812
|
+
for (const segment of splitRelativeProjectPath(absoluteRoot, targetDirectoryPath)) {
|
|
6813
|
+
current = join9(current, segment);
|
|
6814
|
+
let stats;
|
|
6815
|
+
try {
|
|
6816
|
+
stats = await lstat(current);
|
|
6817
|
+
} catch (error) {
|
|
6818
|
+
if (isMissingFile(error)) {
|
|
6819
|
+
return false;
|
|
6820
|
+
}
|
|
6821
|
+
throw error;
|
|
6822
|
+
}
|
|
6823
|
+
if (!stats.isDirectory() || stats.isSymbolicLink()) {
|
|
6824
|
+
throw new Error(upgradeMessages.unsafeFilesystemEntry);
|
|
6825
|
+
}
|
|
6826
|
+
}
|
|
6827
|
+
return true;
|
|
6828
|
+
}
|
|
6829
|
+
async function ensurePrivateDirectoryChain(workspaceRoot, targetDirectoryPath) {
|
|
6830
|
+
const absoluteRoot = resolve3(workspaceRoot);
|
|
6831
|
+
const rootStats = await lstat(absoluteRoot);
|
|
6832
|
+
if (!rootStats.isDirectory() || rootStats.isSymbolicLink()) {
|
|
6833
|
+
throw new Error(upgradeMessages.backupLocationUnavailable(UPGRADE_BACKUP_DIRECTORY));
|
|
6834
|
+
}
|
|
6835
|
+
let current = absoluteRoot;
|
|
6836
|
+
for (const segment of splitRelativeProjectPath(absoluteRoot, targetDirectoryPath)) {
|
|
6837
|
+
current = join9(current, segment);
|
|
6838
|
+
try {
|
|
6839
|
+
const stats = await lstat(current);
|
|
6840
|
+
if (!stats.isDirectory() || stats.isSymbolicLink()) {
|
|
6841
|
+
throw new Error(upgradeMessages.backupLocationUnavailable(UPGRADE_BACKUP_DIRECTORY));
|
|
6842
|
+
}
|
|
6843
|
+
continue;
|
|
6844
|
+
} catch (error) {
|
|
6845
|
+
if (!isMissingFile(error)) {
|
|
6846
|
+
throw error;
|
|
6847
|
+
}
|
|
6848
|
+
}
|
|
6849
|
+
try {
|
|
6850
|
+
await mkdir2(current, { mode: PRIVATE_DIRECTORY_MODE });
|
|
6851
|
+
} catch (error) {
|
|
6852
|
+
if (!isAlreadyExistsFile(error)) {
|
|
6853
|
+
throw error;
|
|
6854
|
+
}
|
|
6855
|
+
const stats = await lstat(current);
|
|
6856
|
+
if (!stats.isDirectory() || stats.isSymbolicLink()) {
|
|
6857
|
+
throw new Error(upgradeMessages.backupLocationUnavailable(UPGRADE_BACKUP_DIRECTORY));
|
|
6858
|
+
}
|
|
6859
|
+
}
|
|
6860
|
+
}
|
|
6861
|
+
}
|
|
6862
|
+
async function readSafeTextFileSnapshot(workspaceRoot, diskPath) {
|
|
6863
|
+
const parentsExist = await validateExistingAncestorDirectories(workspaceRoot, dirname4(diskPath));
|
|
6864
|
+
if (!parentsExist) {
|
|
6865
|
+
return;
|
|
6866
|
+
}
|
|
6867
|
+
let stats;
|
|
6868
|
+
try {
|
|
6869
|
+
stats = await lstat(diskPath);
|
|
6870
|
+
} catch (error) {
|
|
6871
|
+
if (isMissingFile(error)) {
|
|
6872
|
+
return;
|
|
6873
|
+
}
|
|
6874
|
+
throw error;
|
|
6875
|
+
}
|
|
6876
|
+
if (!stats.isFile() || stats.isSymbolicLink()) {
|
|
6877
|
+
throw new Error(upgradeMessages.unsafeFilesystemEntry);
|
|
6878
|
+
}
|
|
6879
|
+
const content = await readFile2(diskPath, "utf8");
|
|
6880
|
+
return {
|
|
6881
|
+
content,
|
|
6882
|
+
gid: stats.gid,
|
|
6883
|
+
mode: stats.mode & 511,
|
|
6884
|
+
uid: stats.uid
|
|
6885
|
+
};
|
|
6886
|
+
}
|
|
6887
|
+
async function writePrivateTextFile(path, content, flags) {
|
|
6888
|
+
const handle = await open(path, flags, PRIVATE_FILE_MODE);
|
|
6889
|
+
try {
|
|
6890
|
+
await handle.writeFile(content, "utf8");
|
|
6891
|
+
await handle.sync();
|
|
6892
|
+
} finally {
|
|
6893
|
+
await handle.close();
|
|
6894
|
+
}
|
|
6895
|
+
}
|
|
6896
|
+
async function writeAtomicPrivateFile(path, content, finalMode, options) {
|
|
6897
|
+
const temporary = join9(dirname4(path), `.${basename2(path)}.${randomUUID()}.next`);
|
|
6898
|
+
const handle = await open(temporary, "wx", PRIVATE_FILE_MODE);
|
|
6899
|
+
try {
|
|
6900
|
+
if (process.platform !== "win32") {
|
|
6901
|
+
if (finalMode !== PRIVATE_FILE_MODE) {
|
|
6902
|
+
await handle.chmod(finalMode);
|
|
6903
|
+
}
|
|
6904
|
+
const owner = options?.originalOwner;
|
|
6905
|
+
if (owner !== undefined) {
|
|
6906
|
+
await handle.chown(owner.uid, owner.gid);
|
|
6907
|
+
}
|
|
6908
|
+
}
|
|
6909
|
+
await handle.writeFile(content, "utf8");
|
|
6910
|
+
await handle.sync();
|
|
6911
|
+
} catch (error) {
|
|
6912
|
+
await handle.close();
|
|
6913
|
+
await rm2(temporary, { force: true }).catch(() => {});
|
|
6914
|
+
throw error;
|
|
6915
|
+
}
|
|
6916
|
+
await handle.close();
|
|
6917
|
+
try {
|
|
6918
|
+
await rename(temporary, path);
|
|
6919
|
+
options?.onReplaced?.();
|
|
6920
|
+
} finally {
|
|
6921
|
+
await rm2(temporary, { force: true }).catch(() => {});
|
|
6922
|
+
}
|
|
6923
|
+
}
|
|
6924
|
+
async function replaceWindowsFilePreservingAcl(sourcePath, destinationPath, backupPath, displayPath) {
|
|
6925
|
+
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) }`;
|
|
6926
|
+
try {
|
|
6927
|
+
await execFileAsync2(WINDOWS_POWERSHELL_EXE, ["-NoProfile", "-NonInteractive", "-Command", script], {
|
|
6928
|
+
encoding: "utf8",
|
|
6929
|
+
env: {
|
|
6930
|
+
...process.env,
|
|
6931
|
+
OPENTEAM_UPGRADE_BACKUP: backupPath ?? "",
|
|
6932
|
+
OPENTEAM_UPGRADE_DESTINATION: destinationPath,
|
|
6933
|
+
OPENTEAM_UPGRADE_SOURCE: sourcePath
|
|
6934
|
+
},
|
|
6935
|
+
timeout: WINDOWS_PS_TIMEOUT_MS,
|
|
6936
|
+
windowsHide: true
|
|
6937
|
+
});
|
|
6938
|
+
} catch (error) {
|
|
6939
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6940
|
+
throw new Error(upgradeMessages.windowsReplaceFailed(displayPath, message));
|
|
6941
|
+
}
|
|
6942
|
+
}
|
|
6943
|
+
async function applyWindowsFileDaclToTemp(sourcePath, targetPath, displayPath) {
|
|
6944
|
+
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)`;
|
|
6945
|
+
try {
|
|
6946
|
+
await execFileAsync2(WINDOWS_POWERSHELL_EXE, ["-NoProfile", "-NonInteractive", "-Command", script], {
|
|
6947
|
+
encoding: "utf8",
|
|
6948
|
+
env: {
|
|
6949
|
+
...process.env,
|
|
6950
|
+
OPENTEAM_UPGRADE_ACL_SOURCE: sourcePath,
|
|
6951
|
+
OPENTEAM_UPGRADE_ACL_TARGET: targetPath
|
|
6952
|
+
},
|
|
6953
|
+
timeout: WINDOWS_PS_TIMEOUT_MS,
|
|
6954
|
+
windowsHide: true
|
|
6955
|
+
});
|
|
6956
|
+
} catch (error) {
|
|
6957
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6958
|
+
throw new Error(upgradeMessages.windowsDaclPrepFailed(displayPath, message));
|
|
6959
|
+
}
|
|
6960
|
+
}
|
|
6961
|
+
async function writeWindowsFileReplacingPreservedAcl(destinationPath, content, backupPath, displayPath) {
|
|
6962
|
+
const temporary = join9(dirname4(destinationPath), `.${basename2(destinationPath)}.${randomUUID()}.next`);
|
|
6963
|
+
const handle = await open(temporary, "wx", PRIVATE_FILE_MODE);
|
|
6964
|
+
try {
|
|
6965
|
+
await applyWindowsFileDaclToTemp(destinationPath, temporary, displayPath);
|
|
6966
|
+
await handle.writeFile(content, "utf8");
|
|
6967
|
+
await handle.sync();
|
|
6968
|
+
} catch (error) {
|
|
6969
|
+
await handle.close();
|
|
6970
|
+
await rm2(temporary, { force: true }).catch(() => {});
|
|
6971
|
+
throw error;
|
|
6972
|
+
}
|
|
6973
|
+
await handle.close();
|
|
6974
|
+
try {
|
|
6975
|
+
await replaceWindowsFilePreservingAcl(temporary, destinationPath, backupPath, displayPath);
|
|
6976
|
+
} finally {
|
|
6977
|
+
await rm2(temporary, { force: true }).catch(() => {});
|
|
6978
|
+
}
|
|
6979
|
+
}
|
|
6980
|
+
function backupFileNameForConfig(configPath, content) {
|
|
6981
|
+
const safeStem = configPath.replace(/^[./\\]+/u, "").replace(/[\\/]+/gu, "__").replace(/[^A-Za-z0-9._-]/gu, "_");
|
|
6982
|
+
const stem = safeStem === "" ? "opencode" : safeStem;
|
|
6983
|
+
const digest = createHash2("sha256").update(content).digest("hex").slice(0, 12);
|
|
6984
|
+
return `${stem}.${digest}${UPGRADE_BACKUP_SUFFIX}`;
|
|
6985
|
+
}
|
|
6986
|
+
async function ensureUpgradeBackupRoot(workspaceRoot) {
|
|
6987
|
+
const backupRoot = resolveProjectPath(workspaceRoot, UPGRADE_BACKUP_DIRECTORY);
|
|
6988
|
+
await ensurePrivateDirectoryChain(workspaceRoot, backupRoot);
|
|
6989
|
+
if (process.platform !== "win32") {
|
|
6990
|
+
const dirStats = await lstat(backupRoot);
|
|
6991
|
+
if ((dirStats.mode & 511) !== PRIVATE_DIRECTORY_MODE) {
|
|
6992
|
+
await chmod(backupRoot, PRIVATE_DIRECTORY_MODE);
|
|
6993
|
+
}
|
|
6994
|
+
}
|
|
6995
|
+
const ignorePath = join9(backupRoot, ".gitignore");
|
|
6996
|
+
const ignoreFile = await readSafeTextFileSnapshot(workspaceRoot, ignorePath);
|
|
6997
|
+
if (ignoreFile !== undefined) {
|
|
6998
|
+
if (ignoreFile.content !== UPGRADE_BACKUP_GITIGNORE_CONTENT) {
|
|
6999
|
+
throw new Error(upgradeMessages.backupGitignoreUnexpected(UPGRADE_BACKUP_DIRECTORY));
|
|
7000
|
+
}
|
|
7001
|
+
return backupRoot;
|
|
7002
|
+
}
|
|
7003
|
+
try {
|
|
7004
|
+
await writePrivateTextFile(ignorePath, UPGRADE_BACKUP_GITIGNORE_CONTENT, "wx");
|
|
7005
|
+
} catch (error) {
|
|
7006
|
+
if (!isAlreadyExistsFile(error)) {
|
|
7007
|
+
throw error;
|
|
7008
|
+
}
|
|
7009
|
+
const concurrent = await readSafeTextFileSnapshot(workspaceRoot, ignorePath);
|
|
7010
|
+
if (concurrent === undefined) {
|
|
7011
|
+
throw error;
|
|
7012
|
+
}
|
|
7013
|
+
if (concurrent.content !== UPGRADE_BACKUP_GITIGNORE_CONTENT) {
|
|
7014
|
+
throw new Error(upgradeMessages.backupGitignoreUnexpected(UPGRADE_BACKUP_DIRECTORY));
|
|
7015
|
+
}
|
|
7016
|
+
}
|
|
7017
|
+
return backupRoot;
|
|
7018
|
+
}
|
|
7019
|
+
async function ensureUpgradeBackupFile(workspaceRoot, configPath, expectedContent) {
|
|
7020
|
+
try {
|
|
7021
|
+
await ensureUpgradeBackupRoot(workspaceRoot);
|
|
7022
|
+
} catch {
|
|
7023
|
+
throw new Error(upgradeMessages.backupLocationUnavailable(UPGRADE_BACKUP_DIRECTORY));
|
|
7024
|
+
}
|
|
7025
|
+
const backupRelativePath = `${UPGRADE_BACKUP_DIRECTORY}/` + backupFileNameForConfig(configPath, expectedContent);
|
|
7026
|
+
const backupDiskPath = resolveProjectPath(workspaceRoot, backupRelativePath);
|
|
7027
|
+
let existingBackup;
|
|
7028
|
+
try {
|
|
7029
|
+
existingBackup = await readSafeTextFileSnapshot(workspaceRoot, backupDiskPath);
|
|
7030
|
+
} catch {
|
|
7031
|
+
throw new Error(upgradeMessages.backupLocationUnavailable(UPGRADE_BACKUP_DIRECTORY));
|
|
7032
|
+
}
|
|
7033
|
+
if (existingBackup !== undefined) {
|
|
7034
|
+
if (existingBackup.content !== expectedContent) {
|
|
7035
|
+
throw new Error(upgradeMessages.backupConflict(backupRelativePath));
|
|
7036
|
+
}
|
|
7037
|
+
return { created: false, diskPath: backupDiskPath, reuseExisting: true };
|
|
7038
|
+
}
|
|
7039
|
+
if (process.platform === "win32") {
|
|
7040
|
+
return { created: false, diskPath: backupDiskPath, reuseExisting: false };
|
|
7041
|
+
}
|
|
7042
|
+
try {
|
|
7043
|
+
await writeAtomicPrivateFile(backupDiskPath, expectedContent, PRIVATE_FILE_MODE);
|
|
7044
|
+
} catch {
|
|
7045
|
+
throw new Error(upgradeMessages.backupLocationUnavailable(UPGRADE_BACKUP_DIRECTORY));
|
|
7046
|
+
}
|
|
7047
|
+
return { created: true, diskPath: backupDiskPath, reuseExisting: false };
|
|
7048
|
+
}
|
|
7049
|
+
async function readExpectedConfigSnapshot(workspaceRoot, configPath, expectedContent) {
|
|
7050
|
+
const diskPath = resolveProjectPath(workspaceRoot, configPath);
|
|
7051
|
+
const snapshot = await readSafeTextFileSnapshot(workspaceRoot, diskPath);
|
|
7052
|
+
if (snapshot === undefined) {
|
|
7053
|
+
throw new Error(upgradeMessages.writeTargetMissing(configPath));
|
|
7054
|
+
}
|
|
7055
|
+
if (snapshot.content !== expectedContent) {
|
|
7056
|
+
throw new Error(upgradeMessages.concurrentEdit(configPath));
|
|
7057
|
+
}
|
|
7058
|
+
return snapshot;
|
|
7059
|
+
}
|
|
7060
|
+
function createFsUpgradePort(workspaceRoot, fetch) {
|
|
7061
|
+
return {
|
|
7062
|
+
async readOpencodeConfigFile(path) {
|
|
7063
|
+
const diskPath = resolveProjectPath(workspaceRoot, path);
|
|
7064
|
+
const snapshot = await readSafeTextFileSnapshot(workspaceRoot, diskPath);
|
|
7065
|
+
return snapshot?.content;
|
|
7066
|
+
},
|
|
7067
|
+
async writeOpencodeConfigFile(request) {
|
|
7068
|
+
const diskPath = resolveProjectPath(workspaceRoot, request.path);
|
|
7069
|
+
await readExpectedConfigSnapshot(workspaceRoot, request.path, request.expectedContent);
|
|
7070
|
+
const backup = await ensureUpgradeBackupFile(workspaceRoot, request.path, request.expectedContent);
|
|
7071
|
+
let configWritten = false;
|
|
7072
|
+
try {
|
|
7073
|
+
const current = await readExpectedConfigSnapshot(workspaceRoot, request.path, request.expectedContent);
|
|
7074
|
+
if (process.platform === "win32") {
|
|
7075
|
+
await writeWindowsFileReplacingPreservedAcl(diskPath, request.nextContent, backup.reuseExisting ? undefined : backup.diskPath, request.path);
|
|
7076
|
+
configWritten = true;
|
|
7077
|
+
} else {
|
|
7078
|
+
await writeAtomicPrivateFile(diskPath, request.nextContent, current.mode, {
|
|
7079
|
+
originalOwner: { gid: current.gid, uid: current.uid },
|
|
7080
|
+
onReplaced: () => {
|
|
7081
|
+
configWritten = true;
|
|
7082
|
+
}
|
|
7083
|
+
});
|
|
7084
|
+
}
|
|
7085
|
+
} catch (error) {
|
|
7086
|
+
if (backup.created && !configWritten) {
|
|
7087
|
+
await rm2(backup.diskPath, { force: true }).catch(() => {});
|
|
7088
|
+
}
|
|
7089
|
+
throw error;
|
|
7090
|
+
}
|
|
7091
|
+
},
|
|
7092
|
+
async classifyLocalPluginSpec({ configPath, spec }) {
|
|
7093
|
+
const resolved = resolveLocalSpecPath(workspaceRoot, configPath, spec);
|
|
7094
|
+
if (resolved === undefined) {
|
|
7095
|
+
return "unknown";
|
|
7096
|
+
}
|
|
7097
|
+
let current = await manifestSearchStart(resolved, spec);
|
|
7098
|
+
while (true) {
|
|
7099
|
+
const manifest = await readPackageManifestName(join9(current, "package.json"));
|
|
7100
|
+
if (manifest.kind === "name") {
|
|
7101
|
+
return manifest.name === OPENTEAM_PACKAGE_NAME ? "ours" : "other";
|
|
7102
|
+
}
|
|
7103
|
+
if (manifest.kind === "invalid") {
|
|
7104
|
+
return "unknown";
|
|
7105
|
+
}
|
|
7106
|
+
const parent = dirname4(current);
|
|
7107
|
+
if (parent === current) {
|
|
7108
|
+
return "unknown";
|
|
7109
|
+
}
|
|
7110
|
+
current = parent;
|
|
7111
|
+
}
|
|
7112
|
+
},
|
|
7113
|
+
fetch
|
|
7114
|
+
};
|
|
7115
|
+
}
|
|
7116
|
+
async function runUpgrade(positionals, port, opencodeConfigPaths) {
|
|
7117
|
+
const parsedArgs = parseUpgradePositionals(positionals);
|
|
7118
|
+
if (!parsedArgs.ok) {
|
|
7119
|
+
return renderArgError(parsedArgs.error);
|
|
7120
|
+
}
|
|
7121
|
+
const explicitVersion = parsedArgs.value.targetVersion;
|
|
7122
|
+
if (explicitVersion !== undefined && !isStrictSemver(explicitVersion)) {
|
|
7123
|
+
return {
|
|
7124
|
+
exitCode: 1,
|
|
7125
|
+
stdout: [upgradeMessages.header, upgradeMessages.invalidVersion(explicitVersion)].join(`
|
|
7126
|
+
`)
|
|
7127
|
+
};
|
|
7128
|
+
}
|
|
7129
|
+
const analysis = await analyseConfigFiles(opencodeConfigPaths, port);
|
|
7130
|
+
if (analysis.parseError !== undefined) {
|
|
7131
|
+
return {
|
|
7132
|
+
exitCode: 1,
|
|
7133
|
+
stdout: [upgradeMessages.header, analysis.parseError].join(`
|
|
7134
|
+
`)
|
|
7135
|
+
};
|
|
7136
|
+
}
|
|
7137
|
+
if (analysis.files.length === 0) {
|
|
7138
|
+
if (analysis.localOpenteamEntries.length > 0) {
|
|
7139
|
+
return {
|
|
7140
|
+
exitCode: 1,
|
|
7141
|
+
stdout: [
|
|
7142
|
+
upgradeMessages.header,
|
|
7143
|
+
upgradeMessages.localFileOnlyHeader,
|
|
7144
|
+
...analysis.localOpenteamEntries.map((entry) => upgradeMessages.localFileOnlyEntry(entry)),
|
|
7145
|
+
upgradeMessages.localFileOnlyRemedy
|
|
7146
|
+
].join(`
|
|
7147
|
+
`)
|
|
7148
|
+
};
|
|
7149
|
+
}
|
|
7150
|
+
return {
|
|
7151
|
+
exitCode: 1,
|
|
7152
|
+
stdout: [
|
|
7153
|
+
upgradeMessages.header,
|
|
7154
|
+
analysis.foundConfigFile ? upgradeMessages.noPluginEntry : upgradeMessages.noConfigFound(opencodeConfigPaths)
|
|
7155
|
+
].join(`
|
|
7156
|
+
`)
|
|
7157
|
+
};
|
|
7158
|
+
}
|
|
7159
|
+
let targetVersion;
|
|
7160
|
+
if (explicitVersion !== undefined) {
|
|
7161
|
+
const verified = await verifyVersionExists(explicitVersion, port.fetch);
|
|
7162
|
+
if (!verified.ok) {
|
|
7163
|
+
return { exitCode: 1, stdout: [upgradeMessages.header, verified.error].join(`
|
|
7164
|
+
`) };
|
|
7165
|
+
}
|
|
7166
|
+
targetVersion = explicitVersion;
|
|
7167
|
+
} else {
|
|
7168
|
+
const latest = await fetchLatestVersion(port.fetch);
|
|
7169
|
+
if (!latest.ok) {
|
|
7170
|
+
return { exitCode: 1, stdout: [upgradeMessages.header, latest.error].join(`
|
|
7171
|
+
`) };
|
|
7172
|
+
}
|
|
7173
|
+
targetVersion = latest.version;
|
|
7174
|
+
}
|
|
7175
|
+
const localWarnings = analysis.localOpenteamEntries.map((entry) => upgradeMessages.localFileSkipped(entry));
|
|
7176
|
+
if (explicitVersion === undefined) {
|
|
7177
|
+
for (const file of analysis.files) {
|
|
7178
|
+
for (const currentVersion of file.currentVersions) {
|
|
7179
|
+
if (currentVersion !== null && isStrictSemver(currentVersion) && compareSemver(currentVersion, targetVersion) > 0) {
|
|
7180
|
+
return {
|
|
7181
|
+
exitCode: 1,
|
|
7182
|
+
stdout: [
|
|
7183
|
+
upgradeMessages.header,
|
|
7184
|
+
upgradeMessages.noDowngrade({
|
|
7185
|
+
current: currentVersion,
|
|
7186
|
+
target: targetVersion
|
|
7187
|
+
})
|
|
7188
|
+
].join(`
|
|
7189
|
+
`)
|
|
7190
|
+
};
|
|
7191
|
+
}
|
|
7192
|
+
}
|
|
7193
|
+
}
|
|
7194
|
+
}
|
|
7195
|
+
if (parsedArgs.value.check) {
|
|
7196
|
+
const lines = [upgradeMessages.header];
|
|
7197
|
+
let needsUpdate = false;
|
|
7198
|
+
for (const file of analysis.files) {
|
|
7199
|
+
for (const currentVersion of file.currentVersions) {
|
|
7200
|
+
if (currentVersion === targetVersion) {
|
|
7201
|
+
lines.push(upgradeMessages.checkAlreadyCurrent({
|
|
7202
|
+
path: file.path,
|
|
7203
|
+
version: targetVersion
|
|
7204
|
+
}));
|
|
7205
|
+
} else {
|
|
7206
|
+
lines.push(upgradeMessages.checkNeedsUpdate({
|
|
7207
|
+
path: file.path,
|
|
7208
|
+
current: currentVersion,
|
|
7209
|
+
target: targetVersion
|
|
7210
|
+
}));
|
|
7211
|
+
needsUpdate = true;
|
|
7212
|
+
}
|
|
7213
|
+
}
|
|
7214
|
+
}
|
|
7215
|
+
lines.push(...localWarnings);
|
|
7216
|
+
if (needsUpdate) {
|
|
7217
|
+
lines.push(upgradeMessages.checkHint(explicitVersion));
|
|
7218
|
+
}
|
|
7219
|
+
return { exitCode: 0, stdout: lines.join(`
|
|
7220
|
+
`) };
|
|
7221
|
+
}
|
|
7222
|
+
const nextSpec = pinnedPluginSpec(targetVersion);
|
|
7223
|
+
const plans = [];
|
|
7224
|
+
for (const file of analysis.files) {
|
|
7225
|
+
const nextContent = buildUpdatedContent(file.originalContent, file.replacements, nextSpec);
|
|
7226
|
+
if (nextContent === file.originalContent) {
|
|
7227
|
+
continue;
|
|
7228
|
+
}
|
|
7229
|
+
const validationError = validateEffectivePluginUpdate(file.path, nextContent, file.replacements.length, nextSpec);
|
|
7230
|
+
if (validationError !== undefined) {
|
|
7231
|
+
return {
|
|
7232
|
+
exitCode: 1,
|
|
7233
|
+
stdout: [upgradeMessages.header, validationError].join(`
|
|
7234
|
+
`)
|
|
7235
|
+
};
|
|
7236
|
+
}
|
|
7237
|
+
plans.push({
|
|
7238
|
+
path: file.path,
|
|
7239
|
+
expectedContent: file.originalContent,
|
|
7240
|
+
nextContent
|
|
7241
|
+
});
|
|
7242
|
+
}
|
|
7243
|
+
if (plans.length === 0) {
|
|
7244
|
+
return {
|
|
7245
|
+
exitCode: 0,
|
|
7246
|
+
stdout: [
|
|
7247
|
+
upgradeMessages.header,
|
|
7248
|
+
...localWarnings,
|
|
7249
|
+
upgradeMessages.alreadyCurrent(targetVersion)
|
|
7250
|
+
].join(`
|
|
7251
|
+
`)
|
|
7252
|
+
};
|
|
7253
|
+
}
|
|
7254
|
+
const written = [];
|
|
7255
|
+
const failed = [];
|
|
7256
|
+
for (const plan2 of plans) {
|
|
7257
|
+
try {
|
|
7258
|
+
await port.writeOpencodeConfigFile(plan2);
|
|
7259
|
+
written.push(plan2.path);
|
|
7260
|
+
} catch (error) {
|
|
7261
|
+
failed.push({
|
|
7262
|
+
path: plan2.path,
|
|
7263
|
+
error: error instanceof Error ? error.message : String(error)
|
|
7264
|
+
});
|
|
7265
|
+
}
|
|
7266
|
+
}
|
|
7267
|
+
if (failed.length === 0) {
|
|
7268
|
+
return renderSuccess(targetVersion, localWarnings, written);
|
|
7269
|
+
}
|
|
7270
|
+
if (written.length === 0) {
|
|
7271
|
+
return renderFailedWrites(localWarnings, failed);
|
|
7272
|
+
}
|
|
7273
|
+
return renderPartialSuccess(targetVersion, localWarnings, written, failed);
|
|
7274
|
+
}
|
|
7275
|
+
|
|
7276
|
+
// src/config/graphFeatureGate.ts
|
|
7277
|
+
function checkCertificate(status, name) {
|
|
7278
|
+
if (status.status === "absent") {
|
|
7279
|
+
return {
|
|
7280
|
+
code: `${name}-certificate-absent`,
|
|
7281
|
+
detail: `${name} certificate not found — run the ${name} certification suite to produce it`
|
|
7282
|
+
};
|
|
7283
|
+
}
|
|
7284
|
+
if (status.status === "invalid") {
|
|
7285
|
+
return {
|
|
7286
|
+
code: `${name}-certificate-invalid`,
|
|
7287
|
+
detail: `${name} certificate rejected by recomputing parser: ${status.code} — ${status.detail}`
|
|
7288
|
+
};
|
|
7289
|
+
}
|
|
7290
|
+
return;
|
|
7291
|
+
}
|
|
7292
|
+
function evaluateGraphGate(input) {
|
|
7293
|
+
const violations = [];
|
|
7294
|
+
const advisories = [];
|
|
7295
|
+
const shadowV = checkCertificate(input.shadow, "shadow");
|
|
7296
|
+
if (shadowV !== undefined)
|
|
7297
|
+
violations.push(shadowV);
|
|
7298
|
+
const releaseV = checkCertificate(input.release, "release");
|
|
7299
|
+
if (releaseV !== undefined)
|
|
7300
|
+
violations.push(releaseV);
|
|
7301
|
+
const soakV = checkCertificate(input.soak, "soak");
|
|
7302
|
+
if (soakV !== undefined)
|
|
7303
|
+
advisories.push(soakV);
|
|
7304
|
+
if (input.migration === "pending") {
|
|
7305
|
+
violations.push({
|
|
7306
|
+
code: "migration-pending",
|
|
7307
|
+
detail: "legacy migration has pending work — run the migration tool to completion before enabling active mode"
|
|
7308
|
+
});
|
|
7309
|
+
} else if (input.migration === "unknown") {
|
|
7310
|
+
violations.push({
|
|
7311
|
+
code: "migration-unknown",
|
|
7312
|
+
detail: "could not determine migration status — check ledger readability and storage access"
|
|
7313
|
+
});
|
|
7314
|
+
}
|
|
7315
|
+
if (!input.operatorApproval) {
|
|
7316
|
+
violations.push({
|
|
7317
|
+
code: "operator-approval-missing",
|
|
7318
|
+
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"
|
|
7319
|
+
});
|
|
7320
|
+
}
|
|
7321
|
+
return {
|
|
7322
|
+
allowed: violations.length === 0,
|
|
7323
|
+
violations,
|
|
7324
|
+
advisories
|
|
7325
|
+
};
|
|
7326
|
+
}
|
|
7327
|
+
function isGateApplicable(mode) {
|
|
7328
|
+
return mode === "active";
|
|
7329
|
+
}
|
|
7330
|
+
|
|
7331
|
+
// src/config/opencode.ts
|
|
7332
|
+
function stripJsoncComments(src) {
|
|
7333
|
+
const out = [];
|
|
7334
|
+
let i = 0;
|
|
7335
|
+
while (i < src.length) {
|
|
7336
|
+
const ch = src[i];
|
|
7337
|
+
if (ch === undefined)
|
|
7338
|
+
break;
|
|
7339
|
+
if (ch === '"') {
|
|
7340
|
+
out.push(ch);
|
|
7341
|
+
i++;
|
|
7342
|
+
while (i < src.length) {
|
|
7343
|
+
const c = src[i];
|
|
7344
|
+
if (c === undefined)
|
|
7345
|
+
break;
|
|
7346
|
+
out.push(c);
|
|
7347
|
+
i++;
|
|
7348
|
+
if (c === "\\") {
|
|
7349
|
+
const escaped = src[i];
|
|
7350
|
+
if (escaped !== undefined) {
|
|
7351
|
+
out.push(escaped);
|
|
7352
|
+
i++;
|
|
7353
|
+
}
|
|
7354
|
+
} else if (c === '"') {
|
|
7355
|
+
break;
|
|
7356
|
+
}
|
|
7357
|
+
}
|
|
7358
|
+
} else if (ch === "/" && i + 1 < src.length) {
|
|
7359
|
+
if (src[i + 1] === "/") {
|
|
7360
|
+
i += 2;
|
|
7361
|
+
while (i < src.length && src[i] !== `
|
|
7362
|
+
`) {
|
|
7363
|
+
i++;
|
|
7364
|
+
}
|
|
7365
|
+
} else if (src[i + 1] === "*") {
|
|
7366
|
+
i += 2;
|
|
7367
|
+
while (i < src.length && !(src[i] === "*" && src[i + 1] === "/")) {
|
|
7368
|
+
i++;
|
|
7369
|
+
}
|
|
7370
|
+
if (i < src.length) {
|
|
7371
|
+
i += 2;
|
|
7372
|
+
}
|
|
7373
|
+
} else {
|
|
7374
|
+
out.push(ch);
|
|
7375
|
+
i++;
|
|
7376
|
+
}
|
|
7377
|
+
} else {
|
|
7378
|
+
out.push(ch);
|
|
7379
|
+
i++;
|
|
7380
|
+
}
|
|
7381
|
+
}
|
|
7382
|
+
return out.join("");
|
|
7383
|
+
}
|
|
7384
|
+
function isRecord4(v) {
|
|
7385
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
7386
|
+
}
|
|
7387
|
+
var OPENCODE_CONFIG_CANDIDATES = [
|
|
7388
|
+
".opencode/opencode.json",
|
|
7389
|
+
"opencode.json"
|
|
7390
|
+
];
|
|
7391
|
+
function mergeOpencodeConfigs(base, override) {
|
|
7392
|
+
const result = { ...base };
|
|
7393
|
+
for (const [key, value] of Object.entries(override)) {
|
|
7394
|
+
const baseVal = result[key];
|
|
7395
|
+
if (isRecord4(baseVal) && isRecord4(value)) {
|
|
7396
|
+
result[key] = mergeOpencodeConfigs(baseVal, value);
|
|
7397
|
+
} else {
|
|
7398
|
+
result[key] = value;
|
|
7399
|
+
}
|
|
7400
|
+
}
|
|
7401
|
+
return result;
|
|
7402
|
+
}
|
|
7403
|
+
|
|
7404
|
+
// src/graph/certificate.ts
|
|
7405
|
+
import { z as z17 } from "zod";
|
|
7406
|
+
|
|
7407
|
+
// src/contract/opencode.ts
|
|
7408
|
+
var SUPPORTED_OPENCODE_VERSIONS = [
|
|
7409
|
+
"1.17.13",
|
|
7410
|
+
"1.18.18",
|
|
7411
|
+
"1.18.19"
|
|
7412
|
+
];
|
|
7413
|
+
var SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)/;
|
|
7414
|
+
function parseSemver(version) {
|
|
7415
|
+
const normalized = version.trim().replace(/^[=^~v]+/, "");
|
|
7416
|
+
const match = SEMVER_RE.exec(normalized);
|
|
7417
|
+
if (match === null) {
|
|
7418
|
+
throw new Error(`invalid semver: "${version}"`);
|
|
7419
|
+
}
|
|
7420
|
+
return {
|
|
7421
|
+
major: Number(match[1]),
|
|
7422
|
+
minor: Number(match[2]),
|
|
7423
|
+
patch: Number(match[3])
|
|
7424
|
+
};
|
|
7425
|
+
}
|
|
7426
|
+
function isCertificateVersionCompatible(certifiedVersion, liveVersion) {
|
|
7427
|
+
if (certifiedVersion === liveVersion) {
|
|
7428
|
+
return true;
|
|
7429
|
+
}
|
|
7430
|
+
let certified;
|
|
5547
7431
|
let live;
|
|
5548
7432
|
try {
|
|
5549
7433
|
certified = parseSemver(certifiedVersion);
|
|
@@ -5558,31 +7442,31 @@ function isCertificateVersionCompatible(certifiedVersion, liveVersion) {
|
|
|
5558
7442
|
}
|
|
5559
7443
|
|
|
5560
7444
|
// src/graph/soakLedger.ts
|
|
5561
|
-
import { z as
|
|
5562
|
-
var Sha256Schema2 =
|
|
5563
|
-
var SoakPlatformSchema =
|
|
5564
|
-
var PrivacyPairSchema =
|
|
5565
|
-
surfacesScanned:
|
|
5566
|
-
rawFindings:
|
|
7445
|
+
import { z as z16 } from "zod";
|
|
7446
|
+
var Sha256Schema2 = z16.string().regex(/^[0-9a-f]{64}$/);
|
|
7447
|
+
var SoakPlatformSchema = z16.enum(["linux", "win32", "darwin"]);
|
|
7448
|
+
var PrivacyPairSchema = z16.object({
|
|
7449
|
+
surfacesScanned: z16.number().int().nonnegative(),
|
|
7450
|
+
rawFindings: z16.number().int().nonnegative()
|
|
5567
7451
|
}).strict();
|
|
5568
|
-
var DuplicateEffectPairSchema =
|
|
5569
|
-
effectsExamined:
|
|
5570
|
-
duplicatesFound:
|
|
7452
|
+
var DuplicateEffectPairSchema = z16.object({
|
|
7453
|
+
effectsExamined: z16.number().int().nonnegative(),
|
|
7454
|
+
duplicatesFound: z16.number().int().nonnegative()
|
|
5571
7455
|
}).strict();
|
|
5572
|
-
var ModelVerificationPairSchema =
|
|
5573
|
-
nodesChecked:
|
|
5574
|
-
unverified:
|
|
5575
|
-
mismatched:
|
|
7456
|
+
var ModelVerificationPairSchema = z16.object({
|
|
7457
|
+
nodesChecked: z16.number().int().nonnegative(),
|
|
7458
|
+
unverified: z16.number().int().nonnegative(),
|
|
7459
|
+
mismatched: z16.number().int().nonnegative()
|
|
5576
7460
|
}).strict();
|
|
5577
|
-
var SoakObservationSchema =
|
|
5578
|
-
version:
|
|
5579
|
-
seq:
|
|
5580
|
-
timestamp:
|
|
7461
|
+
var SoakObservationSchema = z16.object({
|
|
7462
|
+
version: z16.literal(1),
|
|
7463
|
+
seq: z16.number().int().nonnegative(),
|
|
7464
|
+
timestamp: z16.string().datetime(),
|
|
5581
7465
|
platform: SoakPlatformSchema,
|
|
5582
|
-
opencodeVersion:
|
|
5583
|
-
provenance:
|
|
7466
|
+
opencodeVersion: z16.string().min(1),
|
|
7467
|
+
provenance: z16.enum(["genuine-usage", "ci-synthetic"]),
|
|
5584
7468
|
traceDigest: Sha256Schema2,
|
|
5585
|
-
criticalDivergences:
|
|
7469
|
+
criticalDivergences: z16.number().int().nonnegative().nullable(),
|
|
5586
7470
|
privacy: PrivacyPairSchema.nullable(),
|
|
5587
7471
|
duplicateEffects: DuplicateEffectPairSchema.nullable(),
|
|
5588
7472
|
modelVerification: ModelVerificationPairSchema.nullable(),
|
|
@@ -5653,7 +7537,7 @@ function canonicalLedger(chains) {
|
|
|
5653
7537
|
|
|
5654
7538
|
// src/graph/certificate.ts
|
|
5655
7539
|
var SHADOW_CERTIFICATE_MIN_RUNS = 1000;
|
|
5656
|
-
var DivergenceCodeSchema =
|
|
7540
|
+
var DivergenceCodeSchema = z17.enum([
|
|
5657
7541
|
"status",
|
|
5658
7542
|
"order",
|
|
5659
7543
|
"roles",
|
|
@@ -5661,50 +7545,50 @@ var DivergenceCodeSchema = z16.enum([
|
|
|
5661
7545
|
"fixes",
|
|
5662
7546
|
"outcome"
|
|
5663
7547
|
]);
|
|
5664
|
-
var ProvenanceSchema =
|
|
7548
|
+
var ProvenanceSchema = z17.enum([
|
|
5665
7549
|
"recomputed",
|
|
5666
7550
|
"compiled",
|
|
5667
7551
|
"validated",
|
|
5668
7552
|
"carried"
|
|
5669
7553
|
]);
|
|
5670
|
-
var EvidenceSchema =
|
|
5671
|
-
opencodeVersion:
|
|
5672
|
-
parity:
|
|
5673
|
-
runs:
|
|
5674
|
-
match:
|
|
5675
|
-
divergent:
|
|
5676
|
-
inconclusive:
|
|
5677
|
-
divergences:
|
|
7554
|
+
var EvidenceSchema = z17.object({
|
|
7555
|
+
opencodeVersion: z17.string().min(1),
|
|
7556
|
+
parity: z17.object({
|
|
7557
|
+
runs: z17.number().int().nonnegative(),
|
|
7558
|
+
match: z17.number().int().nonnegative(),
|
|
7559
|
+
divergent: z17.number().int().nonnegative(),
|
|
7560
|
+
inconclusive: z17.number().int().nonnegative(),
|
|
7561
|
+
divergences: z17.array(DivergenceCodeSchema)
|
|
5678
7562
|
}).strict(),
|
|
5679
|
-
legacy:
|
|
5680
|
-
observed:
|
|
5681
|
-
duplicated:
|
|
7563
|
+
legacy: z17.object({
|
|
7564
|
+
observed: z17.number().int().nonnegative(),
|
|
7565
|
+
duplicated: z17.number().int().nonnegative()
|
|
5682
7566
|
}).strict(),
|
|
5683
|
-
privacy:
|
|
5684
|
-
surfacesScanned:
|
|
5685
|
-
rawFindings:
|
|
7567
|
+
privacy: z17.object({
|
|
7568
|
+
surfacesScanned: z17.number().int().nonnegative(),
|
|
7569
|
+
rawFindings: z17.number().int().nonnegative()
|
|
5686
7570
|
}).strict(),
|
|
5687
|
-
overhead:
|
|
5688
|
-
p95Millis:
|
|
5689
|
-
budgetMillis:
|
|
5690
|
-
samples:
|
|
7571
|
+
overhead: z17.object({
|
|
7572
|
+
p95Millis: z17.number().nonnegative(),
|
|
7573
|
+
budgetMillis: z17.number().positive(),
|
|
7574
|
+
samples: z17.number().int().nonnegative()
|
|
5691
7575
|
}).strict(),
|
|
5692
|
-
provenance:
|
|
7576
|
+
provenance: z17.record(DivergenceCodeSchema, ProvenanceSchema)
|
|
5693
7577
|
}).strict();
|
|
5694
|
-
var CertificateSchema =
|
|
5695
|
-
version:
|
|
5696
|
-
certificate:
|
|
5697
|
-
opencodeVersion:
|
|
7578
|
+
var CertificateSchema = z17.object({
|
|
7579
|
+
version: z17.literal(1),
|
|
7580
|
+
certificate: z17.literal("graph-shadow"),
|
|
7581
|
+
opencodeVersion: z17.string().min(1),
|
|
5698
7582
|
evidence: EvidenceSchema,
|
|
5699
|
-
verdict:
|
|
5700
|
-
failedGates:
|
|
7583
|
+
verdict: z17.enum(["pass", "fail"]),
|
|
7584
|
+
failedGates: z17.array(z17.enum([
|
|
5701
7585
|
"sample",
|
|
5702
7586
|
"parity",
|
|
5703
7587
|
"one-legacy-execution",
|
|
5704
7588
|
"privacy",
|
|
5705
7589
|
"overhead"
|
|
5706
7590
|
])),
|
|
5707
|
-
digest:
|
|
7591
|
+
digest: z17.string().regex(/^[0-9a-f]{64}$/)
|
|
5708
7592
|
}).strict();
|
|
5709
7593
|
|
|
5710
7594
|
class ShadowCertificateError extends Error {
|
|
@@ -5819,37 +7703,37 @@ function parseShadowCertificate(value, opencodeVersion) {
|
|
|
5819
7703
|
}
|
|
5820
7704
|
return certificate;
|
|
5821
7705
|
}
|
|
5822
|
-
var ReleaseDeterminismSchema =
|
|
5823
|
-
var ReleaseCrashRecoverySchema =
|
|
5824
|
-
scenarios:
|
|
5825
|
-
allConverge:
|
|
7706
|
+
var ReleaseDeterminismSchema = z17.object({ runs: z17.number().int().nonnegative(), allMatch: z17.boolean() }).strict();
|
|
7707
|
+
var ReleaseCrashRecoverySchema = z17.object({
|
|
7708
|
+
scenarios: z17.number().int().nonnegative(),
|
|
7709
|
+
allConverge: z17.boolean()
|
|
5826
7710
|
}).strict();
|
|
5827
|
-
var ReleaseReplayEquivalenceSchema =
|
|
5828
|
-
checks:
|
|
5829
|
-
allEquivalent:
|
|
7711
|
+
var ReleaseReplayEquivalenceSchema = z17.object({
|
|
7712
|
+
checks: z17.number().int().nonnegative(),
|
|
7713
|
+
allEquivalent: z17.boolean()
|
|
5830
7714
|
}).strict();
|
|
5831
|
-
var ReleasePrivacySchema =
|
|
5832
|
-
surfacesScanned:
|
|
5833
|
-
rawFindings:
|
|
7715
|
+
var ReleasePrivacySchema = z17.object({
|
|
7716
|
+
surfacesScanned: z17.number().int().nonnegative(),
|
|
7717
|
+
rawFindings: z17.number().int().nonnegative()
|
|
5834
7718
|
}).strict();
|
|
5835
|
-
var ReleaseContractSchema =
|
|
5836
|
-
roundTrips:
|
|
5837
|
-
allSettled:
|
|
7719
|
+
var ReleaseContractSchema = z17.object({
|
|
7720
|
+
roundTrips: z17.number().int().nonnegative(),
|
|
7721
|
+
allSettled: z17.boolean()
|
|
5838
7722
|
}).strict();
|
|
5839
|
-
var ReleaseHealthSchema =
|
|
5840
|
-
samples:
|
|
5841
|
-
bounded:
|
|
5842
|
-
idempotent:
|
|
7723
|
+
var ReleaseHealthSchema = z17.object({
|
|
7724
|
+
samples: z17.number().int().nonnegative(),
|
|
7725
|
+
bounded: z17.boolean(),
|
|
7726
|
+
idempotent: z17.boolean()
|
|
5843
7727
|
}).strict();
|
|
5844
|
-
var ReleasePerformanceSchema =
|
|
5845
|
-
p95Millis:
|
|
5846
|
-
budgetMillis:
|
|
5847
|
-
samples:
|
|
7728
|
+
var ReleasePerformanceSchema = z17.object({
|
|
7729
|
+
p95Millis: z17.number().nonnegative(),
|
|
7730
|
+
budgetMillis: z17.number().positive(),
|
|
7731
|
+
samples: z17.number().int().nonnegative()
|
|
5848
7732
|
}).strict();
|
|
5849
|
-
var ReleaseEvidenceSchema =
|
|
5850
|
-
opencodeVersion:
|
|
5851
|
-
platform:
|
|
5852
|
-
shadowCertificateDigest:
|
|
7733
|
+
var ReleaseEvidenceSchema = z17.object({
|
|
7734
|
+
opencodeVersion: z17.string().min(1),
|
|
7735
|
+
platform: z17.enum(["linux", "win32"]),
|
|
7736
|
+
shadowCertificateDigest: z17.string().regex(/^[0-9a-f]{64}$/),
|
|
5853
7737
|
determinism: ReleaseDeterminismSchema,
|
|
5854
7738
|
crashRecovery: ReleaseCrashRecoverySchema,
|
|
5855
7739
|
replayEquivalence: ReleaseReplayEquivalenceSchema,
|
|
@@ -5858,15 +7742,15 @@ var ReleaseEvidenceSchema = z16.object({
|
|
|
5858
7742
|
health: ReleaseHealthSchema,
|
|
5859
7743
|
performance: ReleasePerformanceSchema
|
|
5860
7744
|
}).strict();
|
|
5861
|
-
var ReleaseCertificateSchema =
|
|
5862
|
-
version:
|
|
5863
|
-
certificate:
|
|
5864
|
-
platform:
|
|
5865
|
-
opencodeVersion:
|
|
5866
|
-
shadowCertificateDigest:
|
|
7745
|
+
var ReleaseCertificateSchema = z17.object({
|
|
7746
|
+
version: z17.literal(2),
|
|
7747
|
+
certificate: z17.literal("graph-release"),
|
|
7748
|
+
platform: z17.enum(["linux", "win32"]),
|
|
7749
|
+
opencodeVersion: z17.string().min(1),
|
|
7750
|
+
shadowCertificateDigest: z17.string().regex(/^[0-9a-f]{64}$/),
|
|
5867
7751
|
evidence: ReleaseEvidenceSchema,
|
|
5868
|
-
verdict:
|
|
5869
|
-
failedGates:
|
|
7752
|
+
verdict: z17.enum(["pass", "fail"]),
|
|
7753
|
+
failedGates: z17.array(z17.enum([
|
|
5870
7754
|
"shadow-valid",
|
|
5871
7755
|
"determinism",
|
|
5872
7756
|
"crash-recovery",
|
|
@@ -5876,7 +7760,7 @@ var ReleaseCertificateSchema = z16.object({
|
|
|
5876
7760
|
"health",
|
|
5877
7761
|
"performance"
|
|
5878
7762
|
])),
|
|
5879
|
-
digest:
|
|
7763
|
+
digest: z17.string().regex(/^[0-9a-f]{64}$/)
|
|
5880
7764
|
}).strict();
|
|
5881
7765
|
|
|
5882
7766
|
class ReleaseCertificateError extends Error {
|
|
@@ -6004,7 +7888,7 @@ function parseReleaseCertificate(value, opencodeVersion, expectedShadowDigest) {
|
|
|
6004
7888
|
}
|
|
6005
7889
|
return certificate;
|
|
6006
7890
|
}
|
|
6007
|
-
var ShadowDivergenceCodeSchema =
|
|
7891
|
+
var ShadowDivergenceCodeSchema = z17.enum([
|
|
6008
7892
|
"status",
|
|
6009
7893
|
"order",
|
|
6010
7894
|
"roles",
|
|
@@ -6013,13 +7897,13 @@ var ShadowDivergenceCodeSchema = z16.enum([
|
|
|
6013
7897
|
"outcome"
|
|
6014
7898
|
]);
|
|
6015
7899
|
var RECOMPUTED_DIVERGENCE_CODES = ["fixes"];
|
|
6016
|
-
var RecomputedDivergenceCodeSchema =
|
|
6017
|
-
var SoakPolicySchema =
|
|
6018
|
-
minimumGenuineObservations:
|
|
6019
|
-
minimumDistinctDays:
|
|
6020
|
-
requireGenuineUsageOnAllPlatforms:
|
|
6021
|
-
supportedOpencodeVersions:
|
|
6022
|
-
criticalDivergenceCodes:
|
|
7900
|
+
var RecomputedDivergenceCodeSchema = z17.enum(RECOMPUTED_DIVERGENCE_CODES);
|
|
7901
|
+
var SoakPolicySchema = z17.object({
|
|
7902
|
+
minimumGenuineObservations: z17.number().int().positive(),
|
|
7903
|
+
minimumDistinctDays: z17.number().int().positive(),
|
|
7904
|
+
requireGenuineUsageOnAllPlatforms: z17.boolean(),
|
|
7905
|
+
supportedOpencodeVersions: z17.array(z17.string().min(1)).min(1),
|
|
7906
|
+
criticalDivergenceCodes: z17.array(RecomputedDivergenceCodeSchema).min(1)
|
|
6023
7907
|
}).strict();
|
|
6024
7908
|
var DEFAULT_SOAK_POLICY = {
|
|
6025
7909
|
minimumGenuineObservations: 100,
|
|
@@ -6028,46 +7912,46 @@ var DEFAULT_SOAK_POLICY = {
|
|
|
6028
7912
|
supportedOpencodeVersions: [...SUPPORTED_OPENCODE_VERSIONS],
|
|
6029
7913
|
criticalDivergenceCodes: ["fixes"]
|
|
6030
7914
|
};
|
|
6031
|
-
var SoakPlatformEnumSchema =
|
|
6032
|
-
var SoakPrivacyPairEvidenceSchema =
|
|
6033
|
-
surfacesScanned:
|
|
6034
|
-
rawFindings:
|
|
7915
|
+
var SoakPlatformEnumSchema = z17.enum(["linux", "win32", "darwin"]);
|
|
7916
|
+
var SoakPrivacyPairEvidenceSchema = z17.object({
|
|
7917
|
+
surfacesScanned: z17.number().int().nonnegative(),
|
|
7918
|
+
rawFindings: z17.number().int().nonnegative()
|
|
6035
7919
|
}).strict();
|
|
6036
|
-
var SoakDuplicateEffectPairEvidenceSchema =
|
|
6037
|
-
effectsExamined:
|
|
6038
|
-
duplicatesFound:
|
|
7920
|
+
var SoakDuplicateEffectPairEvidenceSchema = z17.object({
|
|
7921
|
+
effectsExamined: z17.number().int().nonnegative(),
|
|
7922
|
+
duplicatesFound: z17.number().int().nonnegative()
|
|
6039
7923
|
}).strict();
|
|
6040
|
-
var SoakModelVerificationPairEvidenceSchema =
|
|
6041
|
-
nodesChecked:
|
|
6042
|
-
unverified:
|
|
6043
|
-
mismatched:
|
|
7924
|
+
var SoakModelVerificationPairEvidenceSchema = z17.object({
|
|
7925
|
+
nodesChecked: z17.number().int().nonnegative(),
|
|
7926
|
+
unverified: z17.number().int().nonnegative(),
|
|
7927
|
+
mismatched: z17.number().int().nonnegative()
|
|
6044
7928
|
}).strict();
|
|
6045
|
-
var SoakEvidenceSchema =
|
|
6046
|
-
totalObservations:
|
|
6047
|
-
genuineUsageObservations:
|
|
6048
|
-
ciSyntheticObservations:
|
|
6049
|
-
recorderCount:
|
|
6050
|
-
ineligibleObservations:
|
|
6051
|
-
firstTimestamp:
|
|
6052
|
-
lastTimestamp:
|
|
6053
|
-
distinctDays:
|
|
6054
|
-
criticalDivergences:
|
|
7929
|
+
var SoakEvidenceSchema = z17.object({
|
|
7930
|
+
totalObservations: z17.number().int().nonnegative(),
|
|
7931
|
+
genuineUsageObservations: z17.number().int().nonnegative(),
|
|
7932
|
+
ciSyntheticObservations: z17.number().int().nonnegative(),
|
|
7933
|
+
recorderCount: z17.number().int().nonnegative(),
|
|
7934
|
+
ineligibleObservations: z17.number().int().nonnegative(),
|
|
7935
|
+
firstTimestamp: z17.string().datetime().nullable(),
|
|
7936
|
+
lastTimestamp: z17.string().datetime().nullable(),
|
|
7937
|
+
distinctDays: z17.number().int().nonnegative(),
|
|
7938
|
+
criticalDivergences: z17.number().int().nonnegative().nullable(),
|
|
6055
7939
|
privacy: SoakPrivacyPairEvidenceSchema.nullable(),
|
|
6056
7940
|
duplicateEffects: SoakDuplicateEffectPairEvidenceSchema.nullable(),
|
|
6057
7941
|
modelVerification: SoakModelVerificationPairEvidenceSchema.nullable(),
|
|
6058
|
-
platformsGenuine:
|
|
6059
|
-
platformsSynthetic:
|
|
6060
|
-
opencodeVersionsObserved:
|
|
6061
|
-
invalidChains:
|
|
7942
|
+
platformsGenuine: z17.array(SoakPlatformEnumSchema),
|
|
7943
|
+
platformsSynthetic: z17.array(SoakPlatformEnumSchema),
|
|
7944
|
+
opencodeVersionsObserved: z17.array(z17.string().min(1)),
|
|
7945
|
+
invalidChains: z17.number().int().nonnegative()
|
|
6062
7946
|
}).strict();
|
|
6063
|
-
var SoakCertificateSchema =
|
|
6064
|
-
version:
|
|
6065
|
-
certificate:
|
|
6066
|
-
trustBoundary:
|
|
7947
|
+
var SoakCertificateSchema = z17.object({
|
|
7948
|
+
version: z17.literal(1),
|
|
7949
|
+
certificate: z17.literal("graph-soak"),
|
|
7950
|
+
trustBoundary: z17.literal("contributors"),
|
|
6067
7951
|
policy: SoakPolicySchema,
|
|
6068
7952
|
evidence: SoakEvidenceSchema,
|
|
6069
|
-
verdict:
|
|
6070
|
-
failedGates:
|
|
7953
|
+
verdict: z17.enum(["pass", "fail"]),
|
|
7954
|
+
failedGates: z17.array(z17.enum([
|
|
6071
7955
|
"minimum-observations",
|
|
6072
7956
|
"minimum-duration",
|
|
6073
7957
|
"chain-integrity",
|
|
@@ -6078,8 +7962,8 @@ var SoakCertificateSchema = z16.object({
|
|
|
6078
7962
|
"os-diversity",
|
|
6079
7963
|
"opencode-pin"
|
|
6080
7964
|
])),
|
|
6081
|
-
ledgerDigest:
|
|
6082
|
-
digest:
|
|
7965
|
+
ledgerDigest: z17.string().regex(/^[0-9a-f]{64}$/),
|
|
7966
|
+
digest: z17.string().regex(/^[0-9a-f]{64}$/)
|
|
6083
7967
|
}).strict();
|
|
6084
7968
|
|
|
6085
7969
|
class SoakCertificateError extends Error {
|
|
@@ -6205,7 +8089,7 @@ function parseSoakCertificate(value, expectedPolicy, expectedLedgerDigest) {
|
|
|
6205
8089
|
}
|
|
6206
8090
|
|
|
6207
8091
|
// src/lifecycle/root.ts
|
|
6208
|
-
import { isAbsolute, normalize, relative, resolve as
|
|
8092
|
+
import { isAbsolute, normalize, relative as relative2, resolve as resolve4 } from "node:path";
|
|
6209
8093
|
|
|
6210
8094
|
// src/messages/lifecycleStorage.ts
|
|
6211
8095
|
var lifecycleStorageMessages = {
|
|
@@ -6214,12 +8098,12 @@ var lifecycleStorageMessages = {
|
|
|
6214
8098
|
|
|
6215
8099
|
// src/lifecycle/root.ts
|
|
6216
8100
|
var resolveLifecycleRoot = (options) => {
|
|
6217
|
-
const workspaceRoot =
|
|
8101
|
+
const workspaceRoot = resolve4(options.workspaceRoot);
|
|
6218
8102
|
if (isAbsolute(options.configuredRoot)) {
|
|
6219
|
-
return normalize(
|
|
8103
|
+
return normalize(resolve4(options.configuredRoot));
|
|
6220
8104
|
}
|
|
6221
|
-
const resolved =
|
|
6222
|
-
const workspaceRelative =
|
|
8105
|
+
const resolved = resolve4(workspaceRoot, options.configuredRoot);
|
|
8106
|
+
const workspaceRelative = relative2(workspaceRoot, resolved);
|
|
6223
8107
|
if (workspaceRelative === ".." || workspaceRelative.startsWith(`..\\`) || workspaceRelative.startsWith("../") || isAbsolute(workspaceRelative)) {
|
|
6224
8108
|
throw new Error(lifecycleStorageMessages.configuredRootEscapesWorkspace);
|
|
6225
8109
|
}
|
|
@@ -6227,16 +8111,16 @@ var resolveLifecycleRoot = (options) => {
|
|
|
6227
8111
|
};
|
|
6228
8112
|
|
|
6229
8113
|
// src/lifecycle/schema.ts
|
|
6230
|
-
import { z as
|
|
6231
|
-
var nonEmptyString =
|
|
6232
|
-
var nonNegativeInteger =
|
|
6233
|
-
var positiveInteger =
|
|
6234
|
-
var modelSelectionSchema2 =
|
|
8114
|
+
import { z as z18 } from "zod";
|
|
8115
|
+
var nonEmptyString = z18.string().min(1);
|
|
8116
|
+
var nonNegativeInteger = z18.number().int().nonnegative();
|
|
8117
|
+
var positiveInteger = z18.number().int().positive();
|
|
8118
|
+
var modelSelectionSchema2 = z18.object({
|
|
6235
8119
|
providerID: nonEmptyString,
|
|
6236
8120
|
modelID: nonEmptyString
|
|
6237
8121
|
}).strict();
|
|
6238
|
-
var lifecycleFailureSchema =
|
|
6239
|
-
class:
|
|
8122
|
+
var lifecycleFailureSchema = z18.object({
|
|
8123
|
+
class: z18.enum([
|
|
6240
8124
|
"routing-blocked",
|
|
6241
8125
|
"create-rejected",
|
|
6242
8126
|
"create-no-id",
|
|
@@ -6258,25 +8142,25 @@ var lifecycleFailureSchema = z17.object({
|
|
|
6258
8142
|
"interrupted",
|
|
6259
8143
|
"unknown"
|
|
6260
8144
|
]),
|
|
6261
|
-
statusCode:
|
|
6262
|
-
retryable:
|
|
8145
|
+
statusCode: z18.number().int().min(100).max(599).optional(),
|
|
8146
|
+
retryable: z18.boolean().optional()
|
|
6263
8147
|
}).strict();
|
|
6264
|
-
var lifecycleRootOperationSchema =
|
|
8148
|
+
var lifecycleRootOperationSchema = z18.object({
|
|
6265
8149
|
operationID: nonEmptyString,
|
|
6266
8150
|
taskID: nonEmptyString,
|
|
6267
|
-
kind:
|
|
8151
|
+
kind: z18.enum(["coordinator", "graph-node"]),
|
|
6268
8152
|
roleID: nonEmptyString,
|
|
6269
8153
|
agentID: nonEmptyString.optional(),
|
|
6270
8154
|
sessionID: nonEmptyString.optional()
|
|
6271
8155
|
}).strict();
|
|
6272
|
-
var lifecycleRunStartInputSchema =
|
|
8156
|
+
var lifecycleRunStartInputSchema = z18.object({
|
|
6273
8157
|
runID: nonEmptyString,
|
|
6274
|
-
source:
|
|
6275
|
-
executionAuthority:
|
|
8158
|
+
source: z18.enum(["plugin", "cli"]),
|
|
8159
|
+
executionAuthority: z18.enum(["coordinator", "graph"]),
|
|
6276
8160
|
root: lifecycleRootOperationSchema
|
|
6277
8161
|
}).strict();
|
|
6278
8162
|
var LifecycleRunMetadataSchema = lifecycleRunStartInputSchema.extend({
|
|
6279
|
-
version:
|
|
8163
|
+
version: z18.literal(1),
|
|
6280
8164
|
createdAt: nonNegativeInteger
|
|
6281
8165
|
}).strict();
|
|
6282
8166
|
var attemptRefShape = {
|
|
@@ -6288,34 +8172,34 @@ var attemptRefShape = {
|
|
|
6288
8172
|
retryIndex: nonNegativeInteger
|
|
6289
8173
|
};
|
|
6290
8174
|
var eventEnvelopeShape = {
|
|
6291
|
-
v:
|
|
8175
|
+
v: z18.literal(1),
|
|
6292
8176
|
seq: nonNegativeInteger,
|
|
6293
8177
|
runID: nonEmptyString,
|
|
6294
8178
|
at: nonNegativeInteger
|
|
6295
8179
|
};
|
|
6296
8180
|
var runStartedBodyShape = {
|
|
6297
|
-
type:
|
|
6298
|
-
source:
|
|
6299
|
-
executionAuthority:
|
|
8181
|
+
type: z18.literal("run.started"),
|
|
8182
|
+
source: z18.enum(["plugin", "cli"]),
|
|
8183
|
+
executionAuthority: z18.enum(["coordinator", "graph"]),
|
|
6300
8184
|
root: lifecycleRootOperationSchema
|
|
6301
8185
|
};
|
|
6302
8186
|
var operationQueuedBodyShape = {
|
|
6303
|
-
type:
|
|
8187
|
+
type: z18.literal("operation.queued"),
|
|
6304
8188
|
operationID: nonEmptyString,
|
|
6305
8189
|
taskID: nonEmptyString,
|
|
6306
|
-
kind:
|
|
8190
|
+
kind: z18.enum(["role", "graph-node"]),
|
|
6307
8191
|
roleID: nonEmptyString,
|
|
6308
8192
|
agentID: nonEmptyString.optional(),
|
|
6309
8193
|
parentOperationID: nonEmptyString,
|
|
6310
|
-
dependsOnOperationIDs:
|
|
8194
|
+
dependsOnOperationIDs: z18.array(nonEmptyString).readonly()
|
|
6311
8195
|
};
|
|
6312
8196
|
var modelSelectedBodyShape = {
|
|
6313
|
-
type:
|
|
8197
|
+
type: z18.literal("attempt.model-selected"),
|
|
6314
8198
|
...attemptRefShape,
|
|
6315
8199
|
decisionID: nonEmptyString,
|
|
6316
8200
|
model: modelSelectionSchema2,
|
|
6317
|
-
routeKind:
|
|
6318
|
-
selectionCause:
|
|
8201
|
+
routeKind: z18.enum(["local", "frontier"]),
|
|
8202
|
+
selectionCause: z18.enum([
|
|
6319
8203
|
"initial",
|
|
6320
8204
|
"retry-incomplete",
|
|
6321
8205
|
"retry-transport",
|
|
@@ -6325,31 +8209,31 @@ var modelSelectedBodyShape = {
|
|
|
6325
8209
|
runtimeID: nonEmptyString.optional()
|
|
6326
8210
|
};
|
|
6327
8211
|
var attemptQueuedBodyShape = {
|
|
6328
|
-
type:
|
|
8212
|
+
type: z18.literal("attempt.queued"),
|
|
6329
8213
|
...attemptRefShape,
|
|
6330
8214
|
runtimeID: nonEmptyString.optional()
|
|
6331
8215
|
};
|
|
6332
8216
|
var attemptStartedBodyShape = {
|
|
6333
|
-
type:
|
|
8217
|
+
type: z18.literal("attempt.started"),
|
|
6334
8218
|
...attemptRefShape
|
|
6335
8219
|
};
|
|
6336
8220
|
var sessionCreatedBodyShape = {
|
|
6337
|
-
type:
|
|
8221
|
+
type: z18.literal("session.created"),
|
|
6338
8222
|
...attemptRefShape,
|
|
6339
8223
|
sessionID: nonEmptyString,
|
|
6340
8224
|
parentSessionID: nonEmptyString.optional()
|
|
6341
8225
|
};
|
|
6342
8226
|
var attemptTerminalBodyShape = {
|
|
6343
|
-
type:
|
|
8227
|
+
type: z18.literal("attempt.terminal"),
|
|
6344
8228
|
...attemptRefShape,
|
|
6345
|
-
outcome:
|
|
8229
|
+
outcome: z18.enum([
|
|
6346
8230
|
"succeeded",
|
|
6347
8231
|
"failed",
|
|
6348
8232
|
"cancelled",
|
|
6349
8233
|
"interrupted",
|
|
6350
8234
|
"unknown"
|
|
6351
8235
|
]),
|
|
6352
|
-
continuation:
|
|
8236
|
+
continuation: z18.enum([
|
|
6353
8237
|
"none",
|
|
6354
8238
|
"retry-same-model",
|
|
6355
8239
|
"fallback-next-model",
|
|
@@ -6359,10 +8243,10 @@ var attemptTerminalBodyShape = {
|
|
|
6359
8243
|
failure: lifecycleFailureSchema.optional()
|
|
6360
8244
|
};
|
|
6361
8245
|
var operationTerminalBodyShape = {
|
|
6362
|
-
type:
|
|
8246
|
+
type: z18.literal("operation.terminal"),
|
|
6363
8247
|
operationID: nonEmptyString,
|
|
6364
8248
|
taskID: nonEmptyString,
|
|
6365
|
-
outcome:
|
|
8249
|
+
outcome: z18.enum([
|
|
6366
8250
|
"succeeded",
|
|
6367
8251
|
"failed",
|
|
6368
8252
|
"cancelled",
|
|
@@ -6375,8 +8259,8 @@ var operationTerminalBodyShape = {
|
|
|
6375
8259
|
failure: lifecycleFailureSchema.optional()
|
|
6376
8260
|
};
|
|
6377
8261
|
var runTerminalBodyShape = {
|
|
6378
|
-
type:
|
|
6379
|
-
outcome:
|
|
8262
|
+
type: z18.literal("run.terminal"),
|
|
8263
|
+
outcome: z18.enum([
|
|
6380
8264
|
"succeeded",
|
|
6381
8265
|
"failed",
|
|
6382
8266
|
"cancelled",
|
|
@@ -6387,39 +8271,39 @@ var runTerminalBodyShape = {
|
|
|
6387
8271
|
failure: lifecycleFailureSchema.optional()
|
|
6388
8272
|
};
|
|
6389
8273
|
var bodySchemas = [
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
8274
|
+
z18.object(runStartedBodyShape).strict(),
|
|
8275
|
+
z18.object(operationQueuedBodyShape).strict(),
|
|
8276
|
+
z18.object(modelSelectedBodyShape).strict(),
|
|
8277
|
+
z18.object(attemptQueuedBodyShape).strict(),
|
|
8278
|
+
z18.object(attemptStartedBodyShape).strict(),
|
|
8279
|
+
z18.object(sessionCreatedBodyShape).strict(),
|
|
8280
|
+
z18.object(attemptTerminalBodyShape).strict(),
|
|
8281
|
+
z18.object(operationTerminalBodyShape).strict(),
|
|
8282
|
+
z18.object(runTerminalBodyShape).strict()
|
|
6399
8283
|
];
|
|
6400
8284
|
var appendBodySchemas = bodySchemas.slice(1);
|
|
6401
|
-
var LifecycleAppendEventSchema =
|
|
6402
|
-
var LifecycleEventSchema =
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
8285
|
+
var LifecycleAppendEventSchema = z18.discriminatedUnion("type", appendBodySchemas);
|
|
8286
|
+
var LifecycleEventSchema = z18.discriminatedUnion("type", [
|
|
8287
|
+
z18.object({ ...eventEnvelopeShape, ...runStartedBodyShape }).strict(),
|
|
8288
|
+
z18.object({ ...eventEnvelopeShape, ...operationQueuedBodyShape }).strict(),
|
|
8289
|
+
z18.object({ ...eventEnvelopeShape, ...modelSelectedBodyShape }).strict(),
|
|
8290
|
+
z18.object({ ...eventEnvelopeShape, ...attemptQueuedBodyShape }).strict(),
|
|
8291
|
+
z18.object({ ...eventEnvelopeShape, ...attemptStartedBodyShape }).strict(),
|
|
8292
|
+
z18.object({ ...eventEnvelopeShape, ...sessionCreatedBodyShape }).strict(),
|
|
8293
|
+
z18.object({ ...eventEnvelopeShape, ...attemptTerminalBodyShape }).strict(),
|
|
8294
|
+
z18.object({ ...eventEnvelopeShape, ...operationTerminalBodyShape }).strict(),
|
|
8295
|
+
z18.object({ ...eventEnvelopeShape, ...runTerminalBodyShape }).strict()
|
|
6412
8296
|
]);
|
|
6413
|
-
var LifecycleWriterLeaseInputSchema =
|
|
6414
|
-
writer:
|
|
8297
|
+
var LifecycleWriterLeaseInputSchema = z18.object({
|
|
8298
|
+
writer: z18.object({
|
|
6415
8299
|
processID: positiveInteger,
|
|
6416
8300
|
processInstanceID: nonEmptyString
|
|
6417
8301
|
}).strict(),
|
|
6418
8302
|
now: nonNegativeInteger,
|
|
6419
8303
|
leaseDurationMs: positiveInteger
|
|
6420
8304
|
}).strict();
|
|
6421
|
-
var LifecycleWriterLeaseSchema =
|
|
6422
|
-
version:
|
|
8305
|
+
var LifecycleWriterLeaseSchema = z18.object({
|
|
8306
|
+
version: z18.literal(1),
|
|
6423
8307
|
runID: nonEmptyString,
|
|
6424
8308
|
writerToken: nonEmptyString,
|
|
6425
8309
|
processID: positiveInteger,
|
|
@@ -7304,9 +9188,9 @@ function createRuntimeConcurrencyLimiter(options) {
|
|
|
7304
9188
|
}
|
|
7305
9189
|
const state = stateFor(runtimeId);
|
|
7306
9190
|
const queuedAt = options.now();
|
|
7307
|
-
return new Promise((
|
|
9191
|
+
return new Promise((resolve5) => {
|
|
7308
9192
|
state.queues[priority].push((release) => {
|
|
7309
|
-
|
|
9193
|
+
resolve5({ release, waitedMs: options.now() - queuedAt });
|
|
7310
9194
|
});
|
|
7311
9195
|
});
|
|
7312
9196
|
},
|
|
@@ -7341,30 +9225,82 @@ function embeddingsEndpoint(baseURL) {
|
|
|
7341
9225
|
return `${normalizeBaseURL(baseURL)}/embeddings`;
|
|
7342
9226
|
}
|
|
7343
9227
|
function errorMessage(error) {
|
|
9228
|
+
const chain = errorChain(error);
|
|
9229
|
+
const dnsDetail = dnsErrorMessage(chain);
|
|
9230
|
+
if (dnsDetail !== undefined) {
|
|
9231
|
+
return dnsDetail;
|
|
9232
|
+
}
|
|
9233
|
+
for (const entry of chain) {
|
|
9234
|
+
if (!(entry instanceof Error)) {
|
|
9235
|
+
continue;
|
|
9236
|
+
}
|
|
9237
|
+
if (!isGenericTransportMessage(entry.message)) {
|
|
9238
|
+
return entry.message;
|
|
9239
|
+
}
|
|
9240
|
+
}
|
|
7344
9241
|
if (error instanceof Error) {
|
|
7345
9242
|
return error.message;
|
|
7346
9243
|
}
|
|
7347
9244
|
return String(error);
|
|
7348
9245
|
}
|
|
9246
|
+
function errorChain(error) {
|
|
9247
|
+
const chain = [];
|
|
9248
|
+
const seen = new Set;
|
|
9249
|
+
let current = error;
|
|
9250
|
+
while (current !== undefined && !seen.has(current)) {
|
|
9251
|
+
chain.push(current);
|
|
9252
|
+
seen.add(current);
|
|
9253
|
+
if (typeof current === "object" && current !== null && "cause" in current) {
|
|
9254
|
+
current = current.cause;
|
|
9255
|
+
continue;
|
|
9256
|
+
}
|
|
9257
|
+
break;
|
|
9258
|
+
}
|
|
9259
|
+
return chain;
|
|
9260
|
+
}
|
|
9261
|
+
function errorCode(error) {
|
|
9262
|
+
return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : undefined;
|
|
9263
|
+
}
|
|
9264
|
+
function errorHostname(error) {
|
|
9265
|
+
return typeof error === "object" && error !== null && "hostname" in error && typeof error.hostname === "string" ? error.hostname : undefined;
|
|
9266
|
+
}
|
|
9267
|
+
function isGenericTransportMessage(message) {
|
|
9268
|
+
const normalized = message.trim().toLowerCase();
|
|
9269
|
+
return normalized.length === 0 || normalized === "fetch failed" || normalized === "network error" || normalized === "network request failed";
|
|
9270
|
+
}
|
|
9271
|
+
function dnsErrorMessage(chain) {
|
|
9272
|
+
for (const entry of chain) {
|
|
9273
|
+
const code = errorCode(entry);
|
|
9274
|
+
if (code !== "ENOTFOUND" && code !== "EAI_AGAIN") {
|
|
9275
|
+
continue;
|
|
9276
|
+
}
|
|
9277
|
+
if (entry instanceof Error && !isGenericTransportMessage(entry.message)) {
|
|
9278
|
+
return entry.message;
|
|
9279
|
+
}
|
|
9280
|
+
const hostname = errorHostname(entry);
|
|
9281
|
+
return hostname !== undefined && hostname.length > 0 ? localRuntimeMessages.dnsLookupFailedFor(hostname, code) : localRuntimeMessages.dnsLookupFailed(code);
|
|
9282
|
+
}
|
|
9283
|
+
return;
|
|
9284
|
+
}
|
|
7349
9285
|
async function listOpenAICompatibleModels(baseURL, fetch) {
|
|
7350
9286
|
const response = await fetch(modelsEndpoint(baseURL), {
|
|
7351
9287
|
method: "GET",
|
|
7352
9288
|
headers: { accept: "application/json" }
|
|
7353
9289
|
});
|
|
7354
9290
|
if (!response.ok) {
|
|
7355
|
-
throw new Error(
|
|
9291
|
+
throw new Error(localRuntimeMessages.modelListHttpError(response.status));
|
|
7356
9292
|
}
|
|
7357
9293
|
let payload;
|
|
7358
9294
|
try {
|
|
7359
9295
|
payload = await response.json();
|
|
7360
9296
|
} catch (error) {
|
|
7361
|
-
throw new Error(
|
|
9297
|
+
throw new Error(localRuntimeMessages.malformedModelsJson(errorMessage(error)));
|
|
7362
9298
|
}
|
|
7363
9299
|
return parseOpenAIModels(payload);
|
|
7364
9300
|
}
|
|
7365
9301
|
function parseOpenAIModels(payload) {
|
|
7366
9302
|
if (!isObject(payload) || !Array.isArray(payload.data)) {
|
|
7367
|
-
throw new Error(
|
|
9303
|
+
throw new Error(localRuntimeMessages.malformedModelsResponseExpectedDataArray);
|
|
7368
9304
|
}
|
|
7369
9305
|
return payload.data.map(parseOpenAIModel);
|
|
7370
9306
|
}
|
|
@@ -7399,7 +9335,7 @@ async function probeOpenAICompatibleRuntime(input) {
|
|
|
7399
9335
|
}
|
|
7400
9336
|
function parseOpenAIModel(value) {
|
|
7401
9337
|
if (!isObject(value) || typeof value.id !== "string" || value.id.length === 0) {
|
|
7402
|
-
throw new Error(
|
|
9338
|
+
throw new Error(localRuntimeMessages.malformedModelsResponseModelId);
|
|
7403
9339
|
}
|
|
7404
9340
|
const contextWindow = readContextWindow(value);
|
|
7405
9341
|
const model = {
|
|
@@ -7597,9 +9533,12 @@ var NON_TEXT_LABELS = new Set([
|
|
|
7597
9533
|
"embedding",
|
|
7598
9534
|
"reranking"
|
|
7599
9535
|
]);
|
|
7600
|
-
var PARALLEL_ARG = /(?:^|\s)(?:--parallel|-np)[\s=]+(\d+)(
|
|
9536
|
+
var PARALLEL_ARG = /(?:^|\s)(?:--parallel|-np)[\s=]+(\d+)(?=\s|$)/;
|
|
7601
9537
|
var PARALLEL_FLAGS = new Set(["--parallel", "-np"]);
|
|
7602
9538
|
var PARALLEL_FUSED = /^(?:--parallel|-np)=(\d+)$/;
|
|
9539
|
+
var CTX_SIZE_FUSED = /^--ctx-size=(\d+)$/;
|
|
9540
|
+
var CTX_SIZE_FLAGS = new Set(["--ctx-size"]);
|
|
9541
|
+
var CTX_SIZE_ARG = /(?:^|\s)--ctx-size[\s=]+(\d+)(?=\s|$)/;
|
|
7603
9542
|
function createLemonadeAdapter() {
|
|
7604
9543
|
const listModels = async (options) => {
|
|
7605
9544
|
const baseURL = normalizeBaseURL(options.baseURL ?? LEMONADE_DEFAULT_BASE_URL);
|
|
@@ -7638,13 +9577,13 @@ async function listLemonadeModels(baseURL, fetch) {
|
|
|
7638
9577
|
headers: { accept: "application/json" }
|
|
7639
9578
|
});
|
|
7640
9579
|
if (!response.ok) {
|
|
7641
|
-
throw new Error(
|
|
9580
|
+
throw new Error(localRuntimeMessages.modelListHttpError(response.status));
|
|
7642
9581
|
}
|
|
7643
9582
|
let payload;
|
|
7644
9583
|
try {
|
|
7645
9584
|
payload = await response.json();
|
|
7646
9585
|
} catch (error) {
|
|
7647
|
-
throw new Error(
|
|
9586
|
+
throw new Error(localRuntimeMessages.malformedModelsJson(errorMessage(error)));
|
|
7648
9587
|
}
|
|
7649
9588
|
const nonText = readNonTextModelIDs(payload);
|
|
7650
9589
|
return parseOpenAIModels(payload).filter((model) => !nonText.has(model.modelID));
|
|
@@ -7695,13 +9634,19 @@ async function readLoadedModels(baseURL, fetch) {
|
|
|
7695
9634
|
if (entry.loaded === false) {
|
|
7696
9635
|
continue;
|
|
7697
9636
|
}
|
|
7698
|
-
loaded.set(entry.model_name, {
|
|
9637
|
+
loaded.set(entry.model_name, {
|
|
9638
|
+
slots: readSlotCount(entry),
|
|
9639
|
+
totalContextWindow: readLoadedContextWindow(entry)
|
|
9640
|
+
});
|
|
7699
9641
|
}
|
|
7700
9642
|
return loaded;
|
|
7701
9643
|
}
|
|
7702
9644
|
function readSlotCount(entry) {
|
|
7703
9645
|
return slotsFromLlamacppArgs(entry) ?? slotsFromLaunchCommand(entry);
|
|
7704
9646
|
}
|
|
9647
|
+
function readLoadedContextWindow(entry) {
|
|
9648
|
+
return contextWindowFromRecipeOptions(entry) ?? contextWindowFromLaunchCommand(entry);
|
|
9649
|
+
}
|
|
7705
9650
|
function slotsFromLlamacppArgs(entry) {
|
|
7706
9651
|
const options = entry.recipe_options;
|
|
7707
9652
|
if (!isObject2(options) || typeof options.llamacpp_args !== "string") {
|
|
@@ -7712,7 +9657,7 @@ function slotsFromLlamacppArgs(entry) {
|
|
|
7712
9657
|
}
|
|
7713
9658
|
function slotsFromLaunchCommand(entry) {
|
|
7714
9659
|
const argv = entry.launch_command;
|
|
7715
|
-
if (!Array.isArray(argv)) {
|
|
9660
|
+
if (!Array.isArray(argv) || !launchCommandLooksLikeLlamacpp(argv)) {
|
|
7716
9661
|
return;
|
|
7717
9662
|
}
|
|
7718
9663
|
for (let index = 0;index < argv.length; index += 1) {
|
|
@@ -7738,23 +9683,119 @@ function slotsFromLaunchCommand(entry) {
|
|
|
7738
9683
|
}
|
|
7739
9684
|
return;
|
|
7740
9685
|
}
|
|
9686
|
+
function contextWindowFromRecipeOptions(entry) {
|
|
9687
|
+
const options = entry.recipe_options;
|
|
9688
|
+
if (!isObject2(options) || !hasLlamacppEvidence(entry)) {
|
|
9689
|
+
return;
|
|
9690
|
+
}
|
|
9691
|
+
const direct = positiveIntegerValue(options.ctx_size);
|
|
9692
|
+
if (direct !== undefined) {
|
|
9693
|
+
return direct;
|
|
9694
|
+
}
|
|
9695
|
+
if (typeof options.llamacpp_args !== "string") {
|
|
9696
|
+
return;
|
|
9697
|
+
}
|
|
9698
|
+
const match = CTX_SIZE_ARG.exec(options.llamacpp_args);
|
|
9699
|
+
return match === null ? undefined : positiveSlotCount(match[1]);
|
|
9700
|
+
}
|
|
9701
|
+
function contextWindowFromLaunchCommand(entry) {
|
|
9702
|
+
const argv = entry.launch_command;
|
|
9703
|
+
if (!Array.isArray(argv) || !launchCommandLooksLikeLlamacpp(argv)) {
|
|
9704
|
+
return;
|
|
9705
|
+
}
|
|
9706
|
+
for (let index = 0;index < argv.length; index += 1) {
|
|
9707
|
+
const token = argv[index];
|
|
9708
|
+
if (typeof token !== "string") {
|
|
9709
|
+
continue;
|
|
9710
|
+
}
|
|
9711
|
+
const fused = CTX_SIZE_FUSED.exec(token);
|
|
9712
|
+
if (fused !== null) {
|
|
9713
|
+
const contextWindow = positiveSlotCount(fused[1]);
|
|
9714
|
+
if (contextWindow !== undefined) {
|
|
9715
|
+
return contextWindow;
|
|
9716
|
+
}
|
|
9717
|
+
continue;
|
|
9718
|
+
}
|
|
9719
|
+
if (CTX_SIZE_FLAGS.has(token)) {
|
|
9720
|
+
const next = argv[index + 1];
|
|
9721
|
+
const contextWindow = typeof next === "string" ? positiveSlotCount(next) : undefined;
|
|
9722
|
+
if (contextWindow !== undefined) {
|
|
9723
|
+
return contextWindow;
|
|
9724
|
+
}
|
|
9725
|
+
}
|
|
9726
|
+
}
|
|
9727
|
+
return;
|
|
9728
|
+
}
|
|
7741
9729
|
function positiveSlotCount(raw) {
|
|
7742
9730
|
if (raw === undefined || !/^\d+$/.test(raw)) {
|
|
7743
9731
|
return;
|
|
7744
9732
|
}
|
|
7745
|
-
const parsed = Number.parseInt(raw, 10);
|
|
7746
|
-
return Number.
|
|
9733
|
+
const parsed = Number.parseInt(raw, 10);
|
|
9734
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined;
|
|
9735
|
+
}
|
|
9736
|
+
function positiveIntegerValue(value) {
|
|
9737
|
+
if (typeof value === "number") {
|
|
9738
|
+
return Number.isSafeInteger(value) && value > 0 ? value : undefined;
|
|
9739
|
+
}
|
|
9740
|
+
return typeof value === "string" ? positiveSlotCount(value) : undefined;
|
|
9741
|
+
}
|
|
9742
|
+
function hasLlamacppEvidence(entry) {
|
|
9743
|
+
const recipe = entry.recipe;
|
|
9744
|
+
if (typeof recipe === "string" && recipe.toLowerCase().includes("llamacpp")) {
|
|
9745
|
+
return true;
|
|
9746
|
+
}
|
|
9747
|
+
const options = entry.recipe_options;
|
|
9748
|
+
if (isObject2(options) && typeof options.llamacpp_args === "string") {
|
|
9749
|
+
return true;
|
|
9750
|
+
}
|
|
9751
|
+
return Array.isArray(entry.launch_command) && launchCommandLooksLikeLlamacpp(entry.launch_command);
|
|
9752
|
+
}
|
|
9753
|
+
function launchCommandLooksLikeLlamacpp(argv) {
|
|
9754
|
+
const firstToken = argv.find((token) => typeof token === "string" && token.length > 0);
|
|
9755
|
+
if (firstToken === undefined) {
|
|
9756
|
+
return false;
|
|
9757
|
+
}
|
|
9758
|
+
const normalized = firstToken.replace(/\\/g, "/").toLowerCase();
|
|
9759
|
+
return normalized === "llama-server" || normalized.endsWith("/llama-server") || normalized === "llama-server.exe" || normalized.endsWith("/llama-server.exe");
|
|
9760
|
+
}
|
|
9761
|
+
function derivedConservativeContextWindow(reportedContextWindow, loaded) {
|
|
9762
|
+
if (loaded.totalContextWindow === undefined || loaded.slots === undefined || loaded.slots <= 0) {
|
|
9763
|
+
return;
|
|
9764
|
+
}
|
|
9765
|
+
const derived = Math.floor(loaded.totalContextWindow / loaded.slots);
|
|
9766
|
+
if (derived <= 0) {
|
|
9767
|
+
return;
|
|
9768
|
+
}
|
|
9769
|
+
return reportedContextWindow === undefined ? derived : Math.min(reportedContextWindow, derived);
|
|
9770
|
+
}
|
|
9771
|
+
function withoutUnverifiedContextWindow(model) {
|
|
9772
|
+
const {
|
|
9773
|
+
contextWindow: _contextWindow,
|
|
9774
|
+
contextWindowProvenance: _contextWindowProvenance,
|
|
9775
|
+
...withoutContext
|
|
9776
|
+
} = model;
|
|
9777
|
+
return withoutContext;
|
|
7747
9778
|
}
|
|
7748
9779
|
function enrichWithLoadState(models, loaded) {
|
|
7749
9780
|
if (loaded === undefined) {
|
|
7750
|
-
return
|
|
9781
|
+
return models.map((model) => withoutUnverifiedContextWindow(model));
|
|
7751
9782
|
}
|
|
7752
9783
|
return models.map((model) => {
|
|
9784
|
+
const base = withoutUnverifiedContextWindow(model);
|
|
7753
9785
|
const hit = loaded.get(model.modelID);
|
|
7754
9786
|
if (hit === undefined) {
|
|
7755
|
-
return { ...
|
|
9787
|
+
return { ...base, loaded: false };
|
|
7756
9788
|
}
|
|
7757
|
-
|
|
9789
|
+
const contextWindow = derivedConservativeContextWindow(model.contextWindow, hit);
|
|
9790
|
+
return {
|
|
9791
|
+
...base,
|
|
9792
|
+
loaded: true,
|
|
9793
|
+
...hit.slots !== undefined ? { slots: hit.slots } : {},
|
|
9794
|
+
...contextWindow !== undefined ? {
|
|
9795
|
+
contextWindow,
|
|
9796
|
+
contextWindowProvenance: "derived-conservative"
|
|
9797
|
+
} : {}
|
|
9798
|
+
};
|
|
7758
9799
|
});
|
|
7759
9800
|
}
|
|
7760
9801
|
function isObject2(value) {
|
|
@@ -8007,24 +10048,24 @@ var reportArtifactExists = async (reportPath) => {
|
|
|
8007
10048
|
};
|
|
8008
10049
|
|
|
8009
10050
|
// src/orchestrator/reportArtifactReader.ts
|
|
8010
|
-
import { readFile as
|
|
10051
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
8011
10052
|
var readReportArtifact = async (reportPath) => {
|
|
8012
10053
|
try {
|
|
8013
|
-
return await
|
|
10054
|
+
return await readFile3(reportPath, "utf8");
|
|
8014
10055
|
} catch {
|
|
8015
10056
|
return;
|
|
8016
10057
|
}
|
|
8017
10058
|
};
|
|
8018
10059
|
|
|
8019
10060
|
// src/orchestrator/roster.ts
|
|
8020
|
-
import { z as
|
|
8021
|
-
var RosterEntrySchema =
|
|
8022
|
-
roleID:
|
|
8023
|
-
agentName:
|
|
10061
|
+
import { z as z19 } from "zod";
|
|
10062
|
+
var RosterEntrySchema = z19.object({
|
|
10063
|
+
roleID: z19.string().min(1),
|
|
10064
|
+
agentName: z19.string().min(1)
|
|
8024
10065
|
}).strict();
|
|
8025
|
-
var RosterSchema =
|
|
8026
|
-
universe:
|
|
8027
|
-
entries:
|
|
10066
|
+
var RosterSchema = z19.object({
|
|
10067
|
+
universe: z19.string().min(1),
|
|
10068
|
+
entries: z19.array(RosterEntrySchema)
|
|
8028
10069
|
}).strict();
|
|
8029
10070
|
var ROSTER_JSON_FENCE = /```json\s*([\s\S]*?)```/;
|
|
8030
10071
|
|
|
@@ -8393,9 +10434,9 @@ async function withTimeout(promise, timeoutMs) {
|
|
|
8393
10434
|
return { kind: "settled", value: await promise };
|
|
8394
10435
|
}
|
|
8395
10436
|
let timeoutID;
|
|
8396
|
-
const timeout = new Promise((
|
|
10437
|
+
const timeout = new Promise((resolve5) => {
|
|
8397
10438
|
timeoutID = setTimeout(() => {
|
|
8398
|
-
|
|
10439
|
+
resolve5({ kind: "timeout" });
|
|
8399
10440
|
}, timeoutMs);
|
|
8400
10441
|
});
|
|
8401
10442
|
try {
|
|
@@ -8415,8 +10456,8 @@ async function beforeDeadline(request, deadline, deps) {
|
|
|
8415
10456
|
const controller = new AbortController;
|
|
8416
10457
|
let timeoutID;
|
|
8417
10458
|
const observedRequest = Promise.resolve().then(() => request(controller.signal)).then((value) => ({ kind: "settled", value }), (error) => ({ kind: "rejected", error }));
|
|
8418
|
-
const timeout = new Promise((
|
|
8419
|
-
timeoutID = setTimeout(() =>
|
|
10459
|
+
const timeout = new Promise((resolve5) => {
|
|
10460
|
+
timeoutID = setTimeout(() => resolve5({ kind: "timeout" }), remainingMs);
|
|
8420
10461
|
});
|
|
8421
10462
|
try {
|
|
8422
10463
|
const outcome = await Promise.race([observedRequest, timeout]);
|
|
@@ -8936,259 +10977,46 @@ function sessionEndpointEventFrom(sessionID, url, now, meta = {}) {
|
|
|
8936
10977
|
}
|
|
8937
10978
|
return event;
|
|
8938
10979
|
}
|
|
8939
|
-
var ACTIVITY_SUMMARIES = {
|
|
8940
|
-
"session.created": "Session created",
|
|
8941
|
-
"session.idle": "Session idle",
|
|
8942
|
-
"session.error": "Session error"
|
|
8943
|
-
};
|
|
8944
|
-
function sessionIDFromEvent(event) {
|
|
8945
|
-
const properties = event.properties;
|
|
8946
|
-
if (properties === null || typeof properties !== "object") {
|
|
8947
|
-
return;
|
|
8948
|
-
}
|
|
8949
|
-
const record = properties;
|
|
8950
|
-
if (typeof record.sessionID === "string") {
|
|
8951
|
-
return record.sessionID;
|
|
8952
|
-
}
|
|
8953
|
-
if (typeof record.info?.id === "string") {
|
|
8954
|
-
return record.info.id;
|
|
8955
|
-
}
|
|
8956
|
-
return;
|
|
8957
|
-
}
|
|
8958
|
-
function activityEventFrom(event, now) {
|
|
8959
|
-
const summary = ACTIVITY_SUMMARIES[event.type];
|
|
8960
|
-
if (summary === undefined) {
|
|
8961
|
-
return;
|
|
8962
|
-
}
|
|
8963
|
-
const sessionID = sessionIDFromEvent(event);
|
|
8964
|
-
if (sessionID === undefined) {
|
|
8965
|
-
return;
|
|
8966
|
-
}
|
|
8967
|
-
return {
|
|
8968
|
-
v: EVENT_SCHEMA_VERSION,
|
|
8969
|
-
type: "activity",
|
|
8970
|
-
ts: now(),
|
|
8971
|
-
sessionID,
|
|
8972
|
-
kind: "agent",
|
|
8973
|
-
summary
|
|
8974
|
-
};
|
|
8975
|
-
}
|
|
8976
|
-
|
|
8977
|
-
// src/plugin/commandTool.ts
|
|
8978
|
-
import { tool } from "@opencode-ai/plugin";
|
|
8979
|
-
|
|
8980
|
-
// src/messages/commands.ts
|
|
8981
|
-
var clearCacheMessages = {
|
|
8982
|
-
header: "openteam clear-cache — frozen plugin cache entries:",
|
|
8983
|
-
columns: {
|
|
8984
|
-
specDir: "spec dir",
|
|
8985
|
-
pinned: "spec-pinned",
|
|
8986
|
-
installed: "installed",
|
|
8987
|
-
mtime: "mtime"
|
|
8988
|
-
},
|
|
8989
|
-
reparseSkipSuffix: " [SKIP — reparse point]",
|
|
8990
|
-
deletedLabel: "deleted.",
|
|
8991
|
-
lockedLabel: (message) => `[LOCKED] ${message}`,
|
|
8992
|
-
pathOutsideWarning: (specDir, absolutePath) => ` ⚠ ${specDir}: path outside cacheRoot (${absolutePath}), skipped.`,
|
|
8993
|
-
processed: (count) => `${count} entry(ies) processed.`,
|
|
8994
|
-
found: (count) => `${count} entry(ies) found. Use --delete to remove them.`
|
|
8995
|
-
};
|
|
8996
|
-
var baselineMessages = {
|
|
8997
|
-
effectiveAuto: "cheapest-capable (auto)",
|
|
8998
|
-
pinnedSuffix: (ref) => `${ref} (pinned)`,
|
|
8999
|
-
summary: (params) => [
|
|
9000
|
-
"openteam baseline:",
|
|
9001
|
-
` mode: ${params.mode}`,
|
|
9002
|
-
` pinned: ${params.pinned}`,
|
|
9003
|
-
` hardDefault: ${params.hardDefault}`,
|
|
9004
|
-
` effective: ${params.effective}`
|
|
9005
|
-
],
|
|
9006
|
-
invalidModel: (input) => `Invalid model "${input}". Use the provider/model format, e.g. anthropic/claude-sonnet-4-5.`,
|
|
9007
|
-
pinnedTo: (ref) => `Baseline pinned to ${ref} (pinned mode).`,
|
|
9008
|
-
autoMode: "Baseline set to auto mode (cheapest-capable)."
|
|
9009
|
-
};
|
|
9010
|
-
var localMessages = {
|
|
9011
|
-
help: {
|
|
9012
|
-
status: " openteam local status Show the execution mode (local / frontier / mixed)",
|
|
9013
|
-
off: " openteam local off Use frontier models only",
|
|
9014
|
-
only: " openteam local only Use local models only",
|
|
9015
|
-
on: " openteam local on Enable mixed local/frontier execution"
|
|
9016
|
-
},
|
|
9017
|
-
noRuntimes: "none",
|
|
9018
|
-
modeFrontier: "frontier",
|
|
9019
|
-
modeLocal: "local",
|
|
9020
|
-
modeMixed: "mixed",
|
|
9021
|
-
summary: (params) => [
|
|
9022
|
-
"openteam local:",
|
|
9023
|
-
` execution mode: ${params.mode}`,
|
|
9024
|
-
` local runtimes: ${params.runtimes}`
|
|
9025
|
-
],
|
|
9026
|
-
frontierOnlyNoChange: "No change: execution mode is already frontier.",
|
|
9027
|
-
frontierOnlyEnabled: "Frontier execution enabled.",
|
|
9028
|
-
localOnlyNoRuntimes: "Cannot enable local execution: no enabled local runtime is configured. Run 'openteam setup' or enable a local runtime in .opencode/openteam.json first.",
|
|
9029
|
-
localOnlyNoChange: "No change: execution mode is already local.",
|
|
9030
|
-
localOnlyEnabled: "Local execution enabled.",
|
|
9031
|
-
localFirstNoChange: "No change: execution mode is already mixed.",
|
|
9032
|
-
localFirstReEnabled: "Mixed local/frontier execution enabled. Make sure each configured provider is reachable.",
|
|
9033
|
-
unknownSubcommand: (subcommand, help) => `Unknown local subcommand: ${subcommand}
|
|
9034
|
-
|
|
9035
|
-
${help}`
|
|
9036
|
-
};
|
|
9037
|
-
var yoloMessages = {
|
|
9038
|
-
updated: (path2, status, agentNote) => `${path2} updated. ${status}${agentNote}
|
|
9039
|
-
Restart opencode (or reload) so agents pick up the new permissions.`
|
|
9040
|
-
};
|
|
9041
|
-
var migrateMessages = {
|
|
9042
|
-
header: "openteam migrate:",
|
|
9043
|
-
nothingToMigrate: " nothing to migrate — the P15b layout is already in place.",
|
|
9044
|
-
counts: (params) => [
|
|
9045
|
-
` moved: ${params.moved} file(s)`,
|
|
9046
|
-
` deduped: ${params.deduped} file(s) (destination already identical)`,
|
|
9047
|
-
` conflicts: ${params.conflicts} file(s)`
|
|
9048
|
-
],
|
|
9049
|
-
relocatedHeader: " relocated:",
|
|
9050
|
-
relocatedEntry: (from, to, deduped) => ` · ${from} → ${to}${deduped ? " (deduped)" : ""}`,
|
|
9051
|
-
conflictsHeader: " ⚠ left in place (destination exists with different content — no data lost):",
|
|
9052
|
-
conflictEntry: (from, to) => ` · ${from} → ${to}`,
|
|
9053
|
-
manualWorktreesHeader: " ⚠ legacy git worktree(s) need a manual move (run `git worktree move`):",
|
|
9054
|
-
manualWorktreeEntry: (label, from, to) => ` · ${label}: ${from} → ${to}`,
|
|
9055
|
-
success: " ✓ machine-local runtime output relocated under .opencode/openteam-local/."
|
|
9056
|
-
};
|
|
9057
|
-
var rolesInitMessages = {
|
|
9058
|
-
help: " openteam roles init Compose per-role execution, model, and fallback policy",
|
|
9059
|
-
header: "openteam roles init:",
|
|
9060
|
-
title: "openteam roles init",
|
|
9061
|
-
noRoster: (path2) => ` ✗ no roster at ${path2}.`,
|
|
9062
|
-
noRosterRemedy: " Cast the team first: run `openteam setup`, then ask the orchestrator to register the cast.",
|
|
9063
|
-
unparseableRoster: (path2, error) => ` ✗ ${path2} is present but unparseable: ${error}`,
|
|
9064
|
-
unparseableRosterRemedy: " Run `openteam doctor` for the remedy, then re-run this command.",
|
|
9065
|
-
allProfiled: (count) => ` ✓ ${count} roster role(s) checked; no unprofiled roles — every role resolves a routing profile.`,
|
|
9066
|
-
skipLabel: "Skip for now",
|
|
9067
|
-
skipHint: "leaves the role on its built-in or fallback policy; doctor keeps reporting the missing explicit override",
|
|
9068
|
-
runtimeQuestion: (roleID) => `Preferred local runtime(s) for "${roleID}" (in failover order)`,
|
|
9069
|
-
runtimeHint: "machine-local — written to the git-ignored overlay",
|
|
9070
|
-
cancelled: (reason) => ` ✗ cancelled (${reason}); nothing was written.`,
|
|
9071
|
-
invalidResult: (reason) => ` ✗ refusing to write: the resulting config is invalid — ${reason}`,
|
|
9072
|
-
deprecation: (message) => ` ⚠ ${message}`,
|
|
9073
|
-
nothingWritten: (skipped) => ` · skipped ${skipped}; nothing written.`,
|
|
9074
|
-
nothingToWriteOutro: "Nothing to write.",
|
|
9075
|
-
runtimeBinding: (path2) => ` ✓ runtime binding: ${path2} (git-ignored, machine-local)`,
|
|
9076
|
-
skippedSummary: (roleIDs) => ` · skipped: ${roleIDs} — using built-in or fallback policy; re-run this command to add an explicit override.`,
|
|
9077
|
-
outro: "Role policy updated."
|
|
9078
|
-
};
|
|
9079
|
-
|
|
9080
|
-
// src/messages/executionSetup.ts
|
|
9081
|
-
var executionSetupMessages = {
|
|
9082
|
-
setupIntro: "openteam setup — configure local, frontier, or mixed team execution",
|
|
9083
|
-
runtimeQuestion: "Which local runtimes do you want to enable? (choose 'None' for frontier-only)",
|
|
9084
|
-
runtimeNoneLabel: "None — use frontier models only",
|
|
9085
|
-
runtimeNoneHint: "no local runtime (frontier execution)",
|
|
9086
|
-
executionModeQuestion: "Team execution mode",
|
|
9087
|
-
executionModeChoices: {
|
|
9088
|
-
local: {
|
|
9089
|
-
label: "local — every agent stays on configured local providers",
|
|
9090
|
-
hint: "requires at least one enabled local runtime"
|
|
9091
|
-
},
|
|
9092
|
-
frontier: {
|
|
9093
|
-
label: "frontier — every agent uses frontier providers",
|
|
9094
|
-
hint: "does not require a local runtime"
|
|
9095
|
-
},
|
|
9096
|
-
mixed: {
|
|
9097
|
-
label: "mixed — policies may select local or frontier models",
|
|
9098
|
-
hint: "the global mode is an upper bound; per-agent policies may narrow it"
|
|
9099
|
-
}
|
|
9100
|
-
},
|
|
9101
|
-
frontierOnlyNote: [
|
|
9102
|
-
"No local runtime is enabled, so the team will use frontier providers.",
|
|
9103
|
-
"The selected primary model is written consistently to opencode.json and",
|
|
9104
|
-
".opencode/agent/openteam.md."
|
|
9105
|
-
].join(`
|
|
9106
|
-
`),
|
|
9107
|
-
frontierOnlyTitle: "Frontier execution",
|
|
9108
|
-
localOnlyNote: (model) => [
|
|
9109
|
-
"Every team agent is restricted to configured local providers.",
|
|
9110
|
-
`The primary coordinator is pinned to ${model}.`,
|
|
9111
|
-
"No frontier provider is required for execution while this mode is active."
|
|
9112
|
-
].join(`
|
|
9113
|
-
`),
|
|
9114
|
-
localOnlyTitle: "Local execution",
|
|
9115
|
-
localRequiredError: "local execution requires an enabled local runtime",
|
|
9116
|
-
mixedPrimaryQuestion: "Primary coordinator model",
|
|
9117
|
-
mixedPrimaryLocal: (model) => `Use local thinking model ${model}`,
|
|
9118
|
-
mixedPrimaryFrontier: "Choose a frontier model",
|
|
9119
|
-
frontierModelQuestion: "Frontier model (type to search; cheapest capable entries first)",
|
|
9120
|
-
primaryPolicySummary: (params) => [
|
|
9121
|
-
`Execution mode: ${params.executionMode}`,
|
|
9122
|
-
`Primary model: ${params.primaryModel}`,
|
|
9123
|
-
`Primary fallbacks: ${params.fallbacks}`,
|
|
9124
|
-
"Worker model policy: auto within the global execution mode"
|
|
9125
|
-
],
|
|
9126
|
-
noFallbacks: "none",
|
|
9127
|
-
yoloQuestion: "Enable YOLO mode? (opencode auto-approves all permissions)",
|
|
9128
|
-
configuredSummary: (params) => [
|
|
9129
|
-
...executionSetupMessages.primaryPolicySummary({
|
|
9130
|
-
executionMode: params.executionMode,
|
|
9131
|
-
primaryModel: params.primaryModel,
|
|
9132
|
-
fallbacks: executionSetupMessages.noFallbacks
|
|
9133
|
-
}),
|
|
9134
|
-
`Frontier baseline: ${params.frontierBaseline}`,
|
|
9135
|
-
`Local runtimes: ${params.localRuntimes}`,
|
|
9136
|
-
`YOLO mode: ${params.yolo ? "enabled (auto-approves permissions)" : "disabled"}`,
|
|
9137
|
-
"Web Console: launched separately with 'openteam console' (multi-session, loopback)",
|
|
9138
|
-
`Wrote: ${params.opencodePath}, ${params.configPath}, ${params.agentPath}, ${params.agentDir}/*.md (${params.roleAgentCount} standard subagents), ${params.commandDir}/*.md (${params.commandCount} commands); ensured ${params.gitignorePath}`,
|
|
9139
|
-
"",
|
|
9140
|
-
"Next steps:",
|
|
9141
|
-
params.executionMode === "local" ? " 1. No frontier authentication is required while local execution is active" : " 1. Authenticate the frontier provider: opencode auth login",
|
|
9142
|
-
params.executionMode === "local" ? executionSetupMessages.localRuntimeNextStep : params.executionMode === "mixed" ? executionSetupMessages.mixedNextStep : executionSetupMessages.frontierNextStep,
|
|
9143
|
-
" 3. Press Tab and pick the 'openteam' agent, or type / and pick an /openteam… command"
|
|
9144
|
-
],
|
|
9145
|
-
configuredTitle: "openteam configured",
|
|
9146
|
-
complete: (paths) => `openteam setup complete: ${paths}`,
|
|
9147
|
-
error: (message) => `setup error: ${message}`,
|
|
9148
|
-
localRuntimeNextStep: " 2. Make sure every configured local runtime is reachable",
|
|
9149
|
-
frontierNextStep: " 2. Open opencode in this repo; openteam will use frontier models",
|
|
9150
|
-
mixedNextStep: " 2. Make sure local runtimes are reachable; unavailable candidates can use configured fallbacks",
|
|
9151
|
-
done: "Done. Open opencode and select the 'openteam' agent.",
|
|
9152
|
-
rolePolicy: {
|
|
9153
|
-
whyTitle: "Configure execution and model selection",
|
|
9154
|
-
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.`,
|
|
9155
|
-
modeQuestion: (roleID, agentName) => `Execution mode for "${roleID}" (${agentName})`,
|
|
9156
|
-
modeInheritLabel: "Inherit the team execution mode",
|
|
9157
|
-
modeLocalLabel: "Local only",
|
|
9158
|
-
modeFrontierLabel: "Frontier only",
|
|
9159
|
-
modelQuestion: (roleID) => `Model selection for "${roleID}"`,
|
|
9160
|
-
modelAutoLabel: "Auto — choose the cheapest capable eligible model",
|
|
9161
|
-
modelExactLabel: "Exact provider/model pin",
|
|
9162
|
-
modelExactQuestion: (roleID) => `Exact model for "${roleID}" as provider/model`,
|
|
9163
|
-
modelExactPlaceholder: "provider/model",
|
|
9164
|
-
fallbacksQuestion: (roleID) => `Ordered fallbacks for "${roleID}" (comma-separated provider/model, blank for none)`,
|
|
9165
|
-
fallbacksPlaceholder: "provider/model, provider/model",
|
|
9166
|
-
configured: (roleIDs, path2) => ` ✓ execution/model policy: ${roleIDs} → ${path2}`,
|
|
9167
|
-
invalidModelRef: (value) => `invalid model "${value}"; expected provider/model`
|
|
9168
|
-
}
|
|
9169
|
-
};
|
|
9170
|
-
var executionPolicyMessages = {
|
|
9171
|
-
doctorHelp: " openteam doctor Diagnose runtimes, execution policies, and config",
|
|
9172
|
-
agentsHelp: " openteam agents List agents, model identity, and execution policy",
|
|
9173
|
-
section: "Configured execution policies:",
|
|
9174
|
-
globalMode: (mode) => ` execution mode: ${mode}`,
|
|
9175
|
-
line: (policy) => ` ${policy.owner}: mode=${policy.executionMode ?? "inherit"} · model=${policy.model} · fallbacks=${policy.fallbacks.length > 0 ? policy.fallbacks.join(" → ") : "none"}`,
|
|
9176
|
-
retryLimits: (maxRetries, maxModelsPerNode) => ` retry limits: ${maxRetries} retries per model · ${maxModelsPerNode} model(s) per node`,
|
|
9177
|
-
inheritedDefaultUnset: "inherits the opencode.json default (not set); execution follows the configured team and agent policy",
|
|
9178
|
-
inheritedDefault: (subscription) => `inherits default → ${subscription}; execution follows the configured team and agent policy`,
|
|
9179
|
-
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.",
|
|
9180
|
-
unprofiledRoleRemedy: " remedy: run `openteam roles init`, or add executionMode, model, and ordered fallbacks under orchestrator.roles in .opencode/openteam.json.",
|
|
9181
|
-
noLocalMixed: " ⚠ No local runtime reachable: mixed execution currently has only frontier candidates.",
|
|
9182
|
-
noLocalBlocked: " ✗ No local runtime reachable: local execution is blocked until a configured runtime is available.",
|
|
9183
|
-
primaryLocalMismatch: (name, providerID) => ` ✗ local execution is configured, but primary agent '${name}' points at provider '${providerID}', which opencode.json does not configure.`,
|
|
9184
|
-
primaryLocalMismatchCause: " cause: the primary agent artifact and opencode.json no longer agree on the selected provider/model identity.",
|
|
9185
|
-
primaryLocalMismatchConsequence: " consequence: opencode cannot start the coordinator, so it cannot read the roster or distribute work.",
|
|
9186
|
-
primaryLocalMismatchRemedy: (sourceFile) => ` remedy: re-run \`openteam setup\` to regenerate ${sourceFile} and opencode.json from the same primary policy, then re-run \`openteam doctor\`.`
|
|
9187
|
-
};
|
|
9188
|
-
var localModeChangeMessages = {
|
|
9189
|
-
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\`.`,
|
|
9190
|
-
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\`.`
|
|
10980
|
+
var ACTIVITY_SUMMARIES = {
|
|
10981
|
+
"session.created": "Session created",
|
|
10982
|
+
"session.idle": "Session idle",
|
|
10983
|
+
"session.error": "Session error"
|
|
9191
10984
|
};
|
|
10985
|
+
function sessionIDFromEvent(event) {
|
|
10986
|
+
const properties = event.properties;
|
|
10987
|
+
if (properties === null || typeof properties !== "object") {
|
|
10988
|
+
return;
|
|
10989
|
+
}
|
|
10990
|
+
const record = properties;
|
|
10991
|
+
if (typeof record.sessionID === "string") {
|
|
10992
|
+
return record.sessionID;
|
|
10993
|
+
}
|
|
10994
|
+
if (typeof record.info?.id === "string") {
|
|
10995
|
+
return record.info.id;
|
|
10996
|
+
}
|
|
10997
|
+
return;
|
|
10998
|
+
}
|
|
10999
|
+
function activityEventFrom(event, now) {
|
|
11000
|
+
const summary = ACTIVITY_SUMMARIES[event.type];
|
|
11001
|
+
if (summary === undefined) {
|
|
11002
|
+
return;
|
|
11003
|
+
}
|
|
11004
|
+
const sessionID = sessionIDFromEvent(event);
|
|
11005
|
+
if (sessionID === undefined) {
|
|
11006
|
+
return;
|
|
11007
|
+
}
|
|
11008
|
+
return {
|
|
11009
|
+
v: EVENT_SCHEMA_VERSION,
|
|
11010
|
+
type: "activity",
|
|
11011
|
+
ts: now(),
|
|
11012
|
+
sessionID,
|
|
11013
|
+
kind: "agent",
|
|
11014
|
+
summary
|
|
11015
|
+
};
|
|
11016
|
+
}
|
|
11017
|
+
|
|
11018
|
+
// src/plugin/commandTool.ts
|
|
11019
|
+
import { tool } from "@opencode-ai/plugin";
|
|
9192
11020
|
|
|
9193
11021
|
// src/orchestrator/worktreeReconciler.ts
|
|
9194
11022
|
function planOne(wt) {
|
|
@@ -9244,7 +11072,7 @@ function planWorktreeReconciliation(input) {
|
|
|
9244
11072
|
}
|
|
9245
11073
|
|
|
9246
11074
|
// src/telemetry/otelConfig.ts
|
|
9247
|
-
import { z as
|
|
11075
|
+
import { z as z20 } from "zod";
|
|
9248
11076
|
|
|
9249
11077
|
// src/telemetry/fanout.ts
|
|
9250
11078
|
function createFanOutSink(deps) {
|
|
@@ -9322,10 +11150,10 @@ function createOtelSink(deps) {
|
|
|
9322
11150
|
}
|
|
9323
11151
|
|
|
9324
11152
|
// src/telemetry/otelConfig.ts
|
|
9325
|
-
var OtelBackendConfigSchema =
|
|
9326
|
-
backend:
|
|
9327
|
-
connectionEnv:
|
|
9328
|
-
serviceName:
|
|
11153
|
+
var OtelBackendConfigSchema = z20.object({
|
|
11154
|
+
backend: z20.literal("opentelemetry"),
|
|
11155
|
+
connectionEnv: z20.string().min(1),
|
|
11156
|
+
serviceName: z20.string().min(1).optional()
|
|
9329
11157
|
}).strict();
|
|
9330
11158
|
function parseConnectionString(raw) {
|
|
9331
11159
|
const pairs = new Map;
|
|
@@ -9728,22 +11556,22 @@ var KNOWN_FRONTIER_PROVIDER_IDS = new Set([
|
|
|
9728
11556
|
"openrouter"
|
|
9729
11557
|
]);
|
|
9730
11558
|
var VIRTUAL_ROUTER_PROVIDER_ID = "openteam-router";
|
|
9731
|
-
function
|
|
11559
|
+
function isRecord5(value) {
|
|
9732
11560
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9733
11561
|
}
|
|
9734
11562
|
function parseOpencodeProviders(opencodeConfig) {
|
|
9735
11563
|
const result = new Map;
|
|
9736
11564
|
const provider = opencodeConfig?.provider;
|
|
9737
|
-
if (!
|
|
11565
|
+
if (!isRecord5(provider)) {
|
|
9738
11566
|
return result;
|
|
9739
11567
|
}
|
|
9740
11568
|
for (const [id, value] of Object.entries(provider)) {
|
|
9741
|
-
if (!
|
|
11569
|
+
if (!isRecord5(value)) {
|
|
9742
11570
|
result.set(id, {});
|
|
9743
11571
|
continue;
|
|
9744
11572
|
}
|
|
9745
11573
|
const models = value.models;
|
|
9746
|
-
result.set(id,
|
|
11574
|
+
result.set(id, isRecord5(models) ? { models: new Set(Object.keys(models)) } : {});
|
|
9747
11575
|
}
|
|
9748
11576
|
return result;
|
|
9749
11577
|
}
|
|
@@ -9997,6 +11825,57 @@ function renderConsoleStatus(console_) {
|
|
|
9997
11825
|
}
|
|
9998
11826
|
|
|
9999
11827
|
// src/commands/doctor.ts
|
|
11828
|
+
var DEFAULT_COMPACTION_RESERVED_MAX = 20000;
|
|
11829
|
+
function isRecord6(value) {
|
|
11830
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11831
|
+
}
|
|
11832
|
+
function hasOwn(record, key) {
|
|
11833
|
+
return Object.hasOwn(record, key);
|
|
11834
|
+
}
|
|
11835
|
+
function positiveInteger2(value) {
|
|
11836
|
+
return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value > 0 ? value : undefined;
|
|
11837
|
+
}
|
|
11838
|
+
function nonNegativeInteger2(value) {
|
|
11839
|
+
return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value >= 0 ? value : undefined;
|
|
11840
|
+
}
|
|
11841
|
+
function recordAt(source, key) {
|
|
11842
|
+
const value = source?.[key];
|
|
11843
|
+
return isRecord6(value) ? value : undefined;
|
|
11844
|
+
}
|
|
11845
|
+
function enabledLocalProviderIDs(config) {
|
|
11846
|
+
const providers = new Set;
|
|
11847
|
+
for (const runtime of config.local.runtimes) {
|
|
11848
|
+
if (!runtime.enabled) {
|
|
11849
|
+
continue;
|
|
11850
|
+
}
|
|
11851
|
+
providers.add(runtime.defaultModel.providerID);
|
|
11852
|
+
}
|
|
11853
|
+
return providers;
|
|
11854
|
+
}
|
|
11855
|
+
function detectedContextsByProvider(config, snapshots) {
|
|
11856
|
+
const reachableByRuntime = new Map(snapshots.filter((snapshot) => snapshot.reachable).map((snapshot) => [snapshot.id, snapshot]));
|
|
11857
|
+
const detected = new Map;
|
|
11858
|
+
for (const runtime of config.local.runtimes) {
|
|
11859
|
+
if (!runtime.enabled) {
|
|
11860
|
+
continue;
|
|
11861
|
+
}
|
|
11862
|
+
const snapshot = reachableByRuntime.get(runtime.id);
|
|
11863
|
+
if (snapshot === undefined) {
|
|
11864
|
+
continue;
|
|
11865
|
+
}
|
|
11866
|
+
const providerID = runtime.defaultModel.providerID;
|
|
11867
|
+
const byModel = detected.get(providerID) ?? new Map;
|
|
11868
|
+
for (const model of snapshot.models) {
|
|
11869
|
+
if (model.contextWindow !== undefined) {
|
|
11870
|
+
byModel.set(model.modelID, model.contextWindow);
|
|
11871
|
+
}
|
|
11872
|
+
}
|
|
11873
|
+
if (byModel.size > 0) {
|
|
11874
|
+
detected.set(providerID, byModel);
|
|
11875
|
+
}
|
|
11876
|
+
}
|
|
11877
|
+
return detected;
|
|
11878
|
+
}
|
|
10000
11879
|
function runtimeClassLine(runtime) {
|
|
10001
11880
|
if (runtime === undefined) {
|
|
10002
11881
|
return;
|
|
@@ -10281,6 +12160,121 @@ function agentModelsSection(diagnostics, searchedPaths, localOnly) {
|
|
|
10281
12160
|
lines.push(" note: static checks are offline and deterministic; live checks need a reachable local runtime and can be inconclusive.");
|
|
10282
12161
|
return lines;
|
|
10283
12162
|
}
|
|
12163
|
+
function collectLocalModelLimitWarnings(input) {
|
|
12164
|
+
if (input.opencodeConfig === undefined) {
|
|
12165
|
+
return;
|
|
12166
|
+
}
|
|
12167
|
+
const enabledProviders = enabledLocalProviderIDs(input.config);
|
|
12168
|
+
if (enabledProviders.size === 0) {
|
|
12169
|
+
return { inspectedModels: 0, warnings: [] };
|
|
12170
|
+
}
|
|
12171
|
+
const providerConfig = recordAt(input.opencodeConfig, "provider");
|
|
12172
|
+
const detectedContexts = detectedContextsByProvider(input.config, input.snapshots);
|
|
12173
|
+
const compactionReserved = positiveInteger2(recordAt(input.opencodeConfig, "compaction")?.reserved);
|
|
12174
|
+
const warnings = [];
|
|
12175
|
+
let inspectedModels = 0;
|
|
12176
|
+
for (const providerID of enabledProviders) {
|
|
12177
|
+
const provider = recordAt(providerConfig, providerID);
|
|
12178
|
+
const models = recordAt(provider, "models");
|
|
12179
|
+
if (models === undefined) {
|
|
12180
|
+
continue;
|
|
12181
|
+
}
|
|
12182
|
+
for (const [modelID, modelValue] of Object.entries(models)) {
|
|
12183
|
+
inspectedModels += 1;
|
|
12184
|
+
const problems = [];
|
|
12185
|
+
const remedies = new Set;
|
|
12186
|
+
if (!isRecord6(modelValue)) {
|
|
12187
|
+
problems.push(doctorMessages.localModelLimits.invalidLimitBlock);
|
|
12188
|
+
remedies.add(doctorMessages.localModelLimits.invalidLimitRemedy);
|
|
12189
|
+
warnings.push({
|
|
12190
|
+
providerID,
|
|
12191
|
+
modelID,
|
|
12192
|
+
problems,
|
|
12193
|
+
remedies: [...remedies]
|
|
12194
|
+
});
|
|
12195
|
+
continue;
|
|
12196
|
+
}
|
|
12197
|
+
if (hasOwn(modelValue, "limit") && recordAt(modelValue, "limit") === undefined) {
|
|
12198
|
+
problems.push(doctorMessages.localModelLimits.invalidLimitBlock);
|
|
12199
|
+
remedies.add(doctorMessages.localModelLimits.invalidLimitRemedy);
|
|
12200
|
+
warnings.push({
|
|
12201
|
+
providerID,
|
|
12202
|
+
modelID,
|
|
12203
|
+
problems,
|
|
12204
|
+
remedies: [...remedies]
|
|
12205
|
+
});
|
|
12206
|
+
continue;
|
|
12207
|
+
}
|
|
12208
|
+
const limit = recordAt(modelValue, "limit");
|
|
12209
|
+
const rawOutput = limit?.output;
|
|
12210
|
+
const rawContext = limit?.context;
|
|
12211
|
+
const rawInput = limit?.input;
|
|
12212
|
+
const output = positiveInteger2(rawOutput);
|
|
12213
|
+
const context = nonNegativeInteger2(rawContext);
|
|
12214
|
+
const inputLimit = positiveInteger2(rawInput);
|
|
12215
|
+
if (limit === undefined || !hasOwn(limit, "output")) {
|
|
12216
|
+
problems.push(limit === undefined ? doctorMessages.localModelLimits.unconfiguredOutput : doctorMessages.localModelLimits.missingOutput);
|
|
12217
|
+
remedies.add(limit === undefined ? doctorMessages.localModelLimits.unconfiguredLimitRemedy : doctorMessages.localModelLimits.outputRemedy);
|
|
12218
|
+
} else if (output === undefined) {
|
|
12219
|
+
problems.push(doctorMessages.localModelLimits.invalidOutput);
|
|
12220
|
+
remedies.add(doctorMessages.localModelLimits.invalidLimitRemedy);
|
|
12221
|
+
}
|
|
12222
|
+
if (limit === undefined || !hasOwn(limit, "context")) {
|
|
12223
|
+
problems.push(limit === undefined ? doctorMessages.localModelLimits.unconfiguredContext : doctorMessages.localModelLimits.missingContext);
|
|
12224
|
+
const runtimeContext = detectedContexts.get(providerID)?.get(modelID);
|
|
12225
|
+
remedies.add(limit === undefined ? doctorMessages.localModelLimits.unconfiguredLimitRemedy : runtimeContext === undefined ? doctorMessages.localModelLimits.unknownContextRemedy : doctorMessages.localModelLimits.detectedContextRemedy);
|
|
12226
|
+
} else if (context === undefined) {
|
|
12227
|
+
problems.push(doctorMessages.localModelLimits.invalidContext);
|
|
12228
|
+
remedies.add(doctorMessages.localModelLimits.invalidLimitRemedy);
|
|
12229
|
+
} else if (context === 0) {
|
|
12230
|
+
problems.push(doctorMessages.localModelLimits.unknownContext);
|
|
12231
|
+
remedies.add(doctorMessages.localModelLimits.zeroContextRemedy);
|
|
12232
|
+
}
|
|
12233
|
+
if (limit !== undefined && hasOwn(limit, "input") && inputLimit === undefined) {
|
|
12234
|
+
problems.push(doctorMessages.localModelLimits.invalidInput);
|
|
12235
|
+
remedies.add(doctorMessages.localModelLimits.invalidLimitRemedy);
|
|
12236
|
+
}
|
|
12237
|
+
if (output !== undefined && context !== undefined && context > 0 && output >= context) {
|
|
12238
|
+
problems.push(doctorMessages.localModelLimits.outputExceedsContext);
|
|
12239
|
+
remedies.add(doctorMessages.localModelLimits.invalidLimitRemedy);
|
|
12240
|
+
}
|
|
12241
|
+
if (output !== undefined && inputLimit !== undefined && inputLimit <= (compactionReserved ?? Math.min(DEFAULT_COMPACTION_RESERVED_MAX, output))) {
|
|
12242
|
+
problems.push(doctorMessages.localModelLimits.outputExceedsInput);
|
|
12243
|
+
remedies.add(doctorMessages.localModelLimits.invalidLimitRemedy);
|
|
12244
|
+
}
|
|
12245
|
+
if (problems.length > 0) {
|
|
12246
|
+
warnings.push({
|
|
12247
|
+
providerID,
|
|
12248
|
+
modelID,
|
|
12249
|
+
problems,
|
|
12250
|
+
remedies: [...remedies]
|
|
12251
|
+
});
|
|
12252
|
+
}
|
|
12253
|
+
}
|
|
12254
|
+
}
|
|
12255
|
+
return { inspectedModels, warnings };
|
|
12256
|
+
}
|
|
12257
|
+
function localModelLimitsSection(input) {
|
|
12258
|
+
const report = collectLocalModelLimitWarnings(input);
|
|
12259
|
+
if (report === undefined || report.inspectedModels === 0 && report.warnings.length === 0) {
|
|
12260
|
+
return [];
|
|
12261
|
+
}
|
|
12262
|
+
if (report.warnings.length === 0) {
|
|
12263
|
+
return [doctorMessages.localModelLimits.section, doctorMessages.localModelLimits.healthy];
|
|
12264
|
+
}
|
|
12265
|
+
const lines = [doctorMessages.localModelLimits.warningSummary(report.warnings.length)];
|
|
12266
|
+
const remedies = new Set;
|
|
12267
|
+
for (const warning of report.warnings) {
|
|
12268
|
+
lines.push(doctorMessages.localModelLimits.modelWarning(warning.providerID, warning.modelID, warning.problems.join("; ")));
|
|
12269
|
+
for (const remedy of warning.remedies) {
|
|
12270
|
+
remedies.add(remedy);
|
|
12271
|
+
}
|
|
12272
|
+
}
|
|
12273
|
+
for (const remedy of remedies) {
|
|
12274
|
+
lines.push(remedy);
|
|
12275
|
+
}
|
|
12276
|
+
return lines;
|
|
12277
|
+
}
|
|
10284
12278
|
function renderDoctor(input) {
|
|
10285
12279
|
const enabledRuntimes = input.config.local.runtimes.filter((r) => r.enabled);
|
|
10286
12280
|
const reachable = input.snapshots.filter((s) => s.reachable).length;
|
|
@@ -10339,6 +12333,7 @@ function renderDoctor(input) {
|
|
|
10339
12333
|
if (input.gitignore !== undefined) {
|
|
10340
12334
|
lines.push(...gitignoreSection(input.gitignore));
|
|
10341
12335
|
}
|
|
12336
|
+
lines.push(...localModelLimitsSection(input));
|
|
10342
12337
|
if (input.otelBackend !== undefined) {
|
|
10343
12338
|
const otel = input.otelBackend;
|
|
10344
12339
|
lines.push(" opentelemetry:");
|
|
@@ -10873,9 +12868,7 @@ ${line}`);
|
|
|
10873
12868
|
}
|
|
10874
12869
|
return observation;
|
|
10875
12870
|
}
|
|
10876
|
-
|
|
10877
12871
|
// src/commands/setup.ts
|
|
10878
|
-
var OPENTEAM_PLUGIN_SPEC = "@jmanuelcorral/openteam";
|
|
10879
12872
|
var OPENCODE_GITIGNORE_PATH = ".opencode/.gitignore";
|
|
10880
12873
|
var GENERATED_OPENTEAM_STATE_PATHS = [
|
|
10881
12874
|
DEFAULT_TELEMETRY_PATH,
|
|
@@ -11006,7 +12999,7 @@ function isInsideRepo(repoRoot, relPath) {
|
|
|
11006
12999
|
function isOpenteamEntry(entry) {
|
|
11007
13000
|
if (typeof entry !== "string")
|
|
11008
13001
|
return false;
|
|
11009
|
-
return entry ===
|
|
13002
|
+
return entry === OPENTEAM_PACKAGE_NAME || entry.startsWith(`${OPENTEAM_PACKAGE_NAME}@`);
|
|
11010
13003
|
}
|
|
11011
13004
|
function escapeRegex(s) {
|
|
11012
13005
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -11181,7 +13174,7 @@ function stripOpenteamFromOpencodeConfig(raw) {
|
|
|
11181
13174
|
try {
|
|
11182
13175
|
parsed = JSON.parse(stripped);
|
|
11183
13176
|
} catch {
|
|
11184
|
-
if (raw.includes(
|
|
13177
|
+
if (raw.includes(OPENTEAM_PACKAGE_NAME)) {
|
|
11185
13178
|
return {
|
|
11186
13179
|
status: "failed",
|
|
11187
13180
|
reason: "document is not valid JSON/JSONC; remove the @jmanuelcorral/openteam plugin entry manually"
|
|
@@ -11190,7 +13183,7 @@ function stripOpenteamFromOpencodeConfig(raw) {
|
|
|
11190
13183
|
return { status: "not-present" };
|
|
11191
13184
|
}
|
|
11192
13185
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
11193
|
-
if (raw.includes(
|
|
13186
|
+
if (raw.includes(OPENTEAM_PACKAGE_NAME)) {
|
|
11194
13187
|
return {
|
|
11195
13188
|
status: "failed",
|
|
11196
13189
|
reason: "top-level value is not a JSON object; remove the @jmanuelcorral/openteam plugin entry manually"
|
|
@@ -11201,7 +13194,7 @@ function stripOpenteamFromOpencodeConfig(raw) {
|
|
|
11201
13194
|
const record = parsed;
|
|
11202
13195
|
const plugins = record.plugin;
|
|
11203
13196
|
if (!Array.isArray(plugins)) {
|
|
11204
|
-
if (raw.includes(
|
|
13197
|
+
if (raw.includes(OPENTEAM_PACKAGE_NAME)) {
|
|
11205
13198
|
return {
|
|
11206
13199
|
status: "failed",
|
|
11207
13200
|
reason: "could not locate a top-level plugin array; remove the @jmanuelcorral/openteam plugin entry manually"
|
|
@@ -11224,7 +13217,7 @@ function stripOpenteamFromOpencodeConfig(raw) {
|
|
|
11224
13217
|
const { keyStart, arrayStart, arrayEnd } = bounds;
|
|
11225
13218
|
if (remaining.length === 0) {
|
|
11226
13219
|
const contents2 = removePluginKeyFromObject(raw, keyStart, arrayEnd);
|
|
11227
|
-
const residue2 = contents2.includes(
|
|
13220
|
+
const residue2 = contents2.includes(OPENTEAM_PACKAGE_NAME) ? "openteam is still referenced in a nested context — remove it manually" : undefined;
|
|
11228
13221
|
return residue2 !== undefined ? { status: "removed", contents: contents2, residue: residue2 } : { status: "removed", contents: contents2 };
|
|
11229
13222
|
}
|
|
11230
13223
|
let arrayText = raw.slice(arrayStart, arrayEnd + 1);
|
|
@@ -11232,7 +13225,7 @@ function stripOpenteamFromOpencodeConfig(raw) {
|
|
|
11232
13225
|
arrayText = removeEntryFromArrayText(arrayText, JSON.stringify(entry));
|
|
11233
13226
|
}
|
|
11234
13227
|
const contents = raw.slice(0, arrayStart) + arrayText + raw.slice(arrayEnd + 1);
|
|
11235
|
-
const residue = contents.includes(
|
|
13228
|
+
const residue = contents.includes(OPENTEAM_PACKAGE_NAME) ? "openteam is still referenced in a nested context — remove it manually" : undefined;
|
|
11236
13229
|
return residue !== undefined ? { status: "removed", contents, residue } : { status: "removed", contents };
|
|
11237
13230
|
}
|
|
11238
13231
|
function stripOpenteamFromGitignore(raw) {
|
|
@@ -11296,7 +13289,7 @@ function describeItem(item) {
|
|
|
11296
13289
|
case "agent":
|
|
11297
13290
|
return `${item.path} (${item.name})`;
|
|
11298
13291
|
case "opencode-config":
|
|
11299
|
-
return `${item.path} (remove the ${
|
|
13292
|
+
return `${item.path} (remove the ${OPENTEAM_PACKAGE_NAME} plugin entry)`;
|
|
11300
13293
|
case "gitignore":
|
|
11301
13294
|
return `${item.path} (remove openteam's generated-state rules)`;
|
|
11302
13295
|
case "worktree":
|
|
@@ -11708,6 +13701,9 @@ var HELP = [
|
|
|
11708
13701
|
" openteam report Cost/savings summary (telemetry)",
|
|
11709
13702
|
" openteam clear-cache List the plugin's frozen cache entries",
|
|
11710
13703
|
" openteam clear-cache --delete Delete the frozen cache entries",
|
|
13704
|
+
upgradeMessages.help.command,
|
|
13705
|
+
upgradeMessages.help.check,
|
|
13706
|
+
upgradeMessages.help.version,
|
|
11711
13707
|
" openteam purge List openteam's footprint (dry run, removes nothing)",
|
|
11712
13708
|
" openteam purge --delete Interactively remove openteam category by category",
|
|
11713
13709
|
" openteam purge --yes Remove every openteam category without prompting",
|
|
@@ -12285,6 +14281,7 @@ async function runCli(argv, deps) {
|
|
|
12285
14281
|
telemetryRecords: records.length,
|
|
12286
14282
|
agentModels,
|
|
12287
14283
|
opencodeConfigPaths,
|
|
14284
|
+
...opencodeConfig !== undefined ? { opencodeConfig } : {},
|
|
12288
14285
|
...queueWait !== undefined ? { queueWait } : {},
|
|
12289
14286
|
...rosterAudit !== undefined ? { rosterAudit } : {},
|
|
12290
14287
|
...rosterRoleCount !== undefined ? { rosterRoleCount } : {},
|
|
@@ -12386,6 +14383,15 @@ async function runCli(argv, deps) {
|
|
|
12386
14383
|
...configWarning !== undefined ? { configWarning } : {}
|
|
12387
14384
|
});
|
|
12388
14385
|
}
|
|
14386
|
+
if (command === "upgrade") {
|
|
14387
|
+
if (deps.upgradePort === undefined) {
|
|
14388
|
+
return {
|
|
14389
|
+
exitCode: 1,
|
|
14390
|
+
stdout: upgradeMessages.portNotConfigured
|
|
14391
|
+
};
|
|
14392
|
+
}
|
|
14393
|
+
return await runUpgrade(parsed.positionals, deps.upgradePort, opencodeConfigPaths);
|
|
14394
|
+
}
|
|
12389
14395
|
if (command === "--version" || command === "-v") {
|
|
12390
14396
|
return { exitCode: 0, stdout: deps.version };
|
|
12391
14397
|
}
|
|
@@ -12405,7 +14411,7 @@ ${HELP}`
|
|
|
12405
14411
|
}
|
|
12406
14412
|
|
|
12407
14413
|
// src/plugin/commandTool.ts
|
|
12408
|
-
function commandArgv(action, model) {
|
|
14414
|
+
function commandArgv(action, model, version) {
|
|
12409
14415
|
switch (action) {
|
|
12410
14416
|
case "show":
|
|
12411
14417
|
return ["baseline", "show"];
|
|
@@ -12423,11 +14429,15 @@ function commandArgv(action, model) {
|
|
|
12423
14429
|
return ["console"];
|
|
12424
14430
|
case "clear-cache":
|
|
12425
14431
|
return ["clear-cache"];
|
|
14432
|
+
case "upgrade":
|
|
14433
|
+
return version === undefined ? ["upgrade"] : ["upgrade", "--version", version];
|
|
14434
|
+
case "upgrade-check":
|
|
14435
|
+
return version === undefined ? ["upgrade", "--check"] : ["upgrade", "--check", "--version", version];
|
|
12426
14436
|
}
|
|
12427
14437
|
}
|
|
12428
14438
|
function createCommandTool(deps) {
|
|
12429
14439
|
return tool({
|
|
12430
|
-
description: "openteam runtime commands: baseline (show/set/auto), doctor, report, agents (LLM per agent: local/frontier + subscription)
|
|
14440
|
+
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).",
|
|
12431
14441
|
args: {
|
|
12432
14442
|
action: tool.schema.enum([
|
|
12433
14443
|
"show",
|
|
@@ -12437,12 +14447,15 @@ function createCommandTool(deps) {
|
|
|
12437
14447
|
"report",
|
|
12438
14448
|
"agents",
|
|
12439
14449
|
"console",
|
|
12440
|
-
"clear-cache"
|
|
14450
|
+
"clear-cache",
|
|
14451
|
+
"upgrade",
|
|
14452
|
+
"upgrade-check"
|
|
12441
14453
|
]).describe("Action to run"),
|
|
12442
|
-
model: tool.schema.string().optional().describe("Model provider/model (only for action=set)")
|
|
14454
|
+
model: tool.schema.string().optional().describe("Model provider/model (only for action=set)"),
|
|
14455
|
+
version: tool.schema.string().optional()
|
|
12443
14456
|
},
|
|
12444
14457
|
async execute(args) {
|
|
12445
|
-
const result = await runCli(commandArgv(args.action, args.model), deps);
|
|
14458
|
+
const result = await runCli(commandArgv(args.action, args.model, args.version), deps);
|
|
12446
14459
|
return result.stdout;
|
|
12447
14460
|
}
|
|
12448
14461
|
});
|
|
@@ -12612,36 +14625,36 @@ function formatResponse(response) {
|
|
|
12612
14625
|
}
|
|
12613
14626
|
|
|
12614
14627
|
// src/plugin/reportRunSchema.ts
|
|
12615
|
-
import { z as
|
|
14628
|
+
import { z as z22 } from "zod";
|
|
12616
14629
|
|
|
12617
14630
|
// src/plugin/graphShadowIngress.ts
|
|
12618
|
-
import { z as
|
|
14631
|
+
import { z as z21 } from "zod";
|
|
12619
14632
|
var LEGACY_EXECUTION_TRACE_VERSION = 1;
|
|
12620
|
-
var LegacyExecutionStatusSchema =
|
|
14633
|
+
var LegacyExecutionStatusSchema = z21.enum([
|
|
12621
14634
|
"completed",
|
|
12622
14635
|
"failed",
|
|
12623
14636
|
"cancelled"
|
|
12624
14637
|
]);
|
|
12625
|
-
var LegacyReviewOutcomeSchema =
|
|
14638
|
+
var LegacyReviewOutcomeSchema = z21.enum([
|
|
12626
14639
|
"approved",
|
|
12627
14640
|
"rejected",
|
|
12628
14641
|
"inconclusive"
|
|
12629
14642
|
]);
|
|
12630
|
-
var LegacyTraceNodeV1Schema =
|
|
14643
|
+
var LegacyTraceNodeV1Schema = z21.object({
|
|
12631
14644
|
id: NodeIDSchema,
|
|
12632
14645
|
role: NodeRoleSchema,
|
|
12633
|
-
model:
|
|
12634
|
-
sessionRef:
|
|
14646
|
+
model: z21.string().min(1),
|
|
14647
|
+
sessionRef: z21.string().min(1).optional(),
|
|
12635
14648
|
errorClass: ErrorClassSchema.optional()
|
|
12636
14649
|
}).strict();
|
|
12637
|
-
var LegacyExecutionTraceV1Schema =
|
|
12638
|
-
version:
|
|
14650
|
+
var LegacyExecutionTraceV1Schema = z21.object({
|
|
14651
|
+
version: z21.literal(LEGACY_EXECUTION_TRACE_VERSION),
|
|
12639
14652
|
runID: NodeIDSchema,
|
|
12640
14653
|
status: LegacyExecutionStatusSchema,
|
|
12641
14654
|
outcome: LegacyReviewOutcomeSchema,
|
|
12642
|
-
fixes:
|
|
12643
|
-
nodes:
|
|
12644
|
-
parentSessionRef:
|
|
14655
|
+
fixes: z21.number().int().nonnegative(),
|
|
14656
|
+
nodes: z21.array(LegacyTraceNodeV1Schema).min(1),
|
|
14657
|
+
parentSessionRef: z21.string().min(1).optional()
|
|
12645
14658
|
}).strict();
|
|
12646
14659
|
function gateReason2(gate) {
|
|
12647
14660
|
if (gate === undefined || gate.mode === "off") {
|
|
@@ -12712,20 +14725,20 @@ function parseLegacyExecutionTrace(input) {
|
|
|
12712
14725
|
}
|
|
12713
14726
|
|
|
12714
14727
|
// src/plugin/reportRunSchema.ts
|
|
12715
|
-
var ReportRunNodeSchema =
|
|
14728
|
+
var ReportRunNodeSchema = z22.object({
|
|
12716
14729
|
id: NodeIDSchema,
|
|
12717
14730
|
role: NodeRoleSchema,
|
|
12718
|
-
model:
|
|
12719
|
-
ok:
|
|
12720
|
-
sessionRef:
|
|
14731
|
+
model: z22.string().min(1),
|
|
14732
|
+
ok: z22.boolean(),
|
|
14733
|
+
sessionRef: z22.string().min(1).optional(),
|
|
12721
14734
|
errorClass: ErrorClassSchema.optional()
|
|
12722
14735
|
}).strict();
|
|
12723
|
-
var ReportRunPayloadSchema =
|
|
14736
|
+
var ReportRunPayloadSchema = z22.object({
|
|
12724
14737
|
runID: NodeIDSchema,
|
|
12725
14738
|
status: LegacyExecutionStatusSchema,
|
|
12726
|
-
fixes:
|
|
12727
|
-
nodes:
|
|
12728
|
-
parentSessionRef:
|
|
14739
|
+
fixes: z22.number().int().nonnegative(),
|
|
14740
|
+
nodes: z22.array(ReportRunNodeSchema).min(1),
|
|
14741
|
+
parentSessionRef: z22.string().min(1).optional()
|
|
12729
14742
|
}).strict();
|
|
12730
14743
|
|
|
12731
14744
|
// src/orchestrator/graphShadow.ts
|
|
@@ -14026,62 +16039,62 @@ ${lines.join(`
|
|
|
14026
16039
|
}
|
|
14027
16040
|
|
|
14028
16041
|
// src/memory/types.ts
|
|
14029
|
-
import { z as
|
|
16042
|
+
import { z as z23 } from "zod";
|
|
14030
16043
|
var SHARED_OWNER_KEY = "*";
|
|
14031
|
-
var OwnerKeySchema =
|
|
14032
|
-
var MemoryKindSchema =
|
|
14033
|
-
var MemoryBaseSchema =
|
|
14034
|
-
id:
|
|
16044
|
+
var OwnerKeySchema = z23.string().min(1);
|
|
16045
|
+
var MemoryKindSchema = z23.enum(["fact", "preference", "entity"]);
|
|
16046
|
+
var MemoryBaseSchema = z23.object({
|
|
16047
|
+
id: z23.string().min(1),
|
|
14035
16048
|
ownerKey: OwnerKeySchema,
|
|
14036
|
-
confidence:
|
|
14037
|
-
validFrom:
|
|
14038
|
-
validUntil:
|
|
14039
|
-
createdAt:
|
|
14040
|
-
invalidatedAt:
|
|
14041
|
-
sourceHash:
|
|
14042
|
-
supersededBy:
|
|
16049
|
+
confidence: z23.number().min(0).max(1),
|
|
16050
|
+
validFrom: z23.number().finite(),
|
|
16051
|
+
validUntil: z23.number().finite().nullable().default(null),
|
|
16052
|
+
createdAt: z23.number().finite(),
|
|
16053
|
+
invalidatedAt: z23.number().finite().nullable().default(null),
|
|
16054
|
+
sourceHash: z23.string().min(1),
|
|
16055
|
+
supersededBy: z23.string().min(1).nullable().default(null)
|
|
14043
16056
|
}).strict();
|
|
14044
16057
|
var FactSchema = MemoryBaseSchema.extend({
|
|
14045
|
-
kind:
|
|
14046
|
-
subject:
|
|
14047
|
-
predicate:
|
|
14048
|
-
object:
|
|
14049
|
-
category:
|
|
16058
|
+
kind: z23.literal("fact"),
|
|
16059
|
+
subject: z23.string().min(1),
|
|
16060
|
+
predicate: z23.string().min(1),
|
|
16061
|
+
object: z23.string().min(1),
|
|
16062
|
+
category: z23.string().min(1).nullable().default(null)
|
|
14050
16063
|
});
|
|
14051
16064
|
var PreferenceSchema = MemoryBaseSchema.extend({
|
|
14052
|
-
kind:
|
|
14053
|
-
category:
|
|
14054
|
-
preference:
|
|
14055
|
-
context:
|
|
14056
|
-
lastAccessedAt:
|
|
14057
|
-
accessCount:
|
|
16065
|
+
kind: z23.literal("preference"),
|
|
16066
|
+
category: z23.string().min(1),
|
|
16067
|
+
preference: z23.string().min(1),
|
|
16068
|
+
context: z23.string().min(1).nullable().default(null),
|
|
16069
|
+
lastAccessedAt: z23.number().finite().nullable().default(null),
|
|
16070
|
+
accessCount: z23.number().int().min(0).default(0)
|
|
14058
16071
|
});
|
|
14059
16072
|
var EntitySchema = MemoryBaseSchema.extend({
|
|
14060
|
-
kind:
|
|
14061
|
-
canonicalName:
|
|
14062
|
-
type:
|
|
14063
|
-
aliases:
|
|
16073
|
+
kind: z23.literal("entity"),
|
|
16074
|
+
canonicalName: z23.string().min(1),
|
|
16075
|
+
type: z23.string().min(1),
|
|
16076
|
+
aliases: z23.array(z23.string().min(1)).default([])
|
|
14064
16077
|
});
|
|
14065
16078
|
var RelationSchema = MemoryBaseSchema.extend({
|
|
14066
|
-
kind:
|
|
14067
|
-
from:
|
|
14068
|
-
to:
|
|
14069
|
-
predicate:
|
|
14070
|
-
annotation:
|
|
16079
|
+
kind: z23.literal("relation"),
|
|
16080
|
+
from: z23.string().min(1),
|
|
16081
|
+
to: z23.string().min(1),
|
|
16082
|
+
predicate: z23.string().min(1),
|
|
16083
|
+
annotation: z23.string().min(1).nullable().default(null)
|
|
14071
16084
|
});
|
|
14072
|
-
var MemoryRecordSchema =
|
|
16085
|
+
var MemoryRecordSchema = z23.discriminatedUnion("kind", [
|
|
14073
16086
|
FactSchema,
|
|
14074
16087
|
PreferenceSchema,
|
|
14075
16088
|
EntitySchema,
|
|
14076
16089
|
RelationSchema
|
|
14077
16090
|
]);
|
|
14078
|
-
var RecallQuerySchema =
|
|
16091
|
+
var RecallQuerySchema = z23.object({
|
|
14079
16092
|
ownerKey: OwnerKeySchema,
|
|
14080
|
-
kinds:
|
|
14081
|
-
asOf:
|
|
14082
|
-
limit:
|
|
14083
|
-
minSimilarity:
|
|
14084
|
-
includeShared:
|
|
16093
|
+
kinds: z23.array(MemoryKindSchema).default(["fact", "preference", "entity"]),
|
|
16094
|
+
asOf: z23.number().finite().nullable().default(null),
|
|
16095
|
+
limit: z23.number().int().positive().default(8),
|
|
16096
|
+
minSimilarity: z23.number().min(0).max(1).default(0.2),
|
|
16097
|
+
includeShared: z23.boolean().default(true)
|
|
14085
16098
|
}).strict();
|
|
14086
16099
|
|
|
14087
16100
|
// src/memory/rank.ts
|
|
@@ -14652,42 +16665,42 @@ function buildMemoryInjector(deps, policy) {
|
|
|
14652
16665
|
|
|
14653
16666
|
// src/plugin/memoryTool.ts
|
|
14654
16667
|
import { tool as tool3 } from "@opencode-ai/plugin";
|
|
14655
|
-
import { z as
|
|
16668
|
+
import { z as z25 } from "zod";
|
|
14656
16669
|
|
|
14657
16670
|
// src/memory/extract.ts
|
|
14658
|
-
import { z as
|
|
16671
|
+
import { z as z24 } from "zod";
|
|
14659
16672
|
var REDACTED = "[redacted]";
|
|
14660
|
-
var RawFactSchema =
|
|
14661
|
-
subject:
|
|
14662
|
-
predicate:
|
|
14663
|
-
object:
|
|
14664
|
-
category:
|
|
14665
|
-
confidence:
|
|
16673
|
+
var RawFactSchema = z24.object({
|
|
16674
|
+
subject: z24.string().min(1),
|
|
16675
|
+
predicate: z24.string().min(1),
|
|
16676
|
+
object: z24.string().min(1),
|
|
16677
|
+
category: z24.string().min(1).nullable().optional(),
|
|
16678
|
+
confidence: z24.number().min(0).max(1).optional()
|
|
14666
16679
|
});
|
|
14667
|
-
var RawPreferenceSchema =
|
|
14668
|
-
category:
|
|
14669
|
-
preference:
|
|
14670
|
-
context:
|
|
14671
|
-
confidence:
|
|
16680
|
+
var RawPreferenceSchema = z24.object({
|
|
16681
|
+
category: z24.string().min(1),
|
|
16682
|
+
preference: z24.string().min(1),
|
|
16683
|
+
context: z24.string().min(1).nullable().optional(),
|
|
16684
|
+
confidence: z24.number().min(0).max(1).optional()
|
|
14672
16685
|
});
|
|
14673
|
-
var RawEntitySchema =
|
|
14674
|
-
canonicalName:
|
|
14675
|
-
type:
|
|
14676
|
-
aliases:
|
|
14677
|
-
confidence:
|
|
16686
|
+
var RawEntitySchema = z24.object({
|
|
16687
|
+
canonicalName: z24.string().min(1),
|
|
16688
|
+
type: z24.string().min(1),
|
|
16689
|
+
aliases: z24.array(z24.string().min(1)).optional(),
|
|
16690
|
+
confidence: z24.number().min(0).max(1).optional()
|
|
14678
16691
|
});
|
|
14679
|
-
var RawRelationSchema =
|
|
14680
|
-
from:
|
|
14681
|
-
to:
|
|
14682
|
-
predicate:
|
|
14683
|
-
annotation:
|
|
14684
|
-
confidence:
|
|
16692
|
+
var RawRelationSchema = z24.object({
|
|
16693
|
+
from: z24.string().min(1),
|
|
16694
|
+
to: z24.string().min(1),
|
|
16695
|
+
predicate: z24.string().min(1),
|
|
16696
|
+
annotation: z24.string().min(1).nullable().optional(),
|
|
16697
|
+
confidence: z24.number().min(0).max(1).optional()
|
|
14685
16698
|
}).strict();
|
|
14686
|
-
var RawExtractionSchema =
|
|
14687
|
-
facts:
|
|
14688
|
-
preferences:
|
|
14689
|
-
entities:
|
|
14690
|
-
relations:
|
|
16699
|
+
var RawExtractionSchema = z24.object({
|
|
16700
|
+
facts: z24.array(RawFactSchema).default([]),
|
|
16701
|
+
preferences: z24.array(RawPreferenceSchema).default([]),
|
|
16702
|
+
entities: z24.array(RawEntitySchema).default([]),
|
|
16703
|
+
relations: z24.array(RawRelationSchema).default([])
|
|
14691
16704
|
});
|
|
14692
16705
|
var DEFAULT_CONFIDENCE = 0.6;
|
|
14693
16706
|
var SYSTEM_PROMPT = [
|
|
@@ -14941,13 +16954,13 @@ var memoryToolMessages = {
|
|
|
14941
16954
|
|
|
14942
16955
|
// src/plugin/memoryTool.ts
|
|
14943
16956
|
var SCRIBE_ROLE_ID = "scribe";
|
|
14944
|
-
var MemoryMessageSchema =
|
|
14945
|
-
role:
|
|
14946
|
-
content:
|
|
16957
|
+
var MemoryMessageSchema = z25.object({
|
|
16958
|
+
role: z25.enum(["system", "user", "assistant"]).describe(memoryToolMessages.messageRoleDescription),
|
|
16959
|
+
content: z25.string().min(1).describe(memoryToolMessages.messageContentDescription)
|
|
14947
16960
|
}).strict();
|
|
14948
|
-
var MemoryWritePayloadSchema =
|
|
14949
|
-
messages:
|
|
14950
|
-
roleID:
|
|
16961
|
+
var MemoryWritePayloadSchema = z25.object({
|
|
16962
|
+
messages: z25.array(MemoryMessageSchema).min(1).describe(memoryToolMessages.messagesDescription),
|
|
16963
|
+
roleID: z25.string().min(1).default(SCRIBE_ROLE_ID).describe(memoryToolMessages.roleIDDescription)
|
|
14951
16964
|
}).strict();
|
|
14952
16965
|
function createMemoryTool(deps) {
|
|
14953
16966
|
return tool3({
|
|
@@ -15072,10 +17085,10 @@ function createOrchestratedModelOwnership() {
|
|
|
15072
17085
|
|
|
15073
17086
|
// src/plugin/orchestrateTool.ts
|
|
15074
17087
|
import { tool as tool4 } from "@opencode-ai/plugin";
|
|
15075
|
-
import { z as
|
|
17088
|
+
import { z as z27 } from "zod";
|
|
15076
17089
|
|
|
15077
17090
|
// src/orchestrator/coordinator.ts
|
|
15078
|
-
import { z as
|
|
17091
|
+
import { z as z26 } from "zod";
|
|
15079
17092
|
|
|
15080
17093
|
// src/orchestrator/nodeIteration.ts
|
|
15081
17094
|
var DEFAULT_MAX_RETRIES = 2;
|
|
@@ -15084,7 +17097,7 @@ function nodePassBudget(maxRetries) {
|
|
|
15084
17097
|
}
|
|
15085
17098
|
|
|
15086
17099
|
// src/orchestrator/outputContract.ts
|
|
15087
|
-
import { createHash as
|
|
17100
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
15088
17101
|
var ROLE_REPORTS_ROOT = ".opencode/openteam-local/reports";
|
|
15089
17102
|
var REPORT_STATUS_MARKER = "openteam-status";
|
|
15090
17103
|
var REPORT_STATUS_LINE_PATTERN = /^[ ]{0,3}openteam-status:[ \t]*(.*?)[ \t]*$/i;
|
|
@@ -15151,7 +17164,7 @@ var REPORT_SEGMENT_HASH_CHARS = 24;
|
|
|
15151
17164
|
var SAFE_REPORT_SEGMENT = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,62}[A-Za-z0-9_-])?$/;
|
|
15152
17165
|
var WINDOWS_DEVICE_NAME = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i;
|
|
15153
17166
|
function reportSegmentHash(value) {
|
|
15154
|
-
return
|
|
17167
|
+
return createHash3("sha256").update(value, "utf8").digest("hex").slice(0, REPORT_SEGMENT_HASH_CHARS);
|
|
15155
17168
|
}
|
|
15156
17169
|
function reportPathSegment(value) {
|
|
15157
17170
|
if (value.length <= MAX_REPORT_SEGMENT_CHARS && SAFE_REPORT_SEGMENT.test(value) && value === value.toLowerCase() && !WINDOWS_DEVICE_NAME.test(value)) {
|
|
@@ -15543,7 +17556,7 @@ function buildRecord(input, decision2, subsession, deps, decisionID, batchID) {
|
|
|
15543
17556
|
}
|
|
15544
17557
|
return record;
|
|
15545
17558
|
}
|
|
15546
|
-
var TelemetryFailureClassSchema =
|
|
17559
|
+
var TelemetryFailureClassSchema = z26.enum([
|
|
15547
17560
|
"create-rejected",
|
|
15548
17561
|
"create-no-id",
|
|
15549
17562
|
"prompt-rejected",
|
|
@@ -16359,7 +18372,7 @@ async function runRoleTasks(inputs, deps, options = {}) {
|
|
|
16359
18372
|
var _pluginWarnedRoles = new Set;
|
|
16360
18373
|
var EMPTY_ROLE_ID_SET = new Set;
|
|
16361
18374
|
var SAFE_ROLE_ID = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
16362
|
-
var RoleIDSchema =
|
|
18375
|
+
var RoleIDSchema = z27.string().min(1).superRefine((roleID, ctx) => {
|
|
16363
18376
|
if (!SAFE_ROLE_ID.test(roleID)) {
|
|
16364
18377
|
ctx.addIssue({
|
|
16365
18378
|
code: "custom",
|
|
@@ -16367,16 +18380,16 @@ var RoleIDSchema = z26.string().min(1).superRefine((roleID, ctx) => {
|
|
|
16367
18380
|
});
|
|
16368
18381
|
}
|
|
16369
18382
|
});
|
|
16370
|
-
var RoleAssignmentSchema =
|
|
18383
|
+
var RoleAssignmentSchema = z27.object({
|
|
16371
18384
|
roleID: RoleIDSchema.describe("Role identifier from the roster"),
|
|
16372
|
-
prompt:
|
|
16373
|
-
title:
|
|
16374
|
-
dependsOn:
|
|
18385
|
+
prompt: z27.string().min(1).describe("Work prompt for this role"),
|
|
18386
|
+
title: z27.string().min(1).optional().describe("Human-readable title"),
|
|
18387
|
+
dependsOn: z27.array(RoleIDSchema).optional().describe("Role IDs this assignment depends on (DAG edges)")
|
|
16375
18388
|
}).strict();
|
|
16376
|
-
var OrchestratePayloadSchema =
|
|
16377
|
-
assignments:
|
|
16378
|
-
parentSessionID:
|
|
16379
|
-
directory:
|
|
18389
|
+
var OrchestratePayloadSchema = z27.object({
|
|
18390
|
+
assignments: z27.array(RoleAssignmentSchema).min(1).describe("Role assignments to distribute"),
|
|
18391
|
+
parentSessionID: z27.string().min(1).optional().describe(PARENT_SESSION_DESCRIPTION),
|
|
18392
|
+
directory: z27.string().min(1).optional().describe("Working directory override")
|
|
16380
18393
|
}).strict();
|
|
16381
18394
|
function validateAssignmentDependencies(assignments) {
|
|
16382
18395
|
const ids = new Set;
|
|
@@ -16434,12 +18447,12 @@ function validateAssignmentDependencies(assignments) {
|
|
|
16434
18447
|
}
|
|
16435
18448
|
return;
|
|
16436
18449
|
}
|
|
16437
|
-
function
|
|
18450
|
+
function isRecord7(value) {
|
|
16438
18451
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16439
18452
|
}
|
|
16440
18453
|
function nestedRecord2(value, key) {
|
|
16441
18454
|
const nested = value[key];
|
|
16442
|
-
return
|
|
18455
|
+
return isRecord7(nested) ? nested : undefined;
|
|
16443
18456
|
}
|
|
16444
18457
|
function numberField(records, keys) {
|
|
16445
18458
|
for (const record of records) {
|
|
@@ -16512,7 +18525,7 @@ function retryableFailure(failureClass, statusCode, declared) {
|
|
|
16512
18525
|
return failureClass === "prompt-timeout" || failureClass === "prompt-rate-limited" || failureClass === "prompt-connection" || failureClass === "prompt-server" || statusCode !== undefined && statusCode >= 500 && statusCode <= 599;
|
|
16513
18526
|
}
|
|
16514
18527
|
function normalizeSdkSessionFailure(error, stage) {
|
|
16515
|
-
const root =
|
|
18528
|
+
const root = isRecord7(error) ? error : {};
|
|
16516
18529
|
const data = nestedRecord2(root, "data");
|
|
16517
18530
|
const nestedError = nestedRecord2(root, "error");
|
|
16518
18531
|
const records = [
|
|
@@ -16531,7 +18544,7 @@ function normalizeSdkSessionFailure(error, stage) {
|
|
|
16531
18544
|
};
|
|
16532
18545
|
}
|
|
16533
18546
|
function nestedAssistantFailure(data) {
|
|
16534
|
-
if (!
|
|
18547
|
+
if (!isRecord7(data)) {
|
|
16535
18548
|
return;
|
|
16536
18549
|
}
|
|
16537
18550
|
return nestedRecord2(data, "info")?.error;
|
|
@@ -17112,7 +19125,7 @@ ${advisory}`;
|
|
|
17112
19125
|
|
|
17113
19126
|
// src/plugin/registerCastTool.ts
|
|
17114
19127
|
import { tool as tool5 } from "@opencode-ai/plugin";
|
|
17115
|
-
import { z as
|
|
19128
|
+
import { z as z28 } from "zod";
|
|
17116
19129
|
|
|
17117
19130
|
// src/orchestrator/rosterPersistence.ts
|
|
17118
19131
|
function rosterFence(roster) {
|
|
@@ -17147,13 +19160,13 @@ async function persistRosterPreservingProse(storage, roster, path4 = OPENTEAM_RO
|
|
|
17147
19160
|
}
|
|
17148
19161
|
|
|
17149
19162
|
// src/plugin/registerCastTool.ts
|
|
17150
|
-
var CastEntrySchema =
|
|
17151
|
-
roleID:
|
|
17152
|
-
agentName:
|
|
19163
|
+
var CastEntrySchema = z28.object({
|
|
19164
|
+
roleID: z28.string().min(1).describe("Stable role identifier, e.g. scribe or guardian"),
|
|
19165
|
+
agentName: z28.string().min(1).describe("Themed character name assigned to the role")
|
|
17153
19166
|
}).strict();
|
|
17154
|
-
var RegisterCastPayloadSchema =
|
|
17155
|
-
universe:
|
|
17156
|
-
entries:
|
|
19167
|
+
var RegisterCastPayloadSchema = z28.object({
|
|
19168
|
+
universe: z28.string().min(1).describe("Casting universe for this roster"),
|
|
19169
|
+
entries: z28.array(CastEntrySchema).min(1).describe("Role-to-name mappings")
|
|
17157
19170
|
}).strict();
|
|
17158
19171
|
function offendingFields(error) {
|
|
17159
19172
|
const fields = error.issues.flatMap((issue) => {
|
|
@@ -17443,7 +19456,7 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
|
|
|
17443
19456
|
}
|
|
17444
19457
|
|
|
17445
19458
|
// src/storage/lifecycle/fsLifecycleJournal.ts
|
|
17446
|
-
import { randomUUID as
|
|
19459
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
17447
19460
|
import {
|
|
17448
19461
|
lstatSync as lstatSync3,
|
|
17449
19462
|
mkdirSync as mkdirSync3,
|
|
@@ -17453,22 +19466,22 @@ import {
|
|
|
17453
19466
|
statSync,
|
|
17454
19467
|
unlinkSync as unlinkSync2
|
|
17455
19468
|
} from "node:fs";
|
|
17456
|
-
import { join as
|
|
19469
|
+
import { join as join13, resolve as resolve8 } from "node:path";
|
|
17457
19470
|
import { ZodError } from "zod";
|
|
17458
19471
|
|
|
17459
19472
|
// src/storage/lifecycle/codec.ts
|
|
17460
|
-
import { z as
|
|
19473
|
+
import { z as z29 } from "zod";
|
|
17461
19474
|
var LIFECYCLE_CODEC_VERSION = 1;
|
|
17462
19475
|
var LIFECYCLE_GENESIS_DIGEST = sha256Hex("openteam/lifecycle-journal/genesis/v1");
|
|
17463
19476
|
var NUL5 = "\x00";
|
|
17464
19477
|
var NEWLINE2 = `
|
|
17465
19478
|
`;
|
|
17466
|
-
var frameSchema =
|
|
17467
|
-
v:
|
|
17468
|
-
seq:
|
|
17469
|
-
prev:
|
|
17470
|
-
sum:
|
|
17471
|
-
event:
|
|
19479
|
+
var frameSchema = z29.object({
|
|
19480
|
+
v: z29.literal(LIFECYCLE_CODEC_VERSION),
|
|
19481
|
+
seq: z29.number().int().nonnegative(),
|
|
19482
|
+
prev: z29.string().min(1),
|
|
19483
|
+
sum: z29.string().min(1),
|
|
19484
|
+
event: z29.unknown()
|
|
17472
19485
|
}).strict();
|
|
17473
19486
|
function canonical2(value) {
|
|
17474
19487
|
if (Array.isArray(value)) {
|
|
@@ -17555,7 +19568,7 @@ function decodeLifecycleJournal(text) {
|
|
|
17555
19568
|
}
|
|
17556
19569
|
|
|
17557
19570
|
// src/storage/lifecycle/fsLifecycleSupport.ts
|
|
17558
|
-
import { randomUUID } from "node:crypto";
|
|
19571
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
17559
19572
|
import {
|
|
17560
19573
|
appendFileSync,
|
|
17561
19574
|
closeSync as closeSync2,
|
|
@@ -17572,7 +19585,7 @@ import {
|
|
|
17572
19585
|
unlinkSync,
|
|
17573
19586
|
writeSync as writeSync2
|
|
17574
19587
|
} from "node:fs";
|
|
17575
|
-
import { basename as
|
|
19588
|
+
import { basename as basename3, dirname as dirname5, join as join12, relative as relative3, resolve as resolve7 } from "node:path";
|
|
17576
19589
|
var SAFE_RUN_ID = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,126}[A-Za-z0-9])?$/u;
|
|
17577
19590
|
|
|
17578
19591
|
class LifecycleFsError extends Error {
|
|
@@ -17596,7 +19609,7 @@ function validateRunID(runID) {
|
|
|
17596
19609
|
}
|
|
17597
19610
|
function resolvedLifecycleRoot(root) {
|
|
17598
19611
|
try {
|
|
17599
|
-
const absolute =
|
|
19612
|
+
const absolute = resolve7(root);
|
|
17600
19613
|
mkdirSync2(absolute, { recursive: true });
|
|
17601
19614
|
const rootStat = lstatSync2(absolute);
|
|
17602
19615
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
|
|
@@ -17612,8 +19625,8 @@ function resolvedLifecycleRoot(root) {
|
|
|
17612
19625
|
}
|
|
17613
19626
|
function directRunPath(root, runID) {
|
|
17614
19627
|
validateRunID(runID);
|
|
17615
|
-
const path4 =
|
|
17616
|
-
if (
|
|
19628
|
+
const path4 = join12(root, runID);
|
|
19629
|
+
if (dirname5(path4) !== root || basename3(path4) !== runID) {
|
|
17617
19630
|
throw new LifecycleFsError("corrupt");
|
|
17618
19631
|
}
|
|
17619
19632
|
return path4;
|
|
@@ -17638,8 +19651,8 @@ function assertExistingSafeRun(root, runID) {
|
|
|
17638
19651
|
} catch {
|
|
17639
19652
|
throw new LifecycleFsError("unavailable");
|
|
17640
19653
|
}
|
|
17641
|
-
const child =
|
|
17642
|
-
if (child === "" || child.startsWith("..") ||
|
|
19654
|
+
const child = relative3(root, real);
|
|
19655
|
+
if (child === "" || child.startsWith("..") || resolve7(root, child) !== real || dirname5(real) !== root) {
|
|
17643
19656
|
throw new LifecycleFsError("corrupt");
|
|
17644
19657
|
}
|
|
17645
19658
|
return real;
|
|
@@ -17688,7 +19701,7 @@ function appendDurable2(path4, content) {
|
|
|
17688
19701
|
}
|
|
17689
19702
|
}
|
|
17690
19703
|
function writeDurableAtomically(path4, content) {
|
|
17691
|
-
const temporary =
|
|
19704
|
+
const temporary = join12(dirname5(path4), `.${basename3(path4)}.${randomUUID2()}.next`);
|
|
17692
19705
|
try {
|
|
17693
19706
|
writeDurable2(temporary, content);
|
|
17694
19707
|
renameSync(temporary, path4);
|
|
@@ -17710,8 +19723,8 @@ function readLockContents(path4) {
|
|
|
17710
19723
|
}
|
|
17711
19724
|
}
|
|
17712
19725
|
function withRunMutationLock(runDir, mutate) {
|
|
17713
|
-
const lockPath =
|
|
17714
|
-
const lockToken =
|
|
19726
|
+
const lockPath = join12(runDir, ".mutation-lock");
|
|
19727
|
+
const lockToken = randomUUID2();
|
|
17715
19728
|
let descriptor;
|
|
17716
19729
|
try {
|
|
17717
19730
|
descriptor = openSync2(lockPath, "wx");
|
|
@@ -17780,7 +19793,7 @@ function parseJson(text, parse2) {
|
|
|
17780
19793
|
}
|
|
17781
19794
|
}
|
|
17782
19795
|
function issueWriterToken() {
|
|
17783
|
-
return
|
|
19796
|
+
return randomUUID3().replaceAll("-", "");
|
|
17784
19797
|
}
|
|
17785
19798
|
function createLease(runID, writerToken, input) {
|
|
17786
19799
|
return parseLifecycleWriterLease({
|
|
@@ -17795,12 +19808,12 @@ function createLease(runID, writerToken, input) {
|
|
|
17795
19808
|
});
|
|
17796
19809
|
}
|
|
17797
19810
|
function readLease2(runDir) {
|
|
17798
|
-
const text = readUtf8(
|
|
19811
|
+
const text = readUtf8(join13(runDir, OWNER_FILE2));
|
|
17799
19812
|
return text === undefined ? undefined : parseJson(text, parseLifecycleWriterLease);
|
|
17800
19813
|
}
|
|
17801
19814
|
function readRun(runDir, runID) {
|
|
17802
|
-
const metadataPath =
|
|
17803
|
-
const eventsPath =
|
|
19815
|
+
const metadataPath = join13(runDir, METADATA_FILE);
|
|
19816
|
+
const eventsPath = join13(runDir, EVENTS_FILE);
|
|
17804
19817
|
assertSafeRegularFile(metadataPath);
|
|
17805
19818
|
assertSafeRegularFile(eventsPath);
|
|
17806
19819
|
const metadataText = readUtf8(metadataPath);
|
|
@@ -17847,7 +19860,7 @@ function summaryForRun(runDir, runID) {
|
|
|
17847
19860
|
}
|
|
17848
19861
|
function runBytes(runDir) {
|
|
17849
19862
|
return readdirSync2(runDir).reduce((total, entry) => {
|
|
17850
|
-
const path4 =
|
|
19863
|
+
const path4 = join13(runDir, entry);
|
|
17851
19864
|
const stats = lstatSync3(path4);
|
|
17852
19865
|
if (!stats.isFile() || stats.isSymbolicLink()) {
|
|
17853
19866
|
throw new LifecycleFsError("corrupt");
|
|
@@ -17879,7 +19892,7 @@ function canDeleteTerminalRun(runDir, runID, now) {
|
|
|
17879
19892
|
return now >= lease.expiresAt;
|
|
17880
19893
|
}
|
|
17881
19894
|
var createFsLifecycleJournal = (options) => {
|
|
17882
|
-
const configuredRoot =
|
|
19895
|
+
const configuredRoot = resolve8(options.root);
|
|
17883
19896
|
const now = options.now ?? Date.now;
|
|
17884
19897
|
const mutateRun = options.withMutationLock ?? withRunMutationLock;
|
|
17885
19898
|
return {
|
|
@@ -17901,7 +19914,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
17901
19914
|
throw error;
|
|
17902
19915
|
}
|
|
17903
19916
|
}
|
|
17904
|
-
stagingPath =
|
|
19917
|
+
stagingPath = join13(root, `.start-${runID}-${randomUUID3()}`);
|
|
17905
19918
|
mkdirSync3(stagingPath);
|
|
17906
19919
|
const writerToken = issueWriterToken();
|
|
17907
19920
|
const eventAt = now();
|
|
@@ -17921,10 +19934,10 @@ var createFsLifecycleJournal = (options) => {
|
|
|
17921
19934
|
executionAuthority: parsedInput.executionAuthority,
|
|
17922
19935
|
root: parsedInput.root
|
|
17923
19936
|
});
|
|
17924
|
-
writeDurable2(
|
|
19937
|
+
writeDurable2(join13(stagingPath, METADATA_FILE), `${JSON.stringify(metadata)}
|
|
17925
19938
|
`);
|
|
17926
|
-
writeDurable2(
|
|
17927
|
-
writeDurable2(
|
|
19939
|
+
writeDurable2(join13(stagingPath, EVENTS_FILE), encodeLifecycleJournal([event]));
|
|
19940
|
+
writeDurable2(join13(stagingPath, OWNER_FILE2), `${JSON.stringify(lease)}
|
|
17928
19941
|
`);
|
|
17929
19942
|
try {
|
|
17930
19943
|
renameSync2(stagingPath, runPath);
|
|
@@ -17966,7 +19979,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
17966
19979
|
}
|
|
17967
19980
|
const writerToken = issueWriterToken();
|
|
17968
19981
|
const lease = createLease(runID, writerToken, parsedLeaseInput);
|
|
17969
|
-
writeDurableAtomically(
|
|
19982
|
+
writeDurableAtomically(join13(runDir, OWNER_FILE2), `${JSON.stringify(lease)}
|
|
17970
19983
|
`);
|
|
17971
19984
|
return ok({ runID, writerToken });
|
|
17972
19985
|
});
|
|
@@ -18023,7 +20036,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
18023
20036
|
...parsedBody
|
|
18024
20037
|
});
|
|
18025
20038
|
const frame = encodeLifecycleFrame(loaded.decoded.digest, committedEvent);
|
|
18026
|
-
appendDurable2(
|
|
20039
|
+
appendDurable2(join13(runDir, EVENTS_FILE), `${frame.line}
|
|
18027
20040
|
`);
|
|
18028
20041
|
return ok({ event: committedEvent, head: actualHead + 1 });
|
|
18029
20042
|
});
|
|
@@ -18053,7 +20066,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
18053
20066
|
heartbeatAt: parsed.now,
|
|
18054
20067
|
expiresAt: parsed.now + parsed.leaseDurationMs
|
|
18055
20068
|
});
|
|
18056
|
-
writeDurableAtomically(
|
|
20069
|
+
writeDurableAtomically(join13(runDir, OWNER_FILE2), `${JSON.stringify(lease)}
|
|
18057
20070
|
`);
|
|
18058
20071
|
return ok({ lease });
|
|
18059
20072
|
});
|
|
@@ -18073,7 +20086,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
18073
20086
|
runID: handle.runID
|
|
18074
20087
|
}));
|
|
18075
20088
|
}
|
|
18076
|
-
unlinkSync2(
|
|
20089
|
+
unlinkSync2(join13(runDir, OWNER_FILE2));
|
|
18077
20090
|
return ok(undefined);
|
|
18078
20091
|
});
|
|
18079
20092
|
} catch (error) {
|
|
@@ -18184,14 +20197,14 @@ var createFsLifecycleJournal = (options) => {
|
|
|
18184
20197
|
};
|
|
18185
20198
|
|
|
18186
20199
|
// src/storage/lifecycle/fsLifecycleWriterLivenessProbe.ts
|
|
18187
|
-
import { join as
|
|
20200
|
+
import { join as join14 } from "node:path";
|
|
18188
20201
|
var createFsLifecycleWriterLivenessProbe = (options) => ({
|
|
18189
20202
|
async observe(runID) {
|
|
18190
20203
|
const observedAt = options.now();
|
|
18191
20204
|
try {
|
|
18192
20205
|
const root = resolvedLifecycleRoot(options.root);
|
|
18193
20206
|
const runDir = assertExistingSafeRun(root, runID);
|
|
18194
|
-
const ownerText = readUtf8(
|
|
20207
|
+
const ownerText = readUtf8(join14(runDir, "owner"));
|
|
18195
20208
|
if (ownerText === undefined) {
|
|
18196
20209
|
return { kind: "absent", observedAt };
|
|
18197
20210
|
}
|
|
@@ -18278,111 +20291,6 @@ var createOtlpSpanExporter = (connection, config) => {
|
|
|
18278
20291
|
}
|
|
18279
20292
|
};
|
|
18280
20293
|
};
|
|
18281
|
-
// package.json
|
|
18282
|
-
var package_default = {
|
|
18283
|
-
name: "@jmanuelcorral/openteam",
|
|
18284
|
-
version: "0.21.0",
|
|
18285
|
-
packageManager: "bun@1.3.14",
|
|
18286
|
-
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
18287
|
-
license: "MIT",
|
|
18288
|
-
author: "Jose Manuel Corral",
|
|
18289
|
-
repository: {
|
|
18290
|
-
type: "git",
|
|
18291
|
-
url: "git+https://github.com/jmanuelcorral/openteam.git"
|
|
18292
|
-
},
|
|
18293
|
-
homepage: "https://github.com/jmanuelcorral/openteam#readme",
|
|
18294
|
-
bugs: {
|
|
18295
|
-
url: "https://github.com/jmanuelcorral/openteam/issues"
|
|
18296
|
-
},
|
|
18297
|
-
keywords: [
|
|
18298
|
-
"opencode",
|
|
18299
|
-
"opencode-plugin",
|
|
18300
|
-
"llm",
|
|
18301
|
-
"routing",
|
|
18302
|
-
"local-llm",
|
|
18303
|
-
"ollama",
|
|
18304
|
-
"lm-studio",
|
|
18305
|
-
"foundry-local",
|
|
18306
|
-
"cost-optimization",
|
|
18307
|
-
"multi-agent"
|
|
18308
|
-
],
|
|
18309
|
-
engines: {
|
|
18310
|
-
bun: ">=1.3",
|
|
18311
|
-
node: "^22.22.2 || ^24.15.0 || >=26.0.0"
|
|
18312
|
-
},
|
|
18313
|
-
type: "module",
|
|
18314
|
-
main: "./dist/index.js",
|
|
18315
|
-
module: "./dist/index.js",
|
|
18316
|
-
types: "./dist/index.d.ts",
|
|
18317
|
-
bin: {
|
|
18318
|
-
openteam: "./dist/cli.js"
|
|
18319
|
-
},
|
|
18320
|
-
exports: {
|
|
18321
|
-
".": {
|
|
18322
|
-
types: "./dist/index.d.ts",
|
|
18323
|
-
import: "./dist/index.js"
|
|
18324
|
-
},
|
|
18325
|
-
"./package.json": "./package.json"
|
|
18326
|
-
},
|
|
18327
|
-
files: [
|
|
18328
|
-
"dist",
|
|
18329
|
-
"README.md",
|
|
18330
|
-
"LICENSE",
|
|
18331
|
-
"AGENTS.md",
|
|
18332
|
-
".opencode/openteam.example.json",
|
|
18333
|
-
".opencode/command/openteam.md"
|
|
18334
|
-
],
|
|
18335
|
-
publishConfig: {
|
|
18336
|
-
access: "public",
|
|
18337
|
-
registry: "https://registry.npmjs.org/"
|
|
18338
|
-
},
|
|
18339
|
-
trustedDependencies: [],
|
|
18340
|
-
sideEffects: false,
|
|
18341
|
-
scripts: {
|
|
18342
|
-
prebuild: "bun run clean",
|
|
18343
|
-
build: "bun run build:js && bun run build:cli && bun run build:types && bun run build:certificates",
|
|
18344
|
-
"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",
|
|
18345
|
-
"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',
|
|
18346
|
-
"build:types": "tsc -p tsconfig.build.json",
|
|
18347
|
-
clean: `node -e "require('node:fs').rmSync('dist', { recursive: true, force: true })"`,
|
|
18348
|
-
test: "bun test",
|
|
18349
|
-
"test:cov": "bun test --coverage",
|
|
18350
|
-
"certify:shadow": "bun run scripts/certify-artifact.ts shadow",
|
|
18351
|
-
"certify:release": "bun run scripts/certify-artifact.ts release",
|
|
18352
|
-
"build:certificates": "bun run certify:shadow && bun run certify:release && bun run scripts/bundle-certificates.ts",
|
|
18353
|
-
"coverage:check": "node scripts/check-coverage.mjs",
|
|
18354
|
-
typecheck: "tsc --noEmit",
|
|
18355
|
-
lint: "biome check .",
|
|
18356
|
-
"format:check": "biome format .",
|
|
18357
|
-
"docs:install": "cd docs && bun install --frozen-lockfile --ignore-scripts",
|
|
18358
|
-
"docs:dev": "cd docs && bun run docs:dev",
|
|
18359
|
-
"docs:build": "cd docs && bun run docs:build",
|
|
18360
|
-
"docs:preview": "cd docs && bun run docs:preview",
|
|
18361
|
-
prepublishOnly: "bun run build",
|
|
18362
|
-
"link:local": "bun run build && npm link",
|
|
18363
|
-
"hooks:install": "git config core.hooksPath .githooks"
|
|
18364
|
-
},
|
|
18365
|
-
dependencies: {
|
|
18366
|
-
"@clack/prompts": "1.7.0",
|
|
18367
|
-
"@langchain/core": "1.2.9",
|
|
18368
|
-
"@langchain/langgraph": "1.4.12",
|
|
18369
|
-
"@opencode-ai/plugin": "1.18.19",
|
|
18370
|
-
"@opencode-ai/sdk": "1.18.19",
|
|
18371
|
-
"@opentelemetry/api": "1.9.1",
|
|
18372
|
-
"@opentelemetry/exporter-trace-otlp-http": "0.221.0",
|
|
18373
|
-
"@opentelemetry/resources": "2.10.0",
|
|
18374
|
-
"@opentelemetry/sdk-trace-base": "2.10.0",
|
|
18375
|
-
zod: "4.4.3"
|
|
18376
|
-
},
|
|
18377
|
-
devDependencies: {
|
|
18378
|
-
"@biomejs/biome": "2.5.9",
|
|
18379
|
-
"@types/bun": "1.3.14",
|
|
18380
|
-
typescript: "7.0.2"
|
|
18381
|
-
}
|
|
18382
|
-
};
|
|
18383
|
-
|
|
18384
|
-
// src/version.ts
|
|
18385
|
-
var PACKAGE_VERSION = package_default.version;
|
|
18386
20294
|
|
|
18387
20295
|
// src/index.ts
|
|
18388
20296
|
var LIFECYCLE_WRITER_IDENTITY = {
|
|
@@ -18484,7 +20392,7 @@ var RELEASE_CERT_PATH = "artifacts/graph-release-certificate.json";
|
|
|
18484
20392
|
var SOAK_CERT_PATH = "artifacts/graph-soak-certificate.json";
|
|
18485
20393
|
async function readPackagedCertificate(path4) {
|
|
18486
20394
|
try {
|
|
18487
|
-
return await
|
|
20395
|
+
return await readFile4(new URL(`./certificates/${basename4(path4)}`, import.meta.url), "utf8");
|
|
18488
20396
|
} catch {
|
|
18489
20397
|
return;
|
|
18490
20398
|
}
|
|
@@ -18499,7 +20407,7 @@ async function readAndParseCertificate(storage, path4, parse2, digestExtractor,
|
|
|
18499
20407
|
const cert = parse2(raw);
|
|
18500
20408
|
return { status: "valid", digest: digestExtractor(cert) };
|
|
18501
20409
|
} catch (error) {
|
|
18502
|
-
if (
|
|
20410
|
+
if (isMissingFile2(error)) {
|
|
18503
20411
|
return { status: "absent" };
|
|
18504
20412
|
}
|
|
18505
20413
|
if (error instanceof ShadowCertificateError || error instanceof ReleaseCertificateError || error instanceof SoakCertificateError) {
|
|
@@ -18616,8 +20524,8 @@ async function readOpencodeVersion(serverUrl, options = {}) {
|
|
|
18616
20524
|
}
|
|
18617
20525
|
var DEFAULT_OPENCODE_VERSION_BACKOFF_MS = [50, 250];
|
|
18618
20526
|
function defaultSleep(ms) {
|
|
18619
|
-
return new Promise((
|
|
18620
|
-
setTimeout(
|
|
20527
|
+
return new Promise((resolve9) => {
|
|
20528
|
+
setTimeout(resolve9, ms);
|
|
18621
20529
|
});
|
|
18622
20530
|
}
|
|
18623
20531
|
function createLazyOpencodeVersionReader(serverUrl, options = {}) {
|
|
@@ -18745,7 +20653,7 @@ function createEventSink(rawOptions, storage = createFsStorageProvider(process.c
|
|
|
18745
20653
|
});
|
|
18746
20654
|
return sink;
|
|
18747
20655
|
}
|
|
18748
|
-
function
|
|
20656
|
+
function isMissingFile2(error) {
|
|
18749
20657
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
18750
20658
|
}
|
|
18751
20659
|
function configReadFailure(path4) {
|
|
@@ -18785,7 +20693,7 @@ async function readRoutingRosterEntries(storage) {
|
|
|
18785
20693
|
return content === undefined ? [] : parseRoster(content).entries;
|
|
18786
20694
|
}
|
|
18787
20695
|
var auditStoredRosterForDoctor = (roster, configuredRoles) => typeof roster === "string" ? auditRoster(roster, configuredRoles) : auditRoster(roster, configuredRoles);
|
|
18788
|
-
function createCliDeps(config, registry, telemetryPath, sessionsDir = DEFAULT_SESSIONS_DIR, storage = createFsStorageProvider(process.cwd()), fallbackSource = "options", rawOptions, resolveOpencodeVersion) {
|
|
20696
|
+
function createCliDeps(config, registry, telemetryPath, sessionsDir = DEFAULT_SESSIONS_DIR, storage = createFsStorageProvider(process.cwd()), fallbackSource = "options", rawOptions, resolveOpencodeVersion, workspaceRoot = process.cwd()) {
|
|
18789
20697
|
return {
|
|
18790
20698
|
loadConfig: async (path4, resolution = { explicit: false }) => {
|
|
18791
20699
|
const content = await readCliConfigFromStorage(storage, path4, resolution);
|
|
@@ -18868,12 +20776,13 @@ function createCliDeps(config, registry, telemetryPath, sessionsDir = DEFAULT_SE
|
|
|
18868
20776
|
telemetryPath,
|
|
18869
20777
|
opencodeConfigPaths: OPENCODE_CONFIG_CANDIDATES,
|
|
18870
20778
|
orchestratorAgentPath: ORCHESTRATOR_AGENT_PATH,
|
|
18871
|
-
agentDir:
|
|
20779
|
+
agentDir: dirname6(ORCHESTRATOR_AGENT_PATH),
|
|
18872
20780
|
cachePort: realCacheAdapter,
|
|
18873
20781
|
purge: createPluginPurgeRuntime(sessionsDir),
|
|
18874
20782
|
loadRosterForDoctor: () => readStoredRosterForDoctor(storage),
|
|
18875
20783
|
auditRoster: auditStoredRosterForDoctor,
|
|
18876
|
-
version: PACKAGE_VERSION
|
|
20784
|
+
version: PACKAGE_VERSION,
|
|
20785
|
+
upgradePort: createFsUpgradePort(workspaceRoot, globalThis.fetch)
|
|
18877
20786
|
};
|
|
18878
20787
|
}
|
|
18879
20788
|
function createPluginPurgeRuntime(sessionsDir) {
|
|
@@ -18998,7 +20907,7 @@ var server = async (ctx, rawOptions) => {
|
|
|
18998
20907
|
const cliDeps = createCliDeps(config, registry, telemetryPath, sessionsDir, storage, runtimeConfig.source, rawOptions, async () => {
|
|
18999
20908
|
const version = await getOpencodeVersion();
|
|
19000
20909
|
return version === "unknown" ? undefined : version;
|
|
19001
|
-
});
|
|
20910
|
+
}, workspaceRoot);
|
|
19002
20911
|
const toolcalls = createToolcallTracker({ sink });
|
|
19003
20912
|
const announcedSessions = new Set;
|
|
19004
20913
|
const announceEndpoint = (sessionID) => {
|
|
@@ -19140,8 +21049,8 @@ var server = async (ctx, rawOptions) => {
|
|
|
19140
21049
|
lifecycleRecorder,
|
|
19141
21050
|
abortGraceMs: DEFAULT_ABORT_GRACE_MS,
|
|
19142
21051
|
statusPollMs: DEFAULT_STATUS_POLL_MS,
|
|
19143
|
-
delay: (ms) => new Promise((
|
|
19144
|
-
setTimeout(
|
|
21052
|
+
delay: (ms) => new Promise((resolve9) => {
|
|
21053
|
+
setTimeout(resolve9, ms);
|
|
19145
21054
|
}),
|
|
19146
21055
|
warn: diagnostics.warn("unknown-role")
|
|
19147
21056
|
});
|
|
@@ -19211,7 +21120,7 @@ export {
|
|
|
19211
21120
|
logTelemetryError,
|
|
19212
21121
|
logOpencodeServerUrl,
|
|
19213
21122
|
logAvailabilityRefreshError,
|
|
19214
|
-
isMissingFile,
|
|
21123
|
+
isMissingFile2 as isMissingFile,
|
|
19215
21124
|
evaluateCutoverGateForBoundary,
|
|
19216
21125
|
src_default as default,
|
|
19217
21126
|
createOpencodeVersionReadFailureLogger,
|