@jmanuelcorral/openteam 0.23.0 → 0.24.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 +28 -8
- package/README.md +24 -7
- package/dist/certificates/graph-release-certificate.json +2 -2
- package/dist/certificates/graph-shadow-certificate.json +2 -2
- package/dist/cli/setupAdapters.d.ts +2 -2
- package/dist/cli/setupAdapters.d.ts.map +1 -1
- package/dist/cli.js +955 -380
- package/dist/commands/agents.d.ts +6 -4
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/dispatch.d.ts +1 -1
- package/dist/commands/dispatch.d.ts.map +1 -1
- package/dist/commands/setup.d.ts +22 -33
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1497 -334
- package/dist/local/lemonade.d.ts.map +1 -1
- package/dist/local/lemonadeRequestGuard.d.ts +11 -0
- package/dist/local/lemonadeRequestGuard.d.ts.map +1 -0
- package/dist/local/lemonadeResidency.d.ts +22 -0
- package/dist/local/lemonadeResidency.d.ts.map +1 -0
- package/dist/local/modelResidency.d.ts +4 -0
- package/dist/local/modelResidency.d.ts.map +1 -0
- package/dist/local/slotPool.d.ts +13 -7
- package/dist/local/slotPool.d.ts.map +1 -1
- package/dist/messages/executionSetup.d.ts +19 -2
- package/dist/messages/executionSetup.d.ts.map +1 -1
- package/dist/messages/modelResidency.d.ts +19 -0
- package/dist/messages/modelResidency.d.ts.map +1 -0
- package/dist/messages/orchestration.d.ts +1 -0
- package/dist/messages/orchestration.d.ts.map +1 -1
- package/dist/messages/reload.d.ts +21 -0
- package/dist/messages/reload.d.ts.map +1 -0
- package/dist/opencodeArtifacts/createRosterReload.d.ts +2 -0
- package/dist/opencodeArtifacts/createRosterReload.d.ts.map +1 -0
- package/dist/opencodeArtifacts/orchestratorAgent.d.ts.map +1 -1
- package/dist/opencodeArtifacts/slashCommand.d.ts.map +1 -1
- package/dist/opencodeArtifacts/teamPreparation.d.ts.map +1 -1
- package/dist/orchestrator/coordinator.d.ts.map +1 -1
- package/dist/orchestrator/roster.d.ts +0 -7
- package/dist/orchestrator/roster.d.ts.map +1 -1
- package/dist/orchestrator/runtimeSelection.d.ts +4 -3
- package/dist/orchestrator/runtimeSelection.d.ts.map +1 -1
- package/dist/orchestrator/sessionStatus.d.ts +12 -0
- package/dist/orchestrator/sessionStatus.d.ts.map +1 -0
- package/dist/orchestrator/subsessions.d.ts +2 -10
- package/dist/orchestrator/subsessions.d.ts.map +1 -1
- package/dist/plugin/availability.d.ts +4 -1
- package/dist/plugin/availability.d.ts.map +1 -1
- package/dist/plugin/hooks.d.ts +2 -0
- package/dist/plugin/hooks.d.ts.map +1 -1
- package/dist/plugin/memoryTool.d.ts +9 -3
- package/dist/plugin/memoryTool.d.ts.map +1 -1
- package/dist/plugin/modelResidency.d.ts +47 -0
- package/dist/plugin/modelResidency.d.ts.map +1 -0
- package/dist/plugin/reloadTool.d.ts +33 -0
- package/dist/plugin/reloadTool.d.ts.map +1 -0
- package/dist/router/types.d.ts +2 -0
- package/dist/router/types.d.ts.map +1 -1
- package/dist/telemetry/diagnostics.d.ts +1 -1
- package/dist/telemetry/diagnostics.d.ts.map +1 -1
- package/dist/telemetry/events.d.ts +24 -0
- package/dist/telemetry/events.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1654,6 +1654,28 @@ var ModelCapabilityProfileSchema = z5.object({
|
|
|
1654
1654
|
availability: z5.enum(["available", "degraded", "unavailable"])
|
|
1655
1655
|
}).strict();
|
|
1656
1656
|
|
|
1657
|
+
// src/messages/reload.ts
|
|
1658
|
+
var reloadMessages = {
|
|
1659
|
+
description: "Queue a project-instance reload only after the user explicitly answers the fresh /create_roster reload question affirmatively. General tool approval, YOLO and earlier project-description answers are not consent. End this turn after queuing; do not dispatch work. Cancel withdraws a pending request.",
|
|
1660
|
+
action: "Request a confirmed reload or cancel this session's queued request.",
|
|
1661
|
+
confirmed: "True only for an unambiguous affirmative human answer to the current reload question, after successful preparation and the full Agent/Role/Model and file summaries. This field records consent; it does not independently prove a human answered.",
|
|
1662
|
+
invalid: "Reload not queued: provide only action (request or cancel) and explicit boolean confirmed. No target directory or other arguments are accepted.",
|
|
1663
|
+
declined: "Reload not queued: explicit affirmative consent to the current reload question is required. No files or policies were changed.",
|
|
1664
|
+
denied: "Reload is restricted to the openteam primary in this plugin's project.",
|
|
1665
|
+
closed: "This reload controller is no longer active. Check the current opencode instance before requesting another reload; agent discovery has not been verified.",
|
|
1666
|
+
other: "A reload request is already pending for another session. This call does not replace or extend its confirmation.",
|
|
1667
|
+
authorizing: "Host permission for this project's reload is still pending. This call queues nothing and does not extend the confirmation deadline.",
|
|
1668
|
+
none: "There is no queued reload for this session to cancel.",
|
|
1669
|
+
"reload-queued": "Reload queued, not completed. Waiting up to 30 seconds for this tool and confirming turn to finish and for all project sessions to be idle. End this turn now; no project work or agent readiness is implied.",
|
|
1670
|
+
"reload-waiting": "Reload is still waiting: project sessions are busy or retrying. They will not be aborted; the original 30-second deadline is unchanged.",
|
|
1671
|
+
"reload-accepted": "opencode accepted the project-instance reload request. Agent discovery and readiness have not been verified; existing discovery safeguards still apply.",
|
|
1672
|
+
"reload-cancelled": "The pending reload was cancelled before disposal was requested. Prepared files, history and policies are unchanged.",
|
|
1673
|
+
"reload-timeout": "Reload was not requested: the 30-second idle deadline expired. A new explicit confirmation is required; nothing will retry automatically.",
|
|
1674
|
+
"reload-status-failed": "Reload was not requested: project activity was missing, malformed, unavailable or did not respond within 5 seconds. No idle state was assumed and no automatic retry is armed.",
|
|
1675
|
+
"reload-dispose-failed": "opencode did not confirm acceptance of the reload request. No automatic retry is armed; check the current instance before trying again. Agent readiness is unverified.",
|
|
1676
|
+
"reload-unconfirmed": "Reload acceptance is unconfirmed because the request timed out, was cancelled or the instance was disposed while it was in flight. The host may still finish it; no automatic retry is armed. Check the current instance and agent discovery."
|
|
1677
|
+
};
|
|
1678
|
+
|
|
1657
1679
|
// src/telemetry/diagnostics.ts
|
|
1658
1680
|
var DIAGNOSTIC_CODES = [
|
|
1659
1681
|
"availability-refresh-failed",
|
|
@@ -1666,6 +1688,14 @@ var DIAGNOSTIC_CODES = [
|
|
|
1666
1688
|
"opencode-server-url",
|
|
1667
1689
|
"opencode-version-read-failed",
|
|
1668
1690
|
"privacy-inert",
|
|
1691
|
+
"reload-queued",
|
|
1692
|
+
"reload-waiting",
|
|
1693
|
+
"reload-accepted",
|
|
1694
|
+
"reload-cancelled",
|
|
1695
|
+
"reload-timeout",
|
|
1696
|
+
"reload-status-failed",
|
|
1697
|
+
"reload-dispose-failed",
|
|
1698
|
+
"reload-unconfirmed",
|
|
1669
1699
|
"soak-evidence-rejected",
|
|
1670
1700
|
"telemetry-warning",
|
|
1671
1701
|
"telemetry-write-failed",
|
|
@@ -1693,6 +1723,15 @@ function diagnosticDescription(code) {
|
|
|
1693
1723
|
return "openteam could not read the live opencode version; graph gates fail closed when this happens.";
|
|
1694
1724
|
case "privacy-inert":
|
|
1695
1725
|
return routingMessages.privacyModeDeprecated;
|
|
1726
|
+
case "reload-queued":
|
|
1727
|
+
case "reload-waiting":
|
|
1728
|
+
case "reload-accepted":
|
|
1729
|
+
case "reload-cancelled":
|
|
1730
|
+
case "reload-timeout":
|
|
1731
|
+
case "reload-status-failed":
|
|
1732
|
+
case "reload-dispose-failed":
|
|
1733
|
+
case "reload-unconfirmed":
|
|
1734
|
+
return reloadMessages[code];
|
|
1696
1735
|
case "soak-evidence-rejected":
|
|
1697
1736
|
return "Graph soak evidence contained rejected observation lines; cutover gate evidence may be incomplete.";
|
|
1698
1737
|
case "telemetry-warning":
|
|
@@ -3317,6 +3356,25 @@ var executionSetupMessages = {
|
|
|
3317
3356
|
`),
|
|
3318
3357
|
localOnlyTitle: "Local execution",
|
|
3319
3358
|
localRequiredError: "local execution requires an enabled local runtime",
|
|
3359
|
+
lemonadeDetectedHint: (loaded, advertised) => `detected - ${loaded} confirmed loaded of ${advertised} advertised text model(s)`,
|
|
3360
|
+
lemonadeNoLoadedModels: "Lemonade has no text models verified as loaded and ready. Keep the intended model active in Lemonade and rerun setup; inactive or unknown models cannot be selected or entered manually.",
|
|
3361
|
+
lemonadeModelNotLoaded: (model) => `Lemonade model "${model}" is not positively verified as loaded and ready. Keep that exact text model active and rerun setup; no substitute was selected and no implicit loading is allowed.`,
|
|
3362
|
+
lemonadeProbeRequired: "Lemonade setup requires a fresh read-only residency probe before writing configuration. Use the CLI with its runtime probe enabled; manual model IDs cannot bypass this requirement.",
|
|
3363
|
+
lemonadeProbeFailed: "Lemonade residency could not be verified at the configured endpoint. Check connectivity and the read-only /models, /health, and /internal/aliases responses, then rerun setup with the intended text models already active.",
|
|
3364
|
+
lemonadeEndpointMismatch: "Lemonade endpoint/provider mapping differs from the selected runtime. Reconcile the configured base URL and provider before rerunning setup; no model was substituted.",
|
|
3365
|
+
lemonadeModelIdentityUnknown: (model) => `Lemonade model "${model}" has no usable registered wire identity in the effective opencode configuration. Fix its model declaration before rerunning setup; setup will not replace or guess an alias.`,
|
|
3366
|
+
lemonadeEffectiveConfigLabel: "effective setup configuration",
|
|
3367
|
+
lemonadeEffectiveConfigAmbiguous: "Cannot establish one effective openteam configuration from the configured plugin loaders. Reconcile their options before rerunning setup; no provider identity was guessed.",
|
|
3368
|
+
lemonadeRetainedProviderUnprotected: (providerID) => `Cannot safely keep retained Lemonade provider "${providerID}": the effective configuration must retain one matching Lemonade runtime, disabled when deselected. Reconcile the plugin options or machine overlay, or explicitly remove the provider registration before rerunning setup; no configuration was written.`,
|
|
3369
|
+
lemonadeV2InvalidProvider: (providerID) => `Lemonade provider ${JSON.stringify(providerID)} cannot be represented as an exact native V2 policy resource. Choose a non-empty provider ID without wildcards, slashes, backslashes, or whitespace; setup will not broaden a deny rule.`,
|
|
3370
|
+
lemonadeV2InvalidPolicies: "Cannot safely preserve experimental.policies: experimental must be an object and policies must be an array of provider.use statements with a string resource and allow/deny effect. Fix the project configuration before rerunning setup.",
|
|
3371
|
+
lemonadeV2Title: "Lemonade transport compatibility",
|
|
3372
|
+
lemonadeV2Restriction: (providers) => `Project policies disable native V2 Lemonade access for: ${providers.join(", ")}. Ordinary guarded V1 configuration remains supported; V2 is not an openteam-hook execution path. Higher-precedence or global policies can override this project restriction; it is not a server-atomic no-autoload guarantee.`,
|
|
3373
|
+
lemonadeInventory: (instanceID, providerID, models) => {
|
|
3374
|
+
const inventory = models.map((model) => `${model.modelID} (${model.loaded === true ? "loaded" : model.loaded === false ? "inactive" : "residency unknown"})`).join(", ");
|
|
3375
|
+
return `Lemonade inventory ${instanceID} (provider ${providerID}): ${inventory || "no advertised text models"}. Only confirmed loaded text models count as ready.`;
|
|
3376
|
+
},
|
|
3377
|
+
lemonadeAgentResidency: (agent, model, state) => `Lemonade readiness: ${agent} (${model}): ${state === "not-loaded" ? "inactive (not ready)" : "residency unknown"}; advertised inventory is not loaded readiness. Keep this exact model active and verify residency before use; requests without verified readiness are blocked.`,
|
|
3320
3378
|
mixedPrimaryQuestion: "Primary coordinator model",
|
|
3321
3379
|
mixedPrimaryLocal: (model) => `Use local thinking model ${model}`,
|
|
3322
3380
|
mixedPrimaryFrontier: "Choose a frontier model",
|
|
@@ -3339,12 +3397,14 @@ var executionSetupMessages = {
|
|
|
3339
3397
|
`Local runtimes: ${params.localRuntimes}`,
|
|
3340
3398
|
`YOLO mode: ${params.yolo ? "enabled (auto-approves permissions)" : "disabled"}`,
|
|
3341
3399
|
"Web Console: launched separately with 'openteam console' (multi-session, loopback)",
|
|
3342
|
-
`Wrote: ${params.opencodePath}, ${params.configPath}, ${params.agentPath}, ${params.
|
|
3400
|
+
`Wrote: ${params.opencodePath}, ${params.configPath}, ${params.agentPath}, ${params.commandDir}/*.md (${params.commandCount} commands); ensured ${params.gitignorePath}`,
|
|
3401
|
+
"Worker files are created through conversational roster preparation, not setup; existing worker files were left untouched.",
|
|
3343
3402
|
"",
|
|
3344
3403
|
"Next steps:",
|
|
3345
3404
|
params.executionMode === "local" ? " 1. No frontier authentication is required while local execution is active" : " 1. Authenticate the frontier provider: opencode auth login",
|
|
3346
3405
|
params.executionMode === "local" ? executionSetupMessages.localRuntimeNextStep : params.executionMode === "mixed" ? executionSetupMessages.mixedNextStep : executionSetupMessages.frontierNextStep,
|
|
3347
|
-
" 3. Press Tab and pick the 'openteam' agent, or type / and pick an /openteam… command"
|
|
3406
|
+
" 3. Press Tab and pick the 'openteam' agent, or type / and pick an /openteam… command",
|
|
3407
|
+
" 4. Use /create_roster to compose the team without starting project work, or describe a task to prepare the team and begin work"
|
|
3348
3408
|
],
|
|
3349
3409
|
configuredTitle: "openteam configured",
|
|
3350
3410
|
complete: (paths) => `openteam setup complete: ${paths}`,
|
|
@@ -9207,7 +9267,7 @@ function parseOpencodeProviders(opencodeConfig) {
|
|
|
9207
9267
|
function localRuntimeStates(config) {
|
|
9208
9268
|
const map = new Map;
|
|
9209
9269
|
for (const runtime of config.local.runtimes) {
|
|
9210
|
-
map.set(runtime.
|
|
9270
|
+
map.set(runtime.defaultModel.providerID, { enabled: runtime.enabled });
|
|
9211
9271
|
}
|
|
9212
9272
|
return map;
|
|
9213
9273
|
}
|
|
@@ -9215,7 +9275,7 @@ function disabledLocalProviderIDs(config) {
|
|
|
9215
9275
|
const ids = new Set;
|
|
9216
9276
|
for (const runtime of config.local.runtimes) {
|
|
9217
9277
|
if (!runtime.enabled) {
|
|
9218
|
-
ids.add(runtime.
|
|
9278
|
+
ids.add(runtime.defaultModel.providerID);
|
|
9219
9279
|
}
|
|
9220
9280
|
}
|
|
9221
9281
|
return ids;
|
|
@@ -9231,7 +9291,11 @@ function computeLive(model, isLocalProvider, liveModels) {
|
|
|
9231
9291
|
if (!snapshot.reachable) {
|
|
9232
9292
|
return "unreachable";
|
|
9233
9293
|
}
|
|
9234
|
-
|
|
9294
|
+
if (snapshot.modelIDs.has(model.modelID))
|
|
9295
|
+
return "confirmed";
|
|
9296
|
+
if (snapshot.residency?.has(model.modelID))
|
|
9297
|
+
return snapshot.residency.get(model.modelID) === false ? "not-loaded" : "residency-unknown";
|
|
9298
|
+
return "not-advertised";
|
|
9235
9299
|
}
|
|
9236
9300
|
function resolveAgentModel(model, context) {
|
|
9237
9301
|
const isLocalProvider = KNOWN_LOCAL_PROVIDER_IDS.has(model.providerID) || context.localRuntimes.has(model.providerID);
|
|
@@ -14568,6 +14632,48 @@ function withDeterministicGitLocale(env) {
|
|
|
14568
14632
|
};
|
|
14569
14633
|
}
|
|
14570
14634
|
|
|
14635
|
+
// src/opencodeArtifacts/createRosterReload.ts
|
|
14636
|
+
var CREATE_ROSTER_RELOAD_INSTRUCTIONS = [
|
|
14637
|
+
"## Reload confirmation — /create_roster only",
|
|
14638
|
+
"",
|
|
14639
|
+
"Only after successful persisted registration and verified agent files may you offer reload:",
|
|
14640
|
+
"read back the parseable persisted roster, including guaranteed roles; actually create each missing",
|
|
14641
|
+
"subagent file and verify every required existing or created file.",
|
|
14642
|
+
"First show the complete Agent/Role/Model table returned by `openteam-register-cast`,",
|
|
14643
|
+
"including primary, guaranteed and preserved agents with their unchanged tool-returned policy values.",
|
|
14644
|
+
"Then show the created-versus-preserved file summary and any warnings. Both must be visible",
|
|
14645
|
+
"BEFORE asking a fresh explicit reload question in this opencode conversation.",
|
|
14646
|
+
"If registration, file creation or verification failed or is partial, do not ask the reload question:",
|
|
14647
|
+
"report the exact blocker and do not claim readiness. If registration succeeded, still show its",
|
|
14648
|
+
"complete table even when file preparation later fails.",
|
|
14649
|
+
"",
|
|
14650
|
+
"Ask whether to reload this project's opencode agent definitions now, explaining the request is",
|
|
14651
|
+
"queued/waiting until the requesting turn completes and all project sessions are idle.",
|
|
14652
|
+
"Use the host question tool when available; otherwise ask a normal conversational question",
|
|
14653
|
+
"in opencode and WAIT for the user's answer. Never use a terminal wizard, tool permission",
|
|
14654
|
+
"approval or YOLO permission as reload consent. A greenfield project-description reply is NOT reload consent.",
|
|
14655
|
+
"Only an explicit affirmative answer to this specific reload question authorizes",
|
|
14656
|
+
'`openteam-reload` with `{ action: "request", confirmed: true }`.',
|
|
14657
|
+
"False, no, cancel, an ambiguous answer or no reply means no reload request.",
|
|
14658
|
+
"A decline before anything is queued needs no tool call; do not turn ambiguity into confirmation.",
|
|
14659
|
+
"To cancel an already queued request at the user's direction, use",
|
|
14660
|
+
'`openteam-reload` with `{ action: "cancel", confirmed: false }` and report its actual result.',
|
|
14661
|
+
"",
|
|
14662
|
+
"This internal tool is restricted to the product primary `openteam` and its bound project.",
|
|
14663
|
+
"Do not supply a directory, project, session or other model-selected target.",
|
|
14664
|
+
"Report queued/waiting honestly and end the confirming turn immediately.",
|
|
14665
|
+
"Do not await your own idle state, poll or hold the turn open. Do not start work or call",
|
|
14666
|
+
"`task` or `openteam-orchestrate`; do not rewrite/recast files or change models, permissions",
|
|
14667
|
+
"or execution policies. The idle wait has a finite timeout; surface timeout and failure results",
|
|
14668
|
+
"when the runtime reports them, including rejected requests, rather than promising success or silently retrying.",
|
|
14669
|
+
"SDK acceptance is not verified discovery or readiness. Preserve all existing discovery guards:",
|
|
14670
|
+
"if new agents remain undiscovered, surface the reload/discovery blocker;",
|
|
14671
|
+
"do not dispatch through a generic substitute or claim readiness.",
|
|
14672
|
+
"This workflow and all its replies remain composition only. After completion, decline or cancellation,",
|
|
14673
|
+
"wait for a separate work request; neither a reload answer nor queued acceptance starts project work."
|
|
14674
|
+
].join(`
|
|
14675
|
+
`);
|
|
14676
|
+
|
|
14571
14677
|
// src/opencodeArtifacts/rosterSummary.ts
|
|
14572
14678
|
var ROSTER_SUMMARY_INSTRUCTIONS = [
|
|
14573
14679
|
"After every successful cast creation, repair or extension, show the complete Agent/Role/Model table",
|
|
@@ -14600,6 +14706,20 @@ var TEAM_PREPARATION_INSTRUCTIONS = [
|
|
|
14600
14706
|
"machine bindings stay unchanged; do not require a terminal or manually edit policy to finish hiring.",
|
|
14601
14707
|
"Never infer execution domains from prose, relax permissions, or invent a concrete auto model.",
|
|
14602
14708
|
"Registration/review is idempotent: a capable configured team needs no extra members or file rewrites.",
|
|
14709
|
+
"`agentName`, not `roleID`, determines each worker filename.",
|
|
14710
|
+
"Create `.opencode/agent/<agentName>.md` only for registered roster entries.",
|
|
14711
|
+
"A built-in role profile is not an extra agent.",
|
|
14712
|
+
"Do not create a parallel `<roleID>.md` when the roster maps that role to another alias.",
|
|
14713
|
+
"An existing roster alias equal to its roleID is still valid; do not rename it.",
|
|
14714
|
+
"Do not run `openteam setup` to hire workers or repair their files.",
|
|
14715
|
+
"Preserve unrelated and legacy generic files; do not delete, overwrite or silently register them.",
|
|
14716
|
+
"Registration writes roster/profile state, not worker Markdown.",
|
|
14717
|
+
"Report only verified file changes; do not call pre-existing files newly created.",
|
|
14718
|
+
"When creating a scribe worker, put the following memory instructions in its charter:",
|
|
14719
|
+
"Use `openteam-memory` for durable, reusable facts, entities and typed relations.",
|
|
14720
|
+
"Send only redacted knowledge messages, never raw conversations, prompts or credentials.",
|
|
14721
|
+
"Honor operator permissions and memory settings; do not broaden them.",
|
|
14722
|
+
"A disabled-memory or nothing-recorded result is expected; do not retry it.",
|
|
14603
14723
|
"Create only missing agent definitions; preserve customized files. Show the registration table",
|
|
14604
14724
|
"and verify preparation before dispatch. If opencode cannot discover a new agent, surface",
|
|
14605
14725
|
"the reload/discovery blocker; do not dispatch through a generic substitute or claim readiness."
|
|
@@ -14641,33 +14761,43 @@ function buildOrchestratorAgent(model, options = {}) {
|
|
|
14641
14761
|
"primary agent: there is no pre-created team. You **build the team of",
|
|
14642
14762
|
"subagents on demand** according to the goal of the user and the repository.",
|
|
14643
14763
|
"",
|
|
14644
|
-
"## Golden rule: check the team on EVERY request",
|
|
14645
|
-
"",
|
|
14646
|
-
"Before answering or delegating **any** request, your **first action",
|
|
14647
|
-
"always** is to check whether a team already exists, even if the user does not",
|
|
14648
|
-
"explicitly ask you to create it. Never assume there is a team or that there is not:",
|
|
14649
|
-
`verify it by looking at \`${OPENTEAM_ROSTER_PATH}\` and the \`.opencode/agent/*.md\``,
|
|
14650
|
-
"files with `mode: subagent` (use `read`/`glob`/`list`).",
|
|
14651
|
-
"",
|
|
14652
|
-
ROSTER_SUMMARY_INSTRUCTIONS,
|
|
14653
|
-
"",
|
|
14654
|
-
TEAM_PREPARATION_INSTRUCTIONS,
|
|
14655
|
-
"",
|
|
14656
14764
|
"## Roster composition takes precedence",
|
|
14657
14765
|
"",
|
|
14658
14766
|
"For `/create_roster`, including replies to its pending questions, follow",
|
|
14659
14767
|
"the command's roster-only workflow: do not distribute tasks or start implementation.",
|
|
14768
|
+
"These rules override the ordinary golden rule and capability checks below.",
|
|
14769
|
+
"A bare yes to a pending reload question continues only reload confirmation:",
|
|
14770
|
+
"do not restart roster reads, capability preparation or registration.",
|
|
14660
14771
|
"Reuse or conservatively extend the existing cast and preserve customized agent files.",
|
|
14661
14772
|
"Use a supplied description; otherwise inspect real project source read-only.",
|
|
14662
14773
|
"If there is no meaningful source and no description, ask what the user wants to",
|
|
14663
14774
|
"build in this conversation and wait before any writes or cast registration.",
|
|
14664
14775
|
"Register through `openteam-register-cast`, create missing subagent files, verify",
|
|
14665
|
-
"the persisted roster and files, then
|
|
14776
|
+
"the persisted roster and files, then follow the reload confirmation below.",
|
|
14777
|
+
"Do not call `openteam-orchestrate` or",
|
|
14666
14778
|
"`task` for this workflow. A later answer to your question continues composition",
|
|
14667
14779
|
"only until it completes or the user cancels; it is not an implementation request.",
|
|
14668
14780
|
"",
|
|
14781
|
+
CREATE_ROSTER_RELOAD_INSTRUCTIONS,
|
|
14782
|
+
"",
|
|
14783
|
+
"## Golden rule: check the team on EVERY request",
|
|
14784
|
+
"",
|
|
14785
|
+
"The roster composition and pending reload-reply rules above take precedence.",
|
|
14786
|
+
"Before answering or delegating **any ordinary work** request, your **first action",
|
|
14787
|
+
"always** is to check whether a team already exists, even if the user does not",
|
|
14788
|
+
"explicitly ask you to create it. Never assume there is a team or that there is not:",
|
|
14789
|
+
`verify it by looking at \`${OPENTEAM_ROSTER_PATH}\` and the \`.opencode/agent/*.md\``,
|
|
14790
|
+
"files with `mode: subagent` (use `read`/`glob`/`list`).",
|
|
14791
|
+
"",
|
|
14792
|
+
ROSTER_SUMMARY_INSTRUCTIONS,
|
|
14793
|
+
"",
|
|
14794
|
+
TEAM_PREPARATION_INSTRUCTIONS,
|
|
14795
|
+
"",
|
|
14669
14796
|
"## For work requests, including analysis, review and documentation",
|
|
14670
14797
|
"",
|
|
14798
|
+
"Ordinary automatic hiring must NOT ask for reload or automatically reset the project.",
|
|
14799
|
+
"If discovery is blocked, surface the blocker and preserve the discovery guards instead.",
|
|
14800
|
+
"",
|
|
14671
14801
|
"- **If the team ALREADY exists** → review capability coverage, reuse suitable",
|
|
14672
14802
|
" members and extend only for uncovered needs. Complete any existing member's",
|
|
14673
14803
|
" profile through `openteam-register-cast`; do not hire for a configuration gap.",
|
|
@@ -15042,8 +15172,10 @@ function buildCreateRosterCommand() {
|
|
|
15042
15172
|
"required agent file exists. If anything failed, report the incomplete state and exact",
|
|
15043
15173
|
"blocker; do not delete preserved state or claim the team is ready.",
|
|
15044
15174
|
"Summarize the cast, role rationale/evidence, preserved versus newly created files, and",
|
|
15045
|
-
"any warnings.
|
|
15046
|
-
"
|
|
15175
|
+
"any warnings. Continue only to the reload confirmation below, including its pending replies;",
|
|
15176
|
+
"do not restart preparation when the user answers that reload question.",
|
|
15177
|
+
"",
|
|
15178
|
+
CREATE_ROSTER_RELOAD_INSTRUCTIONS,
|
|
15047
15179
|
"",
|
|
15048
15180
|
"## Project description (user input)",
|
|
15049
15181
|
"",
|
|
@@ -15903,6 +16035,243 @@ function ensureFoundryV1BaseURL(endpoint) {
|
|
|
15903
16035
|
}
|
|
15904
16036
|
}
|
|
15905
16037
|
|
|
16038
|
+
// src/local/lemonadeResidency.ts
|
|
16039
|
+
import { z as z22 } from "zod";
|
|
16040
|
+
|
|
16041
|
+
// src/messages/modelResidency.ts
|
|
16042
|
+
var reasons = {
|
|
16043
|
+
unknown: "fresh residency metadata is unavailable, malformed, or ambiguous",
|
|
16044
|
+
inactive: "the requested model is not verified as resident and serving",
|
|
16045
|
+
identity: "the requested model identity can be rewritten or is ambiguous",
|
|
16046
|
+
destination: "the request destination does not match its configured runtime",
|
|
16047
|
+
transport: "this provider execution path cannot enforce the residency guard",
|
|
16048
|
+
request: "this is not a supported, explicit model inference request",
|
|
16049
|
+
cancelled: "the request was cancelled before residency could be verified",
|
|
16050
|
+
timeout: "the residency metadata deadline expired",
|
|
16051
|
+
configuration: "the residency guard configuration is invalid"
|
|
16052
|
+
};
|
|
16053
|
+
var modelResidencyMessages = {
|
|
16054
|
+
blocked: (reason) => `[openteam] Lemonade model request blocked: ${reasons[reason]}.`,
|
|
16055
|
+
providerDisabled: (providerID) => `[openteam] Lemonade provider "${providerID}" is disabled because its configured transport or runtime mapping cannot enforce loaded-only requests.`,
|
|
16056
|
+
extractionRuntimeUnavailable: "[openteam] Memory extraction requires one enabled local runtime matching the configured extraction provider."
|
|
16057
|
+
};
|
|
16058
|
+
|
|
16059
|
+
// src/local/lemonadeResidency.ts
|
|
16060
|
+
class ModelResidencyError extends Error {
|
|
16061
|
+
code;
|
|
16062
|
+
statusCode = 400;
|
|
16063
|
+
isRetryable = false;
|
|
16064
|
+
constructor(code) {
|
|
16065
|
+
super(modelResidencyMessages.blocked(code));
|
|
16066
|
+
this.code = code;
|
|
16067
|
+
this.name = "ModelResidencyError";
|
|
16068
|
+
}
|
|
16069
|
+
}
|
|
16070
|
+
var modelName = z22.string().min(1).refine((name) => name === name.trim());
|
|
16071
|
+
var LoadedModelSchema = z22.object({
|
|
16072
|
+
model_name: modelName,
|
|
16073
|
+
loaded: z22.boolean().optional(),
|
|
16074
|
+
status: z22.string().optional(),
|
|
16075
|
+
backend_alive: z22.boolean().optional(),
|
|
16076
|
+
backend_health: z22.string().optional(),
|
|
16077
|
+
watchdog_reset: z22.boolean().optional(),
|
|
16078
|
+
watchdog_reset_reason: z22.string().optional(),
|
|
16079
|
+
residency_class: z22.string().optional(),
|
|
16080
|
+
slot_pool: z22.string().optional(),
|
|
16081
|
+
checkpoint: z22.string().optional(),
|
|
16082
|
+
type: z22.string().optional(),
|
|
16083
|
+
device: z22.string().optional(),
|
|
16084
|
+
backend_url: z22.string().optional(),
|
|
16085
|
+
pid: z22.number().int().optional(),
|
|
16086
|
+
launch_command: z22.unknown().optional(),
|
|
16087
|
+
pinned: z22.boolean().optional(),
|
|
16088
|
+
recipe: z22.string().optional(),
|
|
16089
|
+
recipe_options: z22.unknown().optional(),
|
|
16090
|
+
is_busy: z22.boolean().optional(),
|
|
16091
|
+
is_streaming: z22.boolean().optional(),
|
|
16092
|
+
max_context_window: z22.number().optional(),
|
|
16093
|
+
cost_input_per_million: z22.number().optional(),
|
|
16094
|
+
cost_output_per_million: z22.number().optional(),
|
|
16095
|
+
last_use: z22.number().optional()
|
|
16096
|
+
}).strict();
|
|
16097
|
+
var TelemetrySchema = z22.object({
|
|
16098
|
+
enabled: z22.boolean(),
|
|
16099
|
+
captures: z22.array(z22.string()).optional()
|
|
16100
|
+
}).strict();
|
|
16101
|
+
var HealthSchema = z22.object({
|
|
16102
|
+
status: z22.literal("ok"),
|
|
16103
|
+
all_models_loaded: z22.array(LoadedModelSchema),
|
|
16104
|
+
version: z22.string().optional(),
|
|
16105
|
+
model_loaded: z22.string().nullable().optional(),
|
|
16106
|
+
telemetry: TelemetrySchema.optional(),
|
|
16107
|
+
max_models: z22.record(z22.string(), z22.number().int()).optional(),
|
|
16108
|
+
pinned_models: z22.record(z22.string(), z22.number().int()).optional(),
|
|
16109
|
+
pinned_helper_models: z22.record(z22.string(), z22.number().int()).optional(),
|
|
16110
|
+
websocket_port: z22.number().int().optional(),
|
|
16111
|
+
update_check_done: z22.boolean().optional()
|
|
16112
|
+
}).strict();
|
|
16113
|
+
var AliasSchema = z22.object({
|
|
16114
|
+
alias: modelName,
|
|
16115
|
+
target: modelName,
|
|
16116
|
+
downloaded: z22.boolean().optional(),
|
|
16117
|
+
recipe: z22.string().optional()
|
|
16118
|
+
}).strict();
|
|
16119
|
+
var AliasesSchema = z22.object({
|
|
16120
|
+
aliases: z22.array(AliasSchema)
|
|
16121
|
+
}).strict();
|
|
16122
|
+
var MetadataRecordSchema = z22.record(z22.string(), z22.unknown());
|
|
16123
|
+
var inactiveStates = new Set([
|
|
16124
|
+
"loading",
|
|
16125
|
+
"downsizing",
|
|
16126
|
+
"downsized",
|
|
16127
|
+
"evicting",
|
|
16128
|
+
"unloaded"
|
|
16129
|
+
]);
|
|
16130
|
+
var inactiveHealth = new Set(["stopped", "exited", "watchdog_reset"]);
|
|
16131
|
+
var standardPools = new Set([
|
|
16132
|
+
"standard/llm",
|
|
16133
|
+
"standard/embedding",
|
|
16134
|
+
"standard/reranking",
|
|
16135
|
+
"standard/transcription",
|
|
16136
|
+
"standard/image",
|
|
16137
|
+
"standard/tts",
|
|
16138
|
+
"standard/audio-generation",
|
|
16139
|
+
"standard/classification",
|
|
16140
|
+
"standard/mesh"
|
|
16141
|
+
]);
|
|
16142
|
+
function usableState(entry) {
|
|
16143
|
+
if (entry.loaded === false || entry.backend_alive === false || entry.watchdog_reset === true || typeof entry.status === "string" && inactiveStates.has(entry.status) || typeof entry.backend_health === "string" && inactiveHealth.has(entry.backend_health) || entry.residency_class === "routing_helper" || typeof entry.slot_pool === "string" && entry.slot_pool.startsWith("routing_helper/")) {
|
|
16144
|
+
return false;
|
|
16145
|
+
}
|
|
16146
|
+
if (entry.loaded !== true || entry.backend_alive !== true || entry.watchdog_reset !== false || entry.status !== "ready" && entry.status !== "in_use" || entry.backend_health !== "ready" && entry.backend_health !== "busy" || entry.watchdog_reset_reason !== undefined && entry.watchdog_reset_reason !== "" || entry.residency_class !== undefined && entry.residency_class !== "standard" || entry.slot_pool !== undefined && (typeof entry.slot_pool !== "string" || !standardPools.has(entry.slot_pool))) {
|
|
16147
|
+
return;
|
|
16148
|
+
}
|
|
16149
|
+
return true;
|
|
16150
|
+
}
|
|
16151
|
+
function projectMetadataObject(payload, keys) {
|
|
16152
|
+
const record2 = MetadataRecordSchema.safeParse(payload);
|
|
16153
|
+
if (!record2.success)
|
|
16154
|
+
throw new ModelResidencyError("unknown");
|
|
16155
|
+
return Object.fromEntries(keys.filter((key) => Object.hasOwn(record2.data, key)).map((key) => [key, record2.data[key]]));
|
|
16156
|
+
}
|
|
16157
|
+
function parseResidency(healthPayload, aliasPayload) {
|
|
16158
|
+
const healthFields = projectMetadataObject(healthPayload, Object.keys(HealthSchema.shape));
|
|
16159
|
+
if (Array.isArray(healthFields.all_models_loaded)) {
|
|
16160
|
+
healthFields.all_models_loaded = healthFields.all_models_loaded.map((entry) => projectMetadataObject(entry, Object.keys(LoadedModelSchema.shape)));
|
|
16161
|
+
}
|
|
16162
|
+
if (healthFields.telemetry !== undefined) {
|
|
16163
|
+
healthFields.telemetry = projectMetadataObject(healthFields.telemetry, Object.keys(TelemetrySchema.shape));
|
|
16164
|
+
}
|
|
16165
|
+
const aliasFields = projectMetadataObject(aliasPayload, Object.keys(AliasesSchema.shape));
|
|
16166
|
+
if (Array.isArray(aliasFields.aliases)) {
|
|
16167
|
+
aliasFields.aliases = aliasFields.aliases.map((entry) => projectMetadataObject(entry, Object.keys(AliasSchema.shape)));
|
|
16168
|
+
}
|
|
16169
|
+
const health = HealthSchema.safeParse(healthFields);
|
|
16170
|
+
const aliases = AliasesSchema.safeParse(aliasFields);
|
|
16171
|
+
if (!health.success || !aliases.success)
|
|
16172
|
+
throw new ModelResidencyError("unknown");
|
|
16173
|
+
const result = new Map;
|
|
16174
|
+
for (const entry of health.data.all_models_loaded) {
|
|
16175
|
+
if (result.has(entry.model_name))
|
|
16176
|
+
throw new ModelResidencyError("unknown");
|
|
16177
|
+
result.set(entry.model_name, {
|
|
16178
|
+
loaded: entry.model_name.endsWith(":latest") ? undefined : usableState(entry),
|
|
16179
|
+
metadata: entry
|
|
16180
|
+
});
|
|
16181
|
+
}
|
|
16182
|
+
const seenAliases = new Set;
|
|
16183
|
+
for (const entry of aliases.data.aliases) {
|
|
16184
|
+
if (seenAliases.has(entry.alias))
|
|
16185
|
+
throw new ModelResidencyError("unknown");
|
|
16186
|
+
seenAliases.add(entry.alias);
|
|
16187
|
+
result.set(entry.alias, {
|
|
16188
|
+
loaded: undefined,
|
|
16189
|
+
metadata: result.get(entry.alias)?.metadata ?? {}
|
|
16190
|
+
});
|
|
16191
|
+
}
|
|
16192
|
+
return result;
|
|
16193
|
+
}
|
|
16194
|
+
function lemonadeBaseURL(value) {
|
|
16195
|
+
let url;
|
|
16196
|
+
try {
|
|
16197
|
+
url = new URL(value);
|
|
16198
|
+
} catch {
|
|
16199
|
+
throw new ModelResidencyError("destination");
|
|
16200
|
+
}
|
|
16201
|
+
if (url.protocol !== "http:" && url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "" || !/^\/(?:api\/)?v[01]\/?$/.test(url.pathname)) {
|
|
16202
|
+
throw new ModelResidencyError("destination");
|
|
16203
|
+
}
|
|
16204
|
+
return `${url.origin}${url.pathname.replace(/\/$/, "")}`;
|
|
16205
|
+
}
|
|
16206
|
+
async function withResidencyDeadline(operation, options) {
|
|
16207
|
+
const timeoutMs = options.timeoutMs ?? 5000;
|
|
16208
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
16209
|
+
throw new ModelResidencyError("configuration");
|
|
16210
|
+
}
|
|
16211
|
+
const controller = new AbortController;
|
|
16212
|
+
const cancel = () => controller.abort(new ModelResidencyError("cancelled"));
|
|
16213
|
+
if (options.signal?.aborted)
|
|
16214
|
+
throw new ModelResidencyError("cancelled");
|
|
16215
|
+
options.signal?.addEventListener("abort", cancel, { once: true });
|
|
16216
|
+
const schedule = options.scheduleTimeout ?? ((callback, ms2) => {
|
|
16217
|
+
const timer = setTimeout(callback, ms2);
|
|
16218
|
+
return () => clearTimeout(timer);
|
|
16219
|
+
});
|
|
16220
|
+
let onAbort = () => {};
|
|
16221
|
+
const aborted = new Promise((_, reject) => {
|
|
16222
|
+
onAbort = () => reject(controller.signal.reason);
|
|
16223
|
+
controller.signal.addEventListener("abort", onAbort, { once: true });
|
|
16224
|
+
});
|
|
16225
|
+
const clearTimer = schedule(() => controller.abort(new ModelResidencyError("timeout")), timeoutMs);
|
|
16226
|
+
try {
|
|
16227
|
+
controller.signal.throwIfAborted();
|
|
16228
|
+
return await Promise.race([operation(controller.signal), aborted]);
|
|
16229
|
+
} finally {
|
|
16230
|
+
clearTimer();
|
|
16231
|
+
options.signal?.removeEventListener("abort", cancel);
|
|
16232
|
+
controller.signal.removeEventListener("abort", onAbort);
|
|
16233
|
+
controller.abort();
|
|
16234
|
+
}
|
|
16235
|
+
}
|
|
16236
|
+
async function metadata(url, fetch2, signal, headers) {
|
|
16237
|
+
signal.throwIfAborted();
|
|
16238
|
+
let payload;
|
|
16239
|
+
try {
|
|
16240
|
+
const response = await fetch2(url, {
|
|
16241
|
+
method: "GET",
|
|
16242
|
+
headers,
|
|
16243
|
+
signal,
|
|
16244
|
+
redirect: "error",
|
|
16245
|
+
cache: "no-store"
|
|
16246
|
+
});
|
|
16247
|
+
signal.throwIfAborted();
|
|
16248
|
+
if (!response.ok || response.redirected || response.url !== "" && response.url !== url) {
|
|
16249
|
+
throw new ModelResidencyError("unknown");
|
|
16250
|
+
}
|
|
16251
|
+
payload = await response.json();
|
|
16252
|
+
} catch {
|
|
16253
|
+
signal.throwIfAborted();
|
|
16254
|
+
throw new ModelResidencyError("unknown");
|
|
16255
|
+
}
|
|
16256
|
+
signal.throwIfAborted();
|
|
16257
|
+
return payload;
|
|
16258
|
+
}
|
|
16259
|
+
async function readLemonadeResidency(baseURL, fetch2, options = {}) {
|
|
16260
|
+
const base = lemonadeBaseURL(baseURL);
|
|
16261
|
+
const headers = new Headers(options.headers);
|
|
16262
|
+
headers.delete("content-type");
|
|
16263
|
+
headers.delete("content-length");
|
|
16264
|
+
headers.set("accept", "application/json");
|
|
16265
|
+
headers.set("cache-control", "no-cache, no-store");
|
|
16266
|
+
headers.delete("if-none-match");
|
|
16267
|
+
headers.delete("if-modified-since");
|
|
16268
|
+
return withResidencyDeadline(async (signal) => {
|
|
16269
|
+
const aliases = await metadata(`${new URL(base).origin}/internal/aliases`, fetch2, signal, headers);
|
|
16270
|
+
const health = await metadata(`${base}/health`, fetch2, signal, headers);
|
|
16271
|
+
return parseResidency(health, aliases);
|
|
16272
|
+
}, options);
|
|
16273
|
+
}
|
|
16274
|
+
|
|
15906
16275
|
// src/local/lemonade.ts
|
|
15907
16276
|
var LEMONADE_DEFAULT_BASE_URL = "http://localhost:13305/api/v1";
|
|
15908
16277
|
var NON_TEXT_LABELS = new Set([
|
|
@@ -15989,36 +16358,19 @@ function isNonTextModel(entry) {
|
|
|
15989
16358
|
return entry.labels.some((label) => typeof label === "string" && NON_TEXT_LABELS.has(label));
|
|
15990
16359
|
}
|
|
15991
16360
|
async function readLoadedModels(baseURL, fetch2) {
|
|
15992
|
-
let payload;
|
|
15993
16361
|
try {
|
|
15994
|
-
const
|
|
15995
|
-
|
|
15996
|
-
|
|
15997
|
-
|
|
15998
|
-
|
|
15999
|
-
|
|
16000
|
-
|
|
16001
|
-
|
|
16362
|
+
const residency = await readLemonadeResidency(baseURL, fetch2);
|
|
16363
|
+
return new Map([...residency].map(([name, entry]) => [
|
|
16364
|
+
name,
|
|
16365
|
+
{
|
|
16366
|
+
loaded: entry.loaded,
|
|
16367
|
+
slots: entry.loaded === true ? readSlotCount(entry.metadata) : undefined,
|
|
16368
|
+
totalContextWindow: entry.loaded === true ? readLoadedContextWindow(entry.metadata) : undefined
|
|
16369
|
+
}
|
|
16370
|
+
]));
|
|
16002
16371
|
} catch {
|
|
16003
16372
|
return;
|
|
16004
16373
|
}
|
|
16005
|
-
if (!isObject2(payload) || !Array.isArray(payload.all_models_loaded)) {
|
|
16006
|
-
return;
|
|
16007
|
-
}
|
|
16008
|
-
const loaded = new Map;
|
|
16009
|
-
for (const entry of payload.all_models_loaded) {
|
|
16010
|
-
if (!isObject2(entry) || typeof entry.model_name !== "string") {
|
|
16011
|
-
continue;
|
|
16012
|
-
}
|
|
16013
|
-
if (entry.loaded === false) {
|
|
16014
|
-
continue;
|
|
16015
|
-
}
|
|
16016
|
-
loaded.set(entry.model_name, {
|
|
16017
|
-
slots: readSlotCount(entry),
|
|
16018
|
-
totalContextWindow: readLoadedContextWindow(entry)
|
|
16019
|
-
});
|
|
16020
|
-
}
|
|
16021
|
-
return loaded;
|
|
16022
16374
|
}
|
|
16023
16375
|
function readSlotCount(entry) {
|
|
16024
16376
|
return slotsFromLlamacppArgs(entry) ?? slotsFromLaunchCommand(entry);
|
|
@@ -16165,6 +16517,9 @@ function enrichWithLoadState(models, loaded) {
|
|
|
16165
16517
|
if (hit === undefined) {
|
|
16166
16518
|
return { ...base, loaded: false };
|
|
16167
16519
|
}
|
|
16520
|
+
if (hit.loaded !== true) {
|
|
16521
|
+
return hit.loaded === false ? { ...base, loaded: false } : base;
|
|
16522
|
+
}
|
|
16168
16523
|
const contextWindow = derivedConservativeContextWindow(model.contextWindow, hit);
|
|
16169
16524
|
return {
|
|
16170
16525
|
...base,
|
|
@@ -16181,6 +16536,11 @@ function isObject2(value) {
|
|
|
16181
16536
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16182
16537
|
}
|
|
16183
16538
|
|
|
16539
|
+
// src/local/modelResidency.ts
|
|
16540
|
+
function hasRequiredModelResidency(kind, model) {
|
|
16541
|
+
return kind !== "lemonade" || model?.loaded === true;
|
|
16542
|
+
}
|
|
16543
|
+
|
|
16184
16544
|
// src/local/lmstudio.ts
|
|
16185
16545
|
var LMSTUDIO_DEFAULT_BASE_URL = "http://localhost:1234/v1";
|
|
16186
16546
|
function createLMStudioAdapter() {
|
|
@@ -16398,50 +16758,36 @@ function createDetect(exec) {
|
|
|
16398
16758
|
foundryDiscovery: foundryDiscoveryFromExec(exec)
|
|
16399
16759
|
});
|
|
16400
16760
|
const snapshots = await registry.probe(DETECTION_RUNTIMES);
|
|
16401
|
-
return
|
|
16402
|
-
|
|
16403
|
-
|
|
16404
|
-
|
|
16405
|
-
|
|
16406
|
-
|
|
16407
|
-
|
|
16408
|
-
|
|
16409
|
-
|
|
16410
|
-
|
|
16411
|
-
|
|
16412
|
-
|
|
16413
|
-
}
|
|
16414
|
-
return detected;
|
|
16415
|
-
});
|
|
16761
|
+
return DETECTION_RUNTIMES.map((runtime) => detectedRuntime(runtime, snapshots.find((snapshot) => snapshot.id === runtime.id)));
|
|
16762
|
+
};
|
|
16763
|
+
}
|
|
16764
|
+
function detectedRuntime(runtime, snapshot) {
|
|
16765
|
+
const modelInfo = snapshot?.models ?? [];
|
|
16766
|
+
return {
|
|
16767
|
+
id: runtime.id,
|
|
16768
|
+
baseURL: snapshot?.baseURL ?? runtime.baseURL ?? "",
|
|
16769
|
+
reachable: snapshot?.reachable ?? false,
|
|
16770
|
+
models: modelInfo.filter((model) => hasRequiredModelResidency(localRuntimeKind(runtime), model)).map((model) => model.modelID),
|
|
16771
|
+
modelInfo,
|
|
16772
|
+
...snapshot?.error === undefined ? {} : { error: snapshot.error }
|
|
16416
16773
|
};
|
|
16417
16774
|
}
|
|
16418
16775
|
function createProbeRuntime(exec) {
|
|
16419
|
-
return async (
|
|
16776
|
+
return async (kind, baseURL) => {
|
|
16420
16777
|
const registry = new RuntimeRegistry({
|
|
16421
16778
|
fetch: globalThis.fetch,
|
|
16422
16779
|
clock: () => new Date().toISOString(),
|
|
16423
16780
|
foundryDiscovery: foundryDiscoveryFromExec(exec)
|
|
16424
16781
|
});
|
|
16425
16782
|
const runtime = {
|
|
16426
|
-
id,
|
|
16783
|
+
id: kind,
|
|
16784
|
+
kind,
|
|
16427
16785
|
enabled: true,
|
|
16428
16786
|
baseURL,
|
|
16429
|
-
defaultModel: { providerID:
|
|
16787
|
+
defaultModel: { providerID: kind, modelID: "probe" }
|
|
16430
16788
|
};
|
|
16431
16789
|
const [snapshot] = await registry.probe([runtime]);
|
|
16432
|
-
|
|
16433
|
-
id,
|
|
16434
|
-
baseURL: snapshot?.baseURL ?? baseURL,
|
|
16435
|
-
reachable: snapshot?.reachable ?? false,
|
|
16436
|
-
models: snapshot?.models.map((model) => model.modelID) ?? []
|
|
16437
|
-
};
|
|
16438
|
-
if (snapshot?.models.some((model) => model.loaded !== undefined) === true) {
|
|
16439
|
-
detected.modelInfo = snapshot.models;
|
|
16440
|
-
}
|
|
16441
|
-
if (snapshot?.error !== undefined) {
|
|
16442
|
-
detected.error = snapshot.error;
|
|
16443
|
-
}
|
|
16444
|
-
return detected;
|
|
16790
|
+
return detectedRuntime(runtime, snapshot);
|
|
16445
16791
|
};
|
|
16446
16792
|
}
|
|
16447
16793
|
|
|
@@ -16554,11 +16900,11 @@ function planWorktreeReconciliation(input) {
|
|
|
16554
16900
|
}
|
|
16555
16901
|
|
|
16556
16902
|
// src/telemetry/otelConfig.ts
|
|
16557
|
-
import { z as
|
|
16558
|
-
var OtelBackendConfigSchema =
|
|
16559
|
-
backend:
|
|
16560
|
-
connectionEnv:
|
|
16561
|
-
serviceName:
|
|
16903
|
+
import { z as z23 } from "zod";
|
|
16904
|
+
var OtelBackendConfigSchema = z23.object({
|
|
16905
|
+
backend: z23.literal("opentelemetry"),
|
|
16906
|
+
connectionEnv: z23.string().min(1),
|
|
16907
|
+
serviceName: z23.string().min(1).optional()
|
|
16562
16908
|
}).strict();
|
|
16563
16909
|
function parseConnectionString(raw) {
|
|
16564
16910
|
const pairs = new Map;
|
|
@@ -17700,7 +18046,7 @@ import { posix as pathPosix, win32 as pathWin32 } from "node:path";
|
|
|
17700
18046
|
// package.json
|
|
17701
18047
|
var package_default = {
|
|
17702
18048
|
name: "@jmanuelcorral/openteam",
|
|
17703
|
-
version: "0.
|
|
18049
|
+
version: "0.24.1",
|
|
17704
18050
|
packageManager: "bun@1.3.14",
|
|
17705
18051
|
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
17706
18052
|
license: "MIT",
|
|
@@ -17844,31 +18190,31 @@ function compareSemver(a, b) {
|
|
|
17844
18190
|
}
|
|
17845
18191
|
|
|
17846
18192
|
// src/graph/soakLedger.ts
|
|
17847
|
-
import { z as
|
|
17848
|
-
var Sha256Schema2 =
|
|
17849
|
-
var SoakPlatformSchema =
|
|
17850
|
-
var PrivacyPairSchema =
|
|
17851
|
-
surfacesScanned:
|
|
17852
|
-
rawFindings:
|
|
18193
|
+
import { z as z24 } from "zod";
|
|
18194
|
+
var Sha256Schema2 = z24.string().regex(/^[0-9a-f]{64}$/);
|
|
18195
|
+
var SoakPlatformSchema = z24.enum(["linux", "win32", "darwin"]);
|
|
18196
|
+
var PrivacyPairSchema = z24.object({
|
|
18197
|
+
surfacesScanned: z24.number().int().nonnegative(),
|
|
18198
|
+
rawFindings: z24.number().int().nonnegative()
|
|
17853
18199
|
}).strict();
|
|
17854
|
-
var DuplicateEffectPairSchema =
|
|
17855
|
-
effectsExamined:
|
|
17856
|
-
duplicatesFound:
|
|
18200
|
+
var DuplicateEffectPairSchema = z24.object({
|
|
18201
|
+
effectsExamined: z24.number().int().nonnegative(),
|
|
18202
|
+
duplicatesFound: z24.number().int().nonnegative()
|
|
17857
18203
|
}).strict();
|
|
17858
|
-
var ModelVerificationPairSchema =
|
|
17859
|
-
nodesChecked:
|
|
17860
|
-
unverified:
|
|
17861
|
-
mismatched:
|
|
18204
|
+
var ModelVerificationPairSchema = z24.object({
|
|
18205
|
+
nodesChecked: z24.number().int().nonnegative(),
|
|
18206
|
+
unverified: z24.number().int().nonnegative(),
|
|
18207
|
+
mismatched: z24.number().int().nonnegative()
|
|
17862
18208
|
}).strict();
|
|
17863
|
-
var SoakObservationSchema =
|
|
17864
|
-
version:
|
|
17865
|
-
seq:
|
|
17866
|
-
timestamp:
|
|
18209
|
+
var SoakObservationSchema = z24.object({
|
|
18210
|
+
version: z24.literal(1),
|
|
18211
|
+
seq: z24.number().int().nonnegative(),
|
|
18212
|
+
timestamp: z24.string().datetime(),
|
|
17867
18213
|
platform: SoakPlatformSchema,
|
|
17868
|
-
opencodeVersion:
|
|
17869
|
-
provenance:
|
|
18214
|
+
opencodeVersion: z24.string().min(1),
|
|
18215
|
+
provenance: z24.enum(["genuine-usage", "ci-synthetic"]),
|
|
17870
18216
|
traceDigest: Sha256Schema2,
|
|
17871
|
-
criticalDivergences:
|
|
18217
|
+
criticalDivergences: z24.number().int().nonnegative().nullable(),
|
|
17872
18218
|
privacy: PrivacyPairSchema.nullable(),
|
|
17873
18219
|
duplicateEffects: DuplicateEffectPairSchema.nullable(),
|
|
17874
18220
|
modelVerification: ModelVerificationPairSchema.nullable(),
|
|
@@ -18054,57 +18400,6 @@ var GENERATED_OPENTEAM_STATE_GROUPS = [
|
|
|
18054
18400
|
{ kind: "file", paths: [SOAK_RECORDER_ID_PATH] }
|
|
18055
18401
|
];
|
|
18056
18402
|
var OPENCODE_DIR = ".opencode";
|
|
18057
|
-
var AGENT_DIR = `${OPENCODE_DIR}/agent`;
|
|
18058
|
-
var ROLE_AGENT_DESCRIPTIONS = {
|
|
18059
|
-
architect: "openteam architect subagent: high-level design, cross-cutting refactors and hard technical decisions.",
|
|
18060
|
-
integration: "openteam integration subagent: wires components together, owns end-to-end flows and cross-module glue.",
|
|
18061
|
-
"local-runtime": "openteam local-runtime subagent: local model operation, provider binding and runtime health.",
|
|
18062
|
-
"routing-cost": "openteam routing-cost subagent: cost-aware routing analysis and token/budget optimisation.",
|
|
18063
|
-
scribe: "openteam scribe subagent: the team's silent memory. Records decisions and learnings in .opencode/openteam/decisions.md without changing code. When a conversation yields durable, reusable knowledge — such as facts, entities, and the typed relations between them (e.g. a decision that affects a component) — also call the `openteam-memory` tool with those messages to record it in the team's semantic graph; it never stores the raw conversation, and a reply that memory is disabled or that nothing was recorded is expected, so do not retry.",
|
|
18064
|
-
ralph: "openteam ralph subagent: automation and triage driver. Monitors pending work, prioritises it and coordinates execution, escalating blockers to the human.",
|
|
18065
|
-
guardian: "openteam guardian subagent: an assignable security reviewer for threat analysis, exploitability checks and security-focused review.",
|
|
18066
|
-
tester: "openteam tester subagent: writes and runs tests, reproduces bugs and validates fixes.",
|
|
18067
|
-
reviewer: "openteam reviewer subagent: reviews diffs for correctness, security and quality."
|
|
18068
|
-
};
|
|
18069
|
-
function buildRoleAgent(agentName, description) {
|
|
18070
|
-
const frontmatter = [
|
|
18071
|
-
"---",
|
|
18072
|
-
`description: ${JSON.stringify(description)}`,
|
|
18073
|
-
"mode: subagent",
|
|
18074
|
-
"temperature: 0.2",
|
|
18075
|
-
"---"
|
|
18076
|
-
].join(`
|
|
18077
|
-
`);
|
|
18078
|
-
const body = [
|
|
18079
|
-
`You are the **${agentName}** subagent of openteam.`,
|
|
18080
|
-
"",
|
|
18081
|
-
description,
|
|
18082
|
-
"",
|
|
18083
|
-
"Your execution domain, selected model and ordered fallbacks come from the matching policy in `.opencode/openteam.json`; leave `model` unset here so the runtime policy remains authoritative.",
|
|
18084
|
-
"",
|
|
18085
|
-
"Stay focused on your role. Keep changes surgical and report what you did."
|
|
18086
|
-
].join(`
|
|
18087
|
-
`);
|
|
18088
|
-
return `${frontmatter}
|
|
18089
|
-
|
|
18090
|
-
${body}
|
|
18091
|
-
`;
|
|
18092
|
-
}
|
|
18093
|
-
function buildRoleAgentFiles(_config) {
|
|
18094
|
-
const seen = new Set;
|
|
18095
|
-
for (const role of Object.values(TEAM_ROLES)) {
|
|
18096
|
-
const agentName = role.opencodeAgent;
|
|
18097
|
-
if (agentName === undefined || seen.has(agentName)) {
|
|
18098
|
-
continue;
|
|
18099
|
-
}
|
|
18100
|
-
seen.add(agentName);
|
|
18101
|
-
}
|
|
18102
|
-
return [...seen].sort((a, b) => a.localeCompare(b)).map((agentName) => ({
|
|
18103
|
-
agentName,
|
|
18104
|
-
path: `${AGENT_DIR}/${agentName}.md`,
|
|
18105
|
-
contents: buildRoleAgent(agentName, ROLE_AGENT_DESCRIPTIONS[agentName] ?? `openteam ${agentName} subagent.`)
|
|
18106
|
-
}));
|
|
18107
|
-
}
|
|
18108
18403
|
function splitSetupPath(path2) {
|
|
18109
18404
|
return path2.split("/").filter((segment) => segment.length > 0);
|
|
18110
18405
|
}
|
|
@@ -18201,6 +18496,12 @@ var KNOWN_RUNTIMES = [
|
|
|
18201
18496
|
dynamicPort: true
|
|
18202
18497
|
}
|
|
18203
18498
|
];
|
|
18499
|
+
var LEMONADE_PROJECT_CONFIG_CANDIDATES = [
|
|
18500
|
+
".opencode/opencode.jsonc",
|
|
18501
|
+
".opencode/opencode.json",
|
|
18502
|
+
"opencode.jsonc",
|
|
18503
|
+
"opencode.json"
|
|
18504
|
+
];
|
|
18204
18505
|
function knownRuntime(id) {
|
|
18205
18506
|
const found = KNOWN_RUNTIMES.find((runtime) => runtime.id === id);
|
|
18206
18507
|
if (found === undefined) {
|
|
@@ -18217,7 +18518,44 @@ function choiceKind(choice) {
|
|
|
18217
18518
|
function choiceProviderID(choice) {
|
|
18218
18519
|
return choice.providerID ?? choice.id;
|
|
18219
18520
|
}
|
|
18521
|
+
function selectableModelIDs(models, modelInfo, kind) {
|
|
18522
|
+
const byID = new Map(modelInfo?.map((model) => [model.modelID, model]));
|
|
18523
|
+
return models.filter((id) => hasRequiredModelResidency(kind, byID.get(id)));
|
|
18524
|
+
}
|
|
18525
|
+
function assertRuntimeResidency(choice, primary) {
|
|
18526
|
+
const kind = localRuntimeKind(choice);
|
|
18527
|
+
const references2 = [
|
|
18528
|
+
choice.defaultModelID,
|
|
18529
|
+
choice.thinkingModelID,
|
|
18530
|
+
choice.coderModelID,
|
|
18531
|
+
...primary.providerID === choiceProviderID(choice) ? [primary.modelID] : []
|
|
18532
|
+
];
|
|
18533
|
+
for (const id of references2) {
|
|
18534
|
+
if (id === undefined)
|
|
18535
|
+
continue;
|
|
18536
|
+
const info = choice.models.includes(id) ? choice.modelInfo?.find((model) => model.modelID === id) : undefined;
|
|
18537
|
+
if (!hasRequiredModelResidency(kind, info))
|
|
18538
|
+
throw new Error(executionSetupMessages.lemonadeModelNotLoaded(`${choiceProviderID(choice)}/${id}`));
|
|
18539
|
+
}
|
|
18540
|
+
}
|
|
18541
|
+
function assertSetupResidency(answers) {
|
|
18542
|
+
for (const choice of answers.runtimes) {
|
|
18543
|
+
if (choice.enabled) {
|
|
18544
|
+
assertRuntimeResidency(choice, answers.primaryModel);
|
|
18545
|
+
} else if (choiceProviderID(choice) === answers.primaryModel.providerID && !hasRequiredModelResidency(localRuntimeKind(choice), undefined)) {
|
|
18546
|
+
throw new Error(executionSetupMessages.lemonadeModelNotLoaded(`${answers.primaryModel.providerID}/${answers.primaryModel.modelID}`));
|
|
18547
|
+
}
|
|
18548
|
+
}
|
|
18549
|
+
}
|
|
18550
|
+
function lemonadeV2Policies(providers) {
|
|
18551
|
+
return [...new Set(providers)].sort().map((providerID) => {
|
|
18552
|
+
if (providerID.length === 0 || /[*?\\/\s]/.test(providerID))
|
|
18553
|
+
throw new Error(executionSetupMessages.lemonadeV2InvalidProvider(providerID));
|
|
18554
|
+
return { action: "provider.use", resource: providerID, effect: "deny" };
|
|
18555
|
+
});
|
|
18556
|
+
}
|
|
18220
18557
|
function buildOpenTeamConfig(answers) {
|
|
18558
|
+
assertSetupResidency(answers);
|
|
18221
18559
|
const runtimes = answers.runtimes.filter((choice) => choice.enabled).map((choice) => {
|
|
18222
18560
|
const runtime = {
|
|
18223
18561
|
id: choice.id,
|
|
@@ -18286,6 +18624,8 @@ function orchestratorAgentModel(answers) {
|
|
|
18286
18624
|
return { ...answers.primaryModel };
|
|
18287
18625
|
}
|
|
18288
18626
|
function buildOpencodeConfig(answers) {
|
|
18627
|
+
assertSetupResidency(answers);
|
|
18628
|
+
const policies = lemonadeV2Policies(answers.runtimes.filter((choice) => choice.enabled && choiceKind(choice) === "lemonade").map(choiceProviderID));
|
|
18289
18629
|
const provider = {};
|
|
18290
18630
|
const providerOwner = new Map;
|
|
18291
18631
|
for (const choice of answers.runtimes) {
|
|
@@ -18298,7 +18638,7 @@ function buildOpencodeConfig(answers) {
|
|
|
18298
18638
|
continue;
|
|
18299
18639
|
}
|
|
18300
18640
|
const providerID = choiceProviderID(choice);
|
|
18301
|
-
const modelIDs = new Set(choice.models);
|
|
18641
|
+
const modelIDs = new Set(selectableModelIDs(choice.models, choice.modelInfo, meta.id));
|
|
18302
18642
|
modelIDs.add(choice.defaultModelID);
|
|
18303
18643
|
if (choice.thinkingModelID !== undefined) {
|
|
18304
18644
|
modelIDs.add(choice.thinkingModelID);
|
|
@@ -18354,6 +18694,8 @@ function buildOpencodeConfig(answers) {
|
|
|
18354
18694
|
if (answers.yolo) {
|
|
18355
18695
|
config.permission = { "*": "allow" };
|
|
18356
18696
|
}
|
|
18697
|
+
if (policies.length > 0)
|
|
18698
|
+
config.experimental = { policies };
|
|
18357
18699
|
return config;
|
|
18358
18700
|
}
|
|
18359
18701
|
function serializeOpencodeConfig(config) {
|
|
@@ -18453,10 +18795,11 @@ async function chooseFrontier(prompt, profiles) {
|
|
|
18453
18795
|
}
|
|
18454
18796
|
return parseFrontierRef(selected);
|
|
18455
18797
|
}
|
|
18456
|
-
function orderModelChoices(models, modelInfo) {
|
|
18798
|
+
function orderModelChoices(models, modelInfo, kind) {
|
|
18457
18799
|
const byID = new Map((modelInfo ?? []).map((model) => [model.modelID, model]));
|
|
18458
18800
|
const anyLoadState = (modelInfo ?? []).some((model) => model.loaded !== undefined);
|
|
18459
|
-
const
|
|
18801
|
+
const offered = kind === undefined ? models : selectableModelIDs(models, modelInfo, kind);
|
|
18802
|
+
const decorated = offered.map((modelID, index) => {
|
|
18460
18803
|
const info = byID.get(modelID);
|
|
18461
18804
|
return {
|
|
18462
18805
|
modelID,
|
|
@@ -18482,27 +18825,34 @@ function modelStateSuffix(loaded, slots) {
|
|
|
18482
18825
|
}
|
|
18483
18826
|
return slots === undefined ? "(loaded)" : `(loaded · ${slots} slot${slots === 1 ? "" : "s"})`;
|
|
18484
18827
|
}
|
|
18485
|
-
function preferredModelID(models, modelInfo) {
|
|
18486
|
-
const
|
|
18487
|
-
|
|
18828
|
+
function preferredModelID(models, modelInfo, kind) {
|
|
18829
|
+
const offered = kind === undefined ? models : selectableModelIDs(models, modelInfo, kind);
|
|
18830
|
+
const loaded = (modelInfo ?? []).find((model) => model.loaded === true && offered.includes(model.modelID));
|
|
18831
|
+
return loaded?.modelID ?? offered[0];
|
|
18488
18832
|
}
|
|
18489
18833
|
async function chooseRuntimeModel(prompt, models, meta, modelInfo) {
|
|
18490
|
-
|
|
18834
|
+
const offered = selectableModelIDs(models, modelInfo, meta.id);
|
|
18835
|
+
if (offered.length === 0) {
|
|
18836
|
+
if (meta.id === "lemonade")
|
|
18837
|
+
throw new Error(executionSetupMessages.lemonadeNoLoadedModels);
|
|
18491
18838
|
return prompt.text({
|
|
18492
18839
|
message: `Default model for ${meta.label} (no models detected)`,
|
|
18493
18840
|
placeholder: meta.fallbackModelID,
|
|
18494
18841
|
initial: meta.fallbackModelID
|
|
18495
18842
|
});
|
|
18496
18843
|
}
|
|
18497
|
-
const first = preferredModelID(
|
|
18844
|
+
const first = preferredModelID(offered, modelInfo, meta.id);
|
|
18498
18845
|
const opts = {
|
|
18499
18846
|
message: `Default local model for ${meta.label}`,
|
|
18500
|
-
choices: orderModelChoices(
|
|
18847
|
+
choices: orderModelChoices(offered, modelInfo, meta.id)
|
|
18501
18848
|
};
|
|
18502
18849
|
if (first !== undefined) {
|
|
18503
18850
|
opts.initial = first;
|
|
18504
18851
|
}
|
|
18505
|
-
|
|
18852
|
+
const selected = await prompt.select(opts);
|
|
18853
|
+
if (meta.id === "lemonade" && !offered.includes(selected))
|
|
18854
|
+
throw new Error(executionSetupMessages.lemonadeModelNotLoaded(selected));
|
|
18855
|
+
return selected;
|
|
18506
18856
|
}
|
|
18507
18857
|
function remoteBaseURLExample(meta) {
|
|
18508
18858
|
const base = meta.defaultBaseURL ?? "http://localhost:11434/v1";
|
|
@@ -18557,6 +18907,8 @@ async function resolveRuntimeConnection(deps, meta, info) {
|
|
|
18557
18907
|
initial: RUNTIME_LOCATION_LOCAL
|
|
18558
18908
|
});
|
|
18559
18909
|
if (location === RUNTIME_LOCATION_LOCAL) {
|
|
18910
|
+
if (meta.id === "lemonade" && info?.reachable !== true)
|
|
18911
|
+
throw new Error(executionSetupMessages.lemonadeProbeFailed);
|
|
18560
18912
|
const baseURL2 = info?.baseURL !== undefined && info.baseURL.length > 0 ? info.baseURL : meta.defaultBaseURL;
|
|
18561
18913
|
return { baseURL: baseURL2, ...connectionOf(info) };
|
|
18562
18914
|
}
|
|
@@ -18566,16 +18918,26 @@ async function resolveRuntimeConnection(deps, meta, info) {
|
|
|
18566
18918
|
});
|
|
18567
18919
|
const baseURL = normalizeRemoteBaseURL(entered, meta.defaultBaseURL);
|
|
18568
18920
|
let probedRuntime;
|
|
18921
|
+
if (meta.id === "lemonade" && deps.probeRuntime === undefined)
|
|
18922
|
+
throw new Error(executionSetupMessages.lemonadeProbeRequired);
|
|
18569
18923
|
if (deps.probeRuntime !== undefined) {
|
|
18570
18924
|
try {
|
|
18571
18925
|
probedRuntime = await deps.probeRuntime(meta.id, baseURL);
|
|
18572
|
-
} catch {
|
|
18926
|
+
} catch (cause) {
|
|
18927
|
+
if (meta.id === "lemonade")
|
|
18928
|
+
throw new Error(executionSetupMessages.lemonadeProbeFailed, { cause });
|
|
18929
|
+
}
|
|
18930
|
+
if (meta.id === "lemonade" && probedRuntime?.reachable !== true)
|
|
18931
|
+
throw new Error(executionSetupMessages.lemonadeProbeFailed);
|
|
18573
18932
|
}
|
|
18574
18933
|
return { baseURL, ...connectionOf(probedRuntime) };
|
|
18575
18934
|
}
|
|
18576
18935
|
async function chooseClassModel(prompt, models, meta, defaultModelID, modelClass, modelInfo) {
|
|
18577
18936
|
const label = modelClass === "thinking" ? `Thinking model for ${meta.label} (design, analysis, review reasoning)` : `Coder model for ${meta.label} (writing and editing code)`;
|
|
18578
|
-
|
|
18937
|
+
const offered = selectableModelIDs(models, modelInfo, meta.id);
|
|
18938
|
+
if (offered.length === 0) {
|
|
18939
|
+
if (meta.id === "lemonade")
|
|
18940
|
+
throw new Error(executionSetupMessages.lemonadeNoLoadedModels);
|
|
18579
18941
|
const raw = await prompt.text({
|
|
18580
18942
|
message: `${label} — enter to reuse the default`,
|
|
18581
18943
|
placeholder: defaultModelID,
|
|
@@ -18583,14 +18945,17 @@ async function chooseClassModel(prompt, models, meta, defaultModelID, modelClass
|
|
|
18583
18945
|
});
|
|
18584
18946
|
return raw.trim().length > 0 ? raw.trim() : defaultModelID;
|
|
18585
18947
|
}
|
|
18586
|
-
|
|
18948
|
+
const selected = await prompt.select({
|
|
18587
18949
|
message: label,
|
|
18588
|
-
choices: orderModelChoices(
|
|
18950
|
+
choices: orderModelChoices(offered, modelInfo, meta.id).map((choice) => ({
|
|
18589
18951
|
value: choice.value,
|
|
18590
18952
|
label: choice.value === defaultModelID ? `${choice.label} — default` : choice.label
|
|
18591
18953
|
})),
|
|
18592
18954
|
initial: defaultModelID
|
|
18593
18955
|
});
|
|
18956
|
+
if (meta.id === "lemonade" && !offered.includes(selected))
|
|
18957
|
+
throw new Error(executionSetupMessages.lemonadeModelNotLoaded(selected));
|
|
18958
|
+
return selected;
|
|
18594
18959
|
}
|
|
18595
18960
|
async function resolveEnabledRuntime(deps, meta, info) {
|
|
18596
18961
|
const connection = await resolveRuntimeConnection(deps, meta, info);
|
|
@@ -18603,7 +18968,8 @@ async function resolveEnabledRuntime(deps, meta, info) {
|
|
|
18603
18968
|
defaultModelID,
|
|
18604
18969
|
thinkingModelID,
|
|
18605
18970
|
coderModelID,
|
|
18606
|
-
models: connection.models
|
|
18971
|
+
models: selectableModelIDs(connection.models, connection.modelInfo, meta.id),
|
|
18972
|
+
...connection.modelInfo === undefined ? {} : { modelInfo: connection.modelInfo }
|
|
18607
18973
|
};
|
|
18608
18974
|
if (connection.baseURL !== undefined) {
|
|
18609
18975
|
choice.baseURL = connection.baseURL;
|
|
@@ -19103,17 +19469,52 @@ async function readExistingOpencodeConfigFiles(paths, deps) {
|
|
|
19103
19469
|
function opencodeFileAt(files, path2) {
|
|
19104
19470
|
return files.find((file) => file.path === path2);
|
|
19105
19471
|
}
|
|
19106
|
-
function mergeExistingOpencodeConfigFiles(files) {
|
|
19472
|
+
function mergeExistingOpencodeConfigFiles(files, paths, planned = new Map) {
|
|
19107
19473
|
let merged;
|
|
19108
|
-
for (const path2 of [...
|
|
19109
|
-
const
|
|
19110
|
-
if (
|
|
19474
|
+
for (const path2 of [...paths].reverse()) {
|
|
19475
|
+
const raw = planned.get(path2) ?? opencodeFileAt(files, path2)?.raw;
|
|
19476
|
+
if (raw === undefined) {
|
|
19111
19477
|
continue;
|
|
19112
19478
|
}
|
|
19113
|
-
merged = merged === undefined ?
|
|
19479
|
+
merged = merged === undefined ? raw : mergeOpencodeConfigs(merged, raw);
|
|
19114
19480
|
}
|
|
19115
19481
|
return merged;
|
|
19116
19482
|
}
|
|
19483
|
+
async function effectiveSetupConfig(portable, files, deps) {
|
|
19484
|
+
const optionsByLoader = new Map;
|
|
19485
|
+
for (const file of files) {
|
|
19486
|
+
if (!Array.isArray(file.raw.plugin))
|
|
19487
|
+
continue;
|
|
19488
|
+
for (const entry of [...file.raw.plugin].reverse()) {
|
|
19489
|
+
const spec = extractPluginSpec(entry);
|
|
19490
|
+
if (spec === undefined)
|
|
19491
|
+
continue;
|
|
19492
|
+
let identity;
|
|
19493
|
+
if (isOpenteamNpmSpec(spec)) {
|
|
19494
|
+
identity = OPENTEAM_PACKAGE_NAME;
|
|
19495
|
+
} else if (isLocalFileSpec(spec) && await classifyLocalPluginSpecForSetup(spec, file.path, deps.classifyLocalPluginSpec) === "ours") {
|
|
19496
|
+
const resolved = resolvePluginSpecPath(spec, file.path);
|
|
19497
|
+
if (resolved === undefined)
|
|
19498
|
+
throw new Error(executionSetupMessages.lemonadeEffectiveConfigAmbiguous);
|
|
19499
|
+
identity = resolved;
|
|
19500
|
+
} else {
|
|
19501
|
+
continue;
|
|
19502
|
+
}
|
|
19503
|
+
if (!optionsByLoader.has(identity)) {
|
|
19504
|
+
optionsByLoader.set(identity, Array.isArray(entry) ? entry[1] : undefined);
|
|
19505
|
+
}
|
|
19506
|
+
}
|
|
19507
|
+
}
|
|
19508
|
+
const overlayText = await deps.readFile(DEFAULT_LOCAL_OVERLAY_PATH);
|
|
19509
|
+
const overlay = overlayText === undefined ? undefined : parseConfigFileJson(DEFAULT_LOCAL_OVERLAY_PATH, overlayText);
|
|
19510
|
+
const resolutions = [
|
|
19511
|
+
...optionsByLoader.size > 0 ? optionsByLoader.values() : [undefined]
|
|
19512
|
+
].map((options) => validateConfigInput(executionSetupMessages.lemonadeEffectiveConfigLabel, mergeConfigInputs(mergeConfigInputs(portable, configOptionsFromPluginOptions(options)), overlay)));
|
|
19513
|
+
const effective = resolutions[0];
|
|
19514
|
+
if (effective === undefined || resolutions.some((config) => JSON.stringify(config) !== JSON.stringify(effective)))
|
|
19515
|
+
throw new Error(executionSetupMessages.lemonadeEffectiveConfigAmbiguous);
|
|
19516
|
+
return effective;
|
|
19517
|
+
}
|
|
19117
19518
|
function relevantLocalProviderIDs(generated, existingOpenTeamConfig) {
|
|
19118
19519
|
const ids = new Set(Object.keys(generated.provider ?? {}));
|
|
19119
19520
|
for (const runtime of existingOpenTeamConfig?.local.runtimes ?? []) {
|
|
@@ -19290,15 +19691,42 @@ function highestExistingPinVersion(files) {
|
|
|
19290
19691
|
}
|
|
19291
19692
|
return highest;
|
|
19292
19693
|
}
|
|
19694
|
+
function reconcileLemonadeV2Policies(raw, denials) {
|
|
19695
|
+
if (denials.length === 0)
|
|
19696
|
+
return raw;
|
|
19697
|
+
const experimental = raw.experimental;
|
|
19698
|
+
if (experimental !== undefined && !isRecord6(experimental))
|
|
19699
|
+
throw new Error(executionSetupMessages.lemonadeV2InvalidPolicies);
|
|
19700
|
+
const policies = experimental?.policies;
|
|
19701
|
+
if (policies !== undefined && !Array.isArray(policies))
|
|
19702
|
+
throw new Error(executionSetupMessages.lemonadeV2InvalidPolicies);
|
|
19703
|
+
const existing = policies ?? [];
|
|
19704
|
+
for (const policy of existing) {
|
|
19705
|
+
if (!isRecord6(policy) || policy.action !== "provider.use" || typeof policy.resource !== "string" || policy.effect !== "allow" && policy.effect !== "deny")
|
|
19706
|
+
throw new Error(executionSetupMessages.lemonadeV2InvalidPolicies);
|
|
19707
|
+
}
|
|
19708
|
+
const terminal = denials.every((denial, index) => {
|
|
19709
|
+
const policy = existing[existing.length - denials.length + index];
|
|
19710
|
+
return isRecord6(policy) && Object.keys(policy).length === 3 && policy.action === denial.action && policy.resource === denial.resource && policy.effect === denial.effect;
|
|
19711
|
+
});
|
|
19712
|
+
if (terminal)
|
|
19713
|
+
return raw;
|
|
19714
|
+
return {
|
|
19715
|
+
...raw,
|
|
19716
|
+
experimental: { ...experimental, policies: [...existing, ...denials] }
|
|
19717
|
+
};
|
|
19718
|
+
}
|
|
19293
19719
|
function mergeOpencodeConfigForRerun(generated, targetRaw, options) {
|
|
19294
19720
|
const effectiveRaw = options.effectiveRaw ?? targetRaw;
|
|
19295
19721
|
const includePlugin = options.includePlugin ?? true;
|
|
19722
|
+
const managesV2Policies = (generated.experimental?.policies.length ?? 0) > 0;
|
|
19296
19723
|
const managedKeys = new Set([
|
|
19297
19724
|
"$schema",
|
|
19298
19725
|
"provider",
|
|
19299
19726
|
"model",
|
|
19300
19727
|
"small_model",
|
|
19301
19728
|
"permission",
|
|
19729
|
+
...managesV2Policies ? ["experimental"] : [],
|
|
19302
19730
|
...includePlugin ? ["plugin"] : []
|
|
19303
19731
|
]);
|
|
19304
19732
|
const unknownFields = {};
|
|
@@ -19361,7 +19789,10 @@ function mergeOpencodeConfigForRerun(generated, targetRaw, options) {
|
|
|
19361
19789
|
if (permission !== undefined) {
|
|
19362
19790
|
result.permission = permission;
|
|
19363
19791
|
}
|
|
19364
|
-
|
|
19792
|
+
if (managesV2Policies && hasOwn2(targetRaw, "experimental")) {
|
|
19793
|
+
result.experimental = targetRaw.experimental;
|
|
19794
|
+
}
|
|
19795
|
+
return reconcileLemonadeV2Policies(result, generated.experimental?.policies ?? []);
|
|
19365
19796
|
}
|
|
19366
19797
|
function mergeOpenTeamConfigForRerun(generated, existing) {
|
|
19367
19798
|
const existingOrch = existing.orchestrator;
|
|
@@ -19411,6 +19842,21 @@ function mergeOpenTeamConfigForRerun(generated, existing) {
|
|
|
19411
19842
|
assertEffectiveConfigModelDomains(merged);
|
|
19412
19843
|
return merged;
|
|
19413
19844
|
}
|
|
19845
|
+
function preserveRetainedLemonadeRuntimes(generated, previous, opencode) {
|
|
19846
|
+
const providers = recordAt2(opencode, "provider") ?? {};
|
|
19847
|
+
const retained = (previous?.local.runtimes ?? []).filter((runtime) => localRuntimeKind(runtime) === "lemonade" && hasOwn2(providers, runtime.defaultModel.providerID));
|
|
19848
|
+
const deselected = retained.filter((runtime) => !generated.local.runtimes.some((selected) => selected.defaultModel.providerID === runtime.defaultModel.providerID)).map((runtime) => ({ ...runtime, enabled: false }));
|
|
19849
|
+
return {
|
|
19850
|
+
config: deselected.length === 0 ? generated : OpenTeamConfigSchema.parse({
|
|
19851
|
+
...generated,
|
|
19852
|
+
local: {
|
|
19853
|
+
...generated.local,
|
|
19854
|
+
runtimes: [...generated.local.runtimes, ...deselected]
|
|
19855
|
+
}
|
|
19856
|
+
}),
|
|
19857
|
+
providerIDs: retained.map((runtime) => runtime.defaultModel.providerID)
|
|
19858
|
+
};
|
|
19859
|
+
}
|
|
19414
19860
|
async function existingPluginOwnerPath(files, classifyLocalPluginSpec) {
|
|
19415
19861
|
let unknownLocalPlugin;
|
|
19416
19862
|
for (const file of files) {
|
|
@@ -19438,6 +19884,86 @@ async function confirmJsonNormalization(prompt, path2, format) {
|
|
|
19438
19884
|
initial: false
|
|
19439
19885
|
});
|
|
19440
19886
|
}
|
|
19887
|
+
function assertPreviousLemonadePrimary(answers, previousConfig) {
|
|
19888
|
+
const priorLemonadePrimary = previousConfig?.local.runtimes.some((runtime) => runtime.defaultModel.providerID === answers.primaryModel.providerID && localRuntimeKind(runtime) === "lemonade");
|
|
19889
|
+
if (priorLemonadePrimary && !answers.runtimes.some((choice) => choice.enabled && choiceProviderID(choice) === answers.primaryModel.providerID)) {
|
|
19890
|
+
throw new Error(executionSetupMessages.lemonadeModelNotLoaded(`${answers.primaryModel.providerID}/${answers.primaryModel.modelID}`));
|
|
19891
|
+
}
|
|
19892
|
+
}
|
|
19893
|
+
async function verifyLemonadeBeforeWrite(deps, answers, config, opencode) {
|
|
19894
|
+
for (const choice of answers.runtimes) {
|
|
19895
|
+
if (choice.enabled && localRuntimeKind(choice) === "lemonade" && !config.local.runtimes.some((runtime) => runtime.enabled && runtime.defaultModel.providerID === choiceProviderID(choice) && localRuntimeKind(runtime) === "lemonade"))
|
|
19896
|
+
throw new Error(executionSetupMessages.lemonadeEndpointMismatch);
|
|
19897
|
+
}
|
|
19898
|
+
for (const runtime of config.local.runtimes) {
|
|
19899
|
+
if (localRuntimeKind(runtime) !== "lemonade")
|
|
19900
|
+
continue;
|
|
19901
|
+
const providerID = runtime.defaultModel.providerID;
|
|
19902
|
+
const provider = isRecord6(opencode.provider) ? opencode.provider[providerID] : undefined;
|
|
19903
|
+
if (!runtime.enabled && provider === undefined)
|
|
19904
|
+
continue;
|
|
19905
|
+
const endpoint = isRecord6(provider) ? (isRecord6(provider.options) ? provider.options.baseURL : undefined) ?? provider.api : undefined;
|
|
19906
|
+
if (typeof endpoint !== "string" || lemonadeBaseURL(endpoint) !== lemonadeBaseURL(runtime.baseURL ?? LEMONADE_DEFAULT_BASE_URL) || config.local.runtimes.filter((candidate) => candidate.defaultModel.providerID === providerID).length !== 1)
|
|
19907
|
+
throw new Error(executionSetupMessages.lemonadeEndpointMismatch);
|
|
19908
|
+
if (!runtime.enabled)
|
|
19909
|
+
continue;
|
|
19910
|
+
if (deps.probeRuntime === undefined)
|
|
19911
|
+
throw new Error(executionSetupMessages.lemonadeProbeRequired);
|
|
19912
|
+
const references2 = new Set([
|
|
19913
|
+
runtime.defaultModel.modelID,
|
|
19914
|
+
runtime.thinkingModel,
|
|
19915
|
+
runtime.coderModel
|
|
19916
|
+
]);
|
|
19917
|
+
for (const choice of answers.runtimes) {
|
|
19918
|
+
if (choice.enabled && choiceProviderID(choice) === providerID) {
|
|
19919
|
+
for (const id of [
|
|
19920
|
+
...choice.models,
|
|
19921
|
+
choice.defaultModelID,
|
|
19922
|
+
choice.thinkingModelID,
|
|
19923
|
+
choice.coderModelID
|
|
19924
|
+
])
|
|
19925
|
+
references2.add(id);
|
|
19926
|
+
}
|
|
19927
|
+
}
|
|
19928
|
+
for (const ref of [
|
|
19929
|
+
answers.primaryModel,
|
|
19930
|
+
config.orchestrator?.primary?.model,
|
|
19931
|
+
config.router.localDefault
|
|
19932
|
+
]) {
|
|
19933
|
+
if (ref !== null && typeof ref === "object" && ref.providerID === providerID)
|
|
19934
|
+
references2.add(ref.modelID);
|
|
19935
|
+
}
|
|
19936
|
+
for (const key of ["model", "small_model"]) {
|
|
19937
|
+
const ref = opencode[key];
|
|
19938
|
+
if (typeof ref === "string" && ref.startsWith(`${providerID}/`))
|
|
19939
|
+
references2.add(ref.slice(providerID.length + 1));
|
|
19940
|
+
}
|
|
19941
|
+
const models = isRecord6(provider) ? recordAt2(provider, "models") : undefined;
|
|
19942
|
+
const wireIDs = new Set;
|
|
19943
|
+
for (const alias of references2) {
|
|
19944
|
+
if (alias === undefined)
|
|
19945
|
+
continue;
|
|
19946
|
+
const declaration = recordAt2(models, alias);
|
|
19947
|
+
const wireID = declaration !== undefined && hasOwn2(declaration, "id") ? declaration.id : alias;
|
|
19948
|
+
if (declaration === undefined || typeof wireID !== "string" || wireID.length === 0 || wireID !== wireID.trim())
|
|
19949
|
+
throw new Error(executionSetupMessages.lemonadeModelIdentityUnknown(`${providerID}/${alias}`));
|
|
19950
|
+
wireIDs.add(wireID);
|
|
19951
|
+
}
|
|
19952
|
+
let fresh;
|
|
19953
|
+
try {
|
|
19954
|
+
fresh = await deps.probeRuntime(localRuntimeKind(runtime), endpoint);
|
|
19955
|
+
} catch (cause) {
|
|
19956
|
+
throw new Error(executionSetupMessages.lemonadeProbeFailed, { cause });
|
|
19957
|
+
}
|
|
19958
|
+
if (!fresh.reachable || fresh.id !== localRuntimeKind(runtime) || fresh.baseURL.replace(/\/+$/, "") !== endpoint.replace(/\/+$/, ""))
|
|
19959
|
+
throw new Error(executionSetupMessages.lemonadeProbeFailed);
|
|
19960
|
+
for (const wireID of wireIDs) {
|
|
19961
|
+
const info = fresh.models.includes(wireID) ? fresh.modelInfo?.find((model) => model.modelID === wireID) : undefined;
|
|
19962
|
+
if (!hasRequiredModelResidency("lemonade", info))
|
|
19963
|
+
throw new Error(executionSetupMessages.lemonadeModelNotLoaded(`${providerID}/${wireID}`));
|
|
19964
|
+
}
|
|
19965
|
+
}
|
|
19966
|
+
}
|
|
19441
19967
|
async function runSetup(deps) {
|
|
19442
19968
|
const { prompt } = deps;
|
|
19443
19969
|
try {
|
|
@@ -19449,7 +19975,7 @@ async function runSetup(deps) {
|
|
|
19449
19975
|
return {
|
|
19450
19976
|
value: meta.id,
|
|
19451
19977
|
label: meta.label,
|
|
19452
|
-
hint: info?.reachable ? `detected · ${info.models.length} model(s)` : "not detected (you can point it to another machine)",
|
|
19978
|
+
hint: info?.reachable ? meta.id === "lemonade" ? executionSetupMessages.lemonadeDetectedHint(selectableModelIDs(info.models, info.modelInfo, meta.id).length, info.modelInfo?.length ?? info.models.length) : `detected · ${info.models.length} model(s)` : "not detected (you can point it to another machine)",
|
|
19453
19979
|
selected: info?.reachable ?? false
|
|
19454
19980
|
};
|
|
19455
19981
|
});
|
|
@@ -19566,17 +20092,18 @@ async function runSetup(deps) {
|
|
|
19566
20092
|
};
|
|
19567
20093
|
const openTeamConfig = buildOpenTeamConfig(answers);
|
|
19568
20094
|
const opencodeConfig = buildOpencodeConfig(answers);
|
|
20095
|
+
const opencodeConfigPaths = LEMONADE_PROJECT_CONFIG_CANDIDATES;
|
|
19569
20096
|
const orchestratorAgent = buildOrchestratorAgent(orchestratorAgentModel(answers), { yolo });
|
|
19570
20097
|
const slashCommands = buildOpenteamCommands();
|
|
19571
20098
|
const openTeamPath = DEFAULT_CONFIG_PATH;
|
|
19572
|
-
const existingOpencodePath = await deps.resolveOpencodeWriteTarget(
|
|
20099
|
+
const existingOpencodePath = await deps.resolveOpencodeWriteTarget(opencodeConfigPaths);
|
|
19573
20100
|
const opencodeDataPath = existingOpencodePath ?? OPENCODE_CONFIG_CANDIDATES[0];
|
|
19574
20101
|
const agentPath = ORCHESTRATOR_AGENT_PATH;
|
|
19575
20102
|
let existingOpenTeamConfig;
|
|
19576
20103
|
let existingOpencodeFiles;
|
|
19577
20104
|
try {
|
|
19578
20105
|
existingOpenTeamConfig = await readExistingOpenTeamConfig(openTeamPath, deps);
|
|
19579
|
-
existingOpencodeFiles = await readExistingOpencodeConfigFiles(
|
|
20106
|
+
existingOpencodeFiles = await readExistingOpencodeConfigFiles(opencodeConfigPaths, deps);
|
|
19580
20107
|
} catch (error) {
|
|
19581
20108
|
if (error instanceof ConfigParseError) {
|
|
19582
20109
|
return {
|
|
@@ -19586,7 +20113,29 @@ async function runSetup(deps) {
|
|
|
19586
20113
|
}
|
|
19587
20114
|
throw error;
|
|
19588
20115
|
}
|
|
19589
|
-
|
|
20116
|
+
assertPreviousLemonadePrimary(answers, existingOpenTeamConfig);
|
|
20117
|
+
const effectiveExistingOpencode = mergeExistingOpencodeConfigFiles(existingOpencodeFiles, opencodeConfigPaths);
|
|
20118
|
+
const {
|
|
20119
|
+
config: finalOpenTeamConfig,
|
|
20120
|
+
providerIDs: retainedLemonadeProviderIDs
|
|
20121
|
+
} = preserveRetainedLemonadeRuntimes(existingOpenTeamConfig !== undefined ? mergeOpenTeamConfigForRerun(openTeamConfig, existingOpenTeamConfig) : openTeamConfig, existingOpenTeamConfig, effectiveExistingOpencode);
|
|
20122
|
+
assertEffectiveConfigModelDomains(finalOpenTeamConfig);
|
|
20123
|
+
const effectiveOpenTeamConfig = await effectiveSetupConfig(finalOpenTeamConfig, existingOpencodeFiles, deps);
|
|
20124
|
+
assertEffectiveConfigModelDomains(effectiveOpenTeamConfig);
|
|
20125
|
+
for (const providerID of retainedLemonadeProviderIDs) {
|
|
20126
|
+
const matches = effectiveOpenTeamConfig.local.runtimes.filter((runtime) => runtime.defaultModel.providerID === providerID);
|
|
20127
|
+
if (matches.length !== 1 || matches[0] === undefined || localRuntimeKind(matches[0]) !== "lemonade")
|
|
20128
|
+
throw new Error(executionSetupMessages.lemonadeRetainedProviderUnprotected(providerID));
|
|
20129
|
+
}
|
|
20130
|
+
const v2Denials = lemonadeV2Policies([
|
|
20131
|
+
...opencodeConfig.experimental?.policies.map((policy) => policy.resource) ?? [],
|
|
20132
|
+
...effectiveOpenTeamConfig.local.runtimes.filter((runtime) => localRuntimeKind(runtime) === "lemonade").map((runtime) => runtime.defaultModel.providerID)
|
|
20133
|
+
]);
|
|
20134
|
+
if (v2Denials.length > 0)
|
|
20135
|
+
opencodeConfig.experimental = { policies: v2Denials };
|
|
20136
|
+
const v2Notice = v2Denials.length > 0 ? executionSetupMessages.lemonadeV2Restriction(v2Denials.map((policy) => policy.resource)) : undefined;
|
|
20137
|
+
if (v2Notice !== undefined)
|
|
20138
|
+
prompt.note(v2Notice, executionSetupMessages.lemonadeV2Title);
|
|
19590
20139
|
const relevantProviderIDs = relevantLocalProviderIDs(opencodeConfig, existingOpenTeamConfig);
|
|
19591
20140
|
for (const file of existingOpencodeFiles) {
|
|
19592
20141
|
assertRelevantLimitNumbers(file, relevantProviderIDs);
|
|
@@ -19615,8 +20164,6 @@ async function runSetup(deps) {
|
|
|
19615
20164
|
const pluginOwnerFile = opencodeFileAt(existingOpencodeFiles, pluginOwnerPath);
|
|
19616
20165
|
const pluginPlan = await mergePluginEntriesForRerun(Array.isArray(pluginOwnerFile?.raw.plugin) ? pluginOwnerFile.raw.plugin : [], pluginOwnerPath, preservePlugin, deps.classifyLocalPluginSpec);
|
|
19617
20166
|
const includePluginInDataFile = pluginOwnerPath === opencodeDataPath;
|
|
19618
|
-
const finalOpenTeamConfig = existingOpenTeamConfig !== undefined ? mergeOpenTeamConfigForRerun(openTeamConfig, existingOpenTeamConfig) : openTeamConfig;
|
|
19619
|
-
assertEffectiveConfigModelDomains(finalOpenTeamConfig);
|
|
19620
20167
|
const dataTargetRaw = opencodeFileAt(existingOpencodeFiles, opencodeDataPath)?.raw ?? {};
|
|
19621
20168
|
const mergedOpencodeRaw = mergeOpencodeConfigForRerun(opencodeConfig, dataTargetRaw, {
|
|
19622
20169
|
...effectiveExistingOpencode !== undefined ? { effectiveRaw: effectiveExistingOpencode } : {},
|
|
@@ -19631,7 +20178,7 @@ async function runSetup(deps) {
|
|
|
19631
20178
|
providerIDs: relevantProviderIDs
|
|
19632
20179
|
});
|
|
19633
20180
|
const opencodeWritePlan = new Map([
|
|
19634
|
-
[opencodeDataPath,
|
|
20181
|
+
[opencodeDataPath, repairedDataTarget.raw]
|
|
19635
20182
|
]);
|
|
19636
20183
|
for (const file of existingOpencodeFiles) {
|
|
19637
20184
|
if (file.path === opencodeDataPath) {
|
|
@@ -19643,17 +20190,16 @@ async function runSetup(deps) {
|
|
|
19643
20190
|
generated: opencodeConfig,
|
|
19644
20191
|
providerIDs: relevantProviderIDs
|
|
19645
20192
|
});
|
|
19646
|
-
let plannedRaw = repaired.raw;
|
|
19647
|
-
let changed = repaired.changed;
|
|
20193
|
+
let plannedRaw = reconcileLemonadeV2Policies(repaired.raw, v2Denials);
|
|
20194
|
+
let changed = repaired.changed || plannedRaw !== repaired.raw;
|
|
19648
20195
|
if (file.path === pluginOwnerPath && !includePluginInDataFile && pluginPlan.changed) {
|
|
19649
20196
|
plannedRaw = { ...plannedRaw, plugin: [...pluginPlan.plugins] };
|
|
19650
20197
|
changed = true;
|
|
19651
20198
|
}
|
|
19652
20199
|
if (changed) {
|
|
19653
|
-
opencodeWritePlan.set(file.path,
|
|
20200
|
+
opencodeWritePlan.set(file.path, plannedRaw);
|
|
19654
20201
|
}
|
|
19655
20202
|
}
|
|
19656
|
-
const roleAgentFiles = buildRoleAgentFiles(finalOpenTeamConfig);
|
|
19657
20203
|
const opencodeGitignorePath = OPENCODE_GITIGNORE_PATH;
|
|
19658
20204
|
const existingGitignore = await deps.fileExists(opencodeGitignorePath) ? await deps.readFile(opencodeGitignorePath) ?? "" : "";
|
|
19659
20205
|
const opencodeGitignore = buildOpencodeGitignore(existingGitignore);
|
|
@@ -19673,11 +20219,6 @@ async function runSetup(deps) {
|
|
|
19673
20219
|
if (await deps.fileExists(agentPath)) {
|
|
19674
20220
|
existing.add(ORCHESTRATOR_AGENT_PATH);
|
|
19675
20221
|
}
|
|
19676
|
-
for (const roleAgent of roleAgentFiles) {
|
|
19677
|
-
if (await deps.fileExists(roleAgent.path)) {
|
|
19678
|
-
existing.add(roleAgent.path);
|
|
19679
|
-
}
|
|
19680
|
-
}
|
|
19681
20222
|
for (const command of slashCommands) {
|
|
19682
20223
|
if (await deps.fileExists(command.path)) {
|
|
19683
20224
|
existing.add(command.path);
|
|
@@ -19720,14 +20261,15 @@ async function runSetup(deps) {
|
|
|
19720
20261
|
stdout: shouldWriteOpencodeGitignore ? `setup cancelled by user; ${OPENCODE_GITIGNORE_PATH} ensured` : "setup cancelled by user"
|
|
19721
20262
|
};
|
|
19722
20263
|
}
|
|
20264
|
+
const effectivePlannedOpencode = mergeExistingOpencodeConfigFiles(existingOpencodeFiles, opencodeConfigPaths, opencodeWritePlan);
|
|
20265
|
+
if (effectivePlannedOpencode === undefined)
|
|
20266
|
+
throw new Error(executionSetupMessages.lemonadeEndpointMismatch);
|
|
20267
|
+
await verifyLemonadeBeforeWrite(deps, answers, effectiveOpenTeamConfig, effectivePlannedOpencode);
|
|
19723
20268
|
await deps.writeFile(openTeamPath, serializeOpenTeamConfig(finalOpenTeamConfig));
|
|
19724
20269
|
for (const [path2, contents] of opencodeWritePlan) {
|
|
19725
|
-
await deps.writeFile(path2, contents);
|
|
20270
|
+
await deps.writeFile(path2, serializeOpencodeConfig(contents));
|
|
19726
20271
|
}
|
|
19727
20272
|
await deps.writeFile(agentPath, orchestratorAgent);
|
|
19728
|
-
for (const roleAgent of roleAgentFiles) {
|
|
19729
|
-
await deps.writeFile(roleAgent.path, roleAgent.contents);
|
|
19730
|
-
}
|
|
19731
20273
|
for (const command of slashCommands) {
|
|
19732
20274
|
await deps.writeFile(command.path, command.contents);
|
|
19733
20275
|
}
|
|
@@ -19748,8 +20290,6 @@ async function runSetup(deps) {
|
|
|
19748
20290
|
opencodePath: writtenOpencodePaths,
|
|
19749
20291
|
configPath: DEFAULT_CONFIG_PATH,
|
|
19750
20292
|
agentPath: ORCHESTRATOR_AGENT_PATH,
|
|
19751
|
-
agentDir: AGENT_DIR,
|
|
19752
|
-
roleAgentCount: roleAgentFiles.length,
|
|
19753
20293
|
commandDir: OPENTEAM_COMMAND_DIR,
|
|
19754
20294
|
commandCount: slashCommands.length,
|
|
19755
20295
|
gitignorePath: OPENCODE_GITIGNORE_PATH
|
|
@@ -19758,7 +20298,11 @@ async function runSetup(deps) {
|
|
|
19758
20298
|
prompt.outro(executionSetupMessages.done);
|
|
19759
20299
|
return {
|
|
19760
20300
|
exitCode: 0,
|
|
19761
|
-
stdout:
|
|
20301
|
+
stdout: [
|
|
20302
|
+
executionSetupMessages.complete(`${writtenOpencodePaths}, ${DEFAULT_CONFIG_PATH}, ${ORCHESTRATOR_AGENT_PATH}, ${OPENTEAM_COMMAND_DIR}/*.md, ${OPENCODE_GITIGNORE_PATH}`),
|
|
20303
|
+
...v2Notice === undefined ? [] : [v2Notice]
|
|
20304
|
+
].join(`
|
|
20305
|
+
`)
|
|
19762
20306
|
};
|
|
19763
20307
|
} catch (error) {
|
|
19764
20308
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -20413,7 +20957,7 @@ import {
|
|
|
20413
20957
|
import { basename as basename3, dirname as dirname8, join as join19, relative as relative2, resolve as resolve11, win32 } from "node:path";
|
|
20414
20958
|
import { fileURLToPath } from "node:url";
|
|
20415
20959
|
import { promisify as promisify2 } from "node:util";
|
|
20416
|
-
import { z as
|
|
20960
|
+
import { z as z25 } from "zod";
|
|
20417
20961
|
var NPM_ORIGIN = "https://registry.npmjs.org";
|
|
20418
20962
|
var NPM_PACKAGE_PATH = "/@jmanuelcorral%2Fopenteam";
|
|
20419
20963
|
var NPM_LATEST_URL = `${NPM_ORIGIN}${NPM_PACKAGE_PATH}/latest`;
|
|
@@ -20432,9 +20976,9 @@ var UPGRADE_BACKUP_DIRECTORY = ".opencode/openteam-local/upgrade-backups";
|
|
|
20432
20976
|
function npmVersionUrl(version) {
|
|
20433
20977
|
return `${NPM_ORIGIN}${NPM_PACKAGE_PATH}/${version}`;
|
|
20434
20978
|
}
|
|
20435
|
-
var RegistryPackageIdentitySchema =
|
|
20436
|
-
name:
|
|
20437
|
-
version:
|
|
20979
|
+
var RegistryPackageIdentitySchema = z25.object({
|
|
20980
|
+
name: z25.string(),
|
|
20981
|
+
version: z25.string()
|
|
20438
20982
|
}).strict();
|
|
20439
20983
|
|
|
20440
20984
|
class TransientFetchError extends Error {
|
|
@@ -22093,12 +22637,19 @@ function defaultModelFromOpencode(opencodeConfig) {
|
|
|
22093
22637
|
}
|
|
22094
22638
|
return;
|
|
22095
22639
|
}
|
|
22096
|
-
function liveModelsFromSnapshots(snapshots) {
|
|
22640
|
+
function liveModelsFromSnapshots(snapshots, config) {
|
|
22097
22641
|
const map = new Map;
|
|
22098
22642
|
for (const snapshot of snapshots) {
|
|
22099
|
-
|
|
22643
|
+
const runtime = config.local.runtimes.find((runtime2) => runtime2.id === snapshot.id);
|
|
22644
|
+
if (runtime === undefined || !runtime.enabled)
|
|
22645
|
+
continue;
|
|
22646
|
+
const kind = localRuntimeKind(runtime);
|
|
22647
|
+
map.set(runtime.defaultModel.providerID, {
|
|
22100
22648
|
reachable: snapshot.reachable,
|
|
22101
|
-
modelIDs: new Set(snapshot.models.map((model) => model.modelID))
|
|
22649
|
+
modelIDs: new Set(snapshot.models.filter((model) => hasRequiredModelResidency(kind, model)).map((model) => model.modelID)),
|
|
22650
|
+
...kind === "lemonade" ? {
|
|
22651
|
+
residency: new Map(snapshot.models.map((model) => [model.modelID, model.loaded]))
|
|
22652
|
+
} : {}
|
|
22102
22653
|
});
|
|
22103
22654
|
}
|
|
22104
22655
|
return map;
|
|
@@ -22384,7 +22935,7 @@ async function runCli(argv, deps) {
|
|
|
22384
22935
|
const agentModels = diagnoseAgentModels(agentFiles, {
|
|
22385
22936
|
opencodeProviders: parseOpencodeProviders(opencodeConfig),
|
|
22386
22937
|
localRuntimes: localRuntimeStates(config),
|
|
22387
|
-
liveModels: liveModelsFromSnapshots(snapshots),
|
|
22938
|
+
liveModels: liveModelsFromSnapshots(snapshots, config),
|
|
22388
22939
|
sourceDir: deps.agentDir,
|
|
22389
22940
|
...defaultModel !== undefined ? { defaultModel } : {}
|
|
22390
22941
|
});
|
|
@@ -22423,29 +22974,53 @@ async function runCli(argv, deps) {
|
|
|
22423
22974
|
const rosterMissing = deps.loadRosterForDoctor !== undefined && roster === undefined && rosterLoadError === undefined;
|
|
22424
22975
|
const orchestratorAgentName = ORCHESTRATOR_AGENT_PATH.slice(ORCHESTRATOR_AGENT_PATH.lastIndexOf("/") + 1).replace(/\.md$/, "");
|
|
22425
22976
|
const orchestratorAgentMissing = !agentFiles.some((file) => file.name === orchestratorAgentName);
|
|
22977
|
+
const inventoryNotes = [];
|
|
22978
|
+
const readySnapshots = snapshots.map((snapshot) => {
|
|
22979
|
+
const runtime = config.local.runtimes.find((runtime2) => runtime2.id === snapshot.id);
|
|
22980
|
+
if (runtime === undefined || localRuntimeKind(runtime) !== "lemonade")
|
|
22981
|
+
return snapshot;
|
|
22982
|
+
inventoryNotes.push(executionSetupMessages.lemonadeInventory(runtime.id, runtime.defaultModel.providerID, snapshot.models));
|
|
22983
|
+
return {
|
|
22984
|
+
...snapshot,
|
|
22985
|
+
models: snapshot.models.filter((model) => hasRequiredModelResidency(localRuntimeKind(runtime), model))
|
|
22986
|
+
};
|
|
22987
|
+
});
|
|
22988
|
+
const residencyNotes = agentModels.flatMap((agent) => {
|
|
22989
|
+
const live = agent.resolution?.live;
|
|
22990
|
+
if (agent.model === undefined || live !== "not-loaded" && live !== "residency-unknown")
|
|
22991
|
+
return [];
|
|
22992
|
+
return [
|
|
22993
|
+
executionSetupMessages.lemonadeAgentResidency(agent.name, `${agent.model.providerID}/${agent.model.modelID}`, live)
|
|
22994
|
+
];
|
|
22995
|
+
});
|
|
22426
22996
|
return {
|
|
22427
22997
|
exitCode: 0,
|
|
22428
|
-
stdout:
|
|
22429
|
-
|
|
22430
|
-
|
|
22431
|
-
|
|
22432
|
-
|
|
22433
|
-
|
|
22434
|
-
|
|
22435
|
-
|
|
22436
|
-
|
|
22437
|
-
|
|
22438
|
-
|
|
22439
|
-
|
|
22440
|
-
|
|
22441
|
-
|
|
22442
|
-
|
|
22443
|
-
|
|
22444
|
-
|
|
22445
|
-
|
|
22446
|
-
|
|
22447
|
-
|
|
22448
|
-
|
|
22998
|
+
stdout: [
|
|
22999
|
+
renderDoctor({
|
|
23000
|
+
config,
|
|
23001
|
+
snapshots: readySnapshots,
|
|
23002
|
+
telemetryPath,
|
|
23003
|
+
telemetryRecords: records.length,
|
|
23004
|
+
agentModels,
|
|
23005
|
+
opencodeConfigPaths,
|
|
23006
|
+
...opencodeConfig !== undefined ? { opencodeConfig } : {},
|
|
23007
|
+
...queueWait !== undefined ? { queueWait } : {},
|
|
23008
|
+
...rosterAudit !== undefined ? { rosterAudit } : {},
|
|
23009
|
+
...rosterRoleCount !== undefined ? { rosterRoleCount } : {},
|
|
23010
|
+
...rosterLoadError !== undefined ? { rosterLoadError } : {},
|
|
23011
|
+
...rosterMissing ? { rosterMissing } : {},
|
|
23012
|
+
...orchestratorAgentMissing ? { orchestratorAgentMissing } : {},
|
|
23013
|
+
...diagnostics !== undefined && diagnostics.length > 0 ? { diagnostics } : {},
|
|
23014
|
+
...opencodeConfigError !== undefined ? { opencodeConfigError } : {},
|
|
23015
|
+
...cacheEntries !== undefined ? { cacheEntries, cliVersion: deps.version } : {},
|
|
23016
|
+
...legacyLayout !== undefined && legacyLayout.length > 0 ? { legacyLayout } : {},
|
|
23017
|
+
...otelBackend !== undefined ? { otelBackend } : {},
|
|
23018
|
+
...gitignoreCoverage !== undefined ? { gitignore: gitignoreCoverage } : {}
|
|
23019
|
+
}),
|
|
23020
|
+
...inventoryNotes,
|
|
23021
|
+
...residencyNotes
|
|
23022
|
+
].join(`
|
|
23023
|
+
`)
|
|
22449
23024
|
};
|
|
22450
23025
|
}
|
|
22451
23026
|
if (command === "migrate") {
|
|
@@ -22562,14 +23137,14 @@ ${HELP}`
|
|
|
22562
23137
|
}
|
|
22563
23138
|
|
|
22564
23139
|
// src/orchestrator/roster.ts
|
|
22565
|
-
import { z as
|
|
22566
|
-
var RosterEntrySchema =
|
|
22567
|
-
roleID:
|
|
22568
|
-
agentName:
|
|
23140
|
+
import { z as z26 } from "zod";
|
|
23141
|
+
var RosterEntrySchema = z26.object({
|
|
23142
|
+
roleID: z26.string().min(1),
|
|
23143
|
+
agentName: z26.string().min(1)
|
|
22569
23144
|
}).strict();
|
|
22570
|
-
var RosterSchema =
|
|
22571
|
-
universe:
|
|
22572
|
-
entries:
|
|
23145
|
+
var RosterSchema = z26.object({
|
|
23146
|
+
universe: z26.string().min(1),
|
|
23147
|
+
entries: z26.array(RosterEntrySchema)
|
|
22573
23148
|
}).strict();
|
|
22574
23149
|
var ROSTER_JSON_FENCE = /```json\s*([\s\S]*?)```/;
|
|
22575
23150
|
|
|
@@ -23123,7 +23698,7 @@ import { readFile as readFile4 } from "node:fs/promises";
|
|
|
23123
23698
|
import { basename as basename4, dirname as dirname9 } from "node:path";
|
|
23124
23699
|
|
|
23125
23700
|
// src/graph/certificate.ts
|
|
23126
|
-
import { z as
|
|
23701
|
+
import { z as z27 } from "zod";
|
|
23127
23702
|
|
|
23128
23703
|
// src/contract/opencode.ts
|
|
23129
23704
|
var SUPPORTED_OPENCODE_VERSIONS = [
|
|
@@ -23164,7 +23739,7 @@ function isCertificateVersionCompatible(certifiedVersion, liveVersion) {
|
|
|
23164
23739
|
|
|
23165
23740
|
// src/graph/certificate.ts
|
|
23166
23741
|
var SHADOW_CERTIFICATE_MIN_RUNS = 1000;
|
|
23167
|
-
var DivergenceCodeSchema =
|
|
23742
|
+
var DivergenceCodeSchema = z27.enum([
|
|
23168
23743
|
"status",
|
|
23169
23744
|
"order",
|
|
23170
23745
|
"roles",
|
|
@@ -23172,50 +23747,50 @@ var DivergenceCodeSchema = z26.enum([
|
|
|
23172
23747
|
"fixes",
|
|
23173
23748
|
"outcome"
|
|
23174
23749
|
]);
|
|
23175
|
-
var ProvenanceSchema =
|
|
23750
|
+
var ProvenanceSchema = z27.enum([
|
|
23176
23751
|
"recomputed",
|
|
23177
23752
|
"compiled",
|
|
23178
23753
|
"validated",
|
|
23179
23754
|
"carried"
|
|
23180
23755
|
]);
|
|
23181
|
-
var EvidenceSchema =
|
|
23182
|
-
opencodeVersion:
|
|
23183
|
-
parity:
|
|
23184
|
-
runs:
|
|
23185
|
-
match:
|
|
23186
|
-
divergent:
|
|
23187
|
-
inconclusive:
|
|
23188
|
-
divergences:
|
|
23756
|
+
var EvidenceSchema = z27.object({
|
|
23757
|
+
opencodeVersion: z27.string().min(1),
|
|
23758
|
+
parity: z27.object({
|
|
23759
|
+
runs: z27.number().int().nonnegative(),
|
|
23760
|
+
match: z27.number().int().nonnegative(),
|
|
23761
|
+
divergent: z27.number().int().nonnegative(),
|
|
23762
|
+
inconclusive: z27.number().int().nonnegative(),
|
|
23763
|
+
divergences: z27.array(DivergenceCodeSchema)
|
|
23189
23764
|
}).strict(),
|
|
23190
|
-
legacy:
|
|
23191
|
-
observed:
|
|
23192
|
-
duplicated:
|
|
23765
|
+
legacy: z27.object({
|
|
23766
|
+
observed: z27.number().int().nonnegative(),
|
|
23767
|
+
duplicated: z27.number().int().nonnegative()
|
|
23193
23768
|
}).strict(),
|
|
23194
|
-
privacy:
|
|
23195
|
-
surfacesScanned:
|
|
23196
|
-
rawFindings:
|
|
23769
|
+
privacy: z27.object({
|
|
23770
|
+
surfacesScanned: z27.number().int().nonnegative(),
|
|
23771
|
+
rawFindings: z27.number().int().nonnegative()
|
|
23197
23772
|
}).strict(),
|
|
23198
|
-
overhead:
|
|
23199
|
-
p95Millis:
|
|
23200
|
-
budgetMillis:
|
|
23201
|
-
samples:
|
|
23773
|
+
overhead: z27.object({
|
|
23774
|
+
p95Millis: z27.number().nonnegative(),
|
|
23775
|
+
budgetMillis: z27.number().positive(),
|
|
23776
|
+
samples: z27.number().int().nonnegative()
|
|
23202
23777
|
}).strict(),
|
|
23203
|
-
provenance:
|
|
23778
|
+
provenance: z27.record(DivergenceCodeSchema, ProvenanceSchema)
|
|
23204
23779
|
}).strict();
|
|
23205
|
-
var CertificateSchema =
|
|
23206
|
-
version:
|
|
23207
|
-
certificate:
|
|
23208
|
-
opencodeVersion:
|
|
23780
|
+
var CertificateSchema = z27.object({
|
|
23781
|
+
version: z27.literal(1),
|
|
23782
|
+
certificate: z27.literal("graph-shadow"),
|
|
23783
|
+
opencodeVersion: z27.string().min(1),
|
|
23209
23784
|
evidence: EvidenceSchema,
|
|
23210
|
-
verdict:
|
|
23211
|
-
failedGates:
|
|
23785
|
+
verdict: z27.enum(["pass", "fail"]),
|
|
23786
|
+
failedGates: z27.array(z27.enum([
|
|
23212
23787
|
"sample",
|
|
23213
23788
|
"parity",
|
|
23214
23789
|
"one-legacy-execution",
|
|
23215
23790
|
"privacy",
|
|
23216
23791
|
"overhead"
|
|
23217
23792
|
])),
|
|
23218
|
-
digest:
|
|
23793
|
+
digest: z27.string().regex(/^[0-9a-f]{64}$/)
|
|
23219
23794
|
}).strict();
|
|
23220
23795
|
|
|
23221
23796
|
class ShadowCertificateError extends Error {
|
|
@@ -23330,37 +23905,37 @@ function parseShadowCertificate(value, opencodeVersion) {
|
|
|
23330
23905
|
}
|
|
23331
23906
|
return certificate;
|
|
23332
23907
|
}
|
|
23333
|
-
var ReleaseDeterminismSchema =
|
|
23334
|
-
var ReleaseCrashRecoverySchema =
|
|
23335
|
-
scenarios:
|
|
23336
|
-
allConverge:
|
|
23908
|
+
var ReleaseDeterminismSchema = z27.object({ runs: z27.number().int().nonnegative(), allMatch: z27.boolean() }).strict();
|
|
23909
|
+
var ReleaseCrashRecoverySchema = z27.object({
|
|
23910
|
+
scenarios: z27.number().int().nonnegative(),
|
|
23911
|
+
allConverge: z27.boolean()
|
|
23337
23912
|
}).strict();
|
|
23338
|
-
var ReleaseReplayEquivalenceSchema =
|
|
23339
|
-
checks:
|
|
23340
|
-
allEquivalent:
|
|
23913
|
+
var ReleaseReplayEquivalenceSchema = z27.object({
|
|
23914
|
+
checks: z27.number().int().nonnegative(),
|
|
23915
|
+
allEquivalent: z27.boolean()
|
|
23341
23916
|
}).strict();
|
|
23342
|
-
var ReleasePrivacySchema =
|
|
23343
|
-
surfacesScanned:
|
|
23344
|
-
rawFindings:
|
|
23917
|
+
var ReleasePrivacySchema = z27.object({
|
|
23918
|
+
surfacesScanned: z27.number().int().nonnegative(),
|
|
23919
|
+
rawFindings: z27.number().int().nonnegative()
|
|
23345
23920
|
}).strict();
|
|
23346
|
-
var ReleaseContractSchema =
|
|
23347
|
-
roundTrips:
|
|
23348
|
-
allSettled:
|
|
23921
|
+
var ReleaseContractSchema = z27.object({
|
|
23922
|
+
roundTrips: z27.number().int().nonnegative(),
|
|
23923
|
+
allSettled: z27.boolean()
|
|
23349
23924
|
}).strict();
|
|
23350
|
-
var ReleaseHealthSchema =
|
|
23351
|
-
samples:
|
|
23352
|
-
bounded:
|
|
23353
|
-
idempotent:
|
|
23925
|
+
var ReleaseHealthSchema = z27.object({
|
|
23926
|
+
samples: z27.number().int().nonnegative(),
|
|
23927
|
+
bounded: z27.boolean(),
|
|
23928
|
+
idempotent: z27.boolean()
|
|
23354
23929
|
}).strict();
|
|
23355
|
-
var ReleasePerformanceSchema =
|
|
23356
|
-
p95Millis:
|
|
23357
|
-
budgetMillis:
|
|
23358
|
-
samples:
|
|
23930
|
+
var ReleasePerformanceSchema = z27.object({
|
|
23931
|
+
p95Millis: z27.number().nonnegative(),
|
|
23932
|
+
budgetMillis: z27.number().positive(),
|
|
23933
|
+
samples: z27.number().int().nonnegative()
|
|
23359
23934
|
}).strict();
|
|
23360
|
-
var ReleaseEvidenceSchema =
|
|
23361
|
-
opencodeVersion:
|
|
23362
|
-
platform:
|
|
23363
|
-
shadowCertificateDigest:
|
|
23935
|
+
var ReleaseEvidenceSchema = z27.object({
|
|
23936
|
+
opencodeVersion: z27.string().min(1),
|
|
23937
|
+
platform: z27.enum(["linux", "win32"]),
|
|
23938
|
+
shadowCertificateDigest: z27.string().regex(/^[0-9a-f]{64}$/),
|
|
23364
23939
|
determinism: ReleaseDeterminismSchema,
|
|
23365
23940
|
crashRecovery: ReleaseCrashRecoverySchema,
|
|
23366
23941
|
replayEquivalence: ReleaseReplayEquivalenceSchema,
|
|
@@ -23369,15 +23944,15 @@ var ReleaseEvidenceSchema = z26.object({
|
|
|
23369
23944
|
health: ReleaseHealthSchema,
|
|
23370
23945
|
performance: ReleasePerformanceSchema
|
|
23371
23946
|
}).strict();
|
|
23372
|
-
var ReleaseCertificateSchema =
|
|
23373
|
-
version:
|
|
23374
|
-
certificate:
|
|
23375
|
-
platform:
|
|
23376
|
-
opencodeVersion:
|
|
23377
|
-
shadowCertificateDigest:
|
|
23947
|
+
var ReleaseCertificateSchema = z27.object({
|
|
23948
|
+
version: z27.literal(2),
|
|
23949
|
+
certificate: z27.literal("graph-release"),
|
|
23950
|
+
platform: z27.enum(["linux", "win32"]),
|
|
23951
|
+
opencodeVersion: z27.string().min(1),
|
|
23952
|
+
shadowCertificateDigest: z27.string().regex(/^[0-9a-f]{64}$/),
|
|
23378
23953
|
evidence: ReleaseEvidenceSchema,
|
|
23379
|
-
verdict:
|
|
23380
|
-
failedGates:
|
|
23954
|
+
verdict: z27.enum(["pass", "fail"]),
|
|
23955
|
+
failedGates: z27.array(z27.enum([
|
|
23381
23956
|
"shadow-valid",
|
|
23382
23957
|
"determinism",
|
|
23383
23958
|
"crash-recovery",
|
|
@@ -23387,7 +23962,7 @@ var ReleaseCertificateSchema = z26.object({
|
|
|
23387
23962
|
"health",
|
|
23388
23963
|
"performance"
|
|
23389
23964
|
])),
|
|
23390
|
-
digest:
|
|
23965
|
+
digest: z27.string().regex(/^[0-9a-f]{64}$/)
|
|
23391
23966
|
}).strict();
|
|
23392
23967
|
|
|
23393
23968
|
class ReleaseCertificateError extends Error {
|
|
@@ -23515,7 +24090,7 @@ function parseReleaseCertificate(value, opencodeVersion, expectedShadowDigest) {
|
|
|
23515
24090
|
}
|
|
23516
24091
|
return certificate;
|
|
23517
24092
|
}
|
|
23518
|
-
var ShadowDivergenceCodeSchema =
|
|
24093
|
+
var ShadowDivergenceCodeSchema = z27.enum([
|
|
23519
24094
|
"status",
|
|
23520
24095
|
"order",
|
|
23521
24096
|
"roles",
|
|
@@ -23524,13 +24099,13 @@ var ShadowDivergenceCodeSchema = z26.enum([
|
|
|
23524
24099
|
"outcome"
|
|
23525
24100
|
]);
|
|
23526
24101
|
var RECOMPUTED_DIVERGENCE_CODES = ["fixes"];
|
|
23527
|
-
var RecomputedDivergenceCodeSchema =
|
|
23528
|
-
var SoakPolicySchema =
|
|
23529
|
-
minimumGenuineObservations:
|
|
23530
|
-
minimumDistinctDays:
|
|
23531
|
-
requireGenuineUsageOnAllPlatforms:
|
|
23532
|
-
supportedOpencodeVersions:
|
|
23533
|
-
criticalDivergenceCodes:
|
|
24102
|
+
var RecomputedDivergenceCodeSchema = z27.enum(RECOMPUTED_DIVERGENCE_CODES);
|
|
24103
|
+
var SoakPolicySchema = z27.object({
|
|
24104
|
+
minimumGenuineObservations: z27.number().int().positive(),
|
|
24105
|
+
minimumDistinctDays: z27.number().int().positive(),
|
|
24106
|
+
requireGenuineUsageOnAllPlatforms: z27.boolean(),
|
|
24107
|
+
supportedOpencodeVersions: z27.array(z27.string().min(1)).min(1),
|
|
24108
|
+
criticalDivergenceCodes: z27.array(RecomputedDivergenceCodeSchema).min(1)
|
|
23534
24109
|
}).strict();
|
|
23535
24110
|
var DEFAULT_SOAK_POLICY = {
|
|
23536
24111
|
minimumGenuineObservations: 100,
|
|
@@ -23539,46 +24114,46 @@ var DEFAULT_SOAK_POLICY = {
|
|
|
23539
24114
|
supportedOpencodeVersions: [...SUPPORTED_OPENCODE_VERSIONS],
|
|
23540
24115
|
criticalDivergenceCodes: ["fixes"]
|
|
23541
24116
|
};
|
|
23542
|
-
var SoakPlatformEnumSchema =
|
|
23543
|
-
var SoakPrivacyPairEvidenceSchema =
|
|
23544
|
-
surfacesScanned:
|
|
23545
|
-
rawFindings:
|
|
24117
|
+
var SoakPlatformEnumSchema = z27.enum(["linux", "win32", "darwin"]);
|
|
24118
|
+
var SoakPrivacyPairEvidenceSchema = z27.object({
|
|
24119
|
+
surfacesScanned: z27.number().int().nonnegative(),
|
|
24120
|
+
rawFindings: z27.number().int().nonnegative()
|
|
23546
24121
|
}).strict();
|
|
23547
|
-
var SoakDuplicateEffectPairEvidenceSchema =
|
|
23548
|
-
effectsExamined:
|
|
23549
|
-
duplicatesFound:
|
|
24122
|
+
var SoakDuplicateEffectPairEvidenceSchema = z27.object({
|
|
24123
|
+
effectsExamined: z27.number().int().nonnegative(),
|
|
24124
|
+
duplicatesFound: z27.number().int().nonnegative()
|
|
23550
24125
|
}).strict();
|
|
23551
|
-
var SoakModelVerificationPairEvidenceSchema =
|
|
23552
|
-
nodesChecked:
|
|
23553
|
-
unverified:
|
|
23554
|
-
mismatched:
|
|
24126
|
+
var SoakModelVerificationPairEvidenceSchema = z27.object({
|
|
24127
|
+
nodesChecked: z27.number().int().nonnegative(),
|
|
24128
|
+
unverified: z27.number().int().nonnegative(),
|
|
24129
|
+
mismatched: z27.number().int().nonnegative()
|
|
23555
24130
|
}).strict();
|
|
23556
|
-
var SoakEvidenceSchema =
|
|
23557
|
-
totalObservations:
|
|
23558
|
-
genuineUsageObservations:
|
|
23559
|
-
ciSyntheticObservations:
|
|
23560
|
-
recorderCount:
|
|
23561
|
-
ineligibleObservations:
|
|
23562
|
-
firstTimestamp:
|
|
23563
|
-
lastTimestamp:
|
|
23564
|
-
distinctDays:
|
|
23565
|
-
criticalDivergences:
|
|
24131
|
+
var SoakEvidenceSchema = z27.object({
|
|
24132
|
+
totalObservations: z27.number().int().nonnegative(),
|
|
24133
|
+
genuineUsageObservations: z27.number().int().nonnegative(),
|
|
24134
|
+
ciSyntheticObservations: z27.number().int().nonnegative(),
|
|
24135
|
+
recorderCount: z27.number().int().nonnegative(),
|
|
24136
|
+
ineligibleObservations: z27.number().int().nonnegative(),
|
|
24137
|
+
firstTimestamp: z27.string().datetime().nullable(),
|
|
24138
|
+
lastTimestamp: z27.string().datetime().nullable(),
|
|
24139
|
+
distinctDays: z27.number().int().nonnegative(),
|
|
24140
|
+
criticalDivergences: z27.number().int().nonnegative().nullable(),
|
|
23566
24141
|
privacy: SoakPrivacyPairEvidenceSchema.nullable(),
|
|
23567
24142
|
duplicateEffects: SoakDuplicateEffectPairEvidenceSchema.nullable(),
|
|
23568
24143
|
modelVerification: SoakModelVerificationPairEvidenceSchema.nullable(),
|
|
23569
|
-
platformsGenuine:
|
|
23570
|
-
platformsSynthetic:
|
|
23571
|
-
opencodeVersionsObserved:
|
|
23572
|
-
invalidChains:
|
|
24144
|
+
platformsGenuine: z27.array(SoakPlatformEnumSchema),
|
|
24145
|
+
platformsSynthetic: z27.array(SoakPlatformEnumSchema),
|
|
24146
|
+
opencodeVersionsObserved: z27.array(z27.string().min(1)),
|
|
24147
|
+
invalidChains: z27.number().int().nonnegative()
|
|
23573
24148
|
}).strict();
|
|
23574
|
-
var SoakCertificateSchema =
|
|
23575
|
-
version:
|
|
23576
|
-
certificate:
|
|
23577
|
-
trustBoundary:
|
|
24149
|
+
var SoakCertificateSchema = z27.object({
|
|
24150
|
+
version: z27.literal(1),
|
|
24151
|
+
certificate: z27.literal("graph-soak"),
|
|
24152
|
+
trustBoundary: z27.literal("contributors"),
|
|
23578
24153
|
policy: SoakPolicySchema,
|
|
23579
24154
|
evidence: SoakEvidenceSchema,
|
|
23580
|
-
verdict:
|
|
23581
|
-
failedGates:
|
|
24155
|
+
verdict: z27.enum(["pass", "fail"]),
|
|
24156
|
+
failedGates: z27.array(z27.enum([
|
|
23582
24157
|
"minimum-observations",
|
|
23583
24158
|
"minimum-duration",
|
|
23584
24159
|
"chain-integrity",
|
|
@@ -23589,8 +24164,8 @@ var SoakCertificateSchema = z26.object({
|
|
|
23589
24164
|
"os-diversity",
|
|
23590
24165
|
"opencode-pin"
|
|
23591
24166
|
])),
|
|
23592
|
-
ledgerDigest:
|
|
23593
|
-
digest:
|
|
24167
|
+
ledgerDigest: z27.string().regex(/^[0-9a-f]{64}$/),
|
|
24168
|
+
digest: z27.string().regex(/^[0-9a-f]{64}$/)
|
|
23594
24169
|
}).strict();
|
|
23595
24170
|
|
|
23596
24171
|
class SoakCertificateError extends Error {
|
|
@@ -24238,62 +24813,62 @@ var realCacheAdapter = {
|
|
|
24238
24813
|
};
|
|
24239
24814
|
|
|
24240
24815
|
// src/memory/types.ts
|
|
24241
|
-
import { z as
|
|
24816
|
+
import { z as z28 } from "zod";
|
|
24242
24817
|
var SHARED_OWNER_KEY = "*";
|
|
24243
|
-
var OwnerKeySchema =
|
|
24244
|
-
var MemoryKindSchema =
|
|
24245
|
-
var MemoryBaseSchema =
|
|
24246
|
-
id:
|
|
24818
|
+
var OwnerKeySchema = z28.string().min(1);
|
|
24819
|
+
var MemoryKindSchema = z28.enum(["fact", "preference", "entity"]);
|
|
24820
|
+
var MemoryBaseSchema = z28.object({
|
|
24821
|
+
id: z28.string().min(1),
|
|
24247
24822
|
ownerKey: OwnerKeySchema,
|
|
24248
|
-
confidence:
|
|
24249
|
-
validFrom:
|
|
24250
|
-
validUntil:
|
|
24251
|
-
createdAt:
|
|
24252
|
-
invalidatedAt:
|
|
24253
|
-
sourceHash:
|
|
24254
|
-
supersededBy:
|
|
24823
|
+
confidence: z28.number().min(0).max(1),
|
|
24824
|
+
validFrom: z28.number().finite(),
|
|
24825
|
+
validUntil: z28.number().finite().nullable().default(null),
|
|
24826
|
+
createdAt: z28.number().finite(),
|
|
24827
|
+
invalidatedAt: z28.number().finite().nullable().default(null),
|
|
24828
|
+
sourceHash: z28.string().min(1),
|
|
24829
|
+
supersededBy: z28.string().min(1).nullable().default(null)
|
|
24255
24830
|
}).strict();
|
|
24256
24831
|
var FactSchema = MemoryBaseSchema.extend({
|
|
24257
|
-
kind:
|
|
24258
|
-
subject:
|
|
24259
|
-
predicate:
|
|
24260
|
-
object:
|
|
24261
|
-
category:
|
|
24832
|
+
kind: z28.literal("fact"),
|
|
24833
|
+
subject: z28.string().min(1),
|
|
24834
|
+
predicate: z28.string().min(1),
|
|
24835
|
+
object: z28.string().min(1),
|
|
24836
|
+
category: z28.string().min(1).nullable().default(null)
|
|
24262
24837
|
});
|
|
24263
24838
|
var PreferenceSchema = MemoryBaseSchema.extend({
|
|
24264
|
-
kind:
|
|
24265
|
-
category:
|
|
24266
|
-
preference:
|
|
24267
|
-
context:
|
|
24268
|
-
lastAccessedAt:
|
|
24269
|
-
accessCount:
|
|
24839
|
+
kind: z28.literal("preference"),
|
|
24840
|
+
category: z28.string().min(1),
|
|
24841
|
+
preference: z28.string().min(1),
|
|
24842
|
+
context: z28.string().min(1).nullable().default(null),
|
|
24843
|
+
lastAccessedAt: z28.number().finite().nullable().default(null),
|
|
24844
|
+
accessCount: z28.number().int().min(0).default(0)
|
|
24270
24845
|
});
|
|
24271
24846
|
var EntitySchema = MemoryBaseSchema.extend({
|
|
24272
|
-
kind:
|
|
24273
|
-
canonicalName:
|
|
24274
|
-
type:
|
|
24275
|
-
aliases:
|
|
24847
|
+
kind: z28.literal("entity"),
|
|
24848
|
+
canonicalName: z28.string().min(1),
|
|
24849
|
+
type: z28.string().min(1),
|
|
24850
|
+
aliases: z28.array(z28.string().min(1)).default([])
|
|
24276
24851
|
});
|
|
24277
24852
|
var RelationSchema = MemoryBaseSchema.extend({
|
|
24278
|
-
kind:
|
|
24279
|
-
from:
|
|
24280
|
-
to:
|
|
24281
|
-
predicate:
|
|
24282
|
-
annotation:
|
|
24853
|
+
kind: z28.literal("relation"),
|
|
24854
|
+
from: z28.string().min(1),
|
|
24855
|
+
to: z28.string().min(1),
|
|
24856
|
+
predicate: z28.string().min(1),
|
|
24857
|
+
annotation: z28.string().min(1).nullable().default(null)
|
|
24283
24858
|
});
|
|
24284
|
-
var MemoryRecordSchema =
|
|
24859
|
+
var MemoryRecordSchema = z28.discriminatedUnion("kind", [
|
|
24285
24860
|
FactSchema,
|
|
24286
24861
|
PreferenceSchema,
|
|
24287
24862
|
EntitySchema,
|
|
24288
24863
|
RelationSchema
|
|
24289
24864
|
]);
|
|
24290
|
-
var RecallQuerySchema =
|
|
24865
|
+
var RecallQuerySchema = z28.object({
|
|
24291
24866
|
ownerKey: OwnerKeySchema,
|
|
24292
|
-
kinds:
|
|
24293
|
-
asOf:
|
|
24294
|
-
limit:
|
|
24295
|
-
minSimilarity:
|
|
24296
|
-
includeShared:
|
|
24867
|
+
kinds: z28.array(MemoryKindSchema).default(["fact", "preference", "entity"]),
|
|
24868
|
+
asOf: z28.number().finite().nullable().default(null),
|
|
24869
|
+
limit: z28.number().int().positive().default(8),
|
|
24870
|
+
minSimilarity: z28.number().min(0).max(1).default(0.2),
|
|
24871
|
+
includeShared: z28.boolean().default(true)
|
|
24297
24872
|
}).strict();
|
|
24298
24873
|
|
|
24299
24874
|
// src/memory/rank.ts
|
|
@@ -25714,7 +26289,7 @@ function createGitLastCommit(exec) {
|
|
|
25714
26289
|
// src/cli.ts
|
|
25715
26290
|
var execFileAsync3 = promisify3(execFile3);
|
|
25716
26291
|
var execAsync = promisify3(exec);
|
|
25717
|
-
var
|
|
26292
|
+
var AGENT_DIR = dirname10(ORCHESTRATOR_AGENT_PATH);
|
|
25718
26293
|
var storage = createFsStorageProvider(process.cwd());
|
|
25719
26294
|
var CLI_LIFECYCLE_WRITER_IDENTITY = {
|
|
25720
26295
|
processID: process.pid,
|
|
@@ -25959,7 +26534,7 @@ var deps = {
|
|
|
25959
26534
|
telemetryPath: DEFAULT_TELEMETRY_PATH,
|
|
25960
26535
|
opencodeConfigPaths: OPENCODE_CONFIG_CANDIDATES,
|
|
25961
26536
|
orchestratorAgentPath: ORCHESTRATOR_AGENT_PATH,
|
|
25962
|
-
agentDir:
|
|
26537
|
+
agentDir: AGENT_DIR,
|
|
25963
26538
|
cachePort: realCacheAdapter,
|
|
25964
26539
|
purge: createCliPurgeRuntime(),
|
|
25965
26540
|
loadRosterForDoctor: readStoredRosterForDoctor,
|
|
@@ -26092,7 +26667,7 @@ async function main() {
|
|
|
26092
26667
|
sessionsDir: effectiveSessionsDir,
|
|
26093
26668
|
decisionsPath: resolveReadPathForCurrent(DEFAULT_DECISIONS_PATH, legacyExists),
|
|
26094
26669
|
backlogPath: resolveReadPathForCurrent(DEFAULT_BACKLOG_PATH, legacyExists),
|
|
26095
|
-
agentDir:
|
|
26670
|
+
agentDir: AGENT_DIR,
|
|
26096
26671
|
legacyTelemetryPath: effectiveTelemetryPath,
|
|
26097
26672
|
storage,
|
|
26098
26673
|
listAgentFiles: deps.listAgentFiles,
|