@bybrawe/opencode-loop 0.5.33 → 0.5.34
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/CHANGELOG.md +10 -0
- package/README.md +197 -283
- package/commands/loop.md +1 -1
- package/package.json +3 -3
- package/scripts/comprehensive-test.mjs +1 -1
- package/scripts/host-loop-canary.mjs +8 -3
- package/scripts/loop-command-handlers-test.mjs +33 -4
- package/scripts/loop-registration-test.mjs +77 -3
- package/scripts/schedule-policy-test.mjs +114 -0
- package/scripts/schedule-syntax-test.mjs +75 -0
- package/scripts/session-status-idle-recovery-test.mjs +44 -0
- package/src/index.js +433 -100
- package/src/source/core/continuation.js +20 -0
- package/src/source/core/jobs.js +3 -0
- package/src/source/core/schedule-syntax.js +93 -0
- package/src/source/opencode/loop-commands.js +39 -30
- package/src/source/opencode/loop-registration.js +40 -3
- package/src/source/runtime/companion-goal.js +37 -0
- package/src/source/runtime/loop-diagnostics.js +45 -0
- package/src/source/runtime/run-admission.js +2 -13
- package/src/source/runtime/schedule-policy.js +80 -0
- package/src/source/runtime/scheduler-diagnostics.js +30 -0
- package/src/source/runtime/scheduler.js +10 -23
- package/src/source/runtime/session-status.js +28 -4
|
@@ -130,6 +130,24 @@ export function createSessionStatusRuntime(options = {}) {
|
|
|
130
130
|
return cached === "idle" && seenAt > (active.startedAt || 0)
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
async function recoverCompletedTailWithoutActiveRun(directory, client, sessionID, liveType, seenAt) {
|
|
134
|
+
if (activeRuns.has(sessionID)) return false
|
|
135
|
+
if (liveType !== "busy" && liveType !== "retry") return false
|
|
136
|
+
// Never override the first fresh busy observation. Waiting at least one cache
|
|
137
|
+
// window gives the host time to expose a new user/assistant turn if it is real.
|
|
138
|
+
if (!seenAt || now() - seenAt < sessionStatusCacheMs) return false
|
|
139
|
+
const completion = await activeRunCompletionFromMessages(directory, client, sessionID, { startedAt: 0 })
|
|
140
|
+
if (completion !== "completed") return false
|
|
141
|
+
markSessionStatus(sessionID, "idle")
|
|
142
|
+
await appendLoopLog(directory, "status-message-idle-recovery", {
|
|
143
|
+
sessionID,
|
|
144
|
+
staleStatus: liveType,
|
|
145
|
+
statusSeenAt: seenAt,
|
|
146
|
+
staleForMs: Math.max(0, now() - seenAt),
|
|
147
|
+
})
|
|
148
|
+
return true
|
|
149
|
+
}
|
|
150
|
+
|
|
133
151
|
async function sessionStatusType(client, sessionID, directory, options = {}) {
|
|
134
152
|
// OpenCode can briefly report an idle session while a long-running tool or
|
|
135
153
|
// subtask is still executing. Tool lifecycle hooks are the more specific
|
|
@@ -152,10 +170,16 @@ export function createSessionStatusRuntime(options = {}) {
|
|
|
152
170
|
|
|
153
171
|
const live = await readLiveSessionStatus(client, sessionID, directory)
|
|
154
172
|
if (live?.type) {
|
|
155
|
-
// Some OpenCode 1.15.x TUI builds can leave session.status at busy
|
|
156
|
-
// plugin
|
|
157
|
-
//
|
|
158
|
-
//
|
|
173
|
+
// Some OpenCode 1.15.x/1.18.x TUI builds can leave session.status at busy
|
|
174
|
+
// after a plugin command acknowledgement. If no Loop run exists yet, a
|
|
175
|
+
// completed assistant tail plus an already-stale busy observation is a
|
|
176
|
+
// stronger signal than the unchanged live status. A genuinely running turn
|
|
177
|
+
// has an unfinished assistant tail (or latest user message) and is never
|
|
178
|
+
// force-recovered by this path.
|
|
179
|
+
if (await recoverCompletedTailWithoutActiveRun(directory, client, sessionID, live.type, seenAt)) return "idle"
|
|
180
|
+
|
|
181
|
+
// When a Loop-owned turn exists, use its exact start boundary so an older
|
|
182
|
+
// completed assistant message can never finalize a newer active run.
|
|
159
183
|
if ((live.type === "busy" || live.type === "retry") && options.recoverStaleActive !== false) {
|
|
160
184
|
const active = activeRuns.get(sessionID)
|
|
161
185
|
if (active) {
|