@jmanuelcorral/openteam 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.es.md +22 -8
- package/README.md +19 -7
- package/dist/certificates/graph-release-certificate.json +2 -2
- package/dist/certificates/graph-shadow-certificate.json +2 -2
- package/dist/cli.js +131 -84
- package/dist/commands/setup.d.ts +0 -19
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +508 -54
- package/dist/messages/executionSetup.d.ts +0 -2
- package/dist/messages/executionSetup.d.ts.map +1 -1
- 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/roster.d.ts +0 -7
- package/dist/orchestrator/roster.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/reloadTool.d.ts +33 -0
- package/dist/plugin/reloadTool.d.ts.map +1 -0
- 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/index.js
CHANGED
|
@@ -4103,6 +4103,28 @@ import { z as z13 } from "zod";
|
|
|
4103
4103
|
// src/telemetry/events.ts
|
|
4104
4104
|
import { z as z11 } from "zod";
|
|
4105
4105
|
|
|
4106
|
+
// src/messages/reload.ts
|
|
4107
|
+
var reloadMessages = {
|
|
4108
|
+
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.",
|
|
4109
|
+
action: "Request a confirmed reload or cancel this session's queued request.",
|
|
4110
|
+
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.",
|
|
4111
|
+
invalid: "Reload not queued: provide only action (request or cancel) and explicit boolean confirmed. No target directory or other arguments are accepted.",
|
|
4112
|
+
declined: "Reload not queued: explicit affirmative consent to the current reload question is required. No files or policies were changed.",
|
|
4113
|
+
denied: "Reload is restricted to the openteam primary in this plugin's project.",
|
|
4114
|
+
closed: "This reload controller is no longer active. Check the current opencode instance before requesting another reload; agent discovery has not been verified.",
|
|
4115
|
+
other: "A reload request is already pending for another session. This call does not replace or extend its confirmation.",
|
|
4116
|
+
authorizing: "Host permission for this project's reload is still pending. This call queues nothing and does not extend the confirmation deadline.",
|
|
4117
|
+
none: "There is no queued reload for this session to cancel.",
|
|
4118
|
+
"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.",
|
|
4119
|
+
"reload-waiting": "Reload is still waiting: project sessions are busy or retrying. They will not be aborted; the original 30-second deadline is unchanged.",
|
|
4120
|
+
"reload-accepted": "opencode accepted the project-instance reload request. Agent discovery and readiness have not been verified; existing discovery safeguards still apply.",
|
|
4121
|
+
"reload-cancelled": "The pending reload was cancelled before disposal was requested. Prepared files, history and policies are unchanged.",
|
|
4122
|
+
"reload-timeout": "Reload was not requested: the 30-second idle deadline expired. A new explicit confirmation is required; nothing will retry automatically.",
|
|
4123
|
+
"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.",
|
|
4124
|
+
"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.",
|
|
4125
|
+
"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."
|
|
4126
|
+
};
|
|
4127
|
+
|
|
4106
4128
|
// src/telemetry/diagnostics.ts
|
|
4107
4129
|
var DIAGNOSTIC_CODES = [
|
|
4108
4130
|
"availability-refresh-failed",
|
|
@@ -4115,6 +4137,14 @@ var DIAGNOSTIC_CODES = [
|
|
|
4115
4137
|
"opencode-server-url",
|
|
4116
4138
|
"opencode-version-read-failed",
|
|
4117
4139
|
"privacy-inert",
|
|
4140
|
+
"reload-queued",
|
|
4141
|
+
"reload-waiting",
|
|
4142
|
+
"reload-accepted",
|
|
4143
|
+
"reload-cancelled",
|
|
4144
|
+
"reload-timeout",
|
|
4145
|
+
"reload-status-failed",
|
|
4146
|
+
"reload-dispose-failed",
|
|
4147
|
+
"reload-unconfirmed",
|
|
4118
4148
|
"soak-evidence-rejected",
|
|
4119
4149
|
"telemetry-warning",
|
|
4120
4150
|
"telemetry-write-failed",
|
|
@@ -4142,6 +4172,15 @@ function diagnosticDescription(code) {
|
|
|
4142
4172
|
return "openteam could not read the live opencode version; graph gates fail closed when this happens.";
|
|
4143
4173
|
case "privacy-inert":
|
|
4144
4174
|
return routingMessages.privacyModeDeprecated;
|
|
4175
|
+
case "reload-queued":
|
|
4176
|
+
case "reload-waiting":
|
|
4177
|
+
case "reload-accepted":
|
|
4178
|
+
case "reload-cancelled":
|
|
4179
|
+
case "reload-timeout":
|
|
4180
|
+
case "reload-status-failed":
|
|
4181
|
+
case "reload-dispose-failed":
|
|
4182
|
+
case "reload-unconfirmed":
|
|
4183
|
+
return reloadMessages[code];
|
|
4145
4184
|
case "soak-evidence-rejected":
|
|
4146
4185
|
return "Graph soak evidence contained rejected observation lines; cutover gate evidence may be incomplete.";
|
|
4147
4186
|
case "telemetry-warning":
|
|
@@ -4894,6 +4933,48 @@ function withDeterministicGitLocale(env) {
|
|
|
4894
4933
|
};
|
|
4895
4934
|
}
|
|
4896
4935
|
|
|
4936
|
+
// src/opencodeArtifacts/createRosterReload.ts
|
|
4937
|
+
var CREATE_ROSTER_RELOAD_INSTRUCTIONS = [
|
|
4938
|
+
"## Reload confirmation — /create_roster only",
|
|
4939
|
+
"",
|
|
4940
|
+
"Only after successful persisted registration and verified agent files may you offer reload:",
|
|
4941
|
+
"read back the parseable persisted roster, including guaranteed roles; actually create each missing",
|
|
4942
|
+
"subagent file and verify every required existing or created file.",
|
|
4943
|
+
"First show the complete Agent/Role/Model table returned by `openteam-register-cast`,",
|
|
4944
|
+
"including primary, guaranteed and preserved agents with their unchanged tool-returned policy values.",
|
|
4945
|
+
"Then show the created-versus-preserved file summary and any warnings. Both must be visible",
|
|
4946
|
+
"BEFORE asking a fresh explicit reload question in this opencode conversation.",
|
|
4947
|
+
"If registration, file creation or verification failed or is partial, do not ask the reload question:",
|
|
4948
|
+
"report the exact blocker and do not claim readiness. If registration succeeded, still show its",
|
|
4949
|
+
"complete table even when file preparation later fails.",
|
|
4950
|
+
"",
|
|
4951
|
+
"Ask whether to reload this project's opencode agent definitions now, explaining the request is",
|
|
4952
|
+
"queued/waiting until the requesting turn completes and all project sessions are idle.",
|
|
4953
|
+
"Use the host question tool when available; otherwise ask a normal conversational question",
|
|
4954
|
+
"in opencode and WAIT for the user's answer. Never use a terminal wizard, tool permission",
|
|
4955
|
+
"approval or YOLO permission as reload consent. A greenfield project-description reply is NOT reload consent.",
|
|
4956
|
+
"Only an explicit affirmative answer to this specific reload question authorizes",
|
|
4957
|
+
'`openteam-reload` with `{ action: "request", confirmed: true }`.',
|
|
4958
|
+
"False, no, cancel, an ambiguous answer or no reply means no reload request.",
|
|
4959
|
+
"A decline before anything is queued needs no tool call; do not turn ambiguity into confirmation.",
|
|
4960
|
+
"To cancel an already queued request at the user's direction, use",
|
|
4961
|
+
'`openteam-reload` with `{ action: "cancel", confirmed: false }` and report its actual result.',
|
|
4962
|
+
"",
|
|
4963
|
+
"This internal tool is restricted to the product primary `openteam` and its bound project.",
|
|
4964
|
+
"Do not supply a directory, project, session or other model-selected target.",
|
|
4965
|
+
"Report queued/waiting honestly and end the confirming turn immediately.",
|
|
4966
|
+
"Do not await your own idle state, poll or hold the turn open. Do not start work or call",
|
|
4967
|
+
"`task` or `openteam-orchestrate`; do not rewrite/recast files or change models, permissions",
|
|
4968
|
+
"or execution policies. The idle wait has a finite timeout; surface timeout and failure results",
|
|
4969
|
+
"when the runtime reports them, including rejected requests, rather than promising success or silently retrying.",
|
|
4970
|
+
"SDK acceptance is not verified discovery or readiness. Preserve all existing discovery guards:",
|
|
4971
|
+
"if new agents remain undiscovered, surface the reload/discovery blocker;",
|
|
4972
|
+
"do not dispatch through a generic substitute or claim readiness.",
|
|
4973
|
+
"This workflow and all its replies remain composition only. After completion, decline or cancellation,",
|
|
4974
|
+
"wait for a separate work request; neither a reload answer nor queued acceptance starts project work."
|
|
4975
|
+
].join(`
|
|
4976
|
+
`);
|
|
4977
|
+
|
|
4897
4978
|
// src/opencodeArtifacts/rosterSummary.ts
|
|
4898
4979
|
var ROSTER_SUMMARY_INSTRUCTIONS = [
|
|
4899
4980
|
"After every successful cast creation, repair or extension, show the complete Agent/Role/Model table",
|
|
@@ -4926,6 +5007,20 @@ var TEAM_PREPARATION_INSTRUCTIONS = [
|
|
|
4926
5007
|
"machine bindings stay unchanged; do not require a terminal or manually edit policy to finish hiring.",
|
|
4927
5008
|
"Never infer execution domains from prose, relax permissions, or invent a concrete auto model.",
|
|
4928
5009
|
"Registration/review is idempotent: a capable configured team needs no extra members or file rewrites.",
|
|
5010
|
+
"`agentName`, not `roleID`, determines each worker filename.",
|
|
5011
|
+
"Create `.opencode/agent/<agentName>.md` only for registered roster entries.",
|
|
5012
|
+
"A built-in role profile is not an extra agent.",
|
|
5013
|
+
"Do not create a parallel `<roleID>.md` when the roster maps that role to another alias.",
|
|
5014
|
+
"An existing roster alias equal to its roleID is still valid; do not rename it.",
|
|
5015
|
+
"Do not run `openteam setup` to hire workers or repair their files.",
|
|
5016
|
+
"Preserve unrelated and legacy generic files; do not delete, overwrite or silently register them.",
|
|
5017
|
+
"Registration writes roster/profile state, not worker Markdown.",
|
|
5018
|
+
"Report only verified file changes; do not call pre-existing files newly created.",
|
|
5019
|
+
"When creating a scribe worker, put the following memory instructions in its charter:",
|
|
5020
|
+
"Use `openteam-memory` for durable, reusable facts, entities and typed relations.",
|
|
5021
|
+
"Send only redacted knowledge messages, never raw conversations, prompts or credentials.",
|
|
5022
|
+
"Honor operator permissions and memory settings; do not broaden them.",
|
|
5023
|
+
"A disabled-memory or nothing-recorded result is expected; do not retry it.",
|
|
4929
5024
|
"Create only missing agent definitions; preserve customized files. Show the registration table",
|
|
4930
5025
|
"and verify preparation before dispatch. If opencode cannot discover a new agent, surface",
|
|
4931
5026
|
"the reload/discovery blocker; do not dispatch through a generic substitute or claim readiness."
|
|
@@ -4967,33 +5062,43 @@ function buildOrchestratorAgent(model, options = {}) {
|
|
|
4967
5062
|
"primary agent: there is no pre-created team. You **build the team of",
|
|
4968
5063
|
"subagents on demand** according to the goal of the user and the repository.",
|
|
4969
5064
|
"",
|
|
4970
|
-
"## Golden rule: check the team on EVERY request",
|
|
4971
|
-
"",
|
|
4972
|
-
"Before answering or delegating **any** request, your **first action",
|
|
4973
|
-
"always** is to check whether a team already exists, even if the user does not",
|
|
4974
|
-
"explicitly ask you to create it. Never assume there is a team or that there is not:",
|
|
4975
|
-
`verify it by looking at \`${OPENTEAM_ROSTER_PATH}\` and the \`.opencode/agent/*.md\``,
|
|
4976
|
-
"files with `mode: subagent` (use `read`/`glob`/`list`).",
|
|
4977
|
-
"",
|
|
4978
|
-
ROSTER_SUMMARY_INSTRUCTIONS,
|
|
4979
|
-
"",
|
|
4980
|
-
TEAM_PREPARATION_INSTRUCTIONS,
|
|
4981
|
-
"",
|
|
4982
5065
|
"## Roster composition takes precedence",
|
|
4983
5066
|
"",
|
|
4984
5067
|
"For `/create_roster`, including replies to its pending questions, follow",
|
|
4985
5068
|
"the command's roster-only workflow: do not distribute tasks or start implementation.",
|
|
5069
|
+
"These rules override the ordinary golden rule and capability checks below.",
|
|
5070
|
+
"A bare yes to a pending reload question continues only reload confirmation:",
|
|
5071
|
+
"do not restart roster reads, capability preparation or registration.",
|
|
4986
5072
|
"Reuse or conservatively extend the existing cast and preserve customized agent files.",
|
|
4987
5073
|
"Use a supplied description; otherwise inspect real project source read-only.",
|
|
4988
5074
|
"If there is no meaningful source and no description, ask what the user wants to",
|
|
4989
5075
|
"build in this conversation and wait before any writes or cast registration.",
|
|
4990
5076
|
"Register through `openteam-register-cast`, create missing subagent files, verify",
|
|
4991
|
-
"the persisted roster and files, then
|
|
5077
|
+
"the persisted roster and files, then follow the reload confirmation below.",
|
|
5078
|
+
"Do not call `openteam-orchestrate` or",
|
|
4992
5079
|
"`task` for this workflow. A later answer to your question continues composition",
|
|
4993
5080
|
"only until it completes or the user cancels; it is not an implementation request.",
|
|
4994
5081
|
"",
|
|
5082
|
+
CREATE_ROSTER_RELOAD_INSTRUCTIONS,
|
|
5083
|
+
"",
|
|
5084
|
+
"## Golden rule: check the team on EVERY request",
|
|
5085
|
+
"",
|
|
5086
|
+
"The roster composition and pending reload-reply rules above take precedence.",
|
|
5087
|
+
"Before answering or delegating **any ordinary work** request, your **first action",
|
|
5088
|
+
"always** is to check whether a team already exists, even if the user does not",
|
|
5089
|
+
"explicitly ask you to create it. Never assume there is a team or that there is not:",
|
|
5090
|
+
`verify it by looking at \`${OPENTEAM_ROSTER_PATH}\` and the \`.opencode/agent/*.md\``,
|
|
5091
|
+
"files with `mode: subagent` (use `read`/`glob`/`list`).",
|
|
5092
|
+
"",
|
|
5093
|
+
ROSTER_SUMMARY_INSTRUCTIONS,
|
|
5094
|
+
"",
|
|
5095
|
+
TEAM_PREPARATION_INSTRUCTIONS,
|
|
5096
|
+
"",
|
|
4995
5097
|
"## For work requests, including analysis, review and documentation",
|
|
4996
5098
|
"",
|
|
5099
|
+
"Ordinary automatic hiring must NOT ask for reload or automatically reset the project.",
|
|
5100
|
+
"If discovery is blocked, surface the blocker and preserve the discovery guards instead.",
|
|
5101
|
+
"",
|
|
4997
5102
|
"- **If the team ALREADY exists** → review capability coverage, reuse suitable",
|
|
4998
5103
|
" members and extend only for uncovered needs. Complete any existing member's",
|
|
4999
5104
|
" profile through `openteam-register-cast`; do not hire for a configuration gap.",
|
|
@@ -5368,8 +5473,10 @@ function buildCreateRosterCommand() {
|
|
|
5368
5473
|
"required agent file exists. If anything failed, report the incomplete state and exact",
|
|
5369
5474
|
"blocker; do not delete preserved state or claim the team is ready.",
|
|
5370
5475
|
"Summarize the cast, role rationale/evidence, preserved versus newly created files, and",
|
|
5371
|
-
"any warnings.
|
|
5372
|
-
"
|
|
5476
|
+
"any warnings. Continue only to the reload confirmation below, including its pending replies;",
|
|
5477
|
+
"do not restart preparation when the user answers that reload question.",
|
|
5478
|
+
"",
|
|
5479
|
+
CREATE_ROSTER_RELOAD_INSTRUCTIONS,
|
|
5373
5480
|
"",
|
|
5374
5481
|
"## Project description (user input)",
|
|
5375
5482
|
"",
|
|
@@ -5636,7 +5743,7 @@ import { z as z15 } from "zod";
|
|
|
5636
5743
|
// package.json
|
|
5637
5744
|
var package_default = {
|
|
5638
5745
|
name: "@jmanuelcorral/openteam",
|
|
5639
|
-
version: "0.
|
|
5746
|
+
version: "0.24.0",
|
|
5640
5747
|
packageManager: "bun@1.3.14",
|
|
5641
5748
|
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
5642
5749
|
license: "MIT",
|
|
@@ -6015,12 +6122,14 @@ var executionSetupMessages = {
|
|
|
6015
6122
|
`Local runtimes: ${params.localRuntimes}`,
|
|
6016
6123
|
`YOLO mode: ${params.yolo ? "enabled (auto-approves permissions)" : "disabled"}`,
|
|
6017
6124
|
"Web Console: launched separately with 'openteam console' (multi-session, loopback)",
|
|
6018
|
-
`Wrote: ${params.opencodePath}, ${params.configPath}, ${params.agentPath}, ${params.
|
|
6125
|
+
`Wrote: ${params.opencodePath}, ${params.configPath}, ${params.agentPath}, ${params.commandDir}/*.md (${params.commandCount} commands); ensured ${params.gitignorePath}`,
|
|
6126
|
+
"Worker files are created through conversational roster preparation, not setup; existing worker files were left untouched.",
|
|
6019
6127
|
"",
|
|
6020
6128
|
"Next steps:",
|
|
6021
6129
|
params.executionMode === "local" ? " 1. No frontier authentication is required while local execution is active" : " 1. Authenticate the frontier provider: opencode auth login",
|
|
6022
6130
|
params.executionMode === "local" ? executionSetupMessages.localRuntimeNextStep : params.executionMode === "mixed" ? executionSetupMessages.mixedNextStep : executionSetupMessages.frontierNextStep,
|
|
6023
|
-
" 3. Press Tab and pick the 'openteam' agent, or type / and pick an /openteam… command"
|
|
6131
|
+
" 3. Press Tab and pick the 'openteam' agent, or type / and pick an /openteam… command",
|
|
6132
|
+
" 4. Use /create_roster to compose the team without starting project work, or describe a task to prepare the team and begin work"
|
|
6024
6133
|
],
|
|
6025
6134
|
configuredTitle: "openteam configured",
|
|
6026
6135
|
complete: (paths) => `openteam setup complete: ${paths}`,
|
|
@@ -10294,8 +10403,11 @@ var UNAUTHORIZED_MODEL_SWITCH_REASON = "routing-model-switch-not-authorized";
|
|
|
10294
10403
|
function invalidRoleIdentifier(roleID) {
|
|
10295
10404
|
return `invalid role identifier "${roleID}" — use letters, numbers, underscores, or hyphens, starting with a letter or number`;
|
|
10296
10405
|
}
|
|
10406
|
+
function agentPreparationRemedy(agentName) {
|
|
10407
|
+
return "Use `/create_roster` in opencode to complete the missing roster agent " + "definitions without changing existing aliases. " + `If \`.opencode/agent/${agentName}.md\` already exists, reload opencode ` + "to discover it before retrying; do not substitute an unrelated agent.";
|
|
10408
|
+
}
|
|
10297
10409
|
function missingAgentDefinition(agentName, roleID) {
|
|
10298
|
-
return `agent definition "${agentName}" is not installed for role "${roleID}". ` +
|
|
10410
|
+
return `agent definition "${agentName}" is not installed for role "${roleID}". ` + agentPreparationRemedy(agentName);
|
|
10299
10411
|
}
|
|
10300
10412
|
function dependencyValidationError(code, detail) {
|
|
10301
10413
|
return `dependency validation error: ${code} (${detail})`;
|
|
@@ -10548,6 +10660,50 @@ function lifecycleRecordingAdvisory(status) {
|
|
|
10548
10660
|
return `Lifecycle history recording is ${status.state}${failure}; model execution continued without claiming complete history.`;
|
|
10549
10661
|
}
|
|
10550
10662
|
|
|
10663
|
+
// src/orchestrator/sessionStatus.ts
|
|
10664
|
+
function dataProperties(value) {
|
|
10665
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
10666
|
+
return;
|
|
10667
|
+
try {
|
|
10668
|
+
const prototype = Object.getPrototypeOf(value);
|
|
10669
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
10670
|
+
return;
|
|
10671
|
+
if (Reflect.ownKeys(value).some((key) => typeof key !== "string"))
|
|
10672
|
+
return;
|
|
10673
|
+
const properties = Object.getOwnPropertyDescriptors(value);
|
|
10674
|
+
return Object.values(properties).every((property) => ("value" in property) && property.enumerable === true) ? properties : undefined;
|
|
10675
|
+
} catch {
|
|
10676
|
+
return;
|
|
10677
|
+
}
|
|
10678
|
+
}
|
|
10679
|
+
function parseSessionStatus(value) {
|
|
10680
|
+
const properties = dataProperties(value);
|
|
10681
|
+
if (properties === undefined)
|
|
10682
|
+
return;
|
|
10683
|
+
const type = properties.type?.value;
|
|
10684
|
+
if (type === "idle" || type === "busy")
|
|
10685
|
+
return { type };
|
|
10686
|
+
const attempt = properties.attempt?.value;
|
|
10687
|
+
const message = properties.message?.value;
|
|
10688
|
+
const next = properties.next?.value;
|
|
10689
|
+
if (type === "retry" && typeof attempt === "number" && Number.isFinite(attempt) && typeof message === "string" && typeof next === "number" && Number.isFinite(next))
|
|
10690
|
+
return { type, attempt, message, next };
|
|
10691
|
+
return;
|
|
10692
|
+
}
|
|
10693
|
+
function parseSessionStatusMap(value) {
|
|
10694
|
+
const properties = dataProperties(value);
|
|
10695
|
+
if (properties === undefined)
|
|
10696
|
+
return;
|
|
10697
|
+
const entries = [];
|
|
10698
|
+
for (const [sessionID, property] of Object.entries(properties)) {
|
|
10699
|
+
const status = parseSessionStatus(property.value);
|
|
10700
|
+
if (status === undefined)
|
|
10701
|
+
return;
|
|
10702
|
+
entries.push([sessionID, status]);
|
|
10703
|
+
}
|
|
10704
|
+
return Object.fromEntries(entries);
|
|
10705
|
+
}
|
|
10706
|
+
|
|
10551
10707
|
// src/orchestrator/subsessions.ts
|
|
10552
10708
|
var DEFAULT_ABORT_GRACE_MS = 2000;
|
|
10553
10709
|
var DEFAULT_STATUS_POLL_MS = 100;
|
|
@@ -10773,28 +10929,6 @@ function statusArgs(directory, signal) {
|
|
|
10773
10929
|
function abortArgs(sessionID, directory, signal) {
|
|
10774
10930
|
return directory === undefined ? { path: { id: sessionID }, signal } : { path: { id: sessionID }, query: { directory }, signal };
|
|
10775
10931
|
}
|
|
10776
|
-
function isSessionStatus(value) {
|
|
10777
|
-
if (!isObject3(value))
|
|
10778
|
-
return false;
|
|
10779
|
-
const type = safeGet(value, "type");
|
|
10780
|
-
if (type === "idle" || type === "busy")
|
|
10781
|
-
return true;
|
|
10782
|
-
if (type !== "retry")
|
|
10783
|
-
return false;
|
|
10784
|
-
return typeof safeGet(value, "attempt") === "number" && typeof safeGet(value, "message") === "string" && typeof safeGet(value, "next") === "number";
|
|
10785
|
-
}
|
|
10786
|
-
function isSessionStatusMap(value) {
|
|
10787
|
-
if (!isObject3(value) || Array.isArray(value))
|
|
10788
|
-
return false;
|
|
10789
|
-
try {
|
|
10790
|
-
const prototype = Object.getPrototypeOf(value);
|
|
10791
|
-
if (prototype !== Object.prototype && prototype !== null)
|
|
10792
|
-
return false;
|
|
10793
|
-
return Object.values(value).every(isSessionStatus);
|
|
10794
|
-
} catch {
|
|
10795
|
-
return false;
|
|
10796
|
-
}
|
|
10797
|
-
}
|
|
10798
10932
|
async function confirmSessionStopped(client, sessionID, directory, deps, deadline) {
|
|
10799
10933
|
const abortSession = client.session.abort;
|
|
10800
10934
|
if (abortSession === undefined) {
|
|
@@ -10843,8 +10977,8 @@ async function confirmSessionStopped(client, sessionID, directory, deps, deadlin
|
|
|
10843
10977
|
if (safeGet(statuses, "error") !== undefined) {
|
|
10844
10978
|
return { confirmed: false, cause: "status-error" };
|
|
10845
10979
|
}
|
|
10846
|
-
const snapshot = safeGet(statuses, "data");
|
|
10847
|
-
if (
|
|
10980
|
+
const snapshot = parseSessionStatusMap(safeGet(statuses, "data"));
|
|
10981
|
+
if (snapshot === undefined) {
|
|
10848
10982
|
return { confirmed: false, cause: "status-missing" };
|
|
10849
10983
|
}
|
|
10850
10984
|
if (!Object.hasOwn(snapshot, sessionID)) {
|
|
@@ -13174,7 +13308,6 @@ var GENERATED_OPENTEAM_STATE_GROUPS = [
|
|
|
13174
13308
|
{ kind: "file", paths: [SOAK_RECORDER_ID_PATH] }
|
|
13175
13309
|
];
|
|
13176
13310
|
var OPENCODE_DIR = ".opencode";
|
|
13177
|
-
var AGENT_DIR = `${OPENCODE_DIR}/agent`;
|
|
13178
13311
|
function splitSetupPath(path3) {
|
|
13179
13312
|
return path3.split("/").filter((segment) => segment.length > 0);
|
|
13180
13313
|
}
|
|
@@ -20343,6 +20476,307 @@ function createRegisterCastTool(deps) {
|
|
|
20343
20476
|
});
|
|
20344
20477
|
}
|
|
20345
20478
|
|
|
20479
|
+
// src/plugin/reloadTool.ts
|
|
20480
|
+
import { resolve as resolve9 } from "node:path";
|
|
20481
|
+
import { tool as tool7 } from "@opencode-ai/plugin/tool";
|
|
20482
|
+
var WAIT_MS = 30000;
|
|
20483
|
+
var SDK_TIMEOUT_MS = 5000;
|
|
20484
|
+
var POLL_MS2 = 1000;
|
|
20485
|
+
var schema = tool7.schema.object({
|
|
20486
|
+
action: tool7.schema.enum(["request", "cancel"]).describe(reloadMessages.action),
|
|
20487
|
+
confirmed: tool7.schema.boolean().describe(reloadMessages.confirmed)
|
|
20488
|
+
}).strict();
|
|
20489
|
+
function sdkData(value) {
|
|
20490
|
+
if (typeof value !== "object" || value === null)
|
|
20491
|
+
return;
|
|
20492
|
+
try {
|
|
20493
|
+
const prototype = Object.getPrototypeOf(value);
|
|
20494
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
20495
|
+
return;
|
|
20496
|
+
const error = Object.getOwnPropertyDescriptor(value, "error");
|
|
20497
|
+
const data = Object.getOwnPropertyDescriptor(value, "data");
|
|
20498
|
+
if (error !== undefined && (!("value" in error) || error.value !== undefined))
|
|
20499
|
+
return;
|
|
20500
|
+
return data !== undefined && "value" in data ? data.value : undefined;
|
|
20501
|
+
} catch {
|
|
20502
|
+
return;
|
|
20503
|
+
}
|
|
20504
|
+
}
|
|
20505
|
+
function createReloadController(deps) {
|
|
20506
|
+
const scheduler = deps.scheduler ?? {
|
|
20507
|
+
now: () => Date.now(),
|
|
20508
|
+
schedule: (run, ms) => {
|
|
20509
|
+
const timer = setTimeout(run, ms);
|
|
20510
|
+
timer.unref();
|
|
20511
|
+
return () => clearTimeout(timer);
|
|
20512
|
+
}
|
|
20513
|
+
};
|
|
20514
|
+
const directory = resolve9(deps.directory);
|
|
20515
|
+
let pending;
|
|
20516
|
+
let authorizing;
|
|
20517
|
+
let closed = false;
|
|
20518
|
+
function current(request) {
|
|
20519
|
+
return pending === request && !request.abort.signal.aborted;
|
|
20520
|
+
}
|
|
20521
|
+
function finish(request, code) {
|
|
20522
|
+
if (!current(request))
|
|
20523
|
+
return;
|
|
20524
|
+
pending = undefined;
|
|
20525
|
+
request.stopDeadline();
|
|
20526
|
+
request.stopPoll?.();
|
|
20527
|
+
request.unlinkCaller();
|
|
20528
|
+
request.abort.abort();
|
|
20529
|
+
deps.notify(code);
|
|
20530
|
+
}
|
|
20531
|
+
function revokeAuthorization() {
|
|
20532
|
+
authorizing?.abort.abort();
|
|
20533
|
+
authorizing = undefined;
|
|
20534
|
+
}
|
|
20535
|
+
function cancel() {
|
|
20536
|
+
revokeAuthorization();
|
|
20537
|
+
if (pending !== undefined)
|
|
20538
|
+
finish(pending, pending.disposing ? "reload-unconfirmed" : "reload-cancelled");
|
|
20539
|
+
}
|
|
20540
|
+
async function requestPermission(context, authorization) {
|
|
20541
|
+
let finishInterruption;
|
|
20542
|
+
const interrupted = new Promise((done) => {
|
|
20543
|
+
finishInterruption = done;
|
|
20544
|
+
});
|
|
20545
|
+
const onAbort = () => finishInterruption("cancelled");
|
|
20546
|
+
const stopTimer = scheduler.schedule(() => finishInterruption("timeout"), Math.max(0, authorization.deadline - scheduler.now()));
|
|
20547
|
+
context.abort.addEventListener("abort", onAbort, { once: true });
|
|
20548
|
+
authorization.abort.signal.addEventListener("abort", onAbort, {
|
|
20549
|
+
once: true
|
|
20550
|
+
});
|
|
20551
|
+
try {
|
|
20552
|
+
return await Promise.race([
|
|
20553
|
+
context.ask({
|
|
20554
|
+
permission: "openteam-reload",
|
|
20555
|
+
patterns: [directory],
|
|
20556
|
+
always: [directory],
|
|
20557
|
+
metadata: { directory }
|
|
20558
|
+
}).then(() => "approved"),
|
|
20559
|
+
interrupted
|
|
20560
|
+
]);
|
|
20561
|
+
} finally {
|
|
20562
|
+
stopTimer();
|
|
20563
|
+
context.abort.removeEventListener("abort", onAbort);
|
|
20564
|
+
authorization.abort.signal.removeEventListener("abort", onAbort);
|
|
20565
|
+
}
|
|
20566
|
+
}
|
|
20567
|
+
function bounded(request, run) {
|
|
20568
|
+
return new Promise((done) => {
|
|
20569
|
+
const operation = new AbortController;
|
|
20570
|
+
let settled = false;
|
|
20571
|
+
const settle = (outcome) => {
|
|
20572
|
+
if (settled)
|
|
20573
|
+
return;
|
|
20574
|
+
settled = true;
|
|
20575
|
+
stopTimer();
|
|
20576
|
+
request.abort.signal.removeEventListener("abort", onAbort);
|
|
20577
|
+
if (outcome.kind !== "settled")
|
|
20578
|
+
operation.abort();
|
|
20579
|
+
done(outcome);
|
|
20580
|
+
};
|
|
20581
|
+
const onAbort = () => settle({ kind: "cancelled" });
|
|
20582
|
+
const stopTimer = scheduler.schedule(() => settle({ kind: "timeout" }), Math.max(0, Math.min(SDK_TIMEOUT_MS, request.deadline - scheduler.now())));
|
|
20583
|
+
request.abort.signal.addEventListener("abort", onAbort, { once: true });
|
|
20584
|
+
try {
|
|
20585
|
+
run(operation.signal).then((value) => settle({ kind: "settled", value }), () => settle({ kind: "failed" }));
|
|
20586
|
+
} catch {
|
|
20587
|
+
settle({ kind: "failed" });
|
|
20588
|
+
}
|
|
20589
|
+
});
|
|
20590
|
+
}
|
|
20591
|
+
function poll(request) {
|
|
20592
|
+
if (!current(request) || request.stopPoll !== undefined)
|
|
20593
|
+
return;
|
|
20594
|
+
request.stopPoll = scheduler.schedule(() => {
|
|
20595
|
+
request.stopPoll = undefined;
|
|
20596
|
+
probe(request);
|
|
20597
|
+
}, POLL_MS2);
|
|
20598
|
+
}
|
|
20599
|
+
async function probe(request) {
|
|
20600
|
+
if (!current(request) || !request.callerIdle || request.probing || request.disposing)
|
|
20601
|
+
return;
|
|
20602
|
+
if (scheduler.now() >= request.deadline) {
|
|
20603
|
+
finish(request, "reload-timeout");
|
|
20604
|
+
return;
|
|
20605
|
+
}
|
|
20606
|
+
request.stopPoll?.();
|
|
20607
|
+
request.stopPoll = undefined;
|
|
20608
|
+
request.probing = true;
|
|
20609
|
+
const revision = request.revision;
|
|
20610
|
+
try {
|
|
20611
|
+
for (let check = 0;check < 2; check++) {
|
|
20612
|
+
const outcome2 = await bounded(request, (signal) => deps.client.session.status({ query: { directory }, signal }));
|
|
20613
|
+
if (!current(request))
|
|
20614
|
+
return;
|
|
20615
|
+
if (outcome2.kind !== "settled") {
|
|
20616
|
+
finish(request, "reload-status-failed");
|
|
20617
|
+
return;
|
|
20618
|
+
}
|
|
20619
|
+
const snapshot = parseSessionStatusMap(sdkData(outcome2.value));
|
|
20620
|
+
if (snapshot === undefined) {
|
|
20621
|
+
finish(request, "reload-status-failed");
|
|
20622
|
+
return;
|
|
20623
|
+
}
|
|
20624
|
+
if (revision !== request.revision || !request.callerIdle) {
|
|
20625
|
+
poll(request);
|
|
20626
|
+
return;
|
|
20627
|
+
}
|
|
20628
|
+
if (Object.values(snapshot).some((status) => status.type !== "idle")) {
|
|
20629
|
+
if (Object.hasOwn(snapshot, request.sessionID) && snapshot[request.sessionID]?.type !== "idle")
|
|
20630
|
+
request.callerIdle = false;
|
|
20631
|
+
if (!request.waitingReported) {
|
|
20632
|
+
request.waitingReported = true;
|
|
20633
|
+
deps.notify("reload-waiting");
|
|
20634
|
+
}
|
|
20635
|
+
poll(request);
|
|
20636
|
+
return;
|
|
20637
|
+
}
|
|
20638
|
+
}
|
|
20639
|
+
if (scheduler.now() >= request.deadline) {
|
|
20640
|
+
finish(request, "reload-timeout");
|
|
20641
|
+
return;
|
|
20642
|
+
}
|
|
20643
|
+
request.disposing = true;
|
|
20644
|
+
closed = true;
|
|
20645
|
+
const outcome = await bounded(request, (signal) => deps.client.instance.dispose({ query: { directory }, signal }));
|
|
20646
|
+
if (!current(request))
|
|
20647
|
+
return;
|
|
20648
|
+
finish(request, outcome.kind === "timeout" ? "reload-unconfirmed" : outcome.kind === "settled" && sdkData(outcome.value) === true ? "reload-accepted" : "reload-dispose-failed");
|
|
20649
|
+
} finally {
|
|
20650
|
+
request.probing = false;
|
|
20651
|
+
if (current(request) && request.callerIdle && !request.disposing && revision !== request.revision)
|
|
20652
|
+
probe(request);
|
|
20653
|
+
}
|
|
20654
|
+
}
|
|
20655
|
+
const definition = {
|
|
20656
|
+
description: reloadMessages.description,
|
|
20657
|
+
args: schema.shape,
|
|
20658
|
+
async execute(args, context) {
|
|
20659
|
+
const parsed = schema.safeParse(args);
|
|
20660
|
+
if (!parsed.success)
|
|
20661
|
+
return reloadMessages.invalid;
|
|
20662
|
+
if (context.agent !== "openteam" || resolve9(context.directory) !== directory || context.sessionID.trim().length === 0)
|
|
20663
|
+
return reloadMessages.denied;
|
|
20664
|
+
if (parsed.data.action === "cancel") {
|
|
20665
|
+
if ((pending?.sessionID ?? authorizing?.sessionID) !== context.sessionID)
|
|
20666
|
+
return reloadMessages.none;
|
|
20667
|
+
const message = pending?.disposing ? reloadMessages["reload-unconfirmed"] : reloadMessages["reload-cancelled"];
|
|
20668
|
+
cancel();
|
|
20669
|
+
return message;
|
|
20670
|
+
}
|
|
20671
|
+
if (!parsed.data.confirmed) {
|
|
20672
|
+
const inFlight = pending?.sessionID === context.sessionID && pending.disposing;
|
|
20673
|
+
if ((pending?.sessionID ?? authorizing?.sessionID) === context.sessionID)
|
|
20674
|
+
cancel();
|
|
20675
|
+
return inFlight ? reloadMessages["reload-unconfirmed"] : reloadMessages.declined;
|
|
20676
|
+
}
|
|
20677
|
+
if (context.abort.aborted)
|
|
20678
|
+
return reloadMessages["reload-cancelled"];
|
|
20679
|
+
if (closed)
|
|
20680
|
+
return reloadMessages.closed;
|
|
20681
|
+
if (authorizing !== undefined)
|
|
20682
|
+
return authorizing.sessionID === context.sessionID ? reloadMessages.authorizing : reloadMessages.other;
|
|
20683
|
+
if (pending !== undefined) {
|
|
20684
|
+
if (pending.sessionID !== context.sessionID)
|
|
20685
|
+
return reloadMessages.other;
|
|
20686
|
+
pending.toolDone = false;
|
|
20687
|
+
pending.callerIdle = false;
|
|
20688
|
+
pending.revision++;
|
|
20689
|
+
return reloadMessages["reload-queued"];
|
|
20690
|
+
}
|
|
20691
|
+
const authorization = {
|
|
20692
|
+
sessionID: context.sessionID,
|
|
20693
|
+
deadline: scheduler.now() + WAIT_MS,
|
|
20694
|
+
abort: new AbortController
|
|
20695
|
+
};
|
|
20696
|
+
authorizing = authorization;
|
|
20697
|
+
try {
|
|
20698
|
+
const permission = await requestPermission(context, authorization);
|
|
20699
|
+
if (closed)
|
|
20700
|
+
return reloadMessages.closed;
|
|
20701
|
+
if (authorizing !== authorization || context.abort.aborted || permission === "cancelled")
|
|
20702
|
+
return reloadMessages["reload-cancelled"];
|
|
20703
|
+
if (permission === "timeout" || scheduler.now() >= authorization.deadline) {
|
|
20704
|
+
deps.notify("reload-timeout");
|
|
20705
|
+
return reloadMessages["reload-timeout"];
|
|
20706
|
+
}
|
|
20707
|
+
const onAbort = () => {
|
|
20708
|
+
if (pending === request)
|
|
20709
|
+
cancel();
|
|
20710
|
+
};
|
|
20711
|
+
const request = {
|
|
20712
|
+
sessionID: context.sessionID,
|
|
20713
|
+
deadline: authorization.deadline,
|
|
20714
|
+
abort: new AbortController,
|
|
20715
|
+
unlinkCaller: () => context.abort.removeEventListener("abort", onAbort),
|
|
20716
|
+
stopDeadline: () => {},
|
|
20717
|
+
stopPoll: undefined,
|
|
20718
|
+
toolDone: false,
|
|
20719
|
+
callerIdle: false,
|
|
20720
|
+
probing: false,
|
|
20721
|
+
disposing: false,
|
|
20722
|
+
waitingReported: false,
|
|
20723
|
+
revision: 0
|
|
20724
|
+
};
|
|
20725
|
+
pending = request;
|
|
20726
|
+
context.abort.addEventListener("abort", onAbort, { once: true });
|
|
20727
|
+
request.stopDeadline = scheduler.schedule(() => finish(request, request.disposing ? "reload-unconfirmed" : "reload-timeout"), request.deadline - scheduler.now());
|
|
20728
|
+
deps.notify("reload-queued");
|
|
20729
|
+
return reloadMessages["reload-queued"];
|
|
20730
|
+
} finally {
|
|
20731
|
+
if (authorizing === authorization)
|
|
20732
|
+
authorizing = undefined;
|
|
20733
|
+
}
|
|
20734
|
+
}
|
|
20735
|
+
};
|
|
20736
|
+
return {
|
|
20737
|
+
tool: definition,
|
|
20738
|
+
toolCompleted(sessionID) {
|
|
20739
|
+
if (pending?.sessionID !== sessionID)
|
|
20740
|
+
return;
|
|
20741
|
+
pending.unlinkCaller();
|
|
20742
|
+
pending.toolDone = true;
|
|
20743
|
+
pending.callerIdle = false;
|
|
20744
|
+
pending.revision++;
|
|
20745
|
+
},
|
|
20746
|
+
userTurn(_sessionID) {
|
|
20747
|
+
cancel();
|
|
20748
|
+
},
|
|
20749
|
+
event(event) {
|
|
20750
|
+
const sessionID = pending?.sessionID ?? authorizing?.sessionID;
|
|
20751
|
+
if (sessionID === undefined)
|
|
20752
|
+
return;
|
|
20753
|
+
if (event.type === "session.error" && (event.properties.sessionID === undefined || event.properties.sessionID === sessionID) || event.type === "session.deleted" && event.properties.info.id === sessionID) {
|
|
20754
|
+
cancel();
|
|
20755
|
+
return;
|
|
20756
|
+
}
|
|
20757
|
+
if (event.type === "session.created" || event.type === "session.status" && event.properties.status.type !== "idle")
|
|
20758
|
+
revokeAuthorization();
|
|
20759
|
+
const request = pending;
|
|
20760
|
+
if (request === undefined)
|
|
20761
|
+
return;
|
|
20762
|
+
if (event.type === "session.created" || event.type === "session.status") {
|
|
20763
|
+
request.revision++;
|
|
20764
|
+
if (event.type === "session.status" && event.properties.sessionID === request.sessionID && event.properties.status.type !== "idle")
|
|
20765
|
+
request.callerIdle = false;
|
|
20766
|
+
}
|
|
20767
|
+
if (event.type === "session.idle" || event.type === "session.status" && event.properties.status.type === "idle") {
|
|
20768
|
+
if (event.properties.sessionID === request.sessionID && request.toolDone)
|
|
20769
|
+
request.callerIdle = true;
|
|
20770
|
+
probe(request);
|
|
20771
|
+
}
|
|
20772
|
+
},
|
|
20773
|
+
dispose() {
|
|
20774
|
+
closed = true;
|
|
20775
|
+
cancel();
|
|
20776
|
+
}
|
|
20777
|
+
};
|
|
20778
|
+
}
|
|
20779
|
+
|
|
20346
20780
|
// src/plugin/sessionTracker.ts
|
|
20347
20781
|
function createSessionTracker() {
|
|
20348
20782
|
const knownSessions = new Set;
|
|
@@ -20580,7 +21014,7 @@ import {
|
|
|
20580
21014
|
statSync,
|
|
20581
21015
|
unlinkSync as unlinkSync2
|
|
20582
21016
|
} from "node:fs";
|
|
20583
|
-
import { join as join15, resolve as
|
|
21017
|
+
import { join as join15, resolve as resolve11 } from "node:path";
|
|
20584
21018
|
import { ZodError } from "zod";
|
|
20585
21019
|
|
|
20586
21020
|
// src/storage/lifecycle/codec.ts
|
|
@@ -20699,7 +21133,7 @@ import {
|
|
|
20699
21133
|
unlinkSync,
|
|
20700
21134
|
writeSync as writeSync2
|
|
20701
21135
|
} from "node:fs";
|
|
20702
|
-
import { basename as basename3, dirname as dirname7, join as join14, relative as relative3, resolve as
|
|
21136
|
+
import { basename as basename3, dirname as dirname7, join as join14, relative as relative3, resolve as resolve10 } from "node:path";
|
|
20703
21137
|
var SAFE_RUN_ID = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,126}[A-Za-z0-9])?$/u;
|
|
20704
21138
|
|
|
20705
21139
|
class LifecycleFsError extends Error {
|
|
@@ -20723,7 +21157,7 @@ function validateRunID(runID) {
|
|
|
20723
21157
|
}
|
|
20724
21158
|
function resolvedLifecycleRoot(root) {
|
|
20725
21159
|
try {
|
|
20726
|
-
const absolute =
|
|
21160
|
+
const absolute = resolve10(root);
|
|
20727
21161
|
mkdirSync2(absolute, { recursive: true });
|
|
20728
21162
|
const rootStat = lstatSync2(absolute);
|
|
20729
21163
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
|
|
@@ -20766,7 +21200,7 @@ function assertExistingSafeRun(root, runID) {
|
|
|
20766
21200
|
throw new LifecycleFsError("unavailable");
|
|
20767
21201
|
}
|
|
20768
21202
|
const child = relative3(root, real);
|
|
20769
|
-
if (child === "" || child.startsWith("..") ||
|
|
21203
|
+
if (child === "" || child.startsWith("..") || resolve10(root, child) !== real || dirname7(real) !== root) {
|
|
20770
21204
|
throw new LifecycleFsError("corrupt");
|
|
20771
21205
|
}
|
|
20772
21206
|
return real;
|
|
@@ -21006,7 +21440,7 @@ function canDeleteTerminalRun(runDir, runID, now) {
|
|
|
21006
21440
|
return now >= lease.expiresAt;
|
|
21007
21441
|
}
|
|
21008
21442
|
var createFsLifecycleJournal = (options) => {
|
|
21009
|
-
const configuredRoot =
|
|
21443
|
+
const configuredRoot = resolve11(options.root);
|
|
21010
21444
|
const now = options.now ?? Date.now;
|
|
21011
21445
|
const mutateRun = options.withMutationLock ?? withRunMutationLock;
|
|
21012
21446
|
return {
|
|
@@ -21638,8 +22072,8 @@ async function readOpencodeVersion(serverUrl, options = {}) {
|
|
|
21638
22072
|
}
|
|
21639
22073
|
var DEFAULT_OPENCODE_VERSION_BACKOFF_MS = [50, 250];
|
|
21640
22074
|
function defaultSleep(ms) {
|
|
21641
|
-
return new Promise((
|
|
21642
|
-
setTimeout(
|
|
22075
|
+
return new Promise((resolve12) => {
|
|
22076
|
+
setTimeout(resolve12, ms);
|
|
21643
22077
|
});
|
|
21644
22078
|
}
|
|
21645
22079
|
function createLazyOpencodeVersionReader(serverUrl, options = {}) {
|
|
@@ -22163,8 +22597,8 @@ var server = async (ctx, rawOptions) => {
|
|
|
22163
22597
|
lifecycleRecorder,
|
|
22164
22598
|
abortGraceMs: DEFAULT_ABORT_GRACE_MS,
|
|
22165
22599
|
statusPollMs: DEFAULT_STATUS_POLL_MS,
|
|
22166
|
-
delay: (ms) => new Promise((
|
|
22167
|
-
setTimeout(
|
|
22600
|
+
delay: (ms) => new Promise((resolve12) => {
|
|
22601
|
+
setTimeout(resolve12, ms);
|
|
22168
22602
|
}),
|
|
22169
22603
|
warn: diagnostics.warn("unknown-role")
|
|
22170
22604
|
});
|
|
@@ -22184,23 +22618,43 @@ var server = async (ctx, rawOptions) => {
|
|
|
22184
22618
|
options: rawOptions
|
|
22185
22619
|
})
|
|
22186
22620
|
});
|
|
22621
|
+
const reload = createReloadController({
|
|
22622
|
+
directory: ctx.directory,
|
|
22623
|
+
client: ctx.client,
|
|
22624
|
+
notify: (code) => diagnostics.emit({
|
|
22625
|
+
code,
|
|
22626
|
+
level: code === "reload-timeout" || code === "reload-status-failed" || code === "reload-dispose-failed" || code === "reload-unconfirmed" ? "warn" : "info"
|
|
22627
|
+
}, { toast: code !== "reload-queued" })
|
|
22628
|
+
});
|
|
22187
22629
|
return {
|
|
22188
22630
|
...hooks,
|
|
22631
|
+
"chat.message": async (input, output) => {
|
|
22632
|
+
reload.userTurn(input.sessionID);
|
|
22633
|
+
await hooks["chat.message"]?.(input, output);
|
|
22634
|
+
},
|
|
22635
|
+
dispose: async () => {
|
|
22636
|
+
reload.dispose();
|
|
22637
|
+
await hooks.dispose?.();
|
|
22638
|
+
},
|
|
22189
22639
|
tool: {
|
|
22190
22640
|
openteam: createCommandTool(cliDeps),
|
|
22191
22641
|
"openteam-console": createConsoleTool(),
|
|
22192
22642
|
"openteam-graph": graphSurface.definition,
|
|
22193
22643
|
"openteam-orchestrate": orchestrateTool,
|
|
22194
22644
|
"openteam-memory": memoryTool,
|
|
22195
|
-
"openteam-register-cast": registerCastTool
|
|
22645
|
+
"openteam-register-cast": registerCastTool,
|
|
22646
|
+
"openteam-reload": reload.tool
|
|
22196
22647
|
},
|
|
22197
22648
|
"tool.execute.before": async (input) => {
|
|
22198
22649
|
toolcalls.before(input);
|
|
22199
22650
|
},
|
|
22200
22651
|
"tool.execute.after": async (input) => {
|
|
22201
22652
|
await toolcalls.after(input);
|
|
22653
|
+
if (input.tool === "openteam-reload")
|
|
22654
|
+
reload.toolCompleted(input.sessionID);
|
|
22202
22655
|
},
|
|
22203
22656
|
event: async ({ event }) => {
|
|
22657
|
+
reload.event(event);
|
|
22204
22658
|
if (event.type === "session.created" || event.type === "session.idle") {
|
|
22205
22659
|
cache.refresh();
|
|
22206
22660
|
}
|