@bojackduy/opencode-loopd 1.10.4 → 1.11.2
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 +1 -0
- package/README.md +24 -1
- package/commands/goal.md +2 -2
- package/dist/server.js +771 -48
- package/dist/tui.js +1246 -868
- package/package.json +1 -1
- package/skills/loopd/SKILL.md +76 -11
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
### Added
|
|
8
8
|
|
|
9
|
+
- **Agent model discovery and same-goal recovery** — `loopd_list_models` exposes safe provider/model metadata, host capabilities, and owner-scoped goal identities; `switch_goal_model` validates ownership/availability, defers busy workers, and preserves the existing worker session and budgets. Optional `fallbackModels` prepares ordered, one-shot alternatives only for observed provider quota/rate-limit errors; interactive goals never auto-wake. Explicit `resume:true` applies only to provider-limit-blocked goals. Remaining quota/reset information is **unknown/unsupported** in the inspected host APIs, never inferred from connected accounts or API keys. Covered by automated host/service/tool tests; no live provider-exhaustion or TUI proof claimed.
|
|
9
10
|
- **M1 pty parity** — `env` (values to host, names-only persistence), `timeout_seconds` (in-memory deadline → terminate path, `endReason=timeout`, always notifies), `shell:true` (`/bin/sh -c`), `pattern`+`ignore_case` log read (ANSI-stripped match, ReDoS guard), `terminate remove:true`, `endReason` (`exit|terminate|timeout|until|missing`) on every terminal transition.
|
|
10
11
|
- **M2 sentinel watcher engine** — `watch_filter`/`watch_until`/`watch_ignore_case`/`watch_until_action (stop|keep)` at start, `loopd_command_watch` on running commands; 2s coalescing (20 lines/4KB), 100-lines/sec flood-suspend (process keeps running), 30-push budget; `until:stop` terminates with `endReason=until` and exactly one owner message; `loopd_command_await until:` wakes a goal once on match without stopping.
|
|
11
12
|
- **M3 surface** — watch badges + endReason in Commands tab, watch counters in detail panel, SKILL.md watching guide with pty + sentinel migration tables, de-polled `loopd_command_get` docs.
|
package/README.md
CHANGED
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
- **Safe by default** — per-goal artifact isolation (`.opencode/loopd/goals/<id>/`), `maxTurns`/`maxFailures`/`maxNoProgress`, force-finish → semantic `complete_goal` summary → parent notification via wake-up injection.
|
|
22
22
|
- **Scheduled intervals** — `scheduleEveryMs`/`scheduleMaxRuns` auto-requeues the same goal every N ms (e.g., `10s` monitor, `1h` report) without manual `/goal` spam — `5s` poll, `skip-if-running`, `workspaceWrite` serialization, inbox `Scheduled tick N/M`.
|
|
23
23
|
- **Modal TUI dashboard** — `<leader>o` or `/loop` opens a focused dialog (no leak to chat prompt). Vim-style navigation, live running indicator, per-status borders.
|
|
24
|
+
- **Command sessions, not blocked shells** — run installs, builds, dev servers, and REPLs as background OS processes with a fullscreen terminal, owner exit notifications, line-level `filter`/`until` watches, and timeouts — instead of freezing the agent turn in `bash`.
|
|
25
|
+
- **Switch models mid-run** — `loopd_list_models` discovers providers/models and quota status; `switch_goal_model` moves a goal to another model on the *same* worker/session when a provider hits quota. Optional ordered `fallbackModels` switch automatically on 429s. Dashboard: `:model`/`:models`.
|
|
26
|
+
- **Manual mode for interactive work** — `interactive: true` (or `:interactive`) stops the engine from starting turns on its own; every turn comes from your `:send`/nudge. For tasks where the worker waits for input.
|
|
24
27
|
|
|
25
28
|
Keywords: `opencode` `opencode-plugin` `background-agent` `autonomous` `subagent` `loop` `goal` `tui` `codex` `claude-code` `worker`
|
|
26
29
|
|
|
@@ -151,7 +154,9 @@ Dashboard (NORMAL / INSERT `:`) — shared Goals/Commands tabs:
|
|
|
151
154
|
- `o` — goals: open child session (native OpenCode view) · commands: close
|
|
152
155
|
popup, open fullscreen terminal page (route `opencode.loopd.terminal`)
|
|
153
156
|
- `p/r/R/x` — pause / resume / retry / clear selected goal (Goals tab only)
|
|
154
|
-
-
|
|
157
|
+
- `c` — toggle finished on both tabs (completed goals · exited/terminated/missing commands)
|
|
158
|
+
- `:interactive` — toggle manual mode (engine never starts turns) · `:model <provider/model>` — switch goal's model · `:models` — provider/model inventory
|
|
159
|
+
- Commands tab: `X` force-kill · `R` restart · `x` remove finished · `:new <command> [args...]` launch · `:interrupt` ·
|
|
155
160
|
`:terminate` · `:remove` · bare text + Enter writes stdin (owner-scoped)
|
|
156
161
|
- `:` — insert mode → `:send <message>` to steer, `:force` / `:block` to finish manually
|
|
157
162
|
- `?` — toggle help — help stays open while you type
|
|
@@ -174,6 +179,9 @@ inspect_background_goal() — full detail: objective, progress, blocker,
|
|
|
174
179
|
read_goal_transcript() — last N worker messages (what it's doing)
|
|
175
180
|
send_goal_input(goalID, msg) — steer: "skip appendix PDFs"
|
|
176
181
|
pause_goal(goalID) / resume / clear
|
|
182
|
+
loopd_list_models() — providers/models, quota status (unknown where hosts can't report it)
|
|
183
|
+
switch_goal_model(goalID, model) — same goal, new model (same worker/session)
|
|
184
|
+
loopd_command_start(...) — installs/builds/servers as background processes (never block the turn in bash)
|
|
177
185
|
```
|
|
178
186
|
|
|
179
187
|
### 4. Worker tools (child session)
|
|
@@ -260,6 +268,8 @@ Goals accept:
|
|
|
260
268
|
| `checkCwd` | artifact directory | Directory where completion checks run; workspace writes default to project root |
|
|
261
269
|
| `workspaceWrite` | `true` | Marks shared-workspace mutation; only one active workspace writer is allowed. Set `false` explicitly for artifact-only/read-only work |
|
|
262
270
|
| `agent` | `defaultAgent` | Worker agent; goal creation fails if neither is configured nor supplied |
|
|
271
|
+
| `interactive` | `false` | Manual mode: engine never starts turns (`:send`/nudge only). For workers that wait for input |
|
|
272
|
+
| `fallbackModels` | `[]` | Ordered `provider/model` alternatives tried on quota/rate-limit errors only. Empty = no automatic switch |
|
|
263
273
|
| `progressFile` | `<artifactDir>/progress.md` | Transaction state file |
|
|
264
274
|
| `artifactDir` | `goals/<id>/` | Auto — override only if objective names another dir |
|
|
265
275
|
|
|
@@ -293,6 +303,19 @@ loopd_create_goal({
|
|
|
293
303
|
|
|
294
304
|
Without schedule you’d send `/goal` 3× manually; with schedule one creation covers `monitor deploy`, `periodic tests`, `keep going until done`.
|
|
295
305
|
|
|
306
|
+
## Switch models without losing the worker
|
|
307
|
+
|
|
308
|
+
When a provider hits quota or rate limits mid-run:
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
loopd_list_models() — what's connected, quota status (or honestly unknown)
|
|
312
|
+
switch_goal_model(goalID, "other-provider/good-model") — same goal, same worker/session, transcript kept
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
- Busy workers defer the switch to the next turn (`→ pending … applies next turn`); idle ones switch immediately. On v1 the new model takes effect from the next prompt (no mid-stream session switch API); v2 switches the live session where supported, else reports `unsupported` without touching anything.
|
|
316
|
+
- `fallbackModels: ["b/model", "c/model"]` at creation tries alternatives automatically — quota/429 errors only, each once, never looping. Interactive goals record the fallback but never auto-wake; you steer the next turn.
|
|
317
|
+
- Dashboard: `:model <provider/model>` and `:models` do the same for humans.
|
|
318
|
+
|
|
296
319
|
## Dashboard tips
|
|
297
320
|
|
|
298
321
|
- Press `:` then type bare text → sent as `send_goal_input` to the selected goal.
|
package/commands/goal.md
CHANGED
|
@@ -16,8 +16,8 @@ When you have enough to write a concrete contract:
|
|
|
16
16
|
1. Call `loopd_create_goal` with:
|
|
17
17
|
- `name` — a short slug (e.g. "pdf-notes")
|
|
18
18
|
- `objective` — a precise, self-contained statement including verification criteria
|
|
19
|
-
- `agent` — any OpenCode agent name: built-in (`general`, `explore`), `~/.config/opencode/agents/*.md`, or `opencode.jsonc` `agent.*`. Discover with `opencode agent list`. Prefer `subagent`-mode agents for workers; `primary`-mode agents work but may expect user interaction.
|
|
20
|
-
- `model` — any model as `"providerID/modelID"` (e.g. `openai/gpt-5.6-sol`, `ollama/qwen3.8:27b`). Discover with `opencode models [provider]`. Sent on every worker prompt
|
|
19
|
+
- `agent` — any OpenCode agent name: built-in (`general`, `explore`), `~/.config/opencode/agents/*.md`, or `opencode.jsonc` `agent.*`. Discover with `opencode agent list`. Prefer `subagent`-mode agents for workers; `primary`-mode agents work but may expect user interaction. **Omit by default — inherits calling session's live agent, then `defaultAgent`.** Only pass when explicitly requested.
|
|
20
|
+
- `model` — any model as `"providerID/modelID"` (e.g. `openai/gpt-5.6-sol`, `ollama/qwen3.8:27b`). Discover with `opencode models [provider]`. Sent on every worker prompt. **Omit by default — inherits calling session's live model, then `defaultModel`.** Only pass when explicitly requested.
|
|
21
21
|
- `checks` — shell commands that must pass before `complete_goal` is accepted; **mandatory when `workspaceWrite:true`** (the default) — or configure `defaultChecks` in `opencode.jsonc`
|
|
22
22
|
- `workspaceWrite` — default `true` (safe — may touch the shared repo; only one active writer allowed — second `start`/`resume` fails with `already active`); set `false` explicitly for artifact-only/read-only work to allow concurrency
|
|
23
23
|
- `checkCwd` — optional directory where `checks` run; writers default to project root, artifact-only jobs default to their `artifactDir`
|